From 45b77f4968046fb58dfc2e729588f25af2dcc651 Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Sun, 14 Jan 2018 21:55:23 +0530 Subject: [PATCH 1/6] Added Vacuum Agent --- gui/vacuum_agent.py | 165 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 gui/vacuum_agent.py diff --git a/gui/vacuum_agent.py b/gui/vacuum_agent.py new file mode 100644 index 000000000..b2de17fed --- /dev/null +++ b/gui/vacuum_agent.py @@ -0,0 +1,165 @@ +from tkinter import * +import random +import sys +import os.path +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) +from agents import * + +loc_A, loc_B = (0, 0), (1, 0) # The two locations for the Vacuum world + + +class Gui(Environment): + + """This GUI environment has two locations, A and B. Each can be Dirty + or Clean. The agent perceives its location and the location's + status.""" + + def __init__(self, root, height=300, width=380, count=1): + super().__init__() + self.status = {loc_A: 'Clean', + loc_B: 'Clean'} + self.root = root + self.height = height + self.width = width + self.canvas = None + self.buttons = [] + self.count = count + self.create_canvas() + self.create_buttons() + + def thing_classes(self): + """The list of things which can be used in the environment.""" + return [Wall, Dirt, ReflexVacuumAgent, RandomVacuumAgent, + TableDrivenVacuumAgent, ModelBasedVacuumAgent] + + def percept(self, agent): + """Returns the agent's location, and the location status (Dirty/Clean).""" + return (agent.location, self.status[agent.location]) + + def execute_action(self, agent, action): + """Change the location status (Dirty/Clean); track performance. + Score 10 for each dirt cleaned; -1 for each move.""" + if action == 'Right': + agent.location = loc_B + agent.performance -= 1 + elif action == 'Left': + agent.location = loc_A + agent.performance -= 1 + elif action == 'Suck': + if self.status[agent.location] == 'Dirty': + if agent.location == loc_A: + self.buttons[0].config(bg='white') + else: + self.buttons[1].config(bg='white') + agent.performance += 10 + self.status[agent.location] = 'Clean' + + def default_location(self, thing): + """Agents start in either location at random.""" + return random.choice([loc_A, loc_B]) + + def create_canvas(self): + """Creates Canvas element in the GUI.""" + self.canvas = Canvas( + self.root, + width=self.width, + height=self.height, + background='powder blue') + self.canvas.pack(side='bottom') + + def create_buttons(self): + """Creates the buttons required in the GUI.""" + button_left = Button(self.root, height=4, width=12, padx=2, pady=2, bg='white') + button_left.config(command=lambda btn=button_left: self.dirt_switch(btn)) + self.buttons.append(button_left) + button_left_window = self.canvas.create_window(130, 235, anchor=N, window=button_left) + button_right = Button(self.root, height=4, width=12, padx=2, pady=2, bg='white') + button_right.config(command=lambda btn=button_right: self.dirt_switch(btn)) + self.buttons.append(button_right) + button_right_window = self.canvas.create_window(250, 235, anchor=N, window=button_right) + + def dirt_switch(self, button): + """Gives user the option to put dirt in any tile.""" + if self.count % 2 == 0: + button.config(bg='white') + elif self.count % 1 == 0: + button.config(bg='saddle brown') + self.count += 1 + + def read_env(self): + """Reads the current state of the GUI.""" + for i, btn in enumerate(self.buttons): + if i == 0: + if btn['bg'] == 'white': + self.status[loc_A] = 'Clean' + else: + self.status[loc_A] = 'Dirty' + else: + if btn['bg'] == 'white': + self.status[loc_B] = 'Clean' + else: + self.status[loc_B] = 'Dirty' + + def update_env(self, agent): + """Updates the GUI according to the agent's action.""" + self.read_env() + #print(self.status) + before_step = agent.location + self.step() + #print(self.status) + #print(agent.location) + move_agent(self, agent, before_step) + + +def create_agent(env, agent): + """Creates the agent in the GUI and is kept independent of the environment.""" + env.add_thing(agent) + #print(agent.location) + if agent.location == (0, 0): + env.agent_rect_l = env.canvas.create_rectangle(80, 140, 175, 220, fill='lime green') + env.agent_rect_r = None + else: + env.agent_rect_r = env.canvas.create_rectangle(200, 140, 295, 220, fill='lime green') + env.agent_rect_l = None + + +def move_agent(env, agent, before_step): + """Moves the agent in the GUI when 'next' button is pressed.""" + if agent.location == before_step: + pass + else: + if agent.location == (1, 0): + if env.agent_rect_r is None: + env.canvas.move(env.agent_rect_l, 120, 0) + else: + env.canvas.move(env.agent_rect_r, 120, 0) + elif agent.location == (0, 0): + if env.agent_rect_l is None: + env.canvas.move(env.agent_rect_r, -120, 0) + else: + env.canvas.move(env.agent_rect_l, -120, 0) + + +# TODO: Add more agents to the environment. +# TODO: Expand the environment to XYEnvironment. +def main(): + """The main function of the program.""" + root = Tk() + root.title("Vacuum Environment") + root.geometry("420x380") + root.resizable(0, 0) + frame = Frame(root, bg='black') + # reset_button = Button(frame, text='Reset', height=2, width=6, padx=2, pady=2, command=None) + # reset_button.pack(side='left') + next_button = Button(frame, text='Next', height=2, width=6, padx=2, pady=2) + next_button.pack(side='left') + frame.pack(side='bottom') + env = Gui(root) + agent = ReflexVacuumAgent() + create_agent(env, agent) + next_button.config(command=lambda: env.update_env(agent)) + root.mainloop() + + +if __name__ == "__main__": + main() From 048a77a419ea449eb604ec0a900daebc88c61159 Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Mon, 15 Jan 2018 15:00:21 +0530 Subject: [PATCH 2/6] Minor Fix --- gui/vacuum_agent.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/gui/vacuum_agent.py b/gui/vacuum_agent.py index b2de17fed..f5ed4e96c 100644 --- a/gui/vacuum_agent.py +++ b/gui/vacuum_agent.py @@ -116,12 +116,11 @@ def create_agent(env, agent): env.add_thing(agent) #print(agent.location) if agent.location == (0, 0): - env.agent_rect_l = env.canvas.create_rectangle(80, 140, 175, 220, fill='lime green') - env.agent_rect_r = None + env.agent_rect = env.canvas.create_rectangle(80, 140, 175, 220, fill='lime green') + env.text = env.canvas.create_text(128, 180, text="Agent") else: - env.agent_rect_r = env.canvas.create_rectangle(200, 140, 295, 220, fill='lime green') - env.agent_rect_l = None - + env.agent_rect = env.canvas.create_rectangle(200, 140, 295, 220, fill='lime green') + env.text = env.canvas.create_text(248, 180, text="Agent") def move_agent(env, agent, before_step): """Moves the agent in the GUI when 'next' button is pressed.""" @@ -129,15 +128,11 @@ def move_agent(env, agent, before_step): pass else: if agent.location == (1, 0): - if env.agent_rect_r is None: - env.canvas.move(env.agent_rect_l, 120, 0) - else: - env.canvas.move(env.agent_rect_r, 120, 0) + env.canvas.move(env.text, 120, 0) + env.canvas.move(env.agent_rect, 120, 0) elif agent.location == (0, 0): - if env.agent_rect_l is None: - env.canvas.move(env.agent_rect_r, -120, 0) - else: - env.canvas.move(env.agent_rect_l, -120, 0) + env.canvas.move(env.text, -120, 0) + env.canvas.move(env.agent_rect, -120, 0) # TODO: Add more agents to the environment. From 2d67ba3536ca9a6380c8b44afe8316d4165becd9 Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Mon, 15 Jan 2018 15:05:59 +0530 Subject: [PATCH 3/6] Improved Font --- gui/vacuum_agent.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/gui/vacuum_agent.py b/gui/vacuum_agent.py index f5ed4e96c..5adab1e0d 100644 --- a/gui/vacuum_agent.py +++ b/gui/vacuum_agent.py @@ -103,24 +103,25 @@ def read_env(self): def update_env(self, agent): """Updates the GUI according to the agent's action.""" self.read_env() - #print(self.status) + # print(self.status) before_step = agent.location self.step() - #print(self.status) - #print(agent.location) + # print(self.status) + # print(agent.location) move_agent(self, agent, before_step) def create_agent(env, agent): """Creates the agent in the GUI and is kept independent of the environment.""" env.add_thing(agent) - #print(agent.location) + # print(agent.location) if agent.location == (0, 0): env.agent_rect = env.canvas.create_rectangle(80, 140, 175, 220, fill='lime green') - env.text = env.canvas.create_text(128, 180, text="Agent") + env.text = env.canvas.create_text(128, 180, font="Helvetica 10 bold italic", text="Agent") else: env.agent_rect = env.canvas.create_rectangle(200, 140, 295, 220, fill='lime green') - env.text = env.canvas.create_text(248, 180, text="Agent") + env.text = env.canvas.create_text(248, 180, font="Helvetica 10 bold italic", text="Agent") + def move_agent(env, agent, before_step): """Moves the agent in the GUI when 'next' button is pressed.""" From 02db2f4417cb6e6b7eacc4388101f26bc5d75aa3 Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Thu, 18 Jan 2018 00:13:03 +0530 Subject: [PATCH 4/6] Added XYVacuumEnv --- gui/xy_vacuum_environment.py | 181 +++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 gui/xy_vacuum_environment.py diff --git a/gui/xy_vacuum_environment.py b/gui/xy_vacuum_environment.py new file mode 100644 index 000000000..c546d45f3 --- /dev/null +++ b/gui/xy_vacuum_environment.py @@ -0,0 +1,181 @@ +from tkinter import * +import random +import sys +import os.path +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) +from agents import * + + +class Gui(VacuumEnvironment): + """This is a two-dimensional GUI environment. Each location may be + dirty, clean or can have a wall. The user can change these at each step. + """ + xi, yi = (0, 0) + + def __init__(self, root, width=7, height=7, elements=['D', 'W'], count=1): + super().__init__(width, height) + self.root = root + self.create_frames() + self.create_buttons() + self.create_walls() + self.elements = elements + self.count = count + + def create_frames(self): + """Adds frames to the GUI environment.""" + self.frames = [] + for _ in range(7): + frame = Frame(self.root, bg='grey') + frame.pack(side='bottom') + self.frames.append(frame) + + def create_buttons(self): + """Adds buttons to the respective frames in the GUI.""" + self.buttons = [] + for frame in self.frames: + button_row = [] + for _ in range(7): + button = Button(frame, height=3, width=5, padx=2, pady=2) + button.config( + command=lambda btn=button: self.display_element(btn)) + button.pack(side='left') + button_row.append(button) + self.buttons.append(button_row) + + def create_walls(self): + """Creates the outer boundary walls which do not move.""" + for row, button_row in enumerate(self.buttons): + if row == 0 or row == len(self.buttons) - 1: + for button in button_row: + button.config(text='W', state='disabled', + disabledforeground='black') + else: + button_row[0].config( + text='W', state='disabled', disabledforeground='black') + button_row[len(button_row) - 1].config(text='W', + state='disabled', disabledforeground='black') + # Place Agent in the bottom left corner + self.buttons[1][1].config( + text='A', state='disabled', disabledforeground='black') + + def display_element(self, button): + """Show the things on the GUI.""" + if button['text'] != 'A': + if self.count % 3 == 0: + button.config(text='') + elif self.count % 2 == 0: + button.config(text=self.elements[1]) + elif self.count % 1 == 0: + button.config(text=self.elements[0]) + self.count += 1 + + def execute_action(self, agent, action): + """Determines the action the agent performs.""" + xi, yi = ((self.xi, self.yi)) + if action == 'Suck': + dirt_list = self.list_things_at(agent.location, Dirt) + if dirt_list != []: + dirt = dirt_list[0] + agent.performance += 100 + self.delete_thing(dirt) + self.buttons[xi][yi].config(text='', state='normal') + xf, yf = agent.location + self.buttons[xf][yf].config( + text='A', state='disabled', disabledforeground='black') + + else: + agent.bump = False + if action == 'TurnRight': + agent.direction += Direction.R + elif action == 'TurnLeft': + agent.direction += Direction.L + elif action == 'Forward': + agent.bump = self.move_to(agent, agent.direction.move_forward(agent.location)) + if not agent.bump: + self.buttons[xi][yi].config(text='', state='normal') + xf, yf = agent.location + self.buttons[xf][yf].config( + text='A', state='disabled', disabledforeground='black') + + if action != 'NoOp': + agent.performance -= 1 + + def read_env(self): + """Reads the current state of the GUI environment.""" + for i, btn_row in enumerate(self.buttons): + for j, btn in enumerate(btn_row): + if (i != 0 and i != len(self.buttons) - 1) and (j != 0 and j != len(btn_row) - 1): + agt_loc = self.agents[0].location + if self.some_things_at((i, j)) and (i, j) != agt_loc: + for thing in self.list_things_at((i, j)): + self.delete_thing(thing) + if btn['text'] == self.elements[0]: + self.add_thing(Dirt(), (i, j)) + elif btn['text'] == self.elements[1]: + self.add_thing(Wall(), (i, j)) + + def update_env(self): + """Updates the GUI environment according to the current state.""" + self.read_env() + print(self.agents) + print(self.things) + agt = self.agents[0] + previous_agent_location = agt.location + self.xi, self.yi = previous_agent_location + self.step() + xf, yf = agt.location + + +def XYReflexAgentProgram(percept): + """The modified SimpleReflexAgentProgram for the GUI environment.""" + status, bump = percept + if status == 'Dirty': + return 'Suck' + + if bump == 'Bump': + value = random.choice((1, 2)) + else: + value = random.choice((1, 2, 3, 4)) # 1-right, 2-left, others-forward + + if value == 1: + return 'TurnRight' + elif value == 2: + return 'TurnLeft' + else: + return 'Forward' + + +class XYReflexAgent(Agent): + """The modified SimpleReflexAgent for the GUI environment.""" + + def __init__(self, program=None): + super().__init__(program) + self.location = (3, 3) + self.direction = Direction("up") + + +# TODO: Check the coordinate system. +def main(): + """The main function.""" + root = Tk() + root.title("Vacuum Environment") + root.geometry("420x440") + root.resizable(0, 0) + frame = Frame(root, bg='black') + # create a reset button + # reset_button = Button(frame, text='Reset', height=2, + # width=6, padx=2, pady=2, command=None) + # reset_button.pack(side='left') + next_button = Button(frame, text='Next', height=2, + width=6, padx=2, pady=2) + next_button.pack(side='left') + frame.pack(side='bottom') + env = Gui(root) + agt = XYReflexAgent(program=XYReflexAgentProgram) + env.add_thing(agt, location=(3, 3)) + next_button.config(command=env.update_env) + root.mainloop() + + +if __name__ == "__main__": + main() From 015731b58eda760f539f71799da895406fb62ad7 Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Thu, 18 Jan 2018 00:28:56 +0530 Subject: [PATCH 5/6] Minor Fix --- gui/xy_vacuum_environment.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/gui/xy_vacuum_environment.py b/gui/xy_vacuum_environment.py index c546d45f3..865cf6e5f 100644 --- a/gui/xy_vacuum_environment.py +++ b/gui/xy_vacuum_environment.py @@ -54,8 +54,8 @@ def create_walls(self): text='W', state='disabled', disabledforeground='black') button_row[len(button_row) - 1].config(text='W', state='disabled', disabledforeground='black') - # Place Agent in the bottom left corner - self.buttons[1][1].config( + # Place the agent in the centre of the grid. + self.buttons[3][3].config( text='A', state='disabled', disabledforeground='black') def display_element(self, button): @@ -117,8 +117,6 @@ def read_env(self): def update_env(self): """Updates the GUI environment according to the current state.""" self.read_env() - print(self.agents) - print(self.things) agt = self.agents[0] previous_agent_location = agt.location self.xi, self.yi = previous_agent_location From a8115d00bbff43b6a4c43dea5cd1502c7d3c7440 Mon Sep 17 00:00:00 2001 From: Apurv-Bajaj Date: Sat, 20 Jan 2018 23:29:57 +0530 Subject: [PATCH 6/6] Review changes --- gui/vacuum_agent.py | 29 ++++++++++++++--------------- gui/xy_vacuum_environment.py | 17 ++++++++--------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/gui/vacuum_agent.py b/gui/vacuum_agent.py index 5adab1e0d..23292efb3 100644 --- a/gui/vacuum_agent.py +++ b/gui/vacuum_agent.py @@ -14,7 +14,7 @@ class Gui(Environment): or Clean. The agent perceives its location and the location's status.""" - def __init__(self, root, height=300, width=380, count=1): + def __init__(self, root, height=300, width=380): super().__init__() self.status = {loc_A: 'Clean', loc_B: 'Clean'} @@ -23,7 +23,6 @@ def __init__(self, root, height=300, width=380, count=1): self.width = width self.canvas = None self.buttons = [] - self.count = count self.create_canvas() self.create_buttons() @@ -48,9 +47,9 @@ def execute_action(self, agent, action): elif action == 'Suck': if self.status[agent.location] == 'Dirty': if agent.location == loc_A: - self.buttons[0].config(bg='white') + self.buttons[0].config(bg='white', activebackground='light grey') else: - self.buttons[1].config(bg='white') + self.buttons[1].config(bg='white', activebackground='light grey') agent.performance += 10 self.status[agent.location] = 'Clean' @@ -72,19 +71,19 @@ def create_buttons(self): button_left = Button(self.root, height=4, width=12, padx=2, pady=2, bg='white') button_left.config(command=lambda btn=button_left: self.dirt_switch(btn)) self.buttons.append(button_left) - button_left_window = self.canvas.create_window(130, 235, anchor=N, window=button_left) + button_left_window = self.canvas.create_window(130, 200, anchor=N, window=button_left) button_right = Button(self.root, height=4, width=12, padx=2, pady=2, bg='white') button_right.config(command=lambda btn=button_right: self.dirt_switch(btn)) self.buttons.append(button_right) - button_right_window = self.canvas.create_window(250, 235, anchor=N, window=button_right) + button_right_window = self.canvas.create_window(250, 200, anchor=N, window=button_right) def dirt_switch(self, button): """Gives user the option to put dirt in any tile.""" - if self.count % 2 == 0: - button.config(bg='white') - elif self.count % 1 == 0: - button.config(bg='saddle brown') - self.count += 1 + bg_color = button['bg'] + if bg_color == 'saddle brown': + button.config(bg='white', activebackground='light grey') + elif bg_color == 'white': + button.config(bg='saddle brown', activebackground='light goldenrod') def read_env(self): """Reads the current state of the GUI.""" @@ -116,11 +115,11 @@ def create_agent(env, agent): env.add_thing(agent) # print(agent.location) if agent.location == (0, 0): - env.agent_rect = env.canvas.create_rectangle(80, 140, 175, 220, fill='lime green') - env.text = env.canvas.create_text(128, 180, font="Helvetica 10 bold italic", text="Agent") + env.agent_rect = env.canvas.create_rectangle(80, 100, 175, 180, fill='lime green') + env.text = env.canvas.create_text(128, 140, font="Helvetica 10 bold italic", text="Agent") else: - env.agent_rect = env.canvas.create_rectangle(200, 140, 295, 220, fill='lime green') - env.text = env.canvas.create_text(248, 180, font="Helvetica 10 bold italic", text="Agent") + env.agent_rect = env.canvas.create_rectangle(200, 100, 295, 180, fill='lime green') + env.text = env.canvas.create_text(248, 140, font="Helvetica 10 bold italic", text="Agent") def move_agent(env, agent, before_step): diff --git a/gui/xy_vacuum_environment.py b/gui/xy_vacuum_environment.py index 865cf6e5f..72d2f2434 100644 --- a/gui/xy_vacuum_environment.py +++ b/gui/xy_vacuum_environment.py @@ -12,14 +12,13 @@ class Gui(VacuumEnvironment): """ xi, yi = (0, 0) - def __init__(self, root, width=7, height=7, elements=['D', 'W'], count=1): + def __init__(self, root, width=7, height=7, elements=['D', 'W']): super().__init__(width, height) self.root = root self.create_frames() self.create_buttons() self.create_walls() self.elements = elements - self.count = count def create_frames(self): """Adds frames to the GUI environment.""" @@ -60,14 +59,14 @@ def create_walls(self): def display_element(self, button): """Show the things on the GUI.""" - if button['text'] != 'A': - if self.count % 3 == 0: + txt = button['text'] + if txt != 'A': + if txt == 'W': + button.config(text='D') + elif txt == 'D': button.config(text='') - elif self.count % 2 == 0: - button.config(text=self.elements[1]) - elif self.count % 1 == 0: - button.config(text=self.elements[0]) - self.count += 1 + elif txt == '': + button.config(text='W') def execute_action(self, agent, action): """Determines the action the agent performs."""