Skip to content

Commit 089fa72

Browse files
authored
Add files via upload
1 parent ce3dd92 commit 089fa72

File tree

1 file changed

+235
-0
lines changed

1 file changed

+235
-0
lines changed
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
'''
2+
8 PUZZLE PROBLEM SOLVING USING A* ALGORITHM
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+
A* algorithm has 3 parameters:
24+
g: the cost of moving from the initial cell to the current cell.
25+
h: also known as the heuristic value, it is the estimated cost of moving from
26+
the current cell to the final cell. The actual cost cannot be calculated until
27+
the final cell is reached. Hence, h is the estimated cost. We must make sure
28+
that there is never an over estimation of the cost.
29+
f: it is the sum of g and h. So, f = g + h
30+
We always go to the state that has minimum 'f' value.
31+
32+
'''
33+
34+
# importing the necessary libraries
35+
from time import time
36+
from queue import PriorityQueue
37+
38+
# creating a class Puzzle
39+
class Puzzle:
40+
# setting the goal state of 8-puzzle
41+
goal_state=[1,2,3,8,0,4,7,6,5]
42+
# setting up the members of a class
43+
heuristic=None
44+
evaluation_function=None
45+
needs_hueristic=False
46+
num_of_instances=0
47+
48+
# constructor to initialize the class members
49+
def __init__(self,state,parent,action,path_cost,needs_hueristic=False):
50+
self.parent=parent
51+
self.state=state
52+
self.action=action
53+
# calculating the path_cost as the sum of its parent cost and path_cost
54+
if parent:
55+
self.path_cost = path_cost + parent.path_cost
56+
else:
57+
self.path_cost = path_cost
58+
if needs_hueristic:
59+
self.needs_hueristic=True
60+
self.generate_heuristic()
61+
# calculating the expression as f = g + h
62+
self.evaluation_function= path_cost + needs_hueristic
63+
# incrementing the number of instance by 1
64+
Puzzle.num_of_instances+=1
65+
66+
# method used to display a state of 8-puzzle
67+
def __str__(self):
68+
return str(self.state[0:3])+'\n'+str(self.state[3:6])+'\n'+str(self.state[6:9])
69+
70+
# method used to generate a heuristic value
71+
def generate_heuristic(self):
72+
self.heuristic=0
73+
for num in range(1,9):
74+
# calculating the heuristic value as manhattan distance which is the absolute
75+
# difference between current state and goal state.
76+
# using index() method to get the index of num in state
77+
distance= abs(self.state.index(num) - self.goal_state.index(num))
78+
i=int(distance/3)
79+
j=int(distance%3)
80+
self.heuristic=self.heuristic+i+j
81+
82+
def goal_test(self):
83+
# including a condition to compare the current state with the goal state
84+
if self.state == self.goal_state:
85+
return True
86+
return False
87+
88+
@staticmethod
89+
def find_legal_actions(i,j):
90+
# find the legal actions as Up, Down, Left, Right based on each cell of state
91+
legal_action = ['U', 'D', 'L', 'R']
92+
if i == 0: # up is disable
93+
# if row is 0 in board then up is disable
94+
legal_action.remove('U')
95+
elif i == 2:
96+
legal_action.remove('D')
97+
if j == 0:
98+
legal_action.remove('L')
99+
elif j == 2:
100+
legal_action.remove('R')
101+
# returnig legal_action
102+
return legal_action
103+
104+
# method to generate the child of the current state of the board
105+
def generate_child(self):
106+
children=[]
107+
x = self.state.index(0)
108+
# generating the row (i) & col (j) position based on the current index of 0 on the board
109+
i = int(x/3)
110+
j = int(x%3)
111+
# calling the method to find the legal actions based on i and j values
112+
legal_actions=self.find_legal_actions(i,j)
113+
114+
for action in legal_actions:
115+
new_state = self.state.copy()
116+
# if the legal action is UP
117+
if action is 'U':
118+
# swapping between current index of 0 with its up element on the board
119+
new_state[x], new_state[x-3] = new_state[x-3], new_state[x]
120+
elif action is 'D':
121+
# swapping between current index of 0 with its down element on the board
122+
new_state[x], new_state[x+3] = new_state[x+3], new_state[x]
123+
elif action is 'L':
124+
# swapping between the current index of 0 with its left element on the board
125+
new_state[x], new_state[x-1] = new_state[x-1], new_state[x]
126+
elif action is 'R':
127+
# swapping between the current index of 0 with its right element on the board
128+
new_state[x], new_state[x+1] = new_state[x+1], new_state[x]
129+
# appending the new_state of Puzzle object with parent, action,path_cost is 1, its needs_hueristic flag
130+
children.append(Puzzle(new_state, self, action, 1, self.needs_hueristic))
131+
# returning the children
132+
return children
133+
134+
# method to find the solution
135+
def find_solution(self):
136+
solution = []
137+
all_states = []
138+
solution.append(self.action)
139+
all_states.append(self)
140+
path = self
141+
while path.parent != None:
142+
path = path.parent
143+
solution.append(path.action)
144+
all_states.append(path)
145+
solution = solution[:-1]
146+
solution.reverse
147+
148+
print('\nAll states from goal to initial: ')
149+
for i in all_states:
150+
print(i, '\n')
151+
return solution
152+
153+
# method for A-star search
154+
# passing the initial_state as parameter to the breadth_first_search method
155+
def Astar_search(initial_state):
156+
count=0
157+
# creating an empty list of explored nodes
158+
explored=[]
159+
# creating a instance of Puzzle as initial_state, None, None, 0, True
160+
start_node=Puzzle(initial_state, None, None, 0, True)
161+
q = PriorityQueue()
162+
# putting a tuple with start_node.evaluation_function, count, start_node into PriorityQueue
163+
q.put((start_node.evaluation_function, count, start_node))
164+
165+
while not q.empty():
166+
# getting the current node of a queue. Use the get() method of Queue
167+
node=q.get()
168+
# extracting the current node of a PriorityQueue based on the index of a tuple.
169+
# referring a tuple format put in PriorityQueue
170+
node=node[2]
171+
# appending the state of node in the explored list as node.state
172+
explored.append(node.state)
173+
if node.goal_test():
174+
return node.find_solution()
175+
# calling the generate_child method to generate the child node of current node
176+
children=node.generate_child()
177+
for child in children:
178+
if child.state not in explored:
179+
count += 1
180+
# putting a tuple with child.evaluation_function, count, child into PriorityQueue
181+
q.put((child.evaluation_function, count, child))
182+
return
183+
184+
# starting executing the 8-puzzle with setting up the initial state
185+
# here we have considered 3 initial state intitalized using state variable
186+
state= [1, 3, 4,
187+
8, 6, 2,
188+
7, 0, 5]
189+
190+
# initializing the num_of_instances to zero
191+
Puzzle.num_of_instances = 0
192+
# set t0 to current time
193+
t0 = time()
194+
astar = Astar_search(state)
195+
# getting the time t1 after executing the breadth_first_search method
196+
t1 = time() - t0
197+
print('A*:',astar)
198+
print('space:', Puzzle.num_of_instances)
199+
print('time:', t1)
200+
print()
201+
print('------------------------------------------')
202+
203+
'''
204+
Sample working:
205+
206+
All states from goal to initial:
207+
[1, 2, 3]
208+
[8, 0, 4]
209+
[7, 6, 5]
210+
211+
[1, 0, 3]
212+
[8, 2, 4]
213+
[7, 6, 5]
214+
215+
[1, 3, 0]
216+
[8, 2, 4]
217+
[7, 6, 5]
218+
219+
[1, 3, 4]
220+
[8, 2, 0]
221+
[7, 6, 5]
222+
223+
[1, 3, 4]
224+
[8, 0, 2]
225+
[7, 6, 5]
226+
227+
[1, 3, 4]
228+
[8, 6, 2]
229+
[7, 0, 5]
230+
231+
A*: ['D', 'L', 'U', 'R', 'U']
232+
space: 117
233+
time: 0.0029821395874023438
234+
235+
'''

0 commit comments

Comments
 (0)