Skip to content

Commit

Permalink
Simplify python/2024/12 by counting corners
Browse files Browse the repository at this point in the history
  • Loading branch information
IsaacG committed Dec 12, 2024
1 parent c29f3a9 commit bf3dd61
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 44 deletions.
51 changes: 20 additions & 31 deletions 2024/d12.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,38 +72,27 @@ def perimeter1(self, region: set[complex]) -> int:
)

def perimeter2(self, region: set[complex]) -> int:
"""Walk the edge of a region and count turns."""
area = len(region)
if area == 1:
return 4
"""Count the number of edge-runs.
perimeters = 0
unwalked_walls = {r for r in region if any(n not in region for n in aoc.neighbors(r))}
while unwalked_walls:
cur = next(r for r in unwalked_walls if any(n not in region for n in aoc.neighbors(r)))
unwalked_walls.remove(cur)
direction = next(d for d in aoc.FOUR_DIRECTIONS if cur + d not in region)
while cur + direction not in region:
direction *= -1j
start_pos = cur
start_dir = direction

perimeter = 0
while cur != start_pos or direction != start_dir or perimeter < 1:
unwalked_walls.discard(cur)
if cur + direction * 1j in region:
direction *= 1j
perimeter += 1
while cur + direction not in region:
direction *= -1j
perimeter += 1
if cur == start_pos and direction == start_dir and perimeter:
break
if cur + direction in region:
cur += direction
unwalked_walls.discard(cur)
perimeters += perimeter
return perimeters
This can be computed by counting the number of "corners" a region has.
A point is a convex corner if it no neighbors in two adjacent directions (eg up and right).
A point is a concave corner if there are neighbors in
two adjacent directions (eg up and right) but not diagonal in those directions.
"""
d1, d2, d3 = complex(1, 0), complex(0, 1), complex(1, 1)
convex_corners = sum(
1
for coord in region
for rotation in aoc.FOUR_DIRECTIONS
if coord + d1 * rotation not in region and coord + d2 * rotation not in region
)
concave_corners = sum(
1
for coord in region
for rotation in aoc.FOUR_DIRECTIONS
if coord + d1 * rotation in region and coord + d2 * rotation in region and coord + d3 * rotation not in region
)
return convex_corners + concave_corners

def solver(self, puzzle_input: aoc.Map, part_one: bool) -> int:
perimeter = self.perimeter1 if part_one else self.perimeter2
Expand Down
26 changes: 13 additions & 13 deletions pylib/aoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,19 +509,6 @@ def reading_order(data: Sequence[complex]) -> list[complex]:
return sorted(data, key=lambda x: (x.imag, x.real))


def partition_regions(data: dict[complex, T], directions: list[complex] = FOUR_DIRECTIONS) -> list[tuple[T, set[complex]]]:
"""Partition a map into regions."""
regions = []
todo = set(data)
while todo:
cur = todo.pop()
val = data[cur]
region = floodfill(data, cur)
todo -= region
regions.append((val, region))
return regions


def floodfill(data: dict[complex, T], start: complex, directions: list[complex] = FOUR_DIRECTIONS) -> set[complex]:
"""Expand a point to its region by flood filling so long as the char matches."""
todo = {start}
Expand All @@ -537,6 +524,19 @@ def floodfill(data: dict[complex, T], start: complex, directions: list[complex]
return region


def partition_regions(data: dict[complex, T], directions: list[complex] = FOUR_DIRECTIONS) -> list[tuple[T, set[complex]]]:
"""Partition a map into regions."""
regions = []
todo = set(data)
while todo:
cur = todo.pop()
val = data[cur]
region = floodfill(data, cur, directions)
todo -= region
regions.append((val, region))
return regions


def interval_overlap(one: Interval, two: Interval) -> tuple[Interval | None, Interval | None, Interval | None]:
one_start, one_end = one
two_start, two_end = two
Expand Down

0 comments on commit bf3dd61

Please sign in to comment.