Solve 2023:10 "Pipe Maze"

Got completely stuck on part 2. Tried some polygon
area calculations, but none provided the correct
answer, most likely due to the unorthodox polygon
points.

I also tried _shoelace method_ without any luck.
Had not heard about that one earlier, it was a good
learning experience even though I vould not use it
here.

By the subreddit, several people had had luck
using the ray method.

> Part 2 using one of my favorite facts from
> graphics engineering: lets say you have an
> enclosed shape, and you want to color every
> pixel inside of it. How do you know if a given
> pixel is inside the shape or not? Well, it
> turns out: if you shoot a ray in any direction
> from the pixel and it crosses the boundary an
> _odd number_ of times, it's _inside_. if it crosses
> an even number of times, it's outside. Works
> for all enclosed shapes, even self-intersecting
> and non-convex ones.
This commit is contained in:
Anders Englöf Ytterström 2023-12-11 00:19:34 +01:00
parent 741f7b89d8
commit b681e5cdb7

View file

@ -1,44 +1,95 @@
import re
from collections import Counter, defaultdict, deque
from output import answer
n = 10
title = "dddd"
title = "Pipe Maze"
D = (-1, 0), (0, 1), (1, 0), (0, -1)
C = {
(-1, 0): ["|", "7", "F"],
(0, 1): ["-", "7", "J"],
(1, 0): ["|", "L", "J"],
(0, -1): ["-", "L", "F"],
}
A = {
"S": [0, 1, 2, 3],
"-": [1, 3],
"|": [0, 2],
"F": [1, 2],
"L": [0, 1],
"7": [2, 3],
"J": [0, 3],
}
@answer(1, "Answer is {}")
def part_1(data):
return data
def part_1(presolved):
return presolved[0]
@answer(2, "Actually, answer is {}")
def part_2(data):
return data
def part_2(presolved):
return presolved[1]
# uncomment to solve parts in one go
# def presolve(data):
# return data
def presolve(data):
matrix = data.split()
w = len(matrix[0])
h = len(matrix)
q = deque()
visited = set()
for r in range(h):
if "S" in matrix[r]:
start = (r, matrix[r].index("S"))
q.append(start)
break
while q:
o = q.popleft()
visited.add(o)
for di in A[matrix[o[0]][o[1]]]:
d = D[di]
r = o[0] + d[0]
c = o[1] + d[1]
if r >= 0 and r < h and c >= 0 and c < w:
t = matrix[r][c]
p = (r, c)
if p not in visited and t != "." and t in C[d]:
q.append(p)
p1 = len(visited) // 2
p2 = 0
for y in range(h):
for x in range(w):
if (y, x) in visited:
continue
crosses = 0
y2, x2 = y, x
while y2 < h and x2 < w:
c2 = matrix[y2][x2]
if (y2, x2) in visited and c2 not in "L7":
crosses += 1
x2 += 1
y2 += 1
if crosses % 2 == 1:
p2 += 1
return p1, p2
if __name__ == "__main__":
# use dummy data
inp = """
replace me
""".strip()
with open(f"./input/10.txt", "r") as f:
inp = f.read()
# uncomment to instead use stdin
# import sys; inp = sys.stdin.read().strip()
# uncomment to use AoC provided puzzle input
# with open(f"./input/10.txt", "r") as f:
# inp = f.read()
# uncomment to do initial data processing shared by part 1-2
# inp = presolve(inp)
inp = presolve(inp)
a = part_1(inp)
# b = part_2(inp)
b = part_2(inp)
# uncomment and replace 0 with actual output to refactor code
# and ensure nonbreaking changes
# assert a == 0
# assert b == 0
assert a == 6846
assert b == 325