Tidy up 2024 day 11 code.
This commit is contained in:
@@ -1,13 +1,15 @@
|
|||||||
module IntMap = Map.Make (Int)
|
module IntMap = Map.Make (Int)
|
||||||
|
|
||||||
let load_file fname =
|
(** [apply_n n fn arg] is equivalent to [(fn (fn ... (fn (fn arg))))] where [fn]
|
||||||
match In_channel.with_open_text fname In_channel.input_line with
|
is called [n] times.*)
|
||||||
| Some x -> x
|
|
||||||
| None -> failwith "load_file"
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
(** [update_count n o] returns [Some n] if [o] is [None], or [Some (n + x)] if
|
||||||
|
[o] is [Some x]. *)
|
||||||
let update_count n = function None -> Some n | Some x -> Some (x + n)
|
let update_count n = function None -> Some n | Some x -> Some (x + n)
|
||||||
|
|
||||||
|
(** [map_of_ints lst] returns an [IntMap] with key-value pairs counting how many
|
||||||
|
times each integer appears in [lst]. *)
|
||||||
let map_of_ints =
|
let map_of_ints =
|
||||||
let rec impl acc = function
|
let rec impl acc = function
|
||||||
| [] -> acc
|
| [] -> acc
|
||||||
@@ -15,24 +17,21 @@ let map_of_ints =
|
|||||||
in
|
in
|
||||||
impl IntMap.empty
|
impl IntMap.empty
|
||||||
|
|
||||||
(** [calc_blink_rec acc lst] returns an updated map based off [acc] with the
|
(** [map_stone id n map] calculates how a collection of stones changes in a
|
||||||
result of apply a blink step to the stones in [lst]. Entries in [lst] are
|
blink, updating [map] with the result. [id] is the ID of the stone to
|
||||||
pairs of [(stone id, count)]. [acc] and the resulting map have keys which
|
update, [n] is how many stones there are with that ID. *)
|
||||||
are stone id, and values which are count. *)
|
let map_stone id n acc =
|
||||||
let rec calc_blink_rec acc = function
|
match id with
|
||||||
| [] -> acc
|
| 0 -> IntMap.update 1 (update_count n) acc
|
||||||
| (0, n) :: t -> calc_blink_rec (IntMap.update 1 (update_count n) acc) t
|
| x when Aoc.digits10 x mod 2 = 0 ->
|
||||||
| (x, n) :: t when Aoc.digits10 x mod 2 = 0 ->
|
|
||||||
let pow = Aoc.pow10 (Aoc.digits10 x / 2) in
|
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 / pow) (update_count n) acc in
|
||||||
let acc = IntMap.update (x mod pow) (update_count n) acc in
|
let acc = IntMap.update (x mod pow) (update_count n) acc in
|
||||||
calc_blink_rec acc t
|
acc
|
||||||
| (x, n) :: t ->
|
| x -> IntMap.update (x * 2024) (update_count n) acc
|
||||||
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.
|
(** [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
|
returning the result.
|
||||||
appears. The result is a map with similar key, value pairs.
|
|
||||||
|
|
||||||
This improves performance because we find that the transformation stones go
|
This improves performance because we find that the transformation stones go
|
||||||
through ends up producing repeated numbers. e.g.: 0 -> 1 -> 2024 -> 20 24 ->
|
through ends up producing repeated numbers. e.g.: 0 -> 1 -> 2024 -> 20 24 ->
|
||||||
@@ -41,13 +40,17 @@ let rec calc_blink_rec acc = function
|
|||||||
We also note that despite the problem description saying stones stay in
|
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
|
order, the result we are asked for (number of stones) does not require them
|
||||||
to be in order. *)
|
to be in order. *)
|
||||||
let calc_blink map = IntMap.to_list map |> calc_blink_rec IntMap.empty
|
let calc_blink map = IntMap.fold map_stone map IntMap.empty
|
||||||
|
|
||||||
(** [part n str] returns the number of stones after [n] blinks, given an initial
|
(** [part n lst] returns the number of stones after [n] blinks, given an initial
|
||||||
string [str] of space seperated stone IDs. *)
|
list, [lst], of stone IDs. *)
|
||||||
let part n str =
|
let part n lst =
|
||||||
let map = Aoc.ints_of_string str |> map_of_ints |> apply_n n calc_blink in
|
let map = map_of_ints lst |> apply_n n calc_blink in
|
||||||
IntMap.fold (fun _ v acc -> v + acc) map 0
|
IntMap.fold (fun _ v acc -> v + acc) map 0
|
||||||
|
|
||||||
|
(** [ints_of_file fname] returns the integers listed on the first line of
|
||||||
|
[fname]. *)
|
||||||
|
let ints_of_file fname = Aoc.string_of_file fname |> Aoc.ints_of_string
|
||||||
|
|
||||||
let _ =
|
let _ =
|
||||||
Aoc.main load_file [ (string_of_int, part 25); (string_of_int, part 75) ]
|
Aoc.main ints_of_file [ (string_of_int, part 25); (string_of_int, part 75) ]
|
||||||
|
@@ -6,6 +6,11 @@ let distance1 a b = abs (a - b)
|
|||||||
let strings_of_file fname =
|
let strings_of_file fname =
|
||||||
In_channel.with_open_text fname In_channel.input_lines
|
In_channel.with_open_text fname In_channel.input_lines
|
||||||
|
|
||||||
|
let string_of_file fname =
|
||||||
|
match In_channel.with_open_text fname In_channel.input_line with
|
||||||
|
| Some x -> x
|
||||||
|
| None -> failwith "Aoc.string_of_file"
|
||||||
|
|
||||||
let main prep parts =
|
let main prep parts =
|
||||||
try
|
try
|
||||||
match Sys.argv with
|
match Sys.argv with
|
||||||
|
@@ -9,6 +9,9 @@ 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 string_of_file : string -> string
|
||||||
|
(** [string_of_file fname] returns the first line in [fname]. *)
|
||||||
|
|
||||||
val log10i : int -> int
|
val log10i : int -> int
|
||||||
(** [log10i n] returns the floor of [(log10 (float_of_int n))]. [n] must be
|
(** [log10i n] returns the floor of [(log10 (float_of_int n))]. [n] must be
|
||||||
positive. *)
|
positive. *)
|
||||||
|
Reference in New Issue
Block a user