Skip to content

Commit e406ad8

Browse files
committed
AoC 2024 Day 12 - cleanup
1 parent c8f9d44 commit e406ad8

File tree

1 file changed

+51
-113
lines changed

1 file changed

+51
-113
lines changed

src/main/python/AoC2024_12.py

Lines changed: 51 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,26 @@
55

66
import sys
77
from collections import defaultdict
8+
from typing import Callable
9+
from typing import Iterator
810

911
from aoc.common import InputData
1012
from aoc.common import SolutionBase
1113
from aoc.common import aoc_samples
1214
from aoc.geometry import Direction
1315
from aoc.graph import flood_fill
1416
from aoc.grid import Cell
15-
from aoc.grid import CharGrid
1617

17-
Input = CharGrid
18+
Input = InputData
1819
Output1 = int
1920
Output2 = int
2021

22+
CORNER_DIRS = [
23+
[Direction.LEFT_AND_UP, Direction.LEFT, Direction.UP],
24+
[Direction.RIGHT_AND_UP, Direction.RIGHT, Direction.UP],
25+
[Direction.RIGHT_AND_DOWN, Direction.RIGHT, Direction.DOWN],
26+
[Direction.LEFT_AND_DOWN, Direction.LEFT, Direction.DOWN],
27+
]
2128

2229
TEST1 = """\
2330
AAAA
@@ -63,118 +70,49 @@
6370

6471
class Solution(SolutionBase[Input, Output1, Output2]):
6572
def parse_input(self, input_data: InputData) -> Input:
66-
return CharGrid.from_strings(list(input_data))
67-
68-
def get_regions(self, grid: CharGrid) -> dict[str, list[set[Cell]]]:
69-
p = defaultdict[str, set[Cell]](set)
70-
for plot in grid.get_cells():
71-
p[grid.get_value(plot)].add(plot)
72-
regions = defaultdict[str, list[set[Cell]]](list)
73-
for k, all_p in p.items():
74-
while all_p:
75-
r = flood_fill(
76-
next(iter(all_p)),
77-
lambda cell: (
78-
n
79-
for n in grid.get_capital_neighbours(cell)
80-
if n in all_p
81-
),
82-
)
83-
regions[k].append(r)
84-
all_p -= r
85-
return regions
86-
87-
def part_1(self, grid: Input) -> Output1:
88-
regions = self.get_regions(grid)
89-
d = list[list[int]]()
90-
for plant in regions:
91-
for region in regions[plant]:
92-
dd = list[int]()
93-
for plot in region:
94-
c = 4
95-
for n in grid.get_capital_neighbours(plot):
96-
if grid.get_value(n) == plant:
97-
c -= 1
98-
dd.append(c)
99-
d.append(dd)
100-
return sum(len(dd) * sum(dd) for dd in d)
101-
102-
def part_2(self, grid: Input) -> Output2:
103-
def count_corners(plot: Cell, region: set[Cell]) -> int:
104-
ans = 0
105-
DO = [
106-
[Direction.LEFT, Direction.LEFT_AND_UP, Direction.UP],
107-
[Direction.UP, Direction.RIGHT_AND_UP, Direction.RIGHT],
108-
[Direction.RIGHT, Direction.RIGHT_AND_DOWN, Direction.DOWN],
109-
[Direction.DOWN, Direction.LEFT_AND_DOWN, Direction.LEFT],
110-
]
111-
for d in DO:
112-
o = list(
113-
filter(
114-
lambda n: n in region, map(lambda dd: plot.at(dd), d)
73+
return input_data
74+
75+
def solve(
76+
self, input: Input, count: Callable[[Cell, set[Cell]], int]
77+
) -> int:
78+
def get_regions(input: Input) -> Iterator[set[Cell]]:
79+
plots_by_plant = defaultdict[str, set[Cell]](set)
80+
for r, row in enumerate(input):
81+
for c, plant in enumerate(row):
82+
plots_by_plant[plant].add(Cell(r, c))
83+
for all_plots_with_plant in plots_by_plant.values():
84+
while all_plots_with_plant:
85+
region = flood_fill(
86+
next(iter(all_plots_with_plant)),
87+
lambda cell: (
88+
n
89+
for n in cell.get_capital_neighbours()
90+
if n in all_plots_with_plant
91+
),
11592
)
116-
)
117-
if len(o) == 0:
118-
ans += 1
119-
if (
120-
plot.at(Direction.LEFT_AND_DOWN) not in region
121-
and plot.at(Direction.LEFT) in region
122-
and plot.at(Direction.DOWN) in region
123-
):
124-
ans += 1
125-
if (
126-
plot.at(Direction.LEFT_AND_UP) not in region
127-
and plot.at(Direction.LEFT) in region
128-
and plot.at(Direction.UP) in region
129-
):
130-
ans += 1
131-
if (
132-
plot.at(Direction.RIGHT_AND_DOWN) not in region
133-
and plot.at(Direction.RIGHT) in region
134-
and plot.at(Direction.DOWN) in region
135-
):
136-
ans += 1
137-
if (
138-
plot.at(Direction.RIGHT_AND_UP) not in region
139-
and plot.at(Direction.RIGHT) in region
140-
and plot.at(Direction.UP) in region
141-
):
142-
ans += 1
143-
if (
144-
plot.at(Direction.LEFT_AND_DOWN) in region
145-
and plot.at(Direction.LEFT) not in region
146-
and plot.at(Direction.DOWN) not in region
147-
):
148-
ans += 1
149-
if (
150-
plot.at(Direction.LEFT_AND_UP) in region
151-
and plot.at(Direction.LEFT) not in region
152-
and plot.at(Direction.UP) not in region
153-
):
154-
ans += 1
155-
if (
156-
plot.at(Direction.RIGHT_AND_DOWN) in region
157-
and plot.at(Direction.RIGHT) not in region
158-
and plot.at(Direction.DOWN) not in region
159-
):
160-
ans += 1
161-
if (
162-
plot.at(Direction.RIGHT_AND_UP) in region
163-
and plot.at(Direction.RIGHT) not in region
164-
and plot.at(Direction.UP) not in region
165-
):
166-
ans += 1
167-
return ans
168-
169-
d = list[list[int]]()
170-
regions = self.get_regions(grid)
171-
for plant in regions:
172-
for region in regions[plant]:
173-
dd = list[int]()
174-
for plot in region:
175-
dd.append(count_corners(plot, region))
176-
d.append(dd)
177-
return sum(len(dd) * sum(dd) for dd in d)
93+
yield region
94+
all_plots_with_plant -= region
95+
96+
return sum(
97+
sum(count(plot, region) for plot in region) * len(region)
98+
for region in get_regions(input)
99+
)
100+
101+
def part_1(self, input: Input) -> Output1:
102+
def count_edges(plot: Cell, region: set[Cell]) -> int:
103+
return 4 - sum(n in region for n in plot.get_capital_neighbours())
104+
105+
return self.solve(input, count_edges)
106+
107+
def part_2(self, input: Input) -> Output2:
108+
def count_corners(plot: Cell, region: set[Cell]) -> int:
109+
return sum(
110+
tuple(1 if plot.at(d[i]) in region else 0 for i in range(3))
111+
in ((0, 0, 0), (1, 0, 0), (0, 1, 1))
112+
for d in CORNER_DIRS
113+
)
114+
115+
return self.solve(input, count_corners)
178116

179117
@aoc_samples(
180118
(

0 commit comments

Comments
 (0)