76 lines
2.1 KiB
OCaml
76 lines
2.1 KiB
OCaml
type grid = { grid : char array; width : int; height : int }
|
|
|
|
let grid_make strs =
|
|
let grid =
|
|
List.fold_left String.cat "" strs |> String.to_seq |> Array.of_seq
|
|
in
|
|
let height = List.length strs in
|
|
let width = Array.length grid / height in
|
|
{ grid; width; height }
|
|
|
|
let grid_copy grid = { grid with grid = Array.copy grid.grid }
|
|
let grid_height grid = grid.height
|
|
let[@warning "-32"] grid_length grid = grid.width * grid.height
|
|
|
|
let[@warning "-32"] grid_print grid =
|
|
Array.iteri
|
|
(fun i c ->
|
|
print_char c;
|
|
if i mod grid.width = grid.width - 1 then print_newline ())
|
|
grid.grid
|
|
|
|
let find_start_idx grid =
|
|
match Array.find_index (( = ) '@') grid.grid with
|
|
| None -> failwith "find_start_idx"
|
|
| Some x -> x
|
|
|
|
let instrs_of_file fname =
|
|
let strs = Aoc.strings_of_file fname in
|
|
let rec impl acc = function
|
|
| [] | "" :: [] -> failwith "instrs_of_file.impl"
|
|
| "" :: t -> (List.rev acc, t)
|
|
| h :: t -> impl (h :: acc) t
|
|
in
|
|
let grid, moves = impl [] strs in
|
|
let grid = grid_make grid in
|
|
( grid,
|
|
List.fold_left String.cat "" moves |> String.to_seq |> List.of_seq,
|
|
find_start_idx grid )
|
|
|
|
let rec move_robot grid i di =
|
|
match grid.grid.(i + di) with
|
|
| '#' -> i
|
|
| 'O' ->
|
|
if move_robot grid (i + di) di = i + di then i else move_robot grid i di
|
|
| '.' ->
|
|
grid.grid.(i + di) <- grid.grid.(i);
|
|
grid.grid.(i) <- '.';
|
|
i + di
|
|
| _ -> failwith "move_robot"
|
|
|
|
let process_move grid robot dir =
|
|
match dir with
|
|
| '^' -> move_robot grid robot ~-(grid_height grid)
|
|
| 'v' -> move_robot grid robot (grid_height grid)
|
|
| '<' -> move_robot grid robot ~-1
|
|
| '>' -> move_robot grid robot 1
|
|
| _ -> failwith "process_move"
|
|
|
|
let rec process_moves grid robot = function
|
|
| [] -> grid
|
|
| h :: t -> process_moves grid (process_move grid robot h) t
|
|
|
|
let calc_score grid =
|
|
Array.mapi
|
|
(fun idx c ->
|
|
if c = 'O' then (idx mod grid.width) + (100 * (idx / grid.height)) else 0)
|
|
grid.grid
|
|
|> Array.fold_left ( + ) 0
|
|
|
|
let part (grid, moves, robot) =
|
|
let grid = grid_copy grid in
|
|
let _ = process_moves grid robot moves in
|
|
calc_score grid
|
|
|
|
let _ = Aoc.main instrs_of_file [ (string_of_int, part) ]
|