From bf738604331153624dd14b5084c7e10844985c47 Mon Sep 17 00:00:00 2001 From: Niklas Kapelle Date: Wed, 15 May 2024 13:54:41 +0200 Subject: [PATCH] more improvements --- src/blackjack.rs | 247 +++++++++++++++++++++++---------------- src/console_blackjack.rs | 88 ++++---------- 2 files changed, 169 insertions(+), 166 deletions(-) diff --git a/src/blackjack.rs b/src/blackjack.rs index 8bcaef1..eb8690e 100644 --- a/src/blackjack.rs +++ b/src/blackjack.rs @@ -2,45 +2,64 @@ use crate::{decks::new_blackjack_shoe, hand::Hand}; pub struct BlackjackGame { shoe: Hand, - player_hand: Hand, + players: Vec, dealer_hand: Hand, state: GameState, } -pub enum PlayResult { - DealerBlackJack, // Dealer has a blackjack. Player does not - PlayerBlackJack, // Player has a blackjack. Dealer does not - PushBlackjack, // Player and dealer have a blackjack - Push, // Dealer has a Blackjack and so does the Player - Bust, // Player bust - DealerBust, // Dealer bust - StandPlayerLose, // Dealer stands and wins - StandPlayerWin, // Dealer stands and loses - Continue, // Game goes on as normal - InvalidMove, +pub struct Player { + hand: Hand, + state: PlayerState, } -#[derive(Clone, Copy,Debug)] +impl Player { + fn new() -> Self { + Player { + hand: Hand::new(), + state: PlayerState::Playing, + } + } + + pub fn get_hand(&self) -> &Hand { + &self.hand + } + + pub fn get_state(&self) -> &PlayerState { + &self.state + } +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum PlayerState { + Playing, + Standing, + DoubleDown, + Busted, + Blackjack, + Maxed, // Reached 21 +} + +#[derive(Clone, Copy, Debug)] pub enum PlayMoves { Hit, Stand, DoubleDown, - Bet, // At the Start of the game + Deal(usize), } pub enum GameState { - Empty, // No cards have been dealt - Over, // Game is over - PlayerTurn, // Its the turn of the player + Starting, + Over, // Game is over + PlayerTurn(usize), // Its the turn of the player } impl BlackjackGame { pub fn new() -> Self { BlackjackGame { shoe: new_blackjack_shoe(6), - player_hand: Hand::new(), + players: Vec::new(), dealer_hand: Hand::new(), - state: GameState::Empty, + state: GameState::Starting, } } @@ -48,98 +67,128 @@ impl BlackjackGame { &self.dealer_hand } - pub fn get_player_hand(&self) -> &Hand { - &self.player_hand - } - pub fn get_state(&self) -> &GameState { &self.state } - pub fn play(&mut self, action: PlayMoves) -> PlayResult { - match (&self.state, action) { - (GameState::Empty, PlayMoves::Bet) => { - self.player_hand.add_card(self.shoe.pop_card().unwrap()); - self.dealer_hand.add_card(self.shoe.pop_card().unwrap()); - - self.player_hand.add_card(self.shoe.pop_card().unwrap()); - self.dealer_hand.add_card(self.shoe.pop_card().unwrap()); - - match (self.dealer_hand.is_backjack(),self.player_hand.is_backjack()) { - (true,true) => { - self.state = GameState::Over; - PlayResult::PushBlackjack - }, - (true,false) => { - self.state = GameState::Over; - PlayResult::DealerBlackJack - }, - (false,true) => { - self.state = GameState::Over; - PlayResult::PlayerBlackJack - }, - (false,false) => { - self.state = GameState::PlayerTurn; - PlayResult::Continue - }, - } - } - (GameState::PlayerTurn, PlayMoves::Hit) => { - self.player_hand.add_card(self.shoe.pop_card().unwrap()); - - return match self.player_hand.get_blackjack_value().cmp(&21) { - std::cmp::Ordering::Equal => { - self.state = GameState::Over; - self.dealer_play() - } - std::cmp::Ordering::Greater => { - self.state = GameState::Over; - PlayResult::Bust - } - std::cmp::Ordering::Less => PlayResult::Continue, - }; - }, - (GameState::PlayerTurn, PlayMoves::DoubleDown) => { - if self.player_hand.count() > 2{ - return PlayResult::InvalidMove; - } - - self.player_hand.add_card(self.shoe.pop_card().unwrap()); - self.state = GameState::Over; - return self.dealer_play(); - }, - (GameState::PlayerTurn, PlayMoves::Stand) => { - self.state = GameState::Over; - return self.dealer_play(); - } - (GameState::Over, _) - | (GameState::Empty, _) - | (GameState::PlayerTurn, PlayMoves::Bet) => { - return PlayResult::InvalidMove; - } - } + pub fn get_player(&self, index: usize) -> Option<&Player> { + self.players.get(index) } - fn dealer_play(&mut self) -> PlayResult { - // Stand on 17 or above - // Hit on 16 and below + pub fn get_player_count(&self) -> usize { + self.players.len() + } - loop { - let dealer_value = self.dealer_hand.get_blackjack_value(); - if dealer_value >= 17 { - let player_value = self.player_hand.get_blackjack_value(); + 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 { + return false; + }; - return match dealer_value.cmp(&player_value) { - std::cmp::Ordering::Equal => PlayResult::Push, - std::cmp::Ordering::Greater => PlayResult::StandPlayerLose, - std::cmp::Ordering::Less => PlayResult::StandPlayerWin, + if player.state != PlayerState::Playing { + return false; + } + + player.hand.add_card(self.shoe.pop_card().unwrap()); + match player.hand.get_blackjack_value().cmp(&21) { + std::cmp::Ordering::Equal => { + player.state = PlayerState::Maxed; + } + std::cmp::Ordering::Greater => { + player.state = PlayerState::Busted; + } + std::cmp::Ordering::Less => { + // Player is still playing + } }; } + (GameState::PlayerTurn(i), PlayMoves::DoubleDown) => { + let Some(player) = self.players.get_mut(*i) else { + return false; + }; - self.dealer_hand.add_card(self.shoe.pop_card().unwrap()); + if player.state != PlayerState::Playing { + return false; + } - if self.dealer_hand.get_blackjack_value() > 21 { - return PlayResult::DealerBust; + 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; + } + std::cmp::Ordering::Greater => { + player.state = PlayerState::Busted; + } + }; + } + (GameState::PlayerTurn(i), PlayMoves::Stand) => { + let Some(player) = self.players.get_mut(*i) else { + return false; + }; + + if player.state != PlayerState::Playing { + return false; + } + + player.state = PlayerState::Standing; + } + (GameState::Over, PlayMoves::Deal(player_count)) + | (GameState::Starting, PlayMoves::Deal(player_count)) => { + for i 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()); + + 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; + } + } + + self.dealer_hand.add_card(self.shoe.pop_card().unwrap()); + + self.state = GameState::PlayerTurn(0); + } + (_, PlayMoves::Deal(_)) | (GameState::Over, _) | (GameState::Starting, _) => { + return false; + } + } + + let player_count = self.players.len(); + + 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; + } + + 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; + } + _ => { + return false; } } } diff --git a/src/console_blackjack.rs b/src/console_blackjack.rs index 2f075ea..244d008 100644 --- a/src/console_blackjack.rs +++ b/src/console_blackjack.rs @@ -4,73 +4,31 @@ use crate::blackjack::{BlackjackGame, GameState, PlayMoves}; pub fn play() -> Result<(), Box> { let mut game = BlackjackGame::new(); - let mut play_move = PlayMoves::Bet; - while !matches!(game.get_state(), GameState::Over) { - match game.play(play_move) { - crate::blackjack::PlayResult::DealerBlackJack => { + loop { + match game.get_state() { + GameState::PlayerTurn(player_index) => { print_full_state(&game); - println!("Dealer wins with blackjack!"); - } - crate::blackjack::PlayResult::PlayerBlackJack => { - print_full_state(&game); - println!("Player has a blackjack!"); + let play_move = get_move(*player_index)?; + if !game.play(play_move){ + println!("You can't do that"); + } }, - crate::blackjack::PlayResult::PushBlackjack => { + GameState::Over => { print_full_state(&game); - println!("Player and Dealer have a blackjack!"); - } - crate::blackjack::PlayResult::DealerBust => { - print_full_state(&game); - println!("Dealer busts. Player wins!"); - } - crate::blackjack::PlayResult::StandPlayerLose => { - print_full_state(&game); - println!( - "Dealer wins with {}", - game.get_dealer_hand().get_blackjack_value() - ); - } - crate::blackjack::PlayResult::StandPlayerWin => { - print_full_state(&game); - println!( - "Player wins with {}", - game.get_player_hand().get_blackjack_value() - ); - } - crate::blackjack::PlayResult::Push => { - print_full_state(&game); - println!("Player and dealer have the same value. Push!"); - } - crate::blackjack::PlayResult::Bust => { - print_full_state(&game); - println!( - "Player busts with {}", - game.get_player_hand().get_blackjack_value() - ); - } - crate::blackjack::PlayResult::InvalidMove => { - println!("You cannot do that!"); - play_move = get_move()?; - } - crate::blackjack::PlayResult::Continue => { - println!("Dealer: {} ?", game.get_dealer_hand().get_card(0).unwrap()); - println!( - "Player: {} ({})", - game.get_player_hand(), - game.get_player_hand().get_blackjack_value() - ); - play_move = get_move()? + println!("Game over"); + return Ok(()); } + GameState::Starting => { + game.play(PlayMoves::Deal(2)); + }, } } - - Ok(()) } -fn get_move() -> Result { +fn get_move(player_index: usize) -> Result { loop { - println!("(H)it (S)tand (D)double"); + println!("P{}, (H)it (S)tand (D)double",player_index); let mut buffer = String::new(); stdin().read_line(&mut buffer)?; @@ -85,14 +43,10 @@ fn get_move() -> Result { } fn print_full_state(game: &BlackjackGame) { - println!( - "Dealer: {} ({})", - game.get_dealer_hand(), - game.get_dealer_hand().get_blackjack_value() - ); - println!( - "Player: {} ({})", - game.get_player_hand(), - game.get_player_hand().get_blackjack_value() - ); + println!("Dealer: {} ({})", game.get_dealer_hand(), game.get_dealer_hand().get_blackjack_value()); + + 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()); + } }