Tutorial: Repository Structure

Introduction

Welcome to the first of four short tutorials, guiding you through the process of creating your own PettingZoo environment, from conception to deployment.

We will be creating a parallel environment, meaning that each agent acts simultaneously.

Before thinking about the environment logic, we should understand the structure of environment repositories.

Tree structure

Environment repositories are usually laid out using the following structure:

Custom-Environment
├── custom-environment
    └── env
        └── custom_environment.py
    └── custom_environment_v0.py
├── README.md
└── requirements.txt
  • /custom-environment/env is where your environment will be stored, along with any helper functions (in the case of a complicated environment).

  • /custom-environment/custom_environment_v0.py is a file that imports the environment - we use the file name for environment version control.

  • /README.md is a file used to describe your environment.

  • /requirements.txt is a file used to keep track of your environment dependencies. At the very least, pettingzoo should be in there. Please version control all your dependencies via ==.

Advanced: Additional (optional) files

The above file structure is minimal. A more deployment-ready environment would include

  • /docs/ for documentation,

  • /setup.py for packaging,

  • /custom-environment/__init__.py for depreciation handling, and

  • Github actions for continuous integration of environment tests.

Implementing these are outside the scope of this tutorial.

Skeleton code

The entirety of your environment logic is stored within /custom-environment/env

/custom-environment/env/custom_environment.py
from pettingzoo import ParallelEnv


class CustomEnvironment(ParallelEnv):
    metadata = {
        "name": "custom_environment_v0",
    }

    def __init__(self):
        pass

    def reset(self, seed=None, options=None):
        pass

    def step(self, actions):
        pass

    def render(self):
        pass

    def observation_space(self, agent):
        return self.observation_spaces[agent]

    def action_space(self, agent):
        return self.action_spaces[agent]