Skip to content

Solving 8 puzzle problem using A* star search

Solving 8 puzzle problem using A* star search in C++

In this tutorial, we will solve the 8 puzzle problem using the A* (star) search algorithm. We will approach the solution by first modelling the problem, building the fundamental blocks and finally applying a solver to solve the puzzle.

Part 1 of this tutorial provides the introduction, the background information and the approach towards the solution from the algorithmic point of view.

Part 2 of this tutorial provides an implementation of the algorithm and the solution using C++ for a console program. Read Part 2, “Solving 8 puzzle problem using A* star search in C++”.

Part 3 of this tutorial provides an implementation of the algorithm and the solution using C# for the Unity project. Read Part 2, 8-Puzzle Problem Using A* in C# and Unity.

View the tutorial on YouTube

Read also

Tutorials on Pathfinding and a WebGL Playground for experimenting pathfinding.



Part 1 – Introduction

Typically A* (Astar) is used in a grid-based pathfinding problem. However, as a general rule, any pathfinding algorithm (A* included) can be used to solve any graph-based problem. For a very detailed understanding of path-finding, I suggest the brilliant tutorial maintained by Amit on Stanford’s site. In this tutorial, I will not go through the theory of A* pathfinding, but rather, I would implement all necessary functions for A* pathfinding to solve the 8 puzzle problem.


The 8 Puzzle Problem


The 8-puzzle, introduced and popularised by Noyes Palmer Chapman in the 1870s, is a scaled-down version of the more famous 15-puzzle, featuring a 3-by-3 grid with eight numbered square blocks and one empty square.

The aim of the puzzle is to rearrange the blocks into a specific sequence, typically with the empty square positioned either at the start or end of the sequence. Blocks can be moved horizontally or vertically into the empty square to achieve the desired arrangement.

The A* pathfinding algorithm is commonly used for grid-based pathfinding tasks. However, in general, any pathfinding algorithm, including A*, can be applied to solve graph-based problems. In this tutorial, we will utilise the A* pathfinding algorithm to solve the 8-puzzle.

Start and goal graphical representation


Before we can solve the 8 puzzle problem, we will need to model the problem. But what do we mean by “Modelling the Problem”?

In general terms, modelling a problem is the process of formulating the problem using precisely defined, well-understood components and logic to reach a solution. In computer science, proper modelling is essential for applying algorithmic design techniques to any real-world problem.

You might be working on a system that simulates air traffic in and around an airport, optimising the dispatch of delivery vans for an e-commerce application, or searching for patterns in a large image dataset. To solve such problems, you will use modelling techniques to represent the problem using rigorously defined abstract structures such as graphs, trees, permutations, sets, and so on.

For our 8 puzzle problem, let’s see how we can model the problem. Let’s take a random state of the 8 puzzle problem as shown in the diagram below. We can either slide tile 5 down, slide 4 right, or slide 2 left to create three variant states from this random state.

These three states will produce subsequent more states (2 for the first, 2 for the second and 2 for the third). This continues until we find the goal state.

We can see that we can transform the various possible states of the 8 puzzle problem into a tree data structure.


The 8 Puzzle Solution Search Space

The 8-puzzle represents the largest possible N-puzzle that can be completely solved. While it is straightforward, it presents a substantial problem space. Larger variants like the 15-puzzle exist but cannot be entirely solved. This complexity classifies the N by N extension of the 8-puzzle as an “N-P” hard problem.

The 8-puzzle encompasses 9 factorial possible tile permutation states. Among these states, every second permutation is solvable. Therefore, there are a total of 9 factorial divided by 2 (9!/2), which is 181,440 solvable problem states.

Alexander Reinefeld from the Paderborn Center for Parallel Computing, Germany, demonstrated that the average length of all optimal solution paths is approximately 22 moves for any random configuration. Across the 181,440 solvable configurations, there are a total of 500,880 optimal solutions, providing an average solution density of 2.76 solutions per problem, with the range of solutions varying from 1 to 64.

