more improvements

This commit is contained in:
Niklas Kapelle 2024-05-15 13:54:41 +02:00
parent 4387e2cb14
commit bf73860433
Signed by: niklas
GPG Key ID: 4EB651B36D841D16
2 changed files with 169 additions and 166 deletions

View File

@ -2,45 +2,64 @@ use crate::{decks::new_blackjack_shoe, hand::Hand};
pub struct BlackjackGame { pub struct BlackjackGame {
shoe: Hand, shoe: Hand,
player_hand: Hand, players: Vec<Player>,
dealer_hand: Hand, dealer_hand: Hand,
state: GameState, state: GameState,
} }
pub enum PlayResult { pub struct Player {
DealerBlackJack, // Dealer has a blackjack. Player does not hand: Hand,
PlayerBlackJack, // Player has a blackjack. Dealer does not state: PlayerState,
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,
} }
#[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 { pub enum PlayMoves {
Hit, Hit,
Stand, Stand,
DoubleDown, DoubleDown,
Bet, // At the Start of the game Deal(usize),
} }
pub enum GameState { pub enum GameState {
Empty, // No cards have been dealt Starting,
Over, // Game is over Over, // Game is over
PlayerTurn, // Its the turn of the player PlayerTurn(usize), // Its the turn of the player
} }
impl BlackjackGame { impl BlackjackGame {
pub fn new() -> Self { pub fn new() -> Self {
BlackjackGame { BlackjackGame {
shoe: new_blackjack_shoe(6), shoe: new_blackjack_shoe(6),
player_hand: Hand::new(), players: Vec::new(),
dealer_hand: Hand::new(), dealer_hand: Hand::new(),
state: GameState::Empty, state: GameState::Starting,
} }
} }
@ -48,98 +67,128 @@ impl BlackjackGame {
&self.dealer_hand &self.dealer_hand
} }
pub fn get_player_hand(&self) -> &Hand {
&self.player_hand
}
pub fn get_state(&self) -> &GameState { pub fn get_state(&self) -> &GameState {
&self.state &self.state
} }
pub fn play(&mut self, action: PlayMoves) -> PlayResult { pub fn get_player(&self, index: usize) -> Option<&Player> {
match (&self.state, action) { self.players.get(index)
(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;
}
}
} }
fn dealer_play(&mut self) -> PlayResult { pub fn get_player_count(&self) -> usize {
// Stand on 17 or above self.players.len()
// Hit on 16 and below }
loop { pub fn play(&mut self, action: PlayMoves) -> bool {
let dealer_value = self.dealer_hand.get_blackjack_value(); match (&self.state, action) {
if dealer_value >= 17 { (GameState::PlayerTurn(i), PlayMoves::Hit) => {
let player_value = self.player_hand.get_blackjack_value(); let Some(player) = self.players.get_mut(*i) else {
return false;
};
return match dealer_value.cmp(&player_value) { if player.state != PlayerState::Playing {
std::cmp::Ordering::Equal => PlayResult::Push, return false;
std::cmp::Ordering::Greater => PlayResult::StandPlayerLose, }
std::cmp::Ordering::Less => PlayResult::StandPlayerWin,
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 { player.hand.add_card(self.shoe.pop_card().unwrap());
return PlayResult::DealerBust; 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;
} }
} }
} }

View File

@ -4,73 +4,31 @@ use crate::blackjack::{BlackjackGame, GameState, PlayMoves};
pub fn play() -> Result<(), Box<dyn std::error::Error>> { pub fn play() -> Result<(), Box<dyn std::error::Error>> {
let mut game = BlackjackGame::new(); let mut game = BlackjackGame::new();
let mut play_move = PlayMoves::Bet;
while !matches!(game.get_state(), GameState::Over) { loop {
match game.play(play_move) { match game.get_state() {
crate::blackjack::PlayResult::DealerBlackJack => { GameState::PlayerTurn(player_index) => {
print_full_state(&game); print_full_state(&game);
println!("Dealer wins with blackjack!"); let play_move = get_move(*player_index)?;
} if !game.play(play_move){
crate::blackjack::PlayResult::PlayerBlackJack => { println!("You can't do that");
print_full_state(&game); }
println!("Player has a blackjack!");
}, },
crate::blackjack::PlayResult::PushBlackjack => { GameState::Over => {
print_full_state(&game); print_full_state(&game);
println!("Player and Dealer have a blackjack!"); println!("Game over");
} return Ok(());
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()?
} }
GameState::Starting => {
game.play(PlayMoves::Deal(2));
},
} }
} }
Ok(())
} }
fn get_move() -> Result<PlayMoves, io::Error> { fn get_move(player_index: usize) -> Result<PlayMoves, io::Error> {
loop { loop {
println!("(H)it (S)tand (D)double"); println!("P{}, (H)it (S)tand (D)double",player_index);
let mut buffer = String::new(); let mut buffer = String::new();
stdin().read_line(&mut buffer)?; stdin().read_line(&mut buffer)?;
@ -85,14 +43,10 @@ fn get_move() -> Result<PlayMoves, io::Error> {
} }
fn print_full_state(game: &BlackjackGame) { fn print_full_state(game: &BlackjackGame) {
println!( println!("Dealer: {} ({})", game.get_dealer_hand(), game.get_dealer_hand().get_blackjack_value());
"Dealer: {} ({})",
game.get_dealer_hand(), for player_index in 0..game.get_player_count(){
game.get_dealer_hand().get_blackjack_value() let player = game.get_player(player_index).unwrap();
); println!("P{}: {} ({})",player_index,player.get_hand(),player.get_hand().get_blackjack_value());
println!( }
"Player: {} ({})",
game.get_player_hand(),
game.get_player_hand().get_blackjack_value()
);
} }