use crate::util::max::IteratorMaxItems;
use crate::rng::{Seed, WaveRng};
-use super::super::{Action, ActionError, Game, UserAction, ValidatedUserAction};
+use super::super::{Action, ActionError, DealerAction, Game, UserAction, ValidatedUserAction};
use super::classify::rank_7_card_hand;
State::TurnBetting => State::DealingRiver,
State::RiverBetting => State::Showdown,
state => {
- error!("In unexpected state while bet of {} received: {:?}: {:?}", chips, state, self);
+ error!("In unexpected state while bet of {} received: {:?}: {:#?}", chips, state, self);
state
}
};
}
}
- fn next_dealer_action(&self, timestamp: SystemTime) -> Option<ValidatedUserAction> {
+ fn next_dealer_action(&self, timestamp: SystemTime) -> DealerAction {
let mut rng = self.rng.clone();
match self.state {
State::NotStarted => {
if self.seats.players_len() == self.settings.max_players as usize { // TODO
if let Some(username) = rng.choose_from(self.seats.player_set()) {
- return Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::NextToDeal}));
+ return DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::NextToDeal})
+ );
}
}
- None
+ DealerAction::WaitForPlayer
}
State::Dealing => {
if let Some(username) = self.receiver {
let card = rng.choose_from(&self.deck).cloned();
- Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::ReceiveCard{card}}))
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::ReceiveCard{card}})
+ )
} else if let Some(username) = self.dealer {
- Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::EndDeal}))
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::EndDeal})
+ )
} else {
- None
+ DealerAction::WaitForPlayer
}
}
State::PostingSmallBlind if self.seats.players_len() == 2 => {
- self.dealer
- .map(|username| {
- let chips = self.stack(username).min(self.small_blind);
+ if let Some(username) = self.dealer {
+ let chips = self.stack(username).min(self.small_blind);
+ DealerAction::TakeAction(
ValidatedUserAction(UserAction{timestamp, username, action: Action::PostBlind{chips}})
- })
+ )
+ } else {
+ error!("There is no player to post the small blind: {:#?}", self);
+ DealerAction::Leave
+ }
}
State::PostingSmallBlind => {
- self.dealer.and_then(|dealer| self.seats.player_after(dealer))
- .map(|username| {
- let chips = self.stack(username).min(self.small_blind);
+ if let Some(username) = self.dealer.and_then(|dealer| self.seats.player_after(dealer)) {
+ let chips = self.stack(username).min(self.small_blind);
+ DealerAction::TakeAction(
ValidatedUserAction(UserAction{timestamp, username, action: Action::PostBlind{chips}})
- })
+ )
+ } else {
+ error!("There is no player to post the small blind: {:#?}", self);
+ DealerAction::WaitForPlayer
+ }
}
State::PostingBigBlind if self.seats.players_len() == 2 => {
- self.dealer.and_then(|dealer| self.seats.player_after(dealer))
- .map(|username| {
- let chips = self.stack(username).min(self.small_blind * 2);
+ if let Some(username) = self.dealer.and_then(|dealer| self.seats.player_after(dealer)) {
+ let chips = self.stack(username).min(self.small_blind * 2);
+ DealerAction::TakeAction(
ValidatedUserAction(UserAction{timestamp, username, action: Action::PostBlind{chips}})
- })
+ )
+ } else {
+ error!("There is no player to post the big blind: {:#?}", self);
+ DealerAction::WaitForPlayer
+ }
}
State::PostingBigBlind => {
- self.dealer.and_then(|dealer| self.seats.player_after(dealer))
+ if let Some(username) = self.dealer
+ .and_then(|dealer| self.seats.player_after(dealer))
.and_then(|small_blind| self.seats.player_after(small_blind))
- .map(|username| {
- let chips = self.stack(username).min(self.small_blind * 2);
+ {
+ let chips = self.stack(username).min(self.small_blind * 2);
+ DealerAction::TakeAction(
ValidatedUserAction(UserAction{timestamp, username, action: Action::PostBlind{chips}})
- })
+ )
+ } else {
+ error!("There is no player to post the big blind: {:#?}", self);
+ DealerAction::WaitForPlayer
+ }
}
State::PreFlopBetting | State::PostFlopBetting | State::TurnBetting | State::RiverBetting => {
if self.players.len() <= 1 {
if self.pot > 0 {
- self.players.iter().next()
- .map(|&username| ValidatedUserAction(UserAction {
- timestamp,
- username,
- action: Action::WinHand {
- chips: self.pot,
- hand: None,
- }
- }))
+ if let Some(&username) = self.players.iter().next() {
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction {
+ timestamp,
+ username,
+ action: Action::WinHand {
+ chips: self.pot,
+ hand: None,
+ }
+ })
+ )
+ } else {
+ error!("There is no player to win the pot: {:#?}", self);
+ DealerAction::Leave
+ }
} else if self.seats.players_len() == 1 {
- self.seats.player_set().iter().next()
- .map(|&username| ValidatedUserAction(UserAction{timestamp, username, action: Action::WinGame}))
+ if let Some(&username) = self.seats.player_set().iter().next() {
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::WinGame})
+ )
+ } else {
+ error!("There is no player to win the game {:#?}", self);
+ DealerAction::Leave
+ }
} else if let Some((&username, _)) = self.stacks.iter().find(|&(_, &stack)| stack == 0) {
- Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::KnockedOut}))
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::KnockedOut})
+ )
} else if let Some(username) = self.dealer.and_then(|dealer| self.seats.player_after(dealer)) {
- Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::NextToDeal}))
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::NextToDeal})
+ )
} else {
error!("Logic error: no dealer could be chosen: {:#?}", self);
- None
+ DealerAction::Leave
}
} else {
- None
+ DealerAction::WaitForPlayer
}
}
State::DealingFlop | State::DealingTurn | State::DealingRiver => {
- self.dealer.and_then(|username|
- rng.choose_from(&self.deck).map(|&card|
- ValidatedUserAction(UserAction{timestamp, username, action: Action::CommunityCard{card}})))
+ if let Some(username) = self.dealer {
+ if let Some(&card) = rng.choose_from(&self.deck) {
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::CommunityCard{card}})
+ )
+ } else {
+ error!("Dealing community card but there are no cards left in deck: {:#?}", self);
+ DealerAction::Leave
+ }
+ } else {
+ error!("Dealing community card but there is no dealer: {:#?}", self);
+ DealerAction::Leave
+ }
}
State::Showdown if self.pot == 0 => {
if let Some((&username, _)) = self.stacks.iter().find(|&(_, &stack)| stack == 0) {
- Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::KnockedOut}))
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::KnockedOut})
+ )
} else if self.seats.players_len() == 1 {
- self.seats.player_set().iter().next()
- .map(|&username| ValidatedUserAction(UserAction{timestamp, username, action: Action::WinGame}))
+ if let Some(&username) = self.seats.player_set().iter().next() {
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::WinGame})
+ )
+ } else {
+ error!("There was no player to win the game: {:#?}", self);
+ DealerAction::Leave
+ }
} else if let Some(username) = self.dealer.and_then(|dealer| self.seats.player_after(dealer)) {
- Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::NextToDeal}))
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::NextToDeal})
+ )
} else {
error!("Logic error: no dealer could be chosen: {:#?}", self);
- None
+ DealerAction::Leave
}
}
State::Showdown => {
info!("Showdown: community: {:?}", self.community);
info!("Showdown: all hands: {:?}", self.hands);
info!("Showdown: winning hands: {:?}", winning_hands);
- winning_hands.first()
- .map(|&(username, hand)| ValidatedUserAction(UserAction {
- timestamp,
- username,
- action: Action::WinHand {
- chips: (self.pot / winning_hands.len() as u64).min(self.max_winnings(username)),
- hand: Some(hand.to_string()),
- }
- }))
+ if let Some(&(username, hand)) = winning_hands.first() {
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction {
+ timestamp,
+ username,
+ action: Action::WinHand {
+ chips: (self.pot / winning_hands.len() as u64).min(self.max_winnings(username)),
+ hand: Some(hand.to_string()),
+ }
+ })
+ )
+ } else {
+ error!("There were no winning hands in the showdown: {:#?}", self);
+ DealerAction::Leave
+ }
}
- State::Completed => None,
+ State::Completed => DealerAction::Leave,
}
}
}
game.take_action(validated).unwrap();
}
_ => {
- let dealer_action = game.next_dealer_action(SystemTime::UNIX_EPOCH).unwrap();
- assert_eq!(ValidatedUserAction(action), dealer_action);
- game.take_action(dealer_action).unwrap();
+ let dealer_action = game.next_dealer_action(SystemTime::UNIX_EPOCH);
+ if let DealerAction::TakeAction(ValidatedUserAction(dealer_action)) = dealer_action {
+ assert_eq!(action, dealer_action);
+ game.take_action(ValidatedUserAction(action)).unwrap();
+ } else {
+ panic!("Expected DealerAction::TakeAction, got {:?}", dealer_action);
+ }
}
}
}
use crate::username::Username;
use crate::util::max::IteratorMaxItems;
-use super::{Action, ActionError, Game, UserAction, ValidatedUserAction};
+use super::{Action, ActionError, DealerAction, Game, UserAction, ValidatedUserAction};
#[derive(Copy, Clone, Debug)]
enum State {
}
}
- fn next_dealer_action(&self, timestamp: SystemTime) -> Option<ValidatedUserAction> {
+ fn next_dealer_action(&self, timestamp: SystemTime) -> DealerAction {
let mut rng = self.rng.clone();
match self.state {
State::NotStarted => {
if self.seats.players_len() == self.settings.max_players as usize { // TODO
if let Some(username) = rng.choose_from(self.seats.player_set()) {
- return Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::NextToDeal}));
+ return DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::NextToDeal})
+ );
}
}
- None
+ DealerAction::WaitForPlayer
}
State::Dealing => {
if let Some(username) = self.receiver {
let card = rng.choose_from(&self.deck).cloned();
- Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::ReceiveCard{card}}))
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::ReceiveCard{card}})
+ )
} else if let Some(username) = self.dealer {
match (self.call, self.trump_card) {
(None, None) => {
if let Some(&card) = rng.choose_from(&self.deck) {
- Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::CommunityCard{card}}))
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::CommunityCard{card}})
+ )
} else {
- None
+ error!("Expected to deal a card but none were left in deck");
+ DealerAction::Leave
}
}
- (Some(_), _) | (None, Some(_)) => Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::EndDeal})),
+ (Some(_), _) | (None, Some(_)) => DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::EndDeal})
+ ),
}
} else {
- None
+ error!("Expected to deal a card but there was no dealer");
+ DealerAction::Leave
}
}
State::ChoosingTrumps => {
- None
+ DealerAction::WaitForPlayer
}
State::Playing => {
if !self.winners.is_empty() {
for username in self.seats.player_set() {
if matches!(self.tricks_won.get(&username), Some(0) | None) {
- return Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::KnockedOut}));
+ return DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::KnockedOut})
+ );
}
}
if self.seats.players_len() == 1 {
if let Some(&username) = self.winners.iter().next() {
- return Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::WinGame}));
+ return DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::WinGame})
+ );
}
}
if let Some(username) = self.call {
- return Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::WinCall}));
+ return DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::WinCall})
+ );
}
- None
+ DealerAction::WaitForPlayer
} else if let Some(username) = self.trick_winner() {
- Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::WinTrick}))
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::WinTrick})
+ )
} else {
- None
+ DealerAction::WaitForPlayer
}
}
State::CutForCall => {
if let Some(username) = self.receiver {
if let Some(card) = rng.choose_from(&self.deck).cloned() {
- Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::RevealCard{card}}))
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::RevealCard{card}})
+ )
} else {
- None
+ error!("Expected to cut for call but there were no cards left in the deck");
+ DealerAction::Leave
}
} else if let Some(username) = self.call {
- Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::WinCall}))
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::WinCall})
+ )
} else {
- None
+ error!("Cutting for call but there is nobody to receive a card");
+ DealerAction::Leave
}
}
State::RoundCompleted => {
if let Some(username) = self.dealer.and_then(|dealer| self.seats.player_after(dealer)) {
- Some(ValidatedUserAction(UserAction{timestamp, username, action: Action::NextToDeal}))
+ DealerAction::TakeAction(
+ ValidatedUserAction(UserAction{timestamp, username, action: Action::NextToDeal})
+ )
} else {
- None
+ error!("Round completed but there is nobody to deal");
+ DealerAction::Leave
}
}
State::Completed => {
- None
+ DealerAction::Leave
}
}
}
game.take_action(validated).unwrap();
}
_ => {
- let dealer_action = game.next_dealer_action(SystemTime::UNIX_EPOCH).unwrap();
- assert_eq!(ValidatedUserAction(action), dealer_action);
- game.take_action(dealer_action).unwrap();
+ let dealer_action = game.next_dealer_action(SystemTime::UNIX_EPOCH);
+ if let DealerAction::TakeAction(ValidatedUserAction(dealer_action)) = dealer_action {
+ assert_eq!(action, dealer_action);
+ game.take_action(ValidatedUserAction(action)).unwrap();
+ } else {
+ panic!("Expected DealerAction::TakeAction, got {:?}", dealer_action);
+ }
}
}
}