diff --git a/.gitignore b/.gitignore index c7740586c..5603b7cf5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,147 @@ -## ALE +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +## ALE ale build doc/examples/*Example -## Generic - # Emacs temp files *~ .* @@ -20,9 +156,6 @@ doc/examples/*Example *.o *.d -# Compiled Dynamic libraries -*.so - # Compiled Static libraries *.lai *.la @@ -30,5 +163,3 @@ doc/examples/*Example # Python *.pyc - -*.egg-info/ diff --git a/examples/python-interface/python_example.py b/examples/python-interface/python_example.py index c11146ed3..b2fb928e2 100755 --- a/examples/python-interface/python_example.py +++ b/examples/python-interface/python_example.py @@ -6,7 +6,8 @@ # ALE provided in examples/sharedLibraryInterfaceExample.cpp import sys from random import randrange -from ale_py import ALEInterface, SDL_SUPPORT + +from ale_py import SDL_SUPPORT, ALEInterface if len(sys.argv) < 2: print(f"Usage: {sys.argv[0]} rom_file") diff --git a/examples/python-interface/python_example_with_modes.py b/examples/python-interface/python_example_with_modes.py index d9b656c40..eb528ff26 100755 --- a/examples/python-interface/python_example_with_modes.py +++ b/examples/python-interface/python_example_with_modes.py @@ -6,7 +6,8 @@ # ALE provided in doc/examples/sharedLibraryInterfaceWithModesExample.cpp import sys from random import randrange -from ale_py import ALEInterface, SDL_SUPPORT + +from ale_py import SDL_SUPPORT, ALEInterface if len(sys.argv) < 2: print(f"Usage: {sys.argv[0]} rom_file") diff --git a/examples/python-rom-package/roms/__init__.py b/examples/python-rom-package/roms/__init__.py index 95436eefd..c6231af0c 100644 --- a/examples/python-rom-package/roms/__init__.py +++ b/examples/python-rom-package/roms/__init__.py @@ -1,5 +1,5 @@ -import sys import pathlib +import sys if sys.version_info >= (3, 9): import importlib.resources as resources diff --git a/md5.txt b/md5.txt deleted file mode 100644 index 63b23408c..000000000 --- a/md5.txt +++ /dev/null @@ -1,106 +0,0 @@ -# The following is a list of the md5 checksums for the various roms supported by ALE. - -4b27f5397c442d25f0c418ccdacf1926 adventure.bin -35be55426c1fec32dfb503b4f0651572 air_raid.bin -f1a0a23e6464d954e3a9579c4ccd01c8 alien.bin -acb7750b4d0c4bd34969802a7deb2990 amidar.bin -de78b3a064d374390ac0710f95edde92 assault.bin -89a68746eff7f266bbf08de2483abe55 asterix.bin -ccbd36746ed4525821a8083b0d6d2c2c asteroids.bin -826481f6fc53ea47c9f272f7050eedf7 atlantis2.bin -9ad36e699ef6f45d9eb6c4cf90475c9f atlantis.bin -8556b42aa05f94bc29ff39c39b11bff4 backgammon.bin -00ce0bdd43aed84a983bef38fe7f5ee3 bank_heist.bin -819aeeb9a2e11deb54e6de334f843894 basic_math.bin -41f252a66c6301f1e8ab3612c19bc5d4 battle_zone.bin -79ab4123a83dc11d468fb2108ea09e2e beam_rider.bin -136f75c4dd02c29283752b7e5799f978 berzerk.bin -0a981c03204ac2b278ba392674682560 blackjack.bin -c9b7afad3bfd922e006a6bfc1d4f3fe7 bowling.bin -c3ef5c4653212088eda54dc91d787870 boxing.bin -f34f08e5eb96e500e851a80be3277a56 breakout.bin -028024fb8e5e5f18ea586652f9799c96 carnival.bin -b816296311019ab69a21cb9e9e235d12 casino.bin -91c2098e88a6b13f977af8c003e0bca5 centipede.bin -c1cb228470a87beb5f36e90ac745da26 chopper_command.bin -55ef7b65066428367844342ed59f956c crazy_climber.bin -8cd26dcf249456fe4aeb8db42d49df74 crossbow.bin -106855474c69d08c8ffa308d47337269 darkchambers.bin -0f643c34e40e3f1daafd9c524d3ffe64 defender.bin -f0e0addc07971561ab80d9abe1b8d333 demon_attack.bin -36b20c427975760cb9cf4a47e41369e4 donkey_kong.bin -368d88a6c071caba60b4f778615aae94 double_dunk.bin -5aea9974b975a6a844e6df10d2b861c4 earthworld.bin -71f8bacfbdca019113f3f0801849057e elevator_action.bin -94b92a882f6dbaa6993a46e2dcc58402 enduro.bin -6b683be69f92958abe0e2a9945157ad5 entombed.bin -615a3bf251a38eb6638cdc7ffbde5480 et.bin -b8865f05676e64f3bec72b9defdacfa7 fishing_derby.bin -30512e0e83903fc05541d2f6a6a62654 flag_capture.bin -8e0ab801b1705a740b476b7f588c6d16 freeway.bin -081e2c114c9c20b61acf25fc95c71bf4 frogger.bin -4ca73eb959299471788f0b685c3ba0b5 frostbite.bin -211774f4c5739042618be8ff67351177 galaxian.bin -c16c79aad6272baffb8aae9a7fff0864 gopher.bin -8ac18076d01a6b63acf6e2cab4968940 gravitar.bin -f16c709df0a6c52f47ff52b9d95b7d8d hangman.bin -f0a6e99f5875891246c3dbecbf2d2cea haunted_house.bin -fca4a5be1251927027f2c24774a02160 hero.bin -7972e5101fa548b952d852db24ad6060 human_cannonball.bin -a4c08c4994eb9d24fb78be1793e82e26 ice_hockey.bin -e51030251e440cffaab1ac63438b44ae jamesbond.bin -718ae62c70af4e5fd8e932fee216948a journey_escape.bin -5428cdfada281c569c74c7308c7f2c26 kaboom.bin -4326edb70ff20d0ee5ba58fa5cb09d60 kangaroo.bin -6c1f3f2e359dbf55df462ccbcdd2f6bf keystone_kapers.bin -0dd4c69b5f9a7ae96a7a08329496779a king_kong.bin -eed9eaf1a0b6a2b9bc4c8032cb43e3fb klax.bin -534e23210dd1993c828d944c6ac4d9fb koolaid.bin -4baada22435320d185c95b7dd2bcdb24 krull.bin -5b92a93b23523ff16e2789b820e2a4c5 kung_fu_master.bin -8e4cd60d93fcde8065c1a2b972a26377 laser_gates.bin -2d76c5d1aad506442b9e9fb67765e051 lost_luggage.bin -e908611d99890733be31733a979c62d8 mario_bros.bin -df62a658496ac98a3aa4a6ee5719c251 miniature_golf.bin -3347a6dd59049b15a38394aa2dafa585 montezuma_revenge.bin -aa7bb54d2c189a31bb1fa20099e42859 mr_do.bin -87e79cd41ce136fd4f72cc6e2c161bee ms_pacman.bin -36306070f0c90a72461551a7a4f3a209 name_this_game.bin -113cd09c9771ac278544b7e90efe7df2 othello.bin -fc2233fc116faef0d3c31541717ca2db pacman.bin -7e52a95074a66640fcfde124fffd491a phoenix.bin -6d842c96d5a01967be9680080dd5be54 pitfall2.bin -3e90cf23106f2e08b2781e41299de556 pitfall.bin -60e0ea3cbe0913d39803477945e9e5ec pong.bin -4799a40b6e889370b7ee55c17ba65141 pooyan.bin -ef3a4f64b6494ba770862768caf04b86 private_eye.bin -484b0076816a104875e00467d431c2d2 qbert.bin -393948436d1f4cc3192410bb918f9724 riverraid.bin -ce5cc62608be2cd3ed8abd844efb8919 road_runner.bin -4f618c2429138e0280969193ed6c107e robotank.bin -240bfbac5163af4df5ae713985386f92 seaquest.bin -dd0cbe5351551a538414fb9e37fc56e8 sir_lancelot.bin -b76fbadc8ffb1f83e2ca08b6fb4d6c9f skiing.bin -e72eb8d4410152bdcb69e7fba327b420 solaris.bin -72ffbef6504b75e69ee1045af9075f66 space_invaders.bin -b702641d698c60bcdc922dbd8c9dd49c space_war.bin -a3c1c70024d7aabb41381adbfb6d3b25 star_gunner.bin -a9531c763077464307086ec9a1fd057d superman.bin -4d7517ae69f95cfbc053be01312b7dba surround.bin -42cdd6a9e42a3639e190722b8ea3fc51 tennis.bin -b0e1ee07fbc73493eac5651a52f90f00 tetris.bin -0db4f4150fecf77e4ce72ca4d04c052f tic_tac_toe_3d.bin -fc2104dd2dadf9a6176c1c1c8f87ced9 time_pilot.bin -fb27afe896e7c928089307b32e5642ee trondead.bin -7a5463545dfb2dcfdafa6074b2f2c15e turmoil.bin -085322bae40d904f53bdcc56df0593fc tutankham.bin -a499d720e7ee35c62424de882a3351b6 up_n_down.bin -3e899eba0ca8cd2972da1ae5479b4f0d venture.bin -539d26b6e9df0da8e7465f0f5ad863b7 video_checkers.bin -f0b7db930ca0e548c41a97160b9f6275 video_chess.bin -3f540a30fdee0b20aed7288e4a5ea528 video_cube.bin -107cc025334211e6d29da0b6be46aec7 video_pinball.bin -7e8aa18bc9502eb57daaf5e7c1e94da7 wizard_of_wor.bin -ec3beb6d8b5689e867bafb5d5f507491 word_zapper.bin -c5930d0e8cdae3e037349bfa08e871be yars_revenge.bin -eea0da9b987d661264cce69a7c13c3bd zaxxon.bin diff --git a/pyproject.toml b/pyproject.toml index aa2443541..7dcb5c9dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,16 +33,16 @@ classifiers = [ ] dependencies = [ "numpy", + "gymnasium", "importlib-metadata>=4.10.0; python_version < '3.10'", "importlib-resources; python_version < '3.9'", - "typing-extensions; python_version < '3.11'" + "typing-extensions; python_version < '3.11'", ] dynamic = ["version"] [project.optional-dependencies] test = [ "pytest>=7.0", - "gym~=0.23", ] [project.urls] @@ -50,22 +50,10 @@ homepage = "https://github.com/mgbellemare/Arcade-Learning-Environment" documentation = "https://github.com/mgbellemare/Arcade-Learning-Environment/tree/master/docs" changelog = "https://github.com/mgbellemare/Arcade-Learning-Environment/blob/master/CHANGELOG.md" -[project.scripts] -ale-import-roms = "ale_py.scripts.import_roms:main" - -[project.entry-points."gym.envs"] -ALE = "ale_py.gym:register_gym_envs" -__internal__ = "ale_py.gym:register_legacy_gym_envs" - [tool.setuptools] -packages = [ - "ale_py", - "ale_py.roms", - "ale_py.env", - "ale_py.scripts" -] -package-dir = {ale_py = "src/python", gym = "src/gym"} -package-data = {"ale_py" = ["py.typed", "*.pyi", "**/*.pyi"], "ale_py.roms" = ["*.bin", "md5.txt"]} +packages = ["ale_py", "ale_py.roms"] +package-dir = {ale_py = "src/python"} +package-data = {"ale_py" = ["py.typed", "*.pyi", "**/*.pyi"], "ale_py.roms" = ["*.bin", "md5.json"]} [tool.pytest.ini_options] minversion = "7.0" @@ -79,12 +67,6 @@ skip = ["*-win32", "*i686", "pp*", "*-musllinux*"] build-frontend = "build" -# Test configuration -# test-extras = ["test"] -# TODO(jfarebro): Temporarily use upstream Gym until v26 release. -test-requires = ["pytest", "git+https://github.com/openai/gym#egg=gym"] -test-command = "pytest {project}" - # vcpkg manylinux images manylinux-x86_64-image = "ghcr.io/jessefarebro/manylinux2014_x86_64-vcpkg" diff --git a/src/python/__init__.py b/src/python/__init__.py index d7e4001f9..7343e6457 100644 --- a/src/python/__init__.py +++ b/src/python/__init__.py @@ -3,8 +3,6 @@ import sys import warnings -packagedir = os.path.abspath(os.path.dirname(__file__)) - # Make sure to adjust the filter to show DeprecationWarning warnings.filterwarnings("default", category=DeprecationWarning, module=__name__) @@ -16,8 +14,8 @@ ctypes.CDLL("msvcp140.dll") except OSError: raise OSError( - """Microsoft Visual C++ Redistribution Pack is not installed. -It can be downloaded from https://aka.ms/vs/16/release/vc_redist.x64.exe.""" + "Microsoft Visual C++ Redistribution Pack is not installed. \n" + "It can be downloaded from https://aka.ms/vs/16/release/vc_redist.x64.exe." ) # Loading DLLs on Windows is kind of a disaster @@ -25,6 +23,7 @@ # with user defined search paths. This kind of acts like # $ORIGIN or @loader_path on Unix / macOS. # This way we guarantee we load OUR DLLs. + packagedir = os.path.abspath(os.path.dirname(__file__)) if sys.version_info.major == 3 and sys.version_info.minor >= 8: os.add_dll_directory(packagedir) else: @@ -45,6 +44,12 @@ __version__ = "unknown" # Import native shared library -from ale_py._ale_py import SDL_SUPPORT, Action, ALEInterface, ALEState, LoggerMode +from ale_py._ale_py import (SDL_SUPPORT, Action, ALEInterface, ALEState, + LoggerMode) __all__ = ["Action", "ALEInterface", "ALEState", "LoggerMode", "SDL_SUPPORT"] + + +from .register_gymnasium import register_gymnasium + +register_gymnasium() diff --git a/src/python/__init__.pyi b/src/python/__init__.pyi index d1c619727..6904abea1 100644 --- a/src/python/__init__.pyi +++ b/src/python/__init__.pyi @@ -28,6 +28,7 @@ class LoggerMode: """ :type: str """ + @property def value(self) -> int: """ @@ -54,6 +55,7 @@ class Action: """ :type: str """ + @property def value(self) -> int: """ diff --git a/src/python/env/gym.py b/src/python/atari_env.py similarity index 72% rename from src/python/env/gym.py rename to src/python/atari_env.py index 44353418c..69453e00d 100644 --- a/src/python/env/gym.py +++ b/src/python/atari_env.py @@ -1,14 +1,15 @@ +from __future__ import annotations + import sys -from typing import Any, Dict, List, Optional, Sequence, Tuple, Union +from typing import Any, Literal, Optional, Sequence, Union import ale_py -import ale_py.roms as roms -import ale_py.roms.utils as rom_utils +import gymnasium +import gymnasium.logger as logger import numpy as np - -import gym -import gym.logger as logger -from gym import error, spaces, utils +from ale_py import roms +from gymnasium import error, spaces, utils +from gymnasium.utils import seeding if sys.version_info < (3, 11): from typing_extensions import NotRequired, TypedDict @@ -23,7 +24,7 @@ class AtariEnvStepMetadata(TypedDict): seeds: NotRequired[Sequence[int]] -class AtariEnv(gym.Env, utils.EzPickle): +class AtariEnv(gymnasium.Env, utils.EzPickle): """ (A)rcade (L)earning (Gym) (Env)ironment. A Gym wrapper around the Arcade Learning Environment (ALE). @@ -37,15 +38,15 @@ def __init__( game: str = "pong", mode: Optional[int] = None, difficulty: Optional[int] = None, - obs_type: str = "rgb", - frameskip: Union[Tuple[int, int], int] = 4, + obs_type: Literal["rgb", "grayscale", "ram"] = "rgb", + frameskip: Union[tuple[int, int], int] = 4, repeat_action_probability: float = 0.25, full_action_space: bool = False, max_num_frames_per_episode: Optional[int] = None, - render_mode: Optional[str] = None, + render_mode: Optional[Literal["human", "rgb_array"]] = None, ) -> None: """ - Initialize the ALE for Gym. + Initialize the ALE for Gymnasium. Default parameters are taken from Machado et al., 2018. Args: @@ -53,7 +54,7 @@ def __init__( mode: Optional[int] => Game mode, see Machado et al., 2018 difficulty: Optional[int] => Game difficulty,see Machado et al., 2018 obs_type: str => Observation type in { 'rgb', 'grayscale', 'ram' } - frameskip: Union[Tuple[int, int], int] => + frameskip: Union[tuple[int, int], int] => Stochastic frameskip as tuple or fixed. repeat_action_probability: int => Probability to repeat actions, see Machado et al., 2018 @@ -79,11 +80,6 @@ def __init__( and Open Problems for General Agents`, Machado et al., 2018, JAIR URL: https://jair.org/index.php/jair/article/view/11182 """ - if obs_type == "image": - logger.warn( - 'obs_type "image" should be replaced with the image type, one of: rgb, grayscale' - ) - obs_type = "rgb" if obs_type not in {"rgb", "grayscale", "ram"}: raise error.Error( f"Invalid observation type: {obs_type}. Expecting: rgb, grayscale, ram." @@ -129,14 +125,13 @@ def __init__( # Initialize ALE self.ale = ale_py.ALEInterface() - self._game = rom_utils.rom_id_to_name(game) - + self._game = game self._game_mode = mode self._game_difficulty = difficulty self._frameskip = frameskip self._obs_type = obs_type - self._render_mode = render_mode + self.render_mode = render_mode # Set logger mode to error only self.ale.setLoggerMode(ale_py.LoggerMode.Error) @@ -151,19 +146,21 @@ def __init__( self.ale.setBool("display_screen", True) self.ale.setBool("sound", True) - # Seed + Load - self.seed() + # seed + load + self.seed_game() + self.load_game() + # initialize action space self._action_set = ( self.ale.getLegalActionSet() if full_action_space else self.ale.getMinimalActionSet() ) - self._action_space = spaces.Discrete(len(self._action_set)) + self.action_space = spaces.Discrete(len(self._action_set)) - # Initialize observation type + # initialize observation space if self._obs_type == "ram": - self._obs_space = spaces.Box( + self.observation_space = spaces.Box( low=0, high=255, dtype=np.uint8, shape=(self.ale.getRAMSize(),) ) elif self._obs_type == "rgb" or self._obs_type == "grayscale": @@ -174,44 +171,22 @@ def __init__( ) if self._obs_type == "rgb": image_shape += (3,) - self._obs_space = spaces.Box( + self.observation_space = spaces.Box( low=0, high=255, dtype=np.uint8, shape=image_shape ) else: raise error.Error(f"Unrecognized observation type: {self._obs_type}") - def seed(self, seed: Optional[int] = None) -> Tuple[int, int]: - """ - Seeds both the internal numpy rng for stochastic frame skip - as well as the ALE RNG. - - This function must also initialize the ROM and set the corresponding - mode and difficulty. `seed` may be called to initialize the environment - during deserialization by Gym so these side-effects must reside here. - - Args: - seed: int => Manually set the seed for RNG. - Returns: - tuple[int, int] => (np seed, ALE seed) - """ + def seed_game(self, seed: Optional[int] = None) -> tuple[int, int]: + """Seeds the internal and ALE RNG.""" ss = np.random.SeedSequence(seed) - seed1, seed2 = ss.generate_state(n_words=2) + np_seed, ale_seed = ss.generate_state(n_words=2) + self._np_random, seed = seeding.np_random(int(np_seed)) + self.ale.setInt("random_seed", np.int32(ale_seed)) + return np_seed, ale_seed - self.np_random = np.random.default_rng(seed1) - # ALE only takes signed integers for `setInt`, it'll get converted back - # to unsigned in StellaEnvironment. - self.ale.setInt("random_seed", seed2.astype(np.int32)) - - if not hasattr(roms, self._game): - raise error.Error( - f'We\'re Unable to find the game "{self._game}". Note: Gym no longer distributes ROMs. ' - f"If you own a license to use the necessary ROMs for research purposes you can download them " - f'via `pip install gym[accept-rom-license]`. Otherwise, you should try importing "{self._game}" ' - f'via the command `ale-import-roms`. If you believe this is a mistake perhaps your copy of "{self._game}" ' - "is unsupported. To check if this is the case try providing the environment variable " - "`PYTHONWARNINGS=default::ImportWarning:ale_py.roms`. For more information see: " - "https://github.com/mgbellemare/Arcade-Learning-Environment#rom-management" - ) + def load_game(self) -> None: + """This function initializes the ROM and sets the corresponding mode and difficulty.""" self.ale.loadROM(getattr(roms, self._game)) if self._game_mode is not None: @@ -219,12 +194,10 @@ def seed(self, seed: Optional[int] = None) -> Tuple[int, int]: if self._game_difficulty is not None: self.ale.setDifficulty(self._game_difficulty) - return seed1, seed2 - - def step( + def step( # pyright: ignore[reportIncompatibleMethodOverride] self, - action_ind: int, - ) -> Tuple[np.ndarray, float, bool, bool, AtariEnvStepMetadata]: + action: int, + ) -> tuple[np.ndarray, float, bool, bool, AtariEnvStepMetadata]: """ Perform one agent step, i.e., repeats `action` frameskip # of steps. @@ -232,15 +205,12 @@ def step( action_ind: int => Action index to execute Returns: - Tuple[np.ndarray, float, bool, Dict[str, Any]] => - observation, reward, terminal, metadata + tuple[np.ndarray, float, bool, bool, Dict[str, Any]] => + observation, reward, terminal, truncation, metadata Note: `metadata` contains the keys "lives" and "rgb" if render_mode == 'rgb_array'. """ - # Get action enum, terminal bool, metadata - action = self._action_set[action_ind] - # If frameskip is a length 2 tuple then it's stochastic # frameskip between [frameskip[0], frameskip[1]] uniformly. if isinstance(self._frameskip, int): @@ -253,38 +223,36 @@ def step( # Frameskip reward = 0.0 for _ in range(frameskip): - reward += self.ale.act(action) + reward += self.ale.act(self._action_set[action]) is_terminal = self.ale.game_over(with_truncation=False) is_truncated = self.ale.game_truncated() return self._get_obs(), reward, is_terminal, is_truncated, self._get_info() - def reset( + def reset( # pyright: ignore[reportIncompatibleMethodOverride] self, *, seed: Optional[int] = None, - options: Optional[Dict[str, Any]] = None, - ) -> Tuple[np.ndarray, AtariEnvStepMetadata]: - """ - Resets environment and returns initial observation. - """ - del options - # Gym's new seeding API seeds on reset. - # This will cause the console to be recreated - # and loose all previous state, e.g., statistics, etc. + options: Optional[dict[str, Any]] = None, + ) -> tuple[np.ndarray, AtariEnvStepMetadata]: + """Resets environment and returns initial observation.""" + # sets the seeds if it's specified for both ALE and frameskip np + # we only want to do this when commanded to so we don't reset all previous states, statistics, etc. seeded_with = None if seed is not None: - seeded_with = self.seed(seed) + seeded_with = self.seed_game(seed) + self.load_game() self.ale.reset_game() - obs = self._get_obs() + obs = self._get_obs() info = self._get_info() if seeded_with is not None: info["seeds"] = seeded_with + return obs, info - def render(self) -> Any: + def render(self) -> Optional[np.ndarray]: """ Render is not supported by ALE. We use a paradigm similar to Gym3 which allows you to specify `render_mode` during construction. @@ -294,13 +262,13 @@ def render(self) -> Any: will display the ALE and maintain the proper interval to match the FPS target set by the ROM. """ - if self._render_mode == "rgb_array": + if self.render_mode == "rgb_array": return self.ale.getScreenRGB() - elif self._render_mode == "human": - pass + elif self.render_mode == "human": + return else: raise error.Error( - f"Invalid render mode `{self._render_mode}`. " + f"Invalid render mode `{self.render_mode}`. " "Supported modes: `human`, `rgb_array`." ) @@ -325,7 +293,7 @@ def _get_info(self) -> AtariEnvStepMetadata: "frame_number": self.ale.getFrameNumber(), } - def get_keys_to_action(self) -> Dict[Tuple[int], ale_py.Action]: + def get_keys_to_action(self) -> dict[tuple[int], ale_py.Action]: """ Return keymapping -> actions for human play. """ @@ -360,15 +328,14 @@ def get_keys_to_action(self) -> Dict[Tuple[int], ale_py.Action]: # (key, key, ...) -> action_idx # where action_idx is the integer value of the action enum # - actions = self._action_set return dict( zip( - map(lambda action: tuple(sorted(mapping[action])), actions), - range(len(actions)), + map(lambda action: tuple(sorted(mapping[action])), self._action_set), + range(len(self._action_set)), ) ) - def get_action_meanings(self) -> List[str]: + def get_action_meanings(self) -> list[str]: """ Return the meaning of each integer action. """ @@ -402,24 +369,3 @@ def restore_full_state(self, state: ale_py.ALEState) -> None: "Please use `restore_state(state)` which will restore the state regardless of being a full or partial state. " ) self.ale.restoreSystemState(state) - - @property - def action_space(self) -> spaces.Discrete: - """ - Return Gym's action space. - """ - return self._action_space - - @property - def observation_space(self) -> spaces.Box: - """ - Return Gym's observation space. - """ - return self._obs_space - - @property - def render_mode(self) -> str: - """ - Attribute render_mode to comply Gym API. - """ - return self._render_mode diff --git a/src/python/env/__init__.py b/src/python/env/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/python/gym.py b/src/python/gym.py deleted file mode 100644 index 62aec69cf..000000000 --- a/src/python/gym.py +++ /dev/null @@ -1,185 +0,0 @@ -from collections import defaultdict -from typing import Any, Callable, Mapping, NamedTuple, Sequence, Text, Union - -import ale_py.roms as roms -from ale_py.roms import utils as rom_utils - -from gym.envs.registration import register - - -class GymFlavour(NamedTuple): - suffix: str - kwargs: Union[Mapping[Text, Any], Callable[[str], Mapping[Text, Any]]] - - -class GymConfig(NamedTuple): - version: str - kwargs: Mapping[Text, Any] - flavours: Sequence[GymFlavour] - - -def _register_gym_configs( - roms: Sequence[str], - obs_types: Sequence[str], - configs: Sequence[GymConfig], - prefix: str = "", -) -> None: - if len(prefix) > 0 and prefix[-1] != "/": - prefix += "/" - - for rom in roms: - for obs_type in obs_types: - for config in configs: - for flavour in config.flavours: - name = rom_utils.rom_id_to_name(rom) - name = f"{name}-ram" if obs_type == "ram" else name - - # Parse config kwargs - config_kwargs = ( - config.kwargs(rom) if callable(config.kwargs) else config.kwargs - ) - # Parse flavour kwargs - flavour_kwargs = ( - flavour.kwargs(rom) - if callable(flavour.kwargs) - else flavour.kwargs - ) - - # Register the environment - register( - id=f"{prefix}{name}{flavour.suffix}-{config.version}", - entry_point="ale_py.env.gym:AtariEnv", - kwargs=dict( - game=rom, - obs_type=obs_type, - **config_kwargs, - **flavour_kwargs, - ), - ) - - -def register_legacy_gym_envs() -> None: - legacy_games = [ - "adventure", - "air_raid", - "alien", - "amidar", - "assault", - "asterix", - "asteroids", - "atlantis", - "bank_heist", - "battle_zone", - "beam_rider", - "berzerk", - "bowling", - "boxing", - "breakout", - "carnival", - "centipede", - "chopper_command", - "crazy_climber", - "defender", - "demon_attack", - "double_dunk", - "elevator_action", - "enduro", - "fishing_derby", - "freeway", - "frostbite", - "gopher", - "gravitar", - "hero", - "ice_hockey", - "jamesbond", - "journey_escape", - "kangaroo", - "krull", - "kung_fu_master", - "montezuma_revenge", - "ms_pacman", - "name_this_game", - "phoenix", - "pitfall", - "pong", - "pooyan", - "private_eye", - "qbert", - "riverraid", - "road_runner", - "robotank", - "seaquest", - "skiing", - "solaris", - "space_invaders", - "star_gunner", - "tennis", - "time_pilot", - "tutankham", - "up_n_down", - "venture", - "video_pinball", - "wizard_of_wor", - "yars_revenge", - "zaxxon", - ] - obs_types = ["rgb", "ram"] - frameskip = defaultdict(lambda: 4, [("space_invaders", 3)]) - - versions = [ - GymConfig( - version="v0", - kwargs={ - "repeat_action_probability": 0.25, - "full_action_space": False, - "max_num_frames_per_episode": 108_000, - }, - flavours=[ - # Default for v0 has 10k steps, no idea why... - GymFlavour("", {"frameskip": (2, 5)}), - # Deterministic has 100k steps, close to the standard of 108k (30 mins gameplay) - GymFlavour("Deterministic", lambda rom: {"frameskip": frameskip[rom]}), - # NoFrameSkip imposes a max episode steps of frameskip * 100k, weird... - GymFlavour("NoFrameskip", {"frameskip": 1}), - ], - ), - GymConfig( - version="v4", - kwargs={ - "repeat_action_probability": 0.0, - "full_action_space": False, - "max_num_frames_per_episode": 108_000, - }, - flavours=[ - # Unlike v0, v4 has 100k max episode steps - GymFlavour("", {"frameskip": (2, 5)}), - GymFlavour("Deterministic", lambda rom: {"frameskip": frameskip[rom]}), - # Same weird frameskip * 100k max steps for v4? - GymFlavour("NoFrameskip", {"frameskip": 1}), - ], - ), - ] - - _register_gym_configs(legacy_games, obs_types, versions) - - -def register_gym_envs(): - all_games = list(map(rom_utils.rom_name_to_id, dir(roms))) - obs_types = ["rgb", "ram"] - - # max_episode_steps is 108k frames which is 30 mins of gameplay. - # This corresponds to 108k / 4 = 27,000 steps - versions = [ - GymConfig( - version="v5", - kwargs={ - "repeat_action_probability": 0.25, - "full_action_space": False, - "frameskip": 4, - "max_num_frames_per_episode": 108_000, - }, - flavours=[GymFlavour("", {})], - ) - ] - - _register_gym_configs(all_games, obs_types, versions) diff --git a/src/python/register_gymnasium.py b/src/python/register_gymnasium.py new file mode 100644 index 000000000..ddd21f2ba --- /dev/null +++ b/src/python/register_gymnasium.py @@ -0,0 +1,288 @@ +from collections import defaultdict +from typing import Any, Callable, Mapping, NamedTuple, Sequence + +from gymnasium.envs.registration import register + +ALL_ATARI_GAMES = ( + "adventure", + "air_raid", + "alien", + "amidar", + "assault", + "asterix", + "asteroids", + "atlantis", + "atlantis2", + "backgammon", + "bank_heist", + "basic_math", + "battle_zone", + "beam_rider", + "berzerk", + "blackjack", + "bowling", + "boxing", + "breakout", + "carnival", + "casino", + "centipede", + "chopper_command", + "crazy_climber", + "crossbow", + "darkchambers", + "defender", + "demon_attack", + "donkey_kong", + "double_dunk", + "earthworld", + "elevator_action", + "enduro", + "entombed", + "et", + "fishing_derby", + "flag_capture", + "freeway", + "frogger", + "frostbite", + "galaxian", + "gopher", + "gravitar", + "hangman", + "haunted_house", + "hero", + "human_cannonball", + "ice_hockey", + "jamesbond", + "journey_escape", + "kaboom", + "kangaroo", + "keystone_kapers", + "king_kong", + "klax", + "koolaid", + "krull", + "kung_fu_master", + "laser_gates", + "lost_luggage", + "mario_bros", + "miniature_golf", + "montezuma_revenge", + "mr_do", + "ms_pacman", + "name_this_game", + "othello", + "pacman", + "phoenix", + "pitfall", + "pitfall2", + "pong", + "pooyan", + "private_eye", + "qbert", + "riverraid", + "road_runner", + "robotank", + "seaquest", + "sir_lancelot", + "skiing", + "solaris", + "space_invaders", + "space_war", + "star_gunner", + "superman", + "surround", + "tennis", + "tetris", + "tic_tac_toe_3d", + "time_pilot", + "trondead", + "turmoil", + "tutankham", + "up_n_down", + "venture", + "video_checkers", + "video_chess", + "video_cube", + "video_pinball", + "wizard_of_wor", + "word_zapper", + "yars_revenge", + "zaxxon", +) +LEGACY_ATARI_GAMES = ( + "adventure", + "air_raid", + "alien", + "amidar", + "assault", + "asterix", + "asteroids", + "atlantis", + "bank_heist", + "battle_zone", + "beam_rider", + "berzerk", + "bowling", + "boxing", + "breakout", + "carnival", + "centipede", + "chopper_command", + "crazy_climber", + "defender", + "demon_attack", + "double_dunk", + "elevator_action", + "enduro", + "fishing_derby", + "freeway", + "frostbite", + "gopher", + "gravitar", + "hero", + "ice_hockey", + "jamesbond", + "journey_escape", + "kangaroo", + "krull", + "kung_fu_master", + "montezuma_revenge", + "ms_pacman", + "name_this_game", + "phoenix", + "pitfall", + "pong", + "pooyan", + "private_eye", + "qbert", + "riverraid", + "road_runner", + "robotank", + "seaquest", + "skiing", + "solaris", + "space_invaders", + "star_gunner", + "tennis", + "time_pilot", + "tutankham", + "up_n_down", + "venture", + "video_pinball", + "wizard_of_wor", + "yars_revenge", + "zaxxon", +) + + +class GymFlavour(NamedTuple): + """A Gymnasium Flavour.""" + + suffix: str + kwargs: Mapping[str, Any] | Callable[[str], Mapping[str, Any]] + + +class GymConfig(NamedTuple): + """A Gymnasium Configuration.""" + + version: str + kwargs: Mapping[str, Any] + flavours: Sequence[GymFlavour] + + +def _register_configs( + roms: Sequence[str], + obs_types: Sequence[str], + configs: Sequence[GymConfig], + prefix: str = "", +): + """Registers all possible configurations of the atari games given a list of roms.""" + for rom in roms: + for obs_type in obs_types: + for config in configs: + for flavour in config.flavours: + # convert snake to pascal, ie: space_invaders -> SpaceInvaders + name = rom.title().replace("_", "") + if obs_type == "ram": + name = f"{name}-ram" + + # Parse config kwargs + if callable(config.kwargs): + config_kwargs = config.kwargs(rom) + else: + config_kwargs = config.kwargs + + # Parse flavour kwargs + if callable(flavour.kwargs): + flavour_kwargs = flavour.kwargs(rom) + else: + flavour_kwargs = flavour.kwargs + + # Register the environment + register( + id=f"{prefix}{name}{flavour.suffix}-{config.version}", + entry_point="ale_py.atari_env:AtariEnv", + kwargs={ + "game": rom, + "obs_type": obs_type, + **config_kwargs, + **flavour_kwargs, + }, + ) + + +def register_gymnasium(): + frameskip: dict[str, int] = defaultdict(lambda: 4, [("space_invaders", 3)]) + + configs = [ + GymConfig( + version="v0", + kwargs={ + "repeat_action_probability": 0.25, + "full_action_space": False, + "max_num_frames_per_episode": 108_000, + }, + flavours=[ + # Default for v0 has 10k steps, no idea why... + GymFlavour("", {"frameskip": (2, 5)}), + # Deterministic has 100k steps, close to the standard of 108k (30 mins gameplay) + GymFlavour("Deterministic", lambda rom: {"frameskip": frameskip[rom]}), + # NoFrameSkip imposes a max episode steps of frameskip * 100k, weird... + GymFlavour("NoFrameskip", {"frameskip": 1}), + ], + ), + GymConfig( + version="v4", + kwargs={ + "repeat_action_probability": 0.0, + "full_action_space": False, + "max_num_frames_per_episode": 108_000, + }, + flavours=[ + # Unlike v0, v4 has 100k max episode steps + GymFlavour("", {"frameskip": (2, 5)}), + GymFlavour("Deterministic", lambda rom: {"frameskip": frameskip[rom]}), + # Same weird frameskip * 100k max steps for v4? + GymFlavour("NoFrameskip", {"frameskip": 1}), + ], + ), + ] + _register_configs(LEGACY_ATARI_GAMES, obs_types=("rgb", "ram"), configs=configs) + + # max_episode_steps is 108k frames which is 30 mins of gameplay. + # This corresponds to 108k / 4 = 27,000 steps + configs = [ + GymConfig( + version="v5", + kwargs={ + "repeat_action_probability": 0.25, + "full_action_space": False, + "frameskip": 4, + "max_num_frames_per_episode": 108_000, + }, + flavours=[GymFlavour("", {})], + ) + ] + _register_configs( + ALL_ATARI_GAMES, obs_types=("rgb", "ram"), configs=configs, prefix="ALE/" + ) diff --git a/src/python/roms/__init__.py b/src/python/roms/__init__.py index cf2e8b1ee..582df52cb 100644 --- a/src/python/roms/__init__.py +++ b/src/python/roms/__init__.py @@ -1,141 +1,25 @@ import functools -import logging -import os +import json import pathlib -import sys -import warnings -from typing import List, Optional - -from ale_py import ALEInterface -from ale_py.roms import plugins, utils - -# pylint: disable=g-import-not-at-top -if sys.version_info >= (3, 9): - import importlib.resources as resources -else: - import importlib_resources as resources -# pylint: enable=g-import-not-at-top - -# Precedence is as follows: -# 1. Internal ROMs -# 2. External ROMs -# 3. ROMs from atari-py.roms -# 4. ROMs from atari-py-roms.roms -_ROM_PLUGIN_REGISTRY: List[plugins.Plugin] = [ - plugins.Package("ale_py.roms"), - plugins.EntryPoint("ale_py.roms"), - plugins.Package("atari_py.atari_roms"), - plugins.Package("atari_py_roms.atari_roms"), -] - -# Environment variable for ROM discovery. -# ale-py will search for supported ROMs in: -# ${ALE_PY_ROM_DIR}/*.bin -_ROM_DIRECTORY_ENV_KEY = "ALE_PY_ROM_DIR" -_ROM_DIRECTORY_ENV_VALUE = os.environ.get(_ROM_DIRECTORY_ENV_KEY, None) - -if _ROM_DIRECTORY_ENV_VALUE is not None: - _ROM_PLUGIN_REGISTRY.append(plugins.Directory(_ROM_DIRECTORY_ENV_VALUE)) - - -def _resolve_rom(name: str) -> Optional[pathlib.Path]: - """Resolve a ROM path from the ROM registry.""" - for package in _ROM_PLUGIN_REGISTRY: - rom_id = utils.rom_name_to_id(name) - - # Resolve ROM from package - try: - rom_path = package.resolve(rom_id) - except ModuleNotFoundError: - continue - - # Failed to resolve ROM - if rom_path is None: - logging.debug(f"{package} did not resolve {rom_id}.") - continue - - # ROM isn't supported - resolved_id = ALEInterface.isSupportedROM(rom_path) - if resolved_id is None: - warnings.warn( - f"{package} contains unsupported ROM: {rom_path}", - category=ImportWarning, - stacklevel=2, - ) - continue - - # If the ROMs resolved differently - if resolved_id != rom_id: - warnings.warn( - f"{package} contains ROM {rom_id} which doesn't resolve to {resolved_id}. " - "This is most likely caused by a filename mismatch.", - ) - continue - - # Deprecation warning for atari-py - if isinstance(package, plugins.Package) and package.package.startswith( - "atari_py" - ): - warnings.warn( - "Automatic importing of atari-py roms won't be supported in future releases of ale-py. " - "Please migrate over to using `ale-import-roms` OR an ALE-supported ROM package. " - "To make this warning disappear you can run " - f"`ale-import-roms --import-from-pkg {package.package}`. " - "For more information see: https://github.com/mgbellemare/Arcade-Learning-Environment#rom-management", - category=DeprecationWarning, - stacklevel=2, - ) - - return rom_path - # Return None if we couldn't resolve the ROM from any package - return None +from os import path @functools.lru_cache(maxsize=None) -def __dir__() -> List[str]: - """Return the ROM directory, i.e., a list of all supported ROMs.""" - md5s = resources.files(__name__).joinpath("md5.txt") - if not md5s.exists(): - raise FileNotFoundError( - f"ROM md5 resource couldn't be found. " - "Are you running from a development environment? " - ) - with md5s.open() as fp: - lines = filter( - lambda line: line.strip() and not line.startswith("#"), fp.readlines() - ) - roms = [pathlib.Path(rom) for _, rom in map(str.split, lines)] - return [utils.rom_id_to_name(rom.stem) for rom in roms] - - -@functools.lru_cache(maxsize=None) -def __getattr__(name: str) -> pathlib.Path: +def __getattr__(rom_name: str) -> pathlib.Path: """Return the path to a ROM.""" - roms = __dir__() - if name not in roms: - raise AttributeError(f"No ROM named {name}. Supported ROMs: {', '.join(roms)}") - - path = _resolve_rom(name) - if path is None: + # get list of available ROMs from the md5 file + # realistically we don't need the MD5s since PyPI will perform hash checks for us + base_path = path.dirname(__file__) + rom_names = [ + n.split(".")[0] + for n in json.load(open(path.join(base_path, "md5.json"))).keys() + ] + + # check that the rom is valid + if rom_name not in rom_names: raise AttributeError( - f"Failed to resolve ROM `{name}` from plugins " - f"{', '.join(map(lambda plugin: f'`{repr(plugin)}`', _ROM_PLUGIN_REGISTRY))}. " - "If you own a license to use the necessary ROMs for research purposes you can download them " - f"via `pip install autorom[accept-rom-license]`. Otherwise, you should try importing `{name}` " - f"via the command `ale-import-roms`. If you believe this is a mistake perhaps your copy of `{name}` " - "is unsupported. To check if this is the case try providing the environment variable " - "`PYTHONWARNINGS=default::ImportWarning:ale_py.roms`. For more information see: " - "https://github.com/mgbellemare/Arcade-Learning-Environment#rom-management" + f"No ROM named {rom_name}. Supported ROMs: {', '.join(rom_names)}" ) - return path - - -def register_plugin(plugin: plugins.Plugin, *, index: int = 0) -> None: - """Register a ROM plugin.""" - if not issubclass(type(plugin), plugins.Plugin): - raise ValueError(f"{repr(plugin)} is not a valid ROM plugin.") - _ROM_PLUGIN_REGISTRY.insert(index, plugin) - __getattr__.cache_clear() - -__all__ = ["register_plugin"] + __dir__() + # return it as a pathlib object + return pathlib.Path(path.join(base_path, f"{rom_name}.bin")) diff --git a/src/python/roms/adventure.bin b/src/python/roms/adventure.bin new file mode 100644 index 000000000..a09224859 Binary files /dev/null and b/src/python/roms/adventure.bin differ diff --git a/src/python/roms/air_raid.bin b/src/python/roms/air_raid.bin new file mode 100644 index 000000000..6adc39c12 Binary files /dev/null and b/src/python/roms/air_raid.bin differ diff --git a/src/python/roms/alien.bin b/src/python/roms/alien.bin new file mode 100644 index 000000000..209d3a9fe Binary files /dev/null and b/src/python/roms/alien.bin differ diff --git a/src/python/roms/amidar.bin b/src/python/roms/amidar.bin new file mode 100644 index 000000000..1a75863ba Binary files /dev/null and b/src/python/roms/amidar.bin differ diff --git a/src/python/roms/assault.bin b/src/python/roms/assault.bin new file mode 100644 index 000000000..da2ea47f1 Binary files /dev/null and b/src/python/roms/assault.bin differ diff --git a/src/python/roms/asterix.bin b/src/python/roms/asterix.bin new file mode 100644 index 000000000..7dfd44ab5 Binary files /dev/null and b/src/python/roms/asterix.bin differ diff --git a/src/python/roms/asteroids.bin b/src/python/roms/asteroids.bin new file mode 100644 index 000000000..f53843df3 Binary files /dev/null and b/src/python/roms/asteroids.bin differ diff --git a/src/python/roms/atlantis.bin b/src/python/roms/atlantis.bin new file mode 100644 index 000000000..ebf1b761c Binary files /dev/null and b/src/python/roms/atlantis.bin differ diff --git a/src/python/roms/atlantis2.bin b/src/python/roms/atlantis2.bin new file mode 100644 index 000000000..387958ae2 Binary files /dev/null and b/src/python/roms/atlantis2.bin differ diff --git a/src/python/roms/backgammon.bin b/src/python/roms/backgammon.bin new file mode 100644 index 000000000..7f5c28c71 Binary files /dev/null and b/src/python/roms/backgammon.bin differ diff --git a/src/python/roms/bank_heist.bin b/src/python/roms/bank_heist.bin new file mode 100644 index 000000000..794009396 Binary files /dev/null and b/src/python/roms/bank_heist.bin differ diff --git a/src/python/roms/basic_math.bin b/src/python/roms/basic_math.bin new file mode 100644 index 000000000..2ad8007a3 Binary files /dev/null and b/src/python/roms/basic_math.bin differ diff --git a/src/python/roms/battle_zone.bin b/src/python/roms/battle_zone.bin new file mode 100644 index 000000000..8dee5f262 Binary files /dev/null and b/src/python/roms/battle_zone.bin differ diff --git a/src/python/roms/beam_rider.bin b/src/python/roms/beam_rider.bin new file mode 100644 index 000000000..d8292a128 Binary files /dev/null and b/src/python/roms/beam_rider.bin differ diff --git a/src/python/roms/berzerk.bin b/src/python/roms/berzerk.bin new file mode 100644 index 000000000..48854dfae Binary files /dev/null and b/src/python/roms/berzerk.bin differ diff --git a/src/python/roms/blackjack.bin b/src/python/roms/blackjack.bin new file mode 100644 index 000000000..924e80436 Binary files /dev/null and b/src/python/roms/blackjack.bin differ diff --git a/src/python/roms/bowling.bin b/src/python/roms/bowling.bin new file mode 100644 index 000000000..18b397cb8 Binary files /dev/null and b/src/python/roms/bowling.bin differ diff --git a/src/python/roms/boxing.bin b/src/python/roms/boxing.bin new file mode 100644 index 000000000..973812c40 Binary files /dev/null and b/src/python/roms/boxing.bin differ diff --git a/src/python/roms/breakout.bin b/src/python/roms/breakout.bin new file mode 100644 index 000000000..abab5a8c0 Binary files /dev/null and b/src/python/roms/breakout.bin differ diff --git a/src/python/roms/carnival.bin b/src/python/roms/carnival.bin new file mode 100644 index 000000000..391d4b303 Binary files /dev/null and b/src/python/roms/carnival.bin differ diff --git a/src/python/roms/casino.bin b/src/python/roms/casino.bin new file mode 100644 index 000000000..0841f816f Binary files /dev/null and b/src/python/roms/casino.bin differ diff --git a/src/python/roms/centipede.bin b/src/python/roms/centipede.bin new file mode 100644 index 000000000..6befff16b Binary files /dev/null and b/src/python/roms/centipede.bin differ diff --git a/src/python/roms/chopper_command.bin b/src/python/roms/chopper_command.bin new file mode 100644 index 000000000..f8358d3db Binary files /dev/null and b/src/python/roms/chopper_command.bin differ diff --git a/src/python/roms/combat.bin b/src/python/roms/combat.bin new file mode 100644 index 000000000..a71ae9a42 Binary files /dev/null and b/src/python/roms/combat.bin differ diff --git a/src/python/roms/crazy_climber.bin b/src/python/roms/crazy_climber.bin new file mode 100644 index 000000000..46841a59d Binary files /dev/null and b/src/python/roms/crazy_climber.bin differ diff --git a/src/python/roms/crossbow.bin b/src/python/roms/crossbow.bin new file mode 100644 index 000000000..480df238e Binary files /dev/null and b/src/python/roms/crossbow.bin differ diff --git a/src/python/roms/darkchambers.bin b/src/python/roms/darkchambers.bin new file mode 100644 index 000000000..f7277e85c Binary files /dev/null and b/src/python/roms/darkchambers.bin differ diff --git a/src/python/roms/defender.bin b/src/python/roms/defender.bin new file mode 100644 index 000000000..d9843f2b7 Binary files /dev/null and b/src/python/roms/defender.bin differ diff --git a/src/python/roms/demon_attack.bin b/src/python/roms/demon_attack.bin new file mode 100644 index 000000000..fbb97f711 Binary files /dev/null and b/src/python/roms/demon_attack.bin differ diff --git a/src/python/roms/donkey_kong.bin b/src/python/roms/donkey_kong.bin new file mode 100644 index 000000000..fbe04314b Binary files /dev/null and b/src/python/roms/donkey_kong.bin differ diff --git a/src/python/roms/double_dunk.bin b/src/python/roms/double_dunk.bin new file mode 100644 index 000000000..b4b0ad624 Binary files /dev/null and b/src/python/roms/double_dunk.bin differ diff --git a/src/python/roms/earthworld.bin b/src/python/roms/earthworld.bin new file mode 100644 index 000000000..7fdf48f39 Binary files /dev/null and b/src/python/roms/earthworld.bin differ diff --git a/src/python/roms/elevator_action.bin b/src/python/roms/elevator_action.bin new file mode 100644 index 000000000..4a44ee2d3 Binary files /dev/null and b/src/python/roms/elevator_action.bin differ diff --git a/src/python/roms/enduro.bin b/src/python/roms/enduro.bin new file mode 100644 index 000000000..e975c0652 Binary files /dev/null and b/src/python/roms/enduro.bin differ diff --git a/src/python/roms/entombed.bin b/src/python/roms/entombed.bin new file mode 100644 index 000000000..d45e4eb5c Binary files /dev/null and b/src/python/roms/entombed.bin differ diff --git a/src/python/roms/et.bin b/src/python/roms/et.bin new file mode 100644 index 000000000..4892f9b3f Binary files /dev/null and b/src/python/roms/et.bin differ diff --git a/src/python/roms/fishing_derby.bin b/src/python/roms/fishing_derby.bin new file mode 100644 index 000000000..1d25bc42b Binary files /dev/null and b/src/python/roms/fishing_derby.bin differ diff --git a/src/python/roms/flag_capture.bin b/src/python/roms/flag_capture.bin new file mode 100644 index 000000000..a8464b887 Binary files /dev/null and b/src/python/roms/flag_capture.bin differ diff --git a/src/python/roms/freeway.bin b/src/python/roms/freeway.bin new file mode 100644 index 000000000..895e05760 Binary files /dev/null and b/src/python/roms/freeway.bin differ diff --git a/src/python/roms/frogger.bin b/src/python/roms/frogger.bin new file mode 100644 index 000000000..4af5e5b78 Binary files /dev/null and b/src/python/roms/frogger.bin differ diff --git a/src/python/roms/frostbite.bin b/src/python/roms/frostbite.bin new file mode 100644 index 000000000..d5be210d8 Binary files /dev/null and b/src/python/roms/frostbite.bin differ diff --git a/src/python/roms/galaxian.bin b/src/python/roms/galaxian.bin new file mode 100644 index 000000000..44078febb Binary files /dev/null and b/src/python/roms/galaxian.bin differ diff --git a/src/python/roms/gopher.bin b/src/python/roms/gopher.bin new file mode 100644 index 000000000..00e1ad4f6 Binary files /dev/null and b/src/python/roms/gopher.bin differ diff --git a/src/python/roms/gravitar.bin b/src/python/roms/gravitar.bin new file mode 100644 index 000000000..bee28da54 Binary files /dev/null and b/src/python/roms/gravitar.bin differ diff --git a/src/python/roms/hangman.bin b/src/python/roms/hangman.bin new file mode 100644 index 000000000..b52d81d96 Binary files /dev/null and b/src/python/roms/hangman.bin differ diff --git a/src/python/roms/haunted_house.bin b/src/python/roms/haunted_house.bin new file mode 100644 index 000000000..0a4610e41 Binary files /dev/null and b/src/python/roms/haunted_house.bin differ diff --git a/src/python/roms/hero.bin b/src/python/roms/hero.bin new file mode 100644 index 000000000..4242bd9ad Binary files /dev/null and b/src/python/roms/hero.bin differ diff --git a/src/python/roms/human_cannonball.bin b/src/python/roms/human_cannonball.bin new file mode 100644 index 000000000..9cf1e0c37 Binary files /dev/null and b/src/python/roms/human_cannonball.bin differ diff --git a/src/python/roms/ice_hockey.bin b/src/python/roms/ice_hockey.bin new file mode 100644 index 000000000..5864e0959 Binary files /dev/null and b/src/python/roms/ice_hockey.bin differ diff --git a/src/python/roms/jamesbond.bin b/src/python/roms/jamesbond.bin new file mode 100644 index 000000000..a9aa5fc39 Binary files /dev/null and b/src/python/roms/jamesbond.bin differ diff --git a/src/python/roms/journey_escape.bin b/src/python/roms/journey_escape.bin new file mode 100644 index 000000000..f883ac8bf Binary files /dev/null and b/src/python/roms/journey_escape.bin differ diff --git a/src/python/roms/joust.bin b/src/python/roms/joust.bin new file mode 100644 index 000000000..9b0972aa8 Binary files /dev/null and b/src/python/roms/joust.bin differ diff --git a/src/python/roms/kaboom.bin b/src/python/roms/kaboom.bin new file mode 100644 index 000000000..ae35480ff Binary files /dev/null and b/src/python/roms/kaboom.bin differ diff --git a/src/python/roms/kangaroo.bin b/src/python/roms/kangaroo.bin new file mode 100644 index 000000000..4d82d4dd0 Binary files /dev/null and b/src/python/roms/kangaroo.bin differ diff --git a/src/python/roms/keystone_kapers.bin b/src/python/roms/keystone_kapers.bin new file mode 100644 index 000000000..c3485e727 Binary files /dev/null and b/src/python/roms/keystone_kapers.bin differ diff --git a/src/python/roms/king_kong.bin b/src/python/roms/king_kong.bin new file mode 100644 index 000000000..e0011d8ff Binary files /dev/null and b/src/python/roms/king_kong.bin differ diff --git a/src/python/roms/klax.bin b/src/python/roms/klax.bin new file mode 100644 index 000000000..220a16865 Binary files /dev/null and b/src/python/roms/klax.bin differ diff --git a/src/python/roms/koolaid.bin b/src/python/roms/koolaid.bin new file mode 100644 index 000000000..1f12dcbd1 Binary files /dev/null and b/src/python/roms/koolaid.bin differ diff --git a/src/python/roms/krull.bin b/src/python/roms/krull.bin new file mode 100644 index 000000000..0f5c3782e Binary files /dev/null and b/src/python/roms/krull.bin differ diff --git a/src/python/roms/kung_fu_master.bin b/src/python/roms/kung_fu_master.bin new file mode 100644 index 000000000..387582156 Binary files /dev/null and b/src/python/roms/kung_fu_master.bin differ diff --git a/src/python/roms/laser_gates.bin b/src/python/roms/laser_gates.bin new file mode 100644 index 000000000..587744d41 Binary files /dev/null and b/src/python/roms/laser_gates.bin differ diff --git a/src/python/roms/lost_luggage.bin b/src/python/roms/lost_luggage.bin new file mode 100644 index 000000000..b4a35c728 Binary files /dev/null and b/src/python/roms/lost_luggage.bin differ diff --git a/src/python/roms/mario_bros.bin b/src/python/roms/mario_bros.bin new file mode 100644 index 000000000..a992fddab Binary files /dev/null and b/src/python/roms/mario_bros.bin differ diff --git a/src/python/roms/maze_craze.bin b/src/python/roms/maze_craze.bin new file mode 100644 index 000000000..c3f142e3e Binary files /dev/null and b/src/python/roms/maze_craze.bin differ diff --git a/src/python/roms/md5.json b/src/python/roms/md5.json new file mode 100644 index 000000000..dcac5bca8 --- /dev/null +++ b/src/python/roms/md5.json @@ -0,0 +1,106 @@ +{ + "adventure.bin": "4b27f5397c442d25f0c418ccdacf1926", + "air_raid.bin": "35be55426c1fec32dfb503b4f0651572", + "alien.bin": "f1a0a23e6464d954e3a9579c4ccd01c8", + "amidar.bin": "acb7750b4d0c4bd34969802a7deb2990", + "assault.bin": "de78b3a064d374390ac0710f95edde92", + "asterix.bin": "89a68746eff7f266bbf08de2483abe55", + "asteroids.bin": "ccbd36746ed4525821a8083b0d6d2c2c", + "atlantis2.bin": "826481f6fc53ea47c9f272f7050eedf7", + "atlantis.bin": "9ad36e699ef6f45d9eb6c4cf90475c9f", + "backgammon.bin": "8556b42aa05f94bc29ff39c39b11bff4", + "bank_heist.bin": "00ce0bdd43aed84a983bef38fe7f5ee3", + "basic_math.bin": "819aeeb9a2e11deb54e6de334f843894", + "battle_zone.bin": "41f252a66c6301f1e8ab3612c19bc5d4", + "beam_rider.bin": "79ab4123a83dc11d468fb2108ea09e2e", + "berzerk.bin": "136f75c4dd02c29283752b7e5799f978", + "blackjack.bin": "0a981c03204ac2b278ba392674682560", + "bowling.bin": "c9b7afad3bfd922e006a6bfc1d4f3fe7", + "boxing.bin": "c3ef5c4653212088eda54dc91d787870", + "breakout.bin": "f34f08e5eb96e500e851a80be3277a56", + "carnival.bin": "028024fb8e5e5f18ea586652f9799c96", + "casino.bin": "b816296311019ab69a21cb9e9e235d12", + "centipede.bin": "91c2098e88a6b13f977af8c003e0bca5", + "chopper_command.bin": "c1cb228470a87beb5f36e90ac745da26", + "crazy_climber.bin": "55ef7b65066428367844342ed59f956c", + "crossbow.bin": "8cd26dcf249456fe4aeb8db42d49df74", + "darkchambers.bin": "106855474c69d08c8ffa308d47337269", + "defender.bin": "0f643c34e40e3f1daafd9c524d3ffe64", + "demon_attack.bin": "f0e0addc07971561ab80d9abe1b8d333", + "donkey_kong.bin": "36b20c427975760cb9cf4a47e41369e4", + "double_dunk.bin": "368d88a6c071caba60b4f778615aae94", + "earthworld.bin": "5aea9974b975a6a844e6df10d2b861c4", + "elevator_action.bin": "71f8bacfbdca019113f3f0801849057e", + "enduro.bin": "94b92a882f6dbaa6993a46e2dcc58402", + "entombed.bin": "6b683be69f92958abe0e2a9945157ad5", + "et.bin": "615a3bf251a38eb6638cdc7ffbde5480", + "fishing_derby.bin": "b8865f05676e64f3bec72b9defdacfa7", + "flag_capture.bin": "30512e0e83903fc05541d2f6a6a62654", + "freeway.bin": "8e0ab801b1705a740b476b7f588c6d16", + "frogger.bin": "081e2c114c9c20b61acf25fc95c71bf4", + "frostbite.bin": "4ca73eb959299471788f0b685c3ba0b5", + "galaxian.bin": "211774f4c5739042618be8ff67351177", + "gopher.bin": "c16c79aad6272baffb8aae9a7fff0864", + "gravitar.bin": "8ac18076d01a6b63acf6e2cab4968940", + "hangman.bin": "f16c709df0a6c52f47ff52b9d95b7d8d", + "haunted_house.bin": "f0a6e99f5875891246c3dbecbf2d2cea", + "hero.bin": "fca4a5be1251927027f2c24774a02160", + "human_cannonball.bin": "7972e5101fa548b952d852db24ad6060", + "ice_hockey.bin": "a4c08c4994eb9d24fb78be1793e82e26", + "jamesbond.bin": "e51030251e440cffaab1ac63438b44ae", + "journey_escape.bin": "718ae62c70af4e5fd8e932fee216948a", + "kaboom.bin": "5428cdfada281c569c74c7308c7f2c26", + "kangaroo.bin": "4326edb70ff20d0ee5ba58fa5cb09d60", + "keystone_kapers.bin": "6c1f3f2e359dbf55df462ccbcdd2f6bf", + "king_kong.bin": "0dd4c69b5f9a7ae96a7a08329496779a", + "klax.bin": "eed9eaf1a0b6a2b9bc4c8032cb43e3fb", + "koolaid.bin": "534e23210dd1993c828d944c6ac4d9fb", + "krull.bin": "4baada22435320d185c95b7dd2bcdb24", + "kung_fu_master.bin": "5b92a93b23523ff16e2789b820e2a4c5", + "laser_gates.bin": "8e4cd60d93fcde8065c1a2b972a26377", + "lost_luggage.bin": "2d76c5d1aad506442b9e9fb67765e051", + "mario_bros.bin": "e908611d99890733be31733a979c62d8", + "miniature_golf.bin": "df62a658496ac98a3aa4a6ee5719c251", + "montezuma_revenge.bin": "3347a6dd59049b15a38394aa2dafa585", + "mr_do.bin": "aa7bb54d2c189a31bb1fa20099e42859", + "ms_pacman.bin": "87e79cd41ce136fd4f72cc6e2c161bee", + "name_this_game.bin": "36306070f0c90a72461551a7a4f3a209", + "othello.bin": "113cd09c9771ac278544b7e90efe7df2", + "pacman.bin": "fc2233fc116faef0d3c31541717ca2db", + "phoenix.bin": "7e52a95074a66640fcfde124fffd491a", + "pitfall2.bin": "6d842c96d5a01967be9680080dd5be54", + "pitfall.bin": "3e90cf23106f2e08b2781e41299de556", + "pong.bin": "60e0ea3cbe0913d39803477945e9e5ec", + "pooyan.bin": "4799a40b6e889370b7ee55c17ba65141", + "private_eye.bin": "ef3a4f64b6494ba770862768caf04b86", + "qbert.bin": "484b0076816a104875e00467d431c2d2", + "riverraid.bin": "393948436d1f4cc3192410bb918f9724", + "road_runner.bin": "ce5cc62608be2cd3ed8abd844efb8919", + "robotank.bin": "4f618c2429138e0280969193ed6c107e", + "seaquest.bin": "240bfbac5163af4df5ae713985386f92", + "sir_lancelot.bin": "dd0cbe5351551a538414fb9e37fc56e8", + "skiing.bin": "b76fbadc8ffb1f83e2ca08b6fb4d6c9f", + "solaris.bin": "e72eb8d4410152bdcb69e7fba327b420", + "space_invaders.bin": "72ffbef6504b75e69ee1045af9075f66", + "space_war.bin": "b702641d698c60bcdc922dbd8c9dd49c", + "star_gunner.bin": "a3c1c70024d7aabb41381adbfb6d3b25", + "superman.bin": "a9531c763077464307086ec9a1fd057d", + "surround.bin": "4d7517ae69f95cfbc053be01312b7dba", + "tennis.bin": "42cdd6a9e42a3639e190722b8ea3fc51", + "tetris.bin": "b0e1ee07fbc73493eac5651a52f90f00", + "tic_tac_toe_3d.bin": "0db4f4150fecf77e4ce72ca4d04c052f", + "time_pilot.bin": "fc2104dd2dadf9a6176c1c1c8f87ced9", + "trondead.bin": "fb27afe896e7c928089307b32e5642ee", + "turmoil.bin": "7a5463545dfb2dcfdafa6074b2f2c15e", + "tutankham.bin": "085322bae40d904f53bdcc56df0593fc", + "up_n_down.bin": "a499d720e7ee35c62424de882a3351b6", + "venture.bin": "3e899eba0ca8cd2972da1ae5479b4f0d", + "video_checkers.bin": "539d26b6e9df0da8e7465f0f5ad863b7", + "video_chess.bin": "f0b7db930ca0e548c41a97160b9f6275", + "video_cube.bin": "3f540a30fdee0b20aed7288e4a5ea528", + "video_pinball.bin": "107cc025334211e6d29da0b6be46aec7", + "wizard_of_wor.bin": "7e8aa18bc9502eb57daaf5e7c1e94da7", + "word_zapper.bin": "ec3beb6d8b5689e867bafb5d5f507491", + "yars_revenge.bin": "c5930d0e8cdae3e037349bfa08e871be", + "zaxxon.bin": "eea0da9b987d661264cce69a7c13c3bd" +} diff --git a/src/python/roms/md5.txt b/src/python/roms/md5.txt deleted file mode 120000 index b9bf6d10a..000000000 --- a/src/python/roms/md5.txt +++ /dev/null @@ -1 +0,0 @@ -../../../md5.txt \ No newline at end of file diff --git a/src/python/roms/miniature_golf.bin b/src/python/roms/miniature_golf.bin new file mode 100644 index 000000000..f02a02a5a Binary files /dev/null and b/src/python/roms/miniature_golf.bin differ diff --git a/src/python/roms/montezuma_revenge.bin b/src/python/roms/montezuma_revenge.bin new file mode 100644 index 000000000..858309a4e Binary files /dev/null and b/src/python/roms/montezuma_revenge.bin differ diff --git a/src/python/roms/mr_do.bin b/src/python/roms/mr_do.bin new file mode 100644 index 000000000..ff01de527 Binary files /dev/null and b/src/python/roms/mr_do.bin differ diff --git a/src/python/roms/ms_pacman.bin b/src/python/roms/ms_pacman.bin new file mode 100644 index 000000000..4b10657b8 Binary files /dev/null and b/src/python/roms/ms_pacman.bin differ diff --git a/src/python/roms/name_this_game.bin b/src/python/roms/name_this_game.bin new file mode 100644 index 000000000..2ccfe68d2 Binary files /dev/null and b/src/python/roms/name_this_game.bin differ diff --git a/src/python/roms/othello.bin b/src/python/roms/othello.bin new file mode 100644 index 000000000..49e0b1832 Binary files /dev/null and b/src/python/roms/othello.bin differ diff --git a/src/python/roms/pacman.bin b/src/python/roms/pacman.bin new file mode 100644 index 000000000..78caafade Binary files /dev/null and b/src/python/roms/pacman.bin differ diff --git a/src/python/roms/phoenix.bin b/src/python/roms/phoenix.bin new file mode 100644 index 000000000..b4bb21f3d Binary files /dev/null and b/src/python/roms/phoenix.bin differ diff --git a/src/python/roms/pitfall.bin b/src/python/roms/pitfall.bin new file mode 100644 index 000000000..3a667676a Binary files /dev/null and b/src/python/roms/pitfall.bin differ diff --git a/src/python/roms/pitfall2.bin b/src/python/roms/pitfall2.bin new file mode 100644 index 000000000..9d0c0dd6e Binary files /dev/null and b/src/python/roms/pitfall2.bin differ diff --git a/src/python/roms/plugins.py b/src/python/roms/plugins.py deleted file mode 100644 index 8dc4e9f06..000000000 --- a/src/python/roms/plugins.py +++ /dev/null @@ -1,108 +0,0 @@ -import abc -import inspect -import pathlib -import sys -import warnings -from typing import Optional, Union - -from ale_py.roms import utils - -# pylint: disable=g-import-not-at-top -if sys.version_info < (3, 10): - import importlib_metadata as metadata -else: - import importlib.metadata as metadata - -if sys.version_info >= (3, 9): - import importlib.resources as resources -else: - import importlib_resources as resources -# pylint: enable=g-import-not-at-top - -from ale_py import ALEInterface - - -class Plugin(abc.ABC): - @abc.abstractmethod - def resolve(self, id: str) -> Optional[pathlib.Path]: - """ - Resolve the ROMs supported by this plugin. - """ - pass - - -class Package(Plugin): - def __init__(self, package: str): - self.package = package - - def resolve(self, id: str) -> Optional[pathlib.Path]: - rom = resources.files(self.package).joinpath(f"{id}.bin") - if not rom.exists(): - return None - return rom - - def __str__(self) -> str: - return f"{self.package}" - - def __repr__(self) -> str: - return f"Package[{self.package}]" - - -class EntryPoint(Plugin): - def __init__(self, group: str): - self.group = group - - def resolve(self, id: str) -> Optional[pathlib.Path]: - # Iterate over all entrypoints in this group - for external in metadata.entry_points(group=self.group): - # We load the external load ROM function and - # update the ROM dict with the result - external_fn = external.load() - sig = inspect.signature(external_fn) - - # Check signature of entry-point for backwards compatibility - if not sig.parameters: - rom = None - for path in external_fn(): - if path.stem == id: - rom = path - break - elif len(sig.parameters) == 1: - rom = external_fn(id) - else: - warnings.warn( - f"Entry point {external_fn} has an invalid signature " - f"with parameters {sig.parameters}" - ) - continue - - if rom is None: - continue - # We'll manually check if the ROM is supported because we don't - # want to exit early in case one plugin provided an invalid ROM. - if ALEInterface.isSupportedROM(rom): - return rom - return None - - def __str__(self) -> str: - return f"{self.group}" - - def __repr__(self) -> str: - return f"EntryPoint[{self.group}]" - - -class Directory(Plugin): - def __init__(self, directory: Union[str, pathlib.Path]): - self.directory = pathlib.Path(directory) - - def resolve(self, id: str) -> Optional[pathlib.Path]: - rom = self.directory.joinpath(f"{id}.bin") - if not rom.exists(): - return None - return rom - - def __str__(self) -> str: - return f"{self.directory}" - - def __repr__(self) -> str: - return f"Directory[{self.directory}]" diff --git a/src/python/roms/pong.bin b/src/python/roms/pong.bin new file mode 100644 index 000000000..14a5bdfc7 Binary files /dev/null and b/src/python/roms/pong.bin differ diff --git a/src/python/roms/pooyan.bin b/src/python/roms/pooyan.bin new file mode 100644 index 000000000..2578e2f1a Binary files /dev/null and b/src/python/roms/pooyan.bin differ diff --git a/src/python/roms/private_eye.bin b/src/python/roms/private_eye.bin new file mode 100644 index 000000000..0d15e45f9 Binary files /dev/null and b/src/python/roms/private_eye.bin differ diff --git a/src/python/roms/qbert.bin b/src/python/roms/qbert.bin new file mode 100644 index 000000000..e844d1497 Binary files /dev/null and b/src/python/roms/qbert.bin differ diff --git a/src/python/roms/riverraid.bin b/src/python/roms/riverraid.bin new file mode 100644 index 000000000..58691ce37 Binary files /dev/null and b/src/python/roms/riverraid.bin differ diff --git a/src/python/roms/road_runner.bin b/src/python/roms/road_runner.bin new file mode 100644 index 000000000..1451b6196 Binary files /dev/null and b/src/python/roms/road_runner.bin differ diff --git a/src/python/roms/robotank.bin b/src/python/roms/robotank.bin new file mode 100644 index 000000000..4471fa1e8 Binary files /dev/null and b/src/python/roms/robotank.bin differ diff --git a/src/python/roms/seaquest.bin b/src/python/roms/seaquest.bin new file mode 100644 index 000000000..d0a5d95a2 Binary files /dev/null and b/src/python/roms/seaquest.bin differ diff --git a/src/python/roms/sir_lancelot.bin b/src/python/roms/sir_lancelot.bin new file mode 100644 index 000000000..8545bf73d Binary files /dev/null and b/src/python/roms/sir_lancelot.bin differ diff --git a/src/python/roms/skiing.bin b/src/python/roms/skiing.bin new file mode 100644 index 000000000..8bb50d6b4 Binary files /dev/null and b/src/python/roms/skiing.bin differ diff --git a/src/python/roms/solaris.bin b/src/python/roms/solaris.bin new file mode 100644 index 000000000..0ed3d8d3d Binary files /dev/null and b/src/python/roms/solaris.bin differ diff --git a/src/python/roms/space_invaders.bin b/src/python/roms/space_invaders.bin new file mode 100644 index 000000000..51750f288 Binary files /dev/null and b/src/python/roms/space_invaders.bin differ diff --git a/src/python/roms/space_war.bin b/src/python/roms/space_war.bin new file mode 100644 index 000000000..b7b267423 Binary files /dev/null and b/src/python/roms/space_war.bin differ diff --git a/src/python/roms/star_gunner.bin b/src/python/roms/star_gunner.bin new file mode 100644 index 000000000..87820fe6e Binary files /dev/null and b/src/python/roms/star_gunner.bin differ diff --git a/src/python/roms/superman.bin b/src/python/roms/superman.bin new file mode 100644 index 000000000..60b04faeb Binary files /dev/null and b/src/python/roms/superman.bin differ diff --git a/src/python/roms/surround.bin b/src/python/roms/surround.bin new file mode 100644 index 000000000..e0b86f3eb Binary files /dev/null and b/src/python/roms/surround.bin differ diff --git a/src/python/roms/tennis.bin b/src/python/roms/tennis.bin new file mode 100644 index 000000000..faef0f0d9 Binary files /dev/null and b/src/python/roms/tennis.bin differ diff --git a/src/python/roms/tic_tac_toe_3d.bin b/src/python/roms/tic_tac_toe_3d.bin new file mode 100644 index 000000000..2156f09a0 Binary files /dev/null and b/src/python/roms/tic_tac_toe_3d.bin differ diff --git a/src/python/roms/time_pilot.bin b/src/python/roms/time_pilot.bin new file mode 100644 index 000000000..37347ed1a Binary files /dev/null and b/src/python/roms/time_pilot.bin differ diff --git a/src/python/roms/trondead.bin b/src/python/roms/trondead.bin new file mode 100644 index 000000000..6096f2a12 Binary files /dev/null and b/src/python/roms/trondead.bin differ diff --git a/src/python/roms/turmoil.bin b/src/python/roms/turmoil.bin new file mode 100644 index 000000000..d44aaa080 Binary files /dev/null and b/src/python/roms/turmoil.bin differ diff --git a/src/python/roms/tutankham.bin b/src/python/roms/tutankham.bin new file mode 100644 index 000000000..cbe3f285f Binary files /dev/null and b/src/python/roms/tutankham.bin differ diff --git a/src/python/roms/up_n_down.bin b/src/python/roms/up_n_down.bin new file mode 100644 index 000000000..290a1e6ed Binary files /dev/null and b/src/python/roms/up_n_down.bin differ diff --git a/src/python/roms/utils.py b/src/python/roms/utils.py deleted file mode 100644 index d492607f3..000000000 --- a/src/python/roms/utils.py +++ /dev/null @@ -1,29 +0,0 @@ -import re - -_ROM_NAME_TO_ID_RE = re.compile(r"([0-9]*[A-Z][a-z]*(\d*$)?)") - - -def rom_id_to_name(rom: str) -> str: - """ - Let the ROM ID be the ROM identifier in snakecase. - For example, `space_invaders` - The ROM name is the ROM ID in camelcase. - For example, `SpaceInvaders` - - This function converts the ROM ID to the ROM name. - i.e., snakecase -> camelcase - """ - return rom.title().replace("_", "") - - -def rom_name_to_id(rom: str) -> str: - """ - Let the ROM ID be the ROM identifier in snakecase. - For example, `space_invaders` - The ROM name is the ROM ID in camelcase. - For example, `SpaceInvaders` - - This function converts the ROM name to the ROM ID. - i.e., camelcase -> snakecase - """ - return _ROM_NAME_TO_ID_RE.sub(r"\1_", rom).lower().rstrip("_") diff --git a/src/python/roms/venture.bin b/src/python/roms/venture.bin new file mode 100644 index 000000000..8b168aa5e Binary files /dev/null and b/src/python/roms/venture.bin differ diff --git a/src/python/roms/video_checkers.bin b/src/python/roms/video_checkers.bin new file mode 100644 index 000000000..0af80cefb Binary files /dev/null and b/src/python/roms/video_checkers.bin differ diff --git a/src/python/roms/video_chess.bin b/src/python/roms/video_chess.bin new file mode 100644 index 000000000..aff226ed3 Binary files /dev/null and b/src/python/roms/video_chess.bin differ diff --git a/src/python/roms/video_cube.bin b/src/python/roms/video_cube.bin new file mode 100644 index 000000000..0ee23f016 Binary files /dev/null and b/src/python/roms/video_cube.bin differ diff --git a/src/python/roms/video_pinball.bin b/src/python/roms/video_pinball.bin new file mode 100644 index 000000000..b68b0eec9 Binary files /dev/null and b/src/python/roms/video_pinball.bin differ diff --git a/src/python/roms/warlords.bin b/src/python/roms/warlords.bin new file mode 100644 index 000000000..4bf5fb96f Binary files /dev/null and b/src/python/roms/warlords.bin differ diff --git a/src/python/roms/wizard_of_wor.bin b/src/python/roms/wizard_of_wor.bin new file mode 100644 index 000000000..d02165a9f Binary files /dev/null and b/src/python/roms/wizard_of_wor.bin differ diff --git a/src/python/roms/word_zapper.bin b/src/python/roms/word_zapper.bin new file mode 100644 index 000000000..5e5f3cdd2 Binary files /dev/null and b/src/python/roms/word_zapper.bin differ diff --git a/src/python/roms/yars_revenge.bin b/src/python/roms/yars_revenge.bin new file mode 100644 index 000000000..9545161e4 Binary files /dev/null and b/src/python/roms/yars_revenge.bin differ diff --git a/src/python/roms/zaxxon.bin b/src/python/roms/zaxxon.bin new file mode 100644 index 000000000..fbb7188af Binary files /dev/null and b/src/python/roms/zaxxon.bin differ diff --git a/src/python/scripts/__init__.py b/src/python/scripts/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/python/scripts/import_roms.py b/src/python/scripts/import_roms.py deleted file mode 100644 index 14a71e266..000000000 --- a/src/python/scripts/import_roms.py +++ /dev/null @@ -1,102 +0,0 @@ -import argparse -import pathlib -import shutil -import sys -import warnings -from typing import Optional - -import ale_py - -if sys.version_info >= (3, 9): - import importlib.resources as resources -else: - import importlib_resources as resources - - -def import_roms( - romdir: pathlib.Path, - datadir: pathlib.Path, - pkg: Optional[str] = None, - dry_run: bool = False, -) -> None: - """ - Recursively copies all compatible ROMs in romdir - to datadir using the proper filename for the ALE. - """ - - supported = {} - unsupported = [] - for path in romdir.glob("**/*.bin"): - rom = ale_py.ALEInterface.isSupportedROM(path) - if rom is not None: - supported[rom] = path - else: - unsupported.append(path) - - # Copy over supported files - for rom, path in supported.items(): - identifier = str(path) if pkg is None else f"{pkg}/{path.name}" - if not dry_run: - shutil.copyfile(path, datadir / f"{rom}.bin") - print(f"\033[92m{'[SUPPORTED]': <15}\033[0m {rom: >20} {identifier: >30}") - - print("\n") - # Print unsuported - for path in unsupported: - identifier = str(path) if pkg is None else f"{pkg}/{path.name}" - print(f"\033[91m{'[NOT SUPPORTED]': <15}\033[0m {'': >20} {identifier: >30}") - - # Print summary - if not dry_run: - print(f"\nImported {len(supported)} / {len(supported)} ROMs") - - -def main() -> None: - """ - CLI for ale-import-roms - """ - parser = argparse.ArgumentParser() - parser.add_argument("--version", action="version", version=ale_py.__version__) - parser.add_argument("--dry-run", action="store_true") - - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument("--import-from-pkg") - group.add_argument("romdir", help="Directory containing ROMs", nargs="?") - - args = parser.parse_args() - - if args.romdir: - romdir = pathlib.Path(args.romdir) - - if not romdir.exists(): - print(f"Path {romdir} doesn't exist.") - sys.exit(1) - elif args.import_from_pkg: - if "." in args.import_from_pkg: - root, subpackage = args.import_from_pkg.split(".", maxsplit=1) - else: - root, subpackage = args.import_from_pkg, None - try: - with resources.path(root, subpackage) as path: - romdir = path.resolve() - if not romdir.exists(): - print(f"Unable to find path {subpackage} in module {root}.") - sys.exit(1) - except ModuleNotFoundError: - print(f"Unable to find module {root}.") - sys.exit(1) - except Exception as e: - print(f"Unknown error {str(e)}.") - sys.exit(1) - - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", category=DeprecationWarning, module="ale_py.roms" - ) - - datadir = resources.files("ale_py.roms") - import_roms(romdir, datadir, pkg=args.import_from_pkg, dry_run=args.dry_run) - - -if __name__ == "__main__": - main() diff --git a/tests/conftest.py b/tests/conftest.py index f57228a2c..5fa194d0b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,5 @@ import os + import pytest diff --git a/tests/python/gym/test_gym_interface.py b/tests/python/gym/test_gym_interface.py index cbc370834..7028008f5 100644 --- a/tests/python/gym/test_gym_interface.py +++ b/tests/python/gym/test_gym_interface.py @@ -8,12 +8,8 @@ import numpy as np from ale_py.env.gym import AtariEnv -from ale_py.gym import ( - _register_gym_configs, - register_gym_envs, - register_legacy_gym_envs, -) - +from ale_py.gym import (_register_gym_configs, register_gym_envs, + register_legacy_gym_envs) from gym import error, spaces from gym.core import Env from gym.envs.registration import registry