From ace08a5cd671a2b8b3e9b49bdac441e865d788f4 Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Wed, 13 Dec 2017 00:26:35 +0530 Subject: [PATCH 1/8] tic-tac-toe gui added --- gui/tic-tac-toe.py | 236 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 gui/tic-tac-toe.py diff --git a/gui/tic-tac-toe.py b/gui/tic-tac-toe.py new file mode 100644 index 000000000..c2781255f --- /dev/null +++ b/gui/tic-tac-toe.py @@ -0,0 +1,236 @@ +from tkinter import * +import sys +import os.path +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) +from games import minimax_decision, alphabeta_player, random_player, TicTacToe +# "gen_state" can be used to generate a game state to apply the algorithm +from tests.test_games import gen_state + +ttt = TicTacToe() +root = None +buttons = [] +frames = [] +x_pos = [] +o_pos = [] +count = 0 +sym = "" +result = None +choices = None + + +def create_frames(root): + """ + This function creates the necessary structure of the game. + """ + frame1 = Frame(root) + frame2 = Frame(root) + frame3 = Frame(root) + frame4 = Frame(root) + create_buttons(frame1) + create_buttons(frame2) + create_buttons(frame3) + buttonExit = Button( + frame4, height=1, width=2, + text="Exit", + command=lambda: exit_game(root)) + buttonExit.pack(side=LEFT) + frame4.pack(side=BOTTOM) + frame3.pack(side=BOTTOM) + frame2.pack(side=BOTTOM) + frame1.pack(side=BOTTOM) + frames.append(frame1) + frames.append(frame2) + frames.append(frame3) + for x in frames: + buttons_in_frame = [] + for y in x.winfo_children(): + buttons_in_frame.append(y) + buttons.append(buttons_in_frame) + buttonReset = Button(frame4, height=1, width=2, + text="Reset", command=lambda: reset_game()) + buttonReset.pack(side=LEFT) + + +def create_buttons(frame): + """ + This function creates the buttons to be pressed/clicked during the game. + """ + button0 = Button(frame, height=2, width=2, text=" ", + command=lambda: on_click(button0)) + button0.pack(side=LEFT) + button1 = Button(frame, height=2, width=2, text=" ", + command=lambda: on_click(button1)) + button1.pack(side=LEFT) + button2 = Button(frame, height=2, width=2, text=" ", + command=lambda: on_click(button2)) + button2.pack(side=LEFT) + + +# TODO: Add a choice option for the user. +def on_click(button): + """ + This function determines the action of any button. + """ + global ttt, choices, count, sym, result, x_pos, o_pos + + if count % 2 == 0: + sym = "X" + else: + sym = "O" + count += 1 + + button.config( + text=sym, + state='disabled', + disabledforeground="red") # For cross + + x, y = get_coordinates(button) + x += 1 + y += 1 + x_pos.append((x, y)) + state = gen_state(to_move='O', x_positions=x_pos, + o_positions=o_pos) + try: + choice = choices.get() + if "Random" in choice: + a, b = random_player(ttt, state) + elif "Pro" in choice: + a, b = minimax_decision(state, ttt) + else: + a, b = alphabeta_player(ttt, state) + except (ValueError, IndexError, TypeError) as e: + disable_game() + result.set("It's a draw :|") + return + if 1 <= a <= 3 and 1 <= b <= 3: + o_pos.append((a, b)) + button_to_change = get_button(a - 1, b - 1) + if count % 2 == 0: # Used again, will become handy when user is given the choice of turn. + sym = "X" + else: + sym = "O" + count += 1 + + if check_victory(button): + result.set("You win :)") + disable_game() + else: + button_to_change.config(text=sym, state='disabled', + disabledforeground="black") + if check_victory(button_to_change): + result.set("You lose :(") + disable_game() + + +# TODO: Replace "check_victory" by "k_in_row" function. +def check_victory(button): + """ + This function checks various winning conditions of the game. + """ + # check if previous move caused a win on vertical line + global buttons + x, y = get_coordinates(button) + tt = button['text'] + if buttons[0][y]['text'] == buttons[1][y]['text'] == buttons[2][y]['text'] != " ": + buttons[0][y].config(text="|" + tt + "|") + buttons[1][y].config(text="|" + tt + "|") + buttons[2][y].config(text="|" + tt + "|") + return True + + # check if previous move caused a win on horizontal line + if buttons[x][0]['text'] == buttons[x][1]['text'] == buttons[x][2]['text'] != " ": + buttons[x][0].config(text="--" + tt + "--") + buttons[x][1].config(text="--" + tt + "--") + buttons[x][2].config(text="--" + tt + "--") + return True + + # check if previous move was on the main diagonal and caused a win + if x == y and buttons[0][0]['text'] == buttons[1][1]['text'] == buttons[2][2]['text'] != " ": + buttons[0][0].config(text="\\" + tt + "\\") + buttons[1][1].config(text="\\" + tt + "\\") + buttons[2][2].config(text="\\" + tt + "\\") + return True + + # check if previous move was on the secondary diagonal and caused a win + if x + \ + y == 2 and buttons[0][2]['text'] == buttons[1][1]['text'] == buttons[2][0]['text'] != " ": + buttons[0][2].config(text="/" + tt + "/") + buttons[1][1].config(text="/" + tt + "/") + buttons[2][0].config(text="/" + tt + "/") + return True + + return False + + +def get_coordinates(button): + """ + This function returns the coordinates of the button clicked. + """ + global buttons + for x in range(len(buttons)): + for y in range(len(buttons[x])): + if buttons[x][y] == button: + return x, y + + +def get_button(x, y): + """ + This function returns the button memory location corresponding to a coordinate. + """ + global buttons + return buttons[x][y] + + +def reset_game(): + """ + This function will reset all the tiles to the initial null value. + """ + global x_pos, o_pos, frames, count + + count = 0 + x_pos = [] + o_pos = [] + result.set("Your Turn!") + for x in frames: + for y in x.winfo_children(): + y.config(text=" ", state='normal') + + +def disable_game(): + """ + This function deactivates the game after a win, loss or draw. + """ + global frames + for x in frames: + for y in x.winfo_children(): + y.config(state='disabled') + + +def exit_game(root): + """ + This function will exit the game by killing the root. + """ + root.destroy() + + +def main(): + global result, choices + + root = Tk() + root.title("TicTacToe") + root.resizable(0, 0) # To remove the maximize window option + result = StringVar() + result.set("Your Turn!") + w = Label(root, textvariable=result) + w.pack(side=BOTTOM) + create_frames(root) + choices = StringVar(root) + choices.set("Vs Pro") + menu = OptionMenu(root, choices, "Vs Random", "Vs Pro", "Vs Legend") + menu.pack() + root.mainloop() + + +if __name__ == "__main__": + main() + From 01344921029fb4aefe7a609aa893b6ca280b87e0 Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Sat, 16 Dec 2017 16:50:45 +0530 Subject: [PATCH 2/8] Added GUI for Searching --- gui/romania_problem.py | 271 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 gui/romania_problem.py diff --git a/gui/romania_problem.py b/gui/romania_problem.py new file mode 100644 index 000000000..0e377d9a7 --- /dev/null +++ b/gui/romania_problem.py @@ -0,0 +1,271 @@ +from tkinter import * +import sys +import os.path +import math +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) +from search import * + +root = None +city_coord = {} +height = 0 + + +def create_map(root): + ''' + This function draws out the required map. + ''' + romania_problem = GraphProblem('Arad', 'Bucharest', romania_map) + romania_locations = romania_map.locations + global height + width = 700 + height = 800 + margin = 5 + city_map = Canvas(root, width=width, height=height) + city_map.pack() + + for city in romania_locations.keys(): + create_rectangle( + city_map, + romania_locations[city][0], + height - + romania_locations[city][1], + margin, + city) + + # Since lines have to be drawn between particular points, we need to list + # them separately + create_line( + city_map, + romania_locations['Arad'][0], + height - + romania_locations['Arad'][1], + romania_locations['Sibiu'][0], + height - + romania_locations['Sibiu'][1], + 140) + create_line( + city_map, + romania_locations['Arad'][0], + height - + romania_locations['Arad'][1], + romania_locations['Zerind'][0], + height - + romania_locations['Zerind'][1], + 75) + create_line( + city_map, + romania_locations['Arad'][0], + height - + romania_locations['Arad'][1], + romania_locations['Timisoara'][0], + height - + romania_locations['Timisoara'][1], + 118) + create_line( + city_map, + romania_locations['Oradea'][0], + height - + romania_locations['Oradea'][1], + romania_locations['Zerind'][0], + height - + romania_locations['Zerind'][1], + 71) + create_line( + city_map, + romania_locations['Oradea'][0], + height - + romania_locations['Oradea'][1], + romania_locations['Sibiu'][0], + height - + romania_locations['Sibiu'][1], + 151) + create_line( + city_map, + romania_locations['Lugoj'][0], + height - + romania_locations['Lugoj'][1], + romania_locations['Timisoara'][0], + height - + romania_locations['Timisoara'][1], + 111) + create_line( + city_map, + romania_locations['Lugoj'][0], + height - + romania_locations['Lugoj'][1], + romania_locations['Mehadia'][0], + height - + romania_locations['Mehadia'][1], + 70) + create_line( + city_map, + romania_locations['Drobeta'][0], + height - + romania_locations['Drobeta'][1], + romania_locations['Mehadia'][0], + height - + romania_locations['Mehadia'][1], + 75) + create_line( + city_map, + romania_locations['Drobeta'][0], + height - + romania_locations['Drobeta'][1], + romania_locations['Craiova'][0], + height - + romania_locations['Craiova'][1], + 120) + create_line( + city_map, + romania_locations['Pitesti'][0], + height - + romania_locations['Pitesti'][1], + romania_locations['Craiova'][0], + height - + romania_locations['Craiova'][1], + 138) + create_line( + city_map, + romania_locations['Rimnicu'][0], + height - + romania_locations['Rimnicu'][1], + romania_locations['Craiova'][0], + height - + romania_locations['Craiova'][1], + 146) + create_line( + city_map, + romania_locations['Rimnicu'][0], + height - + romania_locations['Rimnicu'][1], + romania_locations['Sibiu'][0], + height - + romania_locations['Sibiu'][1], + 80) + create_line( + city_map, + romania_locations['Rimnicu'][0], + height - + romania_locations['Rimnicu'][1], + romania_locations['Pitesti'][0], + height - + romania_locations['Pitesti'][1], + 97) + create_line( + city_map, + romania_locations['Fagaras'][0], + height - + romania_locations['Fagaras'][1], + romania_locations['Sibiu'][0], + height - + romania_locations['Sibiu'][1], + 99) + create_line( + city_map, + romania_locations['Fagaras'][0], + height - + romania_locations['Fagaras'][1], + romania_locations['Bucharest'][0], + height - + romania_locations['Bucharest'][1], + 211) + create_line( + city_map, + romania_locations['Giurgiu'][0], + height - + romania_locations['Giurgiu'][1], + romania_locations['Bucharest'][0], + height - + romania_locations['Bucharest'][1], + 90) + create_line( + city_map, + romania_locations['Urziceni'][0], + height - + romania_locations['Urziceni'][1], + romania_locations['Bucharest'][0], + height - + romania_locations['Bucharest'][1], + 85) + create_line( + city_map, + romania_locations['Urziceni'][0], + height - + romania_locations['Urziceni'][1], + romania_locations['Hirsova'][0], + height - + romania_locations['Hirsova'][1], + 98) + create_line( + city_map, + romania_locations['Eforie'][0], + height - + romania_locations['Eforie'][1], + romania_locations['Hirsova'][0], + height - + romania_locations['Hirsova'][1], + 86) + create_line( + city_map, + romania_locations['Urziceni'][0], + height - + romania_locations['Urziceni'][1], + romania_locations['Vaslui'][0], + height - + romania_locations['Vaslui'][1], + 142) + create_line( + city_map, + romania_locations['Iasi'][0], + height - + romania_locations['Iasi'][1], + romania_locations['Vaslui'][0], + height - + romania_locations['Vaslui'][1], + 92) + create_line( + city_map, + romania_locations['Iasi'][0], + height - + romania_locations['Iasi'][1], + romania_locations['Neamt'][0], + height - + romania_locations['Neamt'][1], + 87) + + +def create_line(map, x0, y0, x1, y1, distance): + ''' + This function draws out the lines joining various points. + ''' + map.create_line(x0, y0, x1, y1) + map.create_text((x0 + x1) / 2, (y0 + y1) / 2, text=distance) + + +def create_rectangle(map, x0, y0, margin, city_name): + ''' + This function draws out rectangles for various points. + ''' + global city_coord + rect = map.create_rectangle( + x0 - margin, + y0 - margin, + x0 + margin, + y0 + margin) + map.create_text( + x0 - 2 * margin, + y0 - 2 * margin, + text=city_name, + anchor=SE) + city_coord.update({city_name: rect}) + + +def main(): + root = Tk() + root.title("Road Map of Romania") + create_map(root) + root.mainloop() + + +if __name__ == "__main__": + main() From ac7fa0f4ca30e91ddd018851d14dbe83f46e739b Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Sat, 16 Dec 2017 17:43:26 +0530 Subject: [PATCH 3/8] Added Legend and Minor Fix --- gui/romania_problem.py | 85 +++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 34 deletions(-) diff --git a/gui/romania_problem.py b/gui/romania_problem.py index 0e377d9a7..cdb1d33e7 100644 --- a/gui/romania_problem.py +++ b/gui/romania_problem.py @@ -23,18 +23,9 @@ def create_map(root): city_map = Canvas(root, width=width, height=height) city_map.pack() - for city in romania_locations.keys(): - create_rectangle( - city_map, - romania_locations[city][0], - height - - romania_locations[city][1], - margin, - city) - # Since lines have to be drawn between particular points, we need to list # them separately - create_line( + make_line( city_map, romania_locations['Arad'][0], height - @@ -43,7 +34,7 @@ def create_map(root): height - romania_locations['Sibiu'][1], 140) - create_line( + make_line( city_map, romania_locations['Arad'][0], height - @@ -52,7 +43,7 @@ def create_map(root): height - romania_locations['Zerind'][1], 75) - create_line( + make_line( city_map, romania_locations['Arad'][0], height - @@ -61,7 +52,7 @@ def create_map(root): height - romania_locations['Timisoara'][1], 118) - create_line( + make_line( city_map, romania_locations['Oradea'][0], height - @@ -70,7 +61,7 @@ def create_map(root): height - romania_locations['Zerind'][1], 71) - create_line( + make_line( city_map, romania_locations['Oradea'][0], height - @@ -79,7 +70,7 @@ def create_map(root): height - romania_locations['Sibiu'][1], 151) - create_line( + make_line( city_map, romania_locations['Lugoj'][0], height - @@ -88,7 +79,7 @@ def create_map(root): height - romania_locations['Timisoara'][1], 111) - create_line( + make_line( city_map, romania_locations['Lugoj'][0], height - @@ -97,7 +88,7 @@ def create_map(root): height - romania_locations['Mehadia'][1], 70) - create_line( + make_line( city_map, romania_locations['Drobeta'][0], height - @@ -106,7 +97,7 @@ def create_map(root): height - romania_locations['Mehadia'][1], 75) - create_line( + make_line( city_map, romania_locations['Drobeta'][0], height - @@ -115,7 +106,7 @@ def create_map(root): height - romania_locations['Craiova'][1], 120) - create_line( + make_line( city_map, romania_locations['Pitesti'][0], height - @@ -124,7 +115,7 @@ def create_map(root): height - romania_locations['Craiova'][1], 138) - create_line( + make_line( city_map, romania_locations['Rimnicu'][0], height - @@ -133,7 +124,7 @@ def create_map(root): height - romania_locations['Craiova'][1], 146) - create_line( + make_line( city_map, romania_locations['Rimnicu'][0], height - @@ -142,7 +133,7 @@ def create_map(root): height - romania_locations['Sibiu'][1], 80) - create_line( + make_line( city_map, romania_locations['Rimnicu'][0], height - @@ -151,7 +142,7 @@ def create_map(root): height - romania_locations['Pitesti'][1], 97) - create_line( + make_line( city_map, romania_locations['Fagaras'][0], height - @@ -160,7 +151,7 @@ def create_map(root): height - romania_locations['Sibiu'][1], 99) - create_line( + make_line( city_map, romania_locations['Fagaras'][0], height - @@ -169,7 +160,7 @@ def create_map(root): height - romania_locations['Bucharest'][1], 211) - create_line( + make_line( city_map, romania_locations['Giurgiu'][0], height - @@ -178,7 +169,7 @@ def create_map(root): height - romania_locations['Bucharest'][1], 90) - create_line( + make_line( city_map, romania_locations['Urziceni'][0], height - @@ -187,7 +178,7 @@ def create_map(root): height - romania_locations['Bucharest'][1], 85) - create_line( + make_line( city_map, romania_locations['Urziceni'][0], height - @@ -196,7 +187,7 @@ def create_map(root): height - romania_locations['Hirsova'][1], 98) - create_line( + make_line( city_map, romania_locations['Eforie'][0], height - @@ -205,7 +196,7 @@ def create_map(root): height - romania_locations['Hirsova'][1], 86) - create_line( + make_line( city_map, romania_locations['Urziceni'][0], height - @@ -214,7 +205,7 @@ def create_map(root): height - romania_locations['Vaslui'][1], 142) - create_line( + make_line( city_map, romania_locations['Iasi'][0], height - @@ -223,7 +214,7 @@ def create_map(root): height - romania_locations['Vaslui'][1], 92) - create_line( + make_line( city_map, romania_locations['Iasi'][0], height - @@ -233,8 +224,18 @@ def create_map(root): romania_locations['Neamt'][1], 87) + for city in romania_locations.keys(): + make_rectangle( + city_map, + romania_locations[city][0], + height - + romania_locations[city][1], + margin, + city) + + make_legend(city_map) -def create_line(map, x0, y0, x1, y1, distance): +def make_line(map, x0, y0, x1, y1, distance): ''' This function draws out the lines joining various points. ''' @@ -242,7 +243,7 @@ def create_line(map, x0, y0, x1, y1, distance): map.create_text((x0 + x1) / 2, (y0 + y1) / 2, text=distance) -def create_rectangle(map, x0, y0, margin, city_name): +def make_rectangle(map, x0, y0, margin, city_name): ''' This function draws out rectangles for various points. ''' @@ -251,7 +252,8 @@ def create_rectangle(map, x0, y0, margin, city_name): x0 - margin, y0 - margin, x0 + margin, - y0 + margin) + y0 + margin, + fill="white") map.create_text( x0 - 2 * margin, y0 - 2 * margin, @@ -259,6 +261,21 @@ def create_rectangle(map, x0, y0, margin, city_name): anchor=SE) city_coord.update({city_name: rect}) +def make_legend(map): + rect1=map.create_rectangle(600,100,610,110,fill="white") + text1 = map.create_text(615, 105,anchor=W,text="Un-explored") + + rect2=map.create_rectangle(600,115,610,125,fill="orange") + text2 = map.create_text(615, 120,anchor=W,text="Frontier") + + rect3=map.create_rectangle(600,130,610,140,fill="red") + text3 = map.create_text(615, 135,anchor=W,text="Currently Exploring") + + rect4=map.create_rectangle(600,145,610,155,fill="grey") + text4 = map.create_text(615, 150,anchor=W,text="Explored") + + rect5=map.create_rectangle(600,160,610,170,fill="dark green") + text5 = map.create_text(615, 165, anchor=W, text="Final Solution") def main(): root = Tk() From 442765b2a47779b5ee6823ee24ab10873e41afde Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Sun, 17 Dec 2017 01:38:46 +0530 Subject: [PATCH 4/8] Minor Fix and Options added --- gui/romania_problem.py | 80 +++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/gui/romania_problem.py b/gui/romania_problem.py index cdb1d33e7..211a9a605 100644 --- a/gui/romania_problem.py +++ b/gui/romania_problem.py @@ -7,18 +7,20 @@ root = None city_coord = {} -height = 0 +romania_problem = GraphProblem('Arad', 'Bucharest', romania_map) +algo=None +start=None +goal=None def create_map(root): ''' This function draws out the required map. ''' - romania_problem = GraphProblem('Arad', 'Bucharest', romania_map) + global romania_problem romania_locations = romania_map.locations - global height - width = 700 - height = 800 + width = 750 + height = 670 margin = 5 city_map = Canvas(root, width=width, height=height) city_map.pack() @@ -33,7 +35,7 @@ def create_map(root): romania_locations['Sibiu'][0], height - romania_locations['Sibiu'][1], - 140) + romania_map.get('Arad', 'Sibiu')) make_line( city_map, romania_locations['Arad'][0], @@ -42,7 +44,7 @@ def create_map(root): romania_locations['Zerind'][0], height - romania_locations['Zerind'][1], - 75) + romania_map.get('Arad', 'Zerind')) make_line( city_map, romania_locations['Arad'][0], @@ -51,7 +53,7 @@ def create_map(root): romania_locations['Timisoara'][0], height - romania_locations['Timisoara'][1], - 118) + romania_map.get('Arad', 'Timisoara')) make_line( city_map, romania_locations['Oradea'][0], @@ -60,7 +62,7 @@ def create_map(root): romania_locations['Zerind'][0], height - romania_locations['Zerind'][1], - 71) + romania_map.get('Oradea', 'Zerind')) make_line( city_map, romania_locations['Oradea'][0], @@ -69,7 +71,7 @@ def create_map(root): romania_locations['Sibiu'][0], height - romania_locations['Sibiu'][1], - 151) + romania_map.get('Oradea', 'Sibiu')) make_line( city_map, romania_locations['Lugoj'][0], @@ -78,7 +80,7 @@ def create_map(root): romania_locations['Timisoara'][0], height - romania_locations['Timisoara'][1], - 111) + romania_map.get('Lugoj', 'Timisoara')) make_line( city_map, romania_locations['Lugoj'][0], @@ -87,7 +89,7 @@ def create_map(root): romania_locations['Mehadia'][0], height - romania_locations['Mehadia'][1], - 70) + romania_map.get('Lugoj', 'Mehandia')) make_line( city_map, romania_locations['Drobeta'][0], @@ -96,7 +98,7 @@ def create_map(root): romania_locations['Mehadia'][0], height - romania_locations['Mehadia'][1], - 75) + romania_map.get('Drobeta', 'Mehandia')) make_line( city_map, romania_locations['Drobeta'][0], @@ -105,7 +107,7 @@ def create_map(root): romania_locations['Craiova'][0], height - romania_locations['Craiova'][1], - 120) + romania_map.get('Drobeta', 'Craiova')) make_line( city_map, romania_locations['Pitesti'][0], @@ -114,7 +116,7 @@ def create_map(root): romania_locations['Craiova'][0], height - romania_locations['Craiova'][1], - 138) + romania_map.get('Pitesti', 'Craiova')) make_line( city_map, romania_locations['Rimnicu'][0], @@ -123,7 +125,7 @@ def create_map(root): romania_locations['Craiova'][0], height - romania_locations['Craiova'][1], - 146) + romania_map.get('Rimnicu', 'Craiova')) make_line( city_map, romania_locations['Rimnicu'][0], @@ -132,7 +134,7 @@ def create_map(root): romania_locations['Sibiu'][0], height - romania_locations['Sibiu'][1], - 80) + romania_map.get('Rimnicu', 'Sibiu')) make_line( city_map, romania_locations['Rimnicu'][0], @@ -141,7 +143,7 @@ def create_map(root): romania_locations['Pitesti'][0], height - romania_locations['Pitesti'][1], - 97) + romania_map.get('Rimnicu', 'Pitesti')) make_line( city_map, romania_locations['Fagaras'][0], @@ -150,7 +152,7 @@ def create_map(root): romania_locations['Sibiu'][0], height - romania_locations['Sibiu'][1], - 99) + romania_map.get('Fagaras', 'Sibiu')) make_line( city_map, romania_locations['Fagaras'][0], @@ -159,7 +161,7 @@ def create_map(root): romania_locations['Bucharest'][0], height - romania_locations['Bucharest'][1], - 211) + romania_map.get('Fagaras', 'Bucharest')) make_line( city_map, romania_locations['Giurgiu'][0], @@ -168,7 +170,7 @@ def create_map(root): romania_locations['Bucharest'][0], height - romania_locations['Bucharest'][1], - 90) + romania_map.get('Giurgiu', 'Bucharest')) make_line( city_map, romania_locations['Urziceni'][0], @@ -177,7 +179,7 @@ def create_map(root): romania_locations['Bucharest'][0], height - romania_locations['Bucharest'][1], - 85) + romania_map.get('Urziceni', 'Bucharest')) make_line( city_map, romania_locations['Urziceni'][0], @@ -186,7 +188,7 @@ def create_map(root): romania_locations['Hirsova'][0], height - romania_locations['Hirsova'][1], - 98) + romania_map.get('Urziceni', 'Hirsova')) make_line( city_map, romania_locations['Eforie'][0], @@ -195,7 +197,7 @@ def create_map(root): romania_locations['Hirsova'][0], height - romania_locations['Hirsova'][1], - 86) + romania_map.get('Eforie', 'Hirsova')) make_line( city_map, romania_locations['Urziceni'][0], @@ -204,7 +206,7 @@ def create_map(root): romania_locations['Vaslui'][0], height - romania_locations['Vaslui'][1], - 142) + romania_map.get('Urziceni', 'Vaslui')) make_line( city_map, romania_locations['Iasi'][0], @@ -213,7 +215,7 @@ def create_map(root): romania_locations['Vaslui'][0], height - romania_locations['Vaslui'][1], - 92) + romania_map.get('Iasi', 'Vaslui')) make_line( city_map, romania_locations['Iasi'][0], @@ -222,7 +224,7 @@ def create_map(root): romania_locations['Neamt'][0], height - romania_locations['Neamt'][1], - 87) + romania_map.get('Iasi', 'Neamt')) for city in romania_locations.keys(): make_rectangle( @@ -262,6 +264,7 @@ def make_rectangle(map, x0, y0, margin, city_name): city_coord.update({city_name: rect}) def make_legend(map): + rect1=map.create_rectangle(600,100,610,110,fill="white") text1 = map.create_text(615, 105,anchor=W,text="Un-explored") @@ -276,10 +279,31 @@ def make_legend(map): rect5=map.create_rectangle(600,160,610,170,fill="dark green") text5 = map.create_text(615, 165, anchor=W, text="Final Solution") - + def main(): + global algo,start,goal root = Tk() root.title("Road Map of Romania") + root.geometry("950x1150") + algo=StringVar(root) + start = StringVar(root) + goal = StringVar(root) + algo.set("Breadth First Tree Search") + start.set('Arad') + goal.set('Bucharest') + cities=list(romania_map.locations.keys()) + cities.sort() + algorithm_menu=OptionMenu(root,algo,"Breadth-First Tree Search","Depth-First Tree Search") + Label(root,text="\n Search Algorithm").pack() + algorithm_menu.pack() + Label(root,text="\n Start City").pack() + start_menu = OptionMenu(root,start,*cities) + start_menu.pack() + Label(root, text="\n Goal City").pack() + goal_menu = OptionMenu(root,goal,*cities) + goal_menu.pack() + next_button = Button(root, width=6, height=2, text="Next", command=None,padx=2,pady=2,relief=GROOVE) + next_button.pack(side=BOTTOM) create_map(root) root.mainloop() From cd027d5498174b8b9ac251b5f6cdd057c0247514 Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Mon, 18 Dec 2017 10:43:10 +0530 Subject: [PATCH 5/8] Added Breadth-First Tree Search --- gui/romania_problem.py | 201 ++++++++++++++++++++++++++++++++++------- 1 file changed, 168 insertions(+), 33 deletions(-) diff --git a/gui/romania_problem.py b/gui/romania_problem.py index 211a9a605..b930c80dd 100644 --- a/gui/romania_problem.py +++ b/gui/romania_problem.py @@ -4,20 +4,28 @@ import math sys.path.append(os.path.join(os.path.dirname(__file__), '..')) from search import * - +from search import breadth_first_tree_search as bfts +from utils import Stack, FIFOQueue, PriorityQueue +from copy import deepcopy root = None city_coord = {} -romania_problem = GraphProblem('Arad', 'Bucharest', romania_map) -algo=None -start=None -goal=None +romania_problem = None +algo = None +start = None +goal = None +counter = -1 +city_map = None +frontier = None +front = None +node = None +next_button = None def create_map(root): ''' This function draws out the required map. ''' - global romania_problem + global city_map, start, goal romania_locations = romania_map.locations width = 750 height = 670 @@ -237,6 +245,7 @@ def create_map(root): make_legend(city_map) + def make_line(map, x0, y0, x1, y1, distance): ''' This function draws out the lines joining various points. @@ -263,47 +272,173 @@ def make_rectangle(map, x0, y0, margin, city_name): anchor=SE) city_coord.update({city_name: rect}) + def make_legend(map): - - rect1=map.create_rectangle(600,100,610,110,fill="white") - text1 = map.create_text(615, 105,anchor=W,text="Un-explored") - - rect2=map.create_rectangle(600,115,610,125,fill="orange") - text2 = map.create_text(615, 120,anchor=W,text="Frontier") - - rect3=map.create_rectangle(600,130,610,140,fill="red") - text3 = map.create_text(615, 135,anchor=W,text="Currently Exploring") - - rect4=map.create_rectangle(600,145,610,155,fill="grey") - text4 = map.create_text(615, 150,anchor=W,text="Explored") - - rect5=map.create_rectangle(600,160,610,170,fill="dark green") + + rect1 = map.create_rectangle(600, 100, 610, 110, fill="white") + text1 = map.create_text(615, 105, anchor=W, text="Un-explored") + + rect2 = map.create_rectangle(600, 115, 610, 125, fill="orange") + text2 = map.create_text(615, 120, anchor=W, text="Frontier") + + rect3 = map.create_rectangle(600, 130, 610, 140, fill="red") + text3 = map.create_text(615, 135, anchor=W, text="Currently Exploring") + + rect4 = map.create_rectangle(600, 145, 610, 155, fill="grey") + text4 = map.create_text(615, 150, anchor=W, text="Explored") + + rect5 = map.create_rectangle(600, 160, 610, 170, fill="dark green") text5 = map.create_text(615, 165, anchor=W, text="Final Solution") - + + +def tree_search(problem): + ''' + This function has been changed to make it suitable for the Tkinter GUI. + ''' + global counter, frontier, node + # print(counter) + if counter == -1: + frontier.append(Node(problem.initial)) + # print(frontier) + display_frontier(frontier) + if counter % 3 == 0 and counter >= 0: + node = frontier.pop() + # print(node) + display_current(node) + if counter % 3 == 1 and counter >= 0: + if problem.goal_test(node.state): + # print(node) + return node + frontier.extend(node.expand(problem)) + # print(frontier) + display_frontier(frontier) + if counter % 3 == 2 and counter >= 0: + # print(node) + display_explored(node) + return None + + +def display_frontier(queue): + ''' + This function marks the frontier nodes (orange) on the map. + ''' + global city_map, city_coord + qu = deepcopy(queue) + while qu: + node = qu.pop() + for city in city_coord.keys(): + if node.state == city: + city_map.itemconfig(city_coord[city], fill="orange") + return + + +def display_current(node): + ''' + This function marks the currently exploring node (red) on the map. + ''' + global city_map, city_coord + city = node.state + city_map.itemconfig(city_coord[city], fill="red") + return + + +def display_explored(node): + ''' + This function marks the already explored node (gray) on the map. + ''' + global city_map, city_coord + city = node.state + city_map.itemconfig(city_coord[city], fill="gray") + return + + +def display_final(cities): + ''' + This function marks the final solution nodes (green) on the map. + ''' + global city_map, city_coord + for city in cities: + city_map.itemconfig(city_coord[city], fill="green") + return + + +def breadth_first_tree_search(problem): + """Search the shallowest nodes in the search tree first.""" + global frontier, counter + if counter == -1: + frontier = FIFOQueue() + return tree_search(problem) + + +def on_click(): + ''' + This function defines the action of the 'Next' button. + ''' + global algo, counter, next_button, romania_problem, start, goal + romania_problem = GraphProblem(start.get(), goal.get(), romania_map) + if "Breadth-First Tree Search" == algo.get(): + node = breadth_first_tree_search(romania_problem) + if node is not None: + final_path = bfts(romania_problem).solution() + final_path.append(start.get()) + display_final(final_path) + next_button.config(state="disabled") + counter += 1 + + +def reset_map(): + global counter, city_coord, city_map, next_button + counter = -1 + for city in city_coord.keys(): + city_map.itemconfig(city_coord[city], fill="white") + next_button.config(state="normal") + +# TODO: Add more search algorithms in the OptionMenu + + def main(): - global algo,start,goal + global algo, start, goal, next_button root = Tk() root.title("Road Map of Romania") root.geometry("950x1150") - algo=StringVar(root) + algo = StringVar(root) start = StringVar(root) goal = StringVar(root) - algo.set("Breadth First Tree Search") + algo.set("Breadth-First Tree Search") start.set('Arad') goal.set('Bucharest') - cities=list(romania_map.locations.keys()) - cities.sort() - algorithm_menu=OptionMenu(root,algo,"Breadth-First Tree Search","Depth-First Tree Search") - Label(root,text="\n Search Algorithm").pack() + cities = sorted(romania_map.locations.keys()) + algorithm_menu = OptionMenu(root, algo, "Breadth-First Tree Search") + Label(root, text="\n Search Algorithm").pack() algorithm_menu.pack() - Label(root,text="\n Start City").pack() - start_menu = OptionMenu(root,start,*cities) + Label(root, text="\n Start City").pack() + start_menu = OptionMenu(root, start, *cities) start_menu.pack() Label(root, text="\n Goal City").pack() - goal_menu = OptionMenu(root,goal,*cities) + goal_menu = OptionMenu(root, goal, *cities) goal_menu.pack() - next_button = Button(root, width=6, height=2, text="Next", command=None,padx=2,pady=2,relief=GROOVE) - next_button.pack(side=BOTTOM) + frame1 = Frame(root) + next_button = Button( + frame1, + width=6, + height=2, + text="Next", + command=on_click, + padx=2, + pady=2, + relief=GROOVE) + next_button.pack(side=RIGHT) + reset_button = Button( + frame1, + width=6, + height=2, + text="Reset", + command=reset_map, + padx=2, + pady=2, + relief=GROOVE) + reset_button.pack(side=RIGHT) + frame1.pack(side=BOTTOM) create_map(root) root.mainloop() From f2e1a12208c3276b5fb3163e3f381359418664ff Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Mon, 18 Dec 2017 17:56:44 +0530 Subject: [PATCH 6/8] Added Depth-First Tree Search --- gui/romania_problem.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/gui/romania_problem.py b/gui/romania_problem.py index b930c80dd..e80608e14 100644 --- a/gui/romania_problem.py +++ b/gui/romania_problem.py @@ -4,7 +4,7 @@ import math sys.path.append(os.path.join(os.path.dirname(__file__), '..')) from search import * -from search import breadth_first_tree_search as bfts +from search import breadth_first_tree_search as bfts, depth_first_tree_search as dfts from utils import Stack, FIFOQueue, PriorityQueue from copy import deepcopy root = None @@ -370,6 +370,14 @@ def breadth_first_tree_search(problem): return tree_search(problem) +def depth_first_tree_search(problem): + """Search the deepest nodes in the search tree first.""" + global frontier,counter + if counter == -1: + frontier=Stack() + return tree_search(problem) + +# TODO: Remove redundant code. def on_click(): ''' This function defines the action of the 'Next' button. @@ -384,7 +392,14 @@ def on_click(): display_final(final_path) next_button.config(state="disabled") counter += 1 - + elif "Depth-First Tree Search" == algo.get(): + node = depth_first_tree_search(romania_problem) + if node is not None: + final_path = dfts(romania_problem).solution() + final_path.append(start.get()) + display_final(final_path) + next_button.config(state="disabled") + counter += 1 def reset_map(): global counter, city_coord, city_map, next_button @@ -408,7 +423,8 @@ def main(): start.set('Arad') goal.set('Bucharest') cities = sorted(romania_map.locations.keys()) - algorithm_menu = OptionMenu(root, algo, "Breadth-First Tree Search") + algorithm_menu = OptionMenu( + root, algo, "Breadth-First Tree Search", "Depth-First Tree Search") Label(root, text="\n Search Algorithm").pack() algorithm_menu.pack() Label(root, text="\n Start City").pack() From 7233ed3d9d2d060cddaa06c88b91832794c1b5cb Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Mon, 18 Dec 2017 22:47:23 +0530 Subject: [PATCH 7/8] Minor Fix --- gui/romania_problem.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gui/romania_problem.py b/gui/romania_problem.py index e80608e14..c8e551245 100644 --- a/gui/romania_problem.py +++ b/gui/romania_problem.py @@ -372,12 +372,15 @@ def breadth_first_tree_search(problem): def depth_first_tree_search(problem): """Search the deepest nodes in the search tree first.""" + # This search algorithm might not work in case of repeated paths. global frontier,counter if counter == -1: frontier=Stack() return tree_search(problem) -# TODO: Remove redundant code. +# TODO: +# Remove redundant code. +# Make the interchangbility work between various algorithms at each step. def on_click(): ''' This function defines the action of the 'Next' button. From 7e3dc209d587b59003b48ebceabbe1e8c0a5662f Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Wed, 20 Dec 2017 02:21:08 +0530 Subject: [PATCH 8/8] Added Depth-First Graph Search --- gui/romania_problem.py | 74 +++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/gui/romania_problem.py b/gui/romania_problem.py index c8e551245..31a3d04c7 100644 --- a/gui/romania_problem.py +++ b/gui/romania_problem.py @@ -4,7 +4,7 @@ import math sys.path.append(os.path.join(os.path.dirname(__file__), '..')) from search import * -from search import breadth_first_tree_search as bfts, depth_first_tree_search as dfts +from search import breadth_first_tree_search as bfts, depth_first_tree_search as dfts,depth_first_graph_search as dfgs from utils import Stack, FIFOQueue, PriorityQueue from copy import deepcopy root = None @@ -19,7 +19,7 @@ front = None node = None next_button = None - +explored=None def create_map(root): ''' @@ -152,6 +152,15 @@ def create_map(root): height - romania_locations['Pitesti'][1], romania_map.get('Rimnicu', 'Pitesti')) + make_line( + city_map, + romania_locations['Bucharest'][0], + height - + romania_locations['Bucharest'][1], + romania_locations['Pitesti'][0], + height - + romania_locations['Pitesti'][1], + romania_map.get('Bucharest', 'Pitesti')) make_line( city_map, romania_locations['Fagaras'][0], @@ -293,6 +302,9 @@ def make_legend(map): def tree_search(problem): ''' + earch through the successors of a problem to find a goal. + The argument frontier should be an empty queue. + Don't worry about repeated paths to a state. [Figure 3.7] This function has been changed to make it suitable for the Tkinter GUI. ''' global counter, frontier, node @@ -317,6 +329,34 @@ def tree_search(problem): display_explored(node) return None +def graph_search(problem): + ''' + Search through the successors of a problem to find a goal. + The argument frontier should be an empty queue. + If two paths reach a state, only use the first one. [Figure 3.7] + This function has been changed to make it suitable for the Tkinter GUI. + ''' + global counter,frontier,node,explored + if counter == -1: + frontier.append(Node(problem.initial)) + explored=set() + display_frontier(frontier) + if counter % 3 ==0 and counter >=0: + node = frontier.pop() + display_current(node) + if counter % 3 == 1 and counter >= 0: + if problem.goal_test(node.state): + return node + explored.add(node.state) + frontier.extend(child for child in node.expand(problem) + if child.state not in explored and + child not in frontier) + display_frontier(frontier) + if counter % 3 == 2 and counter >= 0: + display_explored(node) + return None + + def display_frontier(queue): ''' @@ -329,8 +369,6 @@ def display_frontier(queue): for city in city_coord.keys(): if node.state == city: city_map.itemconfig(city_coord[city], fill="orange") - return - def display_current(node): ''' @@ -339,8 +377,6 @@ def display_current(node): global city_map, city_coord city = node.state city_map.itemconfig(city_coord[city], fill="red") - return - def display_explored(node): ''' @@ -349,8 +385,6 @@ def display_explored(node): global city_map, city_coord city = node.state city_map.itemconfig(city_coord[city], fill="gray") - return - def display_final(cities): ''' @@ -359,8 +393,6 @@ def display_final(cities): global city_map, city_coord for city in cities: city_map.itemconfig(city_coord[city], fill="green") - return - def breadth_first_tree_search(problem): """Search the shallowest nodes in the search tree first.""" @@ -378,6 +410,14 @@ def depth_first_tree_search(problem): frontier=Stack() return tree_search(problem) +# TODO: Check if the solution given by this function is consistent with the original function. +def depth_first_graph_search(problem): + """Search the deepest nodes in the search tree first.""" + global frontier, counter + if counter == -1: + frontier = Stack() + return graph_search(problem) + # TODO: # Remove redundant code. # Make the interchangbility work between various algorithms at each step. @@ -403,6 +443,18 @@ def on_click(): display_final(final_path) next_button.config(state="disabled") counter += 1 + elif "Depth-First Graph Search" == algo.get(): + node = depth_first_graph_search(romania_problem) + if node is not None: + print(node) + final_path = dfgs(romania_problem).solution() + print(final_path) + final_path.append(start.get()) + display_final(final_path) + next_button.config(state="disabled") + counter += 1 + + def reset_map(): global counter, city_coord, city_map, next_button @@ -427,7 +479,7 @@ def main(): goal.set('Bucharest') cities = sorted(romania_map.locations.keys()) algorithm_menu = OptionMenu( - root, algo, "Breadth-First Tree Search", "Depth-First Tree Search") + root, algo, "Breadth-First Tree Search", "Depth-First Tree Search","Depth-First Graph Search") Label(root, text="\n Search Algorithm").pack() algorithm_menu.pack() Label(root, text="\n Start City").pack()