diff --git a/src/game.rs b/src/game.rs index 2df7e66..83841b4 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, VecDeque}; use crate::card::{create_deck, draw_card, PlayingCard}; use crate::player::{self, Player}; @@ -17,20 +17,44 @@ struct BettingPot { /// **Value**: Pennies bets: HashMap, pot_total: u32, + /// If there are multiple pots, represents the max value of this pot. + /// Calls or raises above this go into the next pot. + pot_cap: Option, } impl BettingPot { - pub fn new(players: Vec) -> BettingPot { - let mut m: HashMap = HashMap::new(); + pub fn new(players: Vec, starting_bets: Option>) -> BettingPot { + let mut m: HashMap = starting_bets.unwrap_or_default(); for p in players { - m.insert(p, 0); + if !m.contains_key(&p) { + m.insert(p, 0); + } } BettingPot { bets: m, pot_total: 0, + pot_cap: None, } } + pub fn cap_pot(&mut self, pennies: u32) -> HashMap { + self.pot_cap = Some(pennies); + let mut new_map: HashMap = HashMap::new(); + self.bets.iter_mut().for_each(|bet| { + if *bet.1 > pennies { + let difference = *bet.1 - pennies; + self.pot_total -= difference; + *bet.1 = pennies; + new_map.insert(*bet.0, difference); + } + }); + new_map + } + + pub fn declare_winner(&self, id: u32, game: &mut PokerGame) { + game.get_player_mut(id).pay(self.pot_total); + } + pub fn remove_player(&mut self, id: u32) { self.bets.remove(&id); } @@ -80,7 +104,7 @@ impl PokerGame { PokerGame { players, table: vec![], - pots: vec![BettingPot::new(p_ids)], + pots: vec![BettingPot::new(p_ids, None)], big_blind: 0, stage: GameStage::PreFlop, deck: create_deck(), @@ -107,7 +131,16 @@ impl PokerGame { pub fn get_bets(&mut self) { let ids: Vec = self.players.iter().map(|p| p.id()).collect(); - for id in ids { + + // Queue of players that still need to bet. When this is empty, + // all players have placed there bets and the next round is ready to start. + let mut bet_queue: VecDeque = VecDeque::new(); + self.players + .iter() + .for_each(|p| bet_queue.push_back(p.id())); + + while !bet_queue.is_empty() { + let id = bet_queue.pop_front().unwrap(); let action = self.get_player(id).get_move(self); let mut current_bet = 0; match action { @@ -119,12 +152,66 @@ impl PokerGame { } player::TurnAction::Call => { if current_bet > 0 { - let message = format!("You called ${}", (current_bet as f64) / 100.0); + let message = format!("You called ${}.", (current_bet as f64) / 100.0); self.get_player_mut(id).deduct(current_bet, Some(&message)); } + let mut bet = current_bet.clone(); + self.pots.iter_mut().for_each(|pot| match pot.pot_cap { + Some(cap) => { + if cap > bet { + panic!("There's something wrong with the logic, bet is less than the cap??"); + } + pot.add_bet(id, cap); + bet -= cap; + }, + None => { + if bet > 0 { + pot.add_bet(id, bet); + } + } + }); self.pots.last_mut().unwrap().add_bet(id, current_bet); } - player::TurnAction::Raise(_) => todo!(), + player::TurnAction::AllIn(amount) => { + // Remove money from player and add it to the pot + let message = format!( + "You went all in with your last ${}.", + (current_bet as f64) / 100.0 + ); + self.get_player_mut(id).deduct(amount, Some(&message)); + self.pots.last_mut().unwrap().add_bet(id, amount); + + // Take the difference between the current bet and create a new pot + let pot_cap = *self.pots.last().unwrap().bets.get(&id).unwrap(); + let new_betmap = self.pots.last_mut().unwrap().cap_pot(pot_cap); + let new_pot_players: Vec = self + .players + .iter() + .filter(|p| p.id() != id) + .map(|p| p.id()) + .collect(); + let new_pot = BettingPot::new(new_pot_players, Some(new_betmap)); + self.pots.push(new_pot); + } + player::TurnAction::Raise(raise) => { + // New current bet + current_bet = current_bet + raise; + let message = format!("You raised ${}.", (current_bet as f64) / 100.0); + + // Remove money from player + self.get_player_mut(id).deduct(current_bet, Some(&message)); + + // Add money to current pot + self.pots.last_mut().unwrap().add_bet(id, current_bet); + + // Reset queue of players waiting to bet. + // Everyone now has to decide whether to match the raise. + self.players.iter().for_each(|p| { + if !bet_queue.contains(&p.id()) && p.id() != id { + bet_queue.push_back(p.id()) + } + }); + } } } } diff --git a/src/player.rs b/src/player.rs index e9e769c..111cfa0 100644 --- a/src/player.rs +++ b/src/player.rs @@ -6,6 +6,7 @@ use std::io; pub enum TurnAction { Fold, Call, + AllIn(u32), Raise(u32), }