action_timeout: Option<i64>,
#[serde(default)]
start_time: StartCondition,
+ #[serde(default)]
+ hide_cards: bool,
}
impl TexasHoldEmSettings {
pot: u64,
level: Level,
ghosts: HashMap<Username, u8>,
+ revealed: HashSet<(Username, Card)>,
}
impl TexasHoldEm {
pot: 0,
level,
ghosts: HashMap::new(),
+ revealed: HashSet::new(),
}
}
fn only_player_left(&self) -> Option<Username> {
self.seats.player_set().into_iter().filter(|username| !self.ghosts.contains_key(username)).exactly_one().ok()
}
+
+ fn next_card_to_reveal(&self) -> Option<(Username, Card)> {
+ if !self.settings.hide_cards && (self.players_able_to_bet() <= 1 || matches!(self.state, State::Showdown)) {
+ for &username in self.in_hand.iter().sorted() {
+ if let Some(hand) = self.hands.get(&username) {
+ for &card in hand.iter().sorted() {
+ if !self.revealed.contains(&(username, card)) {
+ return Some((username, card));
+ }
+ }
+ }
+ }
+ }
+ None
+ }
}
impl Game for TexasHoldEm {
self.receiver = self.seats.player_after_where(username, |username| self.in_hand.contains(&username));
self.bets.clear();
self.committed.clear();
+ self.revealed.clear();
if self.pot != 0 {
error!("Logic error: pot was {} upon dealing: {:#?}", self.pot, self);
self.pot = 0;
}
Ok(())
}
+ (_, Action::RevealCard { card }) => {
+ self.revealed.insert((username, card));
+ Ok(())
+ }
(State::Dealing, Action::EndDeal) => {
self.state = State::PostingSmallBlind;
self.receiver = None;
}
}
State::DealingFlop | State::DealingTurn | State::DealingRiver => {
- if let Some(username) = self.dealer {
+ if let Some((username, card)) = self.next_card_to_reveal() {
+ DealerAction::TakeAction(ValidatedUserAction(UserAction { timestamp, username, action: Action::RevealCard { card } }))
+ } else 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 {
}
}
State::Showdown => {
- let winning_hands: Vec<_> = self
- .hands
- .iter()
- .sorted_by_key(|&(username, _)| username)
- .map(|(&username, hand)| (username, hand.iter().chain(self.community.iter()).cloned().collect::<Vec<_>>()))
- .filter_map(|(username, cards)| cards.try_into().ok().map(rank_7_card_hand).map(|hand| (username, hand)))
- .max_items_by_key(|(_, hand)| *hand);
- info!("Showdown: community: {:?}", self.community);
- info!("Showdown: all hands: {:?}", self.hands);
- info!("Showdown: winning hands: {:?}", winning_hands);
- 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()),
- },
- }))
+ if let Some((username, card)) = self.next_card_to_reveal() {
+ DealerAction::TakeAction(ValidatedUserAction(UserAction { timestamp, username, action: Action::RevealCard { card } }))
} else {
- error!("There were no winning hands in the showdown: {:#?}", self);
- DealerAction::Leave
+ let winning_hands: Vec<_> = self
+ .hands
+ .iter()
+ .sorted_by_key(|&(username, _)| username)
+ .map(|(&username, hand)| (username, hand.iter().chain(self.community.iter()).cloned().collect::<Vec<_>>()))
+ .filter_map(|(username, cards)| cards.try_into().ok().map(rank_7_card_hand).map(|hand| (username, hand)))
+ .max_items_by_key(|(_, hand)| *hand);
+ info!("Showdown: community: {:?}", self.community);
+ info!("Showdown: all hands: {:?}", self.hands);
+ info!("Showdown: winning hands: {:?}", winning_hands);
+ 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 => DealerAction::Leave,
tournament_length: None,
action_timeout: None,
start_time: StartCondition::WhenFull,
+ hide_cards: false,
};
assert_eq!(50, settings.level(0).small_blind);
tournament_length: Some(4 * 60 * 60 * 1000),
action_timeout: None,
start_time: StartCondition::WhenFull,
+ hide_cards: false,
};
assert_eq!(25, settings.level(0).small_blind);
]"#;
let actions = serde_json::from_str(actions).unwrap();
- let settings = r#"{"title":"2-Player TexasHoldEm Test","max_players":2,"small_blind":100,"starting_stack":1000}"#;
+ let settings = r#"{"title":"2-Player TexasHoldEm Test","max_players":2,"small_blind":100,"starting_stack":1000,"hide_cards":true}"#;
let settings = serde_json::from_str(settings).unwrap();
let seed = r#"{"rng":"ChaCha20","seed":"e0355d5c6c63ef757d1b874b0392a3deec73cadfb0a2aa7947a04db651bf9269"}"#;
]"#;
let actions = serde_json::from_str(actions).unwrap();
- let settings = r#"{"title":"2-Player TexasHoldEm Test","max_players":2,"small_blind":25,"starting_stack":1000}"#;
+ let settings = r#"{"title":"2-Player TexasHoldEm Test","max_players":2,"small_blind":25,"starting_stack":1000,"hide_cards":true}"#;
let settings = serde_json::from_str(settings).unwrap();
let seed = r#"{"rng":"ChaCha20","seed":"f05dc83bdce966e72a3a81b19ccded2e70387eb68deacf60ed8de1ee78b9ff0e"}"#;
]"#;
let actions = serde_json::from_str(actions).unwrap();
- let settings = r#"{"title":"2-Player TexasHoldEm Test","max_players":2,"small_blind":100,"starting_stack":1000}"#;
+ let settings = r#"{"title":"2-Player TexasHoldEm Test","max_players":2,"small_blind":100,"starting_stack":1000,"hide_cards":true}"#;
let settings = serde_json::from_str(settings).unwrap();
let seed = r#"{"rng":"ChaCha20","seed":"fd87ec4b51fcaf056ef53c0460322e1fa5261cf2801d005065c9add8ec541bb4"}"#;
]"#;
let actions = serde_json::from_str(actions).unwrap();
- let settings = r#"{"title":"2-Player TexasHoldEm Test","max_players":2,"small_blind":100,"starting_stack":1000}"#;
+ let settings = r#"{"title":"2-Player TexasHoldEm Test","max_players":2,"small_blind":100,"starting_stack":1000,"hide_cards":true}"#;
let settings = serde_json::from_str(settings).unwrap();
let seed = r#"{"rng":"ChaCha20","seed":"fd87ec4b51fcaf056ef53c0460322e1fa5261cf2801d005065c9add8ec541bb4"}"#;
]"#;
let actions = serde_json::from_str(actions).unwrap();
- let settings = r#"{"title":"2-Player TexasHoldEm Test","max_players":2,"small_blind":100,"starting_stack":1000}"#;
+ let settings = r#"{"title":"2-Player TexasHoldEm Test","max_players":2,"small_blind":100,"starting_stack":1000,"hide_cards":true}"#;
let settings = serde_json::from_str(settings).unwrap();
let seed = r#"{"rng":"ChaCha20","seed":"8de0ac3be302e26cbc0a371044c8b349107108abb1f94a10fe84ba04a59d7f31"}"#;
]"#;
let actions = serde_json::from_str(actions).unwrap();
- let settings = r#"{"format":"TexasHoldEm","title":"4-Player TexasHoldEm Test","max_players":4,"small_blind":25,"starting_stack":1000}"#;
+ let settings = r#"{"format":"TexasHoldEm","title":"4-Player TexasHoldEm Test","max_players":4,"small_blind":25,"starting_stack":1000,"hide_cards":true}"#;
let settings = serde_json::from_str(settings).unwrap();
let seed = r#"{"rng":"ChaCha20","seed":"48e2f45eb4a1ac6bc4ab4f2368ba2d9b0d7c1f132d7fc7f51036e92112dae136"}"#;
]"#;
let actions = serde_json::from_str(actions).unwrap();
- let settings = r#"{"format":"TexasHoldEm","title":"4-Player TexasHoldEm Test","max_players":4,"small_blind":25,"starting_stack":1000}"#;
+ let settings = r#"{"format":"TexasHoldEm","title":"4-Player TexasHoldEm Test","max_players":4,"small_blind":25,"starting_stack":1000,"hide_cards":true}"#;
let settings = serde_json::from_str(settings).unwrap();
let seed = r#"{"rng":"ChaCha20","seed":"48e2f45eb4a1ac6bc4ab4f2368ba2d9b0d7c1f132d7fc7f51036e92112dae136"}"#;
]"#;
let actions = serde_json::from_str(actions).unwrap();
- let settings = r#"{"format":"TexasHoldEm","title":"4-Player TexasHoldEm Test","max_players":4,"small_blind":25,"starting_stack":1000}"#;
+ let settings = r#"{"format":"TexasHoldEm","title":"4-Player TexasHoldEm Test","max_players":4,"small_blind":25,"starting_stack":1000,"hide_cards":true}"#;
let settings = serde_json::from_str(settings).unwrap();
let seed = r#"{"rng":"ChaCha20","seed":"092b99f45313fff167029dc7420ed69a92becae492e09b65bc06ddcaae3c9e9c"}"#;
]"#;
let actions = serde_json::from_str(actions).unwrap();
- let settings = r#"{"format":"TexasHoldEm","title":"4-Player TexasHoldEm Test","max_players":4,"small_blind":25,"starting_stack":1000}"#;
+ let settings = r#"{"format":"TexasHoldEm","title":"4-Player TexasHoldEm Test","max_players":4,"small_blind":25,"starting_stack":1000,"hide_cards":true}"#;
let settings = serde_json::from_str(settings).unwrap();
let seed = r#"{"rng":"ChaCha20","seed":"092b99f45313fff167029dc7420ed69a92becae492e09b65bc06ddcaae3c9e9c"}"#;
]"#;
let actions = serde_json::from_str(actions).unwrap();
- let settings = r#"{"format":"TexasHoldEm","title":"4-Player TexasHoldEm Test","max_players":4,"small_blind":25,"starting_stack":1000}"#;
+ let settings = r#"{"format":"TexasHoldEm","title":"4-Player TexasHoldEm Test","max_players":4,"small_blind":25,"starting_stack":1000,"hide_cards":true}"#;
let settings = serde_json::from_str(settings).unwrap();
let seed = r#"{"rng":"ChaCha20","seed":"092b99f45313fff167029dc7420ed69a92becae492e09b65bc06ddcaae3c9e9c"}"#;
]"#;
let actions = serde_json::from_str(actions).unwrap();
- let settings = r#"{"format":"TexasHoldEm","title":"Ultimate Merriment","max_players":4,"small_blind":200,"starting_stack":5000,"round_length":null,"tournament_length":null,"action_timeout":null,"start_time":null}"#;
+ let settings = r#"{"format":"TexasHoldEm","title":"Ultimate Merriment","max_players":4,"small_blind":200,"starting_stack":5000,"round_length":null,"tournament_length":null,"action_timeout":null,"start_time":null,"hide_cards":true}"#;
let settings = serde_json::from_str(settings).unwrap();
let seed = r#"{"rng":"ChaCha20","seed":"d9d9cf40cd30cc5da249bf1c0c710a34f96d24590ed1c6668d369ae290276222"}"#;