Skip to main content

An NES Emulator and Gymnasium interface

Project description

build-status PackageVersion PythonVersion Stable Format License

nes-py

nes-py is a native NES emulator with a modern Gymnasium interface for reinforcement learning, scripted gameplay, emulator experimentation, and custom environment design. It runs on macOS, Linux, and Windows, builds on the SimpleNES emulator, and currently supports CPython 3.13 and 3.14 in CI.

Bring your own legally obtained .nes ROM, then use nes-py directly as a Gymnasium environment, from the bundled command-line player, or through one of the game-specific environment packages in the same ecosystem.

Highlights

  • Gymnasium-native reset, step, render-mode, and seeding semantics.
  • Native C++ emulator core packaged as the nes_py._native extension.
  • Manual, random, windowed, and headless command-line play modes.
  • NES joypad wrappers for compact reinforcement-learning action spaces.
  • Mapper support for common cartridges including NROM, MMC1, UxROM, CNROM, MMC3, MMC5, AxROM, MMC2, and Sunsoft FME-7.
  • Cross-platform wheels and source distributions published through PyPI trusted publishing.
Bomberman II Castlevania II Excitebike
Super Mario Bros. The Legend of Zelda Tetris
Contra Mega Man II Bubble Bobble

Ecosystem

Use nes-py directly for arbitrary NES ROMs, or start from one of the focused Gymnasium environment packages:

Installation

Install nes-py from PyPI:

pip install nes-py

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

Binary wheels are published for Linux, macOS, and Windows on those supported Python versions. If pip cannot find a compatible wheel for your interpreter or platform, it will fall back to a source build and therefore needs a working native C++ toolchain in the active environment.

Debian

Make sure you have the clang++ compiler installed:

sudo apt-get install clang

Windows

You'll need to install the Visual-Studio 17.0 tools for Windows installation. The Visual Studio Community package provides these tools for free.

Native Runtime Troubleshooting

nes-py ships a native extension, so import-time loader failures usually point to a compiler-runtime mismatch rather than a Python API bug.

  • On Linux, errors mentioning GLIBCXX_* not found mean the active libstdc++.so.6 is older than the one expected by the installed wheel or build artifacts. Update the environment's C++ runtime, use a newer distribution/toolchain, or rebuild from source inside the target environment with pip install --no-binary nes-py nes-py.
  • On Windows, build failures usually mean the MSVC C++ build tools are missing from the selected Python environment. Install Visual Studio Build Tools 2022 or the full Visual Studio Community package with the desktop C++ workload.
  • If you are using conda, venv, or another isolated environment manager, make sure the compiler runtime loaded at import time matches the Python environment where nes-py was installed.

Usage

Command Line

Launch an interactive emulator session with a local ROM:

python3 -m nes_py.play --rom <path_to_rom>

The installed console script exposes the same interface:

nes_py --rom <path_to_rom>

Print the command-line help with:

python3 -m nes_py.play -h

The play command supports keyboard controls and random controls. Random play is handy for smoke tests and can run with or without a graphical window:

python3 -m nes_py.play --rom <path_to_rom> --mode random --steps 500
python3 -m nes_py.play --rom <path_to_rom> --mode random --steps 500 --no-render

Python API

Construct the environment with the desired Gymnasium render mode, seed through reset, and handle the separated termination and truncation flags:

from nes_py.nes_env import NESEnv

env = NESEnv("<path_to_rom>", render_mode="rgb_array")
observation, info = env.reset(seed=123)
terminated = False
truncated = False

while not (terminated or truncated):
    action = env.action_space.sample()
    observation, reward, terminated, truncated, info = env.step(action)
    frame = env.render()

env.close()

ML Observation Helpers

NESEnv.step and render in rgb_array mode keep returning the default (240, 256, 3) uint8 RGB screen view. That view is zero-copy, but it is strided over the native 32-bit screen buffer. Training loops that need a C-contiguous RGB frame or a grayscale frame can opt into explicit copy helpers and reuse output buffers:

import numpy as np

from nes_py.nes_env import NESEnv
from nes_py.nes_env import SCREEN_SHAPE_24_BIT
from nes_py.nes_env import SCREEN_SHAPE_GRAYSCALE

