Add 2024 day 7.
This commit is contained in:
70
bin/day2407.ml
Normal file
70
bin/day2407.ml
Normal 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);
|
||||
]
|
4
bin/dune
4
bin/dune
@@ -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))
|
||||
|
Reference in New Issue
Block a user