The difficulty in solving the puzzle involves building the potential search tree and determining the most efficient path from the initial state to the goal state. To identify the optimal path, we employ Heuristic Search.


Heuristic Search

Heuristic search is a method used to solve search problems more quickly than traditional methods. It often provides an approximate solution when conventional methods cannot, offering a generalised and approximate approach to problem-solving.

In simple terms, a heuristic search can be likened to a rule of thumb or common-sense knowledge. While the answer isn’t guaranteed to be accurate, it aids in swift decision-making, sacrificing optimality, completeness, accuracy, or precision for speed.

Heuristic searches commonly involve heuristic values.

A heuristic value assigned to a node within the construction graph aims to capture the significance of that node’s value, such as cost or gain. Heuristic search, a form of informed search, utilises this heuristic value to optimise the search.

During each branching step, the search evaluates the heuristic value and selects which branch to pursue by ranking alternatives.

There are various types of heuristic search algorithms, with one notable example being the A-star search algorithm.

The A* Search

A* search is a computer search algorithm that is widely used for pathfinding and graph traversal. In our case of the 8 puzzle problem, we will be using it for optimal graph traversal. A* works by keeping track of all visited nodes and ignoring them for further traversal. At the same time, it also keeps track of all the nodes that are yet to be explored and chooses one with the least cost to be further explored.

This simple mechanism allows us to find the most optimal tree branch that will lead us from the start state to the end state.


The Heuristic Value (Cost Function) of an 8 Puzzle State

The heuristic value of an 8 puzzle state is a combination of two values. It is often called the cost function f.

f = h + g

h gives how far the goal node is and g the number of nodes traversed from the start node to the current node. For h, we will use the Manhattan distance, and for g, we will use the depth of the current node.

For our A* search, we will use the sum of Manhattan distance and the current depth of the node as the total cost.

Manhattan distance

The Manhattan distance heuristic is used for its simplicity and ability to estimate the number of moves required to bring a given puzzle state to the solution state. Manhattan distance is computed by the sum of the distances of each tile from where it should belong.

// pseudo code
function manhattan_distance(node, goal) =
    dx = abs(node.x - goal.x)
    dy = abs(node.y - goal.y)
    return dx + dyCode language: JavaScript (javascript)

For example, the Manhattan distance between “213540678” and “123456780” is 9 and between “647850321” and “123456780” is 21.

The diagram below shows the Manhattan cost for a specific tiles configuration.

Manhattan distance calculation for 8-puzzle state

Software Design for Solving 8 Puzzle Problem

In the following section, I will start creating the building blocks for the puzzle solution and finally try to join them to reach the solution.


State

To solve the 8-puzzle problem, we need a data structure to represent the puzzle’s tiles, which we will refer to as the puzzle’s “state.” Each state represents a unique combination of tiles, and throughout our solving process, we will need to manage potentially hundreds or thousands of these states. Each distinct tile arrangement in the puzzle corresponds to a node within a tree data structure.

To represent these states, we will use an integer array whose indices correspond to specific tile positions. The values stored at these indices represent the tile numbers. In this one-dimensional array representation, each index is fixed and represents a predefined tile location. This precise representation is crucial for our problem-solving process. 

State representation and index array.

For example, index 0 corresponds to the top-left tile, index 1 to the top-center tile, and so on up to index 8 for the bottom-right tile. The value stored at each index indicates the actual tile number present in that location. 

For instance, in a given state, as seen here, index 0 holds the value 2, index 1 holds 3, and index 8 holds 7, indicating the tile numbers in those respective positions. Index 4 holds the empty tile.

By manipulating the values in this array representation, while adhering to the constraint of where the empty tile can move with each action, we can efficiently progress towards reaching the goal state of the puzzle. This approach allows us to efficiently track and navigate through the various configurations of the puzzle during the solving process, making our solution approach highly effective.


