1use crate::blackjack::errors::BlackJackError;
2use crate::blackjack::hand::Hand;
3use crate::cards::StandardCard as Card;
4use crate::deck::{Deck, DefaultCollection};
5
6#[repr(C)]
10#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
11pub enum GameState {
12 InProgress,
14 PlayerWon,
16 PlayerLost,
18}
19
20#[repr(C)]
21#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
22pub struct FrozenGame {
23 pub player: Vec<Card>,
25 pub dealer: Vec<Card>,
27 pub deck: Vec<Card>,
29 pub player_stay: bool,
32 pub dealer_stay: bool,
35 pub first_turn: bool,
37}
38
39#[repr(C)]
41#[derive(
42 Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Ord, PartialOrd, Hash,
43)]
44pub struct BlackJack {
45 player: Hand,
47 dealer: Hand,
49 first_turn: bool,
51 deck: Deck<crate::cards::StandardCard>,
53 player_stay_status: bool,
55 dealer_stay_status: bool,
57}
58
59impl BlackJack {
60 pub fn new_game(decks: usize) -> Self {
62 let mut deck = Deck::from(crate::cards::StandardCard::multiple_collections(decks));
64
65 deck.shuffle();
66 let player = deck.draw_many(2).into();
68
69 let dealer = deck.draw_many(2).into();
71
72 Self {
73 player,
74 dealer,
75 deck,
76 dealer_stay_status: false,
77 player_stay_status: false,
78 first_turn: true,
79 }
80 }
81 pub fn freeze(self) -> Result<FrozenGame, GameState> {
91 match self.status() {
92 GameState::InProgress => Ok(FrozenGame {
93 player: self.player.into_vec(),
94 dealer: self.dealer.into_vec(),
95 deck: self.deck.into_vec(),
96 first_turn: self.first_turn,
97 player_stay: self.player_stay_status,
98 dealer_stay: self.dealer_stay_status,
99 }),
100 gs => Err(gs),
101 }
102 }
103 pub fn defrost(g: FrozenGame) -> Self {
105 Self {
106 player: g.player.into(),
107 dealer: g.dealer.into(),
108 deck: Deck::from(g.deck),
109 first_turn: g.first_turn,
110 player_stay_status: g.player_stay,
111 dealer_stay_status: g.dealer_stay,
112 }
113 }
114 pub fn status(&self) -> GameState {
120 if self.first_turn {
121 return GameState::InProgress;
122 }
123 let player_score = self.player.score();
125 let dealer_score = self.dealer.score();
126
127 if self.player.cards_len() == 5 && player_score <= 21 {
129 return GameState::PlayerWon;
130 }
131
132 if self.dealer.cards_len() == 5 && dealer_score <= 21 {
134 return GameState::PlayerWon;
135 }
136
137 if player_score == 21 {
139 return GameState::PlayerWon;
140 }
141
142 if dealer_score == 21 {
144 return GameState::PlayerLost;
145 }
146
147 if player_score > 21 {
149 return GameState::PlayerLost;
150 }
151
152 if !(self.player_stay_status || self.dealer_stay_status) {
153 return GameState::InProgress;
154 }
155
156 if player_score == dealer_score {
158 return GameState::PlayerLost;
159 }
160
161 if dealer_score > 21 {
163 return GameState::PlayerWon;
164 }
165
166 if player_score > dealer_score {
168 return GameState::PlayerWon;
169 }
170 if player_score < dealer_score {
171 return GameState::PlayerLost;
172 }
173
174 GameState::InProgress
176 }
177 pub fn player_hit(&mut self) -> Result<(), BlackJackError> {
184 match self.status() {
186 GameState::InProgress => {
187 self.first_turn = false;
188 self.player.add_card(
189 self.deck
190 .draw()
191 .map_err(|_| BlackJackError::OutOfCardsError)?,
192 );
193 Ok(())
194 }
195 GameState::PlayerLost => Err(BlackJackError::PlayerLostError),
196 GameState::PlayerWon => Err(BlackJackError::PlayerWonError),
197 }
198 }
199 pub fn finish(mut self) -> GameState {
203 self.player_stay_status = true;
204 self.dealer_logic();
205 match self.status() {
206 GameState::InProgress => unreachable!(),
208 gs => gs,
209 }
210 }
211 fn dealer_logic(&mut self) {
213 self.first_turn = false;
214 while self.status() == GameState::InProgress && self.dealer.score() <= 17 {
217 match self.deck.draw() {
218 Ok(card) => self.dealer.add_card(card),
219 Err(_) => break,
220 }
221 }
222 self.dealer_stay_status = true;
223 }
224
225 pub fn display_game(&self) -> GameDisplay {
227 if self.first_turn {
228 let (score, cards) = match self.dealer.cards().first() {
229 Some(card) => (card.face().value(), vec![*card]),
230 None => (0, Vec::new()),
231 };
232 GameDisplay {
233 i_dealer_cards: cards,
234 i_dealer_score: score,
235 i_player_cards: self.player.cards().to_vec(),
236 i_player_score: self.player.score(),
237 i_game_state: self.status().into(),
238 }
239 } else {
240 GameDisplay {
241 i_dealer_cards: self.dealer.cards().to_vec(),
242 i_dealer_score: self.dealer.score(),
243 i_player_cards: self.player.cards().to_vec(),
244 i_player_score: self.player.score(),
245 i_game_state: self.status().into(),
246 }
247 }
248 }
249}
250
251impl Default for BlackJack {
252 fn default() -> Self {
253 let mut deck = Deck::from(crate::cards::StandardCard::default_collection());
255 deck.shuffle();
256 let player = deck.draw_many(2).into();
259
260 let dealer = deck.draw_many(2).into();
262
263 Self {
264 player,
265 dealer,
266 deck,
267 dealer_stay_status: false,
268 player_stay_status: false,
269 first_turn: true,
270 }
271 }
272}
273
274#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
276pub enum GameDisplayState {
277 PlayerWon,
279 PlayerLost,
281 InProgress,
283}
284
285impl From<GameState> for GameDisplayState {
286 fn from(val: GameState) -> Self {
287 match val {
288 GameState::PlayerLost => GameDisplayState::PlayerLost,
289 GameState::PlayerWon => GameDisplayState::PlayerWon,
290 _ => GameDisplayState::InProgress,
291 }
292 }
293}
294
295#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
297pub struct GameDisplay {
298 i_game_state: GameDisplayState,
300 i_dealer_score: u8,
302 i_dealer_cards: Vec<Card>,
304 i_player_score: u8,
306 i_player_cards: Vec<Card>,
308}
309
310impl GameDisplay {
311 pub fn dealer_score(&self) -> u8 {
313 self.i_dealer_score
314 }
315 pub fn dealer_hand(&self) -> &[Card] {
317 &self.i_dealer_cards
318 }
319 pub fn player_score(&self) -> u8 {
321 self.i_player_score
322 }
323 pub fn player_hand(&self) -> &[Card] {
325 &self.i_player_cards
326 }
327 pub fn state(&self) -> GameDisplayState {
329 self.i_game_state
330 }
331}
332
333impl core::fmt::Display for GameDisplayState {
334 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
335 match self {
336 GameDisplayState::InProgress => f.write_str("In Progress"),
337 GameDisplayState::PlayerWon => f.write_str("Player Won"),
338 GameDisplayState::PlayerLost => f.write_str("Player Lost"),
339 }
340 }
341}
342
343impl core::fmt::Display for GameDisplay {
344 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
345 writeln!(
346 f,
347 "{}\nDealer: {:#?}({})\nPlayer: {:#?}({})",
348 self.i_game_state,
349 self.i_dealer_cards,
350 self.i_dealer_score,
351 self.i_player_cards,
352 self.i_player_score
353 )
354 }
355}