Skip to content
This repository has been archived by the owner on Dec 25, 2024. It is now read-only.

Commit

Permalink
optimize (?) day 6 part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
asottile committed Dec 16, 2024
1 parent d811a41 commit 880553b
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 38 deletions.
82 changes: 44 additions & 38 deletions day06/part2.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,49 +10,55 @@
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')


class LoopError(ValueError):
pass


def compute(s: str) -> int:
world = support.parse_coords_hash(s)
bx, by = support.bounds(world)

start, = (
(x, y)
for y, line in enumerate(s.splitlines())
for x, c in enumerate(line) if c == '^'
)

def _try(cx: int, cy: int) -> set[tuple[int, int, support.Direction4]]:
seen = set()
x, y = start
direction = support.Direction4.UP
while True:
if x not in bx.range or y not in by.range:
break
elif (x, y) in world or (x, y) == (cx, cy):
x, y = direction.opposite.apply(x, y)
direction = direction.cw
x, y = direction.apply(x, y)
elif (x, y, direction) in seen:
raise LoopError
else:
seen.add((x, y, direction))
x, y = direction.apply(x, y)
bounds = support.bounds(world)

return seen
pos, = support.parse_coords_hash(s, wall='^')

traced = {(x, y) for x, y, _ in _try(-999, -999)}
seen = set()
seen1 = set()
direction = support.Direction4.UP

bads = set()
for cx, cy in traced:
try:
_try(cx, cy)
except LoopError:
bads.add((cx, cy))

return len(bads)
def _loops(
pos: tuple[int, int],
direction: support.Direction4,
new_wall: tuple[int, int],
) -> bool:
seen2 = set()
direction = direction.cw
while True:
if not support.in_bounds(pos, bounds):
return False
elif pos in world or pos == new_wall:
pos = direction.opposite.apply(*pos)
direction = direction.cw
elif (pos, direction) in seen1 or (pos, direction) in seen2:
return True
else:
seen2.add((pos, direction))
pos = direction.apply(*pos)

found = set()
while True:
if not support.in_bounds(pos, bounds):
break
elif pos in world:
pos = direction.opposite.apply(*pos)
direction = direction.cw
else:
nextpos = direction.apply(*pos)
if (
nextpos not in seen and
nextpos not in world and
_loops(pos, direction, nextpos)
):
found.add(nextpos)
seen1.add((pos, direction))
seen.add(pos)
pos = nextpos

return len(found)


INPUT_S = '''\
Expand Down
4 changes: 4 additions & 0 deletions support-src/support.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ def bounds(points: Iterable[tuple[int, ...]]) -> tuple[Bound, ...]:
return tuple(Bound(min(dim), max(dim)) for dim in zip(*points))


def in_bounds(pt: tuple[int, ...], bounds: tuple[Bound, ...]) -> bool:
return all(n in b.range for n, b in zip(pt, bounds, strict=True))


def format_coords_hash(coords: set[tuple[int, int]]) -> str:
bx, by = bounds(coords)
return '\n'.join(
Expand Down

0 comments on commit 880553b

Please sign in to comment.