server/domain/plays/
play_state.rs1use constants::*;
2use serde::{Deserialize, Serialize};
3
4use crate::{
5 display::format_vec,
6 domain::{
7 Card, GoStatus, Hand, Hands, PLAYER0, PLAYER1, PLAYERS, Play, Player, ScoreSheet, Value,
8 },
9};
10
11#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
16pub struct PlayState {
17 next_to_play: Player,
18 pending_plays: Vec<Vec<Card>>,
19 go_status: GoStatus,
20 current_plays: Vec<Play>,
21 previous_plays: Vec<Play>,
22}
23
24pub trait HasPlayState {
26 fn play_state(&self) -> &PlayState;
28
29 fn play_state_mut(&mut self) -> &mut PlayState;
31}
32
33impl PlayState {
34 pub fn new(next_to_play: Player) -> Self {
36 Self {
37 next_to_play,
38 pending_plays: vec![Vec::default(), Vec::default()],
39 go_status: GoStatus::default(),
40 current_plays: Vec::default(),
41 previous_plays: Vec::default(),
42 }
43 }
44
45 #[must_use]
47 pub const fn next_to_play(&self) -> Player {
48 self.next_to_play
49 }
50
51 #[must_use]
55 pub fn with_pending_plays(mut self, player: Player, cards: &[Card]) -> Self {
56 self.pending_plays.as_mut_slice()[player] = Vec::from(cards);
57 self
58 }
59
60 #[must_use]
62 pub fn running_total(&self) -> Value {
63 self.current_plays.iter().map(|p| p.card().value()).sum()
64 }
65
66 #[must_use]
69 pub fn has_cards(&self, player: Player) -> bool {
70 !self.pending_plays[player].is_empty()
71 }
72
73 #[must_use]
75 pub fn legal_plays(&self, player: Player) -> Vec<Card> {
76 let running_total = self.running_total();
77 let is_in_limit = |c: &Card| running_total + c.value() <= Value::from(PLAY_TARGET);
78
79 self.pending_plays[player]
80 .iter()
81 .filter_map(|c| is_in_limit(c).then_some(*c))
82 .collect::<Vec<_>>()
83 }
84
85 #[must_use]
87 pub fn current_plays(&self) -> &Vec<Play> {
88 &self.current_plays
89 }
90
91 #[must_use]
93 pub fn previous_plays(&self) -> &Vec<Play> {
94 &self.previous_plays
95 }
96
97 #[must_use]
100 pub fn play(&mut self, card: Card) -> ScoreSheet {
101 let player = self.next_to_play;
102 let opponent = player.opponent();
103
104 self.pending_plays.as_mut_slice()[player].retain(|c| c != &card);
105 self.current_plays.push(Play::new(player, card));
106 let sheet = ScoreSheet::play_card(self);
107
108 let reached_target = self.running_total() == Value::from(PLAY_TARGET);
109 let player_has_cards = self.has_cards(player);
110 let opponent_has_cards = self.has_cards(opponent);
111
112 if reached_target {
113 self.start_new_play();
114 } else {
115 match self.go_status {
116 GoStatus::NotCalled if opponent_has_cards => {
117 self.next_to_play = opponent;
118 }
119 GoStatus::NotCalled => {}
120 GoStatus::Called | GoStatus::PlayContinued => {
121 self.go_status = GoStatus::PlayContinued;
122 if !player_has_cards {
124 self.start_new_play();
125 }
126 }
127 }
128 }
129
130 sheet
131 }
132
133 #[must_use]
135 pub fn go(&mut self) -> ScoreSheet {
136 let player = self.next_to_play;
137 let opponent = player.opponent();
138
139 let opponent_has_cards = self.has_cards(opponent);
140
141 let mut sheet = ScoreSheet::default();
142
143 match self.go_status {
144 GoStatus::NotCalled if opponent_has_cards => {
145 self.go_status = GoStatus::Called;
146 self.next_to_play = opponent;
147 }
148 GoStatus::NotCalled => {
149 self.go_status = GoStatus::Called;
150 sheet = ScoreSheet::go(self);
151 self.start_new_play();
152 }
153 GoStatus::Called | GoStatus::PlayContinued => {
154 sheet = ScoreSheet::go(self);
155 self.start_new_play();
156 }
157 }
158
159 sheet
160 }
161
162 fn start_new_play(&mut self) {
163 let last_player = self
166 .current_plays
167 .last()
168 .map_or(self.next_to_play, Play::player);
169 let opponent = last_player.opponent();
170 let opponent_has_cards = self.has_cards(opponent);
171
172 self.next_to_play = if opponent_has_cards {
173 opponent
174 } else {
175 last_player
176 };
177
178 self.previous_plays.append(&mut self.current_plays);
179
180 self.go_status = GoStatus::NotCalled;
181 }
182
183 #[must_use]
185 pub fn is_finished(&self) -> bool {
186 self.pending_plays.iter().all(Vec::is_empty)
187 }
188
189 #[must_use]
191 pub fn finish_plays(&mut self) -> Hands {
192 let hands = self.regather_hands();
193 self.current_plays = Vec::default();
194 self.previous_plays = Vec::default();
195 hands
196 }
197
198 fn regather_hands(&self) -> Hands {
199 let plays = self
200 .previous_plays
201 .iter()
202 .chain(self.current_plays.iter())
203 .collect::<Vec<_>>();
204
205 let hands = PLAYERS
206 .into_iter()
207 .map(|player| {
208 plays
209 .iter()
210 .filter_map(|p| (p.player() == player).then_some(p.card()))
211 .collect::<Hand>()
212 })
213 .collect::<Vec<_>>();
214 let hands = hands.as_slice();
215
216 [hands[PLAYER0].clone(), hands[PLAYER1].clone()]
217 }
218
219 #[must_use]
221 pub fn go_status(&self) -> &GoStatus {
222 &self.go_status
223 }
224
225 #[cfg(test)]
226 pub(crate) fn go_status_mut(&mut self) -> &mut GoStatus {
227 &mut self.go_status
228 }
229
230 #[cfg(test)]
231 pub(crate) fn current_plays_mut(&mut self) -> &mut Vec<Play> {
232 &mut self.current_plays
233 }
234
235 #[cfg(test)]
236 pub(crate) fn previous_plays_mut(&mut self) -> &mut Vec<Play> {
237 &mut self.previous_plays
238 }
239}
240
241impl std::fmt::Display for PlayState {
242 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243 write!(
244 f,
245 "Next({}), GoStatus({}), Pending({} -> {}, {} -> {}), Current({}), Previous({})",
246 self.next_to_play,
247 self.go_status.as_ref(),
248 PLAYER0,
249 format_vec(&self.pending_plays[PLAYER0]),
250 PLAYER1,
251 format_vec(&self.pending_plays[PLAYER1]),
252 format_vec(&self.current_plays),
253 format_vec(&self.previous_plays)
254 )
255 }
256}