Skip to main content

server/domain/phase/state/
discarding.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{
4    display::format_vec,
5    domain::{
6        Card, Crib, Deck, Hands, HasCrib, HasDeck, HasHands, HasPending, HasRoles, HasScoreboard,
7        Pending, Player, Roles, Scoreboard,
8    },
9};
10
11/// Represents the game state during the *discarding* phase, where
12/// players select cards to contribute to the crib.
13///
14/// This phase occurs after roles have been assigned and hands dealt,
15/// but before the play phase begins. Each player removes cards from
16/// their hand, and those cards are accumulated into the crib for the
17/// upcoming scoring sequence.
18#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
19pub struct Discarding {
20    scoreboard: Scoreboard,
21    roles: Roles,
22    hands: Hands,
23    crib: Crib,
24    deck: Deck,
25    pending: Pending,
26}
27
28impl Discarding {
29    /// Constructs a new `Discarding` state.
30    ///
31    /// The caller must ensure that the provided inputs are coherent and reflect
32    /// a valid pre-discarding state.
33    pub fn new(
34        scoreboard: Scoreboard,
35        roles: Roles,
36        hands: Hands,
37        crib: Crib,
38        deck: Deck,
39        pending: Pending,
40    ) -> Self {
41        Self {
42            scoreboard,
43            roles,
44            hands,
45            crib,
46            deck,
47            pending,
48        }
49    }
50
51    /// Moves the specified cards from `player`’s hand into the crib.
52    ///
53    /// This method performs the following operations atomically:
54    /// 1. Removes all `discards` from the player's hand.
55    /// 2. Adds all `discards` to the crib.
56    /// 3. Marks the player as having completed their discard action
57    ///    via the pending-state mechanism.
58    pub fn discard_cards_to_crib(&mut self, player: Player, discards: &[Card]) {
59        self.hands[player].remove_all(discards);
60        self.crib.add_all(discards);
61        let _ = self.pending.acknowledge(player);
62    }
63}
64
65impl HasScoreboard for Discarding {
66    fn scoreboard(&self) -> &Scoreboard {
67        &self.scoreboard
68    }
69
70    fn scoreboard_mut(&mut self) -> &mut Scoreboard {
71        &mut self.scoreboard
72    }
73}
74
75impl HasRoles for Discarding {
76    fn roles(&self) -> &Roles {
77        &self.roles
78    }
79
80    fn roles_mut(&mut self) -> &mut Roles {
81        &mut self.roles
82    }
83}
84
85impl HasHands for Discarding {
86    fn hands(&self) -> &Hands {
87        &self.hands
88    }
89
90    fn hands_mut(&mut self) -> &mut Hands {
91        &mut self.hands
92    }
93}
94
95impl HasCrib for Discarding {
96    fn crib(&self) -> &Crib {
97        &self.crib
98    }
99
100    fn crib_mut(&mut self) -> &mut Crib {
101        &mut self.crib
102    }
103}
104
105impl HasDeck for Discarding {
106    fn deck(&self) -> &Deck {
107        &self.deck
108    }
109
110    fn deck_mut(&mut self) -> &mut Deck {
111        &mut self.deck
112    }
113}
114
115impl HasPending for Discarding {
116    fn pending(&self) -> &Pending {
117        &self.pending
118    }
119
120    fn pending_mut(&mut self) -> &mut Pending {
121        &mut self.pending
122    }
123}
124
125impl std::fmt::Display for Discarding {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        #[rustfmt::skip]
128        let Self { scoreboard, roles, hands, crib, deck, pending } = self;
129        let hands = format_vec(hands);
130
131        write!(
132            f,
133            r#"Discarding(
134    scoreboard: {scoreboard}
135    roles: {roles}
136    hands: {hands}
137    crib: {crib}
138    deck: {deck}
139    pending: {pending}
140)"#
141        )
142    }
143}