|
| 1 | +from operator import attrgetter, itemgetter |
| 2 | + |
| 3 | +from utils.file import read_input |
| 4 | + |
| 5 | +plots = {complex(x, y): c for y, line in enumerate(read_input(__package__)) for x, c in enumerate(line)} |
| 6 | + |
| 7 | + |
| 8 | +def flood(start: complex) -> tuple[str, set[complex]]: |
| 9 | + region_name = plots[start] |
| 10 | + visited: set[complex] = set() |
| 11 | + queue: list[complex] = [start] |
| 12 | + while queue: |
| 13 | + current = queue.pop() |
| 14 | + if current in visited or plots.get(current) != region_name: |
| 15 | + continue |
| 16 | + visited.add(current) |
| 17 | + queue.extend(current + d for d in {-1, 1, -1j, 1j}) |
| 18 | + return region_name, visited |
| 19 | + |
| 20 | + |
| 21 | +def perimeter(region: set[complex]) -> int: |
| 22 | + return sum(plot + d not in region for plot in region for d in {-1, 1, -1j, 1j}) |
| 23 | + |
| 24 | + |
| 25 | +def find_regions() -> list[tuple[str, set[complex]]]: |
| 26 | + visited_plots: set[complex] = set() |
| 27 | + result: list[tuple[str, set[complex]]] = [] |
| 28 | + |
| 29 | + sorted_plots = sorted(plots, key=lambda p: (p.real, p.imag)) |
| 30 | + while sorted_plots: |
| 31 | + current = sorted_plots.pop() |
| 32 | + if current in visited_plots: |
| 33 | + continue |
| 34 | + name, region = flood(current) |
| 35 | + visited_plots |= region |
| 36 | + result.append((name, region)) |
| 37 | + |
| 38 | + return result |
| 39 | + |
| 40 | + |
| 41 | +regions = find_regions() |
| 42 | +print("Part1:", sum(perimeter(region) * len(region) for _, region in regions)) |
0 commit comments