forked from aimacode/aima-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added Vacuum Agent * Minor Fix * Improved Font * Added XYVacuumEnv * Minor Fix * Review changes
- Loading branch information
Showing
2 changed files
with
338 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
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): | ||
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.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', activebackground='light grey') | ||
else: | ||
self.buttons[1].config(bg='white', activebackground='light grey') | ||
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, 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, 200, anchor=N, window=button_right) | ||
|
||
def dirt_switch(self, button): | ||
"""Gives user the option to put dirt in any tile.""" | ||
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.""" | ||
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 = 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, 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): | ||
"""Moves the agent in the GUI when 'next' button is pressed.""" | ||
if agent.location == before_step: | ||
pass | ||
else: | ||
if agent.location == (1, 0): | ||
env.canvas.move(env.text, 120, 0) | ||
env.canvas.move(env.agent_rect, 120, 0) | ||
elif agent.location == (0, 0): | ||
env.canvas.move(env.text, -120, 0) | ||
env.canvas.move(env.agent_rect, -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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
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']): | ||
super().__init__(width, height) | ||
self.root = root | ||
self.create_frames() | ||
self.create_buttons() | ||
self.create_walls() | ||
self.elements = elements | ||
|
||
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 the agent in the centre of the grid. | ||
self.buttons[3][3].config( | ||
text='A', state='disabled', disabledforeground='black') | ||
|
||
def display_element(self, button): | ||
"""Show the things on the GUI.""" | ||
txt = button['text'] | ||
if txt != 'A': | ||
if txt == 'W': | ||
button.config(text='D') | ||
elif txt == 'D': | ||
button.config(text='') | ||
elif txt == '': | ||
button.config(text='W') | ||
|
||
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() | ||
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() |