61 lines
2.1 KiB
OCaml
61 lines
2.1 KiB
OCaml
(** [next_char ch] returns the next character after [ch]. *)
|
|
let next_char ch = Char.chr (1 + Char.code ch)
|
|
|
|
(** [ten] really isn't the digit 10, but is the character after '9'. *)
|
|
let ten = next_char '9'
|
|
|
|
(** The character '1'. *)
|
|
let one = '1'
|
|
|
|
(** [find_trail grid pos0] returns a list of all end points of trails in [grid]
|
|
starting at [pos0]. [pos0] must point to a valid position that contains a
|
|
'0'. The same endpoint may be returned multiple times if there are multiple
|
|
routes to it. *)
|
|
let find_trail grid pos0 =
|
|
assert (Aoc.Grid.get_by_pos grid pos0 = '0');
|
|
let add_pos lst pos digit =
|
|
if Aoc.Grid.pos_is_valid grid pos && Aoc.Grid.get_by_pos grid pos = digit
|
|
then pos :: lst
|
|
else lst
|
|
in
|
|
let add_poses lst (x, y) digit =
|
|
let lst = add_pos lst (x - 1, y) digit in
|
|
let lst = add_pos lst (x + 1, y) digit in
|
|
let lst = add_pos lst (x, y - 1) digit in
|
|
let lst = add_pos lst (x, y + 1) digit in
|
|
lst
|
|
in
|
|
let rec find_next acc digit = function
|
|
| [] -> acc
|
|
| h :: t -> find_next (add_poses acc h digit) digit t
|
|
in
|
|
let rec impl acc digit =
|
|
if digit = ten then acc else impl (find_next [] digit acc) (next_char digit)
|
|
in
|
|
impl [ pos0 ] one
|
|
|
|
(** [find_trails grid] returns the list of list of end-points of trails starting
|
|
at each position in [grid]. The [n]th element of the returned list
|
|
corresponds to the trails starting at index [n]. *)
|
|
let find_trails grid =
|
|
let rec impl acc idx =
|
|
if idx >= Aoc.Grid.length grid then acc
|
|
else if Aoc.Grid.get_by_idx grid idx <> '0' then impl acc (idx + 1)
|
|
else (* grid_get_by_idx grid idx = 0 *)
|
|
impl (find_trail grid (Aoc.Grid.pos_of_idx grid idx) :: acc) (idx + 1)
|
|
in
|
|
impl [] 0 |> List.rev
|
|
|
|
(** [part sort_fn grid] returns a count of all trails in [grid], before counting
|
|
the trails for each grid index are sorted by [sort_fn]. *)
|
|
let part sort_fn grid =
|
|
find_trails grid |> List.map sort_fn |> List.map List.length
|
|
|> List.fold_left ( + ) 0
|
|
|
|
let _ =
|
|
Aoc.main Aoc.Grid.of_file
|
|
[
|
|
(string_of_int, part (List.sort_uniq Stdlib.compare));
|
|
(string_of_int, part Fun.id);
|
|
]
|