Tidy up 2024 day 15
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
type grid = { grid : char array; width : int; height : int }
|
type grid = { grid : char array; width : int }
|
||||||
|
(** Grid type. Not our normal type as we want to use it in a mutable way. *)
|
||||||
|
|
||||||
|
(** [grid_map fn strs] Returns a grid built up from the list of strings [strs].
|
||||||
|
[fn] takes a single string of all map characters and returns a string with
|
||||||
|
the appropriate replacements done. *)
|
||||||
let grid_make posmap_fn strs =
|
let grid_make posmap_fn strs =
|
||||||
let grid =
|
let grid =
|
||||||
List.fold_left String.cat "" strs
|
List.fold_left String.cat "" strs
|
||||||
@@ -7,9 +11,9 @@ let grid_make posmap_fn strs =
|
|||||||
in
|
in
|
||||||
let height = List.length strs in
|
let height = List.length strs in
|
||||||
let width = Array.length grid / height in
|
let width = Array.length grid / height in
|
||||||
Printf.printf "width %d height %d \n" width height;
|
{ grid; width }
|
||||||
{ grid; width; height }
|
|
||||||
|
|
||||||
|
(** [grid_print grid] prints [grid] to standard output. *)
|
||||||
let[@warning "-32"] grid_print grid =
|
let[@warning "-32"] grid_print grid =
|
||||||
Array.iteri
|
Array.iteri
|
||||||
(fun i c ->
|
(fun i c ->
|
||||||
@@ -17,11 +21,16 @@ let[@warning "-32"] grid_print grid =
|
|||||||
if i mod grid.width = grid.width - 1 then print_newline ())
|
if i mod grid.width = grid.width - 1 then print_newline ())
|
||||||
grid.grid
|
grid.grid
|
||||||
|
|
||||||
let find_start_idx grid =
|
(** [find_robot_idx grid] returns the index of the robot in grid. *)
|
||||||
|
let find_robot_idx grid =
|
||||||
match Array.find_index (( = ) '@') grid.grid with
|
match Array.find_index (( = ) '@') grid.grid with
|
||||||
| None -> failwith "find_start_idx"
|
| None -> failwith "find_robot_idx"
|
||||||
| Some x -> x
|
| Some x -> x
|
||||||
|
|
||||||
|
(** [instrs_of_file fname] reads from the file [fname] and returns a
|
||||||
|
[(grid, instrs)] pair. [grid] is a list of strings describing the initial
|
||||||
|
grid state. [instrs] is a list of characters giving movement instructions.
|
||||||
|
*)
|
||||||
let instrs_of_file fname =
|
let instrs_of_file fname =
|
||||||
let strs = Aoc.strings_of_file fname in
|
let strs = Aoc.strings_of_file fname in
|
||||||
let rec impl acc = function
|
let rec impl acc = function
|
||||||
@@ -32,19 +41,29 @@ let instrs_of_file fname =
|
|||||||
let grid, moves = impl [] strs in
|
let grid, moves = impl [] strs in
|
||||||
(grid, List.fold_left String.cat "" moves |> String.to_seq |> List.of_seq)
|
(grid, List.fold_left String.cat "" moves |> String.to_seq |> List.of_seq)
|
||||||
|
|
||||||
let rec move_robot_x grid i di =
|
(** [move_x grid i di] moves the object in [grid] at [i] to [i + di] if
|
||||||
|
possible, returning the new location of the object (either [i] or [i + di]).
|
||||||
|
This assumes a horizontal movement of one step. *)
|
||||||
|
let rec move_x grid i di =
|
||||||
|
assert (di == -1 || di == 1);
|
||||||
|
assert (i >= 0 && i <= Array.length grid.grid);
|
||||||
match grid.grid.(i + di) with
|
match grid.grid.(i + di) with
|
||||||
| '#' -> i
|
| '#' -> i
|
||||||
| 'O' | '[' | ']' ->
|
| 'O' | '[' | ']' ->
|
||||||
if move_robot_x grid (i + di) di = i + di then i
|
if move_x grid (i + di) di = i + di then i else move_x grid i di
|
||||||
else move_robot_x grid i di
|
|
||||||
| '.' ->
|
| '.' ->
|
||||||
grid.grid.(i + di) <- grid.grid.(i);
|
grid.grid.(i + di) <- grid.grid.(i);
|
||||||
grid.grid.(i) <- '.';
|
grid.grid.(i) <- '.';
|
||||||
i + di
|
i + di
|
||||||
| _ -> failwith "move_robot_x"
|
| _ -> failwith "move_x"
|
||||||
|
|
||||||
|
(** [can_move_y grid i di] returns true if and only if it is possible to move
|
||||||
|
whatever is at [i] to [i + di] in [grid]. If [i + di] is full it recursively
|
||||||
|
checks to see if that can be moved as well. [di] must be a vertical
|
||||||
|
movement. *)
|
||||||
let rec can_move_y grid i di =
|
let rec can_move_y grid i di =
|
||||||
|
assert (i >= 0 && i < Array.length grid.grid);
|
||||||
|
assert (di = grid.width || di = -grid.width);
|
||||||
match grid.grid.(i + di) with
|
match grid.grid.(i + di) with
|
||||||
| '#' -> false
|
| '#' -> false
|
||||||
| '.' -> true
|
| '.' -> true
|
||||||
@@ -53,10 +72,15 @@ let rec can_move_y grid i di =
|
|||||||
| ']' -> can_move_y grid (i + di - 1) di && can_move_y grid (i + di) di
|
| ']' -> can_move_y grid (i + di - 1) di && can_move_y grid (i + di) di
|
||||||
| _ -> failwith "can_move_y"
|
| _ -> failwith "can_move_y"
|
||||||
|
|
||||||
let move_robot_y grid i di =
|
(** [move_x grid i di] moves the object in [grid] at [i] to [i + di] if
|
||||||
|
possible, returning the new location of the object (either [i] or [i + di]).
|
||||||
|
This assumes a vertical movement of one step. *)
|
||||||
|
let move_y grid i di =
|
||||||
|
assert (i >= 0 && i < Array.length grid.grid);
|
||||||
|
assert (di = grid.width || di = -grid.width);
|
||||||
let rec do_move i =
|
let rec do_move i =
|
||||||
match grid.grid.(i + di) with
|
match grid.grid.(i + di) with
|
||||||
| '#' -> failwith "move_robot_y.do_move #"
|
| '#' -> failwith "move_y.do_move #"
|
||||||
| '.' ->
|
| '.' ->
|
||||||
grid.grid.(i + di) <- grid.grid.(i);
|
grid.grid.(i + di) <- grid.grid.(i);
|
||||||
grid.grid.(i) <- '.'
|
grid.grid.(i) <- '.'
|
||||||
@@ -71,27 +95,31 @@ let move_robot_y grid i di =
|
|||||||
do_move (i + di - 1);
|
do_move (i + di - 1);
|
||||||
do_move (i + di);
|
do_move (i + di);
|
||||||
do_move i
|
do_move i
|
||||||
| _ -> failwith "move_robot_y.do_move"
|
| _ -> failwith "move_y.do_move"
|
||||||
in
|
in
|
||||||
if can_move_y grid i di then (
|
if can_move_y grid i di then (
|
||||||
do_move i;
|
do_move i;
|
||||||
i + di)
|
i + di)
|
||||||
else i
|
else i
|
||||||
|
|
||||||
|
(** [process_move grid robot dir] attempts to move robot at idx [robot] in
|
||||||
|
[grid] in direction. Returns location of robot after attempt. *)
|
||||||
let process_move grid robot dir =
|
let process_move grid robot dir =
|
||||||
(*grid_print grid;
|
|
||||||
Printf.printf "\nMove: %c\n" dir;*)
|
|
||||||
match dir with
|
match dir with
|
||||||
| '^' -> move_robot_y grid robot ~-(grid.width)
|
| '^' -> move_y grid robot (-grid.width)
|
||||||
| 'v' -> move_robot_y grid robot grid.width
|
| 'v' -> move_y grid robot grid.width
|
||||||
| '<' -> move_robot_x grid robot ~-1
|
| '<' -> move_x grid robot ~-1
|
||||||
| '>' -> move_robot_x grid robot 1
|
| '>' -> move_x grid robot 1
|
||||||
| _ -> failwith "process_move"
|
| _ -> failwith "process_move"
|
||||||
|
|
||||||
|
(** [process_moves grid robot lst] Attempts each move in [lst] in turn given a
|
||||||
|
[grid] and initial starting position of the robot [robot]. Returns the
|
||||||
|
[grid]. *)
|
||||||
let rec process_moves grid robot = function
|
let rec process_moves grid robot = function
|
||||||
| [] -> grid
|
| [] -> ()
|
||||||
| h :: t -> process_moves grid (process_move grid robot h) t
|
| h :: t -> process_moves grid (process_move grid robot h) t
|
||||||
|
|
||||||
|
(** [calc_score grid] returns the score for [grid]. *)
|
||||||
let calc_score grid =
|
let calc_score grid =
|
||||||
Array.mapi
|
Array.mapi
|
||||||
(fun idx c ->
|
(fun idx c ->
|
||||||
@@ -101,6 +129,8 @@ let calc_score grid =
|
|||||||
grid.grid
|
grid.grid
|
||||||
|> Array.fold_left ( + ) 0
|
|> Array.fold_left ( + ) 0
|
||||||
|
|
||||||
|
(** [expand_grid str] given an input [str] returns the output grid string for
|
||||||
|
part 2. *)
|
||||||
let expand_grid str =
|
let expand_grid str =
|
||||||
let b = Buffer.create (String.length str * 2) in
|
let b = Buffer.create (String.length str * 2) in
|
||||||
let add_c = function
|
let add_c = function
|
||||||
@@ -113,10 +143,12 @@ let expand_grid str =
|
|||||||
String.iter add_c str;
|
String.iter add_c str;
|
||||||
Buffer.contents b
|
Buffer.contents b
|
||||||
|
|
||||||
|
(** [part posmap_fn (grid, moves)] executes the [moves] in [grid] having first
|
||||||
|
applied [posmap_fn] to grid. *)
|
||||||
let part posmap_fn (grid, moves) =
|
let part posmap_fn (grid, moves) =
|
||||||
let grid = grid_make posmap_fn grid in
|
let grid = grid_make posmap_fn grid in
|
||||||
let robot = find_start_idx grid in
|
let robot = find_robot_idx grid in
|
||||||
let _ = process_moves grid robot moves in
|
process_moves grid robot moves;
|
||||||
(*grid_print grid;*)
|
(*grid_print grid;*)
|
||||||
calc_score grid
|
calc_score grid
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user