← Build a Tower Defense Game using C++, Raylib & A* Pathfinding

Lesson 3 of 8

Why A*? From BFS to Heuristics

Enemies need to walk from Start to Goal around whatever walls are on the grid, and recompute that route the instant a tower blocks their way. That's a pathfinding problem, and the algorithm this course builds, A* (pronounced "A-star"), is the industry-standard answer for exactly this situation.

Starting point: breadth-first search

BFS explores outward from the start, one ring of neighbors at a time, and is guaranteed to find the shortest path on an unweighted grid like this one. The problem: it explores equally in every direction, including straight away from the goal, wasting a lot of work checking cells that were never going to lead anywhere useful.

BFS explores a growing circle around the start,
even the parts pointing away from the goal:

        β–‘β–‘β–‘β–‘β–‘β–‘β–‘
      β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘
    β–‘β–‘β–‘β–‘Sβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘   G
      β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘
        β–‘β–‘β–‘β–‘β–‘β–‘β–‘

A*'s idea: let the goal pull the search toward it

A* keeps BFS's guarantee of finding the shortest path, but adds a heuristic, an estimate of "how far is this cell from the goal", to prioritize exploring cells that are actually making progress. Every cell A* considers gets a score:

f(n) = g(n) + h(n)
  • g(n): the actual cost to reach cell n from the start, along the best path found so far.
  • h(n): the heuristic, an estimate of the remaining cost from n to the goal.
  • f(n): the combined score, "total estimated cost of a path through this cell." A* always explores the cell with the lowest f next.

The heuristic for a grid: Manhattan distance

On a grid where movement is only up/down/left/right (no diagonals), the natural heuristic is Manhattan distance, the number of grid steps between two cells ignoring any obstacles:

float heuristic(GridPos a, GridPos b) {
    return std::abs(a.row - b.row) + std::abs(a.col - b.col);
}

This heuristic is admissible, it never overestimates the true remaining cost (walls can only make the real path longer, never shorter than the straight-line grid distance), and that's the one property A* needs to guarantee it still finds the truly shortest path, not just a plausible-looking one.

Open set and closed set

A* tracks two collections while it searches:

SetMeaning
Open setCells discovered but not yet fully explored, candidates for "explore next"
Closed setCells already fully explored, no need to revisit

Each step: pull the lowest-f cell out of the open set, mark it closed, look at its neighbors, and for each one either add it to the open set or update its score if a cheaper path to it was just found. The search ends the moment the goal itself is pulled from the open set.

NOTE

BFS is really just A* with h(n) = 0 for every cell, no goal-direction guidance at all. Dijkstra's algorithm (for weighted graphs) is the same idea generalized further. A* is the version tuned specifically for "I have a reasonable estimate of the remaining distance," which is exactly what a grid gives you for free.

πŸ“ Why A* Quiz

Passing score: 70%
  1. 1.What does A* add on top of plain BFS?

  2. 2.Manhattan distance can overestimate the true remaining cost on a 4-directional grid, since walls can only shorten the real path.

  3. 3.f(n) = g(n) + h(n), where g(n) is the actual cost so far and h(n) is the ____.

  4. 4.What does the closed set represent during an A* search?