The Path To Path Finding
By: Danny Buckley
Tags: Bootcamp, Game Development, Coding, Algorithms, Pathfinder

We take for granted the simple joy of instinctively knowing the shortest path to point A to B. But have you ever thought about the process your mind is going through to calculate that path? How would you program that behaviour into a computer, so it can take the hard work of you by working out the quickest route home based on traffic and road closures?

This is a problem that we as users take for granted. And this problem has a number of solutions. I'm going to give a brief overview of the concept behind a pathfinding algorithm, focusing on the popular A* Seach Algorithm.

Brief History Lesson

Some people decided they want to make a robot that was smart enough to transverse through an environment, point A to point B, in the most efficient way possible.

The Shakey robot

The A* pathfinding algorithm was born out of this project called The Shakey Project by a guy called Nils Nilsson. A* was originally designed for finding least-cost paths when the cost of a path is the sum of its edge costs, but it has been shown that A* can be used to find optimal paths for any problem satisfying the conditions of a cost algebra.

Down to the nitty-gritty

Understanding pathfinding concepts can be quite hard, especially if you think about them in a more real-life situation, calculating the shortest distance for 3D spaces. So we will concentrate on the concepts of the algorithm using a 2D grid.

First, we need to look at Dijkstra’s Algorithm, as this is what makes up part of A*.

Dijkstra’s Algorithm works by visiting vertices in the graph starting with the object’s starting point. It then repeatedly examines the closest not-yet-examined vertex, adding its vertices to the set of vertices to be examined.

It keeps expanding the search outwards until the target is found.

In the following diagram, the pink square is the starting point, the blue square is the goal, and the teal areas show what areas Dijkstra’s Algorithm scanned. The lightest teal areas are those farthest from the starting point.

This process works and guarantees that the shortest path will be found, but the number of calculations is costly to achieve the result. As you can see, the number of squares(nodes) checked was a lot compared to what was required to be checked. It would be helpful if the algorithm checked in a general direction of the target first for a path to the target, reducing the number of calculations required.

Let's look at a similar algorithm called Greedy Best-First-Search, that tries to answer this problem.

It works in a similar way except that it has some estimate (called a heuristic) of how far from the goal any vertex is. Instead of selecting the vertex closest to the starting point, it selects the vertex closest to the goal. This, however, comes at a trade-off, as it does not guarantee the shortest path.

You can see in the following example, Greedy Best-First-Search can find paths very quickly compared to Dijkstra’s Algorithm.

Greedy Best-First-Search

This is all well and good, but when you actually apply this to a more real-world situation, with some real word obstacles, this can cause Greedy Best-First-Search to take much longer paths.

Greedy Best-First-Search

Not very useful.

Let's compare an example of how Dijkstra’s Algorithm works harder but is guaranteed to find the shortest path for the same problem.

Dijkstra’s

The trouble is that Greedy Best-First-Search is “greedy” and tries to move towards the goal even if it’s not the right path. Since it only considers the cost to get to the goal and ignores the cost of the path so far, it keeps going even if the path it’s on has become really long.

So the clever developers of 1968 decided that their robot should use a combination of both these approaches to allow the robot to select the shortest paths in the most efficient way.

The A* algorithm was born.

A* is like Dijkstra’s Algorithm in that it can be used to find the shortest path. A* is like Greedy Best-First-Search in that it can use a heuristic to guide itself.

In the simple example, it is as fast as Greedy Best-First-Search.

A*

In the example with a concave obstacle, A* finds a path as good as what Dijkstra’s Algorithm found.

A*

The secret to A*s success is that it favours looking at squares (nodes) in the general direction of the target first, similar to Greedy Best-First-Search, and once it gets disappointed that it hits an obstacle, focuses on squares (nodes) closer to the starting point, similar to Dijkstra’s Algorithm.