mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
106 lines
2.3 KiB
Python
106 lines
2.3 KiB
Python
import numpy
|
|
|
|
from . import SeparateRunner
|
|
|
|
|
|
def does_loop(
|
|
grid: numpy.array,
|
|
x: int,
|
|
y: int,
|
|
dx: int,
|
|
dy: int,
|
|
visited: set[tuple[int, int, int, int]],
|
|
) -> bool:
|
|
try:
|
|
while True:
|
|
while y + dy >= 0 and x + dx >= 0 and grid[y + dy, x + dx] == "#":
|
|
dx, dy = -dy, dx
|
|
|
|
x += dx
|
|
y += dy
|
|
|
|
if x < 0 or y < 0:
|
|
return False
|
|
|
|
pos = (x, y, dx, dy)
|
|
|
|
if pos in visited:
|
|
return True
|
|
else:
|
|
visited.add(pos)
|
|
except IndexError:
|
|
return False
|
|
|
|
|
|
class DayRunner(SeparateRunner):
|
|
@classmethod
|
|
def part1(cls, input: str) -> int:
|
|
grid = input.strip().split("\n")
|
|
|
|
for y, line in enumerate(grid):
|
|
if (x := line.find("^")) != -1:
|
|
break
|
|
|
|
dx = 0
|
|
dy = -1
|
|
|
|
visited = {(x, y)}
|
|
|
|
try:
|
|
while True:
|
|
nx = x + dx
|
|
ny = y + dy
|
|
|
|
if grid[ny][nx] == "#":
|
|
dx, dy = -dy, dx
|
|
else:
|
|
x, y = nx, ny
|
|
visited.add((x, y))
|
|
except IndexError:
|
|
pass
|
|
|
|
return len(visited)
|
|
|
|
@classmethod
|
|
def part2(cls, input: str) -> int:
|
|
grid = numpy.array(list(map(list, input.strip().split("\n"))))
|
|
y, x = numpy.where(grid == "^")
|
|
|
|
y = y[0]
|
|
x = x[0]
|
|
|
|
dx = 0
|
|
dy = -1
|
|
loops = 0
|
|
|
|
visited = {(x, y, dx, dy)}
|
|
tiles_visited = {(x, y)}
|
|
|
|
try:
|
|
while True:
|
|
while y + dy >= 0 and x + dx >= 0 and grid[y + dy, x + dx] == "#":
|
|
dx, dy = -dy, dx
|
|
|
|
nx = x + dx
|
|
ny = y + dy
|
|
|
|
if nx < 0 or ny < 0:
|
|
break
|
|
|
|
if (nx, ny) not in tiles_visited:
|
|
# check for a loop
|
|
grid[ny, nx] = "#"
|
|
if does_loop(grid, x, y, dx, dy, visited.copy()):
|
|
loops += 1
|
|
grid[ny, nx] = "L"
|
|
else:
|
|
grid[ny, nx] = "."
|
|
|
|
x, y = nx, ny
|
|
tiles_visited.add((x, y))
|
|
visited.add((x, y, dx, dy))
|
|
except IndexError:
|
|
pass
|
|
|
|
return loops
|