Implement 2024 day 6

This commit is contained in:
2024-12-06 09:20:08 +01:00
parent e9a57701c9
commit 0c7c54b5c9
3 changed files with 132 additions and 0 deletions

105
2024/src/aoc/days/day6.py Normal file
View File

@@ -0,0 +1,105 @@
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

10
2024/tests/samples/06.txt Normal file
View File

@@ -0,0 +1,10 @@
....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...

17
2024/tests/test_day6.py Normal file
View File

@@ -0,0 +1,17 @@
import os
from aoc.days.day6 import DayRunner
def get_data() -> str:
sample = os.path.dirname(__file__) + "/samples/06.txt"
with open(sample, mode="rt", encoding="utf-8") as f:
return f.read()
def test_sample_part1() -> None:
assert DayRunner.part1(get_data()) == 41
def test_sample_part2() -> None:
assert DayRunner.part2(get_data()) == 6