Skip to content

Commit

Permalink
✨ Add 2024 Day 18
Browse files Browse the repository at this point in the history
  • Loading branch information
advaithasabnis committed Dec 21, 2024
1 parent 8baee5f commit 353af7b
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 0 deletions.
41 changes: 41 additions & 0 deletions advent_of_code/year2024/day18/part1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from .shared import Pos, shortest_path


def main(text: str, first_N: int = 1024, dimensions: int = 71) -> int:
blockers: set[Pos] = set()
for line in text.splitlines()[:first_N]:
x, y = map(int, line.split(','))
blockers.add((x, y))

return shortest_path(blockers, dimensions)


_input = """
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
""".strip()

assert main(_input, 12, 7) == 22
59 changes: 59 additions & 0 deletions advent_of_code/year2024/day18/part2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from .shared import Pos, shortest_path


def find_critical_blocker(blockers: list[Pos], first_N: int, dimensions: int) -> Pos | None:
"""Binary search to find the first critical blocker that makes a path impossible."""
left, right = first_N, len(blockers)
while left < right:
mid = (left + right) // 2
current_blockers = set(blockers[: mid + 1])
if shortest_path(current_blockers, dimensions) == -1:
right = mid
else:
left = mid + 1
return blockers[left] if left < len(blockers) else None


def main(text: str, first_N: int = 1024, dimensions: int = 71) -> str:
blockers: list[Pos] = []
for line in text.splitlines():
x, y = map(int, line.split(','))
blockers.append((x, y))

critical_blocker = find_critical_blocker(blockers, first_N, dimensions)

if critical_blocker is None:
return 'Could not find critical blocker'

return f'{critical_blocker[0]},{critical_blocker[1]}'


_input = """
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
""".strip()

assert main(_input, 12, 7) == "6,1"
48 changes: 48 additions & 0 deletions advent_of_code/year2024/day18/shared.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from collections import deque


Pos = tuple[int, int]


def shortest_path(blockers: set[Pos], dimensions: int) -> int:
"""
Find the shortest path from (0, 0) to (dimensions - 1, dimensions - 1) in a grid
of size dimensions x dimensions, where blockers are obstacles.
Parameters
----------
blockers : set[Pos]
Set of blocked positions.
dimensions : int
Dimensions of the grid.
Returns
-------
int
Shortest path length. -1 if no path is found.
"""
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
start, goal = (0, 0), (dimensions - 1, dimensions - 1)

queue: deque[tuple[Pos, int]] = deque([(start, 0)])
visited = set([start])

while queue:
(x, y), dist = queue.popleft()

if (x, y) == goal:
return dist

for dx, dy in directions:
nx, ny = x + dx, y + dy
if (
0 <= nx < dimensions
and 0 <= ny < dimensions
and (nx, ny) not in visited
and (nx, ny) not in blockers
):
visited.add((nx, ny))
queue.append(((nx, ny), dist + 1))

return -1

0 comments on commit 353af7b

Please sign in to comment.