advent-of-code/2024-python/output/day_12.py
Anders Englöf Ytterström 9a7a9c878b Solve 2024:12 p2 "Garden Groups"
Funny that original 2023 day 5 also was a PITA
to figure out.

Pt 1 was solved using BFS to flood-fill. After
trying some different methods for pt 2, including:

- wallcrawling,
- side couting,
- corner counting

I never produced code to get past the test cases.

- Wall crawling are hard due to overlapping
regions.
- corner couting and side counting are both hard,
but will act as equally good solutions (since side
count equals corner count).
- Concave corners are hard, convex corners are
easy.

The final code is based on the posts on the
solutions megathread. Changes:

- Keep all areas in a set, defining a region.
- find all convex and concave corners in each
region.

A new helper got introduced: Di, storing all
diagonal neighbors for grid traversing.

Convex corners:

..  R.  .R  ..
R.  ..  ..  .R

Concave corners:

RR  .R  R.  RR
.R  RR  RR  R.
2025-01-05 00:06:18 +01:00

73 lines
2.2 KiB
Python

from collections import deque
from output import D, Di, cw, matrix
def solve(data):
grid, H, W = matrix(data)
fence_cost = 0
fence_cost_w_discount = 0
seen = set()
for r in range(H):
for c in range(W):
if (r, c) in seen:
continue
id = grid[r][c]
regions = set()
perimeters = 0
q = deque([(r, c)])
while q:
rc = q.popleft()
if rc in seen:
continue
seen.add(rc)
regions.add(rc)
y, x = rc
for delta_y, delta_x in D:
yn, xn = y + delta_y, x + delta_x
if (0 <= yn < H and 0 <= xn < W) and grid[yn][xn] == id:
q.append((yn, xn))
else:
perimeters += 1
if len(regions) <= 2:
corners = 4
else:
corners = count_corners(regions)
fence_cost += len(regions) * perimeters
fence_cost_w_discount += len(regions) * corners
return fence_cost, fence_cost_w_discount
def count_corners(region):
corners = 0
for y, x in region:
for delta_y, delta_x in D:
# convex corners: one horisontal and one vertical
# neighbor are not members of region
delta_ycw, delta_xcw = cw(delta_y, delta_x)
if (y + delta_y, x + delta_x) not in region and (
y + delta_ycw,
x + delta_xcw,
) not in region:
corners += 1
for delta_y, delta_x in Di:
# concave corners: the diagonal neighbor are not
# member of region, but the connected horisontal
# and vertical neighbors are
if (
(y + delta_y, x + delta_x) not in region
and (y + delta_y, x) in region
and (y, x + delta_x) in region
):
corners += 1
return corners
if __name__ == "__main__":
with open("./input/12.txt", "r") as f:
inp = f.read().strip()
p1, p2 = solve(inp)
print(p1)
print(p2)