Skip to content

Commit

Permalink
Extract common BFS function
Browse files Browse the repository at this point in the history
  • Loading branch information
loociano committed Dec 20, 2024
1 parent a8ef870 commit f37d3bb
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 24 deletions.
26 changes: 2 additions & 24 deletions aoc2024/src/day18/python/solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Sequence
from collections import defaultdict, deque
from common.python3.graph_utils import shortest_distance_bfs

_CORRUPTED = '#'
_NOT_CORRUPTED = '.'

type Position = tuple[int, int] # (x,y)


def shortest_path_bfs(grid: list[list[str]], visited: set[Position], start_pos: Position = (0, 0),
end_pos: Position = None):
if end_pos is None:
end_pos = (len(grid[0]) - 1, len(grid) - 1) # (x,y)
queue = deque()
queue.append((start_pos, 0)) # level
while queue:
pos, level = queue.popleft()
if pos == end_pos:
return level
for dxy in ((0, -1), (1, 0), (0, 1), (-1, 0)):
next_pos = (pos[0] + dxy[0], pos[1] + dxy[1])
if (next_pos not in visited
and 0 <= next_pos[0] < len(grid[0])
and 0 <= next_pos[1] < len(grid)
and grid[next_pos[1]][next_pos[0]] != _CORRUPTED):
visited.add(next_pos)
queue.append((next_pos, level + 1))


def min_steps_to_exit(input: Sequence[str], num_bytes: int = 1024,
width: int = 71, length: int = 71) -> int:
Expand All @@ -47,4 +25,4 @@ def min_steps_to_exit(input: Sequence[str], num_bytes: int = 1024,
for i in range(num_bytes):
pos = corrupted_positions[i]
grid[pos[1]][pos[0]] = _CORRUPTED
return shortest_path_bfs(grid=grid, visited=set())
return shortest_distance_bfs(grid=grid, predicate=lambda x, y: grid[y][x] != _CORRUPTED)
32 changes: 32 additions & 0 deletions common/python3/graph_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Common graph utility functions."""
from collections import deque
from typing import Any, Callable
from common.python3.types import Direction, Position


def shortest_distance_bfs(grid: list[list[str]], visited: set[Position] = None,
start_pos: Position = (0, 0), end_pos: Position = None,
directions: tuple[Direction, ...] = ((0, -1), (1, 0), (0, 1), (-1, 0)),
predicate: Callable[[Any, ...], bool] = None):
"""Returns the shortest distance between two points in a grid.
An optional predicate can be provided to detect obstacles:
predicate=lambda x,y: grid[y][x] != OBSTACLE_CHAR
"""
if visited is None:
visited = set()
if end_pos is None:
end_pos = (len(grid[0]) - 1, len(grid) - 1) # (x,y)
queue = deque()
queue.append((start_pos, 0)) # Append level.
while queue:
pos, level = queue.popleft()
if pos == end_pos:
return level
for dxy in directions:
next_pos = (pos[0] + dxy[0], pos[1] + dxy[1])
if (next_pos not in visited
and 0 <= next_pos[0] < len(grid[0])
and 0 <= next_pos[1] < len(grid)
and predicate(next_pos[0], next_pos[1])):
visited.add(next_pos)
queue.append((next_pos, level + 1))
4 changes: 4 additions & 0 deletions common/python3/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""Useful type aliases."""

type Position = tuple[int, int]
type Direction = tuple[int, int]

0 comments on commit f37d3bb

Please sign in to comment.