mirror of
https://github.com/Farama-Foundation/Gymnasium.git
synced 2025-08-20 05:52:03 +00:00
907 lines
73 KiB
HTML
907 lines
73 KiB
HTML
<!doctype html>
|
||
<html class="no-js" lang="en" data-content_root="../../">
|
||
<head><meta charset="utf-8"/>
|
||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||
<meta name="color-scheme" content="light dark">
|
||
<meta name="description" content="A standard API for reinforcement learning and a diverse set of reference environments (formerly Gym)">
|
||
<meta property="og:title" content="Gymnasium Documentation" />
|
||
<meta property="og:type" content="website" />
|
||
<meta property="og:description" content="A standard API for reinforcement learning and a diverse set of reference environments (formerly Gym)" />
|
||
<meta property="og:url" content="https://gymnasium.farama.org/introduction/create_custom_env.html" /><meta property="og:image" content="https://gymnasium.farama.org/_static/img/gymnasium-github.png" /><meta name="twitter:card" content="summary_large_image"><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<link rel="index" title="Index" href="../../genindex/" /><link rel="search" title="Search" href="../../search/" /><link rel="next" title="Recording Agents" href="../record_agent/" /><link rel="prev" title="Training an Agent" href="../train_agent/" />
|
||
<link rel="canonical" href="https://gymnasium.farama.org/introduction/create_custom_env.html" />
|
||
|
||
<link rel="shortcut icon" href="../../_static/favicon.png"/><!-- Generated with Sphinx 7.4.7 and Furo 2023.08.19.dev1 -->
|
||
<title>Create a Custom Environment - Gymnasium Documentation</title>
|
||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=8f2a1f02" />
|
||
<link rel="stylesheet" type="text/css" href="../../_static/styles/furo.css?v=3e7f4c72" />
|
||
<link rel="stylesheet" type="text/css" href="../../_static/sg_gallery.css?v=61a4c737" />
|
||
<link rel="stylesheet" type="text/css" href="../../_static/sg_gallery-binder.css?v=f4aeca0c" />
|
||
<link rel="stylesheet" type="text/css" href="../../_static/sg_gallery-dataframe.css?v=2082cf3c" />
|
||
<link rel="stylesheet" type="text/css" href="../../_static/sg_gallery-rendered-html.css?v=1277b6f3" />
|
||
<link rel="stylesheet" type="text/css" href="../../_static/styles/furo-extensions.css?v=82c8b628" />
|
||
|
||
|
||
|
||
|
||
<style>
|
||
body {
|
||
--color-code-background: #f8f8f8;
|
||
--color-code-foreground: black;
|
||
|
||
}
|
||
@media not print {
|
||
body[data-theme="dark"] {
|
||
--color-code-background: #202020;
|
||
--color-code-foreground: #d0d0d0;
|
||
|
||
}
|
||
@media (prefers-color-scheme: dark) {
|
||
body:not([data-theme="light"]) {
|
||
--color-code-background: #202020;
|
||
--color-code-foreground: #d0d0d0;
|
||
|
||
}
|
||
}
|
||
}
|
||
</style></head>
|
||
<body>
|
||
<header class="farama-header" aria-label="Farama header">
|
||
<div class="farama-header__container">
|
||
<div class="farama-header__left--mobile">
|
||
<label class="nav-overlay-icon" for="__navigation">
|
||
<div class="visually-hidden">Toggle site navigation sidebar</div>
|
||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||
<defs></defs>
|
||
<line x1="0.5" y1="4" x2="23.5" y2="4"></line>
|
||
<line x1="0.232" y1="12" x2="23.5" y2="12"></line>
|
||
<line x1="0.232" y1="20" x2="23.5" y2="20"></line>
|
||
</svg>
|
||
</label>
|
||
</div>
|
||
<div class="farama-header__left farama-header__center--mobile">
|
||
<a href="../../">
|
||
<img class="farama-header__logo only-light" src="../../_static/img/gymnasium_black.svg" alt="Light Logo"/>
|
||
<img class="farama-header__logo only-dark" src="../../_static/img/gymnasium_white.svg" alt="Dark Logo"/>
|
||
<span class="farama-header__title">Gymnasium Documentation</span>
|
||
</a>
|
||
</div>
|
||
<div class="farama-header__right">
|
||
<div class="farama-header-menu">
|
||
<button class="farama-header-menu__btn" aria-label="Open Farama Menu" aria-expanded="false" aria-haspopup="true" aria-controls="farama-menu">
|
||
<img class="farama-black-logo-invert" src="../../_static/img/farama-logo-header.svg">
|
||
<svg viewBox="0 0 24 24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||
<polyline style="stroke-linecap: round; stroke-linejoin: round; fill: none; stroke-width: 2px;" points="1 7 12 18 23 7"></polyline>
|
||
</svg>
|
||
</button>
|
||
<div class="farama-header-menu-container farama-hidden" aria-hidden="true" id="farama-menu">
|
||
<div class="farama-header-menu__header">
|
||
<a href="https://farama.org">
|
||
<img class="farama-header-menu__logo farama-white-logo-invert" src="../../_static/img/farama_solid_white.svg" alt="Farama Foundation logo">
|
||
<span>Farama Foundation</span>
|
||
</a>
|
||
<div class="farama-header-menu-header__right">
|
||
<button id="farama-close-menu">
|
||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor"
|
||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-close">
|
||
<line x1="3" y1="21" x2="21" y2="3"></line>
|
||
<line x1="3" y1="3" x2="21" y2="21"></line>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="farama-header-menu__body">
|
||
<!-- Response from farama.org/api/projects.json -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
|
||
<script>
|
||
document.body.dataset.theme = localStorage.getItem("theme") || "auto";
|
||
</script>
|
||
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||
<symbol id="svg-toc" viewBox="0 0 24 24">
|
||
<title>Contents</title>
|
||
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024">
|
||
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM115.4 518.9L271.7 642c5.8 4.6 14.4.5 14.4-6.9V388.9c0-7.4-8.5-11.5-14.4-6.9L115.4 505.1a8.74 8.74 0 0 0 0 13.8z"/>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-menu" viewBox="0 0 24 24">
|
||
<title>Menu</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-menu">
|
||
<line x1="3" y1="12" x2="21" y2="12"></line>
|
||
<line x1="3" y1="6" x2="21" y2="6"></line>
|
||
<line x1="3" y1="18" x2="21" y2="18"></line>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-arrow-right" viewBox="0 0 24 24">
|
||
<title>Expand</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-chevron-right">
|
||
<polyline points="9 18 15 12 9 6"></polyline>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-sun" viewBox="0 0 24 24">
|
||
<title>Light mode</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="feather-sun">
|
||
<circle cx="12" cy="12" r="5"></circle>
|
||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-moon" viewBox="0 0 24 24">
|
||
<title>Dark mode</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-moon">
|
||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-sun-half" viewBox="0 0 24 24">
|
||
<title>Auto light/dark mode</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-shadow">
|
||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||
<circle cx="12" cy="12" r="9" />
|
||
<path d="M13 12h5" />
|
||
<path d="M13 15h4" />
|
||
<path d="M13 18h1" />
|
||
<path d="M13 9h4" />
|
||
<path d="M13 6h1" />
|
||
</svg>
|
||
</symbol>
|
||
</svg>
|
||
|
||
<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation">
|
||
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc">
|
||
<label class="overlay sidebar-overlay" for="__navigation">
|
||
<div class="visually-hidden">Hide navigation sidebar</div>
|
||
</label>
|
||
<label class="overlay toc-overlay" for="__toc">
|
||
<div class="visually-hidden">Hide table of contents sidebar</div>
|
||
</label>
|
||
|
||
<div class="page">
|
||
<!--<header class="mobile-header">
|
||
<div class="header-left">
|
||
<label class="nav-overlay-icon" for="__navigation">
|
||
<div class="visually-hidden">Toggle site navigation sidebar</div>
|
||
<i class="icon"><svg><use href="#svg-menu"></use></svg></i>
|
||
</label>
|
||
</div>
|
||
<div class="header-center">
|
||
<a href="../../"><div class="brand">Gymnasium Documentation</div></a>
|
||
</div>
|
||
<div class="header-right">
|
||
<div class="theme-toggle-container theme-toggle-header">
|
||
<button class="theme-toggle">
|
||
<div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
|
||
<svg class="theme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
|
||
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
|
||
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
|
||
</button>
|
||
</div>
|
||
<label class="toc-overlay-icon toc-header-icon" for="__toc">
|
||
<div class="visually-hidden">Toggle table of contents sidebar</div>
|
||
<i class="icon"><svg><use href="#svg-toc"></use></svg></i>
|
||
</label>
|
||
</div>
|
||
</header>-->
|
||
<aside class="sidebar-drawer">
|
||
<div class="sidebar-container">
|
||
|
||
<div class="sidebar-sticky"><a class="farama-sidebar__title" href="../../">
|
||
<img class="farama-header__logo only-light" src="../../_static/img/gymnasium_black.svg" alt="Light Logo"/>
|
||
<img class="farama-header__logo only-dark" src="../../_static/img/gymnasium_white.svg" alt="Dark Logo"/>
|
||
<span class="farama-header__title">Gymnasium Documentation</span>
|
||
</a><form class="sidebar-search-container" method="get" action="../../search/" role="search">
|
||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||
<input type="hidden" name="check_keywords" value="yes">
|
||
<input type="hidden" name="area" value="default">
|
||
</form>
|
||
<div id="searchbox"></div><div class="sidebar-scroll"><div class="sidebar-tree">
|
||
<p class="caption" role="heading"><span class="caption-text">Introduction</span></p>
|
||
<ul class="current">
|
||
<li class="toctree-l1"><a class="reference internal" href="../basic_usage/">Basic Usage</a></li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../train_agent/">Training an Agent</a></li>
|
||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Create a Custom Environment</a></li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../record_agent/">Recording Agents</a></li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../speed_up_env/">Speeding Up Training</a></li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../gym_compatibility/">Compatibility with Gym</a></li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../migration_guide/">Migration Guide - v0.21 to v1.0.0</a></li>
|
||
</ul>
|
||
<p class="caption" role="heading"><span class="caption-text">API</span></p>
|
||
<ul>
|
||
<li class="toctree-l1"><a class="reference internal" href="../../api/env/">Env</a></li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../../api/registry/">Make and register</a></li>
|
||
<li class="toctree-l1 has-children"><a class="reference internal" href="../../api/spaces/">Spaces</a><input class="toctree-checkbox" id="toctree-checkbox-1" name="toctree-checkbox-1" role="switch" type="checkbox"/><label for="toctree-checkbox-1"><div class="visually-hidden">Toggle navigation of Spaces</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../api/spaces/fundamental/">Fundamental Spaces</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../api/spaces/composite/">Composite Spaces</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../api/spaces/utils/">Spaces Utils</a></li>
|
||
</ul>
|
||
</li>
|
||
<li class="toctree-l1 has-children"><a class="reference internal" href="../../api/wrappers/">Wrappers</a><input class="toctree-checkbox" id="toctree-checkbox-2" name="toctree-checkbox-2" role="switch" type="checkbox"/><label for="toctree-checkbox-2"><div class="visually-hidden">Toggle navigation of Wrappers</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../api/wrappers/table/">List of Wrappers</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../api/wrappers/misc_wrappers/">Misc Wrappers</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../api/wrappers/action_wrappers/">Action Wrappers</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../api/wrappers/observation_wrappers/">Observation Wrappers</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../api/wrappers/reward_wrappers/">Reward Wrappers</a></li>
|
||
</ul>
|
||
</li>
|
||
<li class="toctree-l1 has-children"><a class="reference internal" href="../../api/vector/">Vectorize</a><input class="toctree-checkbox" id="toctree-checkbox-3" name="toctree-checkbox-3" role="switch" type="checkbox"/><label for="toctree-checkbox-3"><div class="visually-hidden">Toggle navigation of Vectorize</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../api/vector/wrappers/">Wrappers</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../api/vector/async_vector_env/">AsyncVectorEnv</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../api/vector/sync_vector_env/">SyncVectorEnv</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../api/vector/utils/">Utility functions</a></li>
|
||
</ul>
|
||
</li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../../api/utils/">Utility functions</a></li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../../api/functional/">Functional Env</a></li>
|
||
</ul>
|
||
<p class="caption" role="heading"><span class="caption-text">Environments</span></p>
|
||
<ul>
|
||
<li class="toctree-l1 has-children"><a class="reference internal" href="../../environments/classic_control/">Classic Control</a><input class="toctree-checkbox" id="toctree-checkbox-4" name="toctree-checkbox-4" role="switch" type="checkbox"/><label for="toctree-checkbox-4"><div class="visually-hidden">Toggle navigation of Classic Control</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/classic_control/acrobot/">Acrobot</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/classic_control/cart_pole/">Cart Pole</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/classic_control/mountain_car_continuous/">Mountain Car Continuous</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/classic_control/mountain_car/">Mountain Car</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/classic_control/pendulum/">Pendulum</a></li>
|
||
</ul>
|
||
</li>
|
||
<li class="toctree-l1 has-children"><a class="reference internal" href="../../environments/box2d/">Box2D</a><input class="toctree-checkbox" id="toctree-checkbox-5" name="toctree-checkbox-5" role="switch" type="checkbox"/><label for="toctree-checkbox-5"><div class="visually-hidden">Toggle navigation of Box2D</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/box2d/bipedal_walker/">Bipedal Walker</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/box2d/car_racing/">Car Racing</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/box2d/lunar_lander/">Lunar Lander</a></li>
|
||
</ul>
|
||
</li>
|
||
<li class="toctree-l1 has-children"><a class="reference internal" href="../../environments/toy_text/">Toy Text</a><input class="toctree-checkbox" id="toctree-checkbox-6" name="toctree-checkbox-6" role="switch" type="checkbox"/><label for="toctree-checkbox-6"><div class="visually-hidden">Toggle navigation of Toy Text</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/toy_text/blackjack/">Blackjack</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/toy_text/taxi/">Taxi</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/toy_text/cliff_walking/">Cliff Walking</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/toy_text/frozen_lake/">Frozen Lake</a></li>
|
||
</ul>
|
||
</li>
|
||
<li class="toctree-l1 has-children"><a class="reference internal" href="../../environments/mujoco/">MuJoCo</a><input class="toctree-checkbox" id="toctree-checkbox-7" name="toctree-checkbox-7" role="switch" type="checkbox"/><label for="toctree-checkbox-7"><div class="visually-hidden">Toggle navigation of MuJoCo</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/mujoco/ant/">Ant</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/mujoco/half_cheetah/">Half Cheetah</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/mujoco/hopper/">Hopper</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/mujoco/humanoid/">Humanoid</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/mujoco/humanoid_standup/">Humanoid Standup</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/mujoco/inverted_double_pendulum/">Inverted Double Pendulum</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/mujoco/inverted_pendulum/">Inverted Pendulum</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/mujoco/pusher/">Pusher</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/mujoco/reacher/">Reacher</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/mujoco/swimmer/">Swimmer</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../environments/mujoco/walker2d/">Walker2D</a></li>
|
||
</ul>
|
||
</li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../../environments/atari/">Atari</a></li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../../environments/third_party_environments/">External Environments</a></li>
|
||
</ul>
|
||
<p class="caption" role="heading"><span class="caption-text">Tutorials</span></p>
|
||
<ul>
|
||
<li class="toctree-l1 has-children"><a class="reference internal" href="../../tutorials/gymnasium_basics/">Gymnasium Basics Documentation Links</a><input class="toctree-checkbox" id="toctree-checkbox-8" name="toctree-checkbox-8" role="switch" type="checkbox"/><label for="toctree-checkbox-8"><div class="visually-hidden">Toggle navigation of Gymnasium Basics Documentation Links</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../tutorials/gymnasium_basics/load_quadruped_model/">Load custom quadruped robot environments</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../tutorials/gymnasium_basics/handling_time_limits/">Handling Time Limits</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../tutorials/gymnasium_basics/implementing_custom_wrappers/">Implementing Custom Wrappers</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../tutorials/gymnasium_basics/environment_creation/">Make your own custom environment</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../tutorials/gymnasium_basics/vector_envs_tutorial/">Training A2C with Vector Envs and Domain Randomization</a></li>
|
||
</ul>
|
||
</li>
|
||
<li class="toctree-l1 has-children"><a class="reference internal" href="../../tutorials/training_agents/">Training Agents links in the Gymnasium Documentation</a><input class="toctree-checkbox" id="toctree-checkbox-9" name="toctree-checkbox-9" role="switch" type="checkbox"/><label for="toctree-checkbox-9"><div class="visually-hidden">Toggle navigation of Training Agents links in the Gymnasium Documentation</div><i class="icon"><svg><use href="#svg-arrow-right"></use></svg></i></label><ul>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../tutorials/training_agents/reinforce_invpend_gym_v26/">Training using REINFORCE for Mujoco</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../tutorials/training_agents/blackjack_tutorial/">Solving Blackjack with Q-Learning</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="../../tutorials/training_agents/FrozenLake_tuto/">Frozenlake benchmark</a></li>
|
||
</ul>
|
||
</li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../../tutorials/third-party-tutorials/">Third-Party Tutorials</a></li>
|
||
</ul>
|
||
<p class="caption" role="heading"><span class="caption-text">Development</span></p>
|
||
<ul>
|
||
<li class="toctree-l1"><a class="reference external" href="https://github.com/Farama-Foundation/Gymnasium">Github</a></li>
|
||
<li class="toctree-l1"><a class="reference external" href="https://arxiv.org/abs/2407.17032">Paper</a></li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../../gymnasium_release_notes/">Gymnasium Release Notes</a></li>
|
||
<li class="toctree-l1"><a class="reference internal" href="../../gym_release_notes/">Gym Release Notes</a></li>
|
||
<li class="toctree-l1"><a class="reference external" href="https://github.com/Farama-Foundation/Gymnasium/blob/main/docs/README.md">Contribute to the Docs</a></li>
|
||
</ul>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
</aside>
|
||
<div class="main-container">
|
||
|
||
|
||
|
||
|
||
|
||
<div class="main">
|
||
<div class="content">
|
||
<div class="article-container">
|
||
<a href="#" class="back-to-top muted-link">
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||
<path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12z"></path>
|
||
</svg>
|
||
<span>Back to top</span>
|
||
</a>
|
||
<div class="content-icon-container"><div class="edit-this-page">
|
||
<a class="muted-link" href="https://github.com/Farama-Foundation/Gymnasium/edit/main/docs/introduction/create_custom_env.md" title="Edit this page">
|
||
<svg aria-hidden="true" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||
<path d="M4 20h4l10.5 -10.5a1.5 1.5 0 0 0 -4 -4l-10.5 10.5v4" />
|
||
<line x1="13.5" y1="6.5" x2="17.5" y2="10.5" />
|
||
</svg>
|
||
<span class="visually-hidden">Edit this page</span>
|
||
</a>
|
||
</div><div class="theme-toggle-container theme-toggle-content">
|
||
<button class="theme-toggle" title="Toggle color theme">
|
||
<div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
|
||
<svg class="theme-icon-when-auto">
|
||
<use href="#svg-sun-half"></use>
|
||
</svg>
|
||
<svg class="theme-icon-when-dark">
|
||
<use href="#svg-moon"></use>
|
||
</svg>
|
||
<svg class="theme-icon-when-light">
|
||
<use href="#svg-sun"></use>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<label class="toc-overlay-icon toc-content-icon" for="__toc">
|
||
<div class="visually-hidden">Toggle table of contents sidebar</div>
|
||
<i class="icon"><svg>
|
||
<use href="#svg-toc"></use>
|
||
</svg></i>
|
||
</label>
|
||
</div>
|
||
<article role="main">
|
||
|
||
<section class="tex2jax_ignore mathjax_ignore" id="create-a-custom-environment">
|
||
<h1>Create a Custom Environment<a class="headerlink" href="#create-a-custom-environment" title="Link to this heading">¶</a></h1>
|
||
<p>This page provides a short outline of how to create custom environments with Gymnasium, for a more <a class="reference internal" href="../../tutorials/gymnasium_basics/environment_creation/"><span class="doc std std-doc">complete tutorial</span></a> with rendering, please read <a class="reference internal" href="../basic_usage/"><span class="doc std std-doc">basic usage</span></a> before reading this page.</p>
|
||
<p>We will implement a very simplistic game, called <code class="docutils literal notranslate"><span class="pre">GridWorldEnv</span></code>, consisting of a 2-dimensional square grid of fixed size. The agent can move vertically or horizontally between grid cells in each timestep and the goal of the agent is to navigate to a target on the grid that has been placed randomly at the beginning of the episode.</p>
|
||
<p>Basic information about the game</p>
|
||
<ul class="simple">
|
||
<li><p>Observations provide the location of the target and agent.</p></li>
|
||
<li><p>There are 4 discrete actions in our environment, corresponding to the movements “right”, “up”, “left”, and “down”.</p></li>
|
||
<li><p>The environment ends (terminates) when the agent has navigated to the grid cell where the target is located.</p></li>
|
||
<li><p>The agent is only rewarded when it reaches the target, i.e., the reward is one when the agent reaches the target and zero otherwise.</p></li>
|
||
</ul>
|
||
<section id="environment-init">
|
||
<h2>Environment <code class="docutils literal notranslate"><span class="pre">__init__</span></code><a class="headerlink" href="#environment-init" title="Link to this heading">¶</a></h2>
|
||
<p>Like all environments, our custom environment will inherit from <a class="reference internal" href="../../api/env/#gymnasium.Env" title="gymnasium.Env"><code class="xref py py-class docutils literal notranslate"><span class="pre">gymnasium.Env</span></code></a> that defines the structure of environment. One of the requirements for an environment is defining the observation and action space, which declare the general set of possible inputs (actions) and outputs (observations) of the environment. As outlined in our basic information about the game, our agent has four discrete actions, therefore we will use the <code class="docutils literal notranslate"><span class="pre">Discrete(4)</span></code> space with four options.</p>
|
||
<p>For our observation, there are a couple options, for this tutorial we will imagine our observation looks like <code class="docutils literal notranslate"><span class="pre">{"agent":</span> <span class="pre">array([1,</span> <span class="pre">0]),</span> <span class="pre">"target":</span> <span class="pre">array([0,</span> <span class="pre">3])}</span></code> where the array elements represent the x and y positions of the agent or target. Alternative options for representing the observation is as a 2d grid with values representing the agent and target on the grid or a 3d grid with each “layer” containing only the agent or target information. Therefore, we will declare the observation space as <a class="reference internal" href="../../api/spaces/composite/#gymnasium.spaces.Dict" title="gymnasium.spaces.Dict"><code class="xref py py-class docutils literal notranslate"><span class="pre">Dict</span></code></a> with the agent and target spaces being a <a class="reference internal" href="../../api/spaces/fundamental/#gymnasium.spaces.Box" title="gymnasium.spaces.Box"><code class="xref py py-class docutils literal notranslate"><span class="pre">Box</span></code></a> allowing an array output of an int type.</p>
|
||
<p>For a full list of possible spaces to use with an environment, see <a class="reference internal" href="../../api/spaces/"><span class="doc std std-doc">spaces</span></a></p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Optional</span>
|
||
<span class="kn">import</span><span class="w"> </span><span class="nn">numpy</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">np</span>
|
||
<span class="kn">import</span><span class="w"> </span><span class="nn">gymnasium</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">gym</span>
|
||
|
||
|
||
<span class="k">class</span><span class="w"> </span><span class="nc">GridWorldEnv</span><span class="p">(</span><span class="n">gym</span><span class="o">.</span><span class="n">Env</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">size</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">5</span><span class="p">):</span>
|
||
<span class="c1"># The size of the square grid</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">=</span> <span class="n">size</span>
|
||
|
||
<span class="c1"># Define the agent and target location; randomly chosen in `reset` and updated in `step`</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_agent_location</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">dtype</span><span class="o">=</span><span class="n">np</span><span class="o">.</span><span class="n">int32</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_target_location</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">dtype</span><span class="o">=</span><span class="n">np</span><span class="o">.</span><span class="n">int32</span><span class="p">)</span>
|
||
|
||
<span class="c1"># Observations are dictionaries with the agent's and the target's location.</span>
|
||
<span class="c1"># Each location is encoded as an element of {0, ..., `size`-1}^2</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">observation_space</span> <span class="o">=</span> <span class="n">gym</span><span class="o">.</span><span class="n">spaces</span><span class="o">.</span><span class="n">Dict</span><span class="p">(</span>
|
||
<span class="p">{</span>
|
||
<span class="s2">"agent"</span><span class="p">:</span> <span class="n">gym</span><span class="o">.</span><span class="n">spaces</span><span class="o">.</span><span class="n">Box</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">size</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">shape</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,),</span> <span class="n">dtype</span><span class="o">=</span><span class="nb">int</span><span class="p">),</span>
|
||
<span class="s2">"target"</span><span class="p">:</span> <span class="n">gym</span><span class="o">.</span><span class="n">spaces</span><span class="o">.</span><span class="n">Box</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">size</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">shape</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,),</span> <span class="n">dtype</span><span class="o">=</span><span class="nb">int</span><span class="p">),</span>
|
||
<span class="p">}</span>
|
||
<span class="p">)</span>
|
||
|
||
<span class="c1"># We have 4 actions, corresponding to "right", "up", "left", "down"</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">action_space</span> <span class="o">=</span> <span class="n">gym</span><span class="o">.</span><span class="n">spaces</span><span class="o">.</span><span class="n">Discrete</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
|
||
<span class="c1"># Dictionary maps the abstract actions to the directions on the grid</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_action_to_direction</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="mi">0</span><span class="p">:</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]),</span> <span class="c1"># right</span>
|
||
<span class="mi">1</span><span class="p">:</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]),</span> <span class="c1"># up</span>
|
||
<span class="mi">2</span><span class="p">:</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]),</span> <span class="c1"># left</span>
|
||
<span class="mi">3</span><span class="p">:</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">]),</span> <span class="c1"># down</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="constructing-observations">
|
||
<h2>Constructing Observations<a class="headerlink" href="#constructing-observations" title="Link to this heading">¶</a></h2>
|
||
<p>Since we will need to compute observations both in <a class="reference internal" href="../../api/env/#gymnasium.Env.reset" title="gymnasium.Env.reset"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Env.reset()</span></code></a> and <a class="reference internal" href="../../api/env/#gymnasium.Env.step" title="gymnasium.Env.step"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Env.step()</span></code></a>, it is often convenient to have a method <code class="docutils literal notranslate"><span class="pre">_get_obs</span></code> that translates the environment’s state into an observation. However, this is not mandatory and you can compute the observations in <a class="reference internal" href="../../api/env/#gymnasium.Env.reset" title="gymnasium.Env.reset"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Env.reset()</span></code></a> and <a class="reference internal" href="../../api/env/#gymnasium.Env.step" title="gymnasium.Env.step"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Env.step()</span></code></a> separately.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_obs</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="p">{</span><span class="s2">"agent"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_agent_location</span><span class="p">,</span> <span class="s2">"target"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_target_location</span><span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>We can also implement a similar method for the auxiliary information that is returned by <a class="reference internal" href="../../api/env/#gymnasium.Env.reset" title="gymnasium.Env.reset"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Env.reset()</span></code></a> and <a class="reference internal" href="../../api/env/#gymnasium.Env.step" title="gymnasium.Env.step"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Env.step()</span></code></a>. In our case, we would like to provide the manhattan distance between the agent and the target:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="p">{</span>
|
||
<span class="s2">"distance"</span><span class="p">:</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">norm</span><span class="p">(</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_agent_location</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">_target_location</span><span class="p">,</span> <span class="nb">ord</span><span class="o">=</span><span class="mi">1</span>
|
||
<span class="p">)</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Oftentimes, info will also contain some data that is only available inside the <a class="reference internal" href="../../api/env/#gymnasium.Env.step" title="gymnasium.Env.step"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Env.step()</span></code></a> method (e.g., individual reward terms). In that case, we would have to update the dictionary that is returned by <code class="docutils literal notranslate"><span class="pre">_get_info</span></code> in <a class="reference internal" href="../../api/env/#gymnasium.Env.step" title="gymnasium.Env.step"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Env.step()</span></code></a>.</p>
|
||
</section>
|
||
<section id="reset-function">
|
||
<h2>Reset function<a class="headerlink" href="#reset-function" title="Link to this heading">¶</a></h2>
|
||
<p>The purpose of <a class="reference internal" href="../../api/env/#gymnasium.Env.reset" title="gymnasium.Env.reset"><code class="xref py py-meth docutils literal notranslate"><span class="pre">reset()</span></code></a> is to initiate a new episode for an environment and has two parameters: <code class="docutils literal notranslate"><span class="pre">seed</span></code> and <code class="docutils literal notranslate"><span class="pre">options</span></code>. The seed can be used to initialize the random number generator to a deterministic state and options can be used to specify values used within reset. On the first line of the reset, you need to call <code class="docutils literal notranslate"><span class="pre">super().reset(seed=seed)</span></code> which will initialize the random number generate (<a class="reference internal" href="../../api/env/#gymnasium.Env.np_random" title="gymnasium.Env.np_random"><code class="xref py py-attr docutils literal notranslate"><span class="pre">np_random</span></code></a>) to use through the rest of the <a class="reference internal" href="../../api/env/#gymnasium.Env.reset" title="gymnasium.Env.reset"><code class="xref py py-meth docutils literal notranslate"><span class="pre">reset()</span></code></a>.</p>
|
||
<p>Within our custom environment, the <a class="reference internal" href="../../api/env/#gymnasium.Env.reset" title="gymnasium.Env.reset"><code class="xref py py-meth docutils literal notranslate"><span class="pre">reset()</span></code></a> needs to randomly choose the agent and target’s positions (we repeat this if they have the same position). The return type of <a class="reference internal" href="../../api/env/#gymnasium.Env.reset" title="gymnasium.Env.reset"><code class="xref py py-meth docutils literal notranslate"><span class="pre">reset()</span></code></a> is a tuple of the initial observation and any auxiliary information. Therefore, we can use the methods <code class="docutils literal notranslate"><span class="pre">_get_obs</span></code> and <code class="docutils literal notranslate"><span class="pre">_get_info</span></code> that we implemented earlier for that:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">def</span><span class="w"> </span><span class="nf">reset</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">seed</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">options</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">dict</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
|
||
<span class="c1"># We need the following line to seed self.np_random</span>
|
||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">reset</span><span class="p">(</span><span class="n">seed</span><span class="o">=</span><span class="n">seed</span><span class="p">)</span>
|
||
|
||
<span class="c1"># Choose the agent's location uniformly at random</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_agent_location</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">np_random</span><span class="o">.</span><span class="n">integers</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>
|
||
|
||
<span class="c1"># We will sample the target's location randomly until it does not coincide with the agent's location</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_target_location</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_agent_location</span>
|
||
<span class="k">while</span> <span class="n">np</span><span class="o">.</span><span class="n">array_equal</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_target_location</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_agent_location</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_target_location</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">np_random</span><span class="o">.</span><span class="n">integers</span><span class="p">(</span>
|
||
<span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="nb">int</span>
|
||
<span class="p">)</span>
|
||
|
||
<span class="n">observation</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_obs</span><span class="p">()</span>
|
||
<span class="n">info</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_info</span><span class="p">()</span>
|
||
|
||
<span class="k">return</span> <span class="n">observation</span><span class="p">,</span> <span class="n">info</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="step-function">
|
||
<h2>Step function<a class="headerlink" href="#step-function" title="Link to this heading">¶</a></h2>
|
||
<p>The <a class="reference internal" href="../../api/env/#gymnasium.Env.step" title="gymnasium.Env.step"><code class="xref py py-meth docutils literal notranslate"><span class="pre">step()</span></code></a> method usually contains most of the logic for your environment, it accepts an <code class="docutils literal notranslate"><span class="pre">action</span></code> and computes the state of the environment after the applying the action, returning a tuple of the next observation, the resulting reward, if the environment has terminated, if the environment has truncated and auxiliary information.</p>
|
||
<p>For our environment, several things need to happen during the step function:</p>
|
||
<blockquote>
|
||
<div><ul class="simple">
|
||
<li><p>We use the self._action_to_direction to convert the discrete action (e.g., 2) to a grid direction with our agent location. To prevent the agent from going out of bounds of the grid, we clip the agent’s location to stay within bounds.</p></li>
|
||
<li><p>We compute the agent’s reward by checking if the agent’s current position is equal to the target’s location.</p></li>
|
||
<li><p>Since the environment doesn’t truncate internally (we can apply a time limit wrapper to the environment during <a class="reference internal" href="../../api/registry/#gymnasium.make" title="gymnasium.make"><code class="xref py py-meth docutils literal notranslate"><span class="pre">make()</span></code></a>), we permanently set truncated to False.</p></li>
|
||
<li><p>We once again use _get_obs and _get_info to obtain the agent’s observation and auxiliary information.</p></li>
|
||
</ul>
|
||
</div></blockquote>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">def</span><span class="w"> </span><span class="nf">step</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">action</span><span class="p">):</span>
|
||
<span class="c1"># Map the action (element of {0,1,2,3}) to the direction we walk in</span>
|
||
<span class="n">direction</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_action_to_direction</span><span class="p">[</span><span class="n">action</span><span class="p">]</span>
|
||
<span class="c1"># We use `np.clip` to make sure we don't leave the grid bounds</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_agent_location</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">clip</span><span class="p">(</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_agent_location</span> <span class="o">+</span> <span class="n">direction</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">-</span> <span class="mi">1</span>
|
||
<span class="p">)</span>
|
||
|
||
<span class="c1"># An environment is completed if and only if the agent has reached the target</span>
|
||
<span class="n">terminated</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array_equal</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_agent_location</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_target_location</span><span class="p">)</span>
|
||
<span class="n">truncated</span> <span class="o">=</span> <span class="kc">False</span>
|
||
<span class="n">reward</span> <span class="o">=</span> <span class="mi">1</span> <span class="k">if</span> <span class="n">terminated</span> <span class="k">else</span> <span class="mi">0</span> <span class="c1"># the agent is only reached at the end of the episode</span>
|
||
<span class="n">observation</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_obs</span><span class="p">()</span>
|
||
<span class="n">info</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_info</span><span class="p">()</span>
|
||
|
||
<span class="k">return</span> <span class="n">observation</span><span class="p">,</span> <span class="n">reward</span><span class="p">,</span> <span class="n">terminated</span><span class="p">,</span> <span class="n">truncated</span><span class="p">,</span> <span class="n">info</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="registering-and-making-the-environment">
|
||
<h2>Registering and making the environment<a class="headerlink" href="#registering-and-making-the-environment" title="Link to this heading">¶</a></h2>
|
||
<p>While it is possible to use your new custom environment now immediately, it is more common for environments to be initialized using <a class="reference internal" href="../../api/registry/#gymnasium.make" title="gymnasium.make"><code class="xref py py-meth docutils literal notranslate"><span class="pre">gymnasium.make()</span></code></a>. In this section, we explain how to register a custom environment then initialize it.</p>
|
||
<p>The environment ID consists of three components, two of which are optional: an optional namespace (here: <code class="docutils literal notranslate"><span class="pre">gymnasium_env</span></code>), a mandatory name (here: <code class="docutils literal notranslate"><span class="pre">GridWorld</span></code>) and an optional but recommended version (here: v0). It may have also be registered as <code class="docutils literal notranslate"><span class="pre">GridWorld-v0</span></code> (the recommended approach), <code class="docutils literal notranslate"><span class="pre">GridWorld</span></code> or <code class="docutils literal notranslate"><span class="pre">gymnasium_env/GridWorld</span></code>, and the appropriate ID should then be used during environment creation.</p>
|
||
<p>The entry point can be a string or function, as this tutorial isn’t part of a python project, we cannot use a string but for most environments, this is the normal way of specifying the entry point.</p>
|
||
<p>Register has additionally parameters that can be used to specify keyword arguments to the environment, e.g., if to apply a time limit wrapper, etc. See <a class="reference internal" href="../../api/registry/#gymnasium.register" title="gymnasium.register"><code class="xref py py-meth docutils literal notranslate"><span class="pre">gymnasium.register()</span></code></a> for more information.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">gym</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
|
||
<span class="nb">id</span><span class="o">=</span><span class="s2">"gymnasium_env/GridWorld-v0"</span><span class="p">,</span>
|
||
<span class="n">entry_point</span><span class="o">=</span><span class="n">GridWorldEnv</span><span class="p">,</span>
|
||
<span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>For a more complete guide on registering a custom environment (including with a string entry point), please read the full <a class="reference internal" href="../../tutorials/gymnasium_basics/environment_creation/"><span class="doc std std-doc">create environment</span></a> tutorial.</p>
|
||
<p>Once the environment is registered, you can check via <a class="reference internal" href="../../api/registry/#gymnasium.pprint_registry" title="gymnasium.pprint_registry"><code class="xref py py-meth docutils literal notranslate"><span class="pre">gymnasium.pprint_registry()</span></code></a> which will output all registered environment, and the environment can then be initialized using <a class="reference internal" href="../../api/registry/#gymnasium.make" title="gymnasium.make"><code class="xref py py-meth docutils literal notranslate"><span class="pre">gymnasium.make()</span></code></a>. A vectorized version of the environment with multiple instances of the same environment running in parallel can be instantiated with <a class="reference internal" href="../../api/registry/#gymnasium.make_vec" title="gymnasium.make_vec"><code class="xref py py-meth docutils literal notranslate"><span class="pre">gymnasium.make_vec()</span></code></a>.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">gymnasium</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">gym</span>
|
||
<span class="o">>>></span> <span class="n">gym</span><span class="o">.</span><span class="n">make</span><span class="p">(</span><span class="s2">"gymnasium_env/GridWorld-v0"</span><span class="p">)</span>
|
||
<span class="o"><</span><span class="n">OrderEnforcing</span><span class="o"><</span><span class="n">PassiveEnvChecker</span><span class="o"><</span><span class="n">GridWorld</span><span class="o"><</span><span class="n">gymnasium_env</span><span class="o">/</span><span class="n">GridWorld</span><span class="o">-</span><span class="n">v0</span><span class="o">>>>></span>
|
||
<span class="o">>>></span> <span class="n">gym</span><span class="o">.</span><span class="n">make</span><span class="p">(</span><span class="s2">"gymnasium_env/GridWorld-v0"</span><span class="p">,</span> <span class="n">max_episode_steps</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
|
||
<span class="o"><</span><span class="n">TimeLimit</span><span class="o"><</span><span class="n">OrderEnforcing</span><span class="o"><</span><span class="n">PassiveEnvChecker</span><span class="o"><</span><span class="n">GridWorld</span><span class="o"><</span><span class="n">gymnasium_env</span><span class="o">/</span><span class="n">GridWorld</span><span class="o">-</span><span class="n">v0</span><span class="o">>>>>></span>
|
||
<span class="o">>>></span> <span class="n">env</span> <span class="o">=</span> <span class="n">gym</span><span class="o">.</span><span class="n">make</span><span class="p">(</span><span class="s2">"gymnasium_env/GridWorld-v0"</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
|
||
<span class="o">>>></span> <span class="n">env</span><span class="o">.</span><span class="n">unwrapped</span><span class="o">.</span><span class="n">size</span>
|
||
<span class="mi">10</span>
|
||
<span class="o">>>></span> <span class="n">gym</span><span class="o">.</span><span class="n">make_vec</span><span class="p">(</span><span class="s2">"gymnasium_env/GridWorld-v0"</span><span class="p">,</span> <span class="n">num_envs</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>
|
||
<span class="n">SyncVectorEnv</span><span class="p">(</span><span class="n">gymnasium_env</span><span class="o">/</span><span class="n">GridWorld</span><span class="o">-</span><span class="n">v0</span><span class="p">,</span> <span class="n">num_envs</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="using-wrappers">
|
||
<h2>Using Wrappers<a class="headerlink" href="#using-wrappers" title="Link to this heading">¶</a></h2>
|
||
<p>Oftentimes, we want to use different variants of a custom environment, or we want to modify the behavior of an environment that is provided by Gymnasium or some other party. Wrappers allow us to do this without changing the environment implementation or adding any boilerplate code. Check out the <a class="reference internal" href="../../api/wrappers/"><span class="doc std std-doc">wrapper documentation</span></a> for details on how to use wrappers and instructions for implementing your own. In our example, observations cannot be used directly in learning code because they are dictionaries. However, we don’t actually need to touch our environment implementation to fix this! We can simply add a wrapper on top of environment instances to flatten observations into a single array:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span><span class="w"> </span><span class="nn">gymnasium.wrappers</span><span class="w"> </span><span class="kn">import</span> <span class="n">FlattenObservation</span>
|
||
|
||
<span class="gp">>>> </span><span class="n">env</span> <span class="o">=</span> <span class="n">gym</span><span class="o">.</span><span class="n">make</span><span class="p">(</span><span class="s1">'gymnasium_env/GridWorld-v0'</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">env</span><span class="o">.</span><span class="n">observation_space</span>
|
||
<span class="go">Dict('agent': Box(0, 4, (2,), int64), 'target': Box(0, 4, (2,), int64))</span>
|
||
<span class="gp">>>> </span><span class="n">env</span><span class="o">.</span><span class="n">reset</span><span class="p">()</span>
|
||
<span class="go">({'agent': array([4, 1]), 'target': array([2, 4])}, {'distance': 5.0})</span>
|
||
<span class="gp">>>> </span><span class="n">wrapped_env</span> <span class="o">=</span> <span class="n">FlattenObservation</span><span class="p">(</span><span class="n">env</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">wrapped_env</span><span class="o">.</span><span class="n">observation_space</span>
|
||
<span class="go">Box(0, 4, (4,), int64)</span>
|
||
<span class="gp">>>> </span><span class="n">wrapped_env</span><span class="o">.</span><span class="n">reset</span><span class="p">()</span>
|
||
<span class="go">(array([3, 0, 2, 1]), {'distance': 2.0})</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
|
||
</article>
|
||
</div>
|
||
<footer>
|
||
|
||
<div class="related-pages">
|
||
<a class="next-page" href="../record_agent/">
|
||
<div class="page-info">
|
||
<div class="context">
|
||
<span>Next</span>
|
||
</div>
|
||
<div class="title">Recording Agents</div>
|
||
</div>
|
||
<svg class="furo-related-icon">
|
||
<use href="#svg-arrow-right"></use>
|
||
</svg>
|
||
</a>
|
||
<a class="prev-page" href="../train_agent/">
|
||
<svg class="furo-related-icon">
|
||
<use href="#svg-arrow-right"></use>
|
||
</svg>
|
||
<div class="page-info">
|
||
<div class="context">
|
||
<span>Previous</span>
|
||
</div>
|
||
|
||
<div class="title">Training an Agent</div>
|
||
|
||
</div>
|
||
</a>
|
||
</div>
|
||
<div class="bottom-of-page">
|
||
<div class="left-details">
|
||
<div class="copyright">
|
||
Copyright © 2025 Farama Foundation
|
||
</div>
|
||
<!--
|
||
Made with <a href="https://www.sphinx-doc.org/">Sphinx</a> and <a class="muted-link" href="https://pradyunsg.me">@pradyunsg</a>'s
|
||
|
||
<a href="https://github.com/pradyunsg/furo">Furo</a>
|
||
-->
|
||
</div>
|
||
<div class="right-details">
|
||
<div class="icons">
|
||
<a class="muted-link" href="https://github.com/Farama-Foundation/Gymnasium/"
|
||
aria-label="On GitHub">
|
||
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
|
||
<path fill-rule="evenodd"
|
||
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z">
|
||
</path>
|
||
</svg>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</footer>
|
||
</div>
|
||
<aside class="toc-drawer">
|
||
|
||
|
||
<div class="toc-sticky toc-scroll">
|
||
<div class="toc-title-container">
|
||
<span class="toc-title">
|
||
On this page
|
||
</span>
|
||
</div>
|
||
<div class="toc-tree-container">
|
||
<div class="toc-tree">
|
||
<ul>
|
||
<li><a class="reference internal" href="#">Create a Custom Environment</a><ul>
|
||
<li><a class="reference internal" href="#environment-init">Environment <code class="docutils literal notranslate"><span class="pre">__init__</span></code></a></li>
|
||
<li><a class="reference internal" href="#constructing-observations">Constructing Observations</a></li>
|
||
<li><a class="reference internal" href="#reset-function">Reset function</a></li>
|
||
<li><a class="reference internal" href="#step-function">Step function</a></li>
|
||
<li><a class="reference internal" href="#registering-and-making-the-environment">Registering and making the environment</a></li>
|
||
<li><a class="reference internal" href="#using-wrappers">Using Wrappers</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
</aside>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script>
|
||
const toggleMenu = () => {
|
||
const menuBtn = document.querySelector(".farama-header-menu__btn");
|
||
const menuContainer = document.querySelector(".farama-header-menu-container");
|
||
if (document.querySelector(".farama-header-menu").classList.contains("active")) {
|
||
menuBtn.setAttribute("aria-expanded", "false");
|
||
menuContainer.setAttribute("aria-hidden", "true");
|
||
} else {
|
||
menuBtn.setAttribute("aria-expanded", "true");
|
||
menuContainer.setAttribute("aria-hidden", "false");
|
||
}
|
||
document.querySelector(".farama-header-menu").classList.toggle("active");
|
||
}
|
||
|
||
document.querySelector(".farama-header-menu__btn").addEventListener("click", toggleMenu);
|
||
document.getElementById("farama-close-menu").addEventListener("click", toggleMenu);
|
||
</script>
|
||
|
||
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-6H9C8TWXZ8"></script>
|
||
<script>
|
||
const enableGtag = () => {
|
||
window.dataLayer = window.dataLayer || [];
|
||
function gtag(){dataLayer.push(arguments);}
|
||
gtag('js', new Date());
|
||
gtag('config', 'G-6H9C8TWXZ8');
|
||
}
|
||
(() => {
|
||
if (!localStorage.getItem("acceptedCookieAlert")) {
|
||
const boxElem = document.createElement("div");
|
||
boxElem.classList.add("cookie-alert");
|
||
const containerElem = document.createElement("div");
|
||
containerElem.classList.add("cookie-alert__container");
|
||
const textElem = document.createElement("p");
|
||
textElem.innerHTML = `This page uses <a href="https://analytics.google.com/">
|
||
Google Analytics</a> to collect statistics.`;
|
||
containerElem.appendChild(textElem);
|
||
|
||
const declineBtn = Object.assign(document.createElement("button"),
|
||
{
|
||
innerText: "Deny",
|
||
className: "farama-btn cookie-alert__button",
|
||
id: "cookie-alert__decline",
|
||
}
|
||
);
|
||
declineBtn.addEventListener("click", () => {
|
||
localStorage.setItem("acceptedCookieAlert", false);
|
||
boxElem.remove();
|
||
});
|
||
|
||
const acceptBtn = Object.assign(document.createElement("button"),
|
||
{
|
||
innerText: "Allow",
|
||
className: "farama-btn cookie-alert__button",
|
||
id: "cookie-alert__accept",
|
||
}
|
||
);
|
||
acceptBtn.addEventListener("click", () => {
|
||
localStorage.setItem("acceptedCookieAlert", true);
|
||
boxElem.remove();
|
||
enableGtag();
|
||
});
|
||
|
||
containerElem.appendChild(declineBtn);
|
||
containerElem.appendChild(acceptBtn);
|
||
boxElem.appendChild(containerElem);
|
||
document.body.appendChild(boxElem);
|
||
} else if (localStorage.getItem("acceptedCookieAlert") === "true") {
|
||
enableGtag();
|
||
}
|
||
})()
|
||
</script>
|
||
|
||
<script src="../../_static/documentation_options.js?v=25d39d6f"></script>
|
||
<script src="../../_static/doctools.js?v=9a2dae69"></script>
|
||
<script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
|
||
<script src="../../_static/scripts/furo.js?v=7660844c"></script>
|
||
|
||
<script>
|
||
|
||
const createProjectsList = (projects, displayImages) => {
|
||
const ulElem = Object.assign(document.createElement('ul'),
|
||
{
|
||
className:'farama-header-menu-list',
|
||
}
|
||
)
|
||
for (let project of projects) {
|
||
const liElem = document.createElement("li");
|
||
const aElem = Object.assign(document.createElement("a"),
|
||
{
|
||
href: project.link
|
||
}
|
||
);
|
||
liElem.appendChild(aElem);
|
||
if (displayImages) {
|
||
const imgElem = Object.assign(document.createElement("img"),
|
||
{
|
||
src: project.image ? imagesBasepath + project.image : imagesBasepath + "/farama_black.svg",
|
||
alt: `${project.name} logo`,
|
||
className: "farama-black-logo-invert"
|
||
}
|
||
);
|
||
aElem.appendChild(imgElem);
|
||
}
|
||
aElem.appendChild(document.createTextNode(project.name));
|
||
ulElem.appendChild(liElem);
|
||
}
|
||
return ulElem;
|
||
}
|
||
|
||
// Create menu with Farama projects by using the API at farama.org/api/projects.json
|
||
const createCORSRequest = (method, url) => {
|
||
let xhr = new XMLHttpRequest();
|
||
xhr.responseType = 'json';
|
||
|
||
if ("withCredentials" in xhr) {
|
||
xhr.open(method, url, true);
|
||
} else if (typeof XDomainRequest != "undefined") {
|
||
// IE8 & IE9
|
||
xhr = new XDomainRequest();
|
||
xhr.open(method, url);
|
||
} else {
|
||
// CORS not supported.
|
||
xhr = null;
|
||
}
|
||
return xhr;
|
||
};
|
||
|
||
const url = 'https://farama.org/api/projects.json';
|
||
const imagesBasepath = "https://farama.org/assets/images"
|
||
const method = 'GET';
|
||
let xhr = createCORSRequest(method, url);
|
||
|
||
xhr.onload = () => {
|
||
const jsonResponse = xhr.response;
|
||
const sections = {
|
||
"Core Projects": [],
|
||
"Mature Projects": {
|
||
"Documentation": [],
|
||
"Repositories": [],
|
||
},
|
||
"Incubating Projects": {
|
||
"Documentation": [],
|
||
"Repositories": [],
|
||
},
|
||
"Foundation": [
|
||
{
|
||
name: "About",
|
||
link: "https://farama.org/about"
|
||
},
|
||
{
|
||
name: "Standards",
|
||
link: "https://farama.org/project_standards",
|
||
},
|
||
{
|
||
name: "Donate",
|
||
link: "https://farama.org/donations"
|
||
}
|
||
]
|
||
}
|
||
|
||
// Categorize projects
|
||
Object.keys(jsonResponse).forEach(key => {
|
||
projectJson = jsonResponse[key];
|
||
if (projectJson.website !== null) {
|
||
projectJson.link = projectJson.website;
|
||
} else {
|
||
projectJson.link = projectJson.github;
|
||
}
|
||
if (projectJson.type === "core") {
|
||
sections["Core Projects"].push(projectJson)
|
||
} else if (projectJson.type == "mature") {
|
||
if (projectJson.website !== null) {
|
||
sections["Mature Projects"]["Documentation"].push(projectJson)
|
||
} else {
|
||
sections["Mature Projects"]["Repositories"].push(projectJson)
|
||
}
|
||
} else {
|
||
if (projectJson.website !== null) {
|
||
sections["Incubating Projects"]["Documentation"].push(projectJson)
|
||
} else {
|
||
sections["Incubating Projects"]["Repositories"].push(projectJson)
|
||
}
|
||
}
|
||
})
|
||
|
||
const menuContainer = document.querySelector(".farama-header-menu__body");
|
||
|
||
Object.keys(sections).forEach((key, i) => {
|
||
const sectionElem = Object.assign(
|
||
document.createElement('div'), {
|
||
className:'farama-header-menu__section',
|
||
}
|
||
)
|
||
sectionElem.appendChild(Object.assign(document.createElement('span'),
|
||
{
|
||
className:'farama-header-menu__section-title' ,
|
||
innerText: key
|
||
}
|
||
))
|
||
// is not a list
|
||
if (sections[key].constructor !== Array) {
|
||
const subSections = sections[key];
|
||
const subSectionContainerElem = Object.assign(
|
||
document.createElement('div'), {
|
||
className:'farama-header-menu__subsections-container',
|
||
style: 'display: flex'
|
||
}
|
||
)
|
||
Object.keys(subSections).forEach((subKey, i) => {
|
||
const subSectionElem = Object.assign(
|
||
document.createElement('div'), {
|
||
className:'farama-header-menu__subsection',
|
||
}
|
||
)
|
||
subSectionElem.appendChild(Object.assign(document.createElement('span'),
|
||
{
|
||
className:'farama-header-menu__subsection-title' ,
|
||
innerText: subKey
|
||
}
|
||
))
|
||
const ulElem = createProjectsList(subSections[subKey], key !== 'Foundation');
|
||
subSectionElem.appendChild(ulElem);
|
||
subSectionContainerElem.appendChild(subSectionElem);
|
||
})
|
||
sectionElem.appendChild(subSectionContainerElem);
|
||
} else {
|
||
const projects = sections[key];
|
||
const ulElem = createProjectsList(projects, true);
|
||
sectionElem.appendChild(ulElem);
|
||
}
|
||
menuContainer.appendChild(sectionElem)
|
||
});
|
||
}
|
||
|
||
xhr.onerror = function() {
|
||
console.error("Unable to load projects");
|
||
};
|
||
|
||
xhr.send();
|
||
</script>
|
||
|
||
|
||
<script>
|
||
const versioningConfig = {
|
||
githubUser: 'Farama-Foundation',
|
||
githubRepo: 'Gymnasium',
|
||
};
|
||
fetch('/main/_static/versioning/versioning_menu.html').then(response => {
|
||
if (response.status === 200) {
|
||
response.text().then(text => {
|
||
const container = document.createElement("div");
|
||
container.innerHTML = text;
|
||
document.querySelector("body").appendChild(container);
|
||
// innerHtml doenst evaluate scripts, we need to add them dynamically
|
||
Array.from(container.querySelectorAll("script")).forEach(oldScript => {
|
||
const newScript = document.createElement("script");
|
||
Array.from(oldScript.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value));
|
||
newScript.appendChild(document.createTextNode(oldScript.innerHTML));
|
||
oldScript.parentNode.replaceChild(newScript, oldScript);
|
||
});
|
||
});
|
||
} else {
|
||
console.warn("Unable to load versioning menu", response);
|
||
}
|
||
});
|
||
</script>
|
||
|
||
</body>
|
||
</html> |