46 lines
1.5 KiB
OCaml
46 lines
1.5 KiB
OCaml
(** [towels_of_strings lst] returns a pair containing a list of available towels
|
|
and a list of patterns wanted. *)
|
|
let towels_of_strings = function
|
|
| h :: "" :: t ->
|
|
let re = Str.regexp "[, ]+" in
|
|
let h = Str.split re h in
|
|
(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
|
|
|
|
(** [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 count_matched = function
|
|
| [] -> 0
|
|
| h :: t ->
|
|
let towel_len = String.length h in
|
|
if String.starts_with ~prefix:h pattern then
|
|
Aoc.memoize memo
|
|
(count_matches memo towels)
|
|
(String.sub pattern towel_len (pattern_len - towel_len))
|
|
+ count_matched t
|
|
else count_matched t
|
|
in
|
|
if pattern_len = 0 then 1 else count_matched towels
|
|
|
|
let part1 (towels, patterns) =
|
|
List.map (Aoc.memoize memo (count_matches memo towels)) patterns
|
|
|> List.filter (( < ) 0)
|
|
|> List.length
|
|
|
|
let part2 (towels, patterns) =
|
|
List.map (Aoc.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) ]
|