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

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.0.tar.gz (111.4 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.0-cp314-cp314-win_amd64.whl (141.4 kB view details)

Uploaded CPython 3.14Windows x86-64

nes_py-9.0.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (158.0 kB view details)

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

nes_py-9.0.0-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.0-cp314-cp314-macosx_11_0_arm64.whl (136.4 kB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

nes_py-9.0.0-cp314-cp314-macosx_10_15_x86_64.whl (143.4 kB view details)

Uploaded CPython 3.14macOS 10.15+ x86-64

nes_py-9.0.0-cp313-cp313-win_amd64.whl (137.3 kB view details)

Uploaded CPython 3.13Windows x86-64

nes_py-9.0.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (157.4 kB view details)

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

nes_py-9.0.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl (149.9 kB view details)

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

nes_py-9.0.0-cp313-cp313-macosx_11_0_arm64.whl (135.9 kB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

nes_py-9.0.0-cp313-cp313-macosx_10_13_x86_64.whl (143.1 kB view details)

Uploaded CPython 3.13macOS 10.13+ x86-64

File details

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

File metadata

  • Download URL: nes_py-9.0.0.tar.gz
  • Upload date:
  • Size: 111.4 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.0.tar.gz
Algorithm Hash digest
SHA256 ecfce55310146c5cabd491bd21e67c9eddbd7c9f48fb8b25d03772d221543f5d
MD5 7705356b92b1b1638df1e43625bf1f35
BLAKE2b-256 dc1062eb137d09e93a75d299adda3736c0b925a4f25866da809f61dff342098e

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.0.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.0-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: nes_py-9.0.0-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 141.4 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.0-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 ca404c9b0d6b979cb56e174c15754e2ba3df62119ab702bd2323a792bbfb1b7e
MD5 06adec2c17e1fa506d305f514a02a52f
BLAKE2b-256 b9c65827b1f6026020c9cf7325724e4e065aa96732b027b0fe29a7649d08d8f8

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.0-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.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 81d0f39458a959b9f23023bd92e1694c5fb1fb856558946d195f6807d0a595dd
MD5 bae29e4067b6ffe14d737f5079869999
BLAKE2b-256 d30175465faf4802f9ee6abfb49cdbf499f2d580e676b42f5c302d996772b4e0

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.0-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.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 38565d8ef9c56d4fc87f6315d87f18e8e5c27420a19941e88887bd43956a048a
MD5 99da5625b8d1ebd98a257bb12cd9f402
BLAKE2b-256 28d47ab8465144c9ba74792392aeb363de539350610e32a0d7b4895e955a35f8

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.0-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.0-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.0-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 96e3d33c12dce9ff1a970fc781235475c932bda3e7736cbea5113f6d947dc8d1
MD5 bacfbb9781e3456e97a9a47bda7db893
BLAKE2b-256 ff2c0d4e49eadd18d250c2f752ca4398d605e041c9407d6fa631953b047f33f3

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.0-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.0-cp314-cp314-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.0-cp314-cp314-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 f654cceb4318048d60f1cd0806ec5265eeaf2687b2839cea55826e2364f94dc6
MD5 7a75d3fb28e7f55a1b76f79505dba2fb
BLAKE2b-256 22aaab6a4a72d0a42b94593f35231ba0b12a841127070ead6ab25f1dd697bfe0

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.0-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.0-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: nes_py-9.0.0-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 137.3 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.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 0797c9b8620fe32e67737558facf3753ae20e12ffec119ae81097b3a80113312
MD5 7fcc91b4739b556dcc16812f7f3bc50d
BLAKE2b-256 33164feadf7b6205a188740fb6d97083d464a19452527f22b8260db22f478b12

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.0-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.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 a4842e26b3a83cbd012ff6196aa1c4b20ae35d95a4fb80d9917b5142714d154a
MD5 4a5e93c34699d5790aa7cb36d54ddbfa
BLAKE2b-256 72f993835e17f1ee3888ab90390e18c51f3d4c64f85535c9dcffd6b4d5e0346f

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.0-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.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 03ab299d9257f565158141e6603b422b6d6a22e19a61b807cdc28e5eb745d564
MD5 f93d096d20c2dc69b03e2f16bc095a10
BLAKE2b-256 9bdca344ccbc9678943fce9ca2cb12b36fb04822da82ea56d8e2f8634fec8bc2

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.0-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.0-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0595208804cd3014a4b97a0a864e7c3927fdba676f1f545b5a01c71aaabd01f2
MD5 9e70110f7f1ca8db90682d095098bafb
BLAKE2b-256 f03f62d4425ea31e32627b307a36be174a252bcb967d0713f936b1d3808091f1

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.0-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.0-cp313-cp313-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for nes_py-9.0.0-cp313-cp313-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 b169325f31b66a8eef151f27a08ae24b5d407bd24c8b28753aebf75e311c1d95
MD5 bf5ce33d5bab2fd7666a78faa1dd0fea
BLAKE2b-256 c8cac87e00cb2c4a213998619197703e6fc0da11deee6e557688c5ddce0eb97b

See more details on using hashes here.

Provenance

The following attestation bundles were made for nes_py-9.0.0-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