WorldModel-ConnectX / connectx /environment.py
alextoti1's picture
Publish full project code and checkpoint
9ede8c0 verified
Raw
History Blame Contribute Delete
2.51 kB
"""
Minimal common interface for a "domain" this codebase can train on. A state
is any fixed-length tuple of numbers; how those numbers are interpreted is
entirely up to the implementation below (`connectx_env.py`). Nothing in
`model.py` / `train_utils.py` / `search.py` needs to change to support a new
domain that implements this interface.
"""
from abc import ABC, abstractmethod
class Environment(ABC):
# Every state built by this codebase is a discrete, exactly-hashable
# tuple (a one-hot-encoded Connect-4 board) -- kept as a class attribute
# rather than hardcoded into `search.py`'s cycle-detection logic so a
# future continuous-state domain could override it there without
# touching this interface.
discrete_state = True
def observe(self, state):
"""What the model is allowed to see, as a function of the true
state. Default: full observability (identity). ConnectX is fully
observable, so this is never overridden -- kept as an explicit
extension point rather than removed, since every place that feeds
a state to the model calls this first, not the raw state."""
return state
@property
@abstractmethod
def state_dim(self):
"""Length of the fixed-size numeric tuple representing a state."""
@property
@abstractmethod
def num_actions(self):
"""Size of the fixed, discrete action space."""
@property
@abstractmethod
def always_legal_actions(self):
"""Action indices legal from EVERY state, unconditionally -- used
by search's neurosymbolic decode-gate to fall back on safely."""
@abstractmethod
def is_solved(self, state):
...
@abstractmethod
def is_legal(self, state, action_idx):
...
@abstractmethod
def step(self, state, action_idx):
"""Returns (next_state, reward, done). Assumes legality."""
@abstractmethod
def random_problem(self, rng, **kwargs):
"""Returns (state, answer) -- answer is domain-specific (unused for
ConnectX, every game starts from the same empty board)."""
@abstractmethod
def bfs_solve(self, state, max_depth=8):
"""Exact oracle: shortest forced win, or None if not found within
max_depth (or if the state space is too large to search -- see
connectx_env.py's BFS_MAX_CELLS)."""
def format_state(self, state):
return str(state)
def format_action(self, action_idx):
return str(action_idx)