Skip to main content

yahtzee_engine/
view.rs

1//! The decision context handed to strategies.
2
3use crate::{Categories, Dice, Game, Scorecard, State};
4
5/// What the acting player looks at while deciding.
6///
7/// Yahtzee is a perfect-information game, so this is a convenience
8/// bundle rather than a hygiene wall: it points the strategy at its own
9/// card, the dice, and the rolls remaining, with opponents available for
10/// match-aware play.
11#[derive(Debug, Clone, Copy)]
12pub struct View<'a> {
13    game: &'a Game,
14}
15
16impl<'a> View<'a> {
17    pub(crate) const fn new(game: &'a Game) -> Self {
18        Self { game }
19    }
20
21    /// The dice on the table.
22    ///
23    /// # Panics
24    ///
25    /// Panics if no dice are showing; the engine only consults a
26    /// strategy while they are.
27    #[must_use]
28    pub fn dice(&self) -> Dice {
29        self.game.dice().expect("dice are showing")
30    }
31
32    /// How many rolls remain this turn.
33    #[must_use]
34    pub const fn rolls_left(&self) -> u8 {
35        self.game.rolls_left()
36    }
37
38    /// The acting player's seat.
39    #[must_use]
40    pub const fn seat(&self) -> usize {
41        self.game.seat()
42    }
43
44    /// The current round, `0..13`.
45    #[must_use]
46    pub const fn round(&self) -> u8 {
47        self.game.round()
48    }
49
50    /// The acting player's card.
51    #[must_use]
52    pub fn scorecard(&self) -> &'a Scorecard {
53        self.game.scorecard(self.seat())
54    }
55
56    /// The acting player's compact rules state.
57    #[must_use]
58    pub fn state(&self) -> State {
59        self.scorecard().state()
60    }
61
62    /// The categories the dice may legally be scored in.
63    ///
64    /// # Panics
65    ///
66    /// Panics if no dice are showing, like [`dice`](Self::dice).
67    #[must_use]
68    pub fn legal_categories(&self) -> Categories {
69        self.state().legal_categories(self.dice())
70    }
71
72    /// The other players' cards, in seat order after the acting player.
73    pub fn opponents(&self) -> impl Iterator<Item = &'a Scorecard> {
74        let seat = self.seat();
75        let cards = self.game.scorecards();
76        cards[seat + 1..].iter().chain(&cards[..seat])
77    }
78}