Add 2024 day 7.

This commit is contained in:
2024-12-07 07:29:03 +00:00
parent 831bbf4f63
commit 8a454e2082
2 changed files with 72 additions and 2 deletions

70
bin/day2407.ml Normal file
View File

@@ -0,0 +1,70 @@
let ints_of_file fname =
Aoc.strings_of_file fname |> List.map (Aoc.ints_of_string ~sep:"[: ]+")
(** [log10i i] returns the integer part of [log10 i]. [i] must be greater than
zero. *)
let log10i i =
let rec impl acc = function 0 -> acc | x -> impl (acc + 1) (x / 10) in
assert (i > 0);
impl ~-1 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
(** [is_valid_target1 tgt nums] checks to see if we can reach [tgt] from [nums]
using multiply and addition only. [nums] should be in reverse order to that
given in the problem. *)
let rec is_valid_target1 tgt nums =
(* We work backwards from the target and note that:
- if we ever go negative then the route we have taken is invalid
- we can only multiply if dividing the tgt by a number results in no
remainder.
*)
if tgt < 0 then false
else
match nums with
| [] -> tgt = 0
| h :: t ->
let sum_valid = is_valid_target1 (tgt - h) t in
if tgt mod h = 0 then sum_valid || is_valid_target1 (tgt / h) t
else sum_valid
(** [is_valid_target2 tgt nums] checks to see if we can reach [tgt] from [nums]
using multiply, addition and "merger" only. [nums] should be in reverse
order to that given in the problem. *)
let rec is_valid_target2 tgt nums =
(* Same principle as [is_valid_target1], but also noting that merger op is
only possible if the last digits of the current [tgt] are the same as the
number being examined. *)
if tgt < 0 then false
else
match nums with
| [] -> tgt = 0
| h :: t ->
let sum_valid = is_valid_target2 (tgt - h) t in
let p = pow10 (1 + log10i h) in
let merge_valid =
if tgt mod p = h then is_valid_target2 (tgt / p) t else false
in
if tgt mod h = 0 then
sum_valid || merge_valid || is_valid_target2 (tgt / h) t
else sum_valid || merge_valid
let check_target checker = function
| [] -> false
| h :: t -> checker h (List.rev t)
let part checker lst =
List.filter (check_target checker) lst
|> List.map List.hd |> List.fold_left ( + ) 0
let _ =
Aoc.main ints_of_file
[
(string_of_int, part is_valid_target1);
(string_of_int, part is_valid_target2);
]

View File

@@ -1,4 +1,4 @@
(executables
(public_names day2401 day2402 day2403 day2404 day2405 day2406)
(names day2401 day2402 day2403 day2404 day2405 day2406)
(public_names day2401 day2402 day2403 day2404 day2405 day2406 day2407)
(names day2401 day2402 day2403 day2404 day2405 day2406 day2407)
(libraries str aoc))