diff --git a/src/blackjack.rs b/src/blackjack.rs index eb8690e..d038c27 100644 --- a/src/blackjack.rs +++ b/src/blackjack.rs @@ -8,15 +8,35 @@ pub struct BlackjackGame { } pub struct Player { - hand: Hand, - state: PlayerState, + hands: Vec, } impl Player { fn new() -> Self { - Player { + Player { hands: Vec::new() } + } + + pub fn get_hands(&self) -> &Vec { + &self.hands + } + + fn next_playing_hand(&self) -> Option { + self.hands + .iter() + .position(|e| e.state == HandState::Playing) + } +} + +pub struct PlayingHand { + hand: Hand, + state: HandState, +} + +impl PlayingHand { + fn new() -> Self { + PlayingHand { hand: Hand::new(), - state: PlayerState::Playing, + state: HandState::Playing, } } @@ -24,13 +44,13 @@ impl Player { &self.hand } - pub fn get_state(&self) -> &PlayerState { - &self.state + pub fn get_state(&self) -> HandState { + self.state } } #[derive(Clone, Copy, Debug, PartialEq)] -pub enum PlayerState { +pub enum HandState { Playing, Standing, DoubleDown, @@ -49,8 +69,8 @@ pub enum PlayMoves { pub enum GameState { Starting, - Over, // Game is over - PlayerTurn(usize), // Its the turn of the player + Over, // Game is over + PlayerTurn(usize, usize), // Its the turn of the player } impl BlackjackGame { @@ -81,115 +101,194 @@ impl BlackjackGame { pub fn play(&mut self, action: PlayMoves) -> bool { match (&self.state, action) { - (GameState::PlayerTurn(i), PlayMoves::Hit) => { - let Some(player) = self.players.get_mut(*i) else { + (GameState::PlayerTurn(player_index, hand_index), PlayMoves::Hit) => { + let Some(player) = self.players.get_mut(*player_index) else { + // Player does not exists return false; }; - if player.state != PlayerState::Playing { + let Some(hand) = player.hands.get_mut(*hand_index) else { + // Hand does not exist + return false; + }; + + if hand.state != HandState::Playing { return false; } - player.hand.add_card(self.shoe.pop_card().unwrap()); - match player.hand.get_blackjack_value().cmp(&21) { + hand.hand.add_card(self.shoe.pop_card().unwrap()); + + match hand.hand.get_blackjack_value().cmp(&21) { std::cmp::Ordering::Equal => { - player.state = PlayerState::Maxed; + hand.state = HandState::Maxed; } std::cmp::Ordering::Greater => { - player.state = PlayerState::Busted; + hand.state = HandState::Busted; } std::cmp::Ordering::Less => { // Player is still playing } }; } - (GameState::PlayerTurn(i), PlayMoves::DoubleDown) => { - let Some(player) = self.players.get_mut(*i) else { + (GameState::PlayerTurn(player_index, hand_index), PlayMoves::DoubleDown) => { + let Some(player) = self.players.get_mut(*player_index) else { + // Player does not exists return false; }; - if player.state != PlayerState::Playing { + let Some(hand) = player.hands.get_mut(*hand_index) else { + // Hand does not exist + return false; + }; + + if hand.state != HandState::Playing { return false; } - player.hand.add_card(self.shoe.pop_card().unwrap()); - match player.hand.get_blackjack_value().cmp(&21) { - std::cmp::Ordering::Equal | std::cmp::Ordering::Less => { - player.state = PlayerState::Maxed; + if hand.hand.count() != 2 { + // Can oly double down as your first move + return false; + } + + hand.hand.add_card(self.shoe.pop_card().unwrap()); + + match hand.hand.get_blackjack_value().cmp(&21) { + std::cmp::Ordering::Equal => { + hand.state = HandState::Maxed; + } + std::cmp::Ordering::Less => { + hand.state = HandState::Standing; } std::cmp::Ordering::Greater => { - player.state = PlayerState::Busted; + hand.state = HandState::Busted; } }; } - (GameState::PlayerTurn(i), PlayMoves::Stand) => { - let Some(player) = self.players.get_mut(*i) else { + (GameState::PlayerTurn(player_index, hand_index), PlayMoves::Stand) => { + let Some(player) = self.players.get_mut(*player_index) else { + // Player does not exists return false; }; - if player.state != PlayerState::Playing { + let Some(hand) = player.hands.get_mut(*hand_index) else { + // Hand does not exist + return false; + }; + + if hand.state != HandState::Playing { + // Can only stand on playing hands return false; } - player.state = PlayerState::Standing; + hand.state = HandState::Standing; } (GameState::Over, PlayMoves::Deal(player_count)) | (GameState::Starting, PlayMoves::Deal(player_count)) => { - for i in 0..player_count { + + // Create players + for _ in 0..player_count{ self.players.push(Player::new()); - self.players[i].hand.add_card(self.shoe.pop_card().unwrap()); } - self.dealer_hand.add_card(self.shoe.pop_card().unwrap()); + // Create one hand for the players + for player in self.players.iter_mut(){ + player.hands.push(PlayingHand::new()); + } - for i in 0..player_count { - self.players[i].hand.add_card(self.shoe.pop_card().unwrap()); - - if self.players[i].hand.is_backjack() { - self.players[i].state = PlayerState::Blackjack; + // Add one card to each hand the players have + for player in self.players.iter_mut(){ + for hand in player.hands.iter_mut(){ + hand.hand.add_card(self.shoe.pop_card().unwrap()); } } + // Add one card to the dealer self.dealer_hand.add_card(self.shoe.pop_card().unwrap()); - self.state = GameState::PlayerTurn(0); + // Add the 2nd card to the players hand + for player in self.players.iter_mut(){ + for hand in player.hands.iter_mut(){ + hand.hand.add_card(self.shoe.pop_card().unwrap()); + + if hand.hand.is_backjack() { + hand.state = HandState::Blackjack; + } + } + } + + // Add 2nd card to the dealer + self.dealer_hand.add_card(self.shoe.pop_card().unwrap()); + + self.state = GameState::PlayerTurn(0, 0); } (_, PlayMoves::Deal(_)) | (GameState::Over, _) | (GameState::Starting, _) => { return false; } } - let player_count = self.players.len(); + // Find next player or dealer turn + if let Some(next_turn) = self.next_player_and_hand() { + self.state = GameState::PlayerTurn(next_turn.0, next_turn.1); + } else { + self.dealer_turn(); + } - match self.state { - GameState::PlayerTurn(i) => { - if self.players[i].state == PlayerState::Playing { - self.state = GameState::PlayerTurn(i); - } else if i + 1 >= player_count { - loop { - let dealer_value = self.dealer_hand.get_blackjack_value(); - if dealer_value >= 17 { - // Check winners - self.state = GameState::Over; - return true; - } + return true; + } - self.dealer_hand.add_card(self.shoe.pop_card().unwrap()); - - if self.dealer_hand.get_blackjack_value() > 21 { - // Dealer busts - self.state = GameState::Over; - return true; - } - } - } else { - self.state = GameState::PlayerTurn(i + 1); - } - return true; + fn dealer_turn(&mut self) { + loop { + let dealer_value = self.dealer_hand.get_blackjack_value(); + if dealer_value >= 17 { + // Dealer stands + self.state = GameState::Over; + return; } - _ => { - return false; + + self.dealer_hand.add_card(self.shoe.pop_card().unwrap()); + + if self.dealer_hand.get_blackjack_value() > 21 { + // Dealer busts + self.state = GameState::Over; + return; } } } + + fn next_player_and_hand(&self) -> Option<(usize, usize)> { + if let GameState::PlayerTurn(player_index, hand_index) = self.state { + let Some(player) = self.players.get(player_index) else { + // Player does not exists + return None; + }; + + let Some(hand) = player.hands.get(hand_index) else { + // Hand does not exist + return None; + }; + + if hand.state == HandState::Playing { + // Hand is still playing + return Some((player_index, hand_index)); + } + + // Get next valid hand for player + if let Some(next_hand) = player.next_playing_hand() { + return Some((player_index, next_hand)); + } + + // Get next valid player + if let Some(next_hand) = self.players.iter().enumerate().find_map(|p| { + if let Some(h) = p.1.next_playing_hand(){ + Some((p.0,h)) + }else{ + None + } + }) { + return Some((next_hand.0, next_hand.1)); + } + } + + None + } } diff --git a/src/console_blackjack.rs b/src/console_blackjack.rs index 244d008..14a7df7 100644 --- a/src/console_blackjack.rs +++ b/src/console_blackjack.rs @@ -7,7 +7,7 @@ pub fn play() -> Result<(), Box> { loop { match game.get_state() { - GameState::PlayerTurn(player_index) => { + GameState::PlayerTurn(player_index,_) => { print_full_state(&game); let play_move = get_move(*player_index)?; if !game.play(play_move){ @@ -28,7 +28,7 @@ pub fn play() -> Result<(), Box> { fn get_move(player_index: usize) -> Result { loop { - println!("P{}, (H)it (S)tand (D)double",player_index); + println!("Turn {}: (H)it (S)tand (D)double",player_index); let mut buffer = String::new(); stdin().read_line(&mut buffer)?; @@ -47,6 +47,9 @@ fn print_full_state(game: &BlackjackGame) { for player_index in 0..game.get_player_count(){ let player = game.get_player(player_index).unwrap(); - println!("P{}: {} ({})",player_index,player.get_hand(),player.get_hand().get_blackjack_value()); + println!("Player {}:",player_index); + for hand in player.get_hands().iter().enumerate(){ + println!("{}: {} ({}) - {:?}",hand.0,hand.1.get_hand(),hand.1.get_hand().get_blackjack_value(),hand.1.get_state()); + } } }