Compare commits
3 Commits
b9e3907e4d
...
fcc4341237
Author | SHA1 | Date | |
---|---|---|---|
fcc4341237 | |||
2159a5fc5e | |||
8bfe33fece |
@@ -1,20 +1,6 @@
|
|||||||
let ints_of_file fname =
|
let ints_of_file fname =
|
||||||
Aoc.strings_of_file fname |> List.map (Aoc.ints_of_string ~sep:"[: ]+")
|
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
|
|
||||||
|
|
||||||
(** [check_add tgt v] Check to see if [X + v = tgt] is a valid operation. If not
|
(** [check_add tgt v] Check to see if [X + v = tgt] is a valid operation. If not
|
||||||
returns [None] otherwise returns [Some X]. *)
|
returns [None] otherwise returns [Some X]. *)
|
||||||
let check_add tgt v = if v > tgt then None else Some (tgt - v)
|
let check_add tgt v = if v > tgt then None else Some (tgt - v)
|
||||||
@@ -26,7 +12,7 @@ let check_mul tgt v = if tgt mod v = 0 then Some (tgt / v) else None
|
|||||||
(** [check_cat tgt v] Check to see if [X || v = tgt] is a valid operation. If
|
(** [check_cat tgt v] Check to see if [X || v = tgt] is a valid operation. If
|
||||||
not returns [None] otherwise returns [Some X]. *)
|
not returns [None] otherwise returns [Some X]. *)
|
||||||
let check_cat tgt v =
|
let check_cat tgt v =
|
||||||
let p = pow10 (1 + log10i v) in
|
let p = Aoc.pow10 (Aoc.digits10 v) in
|
||||||
if tgt mod p = v then Some (tgt / p) else None
|
if tgt mod p = v then Some (tgt / p) else None
|
||||||
|
|
||||||
(** [is_valid_target tgt nums ops] returns [true] if we can reach [tgt] from
|
(** [is_valid_target tgt nums ops] returns [true] if we can reach [tgt] from
|
||||||
|
@@ -1,47 +1,53 @@
|
|||||||
|
module IntMap = Map.Make (Int)
|
||||||
|
|
||||||
let load_file fname =
|
let load_file fname =
|
||||||
match In_channel.with_open_text fname In_channel.input_line with
|
match In_channel.with_open_text fname In_channel.input_line with
|
||||||
| Some x -> x
|
| Some x -> x
|
||||||
| None -> failwith "load_file"
|
| 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 rec apply_n n fn arg = if n <= 0 then arg else apply_n (n - 1) fn (fn arg)
|
||||||
|
let update_count n = function None -> Some n | Some x -> Some (x + n)
|
||||||
|
|
||||||
(*
|
let map_of_ints =
|
||||||
let print_int_list lst =
|
let rec impl acc = function
|
||||||
List.iter
|
|
||||||
(fun i ->
|
|
||||||
print_int i;
|
|
||||||
print_char ' ')
|
|
||||||
lst;
|
|
||||||
print_newline ();
|
|
||||||
()
|
|
||||||
*)
|
|
||||||
let calc n input =
|
|
||||||
let rec step_rec acc = function
|
|
||||||
| [] -> acc
|
| [] -> acc
|
||||||
| 0 :: t -> step_rec (1 :: acc) t
|
| h :: t -> impl (IntMap.update h (update_count 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
|
in
|
||||||
apply_n n (step_rec []) input
|
impl IntMap.empty
|
||||||
|
|
||||||
let part1 str = Aoc.ints_of_string str |> calc 25 |> List.length
|
(** [calc_blink_rec acc lst] returns an updated map based off [acc] with the
|
||||||
let part2 str = Aoc.ints_of_string str |> calc 75 |> List.length
|
result of apply a blink step to the stones in [lst]. Entries in [lst] are
|
||||||
let _ = Aoc.main load_file [ (string_of_int, part1); (string_of_int, part2) ]
|
pairs of [(stone id, count)]. [acc] and the resulting map have keys which
|
||||||
|
are stone id, and values which are count. *)
|
||||||
|
let rec calc_blink_rec acc = function
|
||||||
|
| [] -> acc
|
||||||
|
| (0, n) :: t -> calc_blink_rec (IntMap.update 1 (update_count n) acc) t
|
||||||
|
| (x, n) :: t when Aoc.digits10 x mod 2 = 0 ->
|
||||||
|
let pow = Aoc.pow10 (Aoc.digits10 x / 2) in
|
||||||
|
let acc = IntMap.update (x / pow) (update_count n) acc in
|
||||||
|
let acc = IntMap.update (x mod pow) (update_count n) acc in
|
||||||
|
calc_blink_rec acc t
|
||||||
|
| (x, n) :: t ->
|
||||||
|
calc_blink_rec (IntMap.update (x * 2024) (update_count n) acc) t
|
||||||
|
|
||||||
|
(** [calc_blink map] calculates how a collection of stones changes in a blink.
|
||||||
|
[map] is a map with key of stone ID, and value number of times that stone
|
||||||
|
appears. The result is a map with similar key, value pairs.
|
||||||
|
|
||||||
|
This improves performance because we find that the transformation stones go
|
||||||
|
through ends up producing repeated numbers. e.g.: 0 -> 1 -> 2024 -> 20 24 ->
|
||||||
|
2 0 2 4 which has two 2s in it.
|
||||||
|
|
||||||
|
We also note that despite the problem description saying stones stay in
|
||||||
|
order, the result we are asked for (number of stones) does not require them
|
||||||
|
to be in order. *)
|
||||||
|
let calc_blink map = IntMap.to_list map |> calc_blink_rec IntMap.empty
|
||||||
|
|
||||||
|
(** [part n str] returns the number of stones after [n] blinks, given an initial
|
||||||
|
string [str] of space seperated stone IDs. *)
|
||||||
|
let part n str =
|
||||||
|
let map = Aoc.ints_of_string str |> map_of_ints |> apply_n n calc_blink in
|
||||||
|
IntMap.fold (fun _ v acc -> v + acc) map 0
|
||||||
|
|
||||||
|
let _ =
|
||||||
|
Aoc.main load_file [ (string_of_int, part 25); (string_of_int, part 75) ]
|
||||||
|
15
lib/aoc.ml
15
lib/aoc.ml
@@ -66,3 +66,18 @@ module Grid = struct
|
|||||||
(String.sub grid.grid (idx + 1) (length grid - idx - 1));
|
(String.sub grid.grid (idx + 1) (length grid - idx - 1));
|
||||||
{ grid with grid = Buffer.contents builder }
|
{ grid with grid = Buffer.contents builder }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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 = function
|
||||||
|
| 0 -> 1
|
||||||
|
| n when n > 0 -> 1 + log10i n
|
||||||
|
| n (* when n < 0 *) -> 1 + log10i (-n)
|
||||||
|
|
||||||
|
let pow10 n =
|
||||||
|
let rec impl acc = function 0 -> acc | x -> impl (acc * 10) (x - 1) in
|
||||||
|
assert (n >= 0);
|
||||||
|
impl 1 n
|
||||||
|
11
lib/aoc.mli
11
lib/aoc.mli
@@ -9,6 +9,17 @@ val strings_of_file : string -> string list
|
|||||||
(** [strings_from_file fname] returns a list of strings from the file [fname].
|
(** [strings_from_file fname] returns a list of strings from the file [fname].
|
||||||
Each string represents a line from the file. *)
|
Each string represents a line from the file. *)
|
||||||
|
|
||||||
|
val log10i : int -> int
|
||||||
|
(** [log10i n] returns the floor of [(log10 (float_of_int n))]. [n] must be
|
||||||
|
positive. *)
|
||||||
|
|
||||||
|
val digits10 : int -> int
|
||||||
|
(** [digits10 n] returns the number of base-10 digits in [n]. *)
|
||||||
|
|
||||||
|
val pow10 : int -> int
|
||||||
|
(** [pow10 n] returns [int_of_float (10. ** float_of_int n)]. [n] must be
|
||||||
|
non-negative. *)
|
||||||
|
|
||||||
val main : (string -> 'a) -> (('b -> string) * ('a -> 'b)) list -> unit
|
val main : (string -> 'a) -> (('b -> string) * ('a -> 'b)) list -> unit
|
||||||
(** [main prep parts] executes an advent of code problem. [prep fname] should be
|
(** [main prep parts] executes an advent of code problem. [prep fname] should be
|
||||||
a function that returns the input from [fname]. Each elemet of [parts] is a
|
a function that returns the input from [fname]. Each elemet of [parts] is a
|
||||||
|
Reference in New Issue
Block a user