Переглянути джерело

Initial commit for adding pre-commit

StringTheory 2 роки тому
батько
коміт
c345e9027f

+ 53 - 0
.pre-commit-config.yaml

@@ -0,0 +1,53 @@
+---
+repos:
+  - repo: https://github.com/python/black
+    rev: 22.3.0
+    hooks:
+      - id: black
+  - repo: https://github.com/codespell-project/codespell
+    rev: v2.1.0
+    hooks:
+      - id: codespell
+#        args:
+#          - --ignore-words-list=
+  - repo: https://gitlab.com/PyCQA/flake8
+    rev: 4.0.1
+    hooks:
+      - id: flake8
+        args:
+          - '--per-file-ignores=*/__init__.py:F401'
+#          - --ignore=
+          - --max-complexity=30
+          - --max-line-length=456
+          - --show-source
+          - --statistics
+  - repo: https://github.com/PyCQA/isort
+    rev: 5.10.1
+    hooks:
+      - id: isort
+        args: ["--profile", "black"]
+#  - repo: https://github.com/pycqa/pydocstyle
+#    rev: 6.1.1
+#    hooks:
+#      - id: pydocstyle
+#        args:
+#          - --source
+#          - --explain
+#          - --convention=google
+#        additional_dependencies: ["toml"]
+  - repo: https://github.com/asottile/pyupgrade
+    rev: v2.32.0
+    hooks:
+      - id: pyupgrade
+        args: ["--py37-plus"]
+#  - repo: local
+#    hooks:
+#      - id: pyright
+#        name: pyright
+#        entry: pyright
+#        language: node
+#        pass_filenames: false
+#        types: [python]
+#        additional_dependencies: ["pyright"]
+#        args:
+#          - --project=pyproject.toml

+ 10 - 8
README.md

@@ -10,7 +10,7 @@ laptop, which means you can run your experiments faster. A known-working RL
 implementation can be found [in this repository](https://github.com/lcswillems/torch-rl).
 
 Requirements:
-- Python 3.5+
+- Python 3.7+
 - OpenAI Gym
 - NumPy
 - Matplotlib (optional, only needed for display)
@@ -132,8 +132,10 @@ compact and efficient encoding, with 3 input values per visible grid cell, 7x7x3
 These values are **not pixels**. If you want to obtain an array of RGB pixels as observations instead,
 use the `RGBImgPartialObsWrapper`. You can use it as follows:
 
-```
-from gym_minigrid.wrappers import *
+```python
+import gym
+from gym_minigrid.wrappers import RGBImgPartialObsWrapper, ImgObsWrapper
+
 env = gym.make('MiniGrid-Empty-8x8-v0')
 env = RGBImgPartialObsWrapper(env) # Get pixel observations
 env = ImgObsWrapper(env) # Get rid of the 'mission' field
@@ -323,7 +325,7 @@ object at split.
 
 ### Locked room environment
 
-Registed configurations:
+Registered configurations:
 - `MiniGrid-LockedRoom-v0`
 
 The environment has six rooms, one of which is locked. The agent receives
@@ -334,7 +336,7 @@ to solve with vanilla reinforcement learning alone.
 
 ### Key corridor environment
 
-Registed configurations:
+Registered configurations:
 - `MiniGrid-KeyCorridorS3R1-v0`
 - `MiniGrid-KeyCorridorS3R2-v0`
 - `MiniGrid-KeyCorridorS3R3-v0`
@@ -361,7 +363,7 @@ key is placed. This environment can be solved without relying on language.
 
 ### Unlock environment
 
-Registed configurations:
+Registered configurations:
 - `MiniGrid-Unlock-v0`
 
 <p align="center">
@@ -373,7 +375,7 @@ relying on language.
 
 ### Unlock pickup environment
 
-Registed configurations:
+Registered configurations:
 - `MiniGrid-UnlockPickup-v0`
 
 <p align="center">
@@ -385,7 +387,7 @@ locked door. This environment can be solved without relying on language.
 
 ### Blocked unlock pickup environment
 
-Registed configurations:
+Registered configurations:
 - `MiniGrid-BlockedUnlockPickup-v0`
 
 <p align="center">

+ 9 - 8
benchmark.py

@@ -1,17 +1,18 @@
 #!/usr/bin/env python3
 
-import time
 import argparse
-import gym_minigrid
+import time
+
 import gym
-from gym_minigrid.wrappers import *
+
+from gym_minigrid.wrappers import ImgObsWrapper, RGBImgPartialObsWrapper
 
 parser = argparse.ArgumentParser()
 parser.add_argument(
     "--env-name",
     dest="env_name",
     help="gym environment to load",
-    default='MiniGrid-LavaGapS7-v0'
+    default="MiniGrid-LavaGapS7-v0",
 )
 parser.add_argument("--num_resets", default=200)
 parser.add_argument("--num_frames", default=5000)
@@ -30,7 +31,7 @@ reset_time = (1000 * dt) / args.num_resets
 # Benchmark rendering
 t0 = time.time()
 for i in range(args.num_frames):
-    env.render('rgb_array')
+    env.render("rgb_array")
 t1 = time.time()
 dt = t1 - t0
 frames_per_sec = args.num_frames / dt
@@ -48,6 +49,6 @@ t1 = time.time()
 dt = t1 - t0
 agent_view_fps = args.num_frames / dt
 
-print('Env reset time: {:.1f} ms'.format(reset_time))
-print('Rendering FPS : {:.0f}'.format(frames_per_sec))
-print('Agent view FPS: {:.0f}'.format(agent_view_fps))
+print(f"Env reset time: {reset_time:.1f} ms")
+print(f"Rendering FPS : {frames_per_sec:.0f}")
+print(f"Agent view FPS: {agent_view_fps:.0f}")

+ 24 - 21
gym_minigrid/envs/__init__.py

@@ -1,21 +1,24 @@
-from gym_minigrid.envs.empty import *
-from gym_minigrid.envs.doorkey import *
-from gym_minigrid.envs.multiroom import *
-from gym_minigrid.envs.fetch import *
-from gym_minigrid.envs.gotoobject import *
-from gym_minigrid.envs.gotodoor import *
-from gym_minigrid.envs.putnear import *
-from gym_minigrid.envs.lockedroom import *
-from gym_minigrid.envs.keycorridor import *
-from gym_minigrid.envs.unlock import *
-from gym_minigrid.envs.unlockpickup import *
-from gym_minigrid.envs.blockedunlockpickup import *
-from gym_minigrid.envs.playground_v0 import *
-from gym_minigrid.envs.redbluedoors import *
-from gym_minigrid.envs.obstructedmaze import *
-from gym_minigrid.envs.memory import *
-from gym_minigrid.envs.fourrooms import *
-from gym_minigrid.envs.crossing import *
-from gym_minigrid.envs.lavagap import *
-from gym_minigrid.envs.dynamicobstacles import *
-from gym_minigrid.envs.distshift import *
+from gym_minigrid.envs.blockedunlockpickup import BlockedUnlockPickup
+from gym_minigrid.envs.crossing import CrossingEnv
+from gym_minigrid.envs.distshift import DistShiftEnv
+from gym_minigrid.envs.doorkey import DoorKeyEnv
+from gym_minigrid.envs.dynamicobstacles import DynamicObstaclesEnv
+from gym_minigrid.envs.empty import EmptyEnv
+from gym_minigrid.envs.fetch import FetchEnv
+from gym_minigrid.envs.fourrooms import FourRoomsEnv
+from gym_minigrid.envs.gotodoor import GoToDoorEnv
+from gym_minigrid.envs.gotoobject import GoToObjectEnv
+from gym_minigrid.envs.keycorridor import KeyCorridor
+from gym_minigrid.envs.lavagap import LavaGapEnv
+from gym_minigrid.envs.lockedroom import LockedRoom
+from gym_minigrid.envs.memory import MemoryEnv
+from gym_minigrid.envs.multiroom import MultiRoomEnv
+from gym_minigrid.envs.obstructedmaze import ObstructedMazeEnv
+from gym_minigrid.envs.playground_v0 import PlaygroundV0
+from gym_minigrid.envs.putnear import PutNearEnv
+from gym_minigrid.envs.redbluedoors import RedBlueDoorEnv, RedBlueDoorEnv6x6
+from gym_minigrid.envs.unlock import Unlock
+from gym_minigrid.envs.unlockpickup import UnlockPickup
+
+# from gym_minigrid.envs.lockedroom import Room as LockedRoom
+# from gym_minigrid.envs.multiroom import Room as MultiRoom

+ 10 - 8
gym_minigrid/envs/blockedunlockpickup.py

@@ -1,6 +1,7 @@
 from gym_minigrid.minigrid import Ball
-from gym_minigrid.roomgrid import RoomGrid
 from gym_minigrid.register import register
+from gym_minigrid.roomgrid import RoomGrid
+
 
 class BlockedUnlockPickup(RoomGrid):
     """
@@ -14,8 +15,8 @@ class BlockedUnlockPickup(RoomGrid):
             num_rows=1,
             num_cols=2,
             room_size=room_size,
-            max_steps=16*room_size**2,
-            seed=seed
+            max_steps=16 * room_size**2,
+            seed=seed,
         )
 
     def _gen_grid(self, width, height):
@@ -27,14 +28,14 @@ class BlockedUnlockPickup(RoomGrid):
         door, pos = self.add_door(0, 0, 0, locked=True)
         # Block the door with a ball
         color = self._rand_color()
-        self.grid.set(pos[0]-1, pos[1], Ball(color))
+        self.grid.set(pos[0] - 1, pos[1], Ball(color))
         # Add a key to unlock the door
-        self.add_object(0, 0, 'key', door.color)
+        self.add_object(0, 0, "key", door.color)
 
         self.place_agent(0, 0)
 
         self.obj = obj
-        self.mission = "pick up the %s %s" % (obj.color, obj.type)
+        self.mission = f"pick up the {obj.color} {obj.type}"
 
     def step(self, action):
         obs, reward, done, info = super().step(action)
@@ -46,7 +47,8 @@ class BlockedUnlockPickup(RoomGrid):
 
         return obs, reward, done, info
 
+
 register(
-    id='MiniGrid-BlockedUnlockPickup-v0',
-    entry_point='gym_minigrid.envs:BlockedUnlockPickup'
+    id="MiniGrid-BlockedUnlockPickup-v0",
+    entry_point="gym_minigrid.envs:BlockedUnlockPickup",
 )

+ 37 - 26
gym_minigrid/envs/crossing.py

@@ -1,8 +1,8 @@
-from gym_minigrid.minigrid import *
-from gym_minigrid.register import register
-
 import itertools as itt
 
+from gym_minigrid.minigrid import Goal, Grid, Lava, MiniGridEnv, Wall
+from gym_minigrid.register import register
+
 
 class CrossingEnv(MiniGridEnv):
     """
@@ -14,10 +14,10 @@ class CrossingEnv(MiniGridEnv):
         self.obstacle_type = obstacle_type
         super().__init__(
             grid_size=size,
-            max_steps=4*size*size,
+            max_steps=4 * size * size,
             # Set this to True for maximum speed
             see_through_walls=False,
-            seed=None
+            seed=None,
         )
 
     def _gen_grid(self, width, height):
@@ -43,9 +43,9 @@ class CrossingEnv(MiniGridEnv):
         rivers = [(v, i) for i in range(2, height - 2, 2)]
         rivers += [(h, j) for j in range(2, width - 2, 2)]
         self.np_random.shuffle(rivers)
-        rivers = rivers[:self.num_crossings]  # sample random rivers
-        rivers_v = sorted([pos for direction, pos in rivers if direction is v])
-        rivers_h = sorted([pos for direction, pos in rivers if direction is h])
+        rivers = rivers[: self.num_crossings]  # sample random rivers
+        rivers_v = sorted(pos for direction, pos in rivers if direction is v)
+        rivers_h = sorted(pos for direction, pos in rivers if direction is h)
         obstacle_pos = itt.chain(
             itt.product(range(1, width - 1), rivers_h),
             itt.product(rivers_v, range(1, height - 1)),
@@ -65,11 +65,13 @@ class CrossingEnv(MiniGridEnv):
             if direction is h:
                 i = limits_v[room_i + 1]
                 j = self.np_random.choice(
-                    range(limits_h[room_j] + 1, limits_h[room_j + 1]))
+                    range(limits_h[room_j] + 1, limits_h[room_j + 1])
+                )
                 room_i += 1
             elif direction is v:
                 i = self.np_random.choice(
-                    range(limits_v[room_i] + 1, limits_v[room_i + 1]))
+                    range(limits_v[room_i] + 1, limits_v[room_i + 1])
+                )
                 j = limits_h[room_j + 1]
                 room_j += 1
             else:
@@ -82,74 +84,83 @@ class CrossingEnv(MiniGridEnv):
             else "find the opening and get to the green goal square"
         )
 
+
 class LavaCrossingEnv(CrossingEnv):
     def __init__(self):
         super().__init__(size=9, num_crossings=1)
 
+
 class LavaCrossingS9N2Env(CrossingEnv):
     def __init__(self):
         super().__init__(size=9, num_crossings=2)
 
+
 class LavaCrossingS9N3Env(CrossingEnv):
     def __init__(self):
         super().__init__(size=9, num_crossings=3)
 
+
 class LavaCrossingS11N5Env(CrossingEnv):
     def __init__(self):
         super().__init__(size=11, num_crossings=5)
 
+
 register(
-    id='MiniGrid-LavaCrossingS9N1-v0',
-    entry_point='gym_minigrid.envs:LavaCrossingEnv'
+    id="MiniGrid-LavaCrossingS9N1-v0", entry_point="gym_minigrid.envs:LavaCrossingEnv"
 )
 
 register(
-    id='MiniGrid-LavaCrossingS9N2-v0',
-    entry_point='gym_minigrid.envs:LavaCrossingS9N2Env'
+    id="MiniGrid-LavaCrossingS9N2-v0",
+    entry_point="gym_minigrid.envs:LavaCrossingS9N2Env",
 )
 
 register(
-    id='MiniGrid-LavaCrossingS9N3-v0',
-    entry_point='gym_minigrid.envs:LavaCrossingS9N3Env'
+    id="MiniGrid-LavaCrossingS9N3-v0",
+    entry_point="gym_minigrid.envs:LavaCrossingS9N3Env",
 )
 
 register(
-    id='MiniGrid-LavaCrossingS11N5-v0',
-    entry_point='gym_minigrid.envs:LavaCrossingS11N5Env'
+    id="MiniGrid-LavaCrossingS11N5-v0",
+    entry_point="gym_minigrid.envs:LavaCrossingS11N5Env",
 )
 
+
 class SimpleCrossingEnv(CrossingEnv):
     def __init__(self):
         super().__init__(size=9, num_crossings=1, obstacle_type=Wall)
 
+
 class SimpleCrossingS9N2Env(CrossingEnv):
     def __init__(self):
         super().__init__(size=9, num_crossings=2, obstacle_type=Wall)
 
+
 class SimpleCrossingS9N3Env(CrossingEnv):
     def __init__(self):
         super().__init__(size=9, num_crossings=3, obstacle_type=Wall)
 
+
 class SimpleCrossingS11N5Env(CrossingEnv):
     def __init__(self):
         super().__init__(size=11, num_crossings=5, obstacle_type=Wall)
 
+
 register(
-    id='MiniGrid-SimpleCrossingS9N1-v0',
-    entry_point='gym_minigrid.envs:SimpleCrossingEnv'
+    id="MiniGrid-SimpleCrossingS9N1-v0",
+    entry_point="gym_minigrid.envs:SimpleCrossingEnv",
 )
 
 register(
-    id='MiniGrid-SimpleCrossingS9N2-v0',
-    entry_point='gym_minigrid.envs:SimpleCrossingS9N2Env'
+    id="MiniGrid-SimpleCrossingS9N2-v0",
+    entry_point="gym_minigrid.envs:SimpleCrossingS9N2Env",
 )
 
 register(
-    id='MiniGrid-SimpleCrossingS9N3-v0',
-    entry_point='gym_minigrid.envs:SimpleCrossingS9N3Env'
+    id="MiniGrid-SimpleCrossingS9N3-v0",
+    entry_point="gym_minigrid.envs:SimpleCrossingS9N3Env",
 )
 
 register(
-    id='MiniGrid-SimpleCrossingS11N5-v0',
-    entry_point='gym_minigrid.envs:SimpleCrossingS11N5Env'
+    id="MiniGrid-SimpleCrossingS11N5-v0",
+    entry_point="gym_minigrid.envs:SimpleCrossingS11N5Env",
 )

+ 13 - 20
gym_minigrid/envs/distshift.py

@@ -1,30 +1,26 @@
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import Goal, Grid, Lava, MiniGridEnv
 from gym_minigrid.register import register
 
+
 class DistShiftEnv(MiniGridEnv):
     """
     Distributional shift environment.
     """
 
     def __init__(
-        self,
-        width=9,
-        height=7,
-        agent_start_pos=(1,1),
-        agent_start_dir=0,
-        strip2_row=2
+        self, width=9, height=7, agent_start_pos=(1, 1), agent_start_dir=0, strip2_row=2
     ):
         self.agent_start_pos = agent_start_pos
         self.agent_start_dir = agent_start_dir
-        self.goal_pos = (width-2, 1)
+        self.goal_pos = (width - 2, 1)
         self.strip2_row = strip2_row
 
         super().__init__(
             width=width,
             height=height,
-            max_steps=4*width*height,
+            max_steps=4 * width * height,
             # Set this to True for maximum speed
-            see_through_walls=True
+            see_through_walls=True,
         )
 
     def _gen_grid(self, width, height):
@@ -39,8 +35,8 @@ class DistShiftEnv(MiniGridEnv):
 
         # Place the lava rows
         for i in range(self.width - 6):
-            self.grid.set(3+i, 1, Lava())
-            self.grid.set(3+i, self.strip2_row, Lava())
+            self.grid.set(3 + i, 1, Lava())
+            self.grid.set(3 + i, self.strip2_row, Lava())
 
         # Place the agent
         if self.agent_start_pos is not None:
@@ -51,20 +47,17 @@ class DistShiftEnv(MiniGridEnv):
 
         self.mission = "get to the green goal square"
 
+
 class DistShift1(DistShiftEnv):
     def __init__(self):
         super().__init__(strip2_row=2)
 
+
 class DistShift2(DistShiftEnv):
     def __init__(self):
         super().__init__(strip2_row=5)
 
-register(
-    id='MiniGrid-DistShift1-v0',
-    entry_point='gym_minigrid.envs:DistShift1'
-)
 
-register(
-    id='MiniGrid-DistShift2-v0',
-    entry_point='gym_minigrid.envs:DistShift2'
-)
+register(id="MiniGrid-DistShift1-v0", entry_point="gym_minigrid.envs:DistShift1")
+
+register(id="MiniGrid-DistShift2-v0", entry_point="gym_minigrid.envs:DistShift2")

+ 15 - 27
gym_minigrid/envs/doorkey.py

@@ -1,16 +1,14 @@
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import Door, Goal, Grid, Key, MiniGridEnv
 from gym_minigrid.register import register
 
+
 class DoorKeyEnv(MiniGridEnv):
     """
     Environment with a door and key, sparse reward
     """
 
     def __init__(self, size=8):
-        super().__init__(
-            grid_size=size,
-            max_steps=10*size*size
-        )
+        super().__init__(grid_size=size, max_steps=10 * size * size)
 
     def _gen_grid(self, width, height):
         # Create an empty grid
@@ -23,7 +21,7 @@ class DoorKeyEnv(MiniGridEnv):
         self.put_obj(Goal(), width - 2, height - 2)
 
         # Create a vertical splitting wall
