mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Implement 2024 day 18
This commit is contained in:
70
2024/src/aoc/days/day18.py
Normal file
70
2024/src/aoc/days/day18.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
from collections import deque
|
||||||
|
|
||||||
|
from . import SeparateRunner
|
||||||
|
|
||||||
|
|
||||||
|
def parse_input(data: str) -> list[tuple[int, int]]:
|
||||||
|
return [tuple(map(int, line.split(","))) for line in data.strip().split("\n")]
|
||||||
|
|
||||||
|
|
||||||
|
def find_exit(fallen: set[tuple[int, int]], width: int, height: int) -> int | None:
|
||||||
|
todo = deque([(0, 0, 0)])
|
||||||
|
|
||||||
|
best = {(0, 0): 0}
|
||||||
|
|
||||||
|
def enqueue(dist: int, x: int, y: int):
|
||||||
|
# print(f"trying {x},{y}")
|
||||||
|
if (x, y) in fallen:
|
||||||
|
return
|
||||||
|
|
||||||
|
if (x, y) not in best or best[x, y] > dist:
|
||||||
|
best[x, y] = dist
|
||||||
|
todo.append((dist, x, y))
|
||||||
|
|
||||||
|
while todo:
|
||||||
|
dist, x, y = todo.popleft()
|
||||||
|
# print(x, y)
|
||||||
|
|
||||||
|
if x == width - 1 and y == height - 1:
|
||||||
|
return dist
|
||||||
|
|
||||||
|
if x > 0:
|
||||||
|
enqueue(dist + 1, x - 1, y)
|
||||||
|
|
||||||
|
if x + 1 < width:
|
||||||
|
enqueue(dist + 1, x + 1, y)
|
||||||
|
|
||||||
|
if y > 0:
|
||||||
|
enqueue(dist + 1, x, y - 1)
|
||||||
|
|
||||||
|
if y + 1 < height:
|
||||||
|
enqueue(dist + 1, x, y + 1)
|
||||||
|
|
||||||
|
|
||||||
|
class DayRunner(SeparateRunner):
|
||||||
|
@classmethod
|
||||||
|
def part1(
|
||||||
|
cls, input: str, width: int = 71, height: int = 71, limit: int = 1024
|
||||||
|
) -> int:
|
||||||
|
falling = parse_input(input)
|
||||||
|
|
||||||
|
return find_exit(set(falling[:limit]), width, height)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def part2(cls, input: str, width: int = 71, height: int = 71) -> str:
|
||||||
|
falling = parse_input(input)
|
||||||
|
|
||||||
|
lower = 0
|
||||||
|
upper = len(falling)
|
||||||
|
|
||||||
|
while lower < upper:
|
||||||
|
mid = lower + (upper - lower) // 2
|
||||||
|
|
||||||
|
if find_exit(set(falling[:mid]), width, height) is not None:
|
||||||
|
lower = mid + 1
|
||||||
|
else:
|
||||||
|
upper = mid
|
||||||
|
|
||||||
|
first_blocker = falling[lower - 1]
|
||||||
|
|
||||||
|
return f"{first_blocker[0]},{first_blocker[1]}"
|
||||||
25
2024/tests/samples/18.txt
Normal file
25
2024/tests/samples/18.txt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
5,4
|
||||||
|
4,2
|
||||||
|
4,5
|
||||||
|
3,0
|
||||||
|
2,1
|
||||||
|
6,3
|
||||||
|
2,4
|
||||||
|
1,5
|
||||||
|
0,6
|
||||||
|
3,3
|
||||||
|
2,6
|
||||||
|
5,1
|
||||||
|
1,2
|
||||||
|
5,5
|
||||||
|
2,5
|
||||||
|
6,5
|
||||||
|
1,4
|
||||||
|
0,4
|
||||||
|
6,4
|
||||||
|
1,1
|
||||||
|
6,1
|
||||||
|
1,0
|
||||||
|
0,5
|
||||||
|
1,6
|
||||||
|
2,0
|
||||||
11
2024/tests/test_day18.py
Normal file
11
2024/tests/test_day18.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from aoc.days.day18 import DayRunner
|
||||||
|
|
||||||
|
from . import get_data
|
||||||
|
|
||||||
|
|
||||||
|
def test_sample_part1() -> None:
|
||||||
|
assert DayRunner.part1(get_data(18), width=7, height=7, limit=12) == 22
|
||||||
|
|
||||||
|
|
||||||
|
def test_sample_part2() -> None:
|
||||||
|
assert DayRunner.part2(get_data(18), width=7, height=7) == "6,1"
|
||||||
Reference in New Issue
Block a user