Add observation_function for full custom control over the observation

Lets a game define how its state becomes an observation as a plain
Python function (module:attr), used identically by GameEnvironment
(training) and TrainedPolicy (inference) instead of two independently
maintained encoding paths. Removes the egocentric/egocentric_player/
egocentric_radius flags — cropping is now something an
observation_function does itself by calling egocentric_board(), and
extras_size is discovered from one sampled observation instead of
being configured via observe_state_sizes.
This commit is contained in:
Chris Proctor
2026-06-23 20:45:48 -04:00
parent 426e59a54e
commit 0cd3c3b488
14 changed files with 479 additions and 205 deletions

View File

@@ -13,6 +13,12 @@ from retro_gamer.trainer import DQNTrainer, DEFAULTS, MODEL_KEYS
@click.group()
def cli():
"""Train and run RL agents for retro games."""
# Running the installed console script puts its own directory on sys.path,
# not the caller's cwd — but observation_function/game modules are
# typically plain files in the directory you ran retro-gamer from.
cwd = str(Path.cwd())
if cwd not in sys.path:
sys.path.insert(0, cwd)
# ---------------------------------------------------------------------------
@@ -79,8 +85,9 @@ def create(game, output, **hyperparams):
raise click.ClickException(str(e))
game_factory = _load_factory(game_config)
g = game_factory()
metadata.board_size = g.board_size
if metadata.board_size is None:
g = game_factory()
metadata.board_size = g.board_size
metadata.validate()
@@ -108,6 +115,8 @@ def create(game, output, **hyperparams):
else:
click.echo(f" characters : (will be auto-discovered during training)")
click.echo(f" architecture: {'CNN (spatial)' if metadata.spatial else 'MLP (non-spatial)'}")
if metadata.observation_function:
click.echo(f" observation : {metadata.observation_function} (custom)")
# ---------------------------------------------------------------------------