Advent of Code 2023 - Day 10Pipe Maze
| Problem statement | Source code | Tags: Grid walkingGeometry
Part 1
It's a straightforward grid walking problem: just follow the characters. The starting point doesn't have a known direction, but it turns out that there are only two possible directions (the other two don't have connected pipes), so we can pick one of them. I trace the loop, and record each corner. Each time, I determine the next direction by looking at the current character and the direction I'm coming from.
There's one gotcha: we didn't test if S itself is a corner. One way to do this is to check which two directions are valid from S, and if they are not opposite to each other, then S is a corner too. Another one (which IMO is simpler) is to just check if we come back to S in a different direction.
Now I can calculate the total loop perimeter. The point farthest from the starting point is just half of the length.
Part 2
Part 1 found the perimeter; natural part 2 finds the enclosed area. I will offer two solutions, one algorithmic and one mathematical.
The first instinct is to do a flood fill from outside, and count how many cells are neither "outside" nor "loop". But there's a problem: there are certain kinds of openings in the loop that the matrix representation cannot capture, such as this:
Here, the is_loop matrix will record the opening in the middle as a big block of TRUE, disallowing the flood fill to reach the inner area. This is fixable by expanding each step from 1 cell to 2 cells, so that the opening has an empty cell in the middle. However this seems complicated, so I went another solution: ray tracing. I shoot rays from each row, and alter between "inside" and "outside" whenever I hit a loop cell. There are a lot of cases to consider:
- If I hit
|, then I have cut across the boundary, so I flip the inside/outside state. - If I hit
F-----7orL-----J, then actually the inside state doesn't change because I haven't cut across the boundary. - If I hit
F-----JorL-----7, then I have cut across the boundary.
So it's just a bunch of spaghetti.
But there's a smarter mathematical solution. I can use the Shoelace formula to get the area of the polygon directly from the coordinates of the corners:
where and . We need some adjustments though; consider the same shape above:
It only fully contains 4 cells (cyan); the other cells (orange) are partially contained and shouldn't count towards the total area. To fix this, realize that each edge cell contributes half of its area to this excluded border area, except 4 reflex corners that contribute 3/4 and 8 convex corners that contribute 1/4, so the area is:
Is this a coincidence? No. Recall that a closed curve must have total turn . Each corner that contributes 1/4 turns , while those that contribute 3/4 turns