-        splitIdx = self._rand_int(2, width-2)
+        splitIdx = self._rand_int(2, width - 2)
         self.grid.vert_wall(splitIdx, 0)
 
         # Place the agent at a random position and orientation
@@ -31,46 +29,36 @@ class DoorKeyEnv(MiniGridEnv):
         self.place_agent(size=(splitIdx, height))
 
         # Place a door in the wall
-        doorIdx = self._rand_int(1, width-2)
-        self.put_obj(Door('yellow', is_locked=True), splitIdx, doorIdx)
+        doorIdx = self._rand_int(1, width - 2)
+        self.put_obj(Door("yellow", is_locked=True), splitIdx, doorIdx)
 
         # Place a yellow key on the left side
-        self.place_obj(
-            obj=Key('yellow'),
-            top=(0, 0),
-            size=(splitIdx, height)
-        )
+        self.place_obj(obj=Key("yellow"), top=(0, 0), size=(splitIdx, height))
 
         self.mission = "use the key to open the door and then get to the goal"
 
+
 class DoorKeyEnv5x5(DoorKeyEnv):
     def __init__(self):
         super().__init__(size=5)
 
+
 class DoorKeyEnv6x6(DoorKeyEnv):
     def __init__(self):
         super().__init__(size=6)
 
+
 class DoorKeyEnv16x16(DoorKeyEnv):
     def __init__(self):
         super().__init__(size=16)
 
-register(
-    id='MiniGrid-DoorKey-5x5-v0',
-    entry_point='gym_minigrid.envs:DoorKeyEnv5x5'
-)
 
-register(
-    id='MiniGrid-DoorKey-6x6-v0',
-    entry_point='gym_minigrid.envs:DoorKeyEnv6x6'
-)
+register(id="MiniGrid-DoorKey-5x5-v0", entry_point="gym_minigrid.envs:DoorKeyEnv5x5")
 
-register(
-    id='MiniGrid-DoorKey-8x8-v0',
-    entry_point='gym_minigrid.envs:DoorKeyEnv'
-)
+register(id="MiniGrid-DoorKey-6x6-v0", entry_point="gym_minigrid.envs:DoorKeyEnv6x6")
+
+register(id="MiniGrid-DoorKey-8x8-v0", entry_point="gym_minigrid.envs:DoorKeyEnv")
 
 register(
-    id='MiniGrid-DoorKey-16x16-v0',
-    entry_point='gym_minigrid.envs:DoorKeyEnv16x16'
+    id="MiniGrid-DoorKey-16x16-v0", entry_point="gym_minigrid.envs:DoorKeyEnv16x16"
 )

+ 34 - 26
gym_minigrid/envs/dynamicobstacles.py

@@ -1,27 +1,27 @@
-from gym_minigrid.minigrid import *
-from gym_minigrid.register import register
 from operator import add
 
+import gym
+
+from gym_minigrid.minigrid import Ball, Goal, Grid, MiniGridEnv
+from gym_minigrid.register import register
+
+
 class DynamicObstaclesEnv(MiniGridEnv):
     """
     Single-room square grid environment with moving obstacles
     """
 
     def __init__(
-            self,
-            size=8,
-            agent_start_pos=(1, 1),
-            agent_start_dir=0,
-            n_obstacles=4
+        self, size=8, agent_start_pos=(1, 1), agent_start_dir=0, n_obstacles=4
     ):
         self.agent_start_pos = agent_start_pos
         self.agent_start_dir = agent_start_dir
 
         # Reduce obstacles if there are too many
-        if n_obstacles <= size/2 + 1:
+        if n_obstacles <= size / 2 + 1:
             self.n_obstacles = int(n_obstacles)
         else:
-            self.n_obstacles = int(size/2)
+            self.n_obstacles = int(size / 2)
         super().__init__(
             grid_size=size,
             max_steps=4 * size * size,
@@ -29,7 +29,7 @@ class DynamicObstaclesEnv(MiniGridEnv):
             see_through_walls=True,
         )
         # Allow only 3 actions permitted: left, right, forward
-        self.action_space = spaces.Discrete(self.actions.forward + 1)
+        self.action_space = gym.spaces.Discrete(self.actions.forward + 1)
         self.reward_range = (-1, 1)
 
     def _gen_grid(self, width, height):
@@ -64,7 +64,7 @@ class DynamicObstaclesEnv(MiniGridEnv):
 
         # Check if there is an obstacle in front of the agent
         front_cell = self.grid.get(*self.front_pos)
-        not_clear = front_cell and front_cell.type != 'goal'
+        not_clear = front_cell and front_cell.type != "goal"
 
         # Update obstacle positions
         for i_obst in range(len(self.obstacles)):
@@ -72,13 +72,15 @@ class DynamicObstaclesEnv(MiniGridEnv):
             top = tuple(map(add, old_pos, (-1, -1)))
 
             try:
-                self.place_obj(self.obstacles[i_obst], top=top, size=(3,3), max_tries=100)
+                self.place_obj(
+                    self.obstacles[i_obst], top=top, size=(3, 3), max_tries=100
+                )
                 self.grid.set(*old_pos, None)
-            except:
+            except Exception:
                 pass
 
         # Update the agent's position/direction
-        obs, reward, done, info = MiniGridEnv.step(self, action)
+        obs, reward, done, info = super().step(action)
 
         # If the agent tried to walk over an obstacle or wall
         if action == self.actions.forward and not_clear:
@@ -88,52 +90,58 @@ class DynamicObstaclesEnv(MiniGridEnv):
 
         return obs, reward, done, info
 
+
 class DynamicObstaclesEnv5x5(DynamicObstaclesEnv):
     def __init__(self):
         super().__init__(size=5, n_obstacles=2)
 
+
 class DynamicObstaclesRandomEnv5x5(DynamicObstaclesEnv):
     def __init__(self):
         super().__init__(size=5, agent_start_pos=None, n_obstacles=2)
 
+
 class DynamicObstaclesEnv6x6(DynamicObstaclesEnv):
     def __init__(self):
         super().__init__(size=6, n_obstacles=3)
 
+
 class DynamicObstaclesRandomEnv6x6(DynamicObstaclesEnv):
     def __init__(self):
         super().__init__(size=6, agent_start_pos=None, n_obstacles=3)
 
+
 class DynamicObstaclesEnv16x16(DynamicObstaclesEnv):
     def __init__(self):
         super().__init__(size=16, n_obstacles=8)
 
+
 register(
-    id='MiniGrid-Dynamic-Obstacles-5x5-v0',
-    entry_point='gym_minigrid.envs:DynamicObstaclesEnv5x5'
+    id="MiniGrid-Dynamic-Obstacles-5x5-v0",
+    entry_point="gym_minigrid.envs:DynamicObstaclesEnv5x5",
 )
 
 register(
-    id='MiniGrid-Dynamic-Obstacles-Random-5x5-v0',
-    entry_point='gym_minigrid.envs:DynamicObstaclesRandomEnv5x5'
+    id="MiniGrid-Dynamic-Obstacles-Random-5x5-v0",
+    entry_point="gym_minigrid.envs:DynamicObstaclesRandomEnv5x5",
 )
 
 register(
-    id='MiniGrid-Dynamic-Obstacles-6x6-v0',
-    entry_point='gym_minigrid.envs:DynamicObstaclesEnv6x6'
+    id="MiniGrid-Dynamic-Obstacles-6x6-v0",
+    entry_point="gym_minigrid.envs:DynamicObstaclesEnv6x6",
 )
 
 register(
-    id='MiniGrid-Dynamic-Obstacles-Random-6x6-v0',
-    entry_point='gym_minigrid.envs:DynamicObstaclesRandomEnv6x6'
+    id="MiniGrid-Dynamic-Obstacles-Random-6x6-v0",
+    entry_point="gym_minigrid.envs:DynamicObstaclesRandomEnv6x6",
 )
 
 register(
-    id='MiniGrid-Dynamic-Obstacles-8x8-v0',
-    entry_point='gym_minigrid.envs:DynamicObstaclesEnv'
+    id="MiniGrid-Dynamic-Obstacles-8x8-v0",
+    entry_point="gym_minigrid.envs:DynamicObstaclesEnv",
 )
 
 register(
-    id='MiniGrid-Dynamic-Obstacles-16x16-v0',
-    entry_point='gym_minigrid.envs:DynamicObstaclesEnv16x16'
+    id="MiniGrid-Dynamic-Obstacles-16x16-v0",
+    entry_point="gym_minigrid.envs:DynamicObstaclesEnv16x16",
 )

+ 17 - 24
gym_minigrid/envs/empty.py

@@ -1,6 +1,7 @@
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import Goal, Grid, MiniGridEnv
 from gym_minigrid.register import register
 
+
 class EmptyEnv(MiniGridEnv):
     """
     Empty grid environment, no obstacles, sparse reward
@@ -9,7 +10,7 @@ class EmptyEnv(MiniGridEnv):
     def __init__(
         self,
         size=8,
-        agent_start_pos=(1,1),
+        agent_start_pos=(1, 1),
         agent_start_dir=0,
     ):
         self.agent_start_pos = agent_start_pos
@@ -17,9 +18,9 @@ class EmptyEnv(MiniGridEnv):
 
         super().__init__(
             grid_size=size,
-            max_steps=4*size*size,
+            max_steps=4 * size * size,
             # Set this to True for maximum speed
-            see_through_walls=True
+            see_through_walls=True,
         )
 
     def _gen_grid(self, width, height):
@@ -41,52 +42,44 @@ class EmptyEnv(MiniGridEnv):
 
         self.mission = "get to the green goal square"
 
+
 class EmptyEnv5x5(EmptyEnv):
     def __init__(self, **kwargs):
         super().__init__(size=5, **kwargs)
 
+
 class EmptyRandomEnv5x5(EmptyEnv):
     def __init__(self):
         super().__init__(size=5, agent_start_pos=None)
 
+
 class EmptyEnv6x6(EmptyEnv):
     def __init__(self, **kwargs):
         super().__init__(size=6, **kwargs)
 
+
 class EmptyRandomEnv6x6(EmptyEnv):
     def __init__(self):
         super().__init__(size=6, agent_start_pos=None)
 
+
 class EmptyEnv16x16(EmptyEnv):
     def __init__(self, **kwargs):
         super().__init__(size=16, **kwargs)
 
-register(
-    id='MiniGrid-Empty-5x5-v0',
-    entry_point='gym_minigrid.envs:EmptyEnv5x5'
-)
 
-register(
-    id='MiniGrid-Empty-Random-5x5-v0',
-    entry_point='gym_minigrid.envs:EmptyRandomEnv5x5'
-)
+register(id="MiniGrid-Empty-5x5-v0", entry_point="gym_minigrid.envs:EmptyEnv5x5")
 
 register(
-    id='MiniGrid-Empty-6x6-v0',
-    entry_point='gym_minigrid.envs:EmptyEnv6x6'
+    id="MiniGrid-Empty-Random-5x5-v0", entry_point="gym_minigrid.envs:EmptyRandomEnv5x5"
 )
 
-register(
-    id='MiniGrid-Empty-Random-6x6-v0',
-    entry_point='gym_minigrid.envs:EmptyRandomEnv6x6'
-)
+register(id="MiniGrid-Empty-6x6-v0", entry_point="gym_minigrid.envs:EmptyEnv6x6")
 
 register(
-    id='MiniGrid-Empty-8x8-v0',
-    entry_point='gym_minigrid.envs:EmptyEnv'
+    id="MiniGrid-Empty-Random-6x6-v0", entry_point="gym_minigrid.envs:EmptyRandomEnv6x6"
 )
 
-register(
-    id='MiniGrid-Empty-16x16-v0',
-    entry_point='gym_minigrid.envs:EmptyEnv16x16'
-)
+register(id="MiniGrid-Empty-8x8-v0", entry_point="gym_minigrid.envs:EmptyEnv")
+
+register(id="MiniGrid-Empty-16x16-v0", entry_point="gym_minigrid.envs:EmptyEnv16x16")

+ 27 - 34
gym_minigrid/envs/fetch.py

@@ -1,24 +1,21 @@
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import COLOR_NAMES, Ball, Grid, Key, MiniGridEnv
 from gym_minigrid.register import register
 
+
 class FetchEnv(MiniGridEnv):
     """
     Environment in which the agent has to fetch a random object
     named using English text strings
     """
 
-    def __init__(
-        self,
-        size=8,
-        numObjs=3
-    ):
+    def __init__(self, size=8, numObjs=3):
         self.numObjs = numObjs
 
         super().__init__(
             grid_size=size,
-            max_steps=5*size**2,
+            max_steps=5 * size**2,
             # Set this to True for maximum speed
-            see_through_walls=True
+            see_through_walls=True,
         )
 
     def _gen_grid(self, width, height):
@@ -26,11 +23,11 @@ class FetchEnv(MiniGridEnv):
 
         # Generate the surrounding walls
         self.grid.horz_wall(0, 0)
-        self.grid.horz_wall(0, height-1)
+        self.grid.horz_wall(0, height - 1)
         self.grid.vert_wall(0, 0)
-        self.grid.vert_wall(width-1, 0)
+        self.grid.vert_wall(width - 1, 0)
 
-        types = ['key', 'ball']
+        types = ["key", "ball"]
 
         objs = []
 
@@ -39,9 +36,9 @@ class FetchEnv(MiniGridEnv):
             objType = self._rand_elem(types)
             objColor = self._rand_elem(COLOR_NAMES)
 
-            if objType == 'key':
+            if objType == "key":
                 obj = Key(objColor)
-            elif objType == 'ball':
+            elif objType == "ball":
                 obj = Ball(objColor)
 
             self.place_obj(obj)
@@ -55,28 +52,30 @@ class FetchEnv(MiniGridEnv):
         self.targetType = target.type
         self.targetColor = target.color
 
-        descStr = '%s %s' % (self.targetColor, self.targetType)
+        descStr = f"{self.targetColor} {self.targetType}"
 
         # Generate the mission string
         idx = self._rand_int(0, 5)
         if idx == 0:
-            self.mission = 'get a %s' % descStr
+            self.mission = "get a %s" % descStr
         elif idx == 1:
-            self.mission = 'go get a %s' % descStr
+            self.mission = "go get a %s" % descStr
         elif idx == 2:
-            self.mission = 'fetch a %s' % descStr
+            self.mission = "fetch a %s" % descStr
         elif idx == 3:
-            self.mission = 'go fetch a %s' % descStr
+            self.mission = "go fetch a %s" % descStr
         elif idx == 4:
-            self.mission = 'you must fetch a %s' % descStr
-        assert hasattr(self, 'mission')
+            self.mission = "you must fetch a %s" % descStr
+        assert hasattr(self, "mission")
 
     def step(self, action):
         obs, reward, done, info = MiniGridEnv.step(self, action)
 
         if self.carrying:
-            if self.carrying.color == self.targetColor and \
-               self.carrying.type == self.targetType:
+            if (
+                self.carrying.color == self.targetColor
+                and self.carrying.type == self.targetType
+            ):
                 reward = self._reward()
                 done = True
             else:
@@ -85,25 +84,19 @@ class FetchEnv(MiniGridEnv):
 
         return obs, reward, done, info
 
+
 class FetchEnv5x5N2(FetchEnv):
     def __init__(self):
         super().__init__(size=5, numObjs=2)
 
+
 class FetchEnv6x6N2(FetchEnv):
     def __init__(self):
         super().__init__(size=6, numObjs=2)
 
-register(
-    id='MiniGrid-Fetch-5x5-N2-v0',
-    entry_point='gym_minigrid.envs:FetchEnv5x5N2'
-)
 
-register(
-    id='MiniGrid-Fetch-6x6-N2-v0',
-    entry_point='gym_minigrid.envs:FetchEnv6x6N2'
-)
+register(id="MiniGrid-Fetch-5x5-N2-v0", entry_point="gym_minigrid.envs:FetchEnv5x5N2")
+
+register(id="MiniGrid-Fetch-6x6-N2-v0", entry_point="gym_minigrid.envs:FetchEnv6x6N2")
 
-register(
-    id='MiniGrid-Fetch-8x8-N3-v0',
-    entry_point='gym_minigrid.envs:FetchEnv'
-)
+register(id="MiniGrid-Fetch-8x8-N3-v0", entry_point="gym_minigrid.envs:FetchEnv")

+ 4 - 8
gym_minigrid/envs/fourrooms.py

@@ -1,7 +1,5 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import Goal, Grid, MiniGridEnv
 from gym_minigrid.register import register
 
 
@@ -66,13 +64,11 @@ class FourRoomsEnv(MiniGridEnv):
         else:
             self.place_obj(Goal())
 
-        self.mission = 'Reach the goal'
+        self.mission = "Reach the goal"
 
     def step(self, action):
         obs, reward, done, info = MiniGridEnv.step(self, action)
         return obs, reward, done, info
 
-register(
-    id='MiniGrid-FourRooms-v0',
-    entry_point='gym_minigrid.envs:FourRoomsEnv'
-)
+
+register(id="MiniGrid-FourRooms-v0", entry_point="gym_minigrid.envs:FourRoomsEnv")

+ 18 - 26
gym_minigrid/envs/gotodoor.py

@@ -1,23 +1,21 @@
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import COLOR_NAMES, Door, Grid, MiniGridEnv
 from gym_minigrid.register import register
 
+
 class GoToDoorEnv(MiniGridEnv):
     """
     Environment in which the agent is instructed to go to a given object
     named using an English text string
     """
 
-    def __init__(
-        self,
-        size=5
-    ):
+    def __init__(self, size=5):
         assert size >= 5
 
         super().__init__(
             grid_size=size,
-            max_steps=5*size**2,
+            max_steps=5 * size**2,
             # Set this to True for maximum speed
-            see_through_walls=True
+            see_through_walls=True,
         )
 
     def _gen_grid(self, width, height):
@@ -25,18 +23,18 @@ class GoToDoorEnv(MiniGridEnv):
         self.grid = Grid(width, height)
 
         # Randomly vary the room width and height
-        width = self._rand_int(5, width+1)
-        height = self._rand_int(5, height+1)
+        width = self._rand_int(5, width + 1)
+        height = self._rand_int(5, height + 1)
 
         # Generate the surrounding walls
         self.grid.wall_rect(0, 0, width, height)
 
         # Generate the 4 doors at random positions
         doorPos = []
-        doorPos.append((self._rand_int(2, width-2), 0))
-        doorPos.append((self._rand_int(2, width-2), height-1))
-        doorPos.append((0, self._rand_int(2, height-2)))
-        doorPos.append((width-1, self._rand_int(2, height-2)))
+        doorPos.append((self._rand_int(2, width - 2), 0))
+        doorPos.append((self._rand_int(2, width - 2), height - 1))
+        doorPos.append((0, self._rand_int(2, height - 2)))
+        doorPos.append((width - 1, self._rand_int(2, height - 2)))
 
         # Generate the door colors
         doorColors = []
@@ -60,7 +58,7 @@ class GoToDoorEnv(MiniGridEnv):
         self.target_color = doorColors[doorIdx]
 
         # Generate the mission string
-        self.mission = 'go to the %s door' % self.target_color
+        self.mission = "go to the %s door" % self.target_color
 
     def step(self, action):
         obs, reward, done, info = super().step(action)
@@ -80,25 +78,19 @@ class GoToDoorEnv(MiniGridEnv):
 
         return obs, reward, done, info
 
+
 class GoToDoor8x8Env(GoToDoorEnv):
     def __init__(self):
         super().__init__(size=8)
 
+
 class GoToDoor6x6Env(GoToDoorEnv):
     def __init__(self):
         super().__init__(size=6)
 
-register(
-    id='MiniGrid-GoToDoor-5x5-v0',
-    entry_point='gym_minigrid.envs:GoToDoorEnv'
-)
 
-register(
-    id='MiniGrid-GoToDoor-6x6-v0',
-    entry_point='gym_minigrid.envs:GoToDoor6x6Env'
-)
+register(id="MiniGrid-GoToDoor-5x5-v0", entry_point="gym_minigrid.envs:GoToDoorEnv")
+
+register(id="MiniGrid-GoToDoor-6x6-v0", entry_point="gym_minigrid.envs:GoToDoor6x6Env")
 
-register(
-    id='MiniGrid-GoToDoor-8x8-v0',
-    entry_point='gym_minigrid.envs:GoToDoor8x8Env'
-)
+register(id="MiniGrid-GoToDoor-8x8-v0", entry_point="gym_minigrid.envs:GoToDoor8x8Env")

+ 17 - 20
gym_minigrid/envs/gotoobject.py

@@ -1,24 +1,21 @@
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import COLOR_NAMES, Ball, Box, Grid, Key, MiniGridEnv
 from gym_minigrid.register import register
 
+
 class GoToObjectEnv(MiniGridEnv):
     """
     Environment in which the agent is instructed to go to a given object
     named using an English text string
     """
 
-    def __init__(
-        self,
-        size=6,
-        numObjs=2
-    ):
+    def __init__(self, size=6, numObjs=2):
         self.numObjs = numObjs
 
         super().__init__(
             grid_size=size,
-            max_steps=5*size**2,
+            max_steps=5 * size**2,
             # Set this to True for maximum speed
-            see_through_walls=True
+            see_through_walls=True,
         )
 
     def _gen_grid(self, width, height):
@@ -28,7 +25,7 @@ class GoToObjectEnv(MiniGridEnv):
         self.grid.wall_rect(0, 0, width, height)
 
         # Types and colors of objects we can generate
-        types = ['key', 'ball', 'box']
+        types = ["key", "ball", "box"]
 
         objs = []
         objPos = []
@@ -42,11 +39,11 @@ class GoToObjectEnv(MiniGridEnv):
             if (objType, objColor) in objs:
                 continue
 
-            if objType == 'key':
+            if objType == "key":
                 obj = Key(objColor)
-            elif objType == 'ball':
+            elif objType == "ball":
                 obj = Ball(objColor)
-            elif objType == 'box':
+            elif objType == "box":
                 obj = Box(objColor)
 
             pos = self.place_obj(obj)
@@ -61,12 +58,12 @@ class GoToObjectEnv(MiniGridEnv):
         self.targetType, self.target_color = objs[objIdx]
         self.target_pos = objPos[objIdx]
 
-        descStr = '%s %s' % (self.target_color, self.targetType)
-        self.mission = 'go to the %s' % descStr
-        #print(self.mission)
+        descStr = f"{self.target_color} {self.targetType}"
+        self.mission = "go to the %s" % descStr
+        # print(self.mission)
 
     def step(self, action):
-        obs, reward, done, info = MiniGridEnv.step(self, action)
+        obs, reward, done, info = super().step(action)
 
         ax, ay = self.agent_pos
         tx, ty = self.target_pos
@@ -83,16 +80,16 @@ class GoToObjectEnv(MiniGridEnv):
 
         return obs, reward, done, info
 
+
 class GotoEnv8x8N2(GoToObjectEnv):
     def __init__(self):
         super().__init__(size=8, numObjs=2)
 
+
 register(
-    id='MiniGrid-GoToObject-6x6-N2-v0',
-    entry_point='gym_minigrid.envs:GoToObjectEnv'
+    id="MiniGrid-GoToObject-6x6-N2-v0", entry_point="gym_minigrid.envs:GoToObjectEnv"
 )
 
 register(
-    id='MiniGrid-GoToObject-8x8-N2-v0',
-    entry_point='gym_minigrid.envs:GotoEnv8x8N2'
+    id="MiniGrid-GoToObject-8x8-N2-v0", entry_point="gym_minigrid.envs:GotoEnv8x8N2"
 )

+ 25 - 53
gym_minigrid/envs/keycorridor.py

@@ -1,5 +1,6 @@
-from gym_minigrid.roomgrid import RoomGrid
 from gym_minigrid.register import register
+from gym_minigrid.roomgrid import RoomGrid
+
 
 class KeyCorridor(RoomGrid):
     """
