A* Pathfinding Algorithm: Efficiently Navigating the Maze of Possibilities

PandaMan
4 min readJul 25, 2023

--

Introduction

In the realm of computer science, there exists a fascinating challenge that mimics real-life situations: finding the shortest path between two points on a map. This is where pathfinding algorithms come into play, and one of the most popular and efficient among them is the A* (A-star) pathfinding algorithm. In this blog post, we will delve into the inner workings of the A* algorithm, explore its key components, and provide a Python code demonstration to illustrate its power and versatility.

Understanding the A* Pathfinding Algorithm

The A* pathfinding algorithm is a heuristic search algorithm used to find the shortest path from a starting point to a goal state on a graph or a grid. It was conceived in 1968 by Peter Hart, Nils Nilsson, and Bertram Raphael and has since become one of the cornerstones of modern pathfinding solutions due to its speed and accuracy.

Key Components of A*:

  1. Open Set and Closed Set: The algorithm maintains two sets of nodes during its execution — the open set and the closed set. The open set contains nodes that are candidates for evaluation, while the closed set contains nodes that have already been evaluated.
  2. Heuristic Function (h): The heuristic function is crucial to the A* algorithm’s efficiency. It estimates the cost from the current node to the goal node, often denoted as h(node). It helps prioritize which nodes should be explored first, guiding the algorithm toward the goal efficiently.
  3. Cost Function (g): The cost function, denoted as g(node) represents the actual cost incurred from the start node to reach a specific node. This function helps the algorithm calculate the tentative cost of reaching neighboring nodes.
  4. F-score (f): The F-score is calculated for each node by adding the heuristic and cost functions: f(node) = g(node) + h(node). It represents the total estimated cost of the cheapest path from the start node to the goal, passing through the current node.
  5. Admissible Heuristic: An admissible heuristic is one that never overestimates the cost to reach the goal from any given node. If a heuristic is admissible, the A* algorithm is guaranteed to find the shortest path.

How A* Works:

  1. Add the starting node to the open set with an initial F-score of zero.
  2. Repeat until the open set is empty, or the goal node is reached: a. Pick the node with the lowest F-score from the open set. b. Move the selected node to the closed set. c. Explore its neighboring nodes. d. For each neighbor, calculate the F-score. e. If the neighbor is already in the closed set or has a higher F-score, ignore it. f. Otherwise, add it to the open set and continue.
  3. If the goal node is reached, reconstruct the path by following the parent nodes from the goal back to the starting node.

Let’s see how to implement the A* algorithm in Python to find the shortest path on a 2D grid.

import heapq

def heuristic(point, goal):
# Manhattan distance heuristic
return abs(point[0] - goal[0]) + abs(point[1] - goal[1])

def astar(grid, start, goal):
open_set = []

# Priority queue with (F-score, node)
heapq.heappush(open_set, (0, start))
came_from = {}
g_score = {start: 0}

while open_set:
_, current = heapq.heappop(open_set)

if current == goal:
# Reconstruct the path and return
path = []
while current in came_from:
path.append(current)
current = came_from[current]
path.append(start)
path.reverse()
return path

for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
x, y = current[0] + dx, current[1] + dy
neighbor = (x, y)

# Assuming uniform cost for each step
tentative_g = g_score[current] + 1

if 0 <= x < len(grid) and 0 <= y < len(grid[0]) and grid[x][y] == 0:
if neighbor not in g_score or tentative_g < g_score[neighbor]:
g_score[neighbor] = tentative_g
f_score = tentative_g + heuristic(neighbor, goal)
heapq.heappush(open_set, (f_score, neighbor))
came_from[neighbor] = current

return None # No path found

# Example usage:
grid = [
[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 1, 0, 0],
[0, 0, 0, 0]
]

start = (0, 0)
goal = (3, 3)

path = astar(grid, start, goal)
print("Shortest path:", path)

Through the following image, we can see the process of the A* algorithm more clearly.

In contrast, let’s take a look at the process of the BFS algorithm.

As we can see, the A* algorithm is much faster than the BFS algorithm.

Conclusion:

The A* pathfinding algorithm is a powerful tool that enables efficient navigation through mazes of possibilities. Its combination of heuristic guidance and cost evaluation makes it one of the most widely used pathfinding algorithms in various domains, from gaming to robotics and logistics. By implementing the A* algorithm in Python, you can unlock a world of possibilities for solving complex pathfinding problems in your projects.

Remember that while the A* algorithm guarantees the shortest path when using an admissible heuristic, selecting the right heuristic can significantly impact its performance. So, choose wisely and happy pathfinding!

--

--