let load_file fname = match In_channel.with_open_text fname In_channel.input_line with | Some x -> x | None -> failwith "load_file" let log10i i = let rec impl acc = function 0 -> acc | x -> impl (acc + 1) (x / 10) in assert (i > 0); impl ~-1 i let digits10 i = 1 + log10i i (** [pow10 n] returns [10] raised to the [n]th power. [n] must be non-negative. *) let pow10 n = let rec impl acc = function 0 -> acc | x -> impl (acc * 10) (x - 1) in assert (n >= 0); impl 1 n let rec apply_n n fn arg = if n <= 0 then arg else apply_n (n - 1) fn (fn arg) (* let print_int_list lst = List.iter (fun i -> print_int i; print_char ' ') lst; print_newline (); () *) let calc n input = let rec step_rec acc = function | [] -> acc | 0 :: t -> step_rec (1 :: acc) t | x :: t when digits10 x mod 2 = 0 -> let pow = pow10 (digits10 x / 2) in let left = x / pow in let right = x mod pow in step_rec (right :: left :: acc) t | x :: t -> step_rec ((x * 2024) :: acc) t in apply_n n (step_rec []) input let part1 str = Aoc.ints_of_string str |> calc 25 |> List.length let part2 str = Aoc.ints_of_string str |> calc 75 |> List.length let _ = Aoc.main load_file [ (string_of_int, part1); (string_of_int, part2) ]