|  | 
|  | 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() | 
0 commit comments