You are here
Home > AI FUNDAMENTALS >

AI Search Algorithms Explained: BFS, DFS, A* Search, and Minimax (Chapter 1.3)

AI Search Algorithms Explained: Uninformed Search, A* Pathfinding, and Minimax

Before an AI agent can navigate a city map, solve a Rubik’s Cube, or play chess, it must answer a fundamental question: What sequence of actions leads from my current state to my goal? In Chapter 1.3 of our AI Fundamentals series on aimlrevisited.com, we compare BFS, DFS, and Uniform Cost Search against A* Pathfinding and Minimax, with a complete Python implementation.

1. Framing Any Problem as a State-Space Search

  1. Initial State (s0): The starting configuration of the agent.
  2. Actions A(s): The set of legal moves available from state s.
  3. Transition Model Result(s, a): The new state reached after taking action a.
  4. Goal Test IsGoal(s): Checks whether state s satisfies the objective.
  5. Path Cost g(n): The cumulative cost (distance, time, energy) from the start to node n.

2. Uninformed vs. Informed Search Comparison

AlgorithmSearch FamilyData StructureComplete?Optimal?Best Engineering Use Case
Breadth-First Search (BFS)UninformedFIFO QueueYesYes (equal costs)Shortest path in unweighted graphs
Depth-First Search (DFS)UninformedLIFO StackNoNoMemory-constrained exploration, cycle detection
Uniform Cost Search (UCS)UninformedPriority Queue by g(n)YesYesWeighted shortest path without a heuristic
Greedy Best-First SearchInformedPriority Queue by h(n)NoNoFast approximate routing
A* (A-Star) SearchInformedPriority Queue by g(n) + h(n)YesYes (admissible h)GPS navigation, game pathfinding, robotics

3. How A* Search and Minimax Work

A* Search evaluates nodes by combining backward path cost g(n) and forward heuristic estimate h(n) into f(n) = g(n) + h(n). Whenever h(n) is admissible (never overestimates the true remaining cost), A* is mathematically guaranteed to find the optimal shortest path.

For two-player zero-sum games like Chess, Minimax alternates between MAX nodes (maximizing the AI’s score) and MIN nodes (assuming the opponent minimizes the AI’s score), while Alpha-Beta Pruning eliminates branches that cannot affect the final move.

4. Hands-On Python Tutorial: A* Grid Pathfinding

import heapq

def manhattan(a, b):
    return abs(a[0] - b[0]) + abs(a[1] - b[1])

def a_star_search(grid, start, goal):
    rows, cols = len(grid), len(grid[0])
    open_heap = [(manhattan(start, goal), 0, start)]
    came_from = {start: None}
    g_score = {start: 0}

    while open_heap:
        _, g, current = heapq.heappop(open_heap)
        if current == goal:
            path = []
            while current is not None:
                path.append(current)
                current = came_from[current]
            return path[::-1]

        for dr, dc in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
            nr, nc = current[0] + dr, current[1] + dc
            neighbor = (nr, nc)
            if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == 0:
                tentative_g = g + 1
                if tentative_g < g_score.get(neighbor, float("inf")):
                    came_from[neighbor] = current
                    g_score[neighbor] = tentative_g
                    f = tentative_g + manhattan(neighbor, goal)
                    heapq.heappush(open_heap, (f, tentative_g, neighbor))
    return None

grid = [[0, 0, 0, 1, 0], [0, 1, 0, 1, 0], [0, 1, 0, 0, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0]]
print("Optimal A* Route:", a_star_search(grid, (0, 0), (4, 4)))

5. Key Takeaways & FAQ

  • When to use BFS vs. A* Search: Use BFS for unweighted graphs and A* Search when edge weights vary or a spatial heuristic h(n) is available.
  • Next Chapter: In Chapter 1.4, we explore Knowledge Representation, Propositional Logic, and Expert Systems.
ninformed Search, A* Pathfinding, and Minimax

Before an AI agent can navigate a city map, solve a Rubik’s Cube, schedule airline crews, or play a grandmaster-level game of chess, it must answer a fundamental question: What sequence of actions leads from where I am now to my goal?

In Classical Artificial Intelligence, systematically exploring possible future states is called Problem Solving by Search. Even in the era of Large Language Models and Deep Reinforcement Learning, search algorithms remain a core pillar of AI engineering—powering GPS route planning, robotics motion planning, compiler optimization, and tree-of-thought reasoning. In Chapter 1.3 of our AI Fundamentals series on aimlrevisited.com, we unpack state-space graphs, compare BFS, DFS, and Uniform Cost Search against A* Pathfinding and Minimax, and implement A* in Python.

1. Framing Any Problem as a State-Space Search

Before running a search algorithm, an AI engineer translates a real-world problem into five formal components:

  1. Initial State (s0): The starting configuration of the agent (such as a robot’s current grid coordinate or the opening board in chess).
  2. Actions A(s): The set of legal moves available from state s.
  3. Transition Model Result(s, a): The new state reached after taking action a in state s. Together, states and transitions form a State-Space Graph.
  4. Goal Test IsGoal(s): A check that determines whether state s satisfies the objective.
  5. Path Cost g(n): The cumulative numeric cost (distance, time, or energy) from the start state to node n.

2. Uninformed vs. Informed Search: Algorithm Comparison

Search algorithms fall into two main families depending on whether they use a domain-specific heuristic function h(n) to estimate how close node n is to the goal:

