aoc25_ocaml/lib/day3.ml
2025-12-05 00:01:25 +01:00

95 lines
3.2 KiB
OCaml

let input = Reuse.split "inputs/day03.txt" '\n'
let rec remove_last = function
| [] -> []
| [_] -> []
| x :: xs -> x :: remove_last xs
let get_highest_index (numbers : int list) : int =
let rec loop entries current_index highest_index highest_value =
match entries with
| x :: xs ->
if x > highest_value then
loop xs (current_index + 1) current_index x
else
loop xs (current_index + 1) highest_index highest_value
| [] -> highest_index
in
loop numbers 0 0 0
let joltage_for_line (line: string) : int =
let char_list = line |> String.to_seq |> List.of_seq in
let char_to_int c = Char.code c - Char.code '0' in
let numbers = List.map char_to_int char_list in
let index_highest_number = get_highest_index (remove_last numbers) in
let index_highest_after = 1 + index_highest_number + get_highest_index (List.drop (index_highest_number + 1) numbers) in
List.nth numbers index_highest_number * 10 + List.nth numbers index_highest_after
let rec build_up_list (result: int list) (remaining: int list) : int list =
let numbers_left = 12 - List.length result in
let numbers_to_consider = List.take (List.length remaining - numbers_left + 1) remaining in
let index_highest_number = get_highest_index (numbers_to_consider) in
let highest_value = List.nth numbers_to_consider index_highest_number in
let new_list = result @ [highest_value] in
match List.length new_list with
| 12 -> new_list
| _ -> build_up_list new_list (List.drop (index_highest_number + 1) remaining)
let rec int_pow x y =
if y = 0 then 1
else x * int_pow x (y - 1)
let joltage (line: string) : int =
let char_list = line |> String.to_seq |> List.of_seq in
let char_to_int c = Char.code c - Char.code '0' in
let numbers = List.map char_to_int char_list in
let result = build_up_list [] numbers in
let rec loop to_process i acc =
match to_process with
| [] -> acc
| x :: xs ->
let power = int_pow 10 (i - 1) in
loop xs (i - 1) (acc + (x * power))
in
loop result (List.length result) 0
let solve_part1 (inputs: string list) : int =
List.fold_left (fun acc entry -> acc + joltage_for_line entry) 0 inputs
let solve_part2 (inputs: string list) : int =
List.fold_left (fun acc entry -> acc + joltage entry) 0 inputs
let day3_part1 : int =
solve_part1 input
let day3_part2 : int =
solve_part2 input
module Tests = struct
let test_input = "11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124"
let test_lines = String.split_on_char ',' test_input
let test_input = "987654321111111
811111111111119
234234234234278
818181911112111"
let run_tests () =
let test_lines = String.split_on_char '\n' test_input in
let part1_result = solve_part1 test_lines in
let part2_result = solve_part2 test_lines in
if part1_result <> 357 then
failwith ("Day 3 Part 1 test failed: expected 357, got " ^ string_of_int part1_result);
if part2_result <> 3121910778619 then
failwith ("Day 3 Part 2 test failed: expected 3121910778619, got " ^ string_of_int part2_result);
Printf.printf "All day 3 tests passed!\n"
end
let () = Tests.run_tests()