Neighbours

Our next objective is to construct the graph of neighbours for the 8-puzzle problem. This involves determining possible moves, or neighbour indices, for each of the 9 tile indices.

For example, starting with tile index 0, the neighbouring indices, where the empty tile can move, are indices 1 and 3.

Similarly, for tile index 1, the neighbours are indices 0, 2, and 4, and so on.

We will summarise this relationship in a list of neighbour indices for each tile index.

Neighbour tiles for an 8-puzzle state
index = 0, {1, 3}
index = 1, {0, 2, 4};
index = 2, {1, 5};
index = 3, {4, 0, 6};
index = 4, {3, 5, 1, 7};
index = 5, {4, 2, 8};
index = 6, {7, 3};
index = 7, {6, 8, 4};
index = 8, {7, 5};

Looking at the above list, we can now access the neighbours for any tile index. For example, for tile index 6, the neighbours are tile indices 7 and 3.

For the first figure below, we have our empty tile in index 4. So for index 4, the neighbours are index 1, 3, 5 and 8. Please note that I am referring to the index of the array and not the actual value of that element in that index of the array.

With this mapping in place, we can then easily determine the neighbours for any tile index. For instance, for tile index 6, the neighbours are tile indices 7 and 3. It’s important to note that these indices refer to positions within the array representation of the puzzle state, not the actual values stored in those array elements.


Node (or the State Tree)

The state tree is the actual tree that comprises all the valid transitions from one state to another state, ultimately reaching the final goal (if the solution exists).

In computer science, a tree is a widely used abstract data type (ADT)—or data structure implementing this ADT—that simulates a hierarchical tree structure, with a root value and subtrees of children with a parent node, represented as a set of linked nodes – source Wikipedia.

Each tree element we call Node will comprise one specific tile for an 8 puzzle for this problem.


Solver for 8 Puzzle

Finally, we look at the Solver framework. The Solver should be able to solve the puzzle based on the A* algorithm. The solver will be implemented simply as a main console function in C++ and a Coroutine in the Unity C# version. The solver class will construct the tree, visit the next best node and collect nodes for the solution until the solution is finally found.


Read Part 2 of the tutorial “Solving 8 puzzle problem using A* star search in C++.”

Read Part 3 of the tutorial 8-Puzzle Problem Using A* in C# and Unity.


Read My Other Tutorials

  1. Implement a Generic Pathfinder in Unity using C#
  2. Create a Jigsaw Puzzle Game in Unity
  3. Generic Finite State Machine Using C#
  4. Implement Bezier Curve using C# in Unity
  5. Create a Jigsaw Tile from an Existing Image
  6. Create a Jigsaw Board from an Existing Image
  7. Solving 8 puzzle problem using A* star search
  8. A Configurable Third-Person Camera in Unity
  9. Player Controls With Finite State Machine Using C# in Unity
  10. Finite State Machine Using C# Delegates in Unity
  11. Enemy Behaviour With Finite State Machine Using C# Delegates in Unity
  12. Augmented Reality – Fire Effect using Vuforia and Unity
  13. Implementing a Finite State Machine Using C# in Unity
  14. Solving 8 puzzle problem using A* star search in C++
  15. What Are C# Delegates And How To Use Them
  16. How to Generate Mazes Using Depth-First Algorithm

5 thoughts on “Solving 8 puzzle problem using A* star search”

  1. Simply want to say your article is as astonishing.
    The clarity in your post is just great and i could assume you’re an expert on this subject.

    Fine with your permission allow me to grab your feed to keep up
    to date with forthcoming post. Thanks a million and please continue the
    gratifying work.

  2. Wow! After all I got a website from where I be capable of actually
    get useful information regarding my study and knowledge.

  3. Wow, incredible blog layout! How long have you been blogging for?
    you make blogging look easy. The overall look of your site is fantastic, let alone the
    content!

Leave a Reply

Your email address will not be published. Required fields are marked *