@@ -7,19 +8,13 @@ class KeyCorridor(RoomGrid):
     random room.
     """
 
-    def __init__(
-        self,
-        num_rows=3,
-        obj_type="ball",
-        room_size=6,
-        seed=None
-    ):
+    def __init__(self, num_rows=3, obj_type="ball", room_size=6, seed=None):
         self.obj_type = obj_type
 
         super().__init__(
             room_size=room_size,
             num_rows=num_rows,
-            max_steps=30*room_size**2,
+            max_steps=30 * room_size**2,
             seed=seed,
         )
 
@@ -37,7 +32,7 @@ class KeyCorridor(RoomGrid):
         obj, _ = self.add_object(2, room_idx, kind=self.obj_type)
 
         # Add a key in a random room on the left side
-        self.add_object(0, self._rand_int(0, self.num_rows), 'key', door.color)
+        self.add_object(0, self._rand_int(0, self.num_rows), "key", door.color)
 
         # Place the agent in the middle
         self.place_agent(1, self.num_rows // 2)
@@ -46,7 +41,7 @@ class KeyCorridor(RoomGrid):
         self.connect_all()
 
         self.obj = obj
-        self.mission = "pick up the %s %s" % (obj.color, obj.type)
+        self.mission = f"pick up the {obj.color} {obj.type}"
 
     def step(self, action):
         obs, reward, done, info = super().step(action)
@@ -58,80 +53,57 @@ class KeyCorridor(RoomGrid):
 
         return obs, reward, done, info
 
+
 class KeyCorridorS3R1(KeyCorridor):
     def __init__(self, seed=None):
-        super().__init__(
-            room_size=3,
-            num_rows=1,
-            seed=seed
-        )
+        super().__init__(room_size=3, num_rows=1, seed=seed)
+
 
 class KeyCorridorS3R2(KeyCorridor):
     def __init__(self, seed=None):
-        super().__init__(
-            room_size=3,
-            num_rows=2,
-            seed=seed
-        )
+        super().__init__(room_size=3, num_rows=2, seed=seed)
+
 
 class KeyCorridorS3R3(KeyCorridor):
     def __init__(self, seed=None):
-        super().__init__(
-            room_size=3,
-            num_rows=3,
-            seed=seed
-        )
+        super().__init__(room_size=3, num_rows=3, seed=seed)
+
 
 class KeyCorridorS4R3(KeyCorridor):
     def __init__(self, seed=None):
-        super().__init__(
-            room_size=4,
-            num_rows=3,
-            seed=seed
-        )
+        super().__init__(room_size=4, num_rows=3, seed=seed)
+
 
 class KeyCorridorS5R3(KeyCorridor):
     def __init__(self, seed=None):
-        super().__init__(
-            room_size=5,
-            num_rows=3,
-            seed=seed
-        )
+        super().__init__(room_size=5, num_rows=3, seed=seed)
+
 
 class KeyCorridorS6R3(KeyCorridor):
     def __init__(self, seed=None):
-        super().__init__(
-            room_size=6,
-            num_rows=3,
-            seed=seed
-        )
+        super().__init__(room_size=6, num_rows=3, seed=seed)
+
 
 register(
-    id='MiniGrid-KeyCorridorS3R1-v0',
-    entry_point='gym_minigrid.envs:KeyCorridorS3R1'
+    id="MiniGrid-KeyCorridorS3R1-v0", entry_point="gym_minigrid.envs:KeyCorridorS3R1"
 )
 
 register(
-    id='MiniGrid-KeyCorridorS3R2-v0',
-    entry_point='gym_minigrid.envs:KeyCorridorS3R2'
+    id="MiniGrid-KeyCorridorS3R2-v0", entry_point="gym_minigrid.envs:KeyCorridorS3R2"
 )
 
 register(
-    id='MiniGrid-KeyCorridorS3R3-v0',
-    entry_point='gym_minigrid.envs:KeyCorridorS3R3'
+    id="MiniGrid-KeyCorridorS3R3-v0", entry_point="gym_minigrid.envs:KeyCorridorS3R3"
 )
 
 register(
-    id='MiniGrid-KeyCorridorS4R3-v0',
-    entry_point='gym_minigrid.envs:KeyCorridorS4R3'
+    id="MiniGrid-KeyCorridorS4R3-v0", entry_point="gym_minigrid.envs:KeyCorridorS4R3"
 )
 
 register(
-    id='MiniGrid-KeyCorridorS5R3-v0',
-    entry_point='gym_minigrid.envs:KeyCorridorS5R3'
+    id="MiniGrid-KeyCorridorS5R3-v0", entry_point="gym_minigrid.envs:KeyCorridorS5R3"
 )
 
 register(
-    id='MiniGrid-KeyCorridorS6R3-v0',
-    entry_point='gym_minigrid.envs:KeyCorridorS6R3'
+    id="MiniGrid-KeyCorridorS6R3-v0", entry_point="gym_minigrid.envs:KeyCorridorS6R3"
 )

+ 19 - 19
gym_minigrid/envs/lavagap.py

@@ -1,6 +1,9 @@
-from gym_minigrid.minigrid import *
+import numpy as np
+
+from gym_minigrid.minigrid import Goal, Grid, Lava, MiniGridEnv
 from gym_minigrid.register import register
 
+
 class LavaGapEnv(MiniGridEnv):
     """
     Environment with one wall of lava with a small gap to cross through
@@ -11,10 +14,10 @@ class LavaGapEnv(MiniGridEnv):
         self.obstacle_type = obstacle_type
         super().__init__(
             grid_size=size,
-            max_steps=4*size*size,
+            max_steps=4 * size * size,
             # Set this to True for maximum speed
             see_through_walls=False,
-            seed=None
+            seed=None,
         )
 
     def _gen_grid(self, width, height):
@@ -35,10 +38,12 @@ class LavaGapEnv(MiniGridEnv):
         self.put_obj(Goal(), *self.goal_pos)
 
         # Generate and store random gap position
-        self.gap_pos = np.array((
-            self._rand_int(2, width - 2),
-            self._rand_int(1, height - 1),
-        ))
+        self.gap_pos = np.array(
+            (
+                self._rand_int(2, width - 2),
+                self._rand_int(1, height - 1),
+            )
+        )
 
         # Place the obstacle wall
         self.grid.vert_wall(self.gap_pos[0], 1, height - 2, self.obstacle_type)
@@ -52,29 +57,24 @@ class LavaGapEnv(MiniGridEnv):
             else "find the opening and get to the green goal square"
         )
 
+
 class LavaGapS5Env(LavaGapEnv):
     def __init__(self):
         super().__init__(size=5)
 
+
 class LavaGapS6Env(LavaGapEnv):
     def __init__(self):
         super().__init__(size=6)
 
+
 class LavaGapS7Env(LavaGapEnv):
     def __init__(self):
         super().__init__(size=7)
 
-register(
-    id='MiniGrid-LavaGapS5-v0',
-    entry_point='gym_minigrid.envs:LavaGapS5Env'
-)
 
-register(
-    id='MiniGrid-LavaGapS6-v0',
-    entry_point='gym_minigrid.envs:LavaGapS6Env'
-)
+register(id="MiniGrid-LavaGapS5-v0", entry_point="gym_minigrid.envs:LavaGapS5Env")
+
+register(id="MiniGrid-LavaGapS6-v0", entry_point="gym_minigrid.envs:LavaGapS6Env")
 
-register(
-    id='MiniGrid-LavaGapS7-v0',
-    entry_point='gym_minigrid.envs:LavaGapS7Env'
-)
+register(id="MiniGrid-LavaGapS7-v0", entry_point="gym_minigrid.envs:LavaGapS7Env")

+ 17 - 37
gym_minigrid/envs/lockedroom.py

@@ -1,13 +1,9 @@
-from gym import spaces
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import COLOR_NAMES, Door, Goal, Grid, Key, MiniGridEnv, Wall
 from gym_minigrid.register import register
 
+
 class Room:
-    def __init__(self,
-        top,
-        size,
-        doorPos
-    ):
+    def __init__(self, top, size, doorPos):
         self.top = top
         self.size = size
         self.doorPos = doorPos
@@ -17,10 +13,8 @@ class Room:
     def rand_pos(self, env):
         topX, topY = self.top
         sizeX, sizeY = self.size
-        return env._rand_pos(
-            topX + 1, topX + sizeX - 1,
-            topY + 1, topY + sizeY - 1
-        )
+        return env._rand_pos(topX + 1, topX + sizeX - 1, topY + 1, topY + sizeY - 1)
+
 
 class LockedRoom(MiniGridEnv):
     """
@@ -28,11 +22,8 @@ class LockedRoom(MiniGridEnv):
     named using an English text string
     """
 
-    def __init__(
-        self,
-        size=19
-    ):
-        super().__init__(grid_size=size, max_steps=10*size)
+    def __init__(self, size=19):
+        super().__init__(grid_size=size, max_steps=10 * size)
 
     def _gen_grid(self, width, height):
         # Create the grid
@@ -41,10 +32,10 @@ class LockedRoom(MiniGridEnv):
         # Generate the surrounding walls
         for i in range(0, width):
             self.grid.set(i, 0, Wall())
-            self.grid.set(i, height-1, Wall())
+            self.grid.set(i, height - 1, Wall())
         for j in range(0, height):
             self.grid.set(0, j, Wall())
-            self.grid.set(width-1, j, Wall())
+            self.grid.set(width - 1, j, Wall())
 
         # Hallway walls
         lWallIdx = width // 2 - 2
@@ -65,16 +56,8 @@ class LockedRoom(MiniGridEnv):
 
             roomW = lWallIdx + 1
             roomH = height // 3 + 1
-            self.rooms.append(Room(
-                (0, j),
-                (roomW, roomH),
-                (lWallIdx, j + 3)
-            ))
-            self.rooms.append(Room(
-                (rWallIdx, j),
-                (roomW, roomH),
-                (rWallIdx, j + 3)
-            ))
+            self.rooms.append(Room((0, j), (roomW, roomH), (lWallIdx, j + 3)))
+            self.rooms.append(Room((rWallIdx, j), (roomW, roomH), (rWallIdx, j + 3)))
 
         # Choose one random room to be locked
         lockedRoom = self._rand_elem(self.rooms)
@@ -103,22 +86,19 @@ class LockedRoom(MiniGridEnv):
 
         # Randomize the player start position and orientation
         self.agent_pos = self.place_agent(
-            top=(lWallIdx, 0),
-            size=(rWallIdx-lWallIdx, height)
+            top=(lWallIdx, 0), size=(rWallIdx - lWallIdx, height)
         )
 
         # Generate the mission string
         self.mission = (
-            'get the %s key from the %s room, '
-            'unlock the %s door and '
-            'go to the goal'
+            "get the %s key from the %s room, "
+            "unlock the %s door and "
+            "go to the goal"
         ) % (lockedRoom.color, keyRoom.color, lockedRoom.color)
 
     def step(self, action):
         obs, reward, done, info = MiniGridEnv.step(self, action)
         return obs, reward, done, info
 
-register(
-    id='MiniGrid-LockedRoom-v0',
-    entry_point='gym_minigrid.envs:LockedRoom'
-)
+
+register(id="MiniGrid-LockedRoom-v0", entry_point="gym_minigrid.envs:LockedRoom")

+ 32 - 19
gym_minigrid/envs/memory.py

@@ -1,6 +1,7 @@
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import Ball, Grid, Key, MiniGridEnv, Wall
 from gym_minigrid.register import register
 
