A Star Search¶
Problem¶
Given a 2D grid where each cell has a non-negative traversal cost, find the shortest (least-cost) path from a start cell to a goal cell using A* search with Manhattan distance heuristic.
Approach¶
Priority queue ordered by f(n) = g(n) + h(n), where g is the cost so far and h is the Manhattan distance heuristic. Expand the node with lowest f; skip already-settled nodes.
When to Use¶
Shortest path when you have a good heuristic (estimated distance to goal). Better than Dijkstra when goal is known — avoids exploring irrelevant nodes. ASI relevance: flight route optimization with destination-aware pruning. Use Manhattan distance for grids, great-circle distance for geospatial.
Complexity¶
| Time | O(E log V) with a good heuristic (grid: E ~ 4V) |
| Space | O(V) |
Implementation¶
a_star_search ¶
A* pathfinding on a weighted grid.
Problem
Given a 2D grid where each cell has a non-negative traversal cost, find the shortest (least-cost) path from a start cell to a goal cell using A* search with Manhattan distance heuristic.
Approach
Priority queue ordered by f(n) = g(n) + h(n), where g is the cost so far and h is the Manhattan distance heuristic. Expand the node with lowest f; skip already-settled nodes.
When to use
Shortest path when you have a good heuristic (estimated distance to goal). Better than Dijkstra when goal is known — avoids exploring irrelevant nodes. ASI relevance: flight route optimization with destination-aware pruning. Use Manhattan distance for grids, great-circle distance for geospatial.
Complexity
Time: O(E log V) with a good heuristic (grid: E ~ 4V) Space: O(V)
a_star ¶
a_star(
grid: list[list[int]],
start: tuple[int, int],
goal: tuple[int, int],
) -> list[tuple[int, int]] | None
Return the shortest path from start to goal on grid.
grid[r][c] is the cost to enter cell (r, c). Returns a list of
(row, col) coordinates from start to goal inclusive, or None if
no path exists.
a_star([[1, 1, 1], [1, 1, 1], [1, 1, 1]], (0, 0), (2, 2)) [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)]
Source code in src/algo/graphs/a_star_search.py
manhattan_distance ¶
"""Tests for A* search on weighted grids."""
from algo.graphs.a_star_search import a_star, manhattan_distance
class TestManhattanDistance:
def test_same_point(self) -> None:
assert manhattan_distance((0, 0), (0, 0)) == 0
def test_basic(self) -> None:
assert manhattan_distance((0, 0), (3, 4)) == 7
class TestAStar:
def test_simple_grid(self) -> None:
grid = [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
path = a_star(grid, (0, 0), (2, 2))
assert path is not None
assert path[0] == (0, 0)
assert path[-1] == (2, 2)
assert len(path) == 5 # Manhattan distance + 1
def test_start_equals_goal(self) -> None:
grid = [[1, 1], [1, 1]]
path = a_star(grid, (0, 0), (0, 0))
assert path == [(0, 0)]
def test_obstacle_avoidance(self) -> None:
grid = [
[1, 999, 1],
[1, 999, 1],
[1, 1, 1],
]
path = a_star(grid, (0, 0), (0, 2))
assert path is not None
assert path[0] == (0, 0)
assert path[-1] == (0, 2)
# Should go around the wall
total_cost = sum(grid[r][c] for r, c in path[1:])
assert total_cost < 999
def test_empty_grid(self) -> None:
assert a_star([], (0, 0), (0, 0)) is None
def test_out_of_bounds(self) -> None:
grid = [[1, 1], [1, 1]]
assert a_star(grid, (5, 5), (0, 0)) is None
def test_weighted_preference(self) -> None:
grid = [
[1, 1, 1],
[1, 10, 1],
[1, 1, 1],
]
path = a_star(grid, (0, 0), (2, 2))
assert path is not None
# Should not go through (1,1) since weight 10
assert (1, 1) not in path
Implement it yourself
Run: just challenge graphs a_star_search
Then implement the functions to make all tests pass.
Use just study graphs for watch mode.
Reveal Solution
a_star_search ¶
A* pathfinding on a weighted grid.
Problem
Given a 2D grid where each cell has a non-negative traversal cost, find the shortest (least-cost) path from a start cell to a goal cell using A* search with Manhattan distance heuristic.
Approach
Priority queue ordered by f(n) = g(n) + h(n), where g is the cost so far and h is the Manhattan distance heuristic. Expand the node with lowest f; skip already-settled nodes.
When to use
Shortest path when you have a good heuristic (estimated distance to goal). Better than Dijkstra when goal is known — avoids exploring irrelevant nodes. ASI relevance: flight route optimization with destination-aware pruning. Use Manhattan distance for grids, great-circle distance for geospatial.
Complexity
Time: O(E log V) with a good heuristic (grid: E ~ 4V) Space: O(V)
a_star ¶
a_star(
grid: list[list[int]],
start: tuple[int, int],
goal: tuple[int, int],
) -> list[tuple[int, int]] | None
Return the shortest path from start to goal on grid.
grid[r][c] is the cost to enter cell (r, c). Returns a list of
(row, col) coordinates from start to goal inclusive, or None if
no path exists.
a_star([[1, 1, 1], [1, 1, 1], [1, 1, 1]], (0, 0), (2, 2)) [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)]