Skip to main content

Simulator

Struct Simulator 

pub struct Simulator<G>
where G: Game,
{ /* private fields */ }
Expand description

Coordinates one match: the rules (G), its current position, which agent controls each seat, and a running log of committed actions.

Pure in-memory bookkeeping: Simulator::step and Simulator::select_human_action are the only ways the position changes, and both just forward to Game::apply. There is no terminal, socket, or timer here, so a simulator runs identically under cargo test and behind a rendering client.

A chance node (PlayerId::CHANCE active) is not a seat any agent controls; Simulator::step resolves it automatically by sampling from chance, a generator seeded from the match seed but offset so it does not share a stream with the state’s own generator.

Implementations§

§

impl<G> Simulator<G>
where G: Game,

pub fn new( game: G, seed: u64, agents: HashMap<PlayerId, PlayerAgent<G>>, ) -> Simulator<G>

Starts a match: game.new_initial_state(seed) seeded with seed, with agents controlling each seat.

pub const fn game(&self) -> &G

Returns the rules governing this match.

pub const fn state(&self) -> &<G as Game>::State

Returns the current position.

pub fn log_history(&self) -> &[String]

Returns every action committed so far, oldest first, formatted for display (a log monitor, a test assertion) rather than for replay.

pub fn awaiting_human(&self) -> Option<PlayerId>

Returns the seat a human is expected to act for right now, if any.

The first (lowest seat index) active PlayerAgent::Human seat, since turnbase::ActivePlayers iterates in ascending order; simultaneous phases with more than one human seat resolve one at a time, same as Simulator::step resolves AI seats one at a time.

pub fn is_terminal(&self) -> bool

Returns whether the match has ended.

pub fn primary_human(&self) -> Option<PlayerId>

Returns the lowest-indexed seat controlled by PlayerAgent::Human, if any.

Iterates a HashMap, so this picks by seat index rather than insertion order, keeping the result deterministic regardless of hash order. turnbase-simulator’s dashboard uses this once, at construction, to decide whose Game::View it renders from for the whole match: a human should never see another seat’s hidden information (their cards, say) just because it happened to be an AI’s turn when the frame was drawn.

§

impl<G> Simulator<G>
where G: Game, <G as Game>::Action: Debug,

pub fn step(&mut self) -> Result<bool, Error>

Advances the match by one atomic decision.

Returns Ok(true) if an AI seat or a chance node advanced, Ok(false) if the match is already over or the active seat is waiting on Simulator::select_human_action, or Err if the bot chose an action Game::is_legal rejects.

A chance node (PlayerId::CHANCE active) is resolved here by sampling a committed outcome, so a driver loop advances past deck deals and dice without any per-game wiring.

§Errors

Returns Error::IllegalAction if the active bot’s chosen action is not legal for it in the current state.

pub fn select_human_action( &mut self, player: PlayerId, action: <G as Game>::Action, ) -> Result<(), Error>

Externally forces player’s action into the state machine.

For a PlayerAgent::Human seat’s UI (or a test) to commit a choice once Simulator::awaiting_human names that seat.

§Errors

Returns Error::NotActive if player is not currently owed a decision, or Error::IllegalAction if action is not legal for them.

Auto Trait Implementations§

§

impl<G> Freeze for Simulator<G>
where G: Freeze, <G as Game>::State: Freeze,

§

impl<G> !RefUnwindSafe for Simulator<G>

§

impl<G> !Send for Simulator<G>

§

impl<G> !Sync for Simulator<G>

§

impl<G> Unpin for Simulator<G>
where G: Unpin, <G as Game>::State: Unpin,

§

impl<G> UnsafeUnpin for Simulator<G>
where G: UnsafeUnpin, <G as Game>::State: UnsafeUnpin,

§

impl<G> !UnwindSafe for Simulator<G>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.