You are on page 1of 7

from collections import deque

class PuzzleState:
def __init__(self, board,
parent=None):
self.board = board
self.blank_position =
self.find_blank_position()
self.hash =
self.calculate_hash()
self.parent = parent

def find_blank_position(self):
for i in range(3):
for j in range(3):
if self.board[i][j] ==
0:
return i, j

def calculate_hash(self):
return tuple(map(tuple,
self.board))

def __eq__(self, other):


return self.hash == other.hash

def __hash__(self):
return hash(self.hash)

def __str__(self):
return '\n'.join(['
'.join(map(str, row)) for row in
self.board])

def is_solvable(initial, goal):


# Check if the initial and goal
states have the same parity
inversions_initial =
count_inversions(initial)
inversions_goal =
count_inversions(goal)
return inversions_initial % 2 ==
inversions_goal % 2

def count_inversions(board):
flattened_board = [val for row in
board for val in row if val != 0]
inversions = 0
for i in
range(len(flattened_board)):
for j in range(i + 1,
len(flattened_board)):
if flattened_board[i] >
flattened_board[j]:
inversions += 1
return inversions

def bidirectional_search(initial,
goal):
if not is_solvable(initial, goal):
return None

initial_state =
PuzzleState(initial)
goal_state = PuzzleState(goal)

# Initialize forward and backward


queues
forward_queue =
deque([initial_state])
backward_queue =
deque([goal_state])

# Initialize forward and backward


visited sets
forward_visited = {initial_state}
backward_visited = {goal_state}

while forward_queue and


backward_queue:
# Explore one level from the
forward direction
forward_state =
forward_queue.popleft()
for neighbor in
generate_neighbors(forward_state):
if neighbor in
backward_visited:
# Found a meeting point
return
reconstruct_path(forward_state,
neighbor, goal_state)
if neighbor not in
forward_visited:
forward_visited.add(neighbor)
forward_queue.append(neighbor)

# Explore one level from the


backward direction
backward_state =
backward_queue.popleft()
for neighbor in
generate_neighbors(backward_state):
if neighbor in
forward_visited:
# Found a meeting point
return
reconstruct_path(backward_state,
neighbor, goal_state)
if neighbor not in
backward_visited:
backward_visited.add(neighbor)
backward_queue.append(neighbor)

return None

def generate_neighbors(state):
i, j = state.blank_position
neighbors = []

for dx, dy in [(1, 0), (-1, 0), (0,


1), (0, -1)]:
ni, nj = i + dx, j + dy
if 0 <= ni < 3 and 0 <= nj < 3:
new_board = [list(row) for
row in state.board]
new_board[i][j],
new_board[ni][nj] = new_board[ni][nj],
new_board[i][j]
neighbors.append(PuzzleState(new_board,
parent=state))

return neighbors

def reconstruct_path(start, middle,


goal):
path = []
current = middle

while current != start:


path.append(current)
current = current.parent

path.reverse()
current = middle

while current != goal:


current = current.parent
path.append(current)

return path

# Example usage:
initial_state = [
[1, 2, 3],
[0, 4, 6],
[7, 5, 8]
]

goal_state = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 0]
]

path =
bidirectional_search(initial_state,
goal_state)

if path:
print("Solution found!")
for step, state in enumerate(path):
print(f"Step {step}:")
print(state)
else:
print("No solution found.")

Output :
C:\Users\Avantika\gui\venv\Scripts\python.exe
C:/Users/Avantika/gui/main.py
Solution found!
Step 0:
123
406
758
Step 1:
123
456
708
Step 2:
123
456
780

Process finished with exit code 0

You might also like