Home/Pathfinding/A* on the real map
Search algorithmsCTRL K

A* on the real map

· Cascavel streets · straight-line heuristic
/pathfinding/real-map-a-star
EXPANDED
intersections closed
OPEN
intersections waiting
DISTANCE
start to the current one
ROUTE
length once found
STRAIGHT LINE
start to goal
explored streets · opencurrentroutestart / goal
Click the map: first the start, then the goalLoading the street map…
step 0 / 0
Route (×100 m)20
route_a_star.ts
1
function route(map: RoadMap, start: Node, goal: Node) {
2
  const open = new MinHeap([start]), distance = new Map([[start, 0]]), parent = new Map();
3
  while (open.size > 0) {
4
    // lowest distance so far + straight line to the goal
5
    const current = open.pop();
6
    if (current === goal) return rebuild(parent, goal);
7
    for (const street of map.streetsFrom(current)) {
8
      const next = street.otherEnd(current);
9
      const candidate = distance.get(current)! + street.metres;
10
      if (candidate >= (distance.get(next) ?? Infinity)) continue;
11
      distance.set(next, candidate); parent.set(next, current);
12
      open.push(next, candidate + straightLine(next, goal));
13
    }
14
  }
15
}
CURRENT STEP
line 1

Loading the street map…

// how it works

Understanding A* on the real map

A* · distance so far plus the crow's flight to the goal
01

The idea

A* ranks every open intersection by the distance driven to reach it plus the straight-line distance still to go. Because no street can be shorter than the straight line, that estimate never overshoots, and the first time the goal comes out of the open set its route is the shortest there is.

On a real street map the effect is visible at once: the search grows as a lobe pointed at the goal instead of a disc, and it closes a few hundred intersections where Dijkstra closes thousands. The route it returns is the same one Dijkstra finds.

02

The four stages

1
placetwo intersections about n × 100 m apart
2
poplowest distance + straight line
3
relaxshorter way to a neighbour: new distance, new parent
4
routefollow parents back along the streets
03

Complexity

best
O(d)a straight road to the goal
average
O(E log V)a lobe of the map, not a disc
worst
O(E log V)a river or a wall: it degrades to Dijkstra
space
O(V)distances, parents and the open set
04

Versus its siblings

INTERSECTIONS EXPANDED · CASCAVEL, 3.2 km ROUTE
a*
537
dijkstra
2,045
bfs
2,303
same start and goal (seed 7, route 30) · 3 949 intersections in the map
05

Pseudocode

ROUTE(map, start, goal)
  open ← {start}; distance[start] ← 0
  while open not empty
    current ← the open intersection with the lowest distance + straightLine(current, goal)
    if current = goal: return the route via parent
    for each street leaving current, to neighbour
      if distance[current] + street.metres < distance[neighbour]: update it, parent[neighbour] ← current, add neighbour to open
06

When to use

Any road, rail or pipe network with lengths on the segments: GPS routing, logistics, network packets.
Rerun on a longer route (the slider) to watch the gap between the three searches open up.
07

Pitfalls

The heuristic must never overestimate: with a speed-based cost, divide the straight line by the fastest road, not the average.
Ties along a grid make the frontier wide; a tiny tie-breaker toward the goal keeps it narrow.
Distances in a Map are fine for a city; a country needs typed arrays and a real heap.
08

History

The map is the centre of Cascavel, Paraná: 4 180 intersections and 5 438 street segments from OpenStreetMap, one-way streets respected, about 10 by 7 km. Every real routing engine runs this same loop on a graph a million times larger, with contraction hierarchies or landmarks precomputed so that a query touches only a sliver of it.

Back to Pathfinding