summaryrefslogtreecommitdiff
path: root/2025/ocaml/lib/application/d04p02.ml
blob: 75b123646a71bc4367a96d5a146e5a659f3fcb2a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
open Domain

let err_empty_input = "input is empty"

let rec count_accessible_rolls matrix =
  let count_paper lst = List.length @@ List.filter (fun c -> c = "@") lst in
  let accessible_rolls_of_paper = ref [] in
  let no_change = ref false in
  while not !no_change do
    let accessible_rolls_of_paper' = !accessible_rolls_of_paper in
    count_accessible_rolls_aux matrix count_paper accessible_rolls_of_paper ;
    if
      List.length accessible_rolls_of_paper'
      = List.length !accessible_rolls_of_paper
    then no_change := true
  done ;
  List.length !accessible_rolls_of_paper

and count_accessible_rolls_aux matrix count_paper accessible_rolls_of_paper =
  for y = 0 to Array.length matrix - 1 do
    for x = 0 to Array.length matrix.(y) - 1 do
      if matrix.(y).(x) = "." then ()
      else
        let neighbour_coords = Matrix.M.get_valid_neighbours matrix x y in
        let neighbours =
          List.map (fun (nx, ny) -> Matrix.M.get matrix nx ny) neighbour_coords
        in
        let paper_count = count_paper neighbours in
        let is_accessible = paper_count < 4 in
        if is_accessible then
          accessible_rolls_of_paper := (x, y) :: !accessible_rolls_of_paper ;
        print_iteration_debug_msg x y neighbour_coords neighbours paper_count
          is_accessible
    done
  done ;
  List.iter
    (fun (x', y') -> Matrix.M.set matrix x' y' ".")
    !accessible_rolls_of_paper

and print_iteration_debug_msg x y neighbour_coords neighbours paper_count
    is_accessible =
  Logs.debug (fun m ->
      m
        "coords=(%d,%d) neighbour_coords=[%s] neighbours=[%s] paper=%d \
         is_accessible=%B"
        x y
        (List.fold_left
           (fun acc (x, y) ->
             if acc = "" then
               " (" ^ string_of_int x ^ "," ^ string_of_int y ^ "); "
             else acc ^ "(" ^ string_of_int x ^ "," ^ string_of_int y ^ "); " )
           "" neighbour_coords )
        (List.fold_left
           (fun acc neighbour ->
             if acc = "" then " " ^ neighbour ^ "; " else acc ^ neighbour ^ "; " )
           "" neighbours )
        paper_count is_accessible )

let solve input () =
  if input = "" then Error err_empty_input
  else
    let matrix = Matrix.M.of_string input in
    let accessible_rolls_of_paper = count_accessible_rolls matrix in
    Ok accessible_rolls_of_paper