Skip to main content

sample_chance

Function sample_chance 

Source
pub fn sample_chance<G: Game>(
    game: &G,
    state: &G::State,
    rng: &mut Prng,
) -> Option<G::Action>
Expand description

Samples one outcome from game.chance_outcomes(state), weighted by probability, using rng. Returns None if there are no outcomes.

rng is the chance sampler’s generator, owned by the driver or search loop, deliberately separate from any per-state generator a game uses for implicit rolls inside apply. Given the same generator position and the same outcome list, the draw is reproducible, which is what makes replay and undo/redo of a dealt card land on the same result.

The returned action is one of the outcomes; the caller applies it with PlayerId::CHANCE to commit it to state. Use it in a driver or rollout loop whenever the chance pseudo-player is active.

§Example

use turnbase::{ActivePlayers, Game, PlayerId, Prng, sample_chance};

// One chance node that reveals a card 0, 1, or 2 (uniform by default).
struct Reveal;
impl Game for Reveal {
    type State = ();
    type Action = u8;
    type View = ();
    fn new_initial_state(&self, _seed: u64) {}
    fn num_players(&self) -> usize { 0 }
    fn active_players(&self, _s: &()) -> ActivePlayers { ActivePlayers::one(PlayerId::CHANCE) }
    fn legal_actions(&self, _s: &(), p: PlayerId) -> Vec<u8> {
        if p.is_chance() { vec![0, 1, 2] } else { vec![] }
    }
    fn apply(&self, _s: &mut (), _p: PlayerId, _a: u8) {}
    fn is_terminal(&self, _s: &()) -> bool { false }
    fn reward(&self, _s: &(), _p: PlayerId) -> f64 { 0.0 }
    fn view(&self, _s: &(), _v: Option<PlayerId>) {}
}

let mut sampler = Prng::new(42);
let mut state = ();
if Reveal.active_players(&state).contains(PlayerId::CHANCE) {
    let card = sample_chance(&Reveal, &state, &mut sampler).unwrap();
    Reveal.apply(&mut state, PlayerId::CHANCE, card); // commit the draw
    assert!(card <= 2);
}