+
 class MemoryEnv(MiniGridEnv):
     """
     This environment is a memory test. The agent starts in a small room
@@ -21,7 +22,7 @@ class MemoryEnv(MiniGridEnv):
         super().__init__(
             seed=seed,
             grid_size=size,
-            max_steps=5*size**2,
+            max_steps=5 * size**2,
             # Set this to True for maximum speed
             see_through_walls=False,
         )
@@ -31,7 +32,7 @@ class MemoryEnv(MiniGridEnv):
 
         # Generate the surrounding walls
         self.grid.horz_wall(0, 0)
-        self.grid.horz_wall(0, height-1)
+        self.grid.horz_wall(0, height - 1)
         self.grid.vert_wall(0, 0)
         self.grid.vert_wall(width - 1, 0)
 
@@ -67,13 +68,13 @@ class MemoryEnv(MiniGridEnv):
 
         # Place objects
         start_room_obj = self._rand_elem([Key, Ball])
-        self.grid.set(1, height // 2 - 1, start_room_obj('green'))
+        self.grid.set(1, height // 2 - 1, start_room_obj("green"))
 
         other_objs = self._rand_elem([[Ball, Key], [Key, Ball]])
         pos0 = (hallway_end + 1, height // 2 - 2)
         pos1 = (hallway_end + 1, height // 2 + 2)
-        self.grid.set(*pos0, other_objs[0]('green'))
-        self.grid.set(*pos1, other_objs[1]('green'))
+        self.grid.set(*pos0, other_objs[0]("green"))
+        self.grid.set(*pos1, other_objs[1]("green"))
 
         # Choose the target objects
         if start_room_obj == other_objs[0]:
@@ -83,7 +84,7 @@ class MemoryEnv(MiniGridEnv):
             self.success_pos = (pos1[0], pos1[1] - 1)
             self.failure_pos = (pos0[0], pos0[1] + 1)
 
-        self.mission = 'go to the matching object at the end of the hallway'
+        self.mission = "go to the matching object at the end of the hallway"
 
     def step(self, action):
         if action == MiniGridEnv.Actions.pickup:
@@ -99,56 +100,68 @@ class MemoryEnv(MiniGridEnv):
 
         return obs, reward, done, info
 
+
 class MemoryS17Random(MemoryEnv):
     def __init__(self, seed=None):
         super().__init__(seed=seed, size=17, random_length=True)
 
+
 register(
-    id='MiniGrid-MemoryS17Random-v0',
-    entry_point='gym_minigrid.envs:MemoryS17Random',
+    id="MiniGrid-MemoryS17Random-v0",
+    entry_point="gym_minigrid.envs:MemoryS17Random",
 )
 
+
 class MemoryS13Random(MemoryEnv):
     def __init__(self, seed=None):
         super().__init__(seed=seed, size=13, random_length=True)
 
+
 register(
-    id='MiniGrid-MemoryS13Random-v0',
-    entry_point='gym_minigrid.envs:MemoryS13Random',
+    id="MiniGrid-MemoryS13Random-v0",
+    entry_point="gym_minigrid.envs:MemoryS13Random",
 )
 
+
 class MemoryS13(MemoryEnv):
     def __init__(self, seed=None):
         super().__init__(seed=seed, size=13)
 
+
 register(
-    id='MiniGrid-MemoryS13-v0',
-    entry_point='gym_minigrid.envs:MemoryS13',
+    id="MiniGrid-MemoryS13-v0",
+    entry_point="gym_minigrid.envs:MemoryS13",
 )
 
+
 class MemoryS11(MemoryEnv):
     def __init__(self, seed=None):
         super().__init__(seed=seed, size=11)
 
+
 register(
-    id='MiniGrid-MemoryS11-v0',
-    entry_point='gym_minigrid.envs:MemoryS11',
+    id="MiniGrid-MemoryS11-v0",
+    entry_point="gym_minigrid.envs:MemoryS11",
 )
 
+
 class MemoryS9(MemoryEnv):
     def __init__(self, seed=None):
         super().__init__(seed=seed, size=9)
 
+
 register(
-    id='MiniGrid-MemoryS9-v0',
-    entry_point='gym_minigrid.envs:MemoryS9',
+    id="MiniGrid-MemoryS9-v0",
+    entry_point="gym_minigrid.envs:MemoryS9",
 )
 
+
 class MemoryS7(MemoryEnv):
     def __init__(self, seed=None):
         super().__init__(seed=seed, size=7)
 
+
 register(
-    id='MiniGrid-MemoryS7-v0',
-    entry_point='gym_minigrid.envs:MemoryS7',
+    id="MiniGrid-MemoryS7-v0",
+    entry_point="gym_minigrid.envs:MemoryS7",
 )

+ 38 - 87
gym_minigrid/envs/multiroom.py

@@ -1,28 +1,21 @@
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import COLOR_NAMES, Door, Goal, Grid, MiniGridEnv, Wall
 from gym_minigrid.register import register
 
+
 class Room:
-    def __init__(self,
-        top,
-        size,
-        entryDoorPos,
-        exitDoorPos
-    ):
+    def __init__(self, top, size, entryDoorPos, exitDoorPos):
         self.top = top
         self.size = size
         self.entryDoorPos = entryDoorPos
         self.exitDoorPos = exitDoorPos
 
+
 class MultiRoomEnv(MiniGridEnv):
     """
     Environment with multiple rooms (subgoals)
     """
 
-    def __init__(self,
-        minNumRooms,
-        maxNumRooms,
-        maxRoomSize=10
-    ):
+    def __init__(self, minNumRooms, maxNumRooms, maxRoomSize=10):
         assert minNumRooms > 0
         assert maxNumRooms >= minNumRooms
         assert maxRoomSize >= 4
@@ -33,24 +26,18 @@ class MultiRoomEnv(MiniGridEnv):
 
         self.rooms = []
 
-        super(MultiRoomEnv, self).__init__(
-            grid_size=25,
-            max_steps=self.maxNumRooms * 20
-        )
+        super().__init__(grid_size=25, max_steps=self.maxNumRooms * 20)
 
     def _gen_grid(self, width, height):
         roomList = []
 
         # Choose a random number of rooms to generate
-        numRooms = self._rand_int(self.minNumRooms, self.maxNumRooms+1)
+        numRooms = self._rand_int(self.minNumRooms, self.maxNumRooms + 1)
 
         while len(roomList) < numRooms:
             curRoomList = []
 
-            entryDoorPos = (
-                self._rand_int(0, width - 2),
-                self._rand_int(0, width - 2)
-            )
+            entryDoorPos = (self._rand_int(0, width - 2), self._rand_int(0, width - 2))
 
             # Recursively place the rooms
             self._placeRoom(
@@ -59,7 +46,7 @@ class MultiRoomEnv(MiniGridEnv):
                 minSz=4,
                 maxSz=self.maxRoomSize,
                 entryDoorWall=2,
-                entryDoorPos=entryDoorPos
+                entryDoorPos=entryDoorPos,
             )
 
             if len(curRoomList) > len(roomList):
@@ -105,7 +92,7 @@ class MultiRoomEnv(MiniGridEnv):
                 self.grid.set(*room.entryDoorPos, entryDoor)
                 prevDoorColor = doorColor
 
-                prevRoom = roomList[idx-1]
+                prevRoom = roomList[idx - 1]
                 prevRoom.exitDoorPos = room.entryDoorPos
 
         # Randomize the starting agent position and direction
@@ -114,20 +101,12 @@ class MultiRoomEnv(MiniGridEnv):
         # Place the final goal in the last room
         self.goal_pos = self.place_obj(Goal(), roomList[-1].top, roomList[-1].size)
 
-        self.mission = 'traverse the rooms to get to the goal'
-
-    def _placeRoom(
-        self,
-        numLeft,
-        roomList,
-        minSz,
-        maxSz,
-        entryDoorWall,
-        entryDoorPos
-    ):
+        self.mission = "traverse the rooms to get to the goal"
+
+    def _placeRoom(self, numLeft, roomList, minSz, maxSz, entryDoorWall, entryDoorPos):
         # Choose the room size randomly
-        sizeX = self._rand_int(minSz, maxSz+1)
-        sizeY = self._rand_int(minSz, maxSz+1)
+        sizeX = self._rand_int(minSz, maxSz + 1)
+        sizeY = self._rand_int(minSz, maxSz + 1)
 
         # The first room will be at the door position
         if len(roomList) == 0:
@@ -163,22 +142,18 @@ class MultiRoomEnv(MiniGridEnv):
 
         # If the room intersects with previous rooms, can't place it here
         for room in roomList[:-1]:
-            nonOverlap = \
-                topX + sizeX < room.top[0] or \
-                room.top[0] + room.size[0] <= topX or \
-                topY + sizeY < room.top[1] or \
-                room.top[1] + room.size[1] <= topY
+            nonOverlap = (
+                topX + sizeX < room.top[0]
+                or room.top[0] + room.size[0] <= topX
+                or topY + sizeY < room.top[1]
+                or room.top[1] + room.size[1] <= topY
+            )
 
             if not nonOverlap:
                 return False
 
         # Add this room to the list
-        roomList.append(Room(
-            (topX, topY),
-            (sizeX, sizeY),
-            entryDoorPos,
-            None
-        ))
+        roomList.append(Room((topX, topY), (sizeX, sizeY), entryDoorPos, None))
 
         # If this was the last room, stop
         if numLeft == 1:
@@ -188,7 +163,7 @@ class MultiRoomEnv(MiniGridEnv):
         for i in range(0, 8):
 
             # Pick which wall to place the out door on
-            wallSet = set((0, 1, 2, 3))
+            wallSet = {0, 1, 2, 3}
             wallSet.remove(entryDoorWall)
             exitDoorWall = self._rand_elem(sorted(wallSet))
             nextEntryWall = (exitDoorWall + 2) % 4
@@ -196,28 +171,16 @@ class MultiRoomEnv(MiniGridEnv):
             # Pick the exit door position
             # Exit on right wall
             if exitDoorWall == 0:
-                exitDoorPos = (
-                    topX + sizeX - 1,
-                    topY + self._rand_int(1, sizeY - 1)
-                )
+                exitDoorPos = (topX + sizeX - 1, topY + self._rand_int(1, sizeY - 1))
             # Exit on south wall
             elif exitDoorWall == 1:
-                exitDoorPos = (
-                    topX + self._rand_int(1, sizeX - 1),
-                    topY + sizeY - 1
-                )
+                exitDoorPos = (topX + self._rand_int(1, sizeX - 1), topY + sizeY - 1)
             # Exit on left wall
             elif exitDoorWall == 2:
-                exitDoorPos = (
-                    topX,
-                    topY + self._rand_int(1, sizeY - 1)
-                )
+                exitDoorPos = (topX, topY + self._rand_int(1, sizeY - 1))
             # Exit on north wall
             elif exitDoorWall == 3:
-                exitDoorPos = (
-                    topX + self._rand_int(1, sizeX - 1),
-                    topY
-                )
+                exitDoorPos = (topX + self._rand_int(1, sizeX - 1), topY)
             else:
                 assert False
 
@@ -228,7 +191,7 @@ class MultiRoomEnv(MiniGridEnv):
                 minSz=minSz,
                 maxSz=maxSz,
                 entryDoorWall=nextEntryWall,
-                entryDoorPos=exitDoorPos
+                entryDoorPos=exitDoorPos,
             )
 
             if success:
@@ -236,40 +199,28 @@ class MultiRoomEnv(MiniGridEnv):
 
         return True
 
+
 class MultiRoomEnvN2S4(MultiRoomEnv):
     def __init__(self):
-        super().__init__(
-            minNumRooms=2,
-            maxNumRooms=2,
-            maxRoomSize=4
-        )
+        super().__init__(minNumRooms=2, maxNumRooms=2, maxRoomSize=4)
+
 
 class MultiRoomEnvN4S5(MultiRoomEnv):
     def __init__(self):
-        super().__init__(
-            minNumRooms=4,
-            maxNumRooms=4,
-            maxRoomSize=5
-        )
+        super().__init__(minNumRooms=4, maxNumRooms=4, maxRoomSize=5)
+
 
 class MultiRoomEnvN6(MultiRoomEnv):
     def __init__(self):
-        super().__init__(
-            minNumRooms=6,
-            maxNumRooms=6
-        )
+        super().__init__(minNumRooms=6, maxNumRooms=6)
 
-register(
-    id='MiniGrid-MultiRoom-N2-S4-v0',
-    entry_point='gym_minigrid.envs:MultiRoomEnvN2S4'
-)
 
 register(
-    id='MiniGrid-MultiRoom-N4-S5-v0',
-    entry_point='gym_minigrid.envs:MultiRoomEnvN4S5'
+    id="MiniGrid-MultiRoom-N2-S4-v0", entry_point="gym_minigrid.envs:MultiRoomEnvN2S4"
 )
 
 register(
-    id='MiniGrid-MultiRoom-N6-v0',
-    entry_point='gym_minigrid.envs:MultiRoomEnvN6'
+    id="MiniGrid-MultiRoom-N4-S5-v0", entry_point="gym_minigrid.envs:MultiRoomEnvN4S5"
 )
+
+register(id="MiniGrid-MultiRoom-N6-v0", entry_point="gym_minigrid.envs:MultiRoomEnvN6")

+ 71 - 48
gym_minigrid/envs/obstructedmaze.py

@@ -1,6 +1,7 @@
-from gym_minigrid.minigrid import *
-from gym_minigrid.roomgrid import RoomGrid
+from gym_minigrid.minigrid import COLOR_NAMES, DIR_TO_VEC, Ball, Box, Key
 from gym_minigrid.register import register
+from gym_minigrid.roomgrid import RoomGrid
+
 
 class ObstructedMazeEnv(RoomGrid):
     """
@@ -8,21 +9,16 @@ class ObstructedMazeEnv(RoomGrid):
     doors may be obstructed by a ball and keys may be hidden in boxes.
     """
 
-    def __init__(self,
-        num_rows,
-        num_cols,
-        num_rooms_visited,
-        seed=None
-    ):
+    def __init__(self, num_rows, num_cols, num_rooms_visited, seed=None):
         room_size = 6
-        max_steps = 4*num_rooms_visited*room_size**2
+        max_steps = 4 * num_rooms_visited * room_size**2
 
         super().__init__(
             room_size=room_size,
             num_rows=num_rows,
             num_cols=num_cols,
             max_steps=max_steps,
-            seed=seed
+            seed=seed,
         )
 
     def _gen_grid(self, width, height):
@@ -49,7 +45,16 @@ class ObstructedMazeEnv(RoomGrid):
 
         return obs, reward, done, info
 
-    def add_door(self, i, j, door_idx=0, color=None, locked=False, key_in_box=False, blocked=False):
+    def add_door(
+        self,
+        i,
+        j,
+        door_idx=0,
+        color=None,
+        locked=False,
+        key_in_box=False,
+        blocked=False,
+    ):
         """
         Add a door. If the door must be locked, it also adds the key.
         If the key must be hidden, it is put in a box. If the door must
@@ -61,8 +66,8 @@ class ObstructedMazeEnv(RoomGrid):
         if blocked:
             vec = DIR_TO_VEC[door_idx]
             blocking_ball = Ball(self.blocking_ball_color) if blocked else None
-            self.grid.set(door_pos[0]-vec[0], door_pos[1]-vec[1], blocking_ball)
-            
+            self.grid.set(door_pos[0] - vec[0], door_pos[1] - vec[1], blocking_ball)
+
         if locked:
             obj = Key(door.color)
             if key_in_box:
@@ -73,6 +78,7 @@ class ObstructedMazeEnv(RoomGrid):
 
         return door, door_pos
 
+
 class ObstructedMaze_1Dlhb(ObstructedMazeEnv):
     """
     A blue ball is hidden in a 2x1 maze. A locked door separates
@@ -83,32 +89,35 @@ class ObstructedMaze_1Dlhb(ObstructedMazeEnv):
         self.key_in_box = key_in_box
         self.blocked = blocked
 
-        super().__init__(
-            num_rows=1,
-            num_cols=2,
-            num_rooms_visited=2,
-            seed=seed
-        )
+        super().__init__(num_rows=1, num_cols=2, num_rooms_visited=2, seed=seed)
 
     def _gen_grid(self, width, height):
         super()._gen_grid(width, height)
 
-        self.add_door(0, 0, door_idx=0, color=self.door_colors[0],
-                      locked=True,
-                      key_in_box=self.key_in_box,
-                      blocked=self.blocked)
+        self.add_door(
+            0,
+            0,
+            door_idx=0,
+            color=self.door_colors[0],
+            locked=True,
+            key_in_box=self.key_in_box,
+            blocked=self.blocked,
+        )
 
         self.obj, _ = self.add_object(1, 0, "ball", color=self.ball_to_find_color)
         self.place_agent(0, 0)
 
+
 class ObstructedMaze_1Dl(ObstructedMaze_1Dlhb):
     def __init__(self, seed=None):
         super().__init__(False, False, seed)
 
+
 class ObstructedMaze_1Dlh(ObstructedMaze_1Dlhb):
     def __init__(self, seed=None):
         super().__init__(True, False, seed)
 
+
 class ObstructedMaze_Full(ObstructedMazeEnv):
     """
     A blue ball is hidden in one of the 4 corners of a 3x3 maze. Doors
@@ -116,18 +125,22 @@ class ObstructedMaze_Full(ObstructedMazeEnv):
     boxes.
     """
 
-    def __init__(self, agent_room=(1, 1), key_in_box=True, blocked=True,
-                 num_quarters=4, num_rooms_visited=25, seed=None):
+    def __init__(
+        self,
+        agent_room=(1, 1),
+        key_in_box=True,
+        blocked=True,
+        num_quarters=4,
+        num_rooms_visited=25,
+        seed=None,
+    ):
         self.agent_room = agent_room
         self.key_in_box = key_in_box
         self.blocked = blocked
         self.num_quarters = num_quarters
 
         super().__init__(
-            num_rows=3,
-            num_cols=3,
-            num_rooms_visited=num_rooms_visited,
-            seed=seed
+            num_rows=3, num_cols=3, num_rooms_visited=num_rooms_visited, seed=seed
         )
 
     def _gen_grid(self, width, height):
@@ -136,31 +149,38 @@ class ObstructedMaze_Full(ObstructedMazeEnv):
         middle_room = (1, 1)
         # Define positions of "side rooms" i.e. rooms that are neither
         # corners nor the center.
-        side_rooms = [(2, 1), (1, 2), (0, 1), (1, 0)][:self.num_quarters]
+        side_rooms = [(2, 1), (1, 2), (0, 1), (1, 0)][: self.num_quarters]
         for i in range(len(side_rooms)):
             side_room = side_rooms[i]
 
             # Add a door between the center room and the side room
-            self.add_door(*middle_room, door_idx=i, color=self.door_colors[i], locked=False)
+            self.add_door(
+                *middle_room, door_idx=i, color=self.door_colors[i], locked=False
+            )
 
             for k in [-1, 1]:
                 # Add a door to each side of the side room
-                self.add_door(*side_room, locked=True,
-                              door_idx=(i+k)%4,
-                              color=self.door_colors[(i+k)%len(self.door_colors)],
-                              key_in_box=self.key_in_box,
-                              blocked=self.blocked)
-
-        corners = [(2, 0), (2, 2), (0, 2), (0, 0)][:self.num_quarters]
+                self.add_door(
+                    *side_room,
+                    locked=True,
+                    door_idx=(i + k) % 4,
+                    color=self.door_colors[(i + k) % len(self.door_colors)],
+                    key_in_box=self.key_in_box,
+                    blocked=self.blocked
+                )
+
+        corners = [(2, 0), (2, 2), (0, 2), (0, 0)][: self.num_quarters]
         ball_room = self._rand_elem(corners)
 
         self.obj, _ = self.add_object(*ball_room, "ball", color=self.ball_to_find_color)
         self.place_agent(*self.agent_room)
 
+
 class ObstructedMaze_2Dl(ObstructedMaze_Full):
     def __init__(self, seed=None):
         super().__init__((2, 1), False, False, 1, 4, seed)
 
+
 class ObstructedMaze_2Dlh(ObstructedMaze_Full):
     def __init__(self, seed=None):
         super().__init__((2, 1), True, False, 1, 4, seed)
@@ -170,55 +190,58 @@ class ObstructedMaze_2Dlhb(ObstructedMaze_Full):
     def __init__(self, seed=None):
         super().__init__((2, 1), True, True, 1, 4, seed)
 
+
 class ObstructedMaze_1Q(ObstructedMaze_Full):
     def __init__(self, seed=None):
         super().__init__((1, 1), True, True, 1, 5, seed)
 
+
 class ObstructedMaze_2Q(ObstructedMaze_Full):
     def __init__(self, seed=None):
         super().__init__((1, 1), True, True, 2, 11, seed)
 
+
 register(
     id="MiniGrid-ObstructedMaze-1Dl-v0",
-    entry_point="gym_minigrid.envs:ObstructedMaze_1Dl"
+    entry_point="gym_minigrid.envs:ObstructedMaze_1Dl",
 )
 
 register(
     id="MiniGrid-ObstructedMaze-1Dlh-v0",
-    entry_point="gym_minigrid.envs:ObstructedMaze_1Dlh"
+    entry_point="gym_minigrid.envs:ObstructedMaze_1Dlh",
 )
 
 register(
     id="MiniGrid-ObstructedMaze-1Dlhb-v0",
-    entry_point="gym_minigrid.envs:ObstructedMaze_1Dlhb"
+    entry_point="gym_minigrid.envs:ObstructedMaze_1Dlhb",
 )
 
 register(
     id="MiniGrid-ObstructedMaze-2Dl-v0",
-    entry_point="gym_minigrid.envs:ObstructedMaze_2Dl"
+    entry_point="gym_minigrid.envs:ObstructedMaze_2Dl",
 )
 
 register(
     id="MiniGrid-ObstructedMaze-2Dlh-v0",
-    entry_point="gym_minigrid.envs:ObstructedMaze_2Dlh"
+    entry_point="gym_minigrid.envs:ObstructedMaze_2Dlh",
 )
 
 register(
     id="MiniGrid-ObstructedMaze-2Dlhb-v0",
-    entry_point="gym_minigrid.envs:ObstructedMaze_2Dlhb"
+    entry_point="gym_minigrid.envs:ObstructedMaze_2Dlhb",
 )
 
 register(
     id="MiniGrid-ObstructedMaze-1Q-v0",
-    entry_point="gym_minigrid.envs:ObstructedMaze_1Q"
+    entry_point="gym_minigrid.envs:ObstructedMaze_1Q",
 )
 
 register(
     id="MiniGrid-ObstructedMaze-2Q-v0",
-    entry_point="gym_minigrid.envs:ObstructedMaze_2Q"
+    entry_point="gym_minigrid.envs:ObstructedMaze_2Q",
 )
 
 register(
     id="MiniGrid-ObstructedMaze-Full-v0",
-    entry_point="gym_minigrid.envs:ObstructedMaze_Full"
-)
+    entry_point="gym_minigrid.envs:ObstructedMaze_Full",
+)

+ 16 - 17
gym_minigrid/envs/playground_v0.py

@@ -1,6 +1,7 @@
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import COLOR_NAMES, Ball, Box, Door, Grid, Key, MiniGridEnv
 from gym_minigrid.register import register
 
+
 class PlaygroundV0(MiniGridEnv):
     """
     Environment with multiple rooms and random objects.
