44import math
55sys .path .append (os .path .join (os .path .dirname (__file__ ), '..' ))
66from search import *
7- from search import breadth_first_tree_search as bfts , depth_first_tree_search as dfts ,depth_first_graph_search as dfgs
7+ from search import breadth_first_tree_search as bfts , depth_first_tree_search as dfts , \
8+ depth_first_graph_search as dfgs , breadth_first_search as bfs
89from utils import Stack , FIFOQueue , PriorityQueue
910from copy import deepcopy
11+
1012root = None
1113city_coord = {}
1214romania_problem = None
1921front = None
2022node = None
2123next_button = None
22- explored = None
24+ explored = None
25+
2326
2427def create_map (root ):
2528 '''
@@ -97,7 +100,7 @@ def create_map(root):
97100 romania_locations ['Mehadia' ][0 ],
98101 height -
99102 romania_locations ['Mehadia' ][1 ],
100- romania_map .get ('Lugoj' , 'Mehandia ' ))
103+ romania_map .get ('Lugoj' , 'Mehadia ' ))
101104 make_line (
102105 city_map ,
103106 romania_locations ['Drobeta' ][0 ],
@@ -106,7 +109,7 @@ def create_map(root):
106109 romania_locations ['Mehadia' ][0 ],
107110 height -
108111 romania_locations ['Mehadia' ][1 ],
109- romania_map .get ('Drobeta' , 'Mehandia ' ))
112+ romania_map .get ('Drobeta' , 'Mehadia ' ))
110113 make_line (
111114 city_map ,
112115 romania_locations ['Drobeta' ][0 ],
@@ -274,11 +277,19 @@ def make_rectangle(map, x0, y0, margin, city_name):
274277 x0 + margin ,
275278 y0 + margin ,
276279 fill = "white" )
277- map .create_text (
278- x0 - 2 * margin ,
279- y0 - 2 * margin ,
280- text = city_name ,
281- anchor = SE )
280+ if "Bucharest" in city_name or "Pitesti" in city_name or "Lugoj" in city_name \
281+ or "Mehadia" in city_name or "Drobeta" in city_name :
282+ map .create_text (
283+ x0 - 2 * margin ,
284+ y0 - 2 * margin ,
285+ text = city_name ,
286+ anchor = E )
287+ else :
288+ map .create_text (
289+ x0 - 2 * margin ,
290+ y0 - 2 * margin ,
291+ text = city_name ,
292+ anchor = SE )
282293 city_coord .update ({city_name : rect })
283294
284295
@@ -302,7 +313,7 @@ def make_legend(map):
302313
303314def tree_search (problem ):
304315 '''
305- earch through the successors of a problem to find a goal.
316+ Search through the successors of a problem to find a goal.
306317 The argument frontier should be an empty queue.
307318 Don't worry about repeated paths to a state. [Figure 3.7]
308319 This function has been changed to make it suitable for the Tkinter GUI.
@@ -329,20 +340,23 @@ def tree_search(problem):
329340 display_explored (node )
330341 return None
331342
343+
332344def graph_search (problem ):
333345 '''
334346 Search through the successors of a problem to find a goal.
335347 The argument frontier should be an empty queue.
336348 If two paths reach a state, only use the first one. [Figure 3.7]
337349 This function has been changed to make it suitable for the Tkinter GUI.
338350 '''
339- global counter ,frontier ,node ,explored
351+ global counter , frontier , node , explored
340352 if counter == - 1 :
341353 frontier .append (Node (problem .initial ))
342- explored = set ()
354+ explored = set ()
355+ # print("Frontier: "+str(frontier))
343356 display_frontier (frontier )
344- if counter % 3 == 0 and counter >= 0 :
357+ if counter % 3 == 0 and counter >= 0 :
345358 node = frontier .pop ()
359+ # print("Current node: "+str(node))
346360 display_current (node )
347361 if counter % 3 == 1 and counter >= 0 :
348362 if problem .goal_test (node .state ):
@@ -351,13 +365,14 @@ def graph_search(problem):
351365 frontier .extend (child for child in node .expand (problem )
352366 if child .state not in explored and
353367 child not in frontier )
368+ # print("Frontier: " + str(frontier))
354369 display_frontier (frontier )
355370 if counter % 3 == 2 and counter >= 0 :
371+ # print("Explored node: "+str(node))
356372 display_explored (node )
357373 return None
358374
359375
360-
361376def display_frontier (queue ):
362377 '''
363378 This function marks the frontier nodes (orange) on the map.
@@ -370,6 +385,7 @@ def display_frontier(queue):
370385 if node .state == city :
371386 city_map .itemconfig (city_coord [city ], fill = "orange" )
372387
388+
373389def display_current (node ):
374390 '''
375391 This function marks the currently exploring node (red) on the map.
@@ -378,6 +394,7 @@ def display_current(node):
378394 city = node .state
379395 city_map .itemconfig (city_coord [city ], fill = "red" )
380396
397+
381398def display_explored (node ):
382399 '''
383400 This function marks the already explored node (gray) on the map.
@@ -386,6 +403,7 @@ def display_explored(node):
386403 city = node .state
387404 city_map .itemconfig (city_coord [city ], fill = "gray" )
388405
406+
389407def display_final (cities ):
390408 '''
391409 This function marks the final solution nodes (green) on the map.
@@ -394,6 +412,7 @@ def display_final(cities):
394412 for city in cities :
395413 city_map .itemconfig (city_coord [city ], fill = "green" )
396414
415+
397416def breadth_first_tree_search (problem ):
398417 """Search the shallowest nodes in the search tree first."""
399418 global frontier , counter
@@ -405,19 +424,48 @@ def breadth_first_tree_search(problem):
405424def depth_first_tree_search (problem ):
406425 """Search the deepest nodes in the search tree first."""
407426 # This search algorithm might not work in case of repeated paths.
408- global frontier ,counter
427+ global frontier , counter
409428 if counter == - 1 :
410- frontier = Stack ()
429+ frontier = Stack ()
411430 return tree_search (problem )
412431
413- # TODO: Check if the solution given by this function is consistent with the original function.
432+
433+ def breadth_first_search (problem ):
434+ """[Figure 3.11]"""
435+ global frontier , node , explored , counter
436+ if counter == - 1 :
437+ node = Node (problem .initial )
438+ display_current (node )
439+ if problem .goal_test (node .state ):
440+ return node
441+ frontier = FIFOQueue ()
442+ frontier .append (node )
443+ display_frontier (frontier )
444+ explored = set ()
445+ if counter % 3 == 0 and counter >= 0 :
446+ node = frontier .pop ()
447+ display_current (node )
448+ explored .add (node .state )
449+ if counter % 3 == 1 and counter >= 0 :
450+ for child in node .expand (problem ):
451+ if child .state not in explored and child not in frontier :
452+ if problem .goal_test (child .state ):
453+ return child
454+ frontier .append (child )
455+ display_frontier (frontier )
456+ if counter % 3 == 2 and counter >= 0 :
457+ display_explored (node )
458+ return None
459+
460+
414461def depth_first_graph_search (problem ):
415462 """Search the deepest nodes in the search tree first."""
416463 global frontier , counter
417464 if counter == - 1 :
418465 frontier = Stack ()
419466 return graph_search (problem )
420467
468+
421469# TODO:
422470# Remove redundant code.
423471# Make the interchangbility work between various algorithms at each step.
@@ -443,19 +491,24 @@ def on_click():
443491 display_final (final_path )
444492 next_button .config (state = "disabled" )
445493 counter += 1
494+ elif "Breadth-First Search" == algo .get ():
495+ node = breadth_first_search (romania_problem )
496+ if node is not None :
497+ final_path = bfs (romania_problem ).solution ()
498+ final_path .append (start .get ())
499+ display_final (final_path )
500+ next_button .config (state = "disabled" )
501+ counter += 1
446502 elif "Depth-First Graph Search" == algo .get ():
447503 node = depth_first_graph_search (romania_problem )
448504 if node is not None :
449- print (node )
450505 final_path = dfgs (romania_problem ).solution ()
451- print (final_path )
452506 final_path .append (start .get ())
453507 display_final (final_path )
454508 next_button .config (state = "disabled" )
455509 counter += 1
456510
457511
458-
459512def reset_map ():
460513 global counter , city_coord , city_map , next_button
461514 counter = - 1
@@ -479,7 +532,9 @@ def main():
479532 goal .set ('Bucharest' )
480533 cities = sorted (romania_map .locations .keys ())
481534 algorithm_menu = OptionMenu (
482- root , algo , "Breadth-First Tree Search" , "Depth-First Tree Search" ,"Depth-First Graph Search" )
535+ root ,
536+ algo , "Breadth-First Tree Search" , "Depth-First Tree Search" ,
537+ "Breadth-First Search" , "Depth-First Graph Search" )
483538 Label (root , text = "\n Search Algorithm" ).pack ()
484539 algorithm_menu .pack ()
485540 Label (root , text = "\n Start City" ).pack ()
0 commit comments