yahtzee-engine 0.1.0

Yahtzee rules, scoring, and bots: a fast heuristic and an exact optimal expected-value solver
Documentation
//! The decision context handed to strategies.

use crate::{Categories, Dice, Game, Scorecard, State};

/// What the acting player looks at while deciding.
///
/// Yahtzee is a perfect-information game, so this is a convenience
/// bundle rather than a hygiene wall: it points the strategy at its own
/// card, the dice, and the rolls remaining, with opponents available for
/// match-aware play.
#[derive(Debug, Clone, Copy)]
pub struct View<'a> {
    game: &'a Game,
}

impl<'a> View<'a> {
    pub(crate) const fn new(game: &'a Game) -> Self {
        Self { game }
    }

    /// The dice on the table.
    ///
    /// # Panics
    ///
    /// Panics if no dice are showing; the engine only consults a
    /// strategy while they are.
    #[must_use]
    pub fn dice(&self) -> Dice {
        self.game.dice().expect("dice are showing")
    }

    /// How many rolls remain this turn.
    #[must_use]
    pub const fn rolls_left(&self) -> u8 {
        self.game.rolls_left()
    }

    /// The acting player's seat.
    #[must_use]
    pub const fn seat(&self) -> usize {
        self.game.seat()
    }

    /// The current round, `0..13`.
    #[must_use]
    pub const fn round(&self) -> u8 {
        self.game.round()
    }

    /// The acting player's card.
    #[must_use]
    pub fn scorecard(&self) -> &'a Scorecard {
        self.game.scorecard(self.seat())
    }

    /// The acting player's compact rules state.
    #[must_use]
    pub fn state(&self) -> State {
        self.scorecard().state()
    }

    /// The categories the dice may legally be scored in.
    ///
    /// # Panics
    ///
    /// Panics if no dice are showing, like [`dice`](Self::dice).
    #[must_use]
    pub fn legal_categories(&self) -> Categories {
        self.state().legal_categories(self.dice())
    }

    /// The other players' cards, in seat order after the acting player.
    pub fn opponents(&self) -> impl Iterator<Item = &'a Scorecard> {
        let seat = self.seat();
        let cards = self.game.scorecards();
        cards[seat + 1..].iter().chain(&cards[..seat])
    }
}