2024 day 5 both parts.

This commit is contained in:
2024-12-05 09:06:31 +00:00
parent 4d6a0683bf
commit 98a30229e4
2 changed files with 85 additions and 2 deletions

83
bin/day2405.ml Normal file
View File

@@ -0,0 +1,83 @@
module IntSet = Set.Make (Int)
module IntMap = Map.Make (Int)
(** [add_rule a b m] adds the rule that [a] must appear before [b] to the rule
map [m]. *)
let add_rule a b =
let update_rule = function
| None -> Some (IntSet.singleton b)
| Some s -> Some (IntSet.add b s)
in
IntMap.update a update_rule
(** [find_rule a b m] returns [true] if the rule map [m] says that [a] should
appear before [b]. *)
let find_rule a b m =
match IntMap.find_opt a m with
| Some s -> ( match IntSet.find_opt b s with Some _ -> true | None -> false)
| None -> false
(** [compare m a b] is a total ordering on pages in the rule map [m]. Returns
[-1] if [a] should appear before [b], [0] if [a = b], and [1] if [b] should
appear before [a]. *)
let compare m a b =
if a = b then 0
else if find_rule a b m then -1
else if find_rule b a m then 1
else failwith "compare"
(** [sort m pages] Sorts [pages] into the order required by the rule map [m]. *)
let sort m = List.sort (compare m)
(** [is_page_order_valid m pages] returns [true] iff the page ordering given in
[pages] is valid under the rule map [m]. *)
let rec is_page_order_valid m pages =
let rec impl h = function
| h' :: t -> find_rule h h' m && impl h t
| [] -> true
in
match pages with h :: t -> impl h t && is_page_order_valid m t | [] -> true
(** [parse_rules lst] parses the rules in the list [lst] stopping when
encountering an empty line. Returns a pair [(rule_map, tail)].
[tail] starts the line after the empty line. *)
let parse_rules =
let re = Str.regexp_string "|" in
let rec impl acc = function
| "" :: t -> (acc, t)
| [] -> failwith "parse_rules.impl"
| h :: t -> (
match List.map int_of_string (Str.split re h) with
| [ a; b ] -> impl (add_rule a b acc) t
| _ -> failwith "parse_rules.impl")
in
impl IntMap.empty
(** [parse_page_orders lst] parses a list of page orders. *)
let parse_page_orders =
let re = Str.regexp_string "," in
let rec impl acc = function
| [] -> acc
| h :: t -> impl (List.map int_of_string (Str.split re h) :: acc) t
in
impl []
(** Read a rule map and list of pages from the file [fname]. *)
let read_file fname =
let lst = Aoc.strings_of_file fname in
let rule_map, t = parse_rules lst in
let page_orders = parse_page_orders t in
(rule_map, page_orders)
let middle_elt lst = List.nth lst (List.length lst / 2)
let part1 (rule_map, page_orders) =
List.filter (is_page_order_valid rule_map) page_orders
|> List.map middle_elt |> List.fold_left ( + ) 0
let part2 (rule_map, page_orders) =
List.filter (fun lst -> not (is_page_order_valid rule_map lst)) page_orders
|> List.map (sort rule_map)
|> List.map middle_elt |> List.fold_left ( + ) 0
let _ = Aoc.main read_file [ (string_of_int, part1); (string_of_int, part2) ]

View File

@@ -1,4 +1,4 @@
(executables
(public_names day2401 day2402 day2403 day2404)
(names day2401 day2402 day2403 day2404)
(public_names day2401 day2402 day2403 day2404 day2405)
(names day2401 day2402 day2403 day2404 day2405)
(libraries str aoc))