text: """
  Maze board
  
  Red rectangle -> explorer
  
  State               Description             Reward
  -----               -----------             ------
  Black rectangles:   blackhole (fail)        -1
  Yellow circle:      treasure (success)      +1
  All other states:   ground                  0
  """
  
  import numpy as np
  import time
  import sys
  import tkinter as tk
  
  
  UNIT = 40   # pixels
  MAZE_H = 4  # grid height
  MAZE_W = 4  # grid width
  
  
  class MazeBoard(tk.Tk, object):
      def __init__(self):
          super(MazeBoard, self).__init__()
          self.title('maze')
          self.geometry('{0}x{1}'.format(MAZE_H * UNIT, MAZE_H * UNIT))
          self._build_maze()
  
      def _build_maze(self):
          self.canvas = tk.Canvas(self, bg='white',
                             height=MAZE_H * UNIT,
                             width=MAZE_W * UNIT)
  
          # create grids
          for c in range(0, MAZE_W * UNIT, UNIT):
              x0, y0, x1, y1 = c, 0, c, MAZE_H * UNIT
              self.canvas.create_line(x0, y0, x1, y1)
          for r in range(0, MAZE_H * UNIT, UNIT):
              x0, y0, x1, y1 = 0, r, MAZE_H * UNIT, r
              self.canvas.create_line(x0, y0, x1, y1)
  
          # create origin
          origin = np.array([20, 20])
  
          # hell
          hell1_center = origin + np.array([UNIT * 2, UNIT])
          self.hell1 = self.canvas.create_rectangle(
              hell1_center[0] - 15, hell1_center[1] - 15,
              hell1_center[0] + 15, hell1_center[1] + 15,
              fill='black')
          # hell
          hell2_center = origin + np.array([UNIT, UNIT * 2])
          self.hell2 = self.canvas.create_rectangle(
              hell2_center[0] - 15, hell2_center[1] - 15,
              hell2_center[0] + 15, hell2_center[1] + 15,
              fill='black')
  
          # create oval
          oval_center = origin + UNIT * 2
          self.oval = self.canvas.create_oval(
              oval_center[0] - 15, oval_center[1] - 15,
              oval_center[0] + 15, oval_center[1] + 15,
              fill='yellow')
  
          # create red rect
          self.rect = self.canvas.create_rectangle(
              origin[0] - 15, origin[1] - 15,
              origin[0] + 15, origin[1] + 15,
              fill='red')
  
          # pack all
          self.canvas.pack()
  
      def reset(self):
          self.update()
          time.sleep(0.5)
          self.canvas.delete(self.rect)
          origin = np.array([20, 20])
          self.rect = self.canvas.create_rectangle(
              origin[0] - 15, origin[1] - 15,
              origin[0] + 15, origin[1] + 15,
              fill='red')
          # return observation
          return self.canvas.coords(self.rect)
  
      def step(self, action):
          s = self.canvas.coords(self.rect)
          base_action = np.array([0, 0])
          if action == 0:   # up
              if s[1] > UNIT:
                  base_action[1] -= UNIT
          elif action == 1:   # down
              if s[1] < (MAZE_H - 1) * UNIT:
                  base_action[1] += UNIT
          elif action == 2:   # right
              if s[0] < (MAZE_W - 1) * UNIT:
                  base_action[0] += UNIT
          elif action == 3:   # left
              if s[0] > UNIT:
                  base_action[0] -= UNIT
  
          self.canvas.move(self.rect, base_action[0], base_action[1])  # move agent
  
          s_ = self.canvas.coords(self.rect)  # next state
  
          # reward function
          if s_ == self.canvas.coords(self.oval):
              reward = 1
              done = True
          elif s_ in [self.canvas.coords(self.hell1), self.canvas.coords(self.hell2)]:
              reward = -1
              done = True
          else:
              reward = 0
              done = False
  
          return s_, reward, done
  
      def render(self):
          time.sleep(0.1)
          self.update()
  
      def reset(self):
          self.update()
          time.sleep(0.5)
          self.canvas.delete(self.rect)
          origin = np.array([20, 20])
          self.rect = self.canvas.create_rectangle(
              origin[0] - 15, origin[1] - 15,
              origin[0] + 15, origin[1] + 15,
              fill='red')
          # return observation
          return self.canvas.coords(self.rect)
  
  if __name__ == '__main__':
      env = MazeBoard()
      env.step(2)
      # env.after(100, update)
      env.mainloop()