0% found this document useful (0 votes)
151 views3 pages

Solve 8 Puzzle with Python Code

The document discusses writing a program to solve 8 puzzle problems using Python and Prolog code. It provides an implementation of solving the 8 puzzle problem using a priority queue and calculating Manhattan distance between puzzle states.

Uploaded by

Krupa
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
151 views3 pages

Solve 8 Puzzle with Python Code

The document discusses writing a program to solve 8 puzzle problems using Python and Prolog code. It provides an implementation of solving the 8 puzzle problem using a priority queue and calculating Manhattan distance between puzzle states.

Uploaded by

Krupa
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

211264116001

Artificial Intelligence (3161608)

Experiment No: 8

TITTLE: Write a program to solve 8 puzzle problems.


EXERCISE
1. Implement python and Prolog code to solve 8 Puzzle Problem.
Ans:
from queue import PriorityQueue
class PuzzleNode:
def __init__(self, state, parent=None, move=None):
[Link] = state
[Link] = parent
[Link] = move
[Link] = 0
[Link] = 0
if parent:
[Link] = [Link] + 1
def __lt__(self, other):
return [Link] < [Link]
def __eq__(self, other):
return [Link] == [Link]
def __hash__(self):
return hash(str([Link]))
def calculate_cost(self, goal_state):
[Link] = [Link] + self.manhattan_distance(goal_state)

def manhattan_distance(self, goal_state):


distance = 0
for i in range(3):

Prof. Ravi Patel


211264116001
Artificial Intelligence (3161608)

for j in range(3):
value = [Link][i][j]
if value != 0:
row = (value - 1) // 3
col = (value - 1) % 3
distance += abs(row - i) + abs(col - j)
return distance

def get_successors(node):
successors = []
i, j = next((i, j) for i in range(3) for j in range(3) if [Link][i][j] == 0)
for x, y in [(i+1, j), (i-1, j), (i, j+1), (i, j-1)]:
if 0 <= x < 3 and 0 <= y < 3:
new_state = [row[:] for row in [Link]]
new_state[i][j], new_state[x][y] = new_state[x][y], new_state[i][j]
[Link](PuzzleNode(new_state, node, (x, y)))
return successors

def solve_8_puzzle(initial_state, goal_state):


start_node = PuzzleNode(initial_state)
start_node.calculate_cost(goal_state)
frontier = PriorityQueue()
[Link](start_node)
explored = set()
while not [Link]():
current_node = [Link]()
if current_node.state == goal_state:

Prof. Ravi Patel


211264116001
Artificial Intelligence (3161608)

path = []
while current_node:
[Link](current_node.state)
current_node = current_node.parent
[Link]()
return path
[Link](current_node)
for successor in get_successors(current_node):
if successor not in explored:
successor.calculate_cost(goal_state)
[Link](successor)
return None
# Example usage:
initial_state = [[1, 2, 3], [4, 5, 6], [7, 0, 8]]
goal_state = [[1, 2, 3], [4, 5, 6], [7, 8, 0]]
path = solve_8_puzzle(initial_state, goal_state)
if path:
print("Solution Path:")
for state in path:
print(state)
else:
print("No solution found.")
Output:
Solution Path:
[[1, 2, 3], [4, 5, 6], [7, 0, 8]]
[[1, 2, 3], [4, 5, 6], [7, 8, 0]]

Prof. Ravi Patel

Common questions

Powered by AI

The `manhattan_distance` is preferred in the 8-puzzle problem because it provides an admissible heuristic, meaning that it never overestimates the cost to reach the goal. This is crucial for ensuring the A* algorithm finds the optimal solution. The Manhattan distance efficiently captures the minimal number of moves required to align each tile with its target position, fundamentally guiding the search process by prioritizing paths that minimize total moves. Moreover, its computational simplicity and ability to guide the search effectively without excessive complexity make it a suitable choice for this problem .

One limitation of the provided Python code for solving the 8-puzzle problem is that it assumes the initial configuration is solvable without verifying the solvability condition of the start state. In the 8-puzzle, not all initial configurations can be solved; specifically, solvability is determined by the number of inversions in the initial state. Failing to check for this could lead to computational resources being spent on trying to solve an unsolvable puzzle configuration, thus potentially leading to inefficiency, particularly with larger state spaces .

The movement of the blank tile in the 8-puzzle solution is represented by identifying the blank's current position and attempting to swap it with adjacent tiles. The function `get_successors` systematically checks each of the four possible movements (up, down, left, right) from the current position of the blank tile. If a movement results in a valid position within the bounds of the 3x3 grid, the state is updated to reflect this move and the corresponding new state is stored as a successor of the current node .

The `PriorityQueue` in the 8-puzzle solution is used to manage the nodes in the order of their priority, determined by their total cost (depth plus Manhattan distance to the goal). It functions within the A* algorithm by always expanding the least-cost node first, which is the node with the lowest priority value. This data structure allows the algorithm to efficiently find the optimal path by exploring the most promising nodes first, thus guiding the search towards the goal while minimizing unnecessary expansions .

Hashing in the 8-puzzle problem is significant because it allows for efficient tracking and detection of explored states. In the implemented solution, each `PuzzleNode` generates a hash from its state's string representation. This hash helps quickly determine whether a state has been seen before, thus preventing redundant explorations and computational waste. It ensures that the algorithm avoids cycles and revisiting nodes, optimizing the search and reducing unnecessary computations .

In the Python implementation of the 8-puzzle problem, the cost of a node is calculated as the sum of the node's depth and its Manhattan distance from the goal state. The code uses a method named `calculate_cost` which internally calls `manhattan_distance`. The Manhattan distance calculates how far each tile is from its target position in terms of grid lines. This heuristic ensures that each move gets us closer to the goal, and is important because it determines the priority of nodes in the PriorityQueue used in the A* search algorithm to efficiently find the solution .

The backtracking mechanism for reconstructing the solution path in the 8-puzzle problem operates by retracing the parent nodes from the goal state back to the initial state. Once a node corresponding to the goal state is dequeued from the PriorityQueue, the code enters a loop where it repeatedly records the current node's state and then assigns its parent to the current node. This process continues until the initial node (with no parent) is reached. The recorded states are stored in reverse order and finally reversed to present the correct sequence from the initial to the goal state, representing the solution path .

The termination condition of the A* algorithm in the 8-puzzle solution is when a node that corresponds to the goal state is dequeued from the PriorityQueue. At this point, the algorithm has found a path from the initial state to the goal state, and the solution can be reconstructed by backtracking from this node to the initial node. This marks a successful termination where the goal has been reached, and the solution path can be returned. If the PriorityQueue is exhausted without reaching the goal, the algorithm concludes no solution exists .

If the `manhattan_distance` heuristic were not included in the 8-puzzle algorithm, the search process would rely solely on the breadth-first search aspect of A*, which prioritizes nodes based only on their depth (or cost so far). This would dramatically increase the search space as the algorithm would lose its heuristic guidance system to efficiently reach the goal. As a result, the algorithm might explore many unnecessary states, significantly increasing time complexity and generally leading to slower solutions, especially in larger and more complex puzzles .

In the Python code for solving the 8-puzzle problem, 'successors' refer to the possible new states generated by moving the blank tile in the puzzle. They are generated using the `get_successors` function, which identifies the position of the blank tile and attempts to move it in four possible directions (up, down, left, right) if the move is valid (within the grid boundaries). Each move leads to a new state, which is represented as a new PuzzleNode, and these nodes are collected as potential paths towards reaching the goal state .

You might also like