1- //! Game state machine (or handler) of Holdem: the core of this lib.
1+ //! Game state machine of poker game (Hold'em or Omaha).
2+
23use crate :: account:: HoldemAccount ;
4+ use crate :: variant:: { EvaluateHandsOutput , GameVariant } ;
35use crate :: errors;
46use crate :: essential:: {
57 ActingPlayer , AwardPot , Display , GameEvent , GameMode , HoldemStage , InternalPlayerJoin , Player ,
68 PlayerResult , PlayerStatus , Pot , Street , ACTION_TIMEOUT_AFK , ACTION_TIMEOUT_POSTFLOP ,
79 ACTION_TIMEOUT_PREFLOP , ACTION_TIMEOUT_RIVER , ACTION_TIMEOUT_TURN , MAX_ACTION_TIMEOUT_COUNT ,
810 TIME_CARD_EXTRA_SECS , WAIT_TIMEOUT_DEFAULT ,
911} ;
10- use crate :: evaluator:: { compare_hands, create_cards, evaluate_cards, PlayerHand } ;
11- use crate :: hand_history:: { BlindBet , BlindType , HandHistory , PlayerAction , Showdown } ;
12+ use crate :: hand_history:: { BlindBet , BlindType , HandHistory , PlayerAction } ;
1213use race_api:: prelude:: * ;
1314use std:: collections:: BTreeMap ;
1415use std:: mem:: take;
1516
1617// Holdem: the game state
1718#[ derive( BorshSerialize , BorshDeserialize , Default , Debug , PartialEq , Clone ) ]
18- pub struct Holdem {
19+ pub struct PokerGame < V : GameVariant > {
1920 pub hand_id : usize ,
2021 pub deck_random_id : usize ,
2122 pub max_deposit : u64 ,
@@ -45,10 +46,11 @@ pub struct Holdem {
4546 pub hand_history : HandHistory ,
4647 pub next_game_start : u64 ,
4748 pub rake_collected : u64 ,
49+ pub variant : V ,
4850}
4951
5052// Methods that mutate or query the game state
51- impl Holdem {
53+ impl < V : GameVariant > PokerGame < V > {
5254 // calc timeout that should be wait after settle by state
5355 fn calc_pre_settle_timeout ( & self ) -> Result < u64 , HandleError > {
5456 // 0.5s for collect chips, 5s for players observer game result
@@ -958,80 +960,15 @@ impl Holdem {
958960 }
959961
960962 pub fn update_game_result ( & mut self , effect : & mut Effect ) -> Result < ( ) , HandleError > {
961- let decryption = effect. get_revealed ( self . deck_random_id ) ?;
962- // Board
963- let board: Vec < & str > = self . board . iter ( ) . map ( |c| c. as_str ( ) ) . collect ( ) ;
964- // Player hands
965- let mut player_hands: Vec < ( u64 , PlayerHand ) > = Vec :: with_capacity ( self . player_order . len ( ) ) ;
966-
967- let mut showdowns = Vec :: < ( u64 , Showdown ) > :: new ( ) ;
963+ let revealed = effect. get_revealed ( self . deck_random_id ) ?;
968964
969- for ( id, idxs) in self . hand_index_map . iter ( ) {
970- if idxs. len ( ) != 2 {
971- return Err ( errors:: invalid_hole_cards_number ( ) ) ;
972- }
965+ let EvaluateHandsOutput { winner_sets, showdown_map } = self . variant . evaluate_hands (
966+ & self . board ,
967+ & self . hand_index_map ,
968+ revealed
969+ ) ?;
973970
974- let Some ( player) = self . player_map . get ( id) else {
975- return Err ( errors:: internal_player_not_found ( ) ) ;
976- } ;
977-
978- if player. status != PlayerStatus :: Fold
979- && player. status != PlayerStatus :: Init
980- && player. status != PlayerStatus :: Waitbb
981- && player. status != PlayerStatus :: Leave
982- {
983- let Some ( first_card_idx) = idxs. first ( ) else {
984- return Err ( errors:: first_hole_card_index_missing ( ) ) ;
985- } ;
986- let Some ( first_card) = decryption. get ( first_card_idx) else {
987- return Err ( errors:: first_hole_card_error ( ) ) ;
988- } ;
989- let Some ( second_card_idx) = idxs. last ( ) else {
990- return Err ( errors:: second_hole_card_index_missing ( ) ) ;
991- } ;
992- let Some ( second_card) = decryption. get ( second_card_idx) else {
993- return Err ( errors:: second_hole_card_error ( ) ) ;
994- } ;
995- let hole_cards = [ first_card. as_str ( ) , second_card. as_str ( ) ] ;
996- let cards = create_cards ( board. as_slice ( ) , & hole_cards) ;
997- let hand = evaluate_cards ( cards) ;
998- let hole_cards = hole_cards. iter ( ) . map ( |c| c. to_string ( ) ) . collect ( ) ;
999- let category = hand. category . clone ( ) ;
1000- let picks = hand. picks . iter ( ) . map ( |c| c. to_string ( ) ) . collect ( ) ;
1001- player_hands. push ( ( * id, hand) ) ;
1002- showdowns. push ( (
1003- * id,
1004- Showdown {
1005- hole_cards,
1006- category,
1007- picks,
1008- } ,
1009- ) ) ;
1010- }
1011- }
1012-
1013- player_hands. sort_by ( |( _, h1) , ( _, h2) | compare_hands ( & h2. value , & h1. value ) ) ;
1014-
1015- println ! ( "Player Hands from strong to weak {:?}" , player_hands) ;
1016-
1017- // Winners example: [[w1], [w2, w3], ... ] where w2 == w3, i.e. a draw/tie
1018- let mut winners: Vec < Vec < u64 > > = Vec :: new ( ) ;
1019- let mut current_value = None ;
1020-
1021- for ( id, hand) in player_hands. into_iter ( ) {
1022- if Some ( & hand. value ) != current_value. as_ref ( ) {
1023- current_value = Some ( hand. value . clone ( ) ) ;
1024- winners. push ( vec ! [ ] ) ;
1025- }
1026- winners
1027- . last_mut ( )
1028- . ok_or ( errors:: strongest_hand_not_found ( ) ) ?
1029- . push ( id) ;
1030- }
1031-
1032- println ! ( "Player rankings in order: {:?}" , winners) ;
1033-
1034- let award_pots = self . assign_winners ( winners) ?;
971+ let award_pots = self . assign_winners ( winner_sets) ?;
1035972 self . calc_prize ( ) ?;
1036973
1037974 let player_result_map = self . update_player_chips ( ) ?;
@@ -1041,7 +978,7 @@ impl Holdem {
1041978 self . mark_eliminated_players ( ) ;
1042979
1043980 // Save to hand history
1044- for ( id, showdown) in showdowns . into_iter ( ) {
981+ for ( id, showdown) in showdown_map . into_iter ( ) {
1045982 self . hand_history . add_showdown ( id, showdown) ;
1046983 }
1047984
@@ -1346,9 +1283,16 @@ impl Holdem {
13461283 }
13471284
13481285 let betted = self . get_player_bet ( sender) ;
1349- if amount + betted < self . street_bet + self . min_raise && amount != player. chips {
1350- return Err ( errors:: raise_amount_is_too_small ( ) ) ;
1351- }
1286+
1287+ self . variant . validate_raise_amount (
1288+ player. chips ,
1289+ betted,
1290+ amount,
1291+ self . street_bet ,
1292+ self . min_raise ,
1293+ & self . pots ,
1294+ ) ?;
1295+
13521296 let ( allin, real_raise_amount) = self . take_bet ( sender. clone ( ) , amount) ?;
13531297 self . set_player_acted ( sender, allin) ?;
13541298 let new_street_bet = betted + real_raise_amount;
@@ -1632,7 +1576,7 @@ impl Holdem {
16321576 }
16331577}
16341578
1635- impl GameHandler for Holdem {
1579+ impl < V : GameVariant > GameHandler for PokerGame < V > {
16361580 fn balances ( & self ) -> Vec < PlayerBalance > {
16371581 self . player_map
16381582 . values ( )
0 commit comments