Skip to main content

gym-zelda-1

BuildStatus PackageVersion PythonVersion Stable Format License

A Gymnasium environment for The Legend of Zelda (i.e., Zelda 1) on The Nintendo Entertainment System (NES) based on the nes-py emulator. This wrapper keeps a deliberately narrow, lower-maturity scope: it exposes Zelda RAM state and NES control semantics for experimentation, while expecting users to supply their own legally obtained ROM and task-specific training wrappers. CI currently tests CPython 3.13 and 3.14 on macOS, Linux, and Windows.

Installation

The preferred installation of gym-zelda-1 is from pip:

pip install gym-zelda-1

Python 3.13 or newer is required. The supported CI targets are CPython 3.13 and 3.14.

gym-zelda-1 does not distribute Nintendo ROM assets. Provide your own legally obtained Zelda ROM through the package's expected local workflow.

Usage

Python

You must import gym_zelda_1 before trying to make an environment. This is because Gymnasium environments are registered at runtime. By default, gym_zelda_1 environments use the full NES action space of 256 discrete actions. To constrain this, gym_zelda_1.actions provides an action list called MOVEMENT (20 discrete actions) for the nes_py.wrappers.JoypadSpace wrapper.

import gymnasium as gym
from nes_py.wrappers import JoypadSpace
import gym_zelda_1
from gym_zelda_1.actions import MOVEMENT

env = gym.make('Zelda1-v0', render_mode='human')
env = JoypadSpace(env, MOVEMENT)

observation, info = env.reset(seed=123)
for step in range(5000):
    action = env.action_space.sample()
    observation, reward, terminated, truncated, info = env.step(action)
    done = terminated or truncated
    env.render()

    if done:
        observation, info = env.reset()

env.close()

NOTE: gym_zelda_1.make is just an alias to gymnasium.make for convenience.

NOTE: remove calls to render in training code for a nontrivial speedup.

Command Line

gym_zelda_1 features a command line interface for playing environments using either the keyboard, or uniform random movement.

Print the command-line help with:

gym_zelda_1 -h
gym_zelda_1 --mode human --actionspace movement
gym_zelda_1 --mode random --steps 500 --render --actionspace movement
gym_zelda_1 --mode random --steps 5000 --no-render --seed 123 --actionspace movement --no-progress

Use --actionspace full for the default 256-action NES controller space, or --actionspace movement for the gym_zelda_1.actions.MOVEMENT preset with nes_py.wrappers.JoypadSpace. Human mode always requires rendering; headless --no-render playback is available in random mode.

Step

Info about the rewards and info returned by the step method.

Zelda1-v0 is a navigation and state-inspection sandbox. It exposes Zelda RAM state through info, preserves the full NES action and observation contract, and leaves task objectives such as route completion, dungeon progress, or time limits to caller-provided wrappers.

Reward Function

The reward is always 0.0. This neutral reward is deliberate: the current v0 environment does not infer long-horizon Zelda progress from partial RAM signals. Use external wrappers when training against a specific navigation, combat, or collection objective.

Termination and Truncation

The environment has no internal terminal condition. terminated is always False for Zelda1-v0; death is treated as a non-terminal recovery sequence. When Link reaches zero health, the environment advances through the death and continue flow before subsequent gameplay continues.

Low health is characterized by the health meter as being above zero and at or below one heart. The pulse 2 audio RAM byte can identify transient death and continue cues (Death Spiral and Continue Screen), but these cues are not used as episode lifecycle signals in v0. The registered Zelda1-v0 spec does not set max_episode_steps, so Gymnasium does not add a registration-level TimeLimit; truncated remains False unless a caller applies an external limit wrapper.

info dictionary

The info dictionary returned by the step method contains the following keys:

