-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
380 lines (304 loc) · 16 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
#################################################################################################################################
### Hassan Shahzad
### CS-D
### Artificial Intelligence (Assignment # 1)
### FAST-NUCES
### chhxnshah@gmail.com
##################################################################################################################################
import sys
import copy # Will be used to deep copy
####################################### GLOBAL VARIABLES #########################################################################
visited_indexes = [] # Tuple that will contain the nodes already visited for BFS
visited_indexes1 = [] # Tuple that will contain the nodes already visited for DFS
agent = "A" # Wil be used later to find index of agent
goal_index = [(10,0)] # Storing the goal index of agent
##CREATING THE MAZE##
## For this we will use 2D arrays and graphs
## In the maze, "*" will represent empty cells while "#" will represent blocked cells
rows , cols = (12,12) # 12 rows and 12 columns
maze = [] # Declaring variables
for i in range(rows): # Loop iterating through rows
col = []
for j in range(cols): # Loop iterating through columns
col.append("#") # Initially storing "#" to show every cell is blocked.
maze.append(col)
## Now the empty spaces are filled according to the given space
## I was exhausted so i decided to simply hardcode it instead of mapping
maze[1][1] = "*"
maze[2][1] = "*"
maze[1][2] = "*"
maze[1][3] = "*"
maze[2][3] = "*"
maze[3][3] = "*"
maze[4][3] = "*"
maze[4][1] = "*"
maze[4][2] = "*"
maze[4][4] = "*"
maze[5][4] = "*"
maze[6][4] = "*"
maze[7][4] = "*"
maze[8][4] = "*"
maze[8][1] = "*"
maze[8][2] = "*"
maze[8][3] = "*"
maze[8][5] = "*"
maze[8][6] = "*"
maze[8][7] = "*"
maze[8][8] = "*"
maze[6][1] = "*"
maze[6][2] = "*"
maze[7][2] = "*"
maze[10][0] = "*"
maze[10][1] = "*"
maze[10][2] = "*"
maze[10][3] = "*"
maze[10][4] = "*"
maze[10][5] = "*"
maze[10][6] = "*"
maze[1][10] = "*"
maze[2][10] = "*"
maze[3][10] = "*"
maze[4][10] = "*"
maze[5][10] = "*"
maze[6][10] = "*"
maze[7][10] = "*"
maze[8][10] = "*"
maze[9][10] = "*"
maze[10][10] = "*"
maze[10][8] = "*"
maze[10][9] = "*"
maze[1][5] = "*"
maze[1][6] = "*"
maze[1][7] = "*"
maze[1][8] = "*"
maze[1][9] = "*"
maze[2][5] = "*"
maze[3][5] = "*"
maze[3][6] = "*"
maze[3][7] = "*"
maze[3][8] = "*"
maze[4][8] = "*"
maze[5][8] = "*"
maze[6][8] = "*"
maze[7][8] = "*"
maze[5][6] = "*"
maze[6][6] = "*"
maze[7][6] = "*"
maze[9][6] = "*"
## Finally the start state
maze[4][11] = "A"
agent_index = [(index, rows.index(agent)) for index, rows in enumerate(maze) if agent in rows] # Storing the current index of agent
x = agent_index[0][0] # Will store the x-coordinate of agent
y = agent_index[0][1] # Will store the y-coordinate of agent
def printMatrix(mat) : # Prints the formatted matrix
for i in range(rows):
for j in range(cols):
print(mat[i][j],end = ' ')
print()
def matrixToIndex(state): # Takes matrix and returns index of actor
temp = state.copy()
idx = [(index, rows.index(agent)) for index, rows in enumerate(temp) if agent in rows] # Getting the index of the Agent (A)
x = idx[0][0] # Will store the x-coordinate of agent
y = idx[0][1] # Will store the y-coordinate of agent
return idx,x,y
######################################################################################################################################
################################################# CREATING NODES #####################################################################
class Node:
def __init__(self, state, parent, operator, moves): # Default Constructor
self.state = state
self.parent = parent
self.operator = operator
self.moves = moves
def create_node(state, parent, operator, cost): # This function creates a node of current state
return Node(state, parent, operator, cost)
def expand_node(node,n): # This function performs all possible operations
expanded_nodes = []
temp_state1 = move_up(node.state,n)
if (temp_state1 is not None):
temp_node1 = create_node(temp_state1,node,"up",node.moves+1) # The state is expanded with upward operation
expanded_nodes.append(temp_node1) # Appending the expanded nodes in the list
temp_state2 = move_left(node.state,n)
if (temp_state2 is not None):
temp_node2 = create_node(temp_state2,node,"left",node.moves+1) # The state is expanded with upward operation
expanded_nodes.append(temp_node2) # Appending the expanded nodes in the list
temp_state3 = move_right(node.state,n)
if (temp_state3 is not None):
temp_node3 = create_node(temp_state3,node,"right",node.moves+1) # The state is expanded with upward operation
expanded_nodes.append(temp_node3) # Appending the expanded nodes in the list
temp_state = move_down(node.state,n)
if (temp_state is not None):
temp_node = create_node(temp_state,node,"down",node.moves+1) # The state is expanded with downward operation
expanded_nodes.append(temp_node) # Appending the expanded nodes in the list
return expanded_nodes
def move_left(state,n):
swap = copy.deepcopy(state)
idx,x,y = matrixToIndex(swap) # Returning index of actor
if (swap[x][y-1] == "#" or y <= 0): # Checks for unallowed moves
return None
else:
swap[x][y-1] , swap[x][y] = swap[x][y] , swap[x][y-1] # Moving the agent one cell left
return swap
def move_right(state,n):
swap = copy.deepcopy(state)
idx,x,y = matrixToIndex(swap) # Returning index of actor
if (y >= n-1 or swap[x][y+1] == "#"): # Checks for unallowed moves
return None
else:
swap[x][y+1] , swap[x][y] = swap[x][y] , swap[x][y+1] # Moving the agent one cell left
return swap
def move_up(state,n):
swap = copy.deepcopy(state)
idx,x,y = matrixToIndex(swap) # Returning index of actor
if (swap[x-1][y] == "#" or x <= 0 ): # Checks for unallowed moves
return None
else:
swap[x-1][y] , swap[x][y] = swap[x][y] , swap[x-1][y] # Moving the agent one cell above
return swap
def move_down(state,n):
swap = copy.deepcopy(state)
idx,x,y = matrixToIndex(swap) # Returning index of actor
if (swap[x+1][y] == "#" or x >= n-1): # Checks for unallowed moves
return None
else:
swap[x+1][y] , swap[x][y] = swap[x][y] , swap[x+1][y] # Moving the agent one cell left
return swap
######################################################################################################################################
################################################## BFS ALGORITHM #####################################################################
def bfs(start,n):
temp_count =0
temp_idx,x1,y1 = matrixToIndex(start)
if (temp_idx == goal_index):
return [None]
else:
to_be_expanded = [] # Array of all nodes in one level/depth
current_node = create_node(start,None,None,0) # Starting node is stored
to_be_expanded.append(current_node) # Adding first node to the expanding array
while (1):
temp_expanded = [] # Storing the nodes not expanded
size = len(to_be_expanded) # Number of nodes yet to be expanded
for j in range(size) :
index,x1,y1 = matrixToIndex (to_be_expanded[j].state)
if (index in visited_indexes) : # Do not expand as has already been visited
continue
# one expansion
node_array = expand_node(to_be_expanded[j],n)
# checking the 4 nodes and adding them to the temp array
for k in range(len(node_array)):
idx,x,y = matrixToIndex(node_array[k].state)
temp_count+=1
if (idx == goal_index):
print()
print("Algorithm Used: BFS (Breadth First Search)")
print()
print("Maze Solved!!!")
print("Final State is as follows: ")
print()
printMatrix(node_array[k].state)
print()
print("Number of explorations in BFS = ", temp_count)
return node_array[k]
else :
temp_expanded.append(node_array[k]) # Node will be expanded later
visited_indexes.append(index) # Index has been visited
to_be_expanded.clear() # Clearing the previous (already expanded) nodes
to_be_expanded = temp_expanded.copy() # Copying over the newly generated nodes
temp_expanded.clear() # Clearing the temp array
return None
######################################################################################################################################
################################################## DFS ALGORITHM #####################################################################
def dfs(start,n):
temp_idx,x1,y1 = matrixToIndex(start) # Getting current index of the agent
if (temp_idx == goal_index): # If agent is already at goal state
return [None]
else:
stack = [] # Stack containing all nodes to be expanded
current_node = create_node(start,None,None,0) # Starting node is stored
stack.append(current_node)
count = 0
while(1):
count+=1
to_be_expanded = stack.pop() # Popping the node from stack to expand
idx,x,y = matrixToIndex(to_be_expanded.state)
if (idx == goal_index): # Checking if current index is goal state
print()
print("Algorithm Used: DFS (Depth First Search)")
print()
print("Maze Solved!!!")
print("Final State is as follows: ")
print()
printMatrix(to_be_expanded.state)
print()
print("Number of explorations in DFS = ", count)
return to_be_expanded
else:
visited_indexes1.append(idx) # Storing visited nodes in an array
# one expansion
node_array = expand_node(to_be_expanded,n) # Expanding the node that was popped earlier
for k in range(len(node_array)):
idx,x,y = matrixToIndex (node_array[k].state)
if (idx in visited_indexes1):
continue
else:
stack.append(node_array[k]) # Pushing the expanded nodes into the stack
return None
######################################################################################################################################
################################################# Implementation of Main done ########################################################
def main():
n=12
starting_state = maze
result = bfs(starting_state,n)
if result == None:
print("No solution found")
elif result == [None]:
print ("Start node was the goal!")
else:
print ("Total number of moves needed = ", result.moves)
# Un-Comment the following lines to see the stepwise execution of the moves taken by the actor
# path = []
# path.append(result.state)
# current = result
# flag = True
# while (flag):
# parent = current.parent
# prev_state = parent.state
# path.append(prev_state)
# current = parent
# if (prev_state == starting_state):
# flag = False
# path.reverse()
# for state in path:
# printMatrix(state)
# print()
print()
print()
print("######################################################################################################################")
print()
result1 = dfs(starting_state,n)
if result1 == None:
print("No solution found")
elif result1 == [None]:
print ("Start node was the goal!")
else:
print ("Total number of moves needed = ", result1.moves)
print()
# Un-Comment the following lines to see the stepwise execution of the moves taken by the actor
# path1 = []
# path1.append(result1.state)
# current1 = result1
# flag1 = True
# while (flag1):
# parent = current1.parent
# prev_state1 = parent.state
# path1.append(prev_state1)
# current1 = parent
# if (prev_state1 == starting_state):
# flag1 = False
# path1.reverse()
# for state in path1:
# printMatrix(state)
# print()
if __name__ == "__main__":
main()
######################################################################################################################
################################################### THE END ##########################################################
######################################################################################################################