Move to use Aoc.Grid

This commit is contained in:
2024-12-10 11:31:37 +00:00
parent fe93f65f6a
commit b2e56f802e
3 changed files with 25 additions and 94 deletions

View File

@@ -1,50 +1,26 @@
type map = { map : string; width : int; height : int }
(** [map] represents a map with layout [map] and a [width] and [height].
[map.map] is a string of length [width * height] with the [i]th character
describing the position [(i mod map.width, i / map.width)]. *)
(** [find_start strs] returns the location [(x, y)] of the starting position. *)
let find_start map =
match String.index_from_opt map.map 0 '^' with
| Some i -> (i mod map.width, i / map.width)
match Aoc.Grid.idx_from_opt map 0 '^' with
| Some i -> Aoc.Grid.pos_of_idx map i
| None -> failwith "find_start"
(** [map_of_strings strs] returns the map generated from the input map described
by the list of strings [strs] *)
let map_of_strings strs =
let width = String.length (List.hd strs) in
let map = List.fold_left String.cat "" strs in
let height = String.length map / width in
{ map; width; height }
(** [read_file fname] reads the input map from [fname]. It returns a
[(map, pos, vel)] tuple, consisting of the obsticle map, initial position,
and initial velocity. *)
let read_file fname =
let lst = Aoc.strings_of_file fname in
let map = map_of_strings lst in
let map = Aoc.Grid.of_file fname in
let pos = find_start map in
(map, pos, (0, -1))
(** [is_valid_pos map pos] returns true if the position [pos] is valid for the
map [map]. *)
let is_valid_pos map (x, y) =
if y < 0 || y >= map.height then false
else if x < 0 || x >= map.width then false
else true
(** [is_block map pos] returns [true] iff the location [pos] is a blockages in
[map]. *)
let is_block map (x, y) =
if is_valid_pos map (x, y) then map.map.[x + (y * map.width)] = '#' else false
let is_block map pos =
if Aoc.Grid.pos_is_valid map pos then Aoc.Grid.get_by_pos map pos = '#'
else false
(** [insert_block map pos] inserts a blockage at [pos] into [map] and returns
the new map. *)
let insert_block map (x, y) =
let idx = x + (y * map.width) in
let start = String.sub map.map 0 idx in
let e = String.sub map.map (idx + 1) (String.length map.map - idx - 1) in
{ map with map = start ^ "#" ^ e }
let insert_block map pos = Aoc.Grid.update_pos map pos '#'
(** [move map (pos, vel)] moves [pos] one step forward on the [map]. [vel] gives
the movement vector. If the movement will cause an obstacle to be hit then
@@ -60,7 +36,8 @@ let rec move map ((x, y), (dx, dy)) =
off one of the sides. *)
let walk_map map (pos, vel) =
let rec impl acc (pos, vel) =
if is_valid_pos map pos then impl (pos :: acc) (move map (pos, vel))
if Aoc.Grid.pos_is_valid map pos then
impl (pos :: acc) (move map (pos, vel))
else acc
in
impl [] (pos, vel)
@@ -75,7 +52,7 @@ let has_cycles map start =
let rec impl agent1 ((pos', _) as agent2) =
(* Only need to check pos' for validity because if pos is not valid then
pos' must also be invalid, and have been invalid before this. *)
if not (is_valid_pos map pos') then false
if not (Aoc.Grid.pos_is_valid map pos') then false
else if agent1 = agent2 then true
else impl (move map agent1) (move map (move map agent2))
in