env = NESEnv("<path_to_rom>")
rgb = np.empty(SCREEN_SHAPE_24_BIT, dtype=np.uint8)
gray = np.empty(SCREEN_SHAPE_GRAYSCALE, dtype=np.uint8)

observation, info = env.reset()
contiguous_rgb = env.observation("rgb_array_contiguous", output=rgb)
grayscale = env.observation("grayscale", output=gray)

The helpers are intended for measured ML pipelines, not as a replacement for Gymnasium's default observation contract. Benchmark local workloads with:

python3 -m nes_py.speedtest --rom <path_to_rom> --observation-profile --no-progress

Vector, RAM, and Snapshot Helpers

Same-ROM training loops can opt into a native vector emulator that batches controller writes, frame stepping, observation copies, RAM readback, and per-slot resets without moving game-specific reward or info logic into nes-py:

import numpy as np

from nes_py.vector_env import VectorNESEmulator

vector = VectorNESEmulator("<path_to_rom>", 4)
vector.reset()
screens = vector.step(np.array([0, 1, 2, 3], dtype=np.uint8))
gray = vector.observation("grayscale")
ram_values = vector.ram_values((0x0000, (0x0001, 2, "little")))
snapshot = vector.dump_state(0)
vector.load_state(0, snapshot)
vector.close()

Scalar NESEnv also exposes ram_values(specs, output=None), dump_state(), and load_state(snapshot). Snapshots are opaque same-process checkpoint objects, not a stable cross-version save-state format.

Design notes and benchmark decisions live in:

  • docs/vector-native-emulator.md
  • docs/native-batch-ram-info-reads.md
  • docs/vector-throughput-instrumentation.md
  • docs/explicit-state-snapshot-api.md

Controls

Keyboard Key NES Joypad
W Up
A Left
S Down
D Right
O A
P B
Enter Start
Space Select

Parallelism Caveats

Both the threading and multiprocessing packages are supported by nes-py. The rendering caveats only apply to windowed human rendering:

  1. rgb_array rendering is supported from threading.Thread and multiprocessing.Process instances.
  2. human rendering is not supported from instances of threading.Thread; it must run on the process's main Python thread.
  3. human rendering is supported from instances of multiprocessing.Process, but the viewer must be created in the process that owns the render call. Importing nes-py or nes_py.play in a parent process does not initialize the windowing backend.

Development

To design a custom environment, introduce new emulator features, or fix a bug, start with the Wiki. It includes:

  • setting up the development environment
  • designing environments based on the NESEnv class
  • reference material for the NESEnv API
  • documentation for the nes_py.wrappers module

Project metadata, runtime dependencies, release extras, console scripts, and package discovery are configured in pyproject.toml. The native emulator source tree lives under nes_emu, with public and internal headers below nes_emu/include/nes_emu and C++ sources below nes_emu/src/nes_emu. CMake builds those sources into the nes_py._native extension through scikit-build-core. The runtime binding imports nes_py._native directly; the old ctypes shared-library discovery path is no longer used. For local development, install the package in editable mode, run the Python test suite, and build distributions through the standard PEP 517 frontend:

python -m pip install --upgrade pip build
python -m pip install --editable . --config-settings=editable.mode=inplace
python -m unittest discover .
./main.sh clean
python -m build

Native emulator internals use opt-in CMake test and benchmark targets so normal Python installs do not fetch C++ test dependencies:

cmake -S . -B build/nes-emu-debug -DCMAKE_BUILD_TYPE=Debug -DNES_EMU_BUILD_TESTS=ON
cmake --build build/nes-emu-debug --target nes_emu_tests
ctest --test-dir build/nes-emu-debug --output-on-failure
cmake -S . -B build/nes-emu-release -DCMAKE_BUILD_TYPE=Release -DNES_EMU_BUILD_BENCHMARKS=ON
cmake --build build/nes-emu-release --target nes_emu_benchmarks

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 nes-py, workflow filename publish.yml, and environment pypi. Then create a GitHub release from a tag matching pyproject.toml's version, with or without a leading v. The workflow builds the source distribution and CPython 3.13 and 3.14 wheels for Linux, Windows, and macOS before publishing.

Benchmarking

Developer throughput checks are available through the packaged speedtest module:

python -m nes_py.speedtest --rom nes_py/tests/games/super-mario-bros-1.nes --steps 5000

