Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 47e6089

Browse files
apb7norvig
authored andcommitted
Adding Tkinter GUI (aimacode#693)
* Added Vacuum Agent * Minor Fix * Improved Font * Added XYVacuumEnv * Minor Fix * Review changes
1 parent b13bb02 commit 47e6089

File tree

2 files changed

+338
-0
lines changed

2 files changed

+338
-0
lines changed

gui/vacuum_agent.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
from tkinter import *
2+
import random
3+
import sys
4+
import os.path
5+
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
6+
from agents import *
7+
8+
loc_A, loc_B = (0, 0), (1, 0) # The two locations for the Vacuum world
9+
10+
11+
class Gui(Environment):
12+
13+
"""This GUI environment has two locations, A and B. Each can be Dirty
14+
or Clean. The agent perceives its location and the location's
15+
status."""
16+
17+
def __init__(self, root, height=300, width=380):
18+
super().__init__()
19+
self.status = {loc_A: 'Clean',
20+
loc_B: 'Clean'}
21+
self.root = root
22+
self.height = height
23+
self.width = width
24+
self.canvas = None
25+
self.buttons = []
26+
self.create_canvas()
27+
self.create_buttons()
28+
29+
def thing_classes(self):
30+
"""The list of things which can be used in the environment."""
31+
return [Wall, Dirt, ReflexVacuumAgent, RandomVacuumAgent,
32+
TableDrivenVacuumAgent, ModelBasedVacuumAgent]
33+
34+
def percept(self, agent):
35+
"""Returns the agent's location, and the location status (Dirty/Clean)."""
36+
return (agent.location, self.status[agent.location])
37+
38+
def execute_action(self, agent, action):
39+
"""Change the location status (Dirty/Clean); track performance.
40+
Score 10 for each dirt cleaned; -1 for each move."""
41+
if action == 'Right':
42+
agent.location = loc_B
43+
agent.performance -= 1
44+
elif action == 'Left':
45+
agent.location = loc_A
46+
agent.performance -= 1
47+
elif action == 'Suck':
48+
if self.status[agent.location] == 'Dirty':
49+
if agent.location == loc_A:
50+
self.buttons[0].config(bg='white', activebackground='light grey')
51+
else:
52+
self.buttons[1].config(bg='white', activebackground='light grey')
53+
agent.performance += 10
54+
self.status[agent.location] = 'Clean'
55+
56+
def default_location(self, thing):
57+
"""Agents start in either location at random."""
58+
return random.choice([loc_A, loc_B])
59+
60+
def create_canvas(self):
61+
"""Creates Canvas element in the GUI."""
62+
self.canvas = Canvas(
63+
self.root,
64+
width=self.width,
65+
height=self.height,
66+
background='powder blue')
67+
self.canvas.pack(side='bottom')
68+
69+
def create_buttons(self):
70+
"""Creates the buttons required in the GUI."""
71+
button_left = Button(self.root, height=4, width=12, padx=2, pady=2, bg='white')
72+
button_left.config(command=lambda btn=button_left: self.dirt_switch(btn))
73+
self.buttons.append(button_left)
74+
button_left_window = self.canvas.create_window(130, 200, anchor=N, window=button_left)
75+
button_right = Button(self.root, height=4, width=12, padx=2, pady=2, bg='white')
76+
button_right.config(command=lambda btn=button_right: self.dirt_switch(btn))
77+
self.buttons.append(button_right)
78+
button_right_window = self.canvas.create_window(250, 200, anchor=N, window=button_right)
79+
80+
def dirt_switch(self, button):
81+
"""Gives user the option to put dirt in any tile."""
82+
bg_color = button['bg']
83+
if bg_color == 'saddle brown':
84+
button.config(bg='white', activebackground='light grey')
85+
elif bg_color == 'white':
86+
button.config(bg='saddle brown', activebackground='light goldenrod')
87+
88+
def read_env(self):
89+
"""Reads the current state of the GUI."""
90+
for i, btn in enumerate(self.buttons):
91+
if i == 0:
92+
if btn['bg'] == 'white':
93+
self.status[loc_A] = 'Clean'
94+
else:
95+
self.status[loc_A] = 'Dirty'
96+
else:
97+
if btn['bg'] == 'white':
98+
self.status[loc_B] = 'Clean'
99+
else:
100+
self.status[loc_B] = 'Dirty'
101+
102+
def update_env(self, agent):
103+
"""Updates the GUI according to the agent's action."""
104+
self.read_env()
105+
# print(self.status)
106+
before_step = agent.location
107+
self.step()
108+
# print(self.status)
109+
# print(agent.location)
110+
move_agent(self, agent, before_step)
111+
112+
113+
def create_agent(env, agent):
114+
"""Creates the agent in the GUI and is kept independent of the environment."""
115+
env.add_thing(agent)
116+
# print(agent.location)
117+
if agent.location == (0, 0):
118+
env.agent_rect = env.canvas.create_rectangle(80, 100, 175, 180, fill='lime green')
119+
env.text = env.canvas.create_text(128, 140, font="Helvetica 10 bold italic", text="Agent")
120+
else:
121+
env.agent_rect = env.canvas.create_rectangle(200, 100, 295, 180, fill='lime green')
122+
env.text = env.canvas.create_text(248, 140, font="Helvetica 10 bold italic", text="Agent")
123+
124+
125+
def move_agent(env, agent, before_step):
126+
"""Moves the agent in the GUI when 'next' button is pressed."""
127+
if agent.location == before_step:
128+
pass
129+
else:
130+
if agent.location == (1, 0):
131+
env.canvas.move(env.text, 120, 0)
132+
env.canvas.move(env.agent_rect, 120, 0)
133+
elif agent.location == (0, 0):
134+
env.canvas.move(env.text, -120, 0)
135+
env.canvas.move(env.agent_rect, -120, 0)
136+
137+
138+
# TODO: Add more agents to the environment.
139+
# TODO: Expand the environment to XYEnvironment.
140+
def main():
141+
"""The main function of the program."""
142+
root = Tk()
143+
root.title("Vacuum Environment")
144+
root.geometry("420x380")
145+
root.resizable(0, 0)
146+
frame = Frame(root, bg='black')
147+
# reset_button = Button(frame, text='Reset', height=2, width=6, padx=2, pady=2, command=None)
148+
# reset_button.pack(side='left')
149+
next_button = Button(frame, text='Next', height=2, width=6, padx=2, pady=2)
150+
next_button.pack(side='left')
151+
frame.pack(side='bottom')
152+
env = Gui(root)
153+
agent = ReflexVacuumAgent()
154+
create_agent(env, agent)
155+
next_button.config(command=lambda: env.update_env(agent))
156+
root.mainloop()
157+
158+
159+
if __name__ == "__main__":
160+
main()

gui/xy_vacuum_environment.py

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
from tkinter import *
2+
import random
3+
import sys
4+
import os.path
5+
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
6+
from agents import *
7+
8+
9+
class Gui(VacuumEnvironment):
10+
"""This is a two-dimensional GUI environment. Each location may be
11+
dirty, clean or can have a wall. The user can change these at each step.
12+
"""
13+
xi, yi = (0, 0)
14+
15+
def __init__(self, root, width=7, height=7, elements=['D', 'W']):
16+
super().__init__(width, height)
17+
self.root = root
18+
self.create_frames()
19+
self.create_buttons()
20+
self.create_walls()
21+
self.elements = elements
22+
23+
def create_frames(self):
24+
"""Adds frames to the GUI environment."""
25+
self.frames = []
26+
for _ in range(7):
27+
frame = Frame(self.root, bg='grey')
28+
frame.pack(side='bottom')
29+
self.frames.append(frame)
30+
31+
def create_buttons(self):
32+
"""Adds buttons to the respective frames in the GUI."""
33+
self.buttons = []
34+
for frame in self.frames:
35+
button_row = []
36+
for _ in range(7):
37+
button = Button(frame, height=3, width=5, padx=2, pady=2)
38+
button.config(
39+
command=lambda btn=button: self.display_element(btn))
40+
button.pack(side='left')
41+
button_row.append(button)
42+
self.buttons.append(button_row)
43+
44+
def create_walls(self):
45+
"""Creates the outer boundary walls which do not move."""
46+
for row, button_row in enumerate(self.buttons):
47+
if row == 0 or row == len(self.buttons) - 1:
48+
for button in button_row:
49+
button.config(text='W', state='disabled',
50+
disabledforeground='black')
51+
else:
52+
button_row[0].config(
53+
text='W', state='disabled', disabledforeground='black')
54+
button_row[len(button_row) - 1].config(text='W',
55+
state='disabled', disabledforeground='black')
56+
# Place the agent in the centre of the grid.
57+
self.buttons[3][3].config(
58+
text='A', state='disabled', disabledforeground='black')
59+
60+
def display_element(self, button):
61+
"""Show the things on the GUI."""
62+
txt = button['text']
63+
if txt != 'A':
64+
if txt == 'W':
65+
button.config(text='D')
66+
elif txt == 'D':
67+
button.config(text='')
68+
elif txt == '':
69+
button.config(text='W')
70+
71+
def execute_action(self, agent, action):
72+
"""Determines the action the agent performs."""
73+
xi, yi = ((self.xi, self.yi))
74+
if action == 'Suck':
75+
dirt_list = self.list_things_at(agent.location, Dirt)
76+
if dirt_list != []:
77+
dirt = dirt_list[0]
78+
agent.performance += 100
79+
self.delete_thing(dirt)
80+
self.buttons[xi][yi].config(text='', state='normal')
81+
xf, yf = agent.location
82+
self.buttons[xf][yf].config(
83+
text='A', state='disabled', disabledforeground='black')
84+
85+
else:
86+
agent.bump = False
87+
if action == 'TurnRight':
88+
agent.direction += Direction.R
89+
elif action == 'TurnLeft':
90+
agent.direction += Direction.L
91+
elif action == 'Forward':
92+
agent.bump = self.move_to(agent, agent.direction.move_forward(agent.location))
93+
if not agent.bump:
94+
self.buttons[xi][yi].config(text='', state='normal')
95+
xf, yf = agent.location
96+
self.buttons[xf][yf].config(
97+
text='A', state='disabled', disabledforeground='black')
98+
99+
if action != 'NoOp':
100+
agent.performance -= 1
101+
102+
def read_env(self):
103+
"""Reads the current state of the GUI environment."""
104+
for i, btn_row in enumerate(self.buttons):
105+
for j, btn in enumerate(btn_row):
106+
if (i != 0 and i != len(self.buttons) - 1) and (j != 0 and j != len(btn_row) - 1):
107+
agt_loc = self.agents[0].location
108+
if self.some_things_at((i, j)) and (i, j) != agt_loc:
109+
for thing in self.list_things_at((i, j)):
110+
self.delete_thing(thing)
111+
if btn['text'] == self.elements[0]:
112+
self.add_thing(Dirt(), (i, j))
113+
elif btn['text'] == self.elements[1]:
114+
self.add_thing(Wall(), (i, j))
115+
116+
def update_env(self):
117+
"""Updates the GUI environment according to the current state."""
118+
self.read_env()
119+
agt = self.agents[0]
120+
previous_agent_location = agt.location
121+
self.xi, self.yi = previous_agent_location
122+
self.step()
123+
xf, yf = agt.location
124+
125+
126+
def XYReflexAgentProgram(percept):
127+
"""The modified SimpleReflexAgentProgram for the GUI environment."""
128+
status, bump = percept
129+
if status == 'Dirty':
130+
return 'Suck'
131+
132+
if bump == 'Bump':
133+
value = random.choice((1, 2))
134+
else:
135+
value = random.choice((1, 2, 3, 4)) # 1-right, 2-left, others-forward
136+
137+
if value == 1:
138+
return 'TurnRight'
139+
elif value == 2:
140+
return 'TurnLeft'
141+
else:
142+
return 'Forward'
143+
144+
145+
class XYReflexAgent(Agent):
146+
"""The modified SimpleReflexAgent for the GUI environment."""
147+
148+
def __init__(self, program=None):
149+
super().__init__(program)
150+
self.location = (3, 3)
151+
self.direction = Direction("up")
152+
153+
154+
# TODO: Check the coordinate system.
155+
def main():
156+
"""The main function."""
157+
root = Tk()
158+
root.title("Vacuum Environment")
159+
root.geometry("420x440")
160+
root.resizable(0, 0)
161+
frame = Frame(root, bg='black')
162+
# create a reset button
163+
# reset_button = Button(frame, text='Reset', height=2,
164+
# width=6, padx=2, pady=2, command=None)
165+
# reset_button.pack(side='left')
166+
next_button = Button(frame, text='Next', height=2,
167+
width=6, padx=2, pady=2)
168+
next_button.pack(side='left')
169+
frame.pack(side='bottom')
170+
env = Gui(root)
171+
agt = XYReflexAgent(program=XYReflexAgentProgram)
172+
env.add_thing(agt, location=(3, 3))
173+
next_button.config(command=env.update_env)
174+
root.mainloop()
175+
176+
177+
if __name__ == "__main__":
178+
main()

0 commit comments

Comments
 (0)