Compare commits

...

3 Commits

Author SHA1 Message Date
6d551f5497 Remove mutable state from day 8 of 2024. 2024-12-08 09:15:45 +00:00
b9af6249a3 2024 day 8 part 2. 2024-12-08 08:36:02 +00:00
71c5b5e5a2 2024 day 8 part 1 2024-12-08 08:09:20 +00:00
2 changed files with 98 additions and 2 deletions

88
bin/day2408.ml Normal file
View File

@@ -0,0 +1,88 @@
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)
else
let station = map_get_by_idx map idx in
let update_fn lst =
match lst with None -> Some [ idx ] | Some t -> Some (idx :: t)
in
impl (CharMap.update station update_fn acc) (idx + 1)
in
impl CharMap.empty 0 |> CharMap.to_list
(** Generate antinodes for part 1. *)
let get_antinodes1 acc _ (px, py) (px', py') =
let dx = px' - px in
let dy = py' - py in
(px - dx, py - dy) :: (px' + dx, py' + dy) :: acc
(** [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
add_antinodes ((x, y) :: lst) map (x + dx, y + dy) (dx, dy)
else lst
(** Generate antinodes for part 2. *)
let get_antinodes2 acc map (px, py) (px', py') =
let dx = px' - px in
let dy = py' - py in
let acc' = add_antinodes acc map (px, py) (dx, dy) in
let acc'' = add_antinodes acc' map (px, py) (-dx, -dy) in
acc''
(** [process_stations map fn stations] generates a list of all antinodes for the
stations in [stations] on the map [map]. [fn acc map p p'] is called to
generate the antinode list for each pair of stations [p] and [p']. It should
add the positions of antinodes to the list [acc]. *)
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
in
let rec impl acc = function
| [] -> acc
| h :: t -> impl (impl2 acc (map_pos_of_idx map h) t) t
in
List.map (impl []) stations
(** [part antifn map station_indices] process all the stations in
station_indices calling [antifn acc map p p'] on all stations. Here [acc] is
a list of antinodes which [antifn] should update and return, [p] and [p']
are positions of stations to generate antinodes for. *)
let part antifn map =
get_station_indices 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.sort_uniq Stdlib.compare
|> List.length
let _ =
Aoc.main map_of_file
[
(string_of_int, part get_antinodes1); (string_of_int, part get_antinodes2);
]

View File

@@ -1,4 +1,12 @@
(executables (executables
(public_names day2401 day2402 day2403 day2404 day2405 day2406 day2407) (public_names
(names day2401 day2402 day2403 day2404 day2405 day2406 day2407) day2401
day2402
day2403
day2404
day2405
day2406
day2407
day2408)
(names day2401 day2402 day2403 day2404 day2405 day2406 day2407 day2408)
(libraries str aoc)) (libraries str aoc))