Key Type Description
current_level int The current level Link is in (0 for overworld)
x_pos int Link's x position in the screen (from the left)
y_pos int Link's y position in the screen (from the top)
direction str Link's direction as one of {"N", "S", "E", "W"}
has_candled bool Whether Link has candled the current room
pulse_1 str The signal playing through pulse 1
pulse_2 str The signal playing through pulse 2
killed_enemies int The number of enemies killed
number_of_deaths int The number of times Link has died
sword str The kind of sword Link has
number_of_bombs int The number of bombs in Link's inventory
arrows_type str The kind of arrows in Link's inventory
has_bow bool Whether Link has the bow in his inventory
candle_type str The type of candle in Link's inventory
has_whistle bool Whether Link has the whistle in his inventory
has_food bool Whether Link has food in his inventory
potion_type str The type of potion in Link's inventory
has_magic_rod bool Whether Link has the magic rod in his inventory
has_raft bool Whether Link has the raft in his inventory
has_magic_book bool Whether Link has the magic book in his inventory
ring_type str The type of ring in Link's inventory
has_step_ladder bool Whether Link has the step ladder in his inventory
has_magic_key bool Whether Link has the magic key in his inventory
has_power_bracelet bool Whether Link has the power bracelet in his inventory
has_letter bool Whether Link has the letter in his inventory
is_clock_possessed bool Whether the clock is possessed
rupees int The number of rupees Link has collected
keys int The number of keys in Link's inventory
heart_containers int The number of heart containers that Link has
hearts float The number of remaining health Link has
has_boomerang bool Whether Link has the boomerang in his inventory
has_magic_boomerang bool Whether Link has the magic boomerang in his inventory
has_magic_shield bool Whether Link has the magic shield in his inventory
max_number_of_bombs int The maximum number of bombs Link can carry

Publishing

PyPI releases are published by the Publish to PyPI GitHub Actions workflow through PyPI trusted publishing, not by local twine credentials. Configure the PyPI project publisher with owner Kautenja, repository gym-zelda-1, workflow filename publish.yml, and environment pypi.

Releases should follow the current GitHub Actions flow:

  1. Create and push a tag that matches pyproject.toml's version, with or without a leading v.
  2. Let the CI workflow build and attach release artifacts for that tag.
  3. Publish a GitHub Release from that tag to trigger the trusted-publishing workflow.

Citation

Please cite gym-zelda-1 if you use it in your research.

@misc{gym-zelda-1,
  author = {Christian Kauten},
  howpublished = {GitHub},
  title = {{The Legend of Zelda} for {Gymnasium}},
  URL = {https://github.com/Kautenja/gym-zelda-1},
  year = {2019},
}

References

The following references contributed to the construction of this project.

  1. The Legend of Zelda: RAM Map. Data Crystal ROM Hacking.
  2. The Legend of Zelda: Memory Addresses. NES Hacker.

Metadata

Release files for gym-zelda-1 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gym-zelda-1 0.3.0
File Size Uploaded
gym_zelda_1-0.3.0.tar.gz 82.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for gym-zelda-1 0.3.0
File Interpreter ABI Platform
gym_zelda_1-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 160.2 kB

Release files / gym_zelda_1-0.3.0.tar.gz

Download URL gym_zelda_1-0.3.0.tar.gz
Size 82.2 kB
Tags Source
SHA-256 checksum
How to use checksums
57bd0226866dc22d5faeb9e863c2b325a8ac9581543ab614a00266672793b3fe
BLAKE2b-256 checksum
How to use checksums
b97f028abfda2a1f3429ce665fabd6780255ed8f8cf85c50da9a7bc5ffc990a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 18, 2026.

Transparency log

Release files / gym_zelda_1-0.3.0-py3-none-any.whl

Download URL gym_zelda_1-0.3.0-py3-none-any.whl
Size 78.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3d130db3ca8303e99dd691c6faca4a26096532383041b76e01e56ef8b530987d
BLAKE2b-256 checksum
How to use checksums
52f460897dd39a265c3c7472834c36a1a5a7a3dc55d2e8a2548e5a3e9e61e78d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 18, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.2

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page