Tidy up 2024 day 19

This commit is contained in:
2024-12-19 11:31:44 +00:00
parent 4c9ae83184
commit 4f963e0f98

View File

@@ -7,59 +7,50 @@ let towels_of_strings = function
(h, t) (h, t)
| _ -> failwith "towels_of_strings" | _ -> 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 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 memo = Hashtbl.create 1000
let rec memoize_has_pattern pattern towels = (** [memoize memo f value] returns the result of [f value]. The hashtable [memo]
let pattern_len = String.length pattern in is used to cache results, so repeated calls with the same [value] will not
let rec has_pattern = function call [f] again. *)
| [] -> false let memoize memo f value =
| h :: t -> match Hashtbl.find_opt memo value with
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
| Some x -> x | Some x -> x
| None -> | None ->
let x = if pattern_len = 0 then true else has_pattern towels in let x = f value in
Hashtbl.add memo pattern x; Hashtbl.add memo value x;
x x
let has_match towels pattern = memoize_has_pattern pattern towels (** [count_hashes memo towels pattern] counts the number of ways of matching
let memo2 = Hashtbl.create 1000 [pattern] using [towels]. [memo] is a hashtable used for memoizing results.
*)
let rec memoize_count_matches pattern towels = let rec count_matches memo towels pattern =
let pattern_len = String.length pattern in let pattern_len = String.length pattern in
let rec has_pattern = function let rec count_matched = function
| [] -> 0 | [] -> 0
| h :: t -> | h :: t ->
let towel_len = String.length h in let towel_len = String.length h in
if String.starts_with ~prefix:h pattern then 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)) (String.sub pattern towel_len (pattern_len - towel_len))
towels + count_matched t
+ has_pattern t else count_matched t
else has_pattern t
in in
match Hashtbl.find_opt memo2 pattern with if pattern_len = 0 then 1 else count_matched towels
| 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
let part1 (towels, patterns) = 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) = 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 _ = let _ =
Aoc.main towels_of_file [ (string_of_int, part1); (string_of_int, part2) ] Aoc.main towels_of_file [ (string_of_int, part1); (string_of_int, part2) ]