69 lines
2.0 KiB
OCaml

type equation = { equals : int; numbers : int list }
let rec print_list l =
match l with
| [] -> print_endline ""
| head :: tail ->
print_int head;
print_string ",";
print_list tail
let equation_from_line line =
let first_num = Scanf.sscanf line "%d:" (fun n1 -> n1) in
let rest_of_numbers =
List.nth (String.split_on_char ':' line) 1
|> String.trim |> String.split_on_char ' '
in
let numbers = List.map int_of_string rest_of_numbers in
{ equals = first_num; numbers }
let attempt_solve { equals; numbers } =
(* [1, 2] *)
let rec loop numbers =
match numbers with
| head :: [] -> [ head ]
| head :: tail ->
let plus = List.map (fun i -> i + head) (loop tail) in
let times = List.map (fun i -> i * head) (loop tail) in
plus @ times
| _ -> raise (Invalid_argument "")
in
let possibilities = loop (List.rev numbers) in
if List.exists (fun i -> i == equals) possibilities then equals else 0
let attempt_solve_part2 { equals; numbers } =
(* [1, 2] *)
let rec loop numbers =
match numbers with
| head :: [] -> [ head ]
| head :: tail ->
let below_solution = List.filter (fun i -> i <= equals) (loop tail) in
let plus = List.map (fun i -> i + head) below_solution in
let times = List.map (fun i -> i * head) below_solution in
let concat =
List.map
(fun i ->
let i_string = string_of_int i in
let head_string = string_of_int head in
int_of_string (i_string ^ head_string))
below_solution
in
plus @ times @ concat
| _ -> raise (Invalid_argument "")
in
let possibilities = loop (List.rev numbers) in
if List.exists (fun i -> i == equals) possibilities then equals else 0
let solve lines =
let part1 =
List.fold_left
(fun acc line -> acc + (equation_from_line line |> attempt_solve))
0 lines
in
let part2 =
List.fold_left
(fun acc line -> acc + (equation_from_line line |> attempt_solve_part2))
0 lines
in
(part1, part2)