Skip to content

Commit caa2c9b

Browse files
committed
Implement 2024 day 18
1 parent 4a8b9f9 commit caa2c9b

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

2024/src/aoc/days/day18.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from collections import deque
2+
3+
from . import SeparateRunner
4+
5+
6+
def parse_input(data: str) -> list[tuple[int, int]]:
7+
return [tuple(map(int, line.split(","))) for line in data.strip().split("\n")]
8+
9+
10+
def find_exit(fallen: set[tuple[int, int]], width: int, height: int) -> int | None:
11+
todo = deque([(0, 0, 0)])
12+
13+
best = {(0, 0): 0}
14+
15+
def enqueue(dist: int, x: int, y: int):
16+
# print(f"trying {x},{y}")
17+
if (x, y) in fallen:
18+
return
19+
20+
if (x, y) not in best or best[x, y] > dist:
21+
best[x, y] = dist
22+
todo.append((dist, x, y))
23+
24+
while todo:
25+
dist, x, y = todo.popleft()
26+
# print(x, y)
27+
28+
if x == width - 1 and y == height - 1:
29+
return dist
30+
31+
if x > 0:
32+
enqueue(dist + 1, x - 1, y)
33+
34+
if x + 1 < width:
35+
enqueue(dist + 1, x + 1, y)
36+
37+
if y > 0:
38+
enqueue(dist + 1, x, y - 1)
39+
40+
if y + 1 < height:
41+
enqueue(dist + 1, x, y + 1)
42+
43+
44+
class DayRunner(SeparateRunner):
45+
@classmethod
46+
def part1(
47+
cls, input: str, width: int = 71, height: int = 71, limit: int = 1024
48+
) -> int:
49+
falling = parse_input(input)
50+
51+
return find_exit(set(falling[:limit]), width, height)
52+
53+
@classmethod
54+
def part2(cls, input: str, width: int = 71, height: int = 71) -> str:
55+
falling = parse_input(input)
56+
57+
lower = 0
58+
upper = len(falling)
59+
60+
while lower < upper:
61+
mid = lower + (upper - lower) // 2
62+
63+
if find_exit(set(falling[:mid]), width, height) is not None:
64+
lower = mid + 1
65+
else:
66+
upper = mid
67+
68+
first_blocker = falling[lower - 1]
69+
70+
return f"{first_blocker[0]},{first_blocker[1]}"

2024/tests/samples/18.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
5,4
2+
4,2
3+
4,5
4+
3,0
5+
2,1
6+
6,3
7+
2,4
8+
1,5
9+
0,6
10+
3,3
11+
2,6
12+
5,1
13+
1,2
14+
5,5
15+
2,5
16+
6,5
17+
1,4
18+
0,4
19+
6,4
20+
1,1
21+
6,1
22+
1,0
23+
0,5
24+
1,6
25+
2,0

2024/tests/test_day18.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from aoc.days.day18 import DayRunner
2+
3+
from . import get_data
4+
5+
6+
def test_sample_part1() -> None:
7+
assert DayRunner.part1(get_data(18), width=7, height=7, limit=12) == 22
8+
9+
10+
def test_sample_part2() -> None:
11+
assert DayRunner.part2(get_data(18), width=7, height=7) == "6,1"

0 commit comments

Comments
 (0)