Day 8! A bit late
This commit is contained in:
@ -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)
|
||||
|
147
AdventOfCode2024/lib/day_08.ml
Normal file
147
AdventOfCode2024/lib/day_08.ml
Normal 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)
|
Reference in New Issue
Block a user