65 lines
1.7 KiB
OCaml
65 lines
1.7 KiB
OCaml
let line_to_numbers line =
|
|
String.split_on_char ' ' line |> List.map int_of_string
|
|
|
|
module IntMap = Map.Make (Int)
|
|
|
|
let num_of_digits num = (float_of_int num |> log10 |> int_of_float) + 1
|
|
|
|
let split_stone num =
|
|
let digits = num_of_digits num in
|
|
let num_str = string_of_int num in
|
|
let first_half = String.sub num_str 0 (digits / 2) |> int_of_string in
|
|
let second_half =
|
|
String.sub num_str (digits / 2) (digits / 2) |> int_of_string
|
|
in
|
|
(first_half, second_half)
|
|
|
|
let upsert k v map =
|
|
IntMap.update k
|
|
(fun existing ->
|
|
match existing with None -> Some v | Some i -> Some (i + v))
|
|
map
|
|
|
|
let blink map =
|
|
IntMap.fold
|
|
(fun k v acc ->
|
|
if k == 0 then upsert 1 v acc
|
|
else if num_of_digits k mod 2 == 0 then
|
|
let first_stone, second_stone = split_stone k in
|
|
upsert first_stone v acc |> upsert second_stone v
|
|
else upsert (k * 2024) v acc)
|
|
map IntMap.empty
|
|
|
|
let blink_times map times =
|
|
let rec loop acc times' =
|
|
match times' with 0 -> acc | t -> loop (blink acc) (t - 1)
|
|
in
|
|
loop map times
|
|
|
|
let print_map map = IntMap.iter (Printf.printf "Key: %d, Value: %d\n") map
|
|
|
|
let solve lines =
|
|
let line = List.nth lines 0 in
|
|
let nums = line_to_numbers line in
|
|
|
|
let filled_map =
|
|
List.fold_left
|
|
(fun acc i ->
|
|
IntMap.update i
|
|
(fun item ->
|
|
match item with None -> Some 1 | Some in_map -> Some (in_map + 1))
|
|
acc)
|
|
IntMap.empty nums
|
|
in
|
|
|
|
let part1 =
|
|
blink_times filled_map 25 |> IntMap.to_list
|
|
|> List.fold_left (fun acc (_, v) -> acc + v) 0
|
|
in
|
|
|
|
let part2 =
|
|
blink_times filled_map 75 |> IntMap.to_list
|
|
|> List.fold_left (fun acc (_, v) -> acc + v) 0
|
|
in
|
|
(part1, part2)
|