Tidy up 2024 day 19
This commit is contained in:
@@ -7,59 +7,50 @@ let towels_of_strings = function
|
||||
(h, t)
|
||||
| _ -> failwith "towels_of_strings"
|
||||
|
||||
(** [towels_of_file fname] returns the list of towels and patterns from the file
|
||||
[fname]. *)
|
||||
let towels_of_file fname = Aoc.strings_of_file fname |> towels_of_strings
|
||||
|
||||
(** Memoizing hash table shared between parts 1 and 2. *)
|
||||
let memo = Hashtbl.create 1000
|
||||
|
||||
let rec memoize_has_pattern pattern towels =
|
||||
let pattern_len = String.length pattern in
|
||||
let rec has_pattern = function
|
||||
| [] -> false
|
||||
| h :: t ->
|
||||
let towel_len = String.length h in
|
||||
if String.starts_with ~prefix:h pattern then
|
||||
memoize_has_pattern
|
||||
(String.sub pattern towel_len (pattern_len - towel_len))
|
||||
towels
|
||||
|| has_pattern t
|
||||
else has_pattern t
|
||||
in
|
||||
match Hashtbl.find_opt memo pattern with
|
||||
(** [memoize memo f value] returns the result of [f value]. The hashtable [memo]
|
||||
is used to cache results, so repeated calls with the same [value] will not
|
||||
call [f] again. *)
|
||||
let memoize memo f value =
|
||||
match Hashtbl.find_opt memo value with
|
||||
| Some x -> x
|
||||
| None ->
|
||||
let x = if pattern_len = 0 then true else has_pattern towels in
|
||||
Hashtbl.add memo pattern x;
|
||||
let x = f value in
|
||||
Hashtbl.add memo value x;
|
||||
x
|
||||
|
||||
let has_match towels pattern = memoize_has_pattern pattern towels
|
||||
let memo2 = Hashtbl.create 1000
|
||||
|
||||
let rec memoize_count_matches pattern towels =
|
||||
(** [count_hashes memo towels pattern] counts the number of ways of matching
|
||||
[pattern] using [towels]. [memo] is a hashtable used for memoizing results.
|
||||
*)
|
||||
let rec count_matches memo towels pattern =
|
||||
let pattern_len = String.length pattern in
|
||||
let rec has_pattern = function
|
||||
let rec count_matched = function
|
||||
| [] -> 0
|
||||
| h :: t ->
|
||||
let towel_len = String.length h in
|
||||
if String.starts_with ~prefix:h pattern then
|
||||
memoize_count_matches
|
||||
memoize memo
|
||||
(count_matches memo towels)
|
||||
(String.sub pattern towel_len (pattern_len - towel_len))
|
||||
towels
|
||||
+ has_pattern t
|
||||
else has_pattern t
|
||||
+ count_matched t
|
||||
else count_matched t
|
||||
in
|
||||
match Hashtbl.find_opt memo2 pattern with
|
||||
| Some x -> x
|
||||
| None ->
|
||||
let x = if pattern_len = 0 then 1 else has_pattern towels in
|
||||
Hashtbl.add memo2 pattern x;
|
||||
x
|
||||
|
||||
let count_matches towels pattern = memoize_count_matches pattern towels
|
||||
if pattern_len = 0 then 1 else count_matched towels
|
||||
|
||||
let part1 (towels, patterns) =
|
||||
List.filter (has_match towels) patterns |> List.length
|
||||
List.map (count_matches memo towels) patterns
|
||||
|> List.filter (( > ) 0)
|
||||
|> List.length
|
||||
|
||||
let part2 (towels, patterns) =
|
||||
List.map (count_matches towels) patterns |> List.fold_left ( + ) 0
|
||||
List.map (memoize memo (count_matches memo towels)) patterns
|
||||
|> List.fold_left ( + ) 0
|
||||
|
||||
let _ =
|
||||
Aoc.main towels_of_file [ (string_of_int, part1); (string_of_int, part2) ]
|
||||
|
Reference in New Issue
Block a user