@@ -16,9 +17,9 @@ class PlaygroundV0(MiniGridEnv):
 
         # Generate the surrounding walls
         self.grid.horz_wall(0, 0)
-        self.grid.horz_wall(0, height-1)
+        self.grid.horz_wall(0, height - 1)
         self.grid.vert_wall(0, 0)
-        self.grid.vert_wall(width-1, 0)
+        self.grid.vert_wall(width - 1, 0)
 
         roomW = width // 3
         roomH = height // 3
@@ -34,16 +35,16 @@ class PlaygroundV0(MiniGridEnv):
                 yB = yT + roomH
 
                 # Bottom wall and door
-                if i+1 < 3:
+                if i + 1 < 3:
                     self.grid.vert_wall(xR, yT, roomH)
-                    pos = (xR, self._rand_int(yT+1, yB-1))
+                    pos = (xR, self._rand_int(yT + 1, yB - 1))
                     color = self._rand_elem(COLOR_NAMES)
                     self.grid.set(*pos, Door(color))
 
                 # Bottom wall and door
-                if j+1 < 3:
+                if j + 1 < 3:
                     self.grid.horz_wall(xL, yB, roomW)
-                    pos = (self._rand_int(xL+1, xR-1), yB)
+                    pos = (self._rand_int(xL + 1, xR - 1), yB)
                     color = self._rand_elem(COLOR_NAMES)
                     self.grid.set(*pos, Door(color))
 
@@ -51,26 +52,24 @@ class PlaygroundV0(MiniGridEnv):
         self.place_agent()
 
         # Place random objects in the world
-        types = ['key', 'ball', 'box']
+        types = ["key", "ball", "box"]
         for i in range(0, 12):
             objType = self._rand_elem(types)
             objColor = self._rand_elem(COLOR_NAMES)
-            if objType == 'key':
+            if objType == "key":
                 obj = Key(objColor)
-            elif objType == 'ball':
+            elif objType == "ball":
                 obj = Ball(objColor)
-            elif objType == 'box':
+            elif objType == "box":
                 obj = Box(objColor)
             self.place_obj(obj)
 
         # No explicit mission in this environment
-        self.mission = ''
+        self.mission = ""
 
     def step(self, action):
-        obs, reward, done, info = MiniGridEnv.step(self, action)
+        obs, reward, done, info = super().step(action)
         return obs, reward, done, info
 
-register(
-    id='MiniGrid-Playground-v0',
-    entry_point='gym_minigrid.envs:PlaygroundV0'
-)
+
+register(id="MiniGrid-Playground-v0", entry_point="gym_minigrid.envs:PlaygroundV0")

+ 21 - 25
gym_minigrid/envs/putnear.py

@@ -1,24 +1,21 @@
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import COLOR_NAMES, Ball, Box, Grid, Key, MiniGridEnv
 from gym_minigrid.register import register
 
+
 class PutNearEnv(MiniGridEnv):
     """
     Environment in which the agent is instructed to place an object near
     another object through a natural language string.
     """
 
-    def __init__(
-        self,
-        size=6,
-        numObjs=2
-    ):
+    def __init__(self, size=6, numObjs=2):
         self.numObjs = numObjs
 
         super().__init__(
             grid_size=size,
-            max_steps=5*size,
+            max_steps=5 * size,
             # Set this to True for maximum speed
-            see_through_walls=True
+            see_through_walls=True,
         )
 
     def _gen_grid(self, width, height):
@@ -26,12 +23,12 @@ class PutNearEnv(MiniGridEnv):
 
         # Generate the surrounding walls
         self.grid.horz_wall(0, 0)
-        self.grid.horz_wall(0, height-1)
+        self.grid.horz_wall(0, height - 1)
         self.grid.vert_wall(0, 0)
-        self.grid.vert_wall(width-1, 0)
+        self.grid.vert_wall(width - 1, 0)
 
         # Types and colors of objects we can generate
-        types = ['key', 'ball', 'box']
+        types = ["key", "ball", "box"]
 
         objs = []
         objPos = []
@@ -53,11 +50,11 @@ class PutNearEnv(MiniGridEnv):
             if (objType, objColor) in objs:
                 continue
 
-            if objType == 'key':
+            if objType == "key":
                 obj = Key(objColor)
-            elif objType == 'ball':
+            elif objType == "ball":
                 obj = Ball(objColor)
-            elif objType == 'box':
+            elif objType == "box":
                 obj = Box(objColor)
 
             pos = self.place_obj(obj, reject_fn=near_obj)
@@ -81,11 +78,11 @@ class PutNearEnv(MiniGridEnv):
         self.target_type, self.target_color = objs[targetIdx]
         self.target_pos = objPos[targetIdx]
 
-        self.mission = 'put the %s %s near the %s %s' % (
+        self.mission = "put the {} {} near the {} {}".format(
             self.moveColor,
             self.move_type,
             self.target_color,
-            self.target_type
+            self.target_type,
         )
 
     def step(self, action):
@@ -99,7 +96,10 @@ class PutNearEnv(MiniGridEnv):
 
         # If we picked up the wrong object, terminate the episode
         if action == self.actions.pickup and self.carrying:
-            if self.carrying.type != self.move_type or self.carrying.color != self.moveColor:
+            if (
+                self.carrying.type != self.move_type
+                or self.carrying.color != self.moveColor
+            ):
                 done = True
 
         # If successfully dropping an object near the target
@@ -111,16 +111,12 @@ class PutNearEnv(MiniGridEnv):
 
         return obs, reward, done, info
 
+
 class PutNear8x8N3(PutNearEnv):
     def __init__(self):
         super().__init__(size=8, numObjs=3)
 
-register(
-    id='MiniGrid-PutNear-6x6-N2-v0',
-    entry_point='gym_minigrid.envs:PutNearEnv'
-)
 
-register(
-    id='MiniGrid-PutNear-8x8-N3-v0',
-    entry_point='gym_minigrid.envs:PutNear8x8N3'
-)
+register(id="MiniGrid-PutNear-6x6-N2-v0", entry_point="gym_minigrid.envs:PutNearEnv")
+
+register(id="MiniGrid-PutNear-8x8-N3-v0", entry_point="gym_minigrid.envs:PutNear8x8N3")

+ 12 - 15
gym_minigrid/envs/redbluedoors.py

@@ -1,6 +1,7 @@
-from gym_minigrid.minigrid import *
+from gym_minigrid.minigrid import Door, Grid, MiniGridEnv
 from gym_minigrid.register import register
 
+
 class RedBlueDoorEnv(MiniGridEnv):
     """
     Single room with red and blue doors on opposite sides.
@@ -11,32 +12,28 @@ class RedBlueDoorEnv(MiniGridEnv):
     def __init__(self, size=8):
         self.size = size
 
-        super().__init__(
-            width=2*size,
-            height=size,
-            max_steps=20*size*size
-        )
+        super().__init__(width=2 * size, height=size, max_steps=20 * size * size)
 
     def _gen_grid(self, width, height):
         # Create an empty grid
         self.grid = Grid(width, height)
 
         # Generate the grid walls
-        self.grid.wall_rect(0, 0, 2*self.size, self.size)
-        self.grid.wall_rect(self.size//2, 0, self.size, self.size)
+        self.grid.wall_rect(0, 0, 2 * self.size, self.size)
+        self.grid.wall_rect(self.size // 2, 0, self.size, self.size)
 
         # Place the agent in the top-left corner
-        self.place_agent(top=(self.size//2, 0), size=(self.size, self.size))
+        self.place_agent(top=(self.size // 2, 0), size=(self.size, self.size))
 
         # Add a red door at a random position in the left wall
         pos = self._rand_int(1, self.size - 1)
         self.red_door = Door("red")
-        self.grid.set(self.size//2, pos, self.red_door)
+        self.grid.set(self.size // 2, pos, self.red_door)
 
         # Add a blue door at a random position in the right wall
         pos = self._rand_int(1, self.size - 1)
         self.blue_door = Door("blue")
-        self.grid.set(self.size//2 + self.size - 1, pos, self.blue_door)
+        self.grid.set(self.size // 2 + self.size - 1, pos, self.blue_door)
 
         # Generate the mission string
         self.mission = "open the red door then the blue door"
@@ -65,16 +62,16 @@ class RedBlueDoorEnv(MiniGridEnv):
 
         return obs, reward, done, info
 
+
 class RedBlueDoorEnv6x6(RedBlueDoorEnv):
     def __init__(self):
         super().__init__(size=6)
 
+
 register(
-    id='MiniGrid-RedBlueDoors-6x6-v0',
-    entry_point='gym_minigrid.envs:RedBlueDoorEnv6x6'
+    id="MiniGrid-RedBlueDoors-6x6-v0", entry_point="gym_minigrid.envs:RedBlueDoorEnv6x6"
 )
 
 register(
-    id='MiniGrid-RedBlueDoors-8x8-v0',
-    entry_point='gym_minigrid.envs:RedBlueDoorEnv'
+    id="MiniGrid-RedBlueDoors-8x8-v0", entry_point="gym_minigrid.envs:RedBlueDoorEnv"
 )

+ 7 - 9
gym_minigrid/envs/unlock.py

@@ -1,6 +1,6 @@
-from gym_minigrid.minigrid import Ball
-from gym_minigrid.roomgrid import RoomGrid
 from gym_minigrid.register import register
+from gym_minigrid.roomgrid import RoomGrid
+
 
 class Unlock(RoomGrid):
     """
@@ -13,8 +13,8 @@ class Unlock(RoomGrid):
             num_rows=1,
             num_cols=2,
             room_size=room_size,
-            max_steps=8*room_size**2,
-            seed=seed
+            max_steps=8 * room_size**2,
+            seed=seed,
         )
 
     def _gen_grid(self, width, height):
@@ -23,7 +23,7 @@ class Unlock(RoomGrid):
         # Make sure the two rooms are directly connected by a locked door
         door, _ = self.add_door(0, 0, 0, locked=True)
         # Add a key to unlock the door
-        self.add_object(0, 0, 'key', door.color)
+        self.add_object(0, 0, "key", door.color)
 
         self.place_agent(0, 0)
 
@@ -40,7 +40,5 @@ class Unlock(RoomGrid):
 
         return obs, reward, done, info
 
-register(
-    id='MiniGrid-Unlock-v0',
-    entry_point='gym_minigrid.envs:Unlock'
-)
+
+register(id="MiniGrid-Unlock-v0", entry_point="gym_minigrid.envs:Unlock")

+ 8 - 10
gym_minigrid/envs/unlockpickup.py

@@ -1,6 +1,6 @@
-from gym_minigrid.minigrid import Ball
-from gym_minigrid.roomgrid import RoomGrid
 from gym_minigrid.register import register
+from gym_minigrid.roomgrid import RoomGrid
+
 
 class UnlockPickup(RoomGrid):
     """
@@ -13,8 +13,8 @@ class UnlockPickup(RoomGrid):
             num_rows=1,
             num_cols=2,
             room_size=room_size,
-            max_steps=8*room_size**2,
-            seed=seed
+            max_steps=8 * room_size**2,
+            seed=seed,
         )
 
     def _gen_grid(self, width, height):
@@ -25,12 +25,12 @@ class UnlockPickup(RoomGrid):
         # Make sure the two rooms are directly connected by a locked door
         door, _ = self.add_door(0, 0, 0, locked=True)
         # Add a key to unlock the door
-        self.add_object(0, 0, 'key', door.color)
+        self.add_object(0, 0, "key", door.color)
 
         self.place_agent(0, 0)
 
         self.obj = obj
-        self.mission = "pick up the %s %s" % (obj.color, obj.type)
+        self.mission = f"pick up the {obj.color} {obj.type}"
 
     def step(self, action):
         obs, reward, done, info = super().step(action)
@@ -42,7 +42,5 @@ class UnlockPickup(RoomGrid):
 
         return obs, reward, done, info
 
-register(
-    id='MiniGrid-UnlockPickup-v0',
-    entry_point='gym_minigrid.envs:UnlockPickup'
-)
+
+register(id="MiniGrid-UnlockPickup-v0", entry_point="gym_minigrid.envs:UnlockPickup")

+ 164 - 177
gym_minigrid/minigrid.py

@@ -1,61 +1,65 @@
-import math
 import hashlib
-import gym
+import math
 from enum import IntEnum
+
+import gym
 import numpy as np
-from gym import error, spaces, utils
+from gym import spaces
 from gym.utils import seeding
-from .rendering import *
+
+from gym_minigrid.rendering import (
+    downsample,
+    fill_coords,
+    highlight_img,
+    point_in_circle,
+    point_in_line,
+    point_in_rect,
+    point_in_triangle,
+    rotate_fn,
+)
 
 # Size in pixels of a tile in the full-scale human view
 TILE_PIXELS = 32
 
 # Map of color names to RGB values
 COLORS = {
-    'red'   : np.array([255, 0, 0]),
-    'green' : np.array([0, 255, 0]),
-    'blue'  : np.array([0, 0, 255]),
-    'purple': np.array([112, 39, 195]),
-    'yellow': np.array([255, 255, 0]),
-    'grey'  : np.array([100, 100, 100])
+    "red": np.array([255, 0, 0]),
+    "green": np.array([0, 255, 0]),
+    "blue": np.array([0, 0, 255]),
+    "purple": np.array([112, 39, 195]),
+    "yellow": np.array([255, 255, 0]),
+    "grey": np.array([100, 100, 100]),
 }
 
 COLOR_NAMES = sorted(list(COLORS.keys()))
 
 # Used to map colors to integers
-COLOR_TO_IDX = {
-    'red'   : 0,
-    'green' : 1,
-    'blue'  : 2,
-    'purple': 3,
-    'yellow': 4,
-    'grey'  : 5
-}
+COLOR_TO_IDX = {"red": 0, "green": 1, "blue": 2, "purple": 3, "yellow": 4, "grey": 5}
 
 IDX_TO_COLOR = dict(zip(COLOR_TO_IDX.values(), COLOR_TO_IDX.keys()))
 
 # Map of object type to integers
 OBJECT_TO_IDX = {
-    'unseen'        : 0,
-    'empty'         : 1,
-    'wall'          : 2,
-    'floor'         : 3,
-    'door'          : 4,
-    'key'           : 5,
-    'ball'          : 6,
-    'box'           : 7,
-    'goal'          : 8,
-    'lava'          : 9,
-    'agent'         : 10,
+    "unseen": 0,
+    "empty": 1,
+    "wall": 2,
+    "floor": 3,
+    "door": 4,
+    "key": 5,
+    "ball": 6,
+    "box": 7,
+    "goal": 8,
+    "lava": 9,
+    "agent": 10,
 }
 
 IDX_TO_OBJECT = dict(zip(OBJECT_TO_IDX.values(), OBJECT_TO_IDX.keys()))
 
 # Map of state names to integers
 STATE_TO_IDX = {
-    'open'  : 0,
-    'closed': 1,
-    'locked': 2,
+    "open": 0,
+    "closed": 1,
+    "locked": 2,
 }
 
 # Map of agent direction indices to vectors
@@ -70,6 +74,7 @@ DIR_TO_VEC = [
     np.array((0, -1)),
 ]
 
+
 class WorldObj:
     """
     Base class for grid world objects
@@ -119,28 +124,28 @@ class WorldObj:
         obj_type = IDX_TO_OBJECT[type_idx]
         color = IDX_TO_COLOR[color_idx]
 
-        if obj_type == 'empty' or obj_type == 'unseen':
+        if obj_type == "empty" or obj_type == "unseen":
             return None
 
         # State, 0: open, 1: closed, 2: locked
         is_open = state == 0
         is_locked = state == 2
 
-        if obj_type == 'wall':
+        if obj_type == "wall":
             v = Wall(color)
-        elif obj_type == 'floor':
+        elif obj_type == "floor":
             v = Floor(color)
-        elif obj_type == 'ball':
+        elif obj_type == "ball":
             v = Ball(color)
-        elif obj_type == 'key':
+        elif obj_type == "key":
             v = Key(color)
-        elif obj_type == 'box':
+        elif obj_type == "box":
             v = Box(color)
-        elif obj_type == 'door':
+        elif obj_type == "door":
             v = Door(color, is_open, is_locked)
-        elif obj_type == 'goal':
+        elif obj_type == "goal":
             v = Goal()
-        elif obj_type == 'lava':
+        elif obj_type == "lava":
             v = Lava()
         else:
             assert False, "unknown object type in decode '%s'" % obj_type
@@ -151,9 +156,10 @@ class WorldObj:
         """Draw this object with the given renderer"""
         raise NotImplementedError
 
+
 class Goal(WorldObj):
     def __init__(self):
-        super().__init__('goal', 'green')
+        super().__init__("goal", "green")
 
     def can_overlap(self):
         return True
@@ -161,13 +167,14 @@ class Goal(WorldObj):
     def render(self, img):
         fill_coords(img, point_in_rect(0, 1, 0, 1), COLORS[self.color])
 
+
 class Floor(WorldObj):
     """
     Colored floor tile the agent can walk over
     """
 
-    def __init__(self, color='blue'):
-        super().__init__('floor', color)
+    def __init__(self, color="blue"):
+        super().__init__("floor", color)
 
     def can_overlap(self):
         return True
@@ -180,7 +187,7 @@ class Floor(WorldObj):
 
 class Lava(WorldObj):
     def __init__(self):
-        super().__init__('lava', 'red')
+        super().__init__("lava", "red")
 
     def can_overlap(self):
         return True
@@ -195,14 +202,15 @@ class Lava(WorldObj):
         for i in range(3):
             ylo = 0.3 + 0.2 * i
             yhi = 0.4 + 0.2 * i
-            fill_coords(img, point_in_line(0.1, ylo, 0.3, yhi, r=0.03), (0,0,0))
-            fill_coords(img, point_in_line(0.3, yhi, 0.5, ylo, r=0.03), (0,0,0))
-            fill_coords(img, point_in_line(0.5, ylo, 0.7, yhi, r=0.03), (0,0,0))
-            fill_coords(img, point_in_line(0.7, yhi, 0.9, ylo, r=0.03), (0,0,0))
+            fill_coords(img, point_in_line(0.1, ylo, 0.3, yhi, r=0.03), (0, 0, 0))
+            fill_coords(img, point_in_line(0.3, yhi, 0.5, ylo, r=0.03), (0, 0, 0))
+            fill_coords(img, point_in_line(0.5, ylo, 0.7, yhi, r=0.03), (0, 0, 0))
+            fill_coords(img, point_in_line(0.7, yhi, 0.9, ylo, r=0.03), (0, 0, 0))
+
 
 class Wall(WorldObj):
-    def __init__(self, color='grey'):
-        super().__init__('wall', color)
+    def __init__(self, color="grey"):
+        super().__init__("wall", color)
 
     def see_behind(self):
         return False
@@ -210,9 +218,10 @@ class Wall(WorldObj):
     def render(self, img):
         fill_coords(img, point_in_rect(0, 1, 0, 1), COLORS[self.color])
 
+
 class Door(WorldObj):
     def __init__(self, color, is_open=False, is_locked=False):
-        super().__init__('door', color)
+        super().__init__("door", color)
         self.is_open = is_open
         self.is_locked = is_locked
 
@@ -253,7 +262,7 @@ class Door(WorldObj):
 
         if self.is_open:
             fill_coords(img, point_in_rect(0.88, 1.00, 0.00, 1.00), c)
-            fill_coords(img, point_in_rect(0.92, 0.96, 0.04, 0.96), (0,0,0))
+            fill_coords(img, point_in_rect(0.92, 0.96, 0.04, 0.96), (0, 0, 0))
             return
 
         # Door frame and door
@@ -265,16 +274,17 @@ class Door(WorldObj):
             fill_coords(img, point_in_rect(0.52, 0.75, 0.50, 0.56), c)
         else:
             fill_coords(img, point_in_rect(0.00, 1.00, 0.00, 1.00), c)
-            fill_coords(img, point_in_rect(0.04, 0.96, 0.04, 0.96), (0,0,0))
+            fill_coords(img, point_in_rect(0.04, 0.96, 0.04, 0.96), (0, 0, 0))
             fill_coords(img, point_in_rect(0.08, 0.92, 0.08, 0.92), c)
-            fill_coords(img, point_in_rect(0.12, 0.88, 0.12, 0.88), (0,0,0))
+            fill_coords(img, point_in_rect(0.12, 0.88, 0.12, 0.88), (0, 0, 0))
 
             # Draw door handle
             fill_coords(img, point_in_circle(cx=0.75, cy=0.50, r=0.08), c)
 
+
 class Key(WorldObj):
-    def __init__(self, color='blue'):
-        super(Key, self).__init__('key', color)
+    def __init__(self, color="blue"):
+        super().__init__("key", color)
 
     def can_pickup(self):
         return True
@@ -291,11 +301,12 @@ class Key(WorldObj):
 
         # Ring
         fill_coords(img, point_in_circle(cx=0.56, cy=0.28, r=0.190), c)
-        fill_coords(img, point_in_circle(cx=0.56, cy=0.28, r=0.064), (0,0,0))
+        fill_coords(img, point_in_circle(cx=0.56, cy=0.28, r=0.064), (0, 0, 0))
+
 
 class Ball(WorldObj):
-    def __init__(self, color='blue'):
-        super(Ball, self).__init__('ball', color)
+    def __init__(self, color="blue"):
+        super().__init__("ball", color)
 
     def can_pickup(self):
         return True
@@ -303,9 +314,10 @@ class Ball(WorldObj):
     def render(self, img):
         fill_coords(img, point_in_circle(0.5, 0.5, 0.31), COLORS[self.color])
 
+
 class Box(WorldObj):
     def __init__(self, color, contains=None):
-        super(Box, self).__init__('box', color)
+        super().__init__("box", color)
         self.contains = contains
 
     def can_pickup(self):
@@ -316,7 +328,7 @@ class Box(WorldObj):
 
         # Outline
         fill_coords(img, point_in_rect(0.12, 0.88, 0.12, 0.88), c)
-        fill_coords(img, point_in_rect(0.18, 0.82, 0.18, 0.82), (0,0,0))
+        fill_coords(img, point_in_rect(0.18, 0.82, 0.18, 0.82), (0, 0, 0))
 
         # Horizontal slit
         fill_coords(img, point_in_rect(0.16, 0.84, 0.47, 0.53), c)
@@ -326,6 +338,7 @@ class Box(WorldObj):
         env.grid.set(*pos, self.contains)
         return True
 
+
 class Grid:
     """
     Represent a grid and operations on it
@@ -359,7 +372,7 @@ class Grid:
         return False
 
     def __eq__(self, other):
-        grid1  = self.encode()
+        grid1 = self.encode()
         grid2 = other.encode()
         return np.array_equal(grid2, grid1)
 
@@ -368,6 +381,7 @@ class Grid:
 
     def copy(self):
         from copy import deepcopy
+
         return deepcopy(self)
 
     def set(self, i, j, v):
@@ -394,9 +408,9 @@ class Grid:
 
     def wall_rect(self, x, y, w, h):
         self.horz_wall(x, y, w)
-        self.horz_wall(x, y+h-1, w)
+        self.horz_wall(x, y + h - 1, w)
         self.vert_wall(x, y, h)
-        self.vert_wall(x+w-1, y, h)
+        self.vert_wall(x + w - 1, y, h)
 
     def rotate_left(self):
         """
@@ -424,8 +438,7 @@ class Grid:
                 x = topX + i
                 y = topY + j
 
-                if x >= 0 and x < self.width and \
-                   y >= 0 and y < self.height:
+                if x >= 0 and x < self.width and y >= 0 and y < self.height:
                     v = self.get(x, y)
                 else:
                     v = Wall()
@@ -436,12 +449,7 @@ class Grid:
 
     @classmethod
     def render_tile(
-        cls,
-        obj,
-        agent_dir=None,
-        highlight=False,
-        tile_size=TILE_PIXELS,
-        subdivs=3
+        cls, obj, agent_dir=None, highlight=False, tile_size=TILE_PIXELS, subdivs=3
     ):
         """
         Render a tile and cache the result
@@ -454,13 +462,15 @@ class Grid:
         if key in cls.tile_cache:
             return cls.tile_cache[key]
 
-        img = np.zeros(shape=(tile_size * subdivs, tile_size * subdivs, 3), dtype=np.uint8)
+        img = np.zeros(
+            shape=(tile_size * subdivs, tile_size * subdivs, 3), dtype=np.uint8
+        )
 
         # Draw the grid lines (top and left edges)
         fill_coords(img, point_in_rect(0, 0.031, 0, 1), (100, 100, 100))
         fill_coords(img, point_in_rect(0, 1, 0, 0.031), (100, 100, 100))
 
-        if obj != None:
+        if obj is not None:
             obj.render(img)
 
         # Overlay the agent on top
@@ -472,7 +482,7 @@ class Grid:
             )
 
             # Rotate the agent based on its direction
-            tri_fn = rotate_fn(tri_fn, cx=0.5, cy=0.5, theta=0.5*math.pi*agent_dir)
+            tri_fn = rotate_fn(tri_fn, cx=0.5, cy=0.5, theta=0.5 * math.pi * agent_dir)
             fill_coords(img, tri_fn, (255, 0, 0))
 
         # Highlight the cell if needed
@@ -487,13 +497,7 @@ class Grid:
 
         return img
 
-    def render(
-        self,
-        tile_size,
-        agent_pos=None,
-        agent_dir=None,
-        highlight_mask=None
-    ):
+    def render(self, tile_size, agent_pos=None, agent_dir=None, highlight_mask=None):
         """
         Render this grid at a given scale
         :param r: target renderer object
@@ -519,13 +523,13 @@ class Grid:
                     cell,
                     agent_dir=agent_dir if agent_here else None,
                     highlight=highlight_mask[i, j],
-                    tile_size=tile_size
+                    tile_size=tile_size,
                 )
 
                 ymin = j * tile_size
-                ymax = (j+1) * tile_size
+                ymax = (j + 1) * tile_size
                 xmin = i * tile_size
-                xmax = (i+1) * tile_size
+                xmax = (i + 1) * tile_size
                 img[ymin:ymax, xmin:xmax, :] = tile_img
 
         return img
@@ -538,7 +542,7 @@ class Grid:
         if vis_mask is None:
             vis_mask = np.ones((self.width, self.height), dtype=bool)
 
-        array = np.zeros((self.width, self.height, 3), dtype='uint8')
+        array = np.zeros((self.width, self.height, 3), dtype="uint8")
 
         for i in range(self.width):
             for j in range(self.height):
@@ -546,7 +550,7 @@ class Grid:
                     v = self.get(i, j)
 
                     if v is None:
-                        array[i, j, 0] = OBJECT_TO_IDX['empty']
+                        array[i, j, 0] = OBJECT_TO_IDX["empty"]
                         array[i, j, 1] = 0
                         array[i, j, 2] = 0
 
@@ -572,7 +576,7 @@ class Grid:
                 type_idx, color_idx, state = array[i, j]
                 v = WorldObj.decode(type_idx, color_idx, state)
                 grid.set(i, j, v)
-                vis_mask[i, j] = (type_idx != OBJECT_TO_IDX['unseen'])
+                vis_mask[i, j] = type_idx != OBJECT_TO_IDX["unseen"]
 
         return grid, vis_mask
 
@@ -582,7 +586,7 @@ class Grid:
         mask[agent_pos[0], agent_pos[1]] = True
 
         for j in reversed(range(0, grid.height)):
-            for i in range(0, grid.width-1):
+            for i in range(0, grid.width - 1):
                 if not mask[i, j]:
                     continue
 
@@ -590,10 +594,10 @@ class Grid:
                 if cell and not cell.see_behind():
                     continue
 
-                mask[i+1, j] = True
+                mask[i + 1, j] = True
                 if j > 0:
-                    mask[i+1, j-1] = True
-                    mask[i, j-1] = True
+                    mask[i + 1, j - 1] = True
+                    mask[i, j - 1] = True
 
             for i in reversed(range(1, grid.width)):
                 if not mask[i, j]:
@@ -603,10 +607,10 @@ class Grid:
                 if cell and not cell.see_behind():
                     continue
 
-                mask[i-1, j] = True
+                mask[i - 1, j] = True
                 if j > 0:
-                    mask[i-1, j-1] = True
-                    mask[i, j-1] = True
+                    mask[i - 1, j - 1] = True
+                    mask[i, j - 1] = True
 
         for j in range(0, grid.height):
             for i in range(0, grid.width):
@@ -615,15 +619,13 @@ class Grid:
 
         return mask
 
+
 class MiniGridEnv(gym.Env):
     """
     2D grid world game environment
     """
 
-    metadata = {
-        'render.modes': ['human', 'rgb_array'],
-        'video.frames_per_second' : 10
-    }
+    metadata = {"render.modes": ["human", "rgb_array"], "video.frames_per_second": 10}
 
     # Enumeration of possible actions
     class Actions(IntEnum):
@@ -650,11 +652,11 @@ class MiniGridEnv(gym.Env):
         max_steps=100,
         see_through_walls=False,
         seed=1337,
-        agent_view_size=7
+        agent_view_size=7,
     ):
         # Can't set both grid_size and width/height
         if grid_size:
-            assert width == None and height == None
+            assert width is None and height is None
             width = grid_size
             height = grid_size
 
@@ -675,11 +677,9 @@ class MiniGridEnv(gym.Env):
             low=0,
             high=255,
             shape=(self.agent_view_size, self.agent_view_size, 3),
-            dtype='uint8'
+            dtype="uint8",
         )
-        self.observation_space = spaces.Dict({
-            'image': self.observation_space
-        })
+        self.observation_space = spaces.Dict({"image": self.observation_space})
 
         # Range of possible rewards
         self.reward_range = (0, 1)
@@ -744,7 +744,7 @@ class MiniGridEnv(gym.Env):
 
         to_encode = [self.grid.encode().tolist(), self.agent_pos, self.agent_dir]
         for item in to_encode:
-            sample_hash.update(str(item).encode('utf8'))
+            sample_hash.update(str(item).encode("utf8"))
 
         return sample_hash.hexdigest()[:size]
 
@@ -761,28 +761,20 @@ class MiniGridEnv(gym.Env):
 
         # Map of object types to short string
         OBJECT_TO_STR = {
-            'wall'          : 'W',
-            'floor'         : 'F',
-            'door'          : 'D',
-            'key'           : 'K',
-            'ball'          : 'A',
-            'box'           : 'B',
-            'goal'          : 'G',
-            'lava'          : 'V',
+            "wall": "W",
+            "floor": "F",
+            "door": "D",
+            "key": "K",
+            "ball": "A",
+            "box": "B",
+            "goal": "G",
+            "lava": "V",
         }
 
-        # Short string for opened door
-        OPENDED_DOOR_IDS = '_'
-
         # Map agent's direction to short string
-        AGENT_DIR_TO_STR = {
-            0: '>',
-            1: 'V',
-            2: '<',
-            3: '^'
-        }
+        AGENT_DIR_TO_STR = {0: ">", 1: "V", 2: "<", 3: "^"}
 
-        str = ''
+        str = ""
 
         for j in range(self.grid.height):
 
@@ -793,23 +785,23 @@ class MiniGridEnv(gym.Env):
 
                 c = self.grid.get(i, j)
 
-                if c == None:
-                    str += '  '
+                if c is None:
+                    str += "  "
                     continue
 
-                if c.type == 'door':
+                if c.type == "door":
                     if c.is_open:
-                        str += '__'
+                        str += "__"
                     elif c.is_locked:
-                        str += 'L' + c.color[0].upper()
+                        str += "L" + c.color[0].upper()
                     else:
-                        str += 'D' + c.color[0].upper()
+                        str += "D" + c.color[0].upper()
                     continue
 
                 str += OBJECT_TO_STR[c.type] + c.color[0].upper()
 
             if j < self.grid.height - 1:
-                str += '\n'
+                str += "\n"
 
         return str
 
@@ -842,7 +834,7 @@ class MiniGridEnv(gym.Env):
         Generate random boolean value
         """
 
-        return (self.np_random.randint(0, 2) == 0)
+        return self.np_random.randint(0, 2) == 0
 
     def _rand_elem(self, iterable):
         """
@@ -884,16 +876,10 @@ class MiniGridEnv(gym.Env):
 
         return (
             self.np_random.randint(xLow, xHigh),
-            self.np_random.randint(yLow, yHigh)
+            self.np_random.randint(yLow, yHigh),
         )
 
-    def place_obj(self,
-        obj,
-        top=None,
-        size=None,
-        reject_fn=None,
-        max_tries=math.inf
-    ):
+    def place_obj(self, obj, top=None, size=None, reject_fn=None, max_tries=math.inf):
         """
         Place an object at an empty position in the grid
 
@@ -916,17 +902,19 @@ class MiniGridEnv(gym.Env):
             # This is to handle with rare cases where rejection sampling
             # gets stuck in an infinite loop
             if num_tries > max_tries:
-                raise RecursionError('rejection sampling failed in place_obj')
+                raise RecursionError("rejection sampling failed in place_obj")
 
             num_tries += 1
 
-            pos = np.array((
-                self._rand_int(top[0], min(top[0] + size[0], self.grid.width)),
-                self._rand_int(top[1], min(top[1] + size[1], self.grid.height))
-            ))
+            pos = np.array(
+                (
+                    self._rand_int(top[0], min(top[0] + size[0], self.grid.width)),
+                    self._rand_int(top[1], min(top[1] + size[1], self.grid.height)),
+                )
+            )
 
             # Don't place the object on top of another object
-            if self.grid.get(*pos) != None:
+            if self.grid.get(*pos) is not None:
                 continue
 
             # Don't place the object where the agent is
@@ -956,13 +944,7 @@ class MiniGridEnv(gym.Env):
         obj.init_pos = (i, j)
         obj.cur_pos = (i, j)
 
-    def place_agent(
-        self,
-        top=None,
-        size=None,
-        rand_dir=True,
-        max_tries=math.inf
-    ):
+    def place_agent(self, top=None, size=None, rand_dir=True, max_tries=math.inf):
         """
         Set the agent's starting point at an empty position in the grid
         """
@@ -1017,16 +999,16 @@ class MiniGridEnv(gym.Env):
         # Compute the absolute coordinates of the top-left view corner
         sz = self.agent_view_size
         hs = self.agent_view_size // 2
-        tx = ax + (dx * (sz-1)) - (rx * hs)
-        ty = ay + (dy * (sz-1)) - (ry * hs)
+        tx = ax + (dx * (sz - 1)) - (rx * hs)
+        ty = ay + (dy * (sz - 1)) - (ry * hs)
 
         lx = i - tx
         ly = j - ty
 
         # Project the coordinates of the object relative to the top-left
         # corner onto the agent's own coordinate system
-        vx = (rx*lx + ry*ly)
-        vy = -(dx*lx + dy*ly)
+        vx = rx * lx + ry * ly
+        vy = -(dx * lx + dy * ly)
 
         return vx, vy
 
@@ -1090,7 +1072,7 @@ class MiniGridEnv(gym.Env):
         vx, vy = coordinates
 
         obs = self.gen_obs()
-        obs_grid, _ = Grid.decode(obs['image'])
+        obs_grid, _ = Grid.decode(obs["image"])
         obs_cell = obs_grid.get(vx, vy)
         world_cell = self.grid.get(x, y)
 
@@ -1120,12 +1102,12 @@ class MiniGridEnv(gym.Env):
 
         # Move forward
         elif action == self.actions.forward:
-            if fwd_cell == None or fwd_cell.can_overlap():
+            if fwd_cell is None or fwd_cell.can_overlap():
                 self.agent_pos = fwd_pos
-            if fwd_cell != None and fwd_cell.type == 'goal':
+            if fwd_cell is not None and fwd_cell.type == "goal":
                 done = True
                 reward = self._reward()
-            if fwd_cell != None and fwd_cell.type == 'lava':
+            if fwd_cell is not None and fwd_cell.type == "lava":
                 done = True
 
         # Pick up an object
@@ -1179,7 +1161,9 @@ class MiniGridEnv(gym.Env):
         # Process occluders and visibility
         # Note that this incurs some performance cost
         if not self.see_through_walls:
-            vis_mask = grid.process_vis(agent_pos=(self.agent_view_size // 2 , self.agent_view_size - 1))
+            vis_mask = grid.process_vis(
+                agent_pos=(self.agent_view_size // 2, self.agent_view_size - 1)
+            )
         else:
             vis_mask = np.ones(shape=(grid.width, grid.height), dtype=bool)
 
@@ -1204,21 +1188,19 @@ class MiniGridEnv(gym.Env):
         # Encode the partially observable view into a numpy array
         image = grid.encode(vis_mask)
 
-        assert hasattr(self, 'mission'), "environments must define a textual mission string"
+        assert hasattr(
+            self, "mission"
+        ), "environments must define a textual mission string"
 
         # Observations are dictionaries containing:
         # - an image (partially observable view of the environment)
         # - the agent's direction/orientation (acting as a compass)
         # - a textual mission string (instructions for the agent)
-        obs = {
-            'image': image,
-            'direction': self.agent_dir,
-            'mission': self.mission
-        }
+        obs = {"image": image, "direction": self.agent_dir, "mission": self.mission}
 
         return obs
 
-    def get_obs_render(self, obs, tile_size=TILE_PIXELS//2):
+    def get_obs_render(self, obs, tile_size=TILE_PIXELS // 2):
         """
         Render an agent observation for visualization
         """
@@ -1230,12 +1212,12 @@ class MiniGridEnv(gym.Env):
             tile_size,
             agent_pos=(self.agent_view_size // 2, self.agent_view_size - 1),
             agent_dir=3,
-            highlight_mask=vis_mask
+            highlight_mask=vis_mask,
         )
 
         return img
 
-    def render(self, mode='human', close=False, highlight=True, tile_size=TILE_PIXELS):
+    def render(self, mode="human", close=False, highlight=True, tile_size=TILE_PIXELS):
         """
         Render the whole-grid human view
         """
@@ -1245,9 +1227,10 @@ class MiniGridEnv(gym.Env):
                 self.window.close()
             return
 
-        if mode == 'human' and not self.window:
+        if mode == "human" and not self.window:
             import gym_minigrid.window
-            self.window = gym_minigrid.window.Window('gym_minigrid')
+
+            self.window = gym_minigrid.window.Window("gym_minigrid")
             self.window.show(block=False)
 
         # Compute which cells are visible to the agent
@@ -1257,7 +1240,11 @@ class MiniGridEnv(gym.Env):
         # of the agent's view area
         f_vec = self.dir_vec
         r_vec = self.right_vec
-        top_left = self.agent_pos + f_vec * (self.agent_view_size-1) - r_vec * (self.agent_view_size // 2)
+        top_left = (
+            self.agent_pos
+            + f_vec * (self.agent_view_size - 1)
+            - r_vec * (self.agent_view_size // 2)
+        )
 
         # Mask of which cells to highlight
         highlight_mask = np.zeros(shape=(self.width, self.height), dtype=bool)
@@ -1285,10 +1272,10 @@ class MiniGridEnv(gym.Env):
             tile_size,
             self.agent_pos,
             self.agent_dir,
-            highlight_mask=highlight_mask if highlight else None
+            highlight_mask=highlight_mask if highlight else None,
         )
 
-        if mode == 'human':
+        if mode == "human":
             self.window.set_caption(self.mission)
             self.window.show_img(img)
 

+ 3 - 10
gym_minigrid/register.py

@@ -2,20 +2,13 @@ from gym.envs.registration import register as gym_register
 
 env_list = []
 
-def register(
-    id,
-    entry_point,
-    reward_threshold=0.95
-):
+
+def register(id, entry_point, reward_threshold=0.95):
     assert id.startswith("MiniGrid-")
     assert id not in env_list
 
     # Register the environment with OpenAI gym
-    gym_register(
-        id=id,
-        entry_point=entry_point,
-        reward_threshold=reward_threshold
-    )
+    gym_register(id=id, entry_point=entry_point, reward_threshold=reward_threshold)
 
     # Add the environment to the set
     env_list.append(id)

+ 15 - 2
gym_minigrid/rendering.py

@@ -1,6 +1,8 @@
 import math
+
 import numpy as np
 
+
 def downsample(img, factor):
     """
     Downsample an image along both dimensions by some factor