AlgorithmSearch FamilyData StructureComplete?Optimal?Best Engineering Use Case
Breadth-First Search (BFS)Uninformed (Blind)FIFO QueueYesYes (equal step costs)Shortest path in unweighted graphs (social network hops)
Depth-First Search (DFS)Uninformed (Blind)LIFO StackNo (infinite trees)NoMemory-constrained exploration, cycle detection, topological sort
Uniform Cost Search (UCS)Uninformed (Blind)Priority Queue by g(n)YesYesWeighted shortest path (Dijkstra) when no heuristic is available
Greedy Best-First SearchInformed (Heuristic)Priority Queue by h(n)NoNoFast approximate routing when speed matters more than optimality
A* (A-Star) SearchInformed (Heuristic)Priority Queue by g(n) + h(n)YesYes (admissible h)Gold standard for GPS navigation, game pathfinding, and robotics

3. Uninformed (Blind) Search: BFS, DFS, and Uniform Cost Search

  • Breadth-First Search (BFS): Expands the shallowest unexpanded nodes first using a First-In, First-Out (FIFO Queue). BFS guarantees finding the minimum number of steps to the goal, though storing the entire frontier requires exponential memory.
  • Depth-First Search (DFS): Explores all the way down one branch to its deepest leaf using a Last-In, First-Out (LIFO Stack) before backtracking. Because DFS requires minimal memory, combining DFS with incremental depth limits produces Iterative Deepening Search (IDS).
  • Uniform Cost Search (UCS): When road segments have different costs, UCS expands the node with the lowest cumulative path cost g(n) using a Min-Heap Priority Queue.

4. Informed (Heuristic) Search: How A* Pathfinding Works

Uniform Cost Search looks only backward at the cost already spent, g(n), exploring in all directions equally. Informed Search introduces a Heuristic Function h(n) that estimates the remaining cost from node n to the goal.

The A* Evaluation Formula: f(n) = g(n) + h(n)

  • g(n): Exact cumulative cost from the start node to node n.
  • h(n): Estimated heuristic cost from node n to the goal (such as Manhattan distance on a grid or Euclidean straight-line distance).
  • f(n) = g(n) + h(n): Estimated total cost of the cheapest solution passing through node n.

Why A* Is Optimal (Admissibility Rule): A* Search is guaranteed to find the true shortest path whenever the heuristic h(n) is admissible—meaning it never overestimates the true remaining cost to reach the goal.

5. Adversarial Search: Minimax and Alpha-Beta Pruning in Games

In two-player zero-sum games like Chess, Checkers, and Tic-Tac-Toe, an opponent actively tries to minimize your score. Adversarial Search models this conflict:

  • The Minimax Algorithm: Alternates between MAX nodes (where the AI selects the move that maximizes the evaluation score) and MIN nodes (where the opponent selects the move that minimizes the score).
  • Alpha-Beta Pruning: Tracks the best guaranteed bounds (alpha for MAX, beta for MIN) and prunes away game-tree branches that cannot possibly influence the final decision—often doubling the searchable lookahead depth.

6. Hands-On Python Tutorial: Implementing A* Grid Pathfinding

Here is a complete, runnable implementation of A* Pathfinding in Python using heapq and the admissible Manhattan Distance heuristic on a 2D warehouse obstacle grid:

import heapq
from typing import Dict, List, Optional, Tuple

Coordinate = Tuple[int, int]

def manhattan_heuristic(a: Coordinate, b: Coordinate) -> int:
    """Admissible heuristic for 4-directional grid movement."""
    return abs(a[0] - b[0]) + abs(a[1] - b[1])

def a_star_search(
    grid: List[List[int]], start: Coordinate, goal: Coordinate
) -> Optional[List[Coordinate]]:
    rows, cols = len(grid), len(grid[0])
    open_heap = [(manhattan_heuristic(start, goal), 0, start)]
    came_from: Dict[Coordinate, Optional[Coordinate]] = {start: None}
    g_score: Dict[Coordinate, int] = {start: 0}

    while open_heap:
        _, current_g, current = heapq.heappop(open_heap)

        if current == goal:
            path = []
            while current is not None:
                path.append(current)
                current = came_from[current]
            return path[::-1]

        for dr, dc in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
            nr, nc = current[0] + dr, current[1] + dc
            neighbor = (nr, nc)

            if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == 0:
                tentative_g = current_g + 1
                if tentative_g < g_score.get(neighbor, float("inf")):
                    came_from[neighbor] = current
                    g_score[neighbor] = tentative_g
                    f_score = tentative_g + manhattan_heuristic(neighbor, goal)
                    heapq.heappush(open_heap, (f_score, tentative_g, neighbor))

    return None

# 0 = Walkable cell, 1 = Obstacle wall
warehouse_grid = [
    [0, 0, 0, 1, 0],
    [0, 1, 0, 1, 0],
    [0, 1, 0, 0, 0],
    [0, 0, 1, 1, 0],
    [0, 0, 0, 0, 0],
]

optimal_route = a_star_search(warehouse_grid, start=(0, 0), goal=(4, 4))
print("Optimal A* Route:", optimal_route)
print("Total Steps:     ", len(optimal_route) - 1)

7. Frequently Asked Questions (FAQ) & Key Takeaways

  • When should I use BFS instead of A* Search? Use BFS when all step costs are equal and no spatial heuristic exists (such as finding degrees of separation in a social graph). Use A* Search whenever edge weights vary or a heuristic h(n) can guide the search toward the goal.
  • What happens if an A* heuristic overestimates the distance? If h(n) is not admissible, A* runs faster and greedier but loses its mathematical guarantee of returning the strictly shortest path.
  • Next Chapter in AI Fundamentals: In Chapter 1.4, we conclude Module 1 by exploring Knowledge Representation, Propositional Logic, and Expert Systems.

Leave a Reply

Top