From 176c75fe292f259913f574b13835e6fb7b1aa494 Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Thu, 12 Dec 2024 10:00:57 -0500 Subject: [PATCH] 2024: d12: ex1: add solution --- 2024/d12/ex1/ex1.py | 67 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100755 2024/d12/ex1/ex1.py diff --git a/2024/d12/ex1/ex1.py b/2024/d12/ex1/ex1.py new file mode 100755 index 0000000..f65030c --- /dev/null +++ b/2024/d12/ex1/ex1.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +import sys +from collections.abc import Iterator +from typing import NamedTuple + + +class Point(NamedTuple): + x: int + y: int + + def neighbours(self) -> Iterator["Point"]: + for dx, dy in ( + (-1, 0), + (1, 0), + (0, -1), + (0, 1), + ): + yield Point(self.x + dx, self.y + dy) + + +def solve(input: str) -> int: + def parse(input: list[str]) -> dict[Point, str]: + return { + Point(x, y): c for x, line in enumerate(input) for y, c in enumerate(line) + } + + def find_plots(garden: dict[Point, str]) -> list[set[Point]]: + res: list[set[Point]] = [] + visited: set[Point] = set() + + for p, plant in garden.items(): + if p in visited: + continue + plot: set[Point] = set() + to_visit = {p} + while to_visit: + p = to_visit.pop() + visited.add(p) + plot.add(p) + assert garden[p] == plant # Sanity check + for n in p.neighbours(): + if garden.get(n) != plant: + continue + if n in visited: + continue + to_visit.add(n) + res.append(plot) + return res + + def fence_price(plot: set[Point]) -> int: + area = len(plot) + perimeter = sum(n not in plot for p in plot for n in p.neighbours()) + return area * perimeter + + garden = parse(input.splitlines()) + plots = find_plots(garden) + return sum(map(fence_price, plots)) + + +def main() -> None: + input = sys.stdin.read() + print(solve(input)) + + +if __name__ == "__main__": + main()