├── README.md
├── .idea
├── misc.xml
├── modules.xml
├── puzzle.iml
└── workspace.xml
├── BFS_search.py
├── Astar_search.py
├── RBFS_search.py
├── main.py
├── .gitignore
└── puzzle.py
/README.md:
--------------------------------------------------------------------------------
1 | # 8-puzzle-search-implementation
2 | this a python BFS , A* and RBFS implementation of 8 puzzle
3 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/puzzle.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/BFS_search.py:
--------------------------------------------------------------------------------
1 | from queue import Queue
2 | from puzzle import Puzzle
3 |
4 |
5 | def breadth_first_search(initial_state):
6 | start_node = Puzzle(initial_state, None, None, 0)
7 | if start_node.goal_test():
8 | return start_node.find_solution()
9 | q = Queue()
10 | q.put(start_node)
11 | explored=[]
12 | while not(q.empty()):
13 | node=q.get()
14 | explored.append(node.state)
15 | children=node.generate_child()
16 | for child in children:
17 | if child.state not in explored:
18 | if child.goal_test():
19 | return child.find_solution()
20 | q.put(child)
21 | return
22 |
--------------------------------------------------------------------------------
/Astar_search.py:
--------------------------------------------------------------------------------
1 | from queue import PriorityQueue
2 | from puzzle import Puzzle
3 |
4 |
5 | def Astar_search(initial_state):
6 | count=0
7 | explored=[]
8 | start_node=Puzzle(initial_state,None,None,0,True)
9 | q = PriorityQueue()
10 | q.put((start_node.evaluation_function,count,start_node))
11 |
12 | while not q.empty():
13 | node=q.get()
14 | node=node[2]
15 | explored.append(node.state)
16 | if node.goal_test():
17 | return node.find_solution()
18 |
19 | children=node.generate_child()
20 | for child in children:
21 | if child.state not in explored:
22 | count += 1
23 | q.put((child.evaluation_function,count,child))
24 | return
25 |
26 |
--------------------------------------------------------------------------------
/RBFS_search.py:
--------------------------------------------------------------------------------
1 | from puzzle import Puzzle
2 | from sys import maxsize
3 |
4 |
5 | def recursive_best_first_search(initial_state):
6 | node=RBFS_search(Puzzle(state=initial_state, parent=None, action=None, path_cost=0, needs_hueristic=True), f_limit=maxsize)
7 | node=node[0]
8 | return node.find_solution()
9 |
10 | def RBFS_search(node,f_limit):
11 | successors=[]
12 |
13 | if node.goal_test():
14 | return node,None
15 | children=node.generate_child()
16 | if not len(children):
17 | return None, maxsize
18 | count=-1
19 | for child in children:
20 | count+=1
21 | successors.append((child.evaluation_function,count,child))
22 | while len(successors):
23 | successors.sort()
24 | best_node=successors[0][2]
25 | if best_node.evaluation_function > f_limit:
26 | return None, best_node.evaluation_function
27 | alternative=successors[1][0]
28 | result,best_node.evaluation_function=RBFS_search(best_node,min(f_limit,alternative))
29 | successors[0]=(best_node.evaluation_function,successors[0][1],best_node)
30 | if result!=None:
31 | break
32 | return result,None
33 |
34 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | from time import time
2 | from BFS_search import breadth_first_search
3 | from Astar_search import Astar_search
4 | from RBFS_search import recursive_best_first_search
5 | from puzzle import Puzzle
6 |
7 |
8 | state=[[1, 3, 4,
9 | 8, 6, 2,
10 | 7, 0, 5],
11 |
12 | [2, 8, 1,
13 | 0, 4, 3,
14 | 7, 6, 5],
15 |
16 | [2, 8, 1,
17 | 4, 6, 3,
18 | 0, 7, 5]]
19 |
20 | for i in range(0,3):
21 | Puzzle.num_of_instances=0
22 | t0=time()
23 | bfs=breadth_first_search(state[i])
24 | t1=time()-t0
25 | print('BFS:', bfs)
26 | print('space:',Puzzle.num_of_instances)
27 | print('time:',t1)
28 | print()
29 |
30 | Puzzle.num_of_instances = 0
31 | t0 = time()
32 | astar = Astar_search(state[i])
33 | t1 = time() - t0
34 | print('A*:',astar)
35 | print('space:', Puzzle.num_of_instances)
36 | print('time:', t1)
37 | print()
38 |
39 | Puzzle.num_of_instances = 0
40 | t0 = time()
41 | RBFS = recursive_best_first_search(state[i])
42 | t1 = time() - t0
43 | print('RBFS:',RBFS)
44 | print('space:', Puzzle.num_of_instances)
45 | print('time:', t1)
46 | print()
47 |
48 | print('------------------------------------------')
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
--------------------------------------------------------------------------------
/puzzle.py:
--------------------------------------------------------------------------------
1 | class Puzzle:
2 | goal_state=[1,2,3,8,0,4,7,6,5]
3 | heuristic=None
4 | evaluation_function=None
5 | needs_hueristic=False
6 | num_of_instances=0
7 | def __init__(self,state,parent,action,path_cost,needs_hueristic=False):
8 | self.parent=parent
9 | self.state=state
10 | self.action=action
11 | if parent:
12 | self.path_cost = parent.path_cost + path_cost
13 | else:
14 | self.path_cost = path_cost
15 | if needs_hueristic:
16 | self.needs_hueristic=True
17 | self.generate_heuristic()
18 | self.evaluation_function=self.heuristic+self.path_cost
19 | Puzzle.num_of_instances+=1
20 |
21 | def __str__(self):
22 | return str(self.state[0:3])+'\n'+str(self.state[3:6])+'\n'+str(self.state[6:9])
23 |
24 | def generate_heuristic(self):
25 | self.heuristic=0
26 | for num in range(1,9):
27 | distance=abs(self.state.index(num) - self.goal_state.index(num))
28 | i=int(distance/3)
29 | j=int(distance%3)
30 | self.heuristic=self.heuristic+i+j
31 |
32 | def goal_test(self):
33 | if self.state == self.goal_state:
34 | return True
35 | return False
36 |
37 | @staticmethod
38 | def find_legal_actions(i,j):
39 | legal_action = ['U', 'D', 'L', 'R']
40 | if i == 0: # up is disable
41 | legal_action.remove('U')
42 | elif i == 2: # down is disable
43 | legal_action.remove('D')
44 | if j == 0:
45 | legal_action.remove('L')
46 | elif j == 2:
47 | legal_action.remove('R')
48 | return legal_action
49 |
50 | def generate_child(self):
51 | children=[]
52 | x = self.state.index(0)
53 | i = int(x / 3)
54 | j = int(x % 3)
55 | legal_actions=self.find_legal_actions(i,j)
56 |
57 | for action in legal_actions:
58 | new_state = self.state.copy()
59 | if action is 'U':
60 | new_state[x], new_state[x-3] = new_state[x-3], new_state[x]
61 | elif action is 'D':
62 | new_state[x], new_state[x+3] = new_state[x+3], new_state[x]
63 | elif action is 'L':
64 | new_state[x], new_state[x-1] = new_state[x-1], new_state[x]
65 | elif action is 'R':
66 | new_state[x], new_state[x+1] = new_state[x+1], new_state[x]
67 | children.append(Puzzle(new_state,self,action,1,self.needs_hueristic))
68 | return children
69 |
70 | def find_solution(self):
71 | solution = []
72 | solution.append(self.action)
73 | path = self
74 | while path.parent != None:
75 | path = path.parent
76 | solution.append(path.action)
77 | solution = solution[:-1]
78 | solution.reverse()
79 | return solution
80 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
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 |
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 |
381 |
382 |
383 |
384 |
385 |
386 | 1525675718559
387 |
388 |
389 | 1525675718559
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
--------------------------------------------------------------------------------