Use --json for machine-readable output. Benchmark numbers are informational and vary by machine, compiler, runner load, and display settings; they are not correctness criteria. Backup and restore stress options use explicit interval semantics, so --backup-interval 12 runs a backup at steps 12, 24, 36, and so on.

Additional profiles are available for ML and vector workflows:

python -m nes_py.speedtest --rom nes_py/tests/games/super-mario-bros-1.nes --observation-profile --json --no-progress
python -m nes_py.speedtest --rom nes_py/tests/games/super-mario-bros-1.nes --ram-profile --json --no-progress
python -m nes_py.speedtest --rom nes_py/tests/games/super-mario-bros-1.nes --vector-profile --runs 5 --env-counts 1,2,4,8,16 --instrumentation --json --no-progress

Cartridge Mapper Compatibility

nes-py supports the following cartridge mappers:

  1. NROM
  2. MMC1 / SxROM
  3. UxROM
  4. CNROM
  5. MMC3 / TxROM
  6. MMC5 / ExROM
  7. AxROM / AOROM
  8. MMC2 / PxROM
  9. Sunsoft FME-7 / Sunsoft 5B

MMC3 support includes PPU A12 observations during the sprite-fetch phase, which keeps scanline IRQ split-screen effects such as Super Mario Bros. 3 status bars aligned with the rendered frame. MMC5 vertical split rendering and MMC5 pulse/PCM audio are not implemented yet. Sunsoft 5B audio register state is preserved, but expansion-audio mixing is not implemented yet. Planned mapper expansion is tracked in the umbrella repository's mapper specs.

Citation

Please cite nes-py if you use it in your research.

@misc{nes-py,
  author = {Christian Kauten},
  howpublished = {GitHub},
  title = {{NES-py}: An {NES} Emulator and {Gymnasium} Interface},
  URL = {https://github.com/Kautenja/nes-py},
  year = {2018},
}

Disclaimer

This project is provided for educational purposes only. It is not affiliated with and has not been approved by Nintendo.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nes_py-9.0.1.tar.gz (113.2 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

nes_py-9.0.1-cp314-cp314-win_amd64.whl (141.6 kB view details)

Uploaded CPython 3.14Windows x86-64

nes_py-9.0.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (158.5 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

nes_py-9.0.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl (150.6 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.24+ ARM64manylinux: glibc 2.28+ ARM64

nes_py-9.0.1-cp314-cp314-macosx_11_0_arm64.whl (137.0 kB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

nes_py-9.0.1-cp314-cp314-macosx_10_15_x86_64.whl (143.9 kB view details)

Uploaded CPython 3.14macOS 10.15+ x86-64

nes_py-9.0.1-cp313-cp313-win_amd64.whl (137.7 kB view details)

Uploaded CPython 3.13Windows x86-64

nes_py-9.0.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (158.0 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

nes_py-9.0.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl (149.3 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.24+ ARM64manylinux: glibc 2.28+ ARM64

nes_py-9.0.1-cp313-cp313-macosx_11_0_arm64.whl (136.5 kB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

nes_py-9.0.1-cp313-cp313-macosx_10_13_x86_64.whl (143.5 kB view details)

Uploaded CPython 3.13macOS 10.13+ x86-64

File details

Details for the file nes_py-9.0.1.tar.gz.

File metadata

  • Download URL: nes_py-9.0.1.tar.gz
  • Upload date:
  • Size: 113.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nes_py-9.0.1.tar.gz
Algorithm Hash digest
SHA256 f9aafc42a90600af39e844b6c0a153fdfc2b7635997cb70be345c22e58b4557b
MD5 1e1706123f5e40c7db7ca713c3721f0b
BLAKE2b-256 c077d27858362aaaea8a371062515ba5c4ae0c48dc482797998485c998c70e8c

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.1.tar.gz:

Publisher: publish.yml on Kautenja/nes-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nes_py-9.0.1-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: nes_py-9.0.1-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 141.6 kB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nes_py-9.0.1-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 f97ff88d504a4a53e40a3a20ff6642367ebb7b9aac3ea397130e80bc425521e0
MD5 95ff028890702071f5a4395cb826e3b9
BLAKE2b-256 1823b60ab177979fc09c94151ca438f815a8e284b6b5a11fcc8bc34a87286d76

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.1-cp314-cp314-win_amd64.whl:

Publisher: publish.yml on Kautenja/nes-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nes_py-9.0.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 20e414ef7300990d2204b1e0fe439fcd1b0a70f5ea18d783db78e23f2cfc3ea5
MD5 a0492ac131f4eb1f020b20dcac596a98
BLAKE2b-256 a72cd6f602b33c3e07dd61a1c01f671b53d1cd39d2e93c54df667a458406f307

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl:

Publisher: publish.yml on Kautenja/nes-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nes_py-9.0.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 65c343f13529ecaa5927d156af6eaa4d06aa4f7aa13e618be342beb87f618157
MD5 a913cb095066af7749fe50c11439aa6b
BLAKE2b-256 41e8cd22a06a8264cc6e49d4ccb6080bac9e38cb3bee7fd89a5e1850b26efd23

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl:

Publisher: publish.yml on Kautenja/nes-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nes_py-9.0.1-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.1-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ecb5827e9b664686f7b2046d5d1878d75553f70076a186df468bdea8b5e2aad6
MD5 9418a426617e5b4302da8bc0bb1b0345
BLAKE2b-256 56fb47cc4ee81c3ea6c9eb7aa031bb3e09820d03a610655c1bdc355986a49ccc

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.1-cp314-cp314-macosx_11_0_arm64.whl:

Publisher: publish.yml on Kautenja/nes-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nes_py-9.0.1-cp314-cp314-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.1-cp314-cp314-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 0934d1b8711e7db1f00772590a2b072eb831907ad932e34ffab4c3afd73de5d7
MD5 79565d3cc6b4778038b6ed7da547f63e
BLAKE2b-256 65c5cbf579c39dc18b91608eb6bd71173b47b65d1b02e311356eed80f7aa9613

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.1-cp314-cp314-macosx_10_15_x86_64.whl:

Publisher: publish.yml on Kautenja/nes-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nes_py-9.0.1-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: nes_py-9.0.1-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 137.7 kB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nes_py-9.0.1-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 2ad6a8e3e57e2af343292b636fcc866fa4887efd14a8de3543045f5f72ef08b6
MD5 6ca95dc67fb63d046eccc1707cfe2491
BLAKE2b-256 78df360f26e13c9787c601162e7c18b8d7d1f84c24989e6a814b4f058976b6eb

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.1-cp313-cp313-win_amd64.whl:

Publisher: publish.yml on Kautenja/nes-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nes_py-9.0.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 628698766186e880498994dfc52bf329e8f6fb49b60916050e01710bed036f9e
MD5 e79d8fb2fb429904288237c0c01fab26
BLAKE2b-256 17cc9e62cccdadeb6e27aa00ffec04c4875268f89d2bba2a3c1e390f31ce774f

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl:

Publisher: publish.yml on Kautenja/nes-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nes_py-9.0.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 d53f3ca69d54a44bc0fbe028a521e06feb4d2a0e09bcb5630e2cf78bc5556bb3
MD5 53f7231c1e1bcd2a2b0ee49c7915d4ee
BLAKE2b-256 791d84be8057c12cdaa60278363f85aeef35c9a0b82b929aacf151b508dbfdbd

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl:

Publisher: publish.yml on Kautenja/nes-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nes_py-9.0.1-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.1-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b15f5d8e7b51916fbfc17994c5f9e139815a169317146365aeee0e0dbb70e153
MD5 d5cbd45eb98f92f84f70b1549ec177c6
BLAKE2b-256 ffb9883da012016194fe02fc3ac28466c84c40bac77024cd3c8a3d6df88e956c

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.1-cp313-cp313-macosx_11_0_arm64.whl:

Publisher: publish.yml on Kautenja/nes-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nes_py-9.0.1-cp313-cp313-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.1-cp313-cp313-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 d61747fd93abfd31eaeb1d4a52bc1385223471e67b016fa06d6e8ee61b1d3523
MD5 bde22f3e90eab2f6c82e8496f3077311
BLAKE2b-256 154bf58ce386f120faa369e7f8615d45024ec55f707948822520af0f630e9fca

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.1-cp313-cp313-macosx_10_13_x86_64.whl:

Publisher: publish.yml on Kautenja/nes-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page