人工智能技术在解决涉及复杂状态空间搜索的组合问题中起着核心作用。其中一个经典的例子是八数码难题(8-tile puzzle),这是一种在 3x3 棋盘上对数字瓷砖进行策略性重排的游戏。在本次作业中,我们探讨了如何应用 A* 搜索算法,结合可采纳的启发式函数、优先队列以及精细的状态管理,来高效地求解该难题。

Background and Problem Definition
The 8-tile puzzle was popularized in the 19th century and continues to serve as a benchmark problem in Artificial Intelligence courses. It consists of a 3x3 board containing seven numbered tiles and two empty slots. The goal is to move the tiles around so that the numbers appear in ascending order from left to right, with both empty slots appearing at the bottom right corner of the grid.
Formally, each configuration of the board is called a “state.” A state can change into another state (i.e., produce a successor) by moving a tile adjacent to an empty slot into that empty slot. Each move is considered to have a uniform cost of 1, and the goal is to reach the target state using the least number of moves possible.
State Representation
For this assignment, the state of the board is represented as a one-dimensional Python list of length nine. Empty slots are denoted by the integer 0
, while tiles are labeled from 1
to 7
. For example, the board:
1 | 2 5 1 |
is represented as [2, 5, 1, 4, 3, 6, 7, 0, 0]
. The position of the empty slots and tiles in the list directly corresponds to their position in the 3x3 grid.
Search Objective and Heuristic
We use the A* search algorithm to navigate from an arbitrary initial state to the goal state [1, 2, 3, 4, 5, 6, 7, 0, 0]
. The A* algorithm selects the next node to explore based on a priority function f(n) = g(n) + h(n)
, where g(n)
is the actual cost from the start state to the current node (i.e., number of moves), and h(n)
is an estimate of the cost to reach the goal from the current node.
For our heuristic function h(n)
, we use the Manhattan distance, which calculates the sum of the horizontal and vertical distances of each tile from its correct position. This heuristic is admissible (it never overestimates) and consistent, making it ideal for A*.
Designing the Solver: A Class-Based Approach
To structure the program clearly, we design the following components:
1. Puzzle State Handling
Each board state must be easily transformable to generate all valid successors. A function is required to find all possible moves from the current configuration. For each successor, we must also compute the heuristic value.
2. Priority Queue with Heapq
Python’s heapq
module is used to maintain a priority queue where the state with the lowest f(n)
value is always extracted first. Each element in the queue stores not only the state and its cost but also meta-information such as the path and parent node, allowing reconstruction of the final solution path.
3. Path Tracing
We maintain a map from each state to its parent so that we can reconstruct the full path to the solution once the goal state is reached. This involves backtracking from the goal node to the start node using stored parent references.
4. Visited Set
To prevent revisiting the same states, we use a hash set that stores all explored configurations. This reduces runtime and ensures the algorithm terminates efficiently.
Core Functions
print_succ(state)
This function generates all valid successors of a given state by moving tiles adjacent to an empty slot into that slot. For each successor, it prints the new configuration and its heuristic value, sorted in lexicographic order.
1 | def print_succ(state): |
solve(state)
This function implements the A* algorithm. It initializes the priority queue with the initial state, and then iteratively expands the state with the lowest f(n)
. For each successor, it calculates new g
, h
, and f
values and adds them to the queue. When the goal state is reached, it reconstructs the solution path and prints each state with its heuristic and move count.
1 | def solve(state): |
Sample Output and Explanation
For the initial state [4,3,0,5,1,6,7,2,0]
, the program would output:
1 | [4, 3, 0, 5, 1, 6, 7, 2, 0] h=7 moves: 0 |
Each line shows the state configuration, the heuristic value at that state, and the total moves taken to reach that state. The maximum queue length is also reported for insight into the algorithm’s space complexity.
Heuristic Function in Detail
The Manhattan distance function is central to guiding the A* algorithm efficiently. It skips empty slots and evaluates how far each tile is from its target position in both row and column terms:
1 | def manhattan(state): |
This ensures that A* expands promising nodes first.
Complexity Analysis
The 8-tile puzzle has a relatively small state space (factorial of 9), but with two blank tiles, the branching factor increases. The time complexity of A* is exponential in the worst case, though in practice it performs efficiently with a good heuristic. Memory usage is dominated by the priority queue and the visited set, both of which can grow large depending on the search depth.
- Generating successors: O(b), where b is branching factor (2 to 4).
- Heuristic computation: O(n) per state, n = 9.
- Overall: O(b^d), d = depth of solution.
Reflection and Extensions
This assignment not only reinforces the mechanics of the A* algorithm but also offers insights into how heuristics influence search behavior. Students are encouraged to explore additional optimizations, such as more efficient state representation using tuples or bitmasks, and alternative heuristics like linear conflict or pattern databases.
Additionally, extensions could include:
- Allowing only one empty slot to explore the classic 8-puzzle variant.
- Visualizing the path and tile movements using a GUI.
- Implementing IDA* to reduce space complexity.
Understanding and applying search algorithms in well-defined environments like the 8-tile puzzle provides a solid foundation for tackling real-world AI problems in robotics, planning, and automated reasoning.