--- layout: "contents" title: Tutorial on Creating Environments firstpage: --- # Tutorial on Creating Environments In this tutorial, we will go through the process of creating a new environment. ## Boilerplate Code ```python class SimpleEnv(MiniGridEnv): def __init__( self, size=8, agent_start_pos=(1, 1), agent_start_dir=0, max_steps: int | None = None, **kwargs, ): self.agent_start_pos = agent_start_pos self.agent_start_dir = agent_start_dir mission_space = MissionSpace(mission_func=self._gen_mission) super().__init__( mission_space=mission_space, grid_size=size, max_steps=256, **kwargs, ) @staticmethod def _gen_mission(): return "grand mission" ``` First, we need to create a class that inherits from `MiniGridEnv`, we call our class `SimpleEnv`. Then, we define a mission space, the recommended way to do it is to define a static function. ```python @staticmethod def _gen_mission(): return "grand mission" ``` that only returns a string which corresponds to the mission. We then pass this function as an argument ```python mission_space = MissionSpace(mission_func=self._gen_mission) ``` Then, in the `__init__` function, we pass the required arguments to the parent class. In this case we are passing the `mission_space`, `grid_size` and `max_steps`. We also create `self.agent_start_pos` and `self.agent_start_dir` so that member functions can have access to these two values. ## Generate the grid-world To create your own grid-world environment we override the function `_gen_grid`. We can see from the `MiniGridEnv` class ```python # MiniGridEnv._gen_grid @abstractmethod def _gen_grid(self, width, height): pass ``` `_gen_grid` takes in two inputs `width` and `height`, which are used to specify the size of the environment. ### Create World To create the environment, we first an empty grid using ```python self.grid = Grid(width, height) ``` Then, we create the walls that surrounds the grid ```python self.grid.wall_rect(0, 0, width, height) ``` Finally, we place the agent in the environment ```python if self.agent_start_pos is not None: self.agent_pos = self.agent_start_pos self.agent_dir = self.agent_start_dir else: self.place_agent() ``` these lines of code is saying if we specified the agent starting position and direction the environment will follow what we specified, otherwise, it will randomly place the agent within the environment. If we render the environment right now, it would look like this: ```{figure} ../../figures/tutorial_imgs/first_step.png :alt: env after first step :width: 200px ``` ### Place Goal To place a goal in the environment, we use the function ```python self.put_obj(Goal(), width - 2, height - 2) ``` which places the goal in the bottom right corner. Now the environment should look like this: ```{figure} ../../figures/tutorial_imgs/second_step.png :alt: env after second step :width: 200px ``` ### Create Separating Walls To create a wall that separates the environment into two rooms, we use the command ```python for i in range(0, height): self.grid.set(5, i, Wall()) ``` this goes over the grids with coordinates `(5, 0)`, `(5, 1)` ... `(5, height)` and make them walls. The result would look like: ```{figure} ../../figures/tutorial_imgs/third_step.png :alt: env after third step :width: 200px ``` ### Add Keys and Doors To add keys and doors, we would first need to import ```python from minigrid.core.constants import COLOR_NAMES from minigrid.core.world_object import Door, Key ``` Then, we can simply place the door and key using the command ```python self.grid.set(5, 6, Door(COLOR_NAMES[0], is_locked=True)) self.grid.set(3, 6, Key(COLOR_NAMES[0])) ``` Now the environment looks like: ```{figure} ../../figures/tutorial_imgs/fourth_step.png :alt: env after fourth step :width: 200px ``` Even for creating more complicated environments, this is all you need know. ## Source Code The source code of this tutorial is ```python from __future__ import annotations from minigrid.core.constants import COLOR_NAMES from minigrid.core.grid import Grid from minigrid.core.mission import MissionSpace from minigrid.core.world_object import Door, Goal, Key, Wall from minigrid.manual_control import ManualControl from minigrid.minigrid_env import MiniGridEnv class SimpleEnv(MiniGridEnv): def __init__( self, size=10, agent_start_pos=(1, 1), agent_start_dir=0, max_steps: int | None = None, **kwargs, ): self.agent_start_pos = agent_start_pos self.agent_start_dir = agent_start_dir mission_space = MissionSpace(mission_func=self._gen_mission) if max_steps is None: max_steps = 4 * size**2 super().__init__( mission_space=mission_space, grid_size=size, # Set this to True for maximum speed see_through_walls=True, max_steps=max_steps, **kwargs, ) @staticmethod def _gen_mission(): return "grand mission" def _gen_grid(self, width, height): # Create an empty grid self.grid = Grid(width, height) # Generate the surrounding walls self.grid.wall_rect(0, 0, width, height) # Generate vertical separation wall for i in range(0, height): self.grid.set(5, i, Wall()) # Place the door and key self.grid.set(5, 6, Door(COLOR_NAMES[0], is_locked=True)) self.grid.set(3, 6, Key(COLOR_NAMES[0])) # Place a goal square in the bottom-right corner self.put_obj(Goal(), width - 2, height - 2) # Place the agent if self.agent_start_pos is not None: self.agent_pos = self.agent_start_pos self.agent_dir = self.agent_start_dir else: self.place_agent() self.mission = "grand mission" def main(): env = SimpleEnv(render_mode="human") # enable manual control for testing manual_control = ManualControl(env, seed=42) manual_control.start() if __name__ == "__main__": main() ```