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.
73 lines
2.2 KiB
Python
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)
|