diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/day04.ml | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/lib/day04.ml b/lib/day04.ml new file mode 100644 index 0000000..c4c3b78 --- /dev/null +++ b/lib/day04.ml @@ -0,0 +1,62 @@ +(* + * SPDX-FileCopyrightText: Copyright 2025 Alexandre Jesus <https://adbjesus.com> + * + * SPDX-License-Identifier: GPL-3.0-or-later + *) + +let parse_data ch = + In_channel.input_all ch + |> String.trim + |> String.split_on_char '\n' + |> List.mapi (fun i s -> (i, s)) + |> List.to_seq + |> Seq.flat_map (fun (i, s) -> + String.to_seq s + |> Seq.mapi (fun j v -> (j, v = '@')) + |> Seq.filter_map (fun (j, p) -> if p then Some ((i, j), 0) else None)) + |> Hashtbl.of_seq + +let neighs = + [ (-1, -1); (-1, 0); (-1, 1); (0, -1); (0, 1); (1, -1); (1, 0); (1, 1) ] + +let neighs (i, j) = List.map (fun (a, b) -> (i + a, j + b)) neighs +let count tbl k = (k, neighs k |> List.filter (Hashtbl.mem tbl) |> List.length) +let counts tbl = Hashtbl.to_seq_keys tbl |> Seq.map (count tbl) + +let part1 ch = + parse_data ch + |> counts + |> Seq.filter (fun (_, v) -> v < 4) + |> Seq.length + |> Printf.printf "%d\n" + +let part2 ch = + let tbl = parse_data ch |> counts |> Hashtbl.of_seq in + let rec fn acc s = + let test k = + match Hashtbl.find_opt tbl k with + | None -> None + | Some v when v = 4 -> + Hashtbl.remove tbl k; + Some k + | Some v -> + Hashtbl.replace tbl k (v - 1); + None + in + match s with + | [] -> acc + | h :: t -> + neighs h + |> List.filter_map test + |> List.fold_left (fun (acc, s) k -> (acc + 1, k :: s)) (acc, t) + |> fun (acc, s) -> fn acc s + in + Hashtbl.to_seq tbl + |> List.of_seq + |> List.filter_map (fun (k, v) -> + if v < 4 then ( + Hashtbl.remove tbl k; + Some k) + else None) + |> (fun s -> fn (List.length s) s) + |> Printf.printf "%d\n" |