@@ -9,12 +11,15 @@ def downsample(img, factor):
     assert img.shape[0] % factor == 0
     assert img.shape[1] % factor == 0
 
-    img = img.reshape([img.shape[0]//factor, factor, img.shape[1]//factor, factor, 3])
+    img = img.reshape(
+        [img.shape[0] // factor, factor, img.shape[1] // factor, factor, 3]
+    )
     img = img.mean(axis=3)
     img = img.mean(axis=1)
 
     return img
 
+
 def fill_coords(img, fn, color):
     """
     Fill pixels of an image with coordinates matching a filter function
@@ -29,6 +34,7 @@ def fill_coords(img, fn, color):
 
     return img
 
+
 def rotate_fn(fin, cx, cy, theta):
     def fout(x, y):
         x = x - cx
@@ -41,6 +47,7 @@ def rotate_fn(fin, cx, cy, theta):
 
     return fout
 
+
 def point_in_line(x0, y0, x1, y1, r):
     p0 = np.array([x0, y0])
     p1 = np.array([x1, y1])
@@ -71,16 +78,21 @@ def point_in_line(x0, y0, x1, y1, r):
 
     return fn
 
+
 def point_in_circle(cx, cy, r):
     def fn(x, y):
-        return (x-cx)*(x-cx) + (y-cy)*(y-cy) <= r * r
+        return (x - cx) * (x - cx) + (y - cy) * (y - cy) <= r * r
+
     return fn
 
+
 def point_in_rect(xmin, xmax, ymin, ymax):
     def fn(x, y):
         return x >= xmin and x <= xmax and y >= ymin and y <= ymax
+
     return fn
 
+
 def point_in_triangle(a, b, c):
     a = np.array(a)
     b = np.array(b)
@@ -108,6 +120,7 @@ def point_in_triangle(a, b, c):
 
     return fn
 
+
 def highlight_img(img, color=(255, 255, 255), alpha=0.30):
     """
     Add highlighting to an image

+ 42 - 47
gym_minigrid/roomgrid.py

@@ -1,4 +1,5 @@
-from .minigrid import *
+from gym_minigrid.minigrid import COLOR_NAMES, Ball, Box, Door, Grid, Key, MiniGridEnv
+
 
 def reject_next_to(env, pos):
     """
@@ -11,12 +12,9 @@ def reject_next_to(env, pos):
     d = abs(sx - x) + abs(sy - y)
     return d < 2
 
+
 class Room:
-    def __init__(
-        self,
-        top,
-        size
-    ):
+    def __init__(self, top, size):
         # Top-left corner and size (tuples)
         self.top = top
         self.size = size
@@ -39,10 +37,7 @@ class Room:
     def rand_pos(self, env):
         topX, topY = self.top
         sizeX, sizeY = self.size
-        return env._randPos(
-            topX + 1, topX + sizeX - 1,
-            topY + 1, topY + sizeY - 1
-        )
+        return env._randPos(topX + 1, topX + sizeX - 1, topY + 1, topY + sizeY - 1)
 
     def pos_inside(self, x, y):
         """
@@ -60,6 +55,7 @@ class Room:
 
         return True
 
+
 class RoomGrid(MiniGridEnv):
     """
     Environment with multiple rooms and random objects.
@@ -73,7 +69,7 @@ class RoomGrid(MiniGridEnv):
         num_cols=3,
         max_steps=100,
         seed=0,
-        agent_view_size=7
+        agent_view_size=7,
     ):
         assert room_size > 0
         assert room_size >= 3
@@ -87,7 +83,7 @@ class RoomGrid(MiniGridEnv):
         width = (room_size - 1) * num_cols + 1
 
         # By default, this environment has no mission
-        self.mission = ''
+        self.mission = ""
 
         super().__init__(
             width=width,
@@ -95,7 +91,7 @@ class RoomGrid(MiniGridEnv):
             max_steps=max_steps,
             see_through_walls=False,
             seed=seed,
-            agent_view_size=agent_view_size
+            agent_view_size=agent_view_size,
         )
 
     def room_from_pos(self, x, y):
@@ -104,8 +100,8 @@ class RoomGrid(MiniGridEnv):
         assert x >= 0
         assert y >= 0
 
-        i = x // (self.room_size-1)
-        j = y // (self.room_size-1)
+        i = x // (self.room_size - 1)
+        j = y // (self.room_size - 1)
 
         assert i < self.num_cols
         assert j < self.num_rows
@@ -130,8 +126,8 @@ class RoomGrid(MiniGridEnv):
             # For each column of rooms
             for i in range(0, self.num_cols):
                 room = Room(
-                    (i * (self.room_size-1), j * (self.room_size-1)),
-                    (self.room_size, self.room_size)
+                    (i * (self.room_size - 1), j * (self.room_size - 1)),
+                    (self.room_size, self.room_size),
                 )
                 row.append(room)
 
@@ -147,26 +143,29 @@ class RoomGrid(MiniGridEnv):
                 room = self.room_grid[j][i]
 
                 x_l, y_l = (room.top[0] + 1, room.top[1] + 1)
-                x_m, y_m = (room.top[0] + room.size[0] - 1, room.top[1] + room.size[1] - 1)
+                x_m, y_m = (
+                    room.top[0] + room.size[0] - 1,
+                    room.top[1] + room.size[1] - 1,
+                )
 
                 # Door positions, order is right, down, left, up
                 if i < self.num_cols - 1:
-                    room.neighbors[0] = self.room_grid[j][i+1]
+                    room.neighbors[0] = self.room_grid[j][i + 1]
                     room.door_pos[0] = (x_m, self._rand_int(y_l, y_m))
                 if j < self.num_rows - 1:
-                    room.neighbors[1] = self.room_grid[j+1][i]
+                    room.neighbors[1] = self.room_grid[j + 1][i]
                     room.door_pos[1] = (self._rand_int(x_l, x_m), y_m)
                 if i > 0:
-                    room.neighbors[2] = self.room_grid[j][i-1]
+                    room.neighbors[2] = self.room_grid[j][i - 1]
                     room.door_pos[2] = room.neighbors[2].door_pos[0]
                 if j > 0:
-                    room.neighbors[3] = self.room_grid[j-1][i]
+                    room.neighbors[3] = self.room_grid[j - 1][i]
                     room.door_pos[3] = room.neighbors[3].door_pos[1]
 
         # The agent starts in the middle, facing right
         self.agent_pos = (
-            (self.num_cols // 2) * (self.room_size-1) + (self.room_size // 2),
-            (self.num_rows // 2) * (self.room_size-1) + (self.room_size // 2)
+            (self.num_cols // 2) * (self.room_size - 1) + (self.room_size // 2),
+            (self.num_rows // 2) * (self.room_size - 1) + (self.room_size // 2),
         )
         self.agent_dir = 0
 
@@ -178,11 +177,7 @@ class RoomGrid(MiniGridEnv):
         room = self.get_room(i, j)
 
         pos = self.place_obj(
-            obj,
-            room.top,
-            room.size,
-            reject_fn=reject_next_to,
-            max_tries=1000
+            obj, room.top, room.size, reject_fn=reject_next_to, max_tries=1000
         )
 
         room.objs.append(obj)
@@ -194,19 +189,19 @@ class RoomGrid(MiniGridEnv):
         Add a new object to room (i, j)
         """
 
-        if kind == None:
-            kind = self._rand_elem(['key', 'ball', 'box'])
+        if kind is None:
+            kind = self._rand_elem(["key", "ball", "box"])
 
-        if color == None:
+        if color is None:
             color = self._rand_color()
 
         # TODO: we probably want to add an Object.make helper function
-        assert kind in ['key', 'ball', 'box']
-        if kind == 'key':
+        assert kind in ["key", "ball", "box"]
+        if kind == "key":
             obj = Key(color)
-        elif kind == 'ball':
+        elif kind == "ball":
             obj = Ball(color)
-        elif kind == 'box':
+        elif kind == "box":
             obj = Box(color)
 
         return self.place_in_room(i, j, obj)
@@ -218,7 +213,7 @@ class RoomGrid(MiniGridEnv):
 
         room = self.get_room(i, j)
 
-        if door_idx == None:
+        if door_idx is None:
             # Need to make sure that there is a neighbor along this wall
             # and that there is not already a door
             while True:
@@ -226,7 +221,7 @@ class RoomGrid(MiniGridEnv):
                 if room.neighbors[door_idx] and room.doors[door_idx] is None:
                     break
 
-        if color == None:
+        if color is None:
             color = self._rand_color()
 
         if locked is None:
@@ -243,7 +238,7 @@ class RoomGrid(MiniGridEnv):
 
         neighbor = room.neighbors[door_idx]
         room.doors[door_idx] = door
-        neighbor.doors[(door_idx+2) % 4] = door
+        neighbor.doors[(door_idx + 2) % 4] = door
 
         return door, pos
 
@@ -281,16 +276,16 @@ class RoomGrid(MiniGridEnv):
 
         # Mark the rooms as connected
         room.doors[wall_idx] = True
-        neighbor.doors[(wall_idx+2) % 4] = True
+        neighbor.doors[(wall_idx + 2) % 4] = True
 
     def place_agent(self, i=None, j=None, rand_dir=True):
         """
         Place the agent in a room
         """
 
-        if i == None:
+        if i is None:
             i = self._rand_int(0, self.num_cols)
-        if j == None:
+        if j is None:
             j = self._rand_int(0, self.num_rows)
 
         room = self.room_grid[j][i]
@@ -299,7 +294,7 @@ class RoomGrid(MiniGridEnv):
         while True:
             super().place_agent(room.top, room.size, rand_dir, max_tries=1000)
             front_cell = self.grid.get(*self.front_pos)
-            if front_cell is None or front_cell.type == 'wall':
+            if front_cell is None or front_cell.type == "wall":
                 break
 
         return self.agent_pos
@@ -333,7 +328,7 @@ class RoomGrid(MiniGridEnv):
             # This is to handle rare situations where random sampling produces
             # a level that cannot be connected, producing in an infinite loop
             if num_itrs > max_itrs:
-                raise RecursionError('connect_all failed')
+                raise RecursionError("connect_all failed")
             num_itrs += 1
 
             # If all rooms are reachable, stop
@@ -377,7 +372,7 @@ class RoomGrid(MiniGridEnv):
 
         while len(dists) < num_distractors:
             color = self._rand_elem(COLOR_NAMES)
-            type = self._rand_elem(['key', 'ball', 'box'])
+            type = self._rand_elem(["key", "ball", "box"])
             obj = (type, color)
 
             if all_unique and obj in objs:
@@ -386,9 +381,9 @@ class RoomGrid(MiniGridEnv):
             # Add the object to a random room if no room specified
             room_i = i
             room_j = j
-            if room_i == None:
+            if room_i is None:
                 room_i = self._rand_int(0, self.num_cols)
-            if room_j == None:
+            if room_j is None:
                 room_j = self._rand_int(0, self.num_rows)
 
             dist, pos = self.add_object(room_i, room_j, *obj)

+ 10 - 12
gym_minigrid/window.py

@@ -1,13 +1,11 @@
-import sys
-import numpy as np
-
 # Only ask users to install matplotlib if they actually need it
 try:
     import matplotlib.pyplot as plt
-except:
-    print('To display the environment in a window, please install matplotlib, eg:')
-    print('pip3 install --user matplotlib')
-    sys.exit(-1)
+except ImportError:
+    raise ImportError(
+        "To display the environment in a window, please install matplotlib, eg: `pip3 install --user matplotlib`"
+    )
+
 
 class Window:
     """
@@ -26,8 +24,8 @@ class Window:
         self.fig.canvas.set_window_title(title)
 
         # Turn off x/y axis numbering/ticks
-        self.ax.xaxis.set_ticks_position('none')
-        self.ax.yaxis.set_ticks_position('none')
+        self.ax.xaxis.set_ticks_position("none")
+        self.ax.yaxis.set_ticks_position("none")
         _ = self.ax.set_xticklabels([])
         _ = self.ax.set_yticklabels([])
 
@@ -37,7 +35,7 @@ class Window:
         def close_handler(evt):
             self.closed = True
 
-        self.fig.canvas.mpl_connect('close_event', close_handler)
+        self.fig.canvas.mpl_connect("close_event", close_handler)
 
     def show_img(self, img):
         """
@@ -47,7 +45,7 @@ class Window:
         # If no image has been shown yet,
         # show the first image of the environment
         if self.imshow_obj is None:
-            self.imshow_obj = self.ax.imshow(img, interpolation='bilinear')
+            self.imshow_obj = self.ax.imshow(img, interpolation="bilinear")
 
         # Update the image data
         self.imshow_obj.set_data(img)
@@ -72,7 +70,7 @@ class Window:
         """
 
         # Keyboard handler
-        self.fig.canvas.mpl_connect('key_press_event', key_handler)
+        self.fig.canvas.mpl_connect("key_press_event", key_handler)
 
     def show(self, block=True):
         """

+ 72 - 72
gym_minigrid/wrappers.py

@@ -2,10 +2,12 @@ import math
 import operator
 from functools import reduce
 
-import numpy as np
 import gym
-from gym import error, spaces, utils
-from .minigrid import OBJECT_TO_IDX, COLOR_TO_IDX, STATE_TO_IDX, Goal
+import numpy as np
+from gym import spaces
+
+from .minigrid import COLOR_TO_IDX, OBJECT_TO_IDX, STATE_TO_IDX, Goal
+
 
 class ReseedWrapper(gym.core.Wrapper):
     """
@@ -29,6 +31,7 @@ class ReseedWrapper(gym.core.Wrapper):
         obs, reward, done, info = self.env.step(action)
         return obs, reward, done, info
 
+
 class ActionBonus(gym.core.Wrapper):
     """
     Wrapper which adds an exploration bonus.
@@ -63,6 +66,7 @@ class ActionBonus(gym.core.Wrapper):
     def reset(self, **kwargs):
         return self.env.reset(**kwargs)
 
+
 class StateBonus(gym.core.Wrapper):
     """
     Adds an exploration bonus based on which positions
@@ -79,7 +83,7 @@ class StateBonus(gym.core.Wrapper):
         # Tuple based on which we index the counts
         # We use the position after an update
         env = self.unwrapped
-        tup = (tuple(env.agent_pos))
+        tup = tuple(env.agent_pos)
 
         # Get the count for this key
         pre_count = 0
@@ -98,6 +102,7 @@ class StateBonus(gym.core.Wrapper):
     def reset(self, **kwargs):
         return self.env.reset(**kwargs)
 
+
 class ImgObsWrapper(gym.core.ObservationWrapper):
     """
     Use the image as the only observation output, no language/mission.
@@ -105,10 +110,11 @@ class ImgObsWrapper(gym.core.ObservationWrapper):
 
     def __init__(self, env):
         super().__init__(env)
-        self.observation_space = env.observation_space.spaces['image']
+        self.observation_space = env.observation_space.spaces["image"]
 
     def observation(self, obs):
-        return obs['image']
+        return obs["image"]
+
 
 class OneHotPartialObsWrapper(gym.core.ObservationWrapper):
     """
@@ -121,21 +127,18 @@ class OneHotPartialObsWrapper(gym.core.ObservationWrapper):
 
         self.tile_size = tile_size
 
-        obs_shape = env.observation_space['image'].shape
+        obs_shape = env.observation_space["image"].shape
 
         # Number of bits per cell
         num_bits = len(OBJECT_TO_IDX) + len(COLOR_TO_IDX) + len(STATE_TO_IDX)
 
         self.observation_space.spaces["image"] = spaces.Box(
-            low=0,
-            high=255,
-            shape=(obs_shape[0], obs_shape[1], num_bits),
-            dtype='uint8'
+            low=0, high=255, shape=(obs_shape[0], obs_shape[1], num_bits), dtype="uint8"
         )
 
     def observation(self, obs):
-        img = obs['image']
-        out = np.zeros(self.observation_space.spaces['image'].shape, dtype='uint8')
+        img = obs["image"]
+        out = np.zeros(self.observation_space.spaces["image"].shape, dtype="uint8")
 
         for i in range(img.shape[0]):
             for j in range(img.shape[1]):
@@ -147,10 +150,8 @@ class OneHotPartialObsWrapper(gym.core.ObservationWrapper):
                 out[i, j, len(OBJECT_TO_IDX) + color] = 1
                 out[i, j, len(OBJECT_TO_IDX) + len(COLOR_TO_IDX) + state] = 1
 
-        return {
-            **obs,
-            'image': out
-        }
+        return {**obs, "image": out}
+
 
 class RGBImgObsWrapper(gym.core.ObservationWrapper):
     """
@@ -163,26 +164,21 @@ class RGBImgObsWrapper(gym.core.ObservationWrapper):
 
         self.tile_size = tile_size
 
-        self.observation_space.spaces['image'] = spaces.Box(
+        self.observation_space.spaces["image"] = spaces.Box(
             low=0,
             high=255,
             shape=(self.env.width * tile_size, self.env.height * tile_size, 3),
-            dtype='uint8'
+            dtype="uint8",
         )
 
     def observation(self, obs):
         env = self.unwrapped
 
         rgb_img = env.render(
-            mode='rgb_array',
-            highlight=False,
-            tile_size=self.tile_size
+            mode="rgb_array", highlight=False, tile_size=self.tile_size
         )
 
-        return {
-            **obs,
-            'image': rgb_img
-        }
+        return {**obs, "image": rgb_img}
 
 
 class RGBImgPartialObsWrapper(gym.core.ObservationWrapper):
@@ -196,26 +192,21 @@ class RGBImgPartialObsWrapper(gym.core.ObservationWrapper):
 
         self.tile_size = tile_size
 
-        obs_shape = env.observation_space.spaces['image'].shape
-        self.observation_space.spaces['image'] = spaces.Box(
+        obs_shape = env.observation_space.spaces["image"].shape
+        self.observation_space.spaces["image"] = spaces.Box(
             low=0,
             high=255,
             shape=(obs_shape[0] * tile_size, obs_shape[1] * tile_size, 3),
-            dtype='uint8'
+            dtype="uint8",
         )
 
     def observation(self, obs):
         env = self.unwrapped
 
-        rgb_img_partial = env.get_obs_render(
-            obs['image'],
-            tile_size=self.tile_size
-        )
+        rgb_img_partial = env.get_obs_render(obs["image"], tile_size=self.tile_size)
+
+        return {**obs, "image": rgb_img_partial}
 
-        return {
-            **obs,
-            'image': rgb_img_partial
-        }
 
 class FullyObsWrapper(gym.core.ObservationWrapper):
     """
@@ -229,22 +220,18 @@ class FullyObsWrapper(gym.core.ObservationWrapper):
             low=0,
             high=255,
             shape=(self.env.width, self.env.height, 3),  # number of cells
-            dtype='uint8'
+            dtype="uint8",
         )
 
     def observation(self, obs):
         env = self.unwrapped
         full_grid = env.grid.encode()
-        full_grid[env.agent_pos[0]][env.agent_pos[1]] = np.array([
-            OBJECT_TO_IDX['agent'],
-            COLOR_TO_IDX['red'],
-            env.agent_dir
-        ])
+        full_grid[env.agent_pos[0]][env.agent_pos[1]] = np.array(
+            [OBJECT_TO_IDX["agent"], COLOR_TO_IDX["red"], env.agent_dir]
+        )
+
+        return {**obs, "image": full_grid}
 
-        return {
-            **obs,
-            'image': full_grid
-        }
 
 class FlatObsWrapper(gym.core.ObservationWrapper):
     """
@@ -258,36 +245,40 @@ class FlatObsWrapper(gym.core.ObservationWrapper):
         self.maxStrLen = maxStrLen
         self.numCharCodes = 27
 
-        imgSpace = env.observation_space.spaces['image']
+        imgSpace = env.observation_space.spaces["image"]
         imgSize = reduce(operator.mul, imgSpace.shape, 1)
 
         self.observation_space = spaces.Box(
             low=0,
             high=255,
             shape=(imgSize + self.numCharCodes * self.maxStrLen,),
-            dtype='uint8'
+            dtype="uint8",
         )
 
         self.cachedStr = None
         self.cachedArray = None
 
     def observation(self, obs):
-        image = obs['image']
-        mission = obs['mission']
+        image = obs["image"]
+        mission = obs["mission"]
 
         # Cache the last-encoded mission string
         if mission != self.cachedStr:
-            assert len(mission) <= self.maxStrLen, 'mission string too long ({} chars)'.format(len(mission))
+            assert (
+                len(mission) <= self.maxStrLen
+            ), f"mission string too long ({len(mission)} chars)"
             mission = mission.lower()
 
-            strArray = np.zeros(shape=(self.maxStrLen, self.numCharCodes), dtype='float32')
+            strArray = np.zeros(
+                shape=(self.maxStrLen, self.numCharCodes), dtype="float32"
+            )
 
             for idx, ch in enumerate(mission):
-                if ch >= 'a' and ch <= 'z':
-                    chNo = ord(ch) - ord('a')
-                elif ch == ' ':
-                    chNo = ord('z') - ord('a') + 1
-                assert chNo < self.numCharCodes, '%s : %d' % (ch, chNo)
+                if ch >= "a" and ch <= "z":
+                    chNo = ord(ch) - ord("a")
+                elif ch == " ":
+                    chNo = ord("z") - ord("a") + 1
+                assert chNo < self.numCharCodes, "%s : %d" % (ch, chNo)
                 strArray[idx, chNo] = 1
 
             self.cachedStr = mission
@@ -297,6 +288,7 @@ class FlatObsWrapper(gym.core.ObservationWrapper):
 
         return obs
 
+
 class ViewSizeWrapper(gym.core.Wrapper):
     """
     Wrapper to customize the agent field of view size.
@@ -314,16 +306,11 @@ class ViewSizeWrapper(gym.core.Wrapper):
 
         # Compute observation space with specified view size
         observation_space = gym.spaces.Box(
-            low=0,
-            high=255,
-            shape=(agent_view_size, agent_view_size, 3),
-            dtype='uint8'
+            low=0, high=255, shape=(agent_view_size, agent_view_size, 3), dtype="uint8"
         )
 
         # Override the environment's observation space
-        self.observation_space = spaces.Dict({
-            'image': observation_space
-        })
+        self.observation_space = spaces.Dict({"image": observation_space})
 
     def reset(self, **kwargs):
         return self.env.reset(**kwargs)
@@ -331,12 +318,14 @@ class ViewSizeWrapper(gym.core.Wrapper):
     def step(self, action):
         return self.env.step(action)
 
+
 class DirectionObsWrapper(gym.core.ObservationWrapper):
     """
     Provides the slope/angular direction to the goal with the observations as modeled by (y2 - y2 )/( x2 - x1)
     type = {slope , angle}
     """
-    def __init__(self, env,type='slope'):
+
+    def __init__(self, env, type="slope"):
         super().__init__(env)
         self.goal_position = None
         self.type = type
@@ -344,16 +333,27 @@ class DirectionObsWrapper(gym.core.ObservationWrapper):
     def reset(self):
         obs = self.env.reset()
         if not self.goal_position:
-            self.goal_position = [x for x,y in enumerate(self.grid.grid) if isinstance(y,(Goal) ) ]
-            if len(self.goal_position) >= 1: # in case there are multiple goals , needs to be handled for other env types
-                self.goal_position = (int(self.goal_position[0]/self.height) , self.goal_position[0]%self.width)
+            self.goal_position = [
+                x for x, y in enumerate(self.grid.grid) if isinstance(y, (Goal))
+            ]
+            if (
+                len(self.goal_position) >= 1
+            ):  # in case there are multiple goals , needs to be handled for other env types
+                self.goal_position = (
+                    int(self.goal_position[0] / self.height),
+                    self.goal_position[0] % self.width,
+                )
         return obs
 
     def observation(self, obs):
-        slope = np.divide( self.goal_position[1] - self.agent_pos[1] ,  self.goal_position[0] - self.agent_pos[0])
-        obs['goal_direction'] = np.arctan( slope ) if self.type == 'angle' else slope
+        slope = np.divide(
+            self.goal_position[1] - self.agent_pos[1],
+            self.goal_position[0] - self.agent_pos[0],
+        )
+        obs["goal_direction"] = np.arctan(slope) if self.type == "angle" else slope
         return obs
 
+
 class SymbolicObsWrapper(gym.core.ObservationWrapper):
     """
     Fully observable grid with a symbolic state representation.
@@ -379,5 +379,5 @@ class SymbolicObsWrapper(gym.core.ObservationWrapper):
         grid = np.mgrid[:w, :h]
         grid = np.concatenate([grid, objects.reshape(1, w, h)])
         grid = np.transpose(grid, (1, 2, 0))
-        obs['image'] = grid
+        obs["image"] = grid
         return obs

+ 29 - 33
manual_control.py

@@ -1,100 +1,96 @@
 #!/usr/bin/env python3
 
-import time
 import argparse
-import numpy as np
+
 import gym
-import gym_minigrid
-from gym_minigrid.wrappers import *
+
 from gym_minigrid.window import Window
+from gym_minigrid.wrappers import ImgObsWrapper, RGBImgPartialObsWrapper
+
 
 def redraw(img):
     if not args.agent_view:
-        img = env.render('rgb_array', tile_size=args.tile_size)
+        img = env.render("rgb_array", tile_size=args.tile_size)
 
     window.show_img(img)
 
+
 def reset():
     if args.seed != -1:
         env.seed(args.seed)
 
     obs = env.reset()
 
-    if hasattr(env, 'mission'):
-        print('Mission: %s' % env.mission)
+    if hasattr(env, "mission"):
+        print("Mission: %s" % env.mission)
         window.set_caption(env.mission)
 
     redraw(obs)
 
+
 def step(action):
     obs, reward, done, info = env.step(action)
-    print('step=%s, reward=%.2f' % (env.step_count, reward))
+    print(f"step={env.step_count}, reward={reward:.2f}")
 
     if done:
-        print('done!')
+        print("done!")
         reset()
     else:
         redraw(obs)
 
+
 def key_handler(event):
-    print('pressed', event.key)
+    print("pressed", event.key)
 
-    if event.key == 'escape':
+    if event.key == "escape":
         window.close()
         return
 
-    if event.key == 'backspace':
+    if event.key == "backspace":
         reset()
         return
 
-    if event.key == 'left':
+    if event.key == "left":
         step(env.actions.left)
         return
-    if event.key == 'right':
+    if event.key == "right":
         step(env.actions.right)
         return
-    if event.key == 'up':
+    if event.key == "up":
         step(env.actions.forward)
         return
 
     # Spacebar
-    if event.key == ' ':
+    if event.key == " ":
         step(env.actions.toggle)
         return
-    if event.key == 'pageup':
+    if event.key == "pageup":
         step(env.actions.pickup)
         return
-    if event.key == 'pagedown':
+    if event.key == "pagedown":
         step(env.actions.drop)
         return
 
-    if event.key == 'enter':
+    if event.key == "enter":
         step(env.actions.done)
         return
 
+
 parser = argparse.ArgumentParser()
 parser.add_argument(
-    "--env",
-    help="gym environment to load",
-    default='MiniGrid-MultiRoom-N6-v0'
+    "--env", help="gym environment to load", default="MiniGrid-MultiRoom-N6-v0"
 )
 parser.add_argument(
-    "--seed",
-    type=int,
-    help="random seed to generate the environment with",
-    default=-1
+    "--seed", type=int, help="random seed to generate the environment with", default=-1
 )
 parser.add_argument(
-    "--tile_size",
-    type=int,
-    help="size at which to render tiles",
-    default=32
+    "--tile_size", type=int, help="size at which to render tiles", default=32
 )
 parser.add_argument(
-    '--agent_view',
+    "--agent_view",
     default=False,
     help="draw the agent sees (partially observable view)",
-    action='store_true'
+    action="store_true",
 )
 
 args = parser.parse_args()
@@ -105,7 +101,7 @@ if args.agent_view:
     env = RGBImgPartialObsWrapper(env)
     env = ImgObsWrapper(env)
 
-window = Window('gym_minigrid - ' + args.env)
+window = Window("gym_minigrid - " + args.env)
 window.reg_key_handler(key_handler)
 
 reset()

+ 49 - 43
run_tests.py

@@ -1,30 +1,41 @@
 #!/usr/bin/env python3
 
 import random
-import numpy as np
+
 import gym
+import numpy as np
+
 import gym_minigrid
-from gym_minigrid.register import env_list
-from gym_minigrid.minigrid import Grid, OBJECT_TO_IDX
 
 # Test specifically importing a specific environment
-from gym_minigrid.envs import DoorKeyEnv
+from gym_minigrid.minigrid import Grid
+from gym_minigrid.register import env_list
+from gym_minigrid.wrappers import (
+    FlatObsWrapper,
+    FullyObsWrapper,
+    ImgObsWrapper,
+    OneHotPartialObsWrapper,
+    ReseedWrapper,
+    RGBImgObsWrapper,
+    RGBImgPartialObsWrapper,
+    ViewSizeWrapper,
+)
+
+##############################################################################
 
 # Test importing wrappers
-from gym_minigrid.wrappers import *
 
-##############################################################################
 
-print('%d environments registered' % len(env_list))
+print("%d environments registered" % len(env_list))
 
 for env_idx, env_name in enumerate(env_list):
-    print('testing {} ({}/{})'.format(env_name, env_idx+1, len(env_list)))
+    print(f"testing {env_name} ({env_idx + 1}/{len(env_list)})")
 
     # Load the gym environment
     env = gym.make(env_name)
     env.max_steps = min(env.max_steps, 200)
     env.reset()
-    env.render('rgb_array')
+    env.render("rgb_array")
 
     # Verify that the same seed always produces the same environment
     for i in range(0, 5):
@@ -50,7 +61,7 @@ for env_idx, env_name in enumerate(env_list):
         assert env.agent_pos[1] < env.height
 
         # Test observation encode/decode roundtrip
-        img = obs['image']
+        img = obs["image"]
         grid, vis_mask = Grid.decode(img)
         img2 = grid.encode(vis_mask=vis_mask)
         assert np.array_equal(img, img2)
@@ -66,7 +77,7 @@ for env_idx, env_name in enumerate(env_list):
             num_episodes += 1
             env.reset()
 
-        env.render('rgb_array')
+        env.render("rgb_array")
 
     # Test the close method
     env.close()
@@ -89,7 +100,7 @@ for env_idx, env_name in enumerate(env_list):
     env = FullyObsWrapper(env)
     env.reset()
     obs, _, _, _ = env.step(0)
-    assert obs['image'].shape == env.observation_space.spaces['image'].shape
+    assert obs["image"].shape == env.observation_space.spaces["image"].shape
     env.close()
 
     # RGB image observation wrapper
@@ -97,7 +108,7 @@ for env_idx, env_name in enumerate(env_list):
     env = RGBImgPartialObsWrapper(env)
     env.reset()
     obs, _, _, _ = env.step(0)
-    assert obs['image'].mean() > 0
+    assert obs["image"].mean() > 0
     env.close()
 
     env = gym.make(env_name)
@@ -113,19 +124,13 @@ for env_idx, env_name in enumerate(env_list):
     env.close()
 
     # Test the wrappers return proper observation spaces.
-    wrappers = [
-        RGBImgObsWrapper,
-        RGBImgPartialObsWrapper,
-        OneHotPartialObsWrapper
-    ]
+    wrappers = [RGBImgObsWrapper, RGBImgPartialObsWrapper, OneHotPartialObsWrapper]
     for wrapper in wrappers:
         env = wrapper(gym.make(env_name))
         obs_space, wrapper_name = env.observation_space, wrapper.__name__
         assert isinstance(
-            obs_space, spaces.Dict
-        ), "Observation space for {0} is not a Dict: {1}.".format(
-            wrapper_name, obs_space
-        )
+            obs_space, gym.spaces.Dict
+        ), f"Observation space for {wrapper_name} is not a Dict: {obs_space}."
         # This should not fail either
         ImgObsWrapper(env)
         env.reset()
@@ -134,30 +139,31 @@ for env_idx, env_name in enumerate(env_list):
 
 ##############################################################################
 
-print('testing extra observations')
+print("testing extra observations")
+
+
 class EmptyEnvWithExtraObs(gym_minigrid.envs.EmptyEnv5x5):
     """
     Custom environment with an extra observation
     """
+
     def __init__(self) -> None:
         super().__init__()
-        self.observation_space['size'] = spaces.Box(
-            low=0,
-            high=np.iinfo(np.uint).max,
-            shape=(2,),
-            dtype=np.uint
+        self.observation_space["size"] = gym.spaces.Box(
+            low=0, high=np.iinfo(np.uint).max, shape=(2,), dtype=np.uint
         )
 
     def reset(self):
         obs = super().reset()
-        obs['size'] = np.array([self.width, self.height])
+        obs["size"] = np.array([self.width, self.height])
         return obs
 
     def step(self, action):
         obs, reward, done, info = super().step(action)
-        obs['size'] = np.array([self.width, self.height])
+        obs["size"] = np.array([self.width, self.height])
         return obs, reward, done, info
 
+
 wrappers = [
     OneHotPartialObsWrapper,
     RGBImgObsWrapper,
@@ -166,36 +172,36 @@ wrappers = [
 ]
 for wrapper in wrappers:
     env1 = wrapper(EmptyEnvWithExtraObs())
-    env2 = wrapper(gym.make('MiniGrid-Empty-5x5-v0'))
+    env2 = wrapper(gym.make("MiniGrid-Empty-5x5-v0"))
 
     env1.seed(0)
     env2.seed(0)
 
     obs1 = env1.reset()
     obs2 = env2.reset()
-    assert 'size' in obs1
-    assert obs1['size'].shape == (2,)
-    assert (obs1['size'] == [5,5]).all()
+    assert "size" in obs1
+    assert obs1["size"].shape == (2,)
+    assert (obs1["size"] == [5, 5]).all()
     for key in obs2:
         assert np.array_equal(obs1[key], obs2[key])
 
     obs1, reward1, done1, _ = env1.step(0)
     obs2, reward2, done2, _ = env2.step(0)
-    assert 'size' in obs1
-    assert obs1['size'].shape == (2,)
-    assert (obs1['size'] == [5,5]).all()
+    assert "size" in obs1
+    assert obs1["size"].shape == (2,)
+    assert (obs1["size"] == [5, 5]).all()
     for key in obs2:
         assert np.array_equal(obs1[key], obs2[key])
 
 ##############################################################################
 
-print('testing agent_sees method')
-env = gym.make('MiniGrid-DoorKey-6x6-v0')
+print("testing agent_sees method")
+env = gym.make("MiniGrid-DoorKey-6x6-v0")
 goal_pos = (env.grid.width - 2, env.grid.height - 2)
 
 # Test the "in" operator on grid objects
-assert ('green', 'goal') in env.grid
-assert ('blue', 'key') not in env.grid
+assert ("green", "goal") in env.grid
+assert ("blue", "key") not in env.grid
 
 # Test the env.agent_sees() function
 env.reset()
@@ -203,8 +209,8 @@ for i in range(0, 500):
     action = random.randint(0, env.action_space.n - 1)
     obs, reward, done, info = env.step(action)
 
-    grid, _ = Grid.decode(obs['image'])
-    goal_visible = ('green', 'goal') in grid
+    grid, _ = Grid.decode(obs["image"])
+    goal_visible = ("green", "goal") in grid
 
     agent_sees_goal = env.agent_sees(*goal_pos)
     assert agent_sees_goal == goal_visible

+ 14 - 17
setup.py

@@ -12,27 +12,24 @@ with open("README.md") as fh:
             break
 
 setup(
-    name='gym_minigrid',
+    name="gym_minigrid",
     author="Farama Foundation",
     author_email="jkterry@farama.org",
-    version='1.0.2',
-    keywords='memory, environment, agent, rl, gym',
-    url='https://github.com/Farama-Foundation/gym-minigrid',
-    description='Minimalistic gridworld reinforcement learning environments',
-    packages=['gym_minigrid', 'gym_minigrid.envs'],
+    version="1.0.2",
+    keywords="memory, environment, agent, rl, gym",
+    url="https://github.com/Farama-Foundation/gym-minigrid",
+    description="Minimalistic gridworld reinforcement learning environments",
+    packages=["gym_minigrid", "gym_minigrid.envs"],
     long_description=long_description,
     python_requires=">=3.7, <3.11",
     long_description_content_type="text/markdown",
-    install_requires=[
-        'gym>=0.24.0',
-        "numpy>=1.18.0"
-    ],
+    install_requires=["gym>=0.24.0", "numpy>=1.18.0"],
     classifiers=[
-    "Development Status :: 5 - Production/Stable",
-    "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.7",
-    "Programming Language :: Python :: 3.8",
-    "Programming Language :: Python :: 3.9",
-    "Programming Language :: Python :: 3.10",
-],
+        "Development Status :: 5 - Production/Stable",
+        "Programming Language :: Python :: 3",
+        "Programming Language :: Python :: 3.7",
+        "Programming Language :: Python :: 3.8",
+        "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
+    ],
 )

+ 4 - 4
test_interactive_mode.py

@@ -1,16 +1,16 @@
 #!/usr/bin/env python3
 
-import time
 import random
+import time
+
 import gym
-import gym_minigrid
 
 # Load the gym environment
-env = gym.make('MiniGrid-Empty-8x8-v0')
+env = gym.make("MiniGrid-Empty-8x8-v0")
 env.reset()
 
 for i in range(0, 100):
-    print("step {}".format(i))
+    print(f"step {i}")
 
     # Pick a random action
     action = random.randint(0, env.action_space.n - 1)