Skip to content

Commit 2ae3107

Browse files
authored
Merge pull request #585 from Manasi2001/issue-584
8 Puzzle Problem using BFS
2 parents e3cecaa + bbebb47 commit 2ae3107

File tree

1 file changed

+333
-0
lines changed

1 file changed

+333
-0
lines changed
Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
'''
2+
8 PUZZLE PROBLEM SOLVING USING BREADTH FIRST SEARCH
3+
4+
An instance of the n-puzzle game consists of a board holding n^{2}-1
5+
distinct movable tiles, plus an empty space. The tiles are numbers from
6+
the set 1,..,n^{2}-1. For any such board, the empty space may be legally
7+
swapped with any tile horizontally or vertically adjacent to it. In this
8+
assignment, the blank space is going to be represented with the number 0.
9+
Given an initial state of the board, the combinatorial search problem is
10+
to find a sequence of moves that transitions this state to the goal state;
11+
that is, the configuration with all tiles arranged in ascending order
12+
0,1,..,n^{2}-1.
13+
14+
So, this is the goal state that we want to reach:
15+
[1, 2, 3]
16+
[8, 0, 4]
17+
[7, 6, 5]
18+
19+
The search space is the set of all possible states reachable from the
20+
initial state. The blank space may be swapped with a component in one of
21+
the four directions {‘Up’, ‘Down’, ‘Left’, ‘Right’}, one move at a time.
22+
23+
Algorithm Review:
24+
The search begins by visiting the root node of the search tree, given by
25+
the initial state. Among other book-keeping details, three major things
26+
happen in sequence in order to visit a node:
27+
-First, we remove a node from the frontier set.
28+
-Second, we check the state against the goal state to determine if a
29+
solution has been found.
30+
-Finally, if the result of the check is negative, we then expand the node.
31+
To expand a given node, we generate successor nodes adjacent to the current
32+
node, and add them to the frontier set. Note that if these successor nodes
33+
are already in the frontier, or have already been visited, then they should
34+
not be added to the frontier again.
35+
36+
'''
37+
38+
# importing the necessary libraries
39+
from time import time
40+
from queue import Queue
41+
42+
# creating a class Puzzle
43+
class Puzzle:
44+
# setting the goal state of 8-puzzle
45+
goal_state=[1,2,3,8,0,4,7,6,5]
46+
num_of_instances=0
47+
# constructor to initialize the class members
48+
def __init__(self,state,parent,action):
49+
self.parent=parent
50+
self.state=state
51+
self.action=action
52+
53+
# incrementing the number of instance by 1
54+
Puzzle.num_of_instances+= 1
55+
56+
# function used to display a state of 8-puzzle
57+
def __str__(self):
58+
return str(self.state[0:3])+'\n'+str(self.state[3:6])+'\n'+str(self.state[6:9])
59+
60+
# method to compare the current state with the goal state
61+
def goal_test(self):
62+
# including a condition to compare the current state with the goal state
63+
if Puzzle.goal_state == self.state:
64+
return True
65+
else:
66+
return False
67+
68+
# static method to find the legal action based on the current board position
69+
@staticmethod
70+
def find_legal_actions(i,j):
71+
legal_action = ['U', 'D', 'L', 'R']
72+
if i == 0:
73+
# if row is 0 in board then up is disabled
74+
legal_action.remove('U')
75+
elif i == 2:
76+
# if row is 2 in board then down is disabled
77+
legal_action.remove('D')
78+
if j == 0:
79+
# if column is 0 in board then left is disabled
80+
legal_action.remove('L')
81+
elif j == 2:
82+
# if column is 2 in board then right is disabled
83+
legal_action.remove('R')
84+
return legal_action
85+
86+
# method to generate the child of the current state of the board
87+
def generate_child(self):
88+
# creating an empty list
89+
children=[]
90+
x = self.state.index(0)
91+
i = int(x / 3)
92+
j = int(x % 3)
93+
# calling the method to find the legal actions based on i and j values
94+
legal_actions = self.find_legal_actions(i, j)
95+
96+
# iterating over all legal actions
97+
for action in legal_actions:
98+
new_state = self.state.copy()
99+
# if the legal action is UP
100+
if action is 'U':
101+
# swapping between current index of 0 with its up element on the board
102+
new_state[x], new_state[x-3] = new_state[x-3], new_state[x]
103+
elif action is 'D':
104+
# swapping between current index of 0 with its down element on the board
105+
new_state[x], new_state[x+3] = new_state[x+3], new_state[x]
106+
elif action is 'L':
107+
# swapping between the current index of 0 with its left element on the board
108+
new_state[x], new_state[x-1] = new_state[x-1], new_state[x]
109+
elif action is 'R':
110+
# swapping between the current index of 0 with its right element on the board
111+
new_state[x], new_state[x+1] = new_state[x+1], new_state[x]
112+
children.append(Puzzle(new_state,self,action))
113+
# returning the children
114+
return children
115+
# method to find the solution
116+
def find_solution(self):
117+
solution = []
118+
all_states = []
119+
solution.append(self.action)
120+
all_states.append(self)
121+
path = self
122+
while path.parent != None:
123+
path = path.parent
124+
solution.append(path.action)
125+
all_states.append(path)
126+
solution = solution[:-1]
127+
solution.reverse()
128+
all_states.reverse()
129+
130+
print("\nAll states: ")
131+
for i in all_states:
132+
print(i, "\n")
133+
return solution
134+
135+
# method for breadth first search
136+
# passing the initial_state as parameter to the breadth_first_search method
137+
def breadth_first_search(initial_state):
138+
start_node = Puzzle(initial_state, None, None)
139+
print("Initial state:")
140+
print(start_node)
141+
if start_node.goal_test():
142+
return start_node.find_solution()
143+
q = Queue()
144+
# putting start_node into the Queue
145+
q.put(start_node)
146+
# creating an empty list of explored nodes
147+
explored=[]
148+
# iterating the queue until empty, using the empty() method of Queue
149+
while not(q.empty()):
150+
# getting the current node of a queue, using the get() method of Queue
151+
node=q.get()
152+
# append the state of node in the explored list as node.state
153+
explored.append(node.state)
154+
# calling the generate_child method to generate the child nodes of current node
155+
children = node.generate_child()
156+
# iterating over each child node in children
157+
for child in children:
158+
if child.state not in explored:
159+
if child.goal_test():
160+
return child.find_solution()
161+
q.put(child)
162+
return
163+
164+
# start executing the 8-puzzle with setting up the initial state
165+
# here we have considered 3 initial state intitalized using state variable
166+
state=[1, 3, 4,
167+
8, 6, 2,
168+
7, 0, 5]
169+
# initializing the num_of_instances to zero
170+
Puzzle.num_of_instances = 0
171+
# setting t0 to current time
172+
t0 = time()
173+
bfs = breadth_first_search(state)
174+
# getting the time t1 after executing the breadth_first_search method
175+
t1 = time() - t0
176+
print('BFS:', bfs)
177+
print('space:',Puzzle.num_of_instances)
178+
print('time:',t1)
179+
print()
180+
print('------------------------------------------')
181+
182+
'''
183+
Sample working:
184+
185+
Initial state:
186+
[1, 3, 4]
187+
[8, 6, 2]
188+
[7, 0, 5]
189+
190+
All states:
191+
[1, 3, 4]
192+
[8, 6, 2]
193+
[7, 0, 5]
194+
195+
[1, 3, 4]
196+
[8, 0, 2]
197+
[7, 6, 5]
198+
199+
[1, 3, 4]
200+
[8, 2, 0]
201+
[7, 6, 5]
202+
203+
[1, 3, 0]
204+
[8, 2, 4]
205+
[7, 6, 5]
206+
207+
[1, 0, 3]
208+
[8, 2, 4]
209+
[7, 6, 5]
210+
211+
[1, 2, 3]
212+
[8, 0, 4]
213+
[7, 6, 5]
214+
215+
BFS: ['U', 'R', 'U', 'L', 'D']
216+
space: 66
217+
time: 0.0
218+
219+
Initial state:
220+
[2, 8, 1]
221+
[0, 4, 3]
222+
[7, 6, 5]
223+
224+
All states:
225+
[2, 8, 1]
226+
[0, 4, 3]
227+
[7, 6, 5]
228+
229+
[0, 8, 1]
230+
[2, 4, 3]
231+
[7, 6, 5]
232+
233+
[8, 0, 1]
234+
[2, 4, 3]
235+
[7, 6, 5]
236+
237+
[8, 1, 0]
238+
[2, 4, 3]
239+
[7, 6, 5]
240+
241+
[8, 1, 3]
242+
[2, 4, 0]
243+
[7, 6, 5]
244+
245+
[8, 1, 3]
246+
[2, 0, 4]
247+
[7, 6, 5]
248+
249+
[8, 1, 3]
250+
[0, 2, 4]
251+
[7, 6, 5]
252+
253+
[0, 1, 3]
254+
[8, 2, 4]
255+
[7, 6, 5]
256+
257+
[1, 0, 3]
258+
[8, 2, 4]
259+
[7, 6, 5]
260+
261+
[1, 2, 3]
262+
[8, 0, 4]
263+
[7, 6, 5]
264+
265+
BFS: ['U', 'R', 'R', 'D', 'L', 'L', 'U', 'R', 'D']
266+
space: 591
267+
time: 0.0030422210693359375
268+
269+
Initial state:
270+
[2, 8, 1]
271+
[4, 6, 3]
272+
[0, 7, 5]
273+
274+
All states:
275+
[2, 8, 1]
276+
[4, 6, 3]
277+
[0, 7, 5]
278+
279+
[2, 8, 1]
280+
[4, 6, 3]
281+
[7, 0, 5]
282+
283+
[2, 8, 1]
284+
[4, 0, 3]
285+
[7, 6, 5]
286+
287+
[2, 8, 1]
288+
[0, 4, 3]
289+
[7, 6, 5]
290+
291+
[0, 8, 1]
292+
[2, 4, 3]
293+
[7, 6, 5]
294+
295+
[8, 0, 1]
296+
[2, 4, 3]
297+
[7, 6, 5]
298+
299+
[8, 1, 0]
300+
[2, 4, 3]
301+
[7, 6, 5]
302+
303+
[8, 1, 3]
304+
[2, 4, 0]
305+
[7, 6, 5]
306+
307+
[8, 1, 3]
308+
[2, 0, 4]
309+
[7, 6, 5]
310+
311+
[8, 1, 3]
312+
[0, 2, 4]
313+
[7, 6, 5]
314+
315+
[0, 1, 3]
316+
[8, 2, 4]
317+
[7, 6, 5]
318+
319+
[1, 0, 3]
320+
[8, 2, 4]
321+
[7, 6, 5]
322+
323+
[1, 2, 3]
324+
[8, 0, 4]
325+
[7, 6, 5]
326+
327+
BFS: ['R', 'U', 'L', 'U', 'R', 'R', 'D', 'L', 'L', 'U', 'R', 'D']
328+
space: 2956
329+
time: 0.03542494773864746
330+
331+
------------------------------------------
332+
333+
'''

0 commit comments

Comments
 (0)