Day 8! A bit late

This commit is contained in:
2024-12-09 22:32:37 +00:00
parent ee88542095
commit 5d62c21b7f
2 changed files with 148 additions and 1 deletions

View File

@ -13,7 +13,7 @@ let read_lines name =
let () =
print_endline "\nAdvent of Code 2024";
let part1, part2 =
read_lines "./inputs/07.txt" |> AdventOfCode2024.Day_07.solve
read_lines "./inputs/08.txt" |> AdventOfCode2024.Day_08.solve
in
Printf.printf "Part 1: %s\nPart 2: %s\n" (string_of_int part1)
(string_of_int part2)

View File

@ -0,0 +1,147 @@
module IntTuple = struct
type t = int * int
let compare (x0, y0) (x1, y1) = if x0 == x1 && y0 == y1 then 0 else 1
end
module TupleSet = Set.Make (IntTuple)
module CharMap = Map.Make (Char)
let exponent x n =
let rec loop acc n = match n with 0 -> acc | _ -> loop (acc * x) (n - 1) in
loop 1 n
let abs x = if x < 0 then -x else x
let get_coordinates lines freq =
let rec loop acc y lines =
match lines with
| [] -> acc
| head :: tail ->
let _, coords =
String.fold_left
(fun (i, accc) c ->
if c == freq then (i + 1, [ (i, y) ] @ accc) else (i + 1, accc))
(0, []) head
in
loop (acc @ coords) (y + 1) tail
in
loop [] 0 lines
let distances (x1, y1) (x2, y2) = (x2 - x1, y2 - y1)
let get_anti_nodes c1 c2 =
let x, y = c1 in
let dx, dy = distances c1 c2 in
[ (x + (2 * dx), y + (2 * dy)); (x - dx, y - dy) ]
let get_part2_anti_nodes x_limit y_limit c1 c2 =
let dx, dy = distances c1 c2 in
let rec loop (x, y) (dx, dy) acc multiplier =
let new_x, new_y = (x + (multiplier * dx), y + (multiplier * dy)) in
if new_x >= 0 && new_x < x_limit && new_y >= 0 && new_y < y_limit then
loop (x, y) (dx, dy) ([ (new_x, new_y) ] @ acc) (multiplier + 1)
else acc
in
let first = loop c1 (dx, dy) [] 1 in
let second = loop c2 (-dx, -dy) [] 1 in
first @ second
let get_frequencies lines =
let rec loop y map lines =
match lines with
| [] -> map
| head :: tail ->
let _, m =
String.fold_left
(fun (i, acc) c ->
if c != '.' then
let new_coord = (i, y) in
let new_map =
CharMap.update c
(fun i ->
match i with
| None -> Some [ new_coord ]
| Some l -> Some ([ new_coord ] @ l))
acc
in
(i + 1, new_map)
else (i + 1, acc))
(0, map) head
in
loop (y + 1) m tail
in
loop 0 CharMap.empty lines
let character_anti_nodes fn m c =
let coords = CharMap.find c m in
let rec loop c1 acc node_list =
match node_list with
| [] -> acc
| c2 :: tail ->
let anti_nodes = fn c1 c2 in
loop c1 (anti_nodes @ acc) tail
in
let rec get_all acc node_list =
match node_list with
| [] -> acc
| c1 :: tail -> get_all (loop c1 [] tail @ acc) tail
in
get_all [] coords
let rec exists l (x1, y1) =
match l with
| [] -> false
| (x2, y2) :: tail ->
if x1 == x2 && y1 == y2 then true else exists tail (x1, y1)
let remove_duplicates l seen =
let rec loop acc seen l =
match l with
| [] -> (acc, seen)
| head :: tail ->
let found = exists seen head in
if not found then
let new_seen = [ head ] @ seen in
loop ([ head ] @ acc) new_seen tail
else loop acc seen tail
in
loop [] seen l
(* Gradient signs are all reversed because y going down is + *)
let solve lines =
let m = get_frequencies lines in
let all_keys = CharMap.to_list m |> List.map (fun (k, _) -> k) in
let part1_anti_nodes = character_anti_nodes get_anti_nodes in
let part2_anti_nodes =
character_anti_nodes
(get_part2_anti_nodes
(String.length (List.nth lines 0))
(List.length lines))
in
let sum_anti_nodes fn =
List.fold_left
(fun (acc, seen) c ->
let anti_nodes, new_seen = remove_duplicates (fn m c) seen in
let valid_anti_nodes =
List.filter
(fun (x, y) ->
x >= 0
&& x < String.length (List.nth lines 0)
&& y >= 0
&& y < List.length lines)
anti_nodes
in
(acc + List.length valid_anti_nodes, new_seen))
(0, []) all_keys
in
let part1, _ = sum_anti_nodes part1_anti_nodes in
let part2, _ = sum_anti_nodes part2_anti_nodes in
(part1, part2)