mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Implement 2024 day 6
This commit is contained in:
105
2024/src/aoc/days/day6.py
Normal file
105
2024/src/aoc/days/day6.py
Normal 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
10
2024/tests/samples/06.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
....#.....
|
||||||
|
.........#
|
||||||
|
..........
|
||||||
|
..#.......
|
||||||
|
.......#..
|
||||||
|
..........
|
||||||
|
.#..^.....
|
||||||
|
........#.
|
||||||
|
#.........
|
||||||
|
......#...
|
||||||
17
2024/tests/test_day6.py
Normal file
17
2024/tests/test_day6.py
Normal 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
|
||||||
Reference in New Issue
Block a user