pub trait Game {
type State;
type Action: PartialEq;
type View;
// Required methods
fn new_initial_state(&self, seed: u64) -> Self::State;
fn num_players(&self) -> usize;
fn active_players(&self, state: &Self::State) -> ActivePlayers;
fn legal_actions(
&self,
state: &Self::State,
player: PlayerId,
) -> Vec<Self::Action>;
fn apply(
&self,
state: &mut Self::State,
player: PlayerId,
action: Self::Action,
);
fn is_terminal(&self, state: &Self::State) -> bool;
fn reward(&self, state: &Self::State, player: PlayerId) -> f64;
fn view(&self, state: &Self::State, viewer: Option<PlayerId>) -> Self::View;
// Provided methods
fn is_legal(
&self,
state: &Self::State,
player: PlayerId,
action: &Self::Action,
) -> bool { ... }
fn chance_outcomes(&self, state: &Self::State) -> Vec<(Self::Action, f64)> { ... }
fn apply_cloned(
&self,
state: &Self::State,
player: PlayerId,
action: Self::Action,
) -> Result<Self::State, Error>
where Self::State: Clone { ... }
fn step_reward(&self, state: &Self::State, player: PlayerId) -> f64 { ... }
}Expand description
A turn-based game defined as pure functions from state and action to new state.
Per-match configuration (player count, board size, variant rules) lives on
the implementing value (&self), so Self::State stays lean and cheap to
clone (cloning is the default backtracking primitive) and there is one home
for num_players and variant flags. Everything is synchronous and
side-effect-free; randomness comes from a generator stored inside the state.
Required Associated Types§
Sourcetype Action: PartialEq
type Action: PartialEq
A single decision. PartialEq powers the default Self::is_legal
membership check; it is trivially derivable for the small enums and
indices actions usually are.
Sourcetype View
type View
What a player or spectator observes, produced by Self::view.
Required Methods§
Sourcefn new_initial_state(&self, seed: u64) -> Self::State
fn new_initial_state(&self, seed: u64) -> Self::State
Returns the initial position for a match, its generator seeded from
seed.
Sourcefn num_players(&self) -> usize
fn num_players(&self) -> usize
Returns the number of seats in this match: the fixed roster, seats
0..num_players, excluding the chance pseudo-player.
A constant property of the configured match, not a live count and not a
capacity. It does not shrink when a player is eliminated (an eliminated
seat simply stops appearing in Self::active_players and has no legal
actions). “Who owes a decision right now” is Self::active_players;
the seats valid for Self::reward and Self::legal_actions are
0..num_players.
Sourcefn active_players(&self, state: &Self::State) -> ActivePlayers
fn active_players(&self, state: &Self::State) -> ActivePlayers
Returns the players who owe a decision right now.
Empty during engine-only resolution, one for alternating play, many
during simultaneous or secret phases. May contain PlayerId::CHANCE
when a committed random outcome is pending.
Sourcefn legal_actions(
&self,
state: &Self::State,
player: PlayerId,
) -> Vec<Self::Action>
fn legal_actions( &self, state: &Self::State, player: PlayerId, ) -> Vec<Self::Action>
Returns the actions available to player at this decision point.
A full turn is a sequence of apply calls until Self::active_players
changes; this enumerates one decision point, not a whole turn.
Sourcefn apply(&self, state: &mut Self::State, player: PlayerId, action: Self::Action)
fn apply(&self, state: &mut Self::State, player: PlayerId, action: Self::Action)
Advances state in place by applying player’s action.
Assumes the action is legal for an active player; callers that want
checking use Self::apply_cloned. Draw any randomness from the
generator inside state so the effect stays reproducible.
Sourcefn is_terminal(&self, state: &Self::State) -> bool
fn is_terminal(&self, state: &Self::State) -> bool
Returns whether the match has ended.
Provided Methods§
Sourcefn is_legal(
&self,
state: &Self::State,
player: PlayerId,
action: &Self::Action,
) -> bool
fn is_legal( &self, state: &Self::State, player: PlayerId, action: &Self::Action, ) -> bool
Returns whether action is legal for player right now.
Defaults to membership in Self::legal_actions. Override with a direct
check for decision points whose legal set is too large to enumerate
(arbitrary map targeting, payment combinatorics).
Sourcefn chance_outcomes(&self, state: &Self::State) -> Vec<(Self::Action, f64)>
fn chance_outcomes(&self, state: &Self::State) -> Vec<(Self::Action, f64)>
Returns the probability distribution over chance outcomes while
PlayerId::CHANCE is active: each possible outcome action paired with
its probability. The probabilities should sum to 1.
Defaults to uniform over legal_actions(state, CHANCE). Override for
non-uniform chance (loaded dice, weighted decks). Mirrors OpenSpiel’s
chance_outcomes. The committed outcome is chosen by a chance sampler
(see sample_chance) using a generator owned by the driver, distinct
from any per-state generator used for implicit rolls inside apply.
Returns a materialized Vec, not an iterator, because callers pass over
it more than once — summing the weights and then sampling, or
enumerating every outcome for expectiminimax. Chance branching is small,
so the allocation is negligible (this matches OpenSpiel’s materialized
ChanceOutcomes).
Sourcefn apply_cloned(
&self,
state: &Self::State,
player: PlayerId,
action: Self::Action,
) -> Result<Self::State, Error>
fn apply_cloned( &self, state: &Self::State, player: PlayerId, action: Self::Action, ) -> Result<Self::State, Error>
Returns a copy of state advanced by action, without mutating the
original. The default backtracking primitive for search and tests.
§Errors
Returns Error::NotActive if player is not currently active, or
Error::IllegalAction if the action is not legal for them.
Sourcefn step_reward(&self, state: &Self::State, player: PlayerId) -> f64
fn step_reward(&self, state: &Self::State, player: PlayerId) -> f64
Returns player’s immediate reward for the last step.
Defaults to 0 (all signal at the terminal). Override to give RL trainers a dense, per-step, per-player signal.