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}