diff --git a/bin/day2406.ml b/bin/day2406.ml index 50cc52c..69fb379 100644 --- a/bin/day2406.ml +++ b/bin/day2406.ml @@ -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 diff --git a/bin/day2408.ml b/bin/day2408.ml index 3d33db0..271b737 100644 --- a/bin/day2408.ml +++ b/bin/day2408.ml @@ -1,29 +1,13 @@ -type map = { map : string; width : int; height : int } - -let map_of_file fname = - let strs = Aoc.strings_of_file fname in - let width = String.length (List.hd strs) in - let map = List.fold_left ( ^ ) "" strs in - let height = String.length map / width in - { map; width; height } - -let map_length map = String.length map.map -let map_get_by_idx map idx = map.map.[idx] -let map_pos_of_idx map idx = (idx mod map.width, idx / map.width) - -let map_is_valid_pos map (x, y) = - x >= 0 && x < map.width && y >= 0 && y < map.height - module CharMap = Map.Make (Char) (** [get_station_indices map] returns a list of pairs mapping station ID to the indices in [map] where there is a station with that ID. *) let get_station_indices map = let rec impl acc idx = - if idx >= map_length map then acc - else if map_get_by_idx map idx = '.' then impl acc (idx + 1) + if idx >= Aoc.Grid.length map then acc + else if Aoc.Grid.get_by_idx map idx = '.' then impl acc (idx + 1) else - let station = map_get_by_idx map idx in + let station = Aoc.Grid.get_by_idx map idx in let update_fn lst = match lst with None -> Some [ idx ] | Some t -> Some (idx :: t) in @@ -40,7 +24,7 @@ let get_antinodes1 acc _ (px, py) (px', py') = (** [add_antinodes lst map pos vel] adds antinodes at [pos + n * vel] to [lst] for all non-negative [n] that are valid positions in [map]. *) let rec add_antinodes lst map (x, y) (dx, dy) = - if map_is_valid_pos map (x, y) then + if Aoc.Grid.pos_is_valid map (x, y) then add_antinodes ((x, y) :: lst) map (x + dx, y + dy) (dx, dy) else lst @@ -60,11 +44,11 @@ let process_stations map fn stations = let rec impl2 acc p t = match t with | [] -> acc - | h :: t -> impl2 (fn acc map p (map_pos_of_idx map h)) p t + | h :: t -> impl2 (fn acc map p (Aoc.Grid.pos_of_idx map h)) p t in let rec impl acc = function | [] -> acc - | h :: t -> impl (impl2 acc (map_pos_of_idx map h) t) t + | h :: t -> impl (impl2 acc (Aoc.Grid.pos_of_idx map h) t) t in List.map (impl []) stations @@ -77,12 +61,12 @@ let part antifn map = |> List.map snd (* we do not care about the station IDs *) |> process_stations map antifn |> List.concat - |> List.filter (map_is_valid_pos map) + |> List.filter (Aoc.Grid.pos_is_valid map) |> List.sort_uniq Stdlib.compare |> List.length let _ = - Aoc.main map_of_file + Aoc.main Aoc.Grid.of_file [ (string_of_int, part get_antinodes1); (string_of_int, part get_antinodes2); ] diff --git a/bin/day2410.ml b/bin/day2410.ml index e35126c..4e03cce 100644 --- a/bin/day2410.ml +++ b/bin/day2410.ml @@ -1,33 +1,3 @@ -type grid = { grid : string; width : int; height : int } -(** Type to hold the grid in... We should be moving this to the library soon *) - -(** [grid_of_file fname] loads a grid from the given file *) -let grid_of_file fname = - let strs = Aoc.strings_of_file fname in - let grid = List.fold_left String.cat "" strs in - let width = String.length (List.hd strs) in - let height = String.length grid / width in - assert (width * height = String.length grid); - { grid; width; height } - -(** [grid_length grid] gives the length of the grid ([width * height]). *) -let grid_length grid = String.length grid.grid - -(** [grid_get_by_idx grid idx] returns the element of [grid] at [idx]. *) -let grid_get_by_idx grid idx = grid.grid.[idx] - -(** [grid_get_by_idx grid pos] returns the element of [grid] at [pos]. *) -let grid_get_by_pos grid (x, y) = grid.grid.[x + (y * grid.width)] - -(** [grid_pos_if_idx grid idx] returns the [(x, y)] position of [idx] in [grid]. -*) -let grid_pos_of_idx grid idx = (idx mod grid.width, idx / grid.width) - -(** [grid_pos_is_valid grid pos] returns [true] if and only if [pos] is a valid - position in [grid]. *) -let grid_pos_is_valid grid (x, y) = - x >= 0 && y >= 0 && x < grid.width && y < grid.height - (** [next_char ch] returns the next character after [ch]. *) let next_char ch = Char.chr (1 + Char.code ch) @@ -42,10 +12,10 @@ let one = '1' '0'. The same endpoint may be returned multiple times if there are multiple routes to it. *) let find_trail grid pos0 = - assert (grid_get_by_pos grid pos0 = '0'); + assert (Aoc.Grid.get_by_pos grid pos0 = '0'); let add_pos lst pos digit = - if grid_pos_is_valid grid pos && grid_get_by_pos grid pos = digit then - pos :: lst + if Aoc.Grid.pos_is_valid grid pos && Aoc.Grid.get_by_pos grid pos = digit + then pos :: lst else lst in let add_poses lst (x, y) digit = @@ -69,10 +39,10 @@ let find_trail grid pos0 = corresponds to the trails starting at index [n]. *) let find_trails grid = let rec impl acc idx = - if idx >= grid_length grid then acc - else if grid_get_by_idx grid idx <> '0' then impl acc (idx + 1) + if idx >= Aoc.Grid.length grid then acc + else if Aoc.Grid.get_by_idx grid idx <> '0' then impl acc (idx + 1) else (* grid_get_by_idx grid idx = 0 *) - impl (find_trail grid (grid_pos_of_idx grid idx) :: acc) (idx + 1) + impl (find_trail grid (Aoc.Grid.pos_of_idx grid idx) :: acc) (idx + 1) in impl [] 0 |> List.rev @@ -83,7 +53,7 @@ let part sort_fn grid = |> List.fold_left ( + ) 0 let _ = - Aoc.main grid_of_file + Aoc.main Aoc.Grid.of_file [ (string_of_int, part (List.sort_uniq Stdlib.compare)); (string_of_int, part Fun.id);