mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 12:50:32 +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