def test_loss(): deal = FullDeal( hole_cards=[mkhand("AcAd"), mkhand("AsKh")], board=Board(flop=mkflop("KsJs3d"), turn=mkcard("7s"), river=mkcard("6s")), ) game = GameRunner(starting_stacks=[300, 400]) game.start_game() # Preflop game.bet_raise(to=10) game.call() # Flop game.bet_raise(to=25) game.call() # Turn game.check() game.bet_raise(to=40) game.call() # River game.check() game.check() results = result.get_result(deal, game.game_view()) model = heads_up.HeadsUpModel("HeadsUp") player_index = 1 example = make_forward_backward_example( player_index, game.game_view(), deal.hole_cards[player_index], deal.board, results, ) ( feature_tensors, target_tensors, ) = model.feature_config.make_features_and_target_tensors( [example.SerializeToString()]) print(tf.cast(target_tensors["reward__cumulative_reward"], tf.float32)) loss = model.loss(feature_tensors, target_tensors) batch_size = 1 num_steps = 9 assert loss.shape == [batch_size, num_steps]
def test_action_probs(): deal = FullDeal( hole_cards=[mkhand("AcAd"), mkhand("AsKh")], board=Board(flop=mkflop("KsJs3d"), turn=mkcard("7s"), river=mkcard("6s")), ) game = GameRunner(starting_stacks=[300, 400]) game.start_game() # Preflop game.bet_raise(to=10) game.call() # Flop game.bet_raise(to=25) game.call() # Turn game.check() game.bet_raise(to=40) game.call() # River game.check() game.check() model = heads_up.HeadsUpModel("HeadsUp") player_index = 1 example = make_forward_example( player_index, game.game_view(), deal.hole_cards[player_index], deal.board, ) logits = model.action_logits( model.feature_config.make_feature_tensors( [example.SerializeToString()])) batch_size = 1 num_steps = 9 num_possible_actions = 22 assert logits.shape == [batch_size, num_steps, num_possible_actions] probs = model.action_probs( model.feature_config.make_feature_tensors( [example.SerializeToString()])) assert_array_almost_equal( tf.reduce_sum(probs, -1).numpy(), np.array([[1, 1, 1, 1, 1, 1, 1, 1, 1]]))
def test_game_result(): deal = FullDeal( hole_cards=[mkhand("AcAh"), mkhand("KdKs"), mkhand("JhJd")], board=Board(flop=mkflop("6dQc2s"), turn=mkcard("6s"), river=mkcard("3c")), ) game = GameRunner(starting_stacks=[100, 200, 300]) game.start_game() # Preflop game.bet_raise(to=10) game.call() game.call() # Flop game.bet_raise(to=20) game.call() game.call() # Turn game.bet_raise(to=30) game.call() game.call() # River game.check() game.check() game.check() result = get_result(deal, game.game_view()) assert result == Result( won_hand=[True, False, False], hand_results=[ EvaluationResult( hand_type=HandType.TWO_PAIR, kicker=33686528, ), EvaluationResult(hand_type=HandType.TWO_PAIR, kicker=16909312), EvaluationResult(hand_type=HandType.TWO_PAIR, kicker=4326400), ], went_to_showdown=[True, True, True], remained_in_hand=[True, True, True], earned_from_pot=[180, 0, 0], profits=[120, -60, -60], )
def test_game_with_tie(): deal = FullDeal( hole_cards=[mkhand("Ac3h"), mkhand("Ad4s"), mkhand("5s5d")], board=Board(flop=mkflop("AsAhKc"), turn=mkcard("Kd"), river=mkcard("7h")), ) game = GameRunner(starting_stacks=[100, 200, 300]) game.start_game() # Preflop game.bet_raise(to=30) game.call() game.call() # Flop game.bet_raise(to=50) game.call() game.call() # Turn game.bet_raise(to=20) game.call() game.call() # River game.bet_raise(to=100) game.call() result = get_result(deal, game.game_view()) assert result == Result( won_hand=[True, True, False], hand_results=[ EvaluationResult(hand_type=HandType.FULL_HOUSE, kicker=33556480), EvaluationResult(hand_type=HandType.FULL_HOUSE, kicker=33556480), EvaluationResult(hand_type=HandType.TWO_PAIR, kicker=50331680), ], remained_in_hand=[True, True, True], went_to_showdown=[True, True, True], earned_from_pot=[150, 350, 0], profits=[50, 150, -200], )
def deal_cards(num_players: int) -> FullDeal: # First, select the preflop hands preflop_hands = random.sample(hands.ALL_HANDS, num_players) # Then, select the board selected_cards: Set[Card] = set() for hand in preflop_hands: selected_cards.update(hand.cards) remaining_cards = [c for c in cards.ALL_CARDS if c not in selected_cards] board_cards = random.sample(remaining_cards, 5) return FullDeal( hole_cards=preflop_hands, board=Board( flop=(board_cards[0], board_cards[1], board_cards[2]), turn=board_cards[3], river=board_cards[4], ), )
def sanity_tests() -> None: # Order doesn't matter assert evaluate_hand(mkhand("7d8s"), Board(flop=mkflop("5h6cJs"))) == evaluate_hand( mkhand("5hJs"), Board(flop=mkflop("7d8s6c"))) # Suits don't matter for non-flushes assert evaluate_hand(mkhand("7d8s"), Board(flop=mkflop("5h6cJs"))) == evaluate_hand( mkhand("7c8h"), Board(flop=mkflop("5h6cJs"))) # Kickers all the way down matter assert evaluate_hand(mkhand("7d8s"), Board(flop=mkflop("AdAcJs"))) > evaluate_hand( mkhand("8s6h"), Board(flop=mkflop("AdAcJs")))
def test_board_at_street() -> None: board = Board(flop=mkflop("AdKs3h"), turn=mkcard("5h"), river=mkcard("7s")) assert board.at_street(Street.TURN) == Board( flop=( Card(rank=Rank.ACE, suit=Suit.DIAMONDS), Card(rank=Rank.KING, suit=Suit.SPADES), Card(rank=Rank.THREE, suit=Suit.HEARTS), ), turn=Card(rank=Rank.FIVE, suit=Suit.HEARTS), river=None, ) assert board.at_street(Street.FLOP) == Board( flop=( Card(rank=Rank.ACE, suit=Suit.DIAMONDS), Card(rank=Rank.KING, suit=Suit.SPADES), Card(rank=Rank.THREE, suit=Suit.HEARTS), ), turn=None, river=None, )
def evaluate_hand(hole_cards: HoleCards, board: Board) -> EvaluationResult: (hand, kicker) = pyholdthem.evaluate_hand_from_indices( hole_cards.index(), [c.index() for c in board.cards()] ) return EvaluationResult(hand_type=HandType(hand), kicker=kicker)
def test_full_hand() -> None: # Player 3 wins with a flopped set of jacks. deal = FullDeal( hole_cards=[mkhand("AhKs"), mkhand("Kc10d"), mkhand("5h5c"), mkhand("7s3d")], board=Board(flop=mkflop("KdJs3d"), turn=mkcard("7s"), river=mkcard("6s")), ) game = GameRunner(starting_stacks=[300, 300, 300, 300]) game.start_game() # Preflop game.bet_raise(to=10) game.fold() game.bet_raise(to=25) game.call() game.call() # Flop game.bet_raise(to=40) game.call() game.fold() # Turn game.check() game.bet_raise(to=60) game.call() # River game.check() game.bet_raise(to=100) game.call() results = result.get_result(deal, game.game_view()) player_index = 1 example = make_example( public_context=make_public_context(game.game_view()), private_context=make_private_context(deal.hole_cards[1]), target=make_target(deal, results), public_states=make_public_states(game.game_view(), deal.board), player_states=make_player_states( player_index, game.game_view(), deal.hole_cards[player_index], deal.board ), last_actions=make_last_actions(game.game_view()), next_actions=make_next_actions(game.game_view()), rewards=make_rewards(game.game_view(), results), ) example_dict = seq_example_to_dict(example) assert example_dict == { "context": { "num_steps": [14], "private_context__hand_encoded": [140], "private_context__hole_card_0_rank": [13], "private_context__hole_card_0_suit": [2], "private_context__hole_card_1_rank": [10], "private_context__hole_card_1_suit": [3], "public_context__num_players": [4], "public_context__starting_stack_sizes": [300, 300, 300, 300], "target__hole_cards": [168, 140, 3, 36], "target__total_rewards": [250, -225, -25, 0], }, "features": { "last_action__action_encoded": [ [-1], [3], [0], [3], [1], [1], [5], [1], [0], [1], [7], [1], [1], [14], ], "last_action__amount_added": [ [-1], [10], [0], [24], [23], [15], [40], [40], [0], [0], [60], [60], [0], [100], ], "last_action__amount_added_percent_of_remaining": [ [-1.0], [0.03333333507180214], [0.0], [0.08026755601167679], [0.07718120515346527], [0.0517241396009922], [0.145454540848732], [0.145454540848732], [0.0], [0.0], [0.25531914830207825], [0.25531914830207825], [0.0], [0.5714285969734192], ], "last_action__amount_raised": [ [-1], [8], [0], [15], [0], [0], [40], [0], [0], [0], [60], [0], [0], [100], ], "last_action__amount_raised_percent_of_pot": [ [-1.0], [2.6666667461395264], [0.0], [1.1538461446762085], [0.0], [0.0], [0.5333333611488342], [0.0], [0.0], [0.0], [0.3870967626571655], [0.0], [0.0], [0.3636363744735718], ], "last_action__move": [ [-1], [5], [3], [5], [4], [4], [5], [4], [3], [4], [5], [4], [4], [5], ], "next_action__action_encoded": [ [3], [0], [3], [1], [1], [5], [1], [0], [1], [7], [1], [1], [14], [1], ], "next_action__amount_added": [ [10], [0], [24], [23], [15], [40], [40], [0], [0], [60], [60], [0], [100], [100], ], "next_action__amount_raised": [ [8], [0], [15], [0], [0], [40], [0], [0], [0], [60], [0], [0], [100], [0], ], "next_action__move": [ [5], [3], [5], [4], [4], [5], [4], [3], [4], [5], [4], [4], [5], [4], ], "next_action__new_total_bet": [ [10], [10], [25], [25], [25], [40], [40], [40], [0], [60], [60], [0], [100], [100], ], "player_state__current_hand_rank": [ [-1], [-1], [-1], [-1], [-1], [-1], [3652], [-1], [-1], [3648], [-1], [-1], [3648], [-1], ], "player_state__current_hand_strength": [ [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [0.5105869770050049], [-1.0], [-1.0], [0.51112300157547], [-1.0], [-1.0], [0.51112300157547], [-1.0], ], "player_state__current_hand_type": [ [-1], [-1], [-1], [-1], [-1], [-1], [2], [-1], [-1], [2], [-1], [-1], [2], [-1], ], "player_state__current_player_offset": [ [1], [2], [-1], [0], [1], [-1], [0], [1], [-1], [0], [-1], [-1], [0], [-1], ], "player_state__frac_hands_better": [ [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [0.046253468841314316], [-1.0], [-1.0], [0.07439613342285156], [-1.0], [-1.0], [0.17171716690063477], [-1.0], ], "player_state__frac_hands_tied": [ [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [0.005550416186451912], [-1.0], [-1.0], [0.005797101650387049], [-1.0], [-1.0], [0.005050505045801401], [-1.0], ], "player_state__frac_hands_worse": [ [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [0.9481961131095886], [-1.0], [-1.0], [0.9198067784309387], [-1.0], [-1.0], [0.8232323527336121], [-1.0], ], "player_state__is_current_player": [ [0], [0], [0], [1], [0], [0], [1], [0], [0], [1], [0], [0], [1], [0], ], "player_state__win_prob_vs_any": [ [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [0.8297058343887329], [-1.0], [-1.0], [0.8359622955322266], [-1.0], [-1.0], [0.8232323527336121], [-1.0], ], "player_state__win_prob_vs_better": [ [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [0.17900000512599945], [-1.0], [-1.0], [0.09700000286102295], [-1.0], [-1.0], [0.0], [-1.0], ], "player_state__win_prob_vs_tied": [ [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [0.052000001072883606], [-1.0], [-1.0], [0.0], [-1.0], [-1.0], [0.0], [-1.0], ], "player_state__win_prob_vs_worse": [ [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [-1.0], [0.8659999966621399], [-1.0], [-1.0], [0.9010000228881836], [-1.0], [-1.0], [1.0], [-1.0], ], "public_state__all_in_player_mask": [ [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], ], "public_state__amount_to_call": [ [1, 0, 2, 2], [9, 8, 0, 10], [9, 8, 0, 10], [0, 23, 15, 25], [0, 0, 15, 25], [0, 0, 0, 0], [0, 40, 40, 40], [0, 0, 40, 40], [0, 0, 0, 0], [0, 0, 0, 0], [60, 0, 60, 60], [0, 0, 0, 0], [0, 0, 0, 0], [100, 0, 100, 100], ], "public_state__current_player_mask": [ [0, 0, 1, 0], [0, 0, 0, 1], [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [1, 0, 0, 0], [0, 1, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0], [0, 1, 0, 0], [1, 0, 0, 0], ], "public_state__flop_0_rank": [ [-1], [-1], [-1], [-1], [-1], [13], [13], [13], [13], [13], [13], [13], [13], [13], ], "public_state__flop_0_suit": [ [-1], [-1], [-1], [-1], [-1], [3], [3], [3], [3], [3], [3], [3], [3], [3], ], "public_state__flop_1_rank": [ [-1], [-1], [-1], [-1], [-1], [11], [11], [11], [11], [11], [11], [11], [11], [11], ], "public_state__flop_1_suit": [ [-1], [-1], [-1], [-1], [-1], [1], [1], [1], [1], [1], [1], [1], [1], [1], ], "public_state__flop_2_rank": [ [-1], [-1], [-1], [-1], [-1], [3], [3], [3], [3], [3], [3], [3], [3], [3], ], "public_state__flop_2_suit": [ [-1], [-1], [-1], [-1], [-1], [3], [3], [3], [3], [3], [3], [3], [3], [3], ], "public_state__folded_player_mask": [ [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], ], "public_state__min_raise_amount": [ [2], [8], [8], [15], [15], [2], [40], [40], [2], [2], [60], [2], [2], [100], ], "public_state__pot_size": [ [3], [13], [13], [37], [60], [75], [115], [155], [155], [155], [215], [275], [275], [375], ], "public_state__river_rank": [ [-1], [-1], [-1], [-1], [-1], [-1], [-1], [-1], [-1], [-1], [-1], [6], [6], [6], ], "public_state__river_suit": [ [-1], [-1], [-1], [-1], [-1], [-1], [-1], [-1], [-1], [-1], [-1], [1], [1], [1], ], "public_state__stack_sizes": [ [299, 298, 300, 300], [299, 298, 290, 300], [299, 298, 290, 300], [275, 298, 290, 300], [275, 275, 290, 300], [275, 275, 275, 300], [235, 275, 275, 300], [235, 235, 275, 300], [235, 235, 275, 300], [235, 235, 275, 300], [235, 175, 275, 300], [175, 175, 275, 300], [175, 175, 275, 300], [175, 75, 275, 300], ], "public_state__street": [ [1], [1], [1], [1], [1], [2], [2], [2], [3], [3], [3], [4], [4], [4], ], "public_state__turn_rank": [ [-1], [-1], [-1], [-1], [-1], [-1], [-1], [-1], [7], [7], [7], [7], [7], [7], ], "public_state__turn_suit": [ [-1], [-1], [-1], [-1], [-1], [-1], [-1], [-1], [1], [1], [1], [1], [1], [1], ], "reward__cumulative_reward": [ [-25], [0], [251], [-223], [-15], [275], [-200], [0], [315], [-160], [315], [375], [-100], [375], ], "reward__instant_reward": [ [-10], [0], [-24], [-23], [-15], [-40], [-40], [0], [0], [-60], [-60], [0], [-100], [375], ], "reward__is_players_last_action": [ [0], [1], [0], [0], [0], [0], [0], [1], [0], [0], [0], [0], [1], [1], ], "reward__won_hand": [ [0], [0], [1], [0], [0], [1], [0], [0], [1], [0], [1], [1], [0], [1], ], }, }
def test_fold_preflop() -> None: # Player 3 wins with a flopped set of jacks. deal = FullDeal( hole_cards=[mkhand("AcAd"), mkhand("AsKh"), mkhand("JcJh")], board=Board(flop=mkflop("KsJs3d"), turn=mkcard("7s"), river=mkcard("6s")), ) game = GameRunner(starting_stacks=[200, 250, 100]) game.start_game() game.bet_raise(to=10) game.fold() game.fold() results = result.get_result(deal, game.game_view()) player_index = 1 example = make_example( public_context=make_public_context(game.game_view()), private_context=make_private_context(deal.hole_cards[1]), target=make_target(deal, results), public_states=make_public_states(game.game_view(), deal.board), player_states=make_player_states( player_index, game.game_view(), deal.hole_cards[player_index], deal.board ), last_actions=make_last_actions(game.game_view()), next_actions=make_next_actions(game.game_view()), rewards=make_rewards(game.game_view(), results), ) example_dict = seq_example_to_dict(example) assert example_dict == { "context": { "num_steps": [3], "private_context__hand_encoded": [168], "private_context__hole_card_0_rank": [14], "private_context__hole_card_0_suit": [1], "private_context__hole_card_1_rank": [13], "private_context__hole_card_1_suit": [4], "public_context__num_players": [3], "public_context__starting_stack_sizes": [200, 250, 100], "target__hole_cards": [12, 168, 9], "target__total_rewards": [-1, -2, 3], }, "features": { "last_action__action_encoded": [[-1], [4], [0]], "last_action__amount_added": [[-1], [10], [0]], "last_action__amount_added_percent_of_remaining": [ [-1.0], [0.10000000149011612], [0.0], ], "last_action__amount_raised": [[-1], [8], [0]], "last_action__amount_raised_percent_of_pot": [ [-1.0], [2.6666667461395264], [0.0], ], "last_action__move": [[-1], [5], [3]], "next_action__action_encoded": [[4], [0], [0]], "next_action__amount_added": [[10], [0], [0]], "next_action__amount_raised": [[8], [0], [0]], "next_action__move": [[5], [3], [3]], "next_action__new_total_bet": [[10], [10], [10]], "player_state__current_hand_rank": [[-1], [-1], [-1]], "player_state__current_hand_strength": [[-1.0], [-1.0], [-1.0]], "player_state__current_hand_type": [[-1], [-1], [-1]], "player_state__current_player_offset": [[1], [-1], [0]], "player_state__frac_hands_better": [[-1.0], [-1.0], [-1.0]], "player_state__frac_hands_tied": [[-1.0], [-1.0], [-1.0]], "player_state__frac_hands_worse": [[-1.0], [-1.0], [-1.0]], "player_state__is_current_player": [[0], [0], [1]], "player_state__win_prob_vs_any": [[-1.0], [-1.0], [-1.0]], "player_state__win_prob_vs_better": [[-1.0], [-1.0], [-1.0]], "player_state__win_prob_vs_tied": [[-1.0], [-1.0], [-1.0]], "player_state__win_prob_vs_worse": [[-1.0], [-1.0], [-1.0]], "public_state__all_in_player_mask": [[0, 0, 0], [0, 0, 0], [0, 0, 0]], "public_state__amount_to_call": [[1, 0, 2], [9, 8, 0], [9, 8, 0]], "public_state__current_player_mask": [[0, 0, 1], [1, 0, 0], [0, 1, 0]], "public_state__flop_0_rank": [[-1], [-1], [-1]], "public_state__flop_0_suit": [[-1], [-1], [-1]], "public_state__flop_1_rank": [[-1], [-1], [-1]], "public_state__flop_1_suit": [[-1], [-1], [-1]], "public_state__flop_2_rank": [[-1], [-1], [-1]], "public_state__flop_2_suit": [[-1], [-1], [-1]], "public_state__folded_player_mask": [[0, 0, 0], [0, 0, 0], [1, 0, 0]], "public_state__min_raise_amount": [[2], [8], [8]], "public_state__pot_size": [[3], [13], [13]], "public_state__river_rank": [[-1], [-1], [-1]], "public_state__river_suit": [[-1], [-1], [-1]], "public_state__stack_sizes": [ [199, 248, 100], [199, 248, 90], [199, 248, 90], ], "public_state__street": [[1], [1], [1]], "public_state__turn_rank": [[-1], [-1], [-1]], "public_state__turn_suit": [[-1], [-1], [-1]], "reward__cumulative_reward": [[3], [0], [0]], "reward__instant_reward": [[3], [0], [0]], "reward__is_players_last_action": [[1], [1], [1]], "reward__won_hand": [[1], [0], [0]], }, }
def test_monster() -> None: deal = FullDeal( hole_cards=[mkhand("JcJd"), mkhand("Kc10d")], board=Board(flop=mkflop("JsTs3h"), turn=mkcard("Jh"), river=mkcard("As")), ) game = GameRunner(starting_stacks=[300, 400]) game.start_game() # Preflop game.bet_raise(to=10) game.call() # Flop game.check() game.check() # Turn game.check() game.check() # River game.check() game.check() player_index = 0 private_states = make_player_states(player_index, game.game_view(), deal.hole_cards[player_index], deal.board) assert private_states == [ PlayerState( is_current_player=True, current_player_offset=0, current_hand_type=None, frac_better_hands=None, frac_tied_hands=None, frac_worse_hands=None, win_odds=None, tie_odds=None, lose_odds=None, win_odds_vs_better=None, tie_odds_vs_better=None, lose_odds_vs_better=None, win_odds_vs_tied=None, tie_odds_vs_tied=None, lose_odds_vs_tied=None, win_odds_vs_worse=None, tie_odds_vs_worse=None, lose_odds_vs_worse=None, ), PlayerState( is_current_player=False, current_player_offset=1, current_hand_type=None, frac_better_hands=None, frac_tied_hands=None, frac_worse_hands=None, win_odds=None, tie_odds=None, lose_odds=None, win_odds_vs_better=None, tie_odds_vs_better=None, lose_odds_vs_better=None, win_odds_vs_tied=None, tie_odds_vs_tied=None, lose_odds_vs_tied=None, win_odds_vs_worse=None, tie_odds_vs_worse=None, lose_odds_vs_worse=None, ), PlayerState( is_current_player=True, current_player_offset=0, current_hand_type=4, frac_better_hands=0.0, frac_tied_hands=0.0, frac_worse_hands=1.0, win_odds=approx(0.9300000071525574, abs=0.1), tie_odds=0.0, lose_odds=approx(0.07000000029802322, abs=0.1), win_odds_vs_better=0.0, tie_odds_vs_better=0.0, lose_odds_vs_better=0.0, win_odds_vs_tied=0.0, tie_odds_vs_tied=0.0, lose_odds_vs_tied=0.0, win_odds_vs_worse=approx(0.9300000071525574, abs=0.1), tie_odds_vs_worse=0.0, lose_odds_vs_worse=approx(0.07000000029802322, abs=0.1), ), PlayerState( is_current_player=False, current_player_offset=1, current_hand_type=None, frac_better_hands=None, frac_tied_hands=None, frac_worse_hands=None, win_odds=None, tie_odds=None, lose_odds=None, win_odds_vs_better=None, tie_odds_vs_better=None, lose_odds_vs_better=None, win_odds_vs_tied=None, tie_odds_vs_tied=None, lose_odds_vs_tied=None, win_odds_vs_worse=None, tie_odds_vs_worse=None, lose_odds_vs_worse=None, ), PlayerState( is_current_player=True, current_player_offset=0, current_hand_type=8, frac_better_hands=0.0, frac_tied_hands=0.0, frac_worse_hands=1.0, win_odds=approx(0.9990000128746033, abs=0.1), tie_odds=0.0, lose_odds=approx(0.0010000000474974513, abs=0.1), win_odds_vs_better=0.0, tie_odds_vs_better=0.0, lose_odds_vs_better=0.0, win_odds_vs_tied=0.0, tie_odds_vs_tied=0.0, lose_odds_vs_tied=0.0, win_odds_vs_worse=approx(0.9990000128746033, abs=0.1), tie_odds_vs_worse=0.0, lose_odds_vs_worse=approx(0.0010000000474974513, abs=0.1), ), PlayerState( is_current_player=False, current_player_offset=1, current_hand_type=None, frac_better_hands=None, frac_tied_hands=None, frac_worse_hands=None, win_odds=None, tie_odds=None, lose_odds=None, win_odds_vs_better=None, tie_odds_vs_better=None, lose_odds_vs_better=None, win_odds_vs_tied=None, tie_odds_vs_tied=None, lose_odds_vs_tied=None, win_odds_vs_worse=None, tie_odds_vs_worse=None, lose_odds_vs_worse=None, ), PlayerState( is_current_player=True, current_player_offset=0, current_hand_type=8, frac_better_hands=approx(0.001010101055726409, abs=0.1), frac_tied_hands=0.0, frac_worse_hands=approx(0.9989898800849915, abs=0.1), win_odds=approx(0.9989898800849915, abs=0.1), tie_odds=0.0, lose_odds=approx(0.001010101055726409, abs=0.1), win_odds_vs_better=0.0, tie_odds_vs_better=0.0, lose_odds_vs_better=1.0, win_odds_vs_tied=0.0, tie_odds_vs_tied=0.0, lose_odds_vs_tied=0.0, win_odds_vs_worse=1.0, tie_odds_vs_worse=0.0, lose_odds_vs_worse=0.0, ), PlayerState( is_current_player=False, current_player_offset=1, current_hand_type=None, frac_better_hands=None, frac_tied_hands=None, frac_worse_hands=None, win_odds=None, tie_odds=None, lose_odds=None, win_odds_vs_better=None, tie_odds_vs_better=None, lose_odds_vs_better=None, win_odds_vs_tied=None, tie_odds_vs_tied=None, lose_odds_vs_tied=None, win_odds_vs_worse=None, tie_odds_vs_worse=None, lose_odds_vs_worse=None, ), ]
def test_winner() -> None: hole_cards = mkhand("AdAc") board = Board(flop=mkflop("AdKs3h"), turn=mkcard("5h"), river=mkcard("7s")) eval_result = evaluate_hand(hole_cards, board) assert eval_result == EvaluationResult(hand_type=HandType.TRIPS, kicker=33556512)
def make_public_states(game: GameView, board: Optional[Board]): public_states = [] for i in iter_game_states(game): game_view = game.view(i) if board is None: current_board = Board(flop=None, turn=None, river=None) else: current_board = board.at_street(game_view.street()) current_player_mask = [0 for _ in range(game_view.num_players())] current_player_mask[game_view.current_player()] = 1 if game_view.street( ) >= Street.FLOP and current_board.flop is not None: flop_0, flop_1, flop_2 = sorted(current_board.flop, key=card_order) flop_0_rank = flop_0.rank.value flop_0_suit = flop_0.suit.value flop_1_rank = flop_1.rank.value flop_1_suit = flop_1.suit.value flop_2_rank = flop_2.rank.value flop_2_suit = flop_2.suit.value else: flop_0_rank = None flop_0_suit = None flop_1_rank = None flop_1_suit = None flop_2_rank = None flop_2_suit = None if game_view.street( ) >= Street.TURN and current_board.turn is not None: turn = current_board.turn turn_rank = turn.rank.value turn_suit = turn.suit.value else: turn_rank = None turn_suit = None if game_view.street( ) >= Street.RIVER and current_board.river is not None: river = current_board.river river_rank = river.rank.value river_suit = river.suit.value else: river_rank = None river_suit = None public_states.append( PublicState( num_players_remaining=sum(game_view.is_in_hand()), pot_size=game_view.pot_size(), street=game_view.street().value, current_player_mask=current_player_mask, folded_player_mask=game_view.is_folded(), all_in_player_mask=game_view.is_all_in(), stack_sizes=game_view.current_stack_sizes(), amount_to_call=game_view.amount_to_call(), min_raise_amount=game_view.min_bet_amount(), flop_0_rank=flop_0_rank, flop_0_suit=flop_0_suit, flop_1_rank=flop_1_rank, flop_1_suit=flop_1_suit, flop_2_rank=flop_2_rank, flop_2_suit=flop_2_suit, turn_rank=turn_rank, turn_suit=turn_suit, river_rank=river_rank, river_suit=river_suit, )) return public_states
def test_royal() -> None: hole_cards = mkhand("AcKc") board = Board(flop=mkflop("TcJcQc")) eval_result = evaluate_hand(hole_cards, board) assert eval_result == EvaluationResult(hand_type=HandType.STRAIGHT_FLUSH, kicker=9)
def test_turn() -> None: hole_cards = mkhand("7d8s") board = Board(flop=mkflop("5h6cJs"), turn=mkcard("5h")) eval_result = evaluate_hand(hole_cards, board) assert eval_result == EvaluationResult(hand_type=HandType.PAIR, kicker=66144)
def make_player_states(player_index: int, game: GameView, hole_cards: HoleCards, board: Board) -> List[PlayerState]: player_states = [] street_cache: Dict[Street, PlayerState] = {} for i in iter_game_states(game): game_view = game.view(i) is_player_turn = game_view.current_player() == player_index # We don't set the rest of the values for non-current-players if not is_player_turn: player_states.append( PlayerState( is_current_player=False, current_player_offset=(game_view.current_player() - player_index), )) continue street = game_view.street() # These values don't vary by street, so we cache them if street in street_cache: player_states.append(street_cache[street]) continue if game_view.street() == Street.PREFLOP: player_state = PlayerState(is_current_player=True, current_player_offset=0) else: current_board = board.at_street(game_view.street()) hand_eval = evaluate_hand(hole_cards, current_board) hand_features = pyholdthem.make_hand_features_from_indices( hole_cards.index(), [c.index() for c in current_board.cards()], 1000) player_state = PlayerState( is_current_player=True, current_player_offset=0, current_hand_type=hand_eval.hand_type.value, frac_better_hands=hand_features.frac_better_hands, frac_tied_hands=hand_features.frac_tied_hands, frac_worse_hands=hand_features.frac_worse_hands, win_odds=hand_features.win_odds, tie_odds=hand_features.tie_odds, lose_odds=hand_features.lose_odds, win_odds_vs_better=hand_features.win_odds_vs_better, tie_odds_vs_better=hand_features.tie_odds_vs_better, lose_odds_vs_better=hand_features.lose_odds_vs_better, win_odds_vs_tied=hand_features.win_odds_vs_tied, tie_odds_vs_tied=hand_features.tie_odds_vs_tied, lose_odds_vs_tied=hand_features.lose_odds_vs_tied, win_odds_vs_worse=hand_features.win_odds_vs_worse, tie_odds_vs_worse=hand_features.tie_odds_vs_worse, lose_odds_vs_worse=hand_features.lose_odds_vs_worse, ) street_cache[street] = player_state player_states.append(player_state) return player_states
def test_state() -> None: deal = FullDeal( hole_cards=[mkhand("AhKs"), mkhand("Kc10d")], board=Board(flop=mkflop("KdJs3d"), turn=mkcard("7s"), river=mkcard("6s")), ) game = GameRunner(starting_stacks=[300, 400]) game.start_game() # Preflop game.bet_raise(to=10) game.call() # Flop game.check() game.check() # Turn game.check() game.check() # River game.check() game.check() player_index = 0 private_states = make_player_states(player_index, game.game_view(), deal.hole_cards[player_index], deal.board) assert private_states == [ PlayerState( is_current_player=True, current_player_offset=0, current_hand_type=None, frac_better_hands=None, frac_tied_hands=None, frac_worse_hands=None, win_odds=None, tie_odds=None, lose_odds=None, win_odds_vs_better=None, tie_odds_vs_better=None, lose_odds_vs_better=None, win_odds_vs_tied=None, tie_odds_vs_tied=None, lose_odds_vs_tied=None, win_odds_vs_worse=None, tie_odds_vs_worse=None, lose_odds_vs_worse=None, ), PlayerState( is_current_player=False, current_player_offset=1, current_hand_type=None, frac_better_hands=None, frac_tied_hands=None, frac_worse_hands=None, win_odds=None, tie_odds=None, lose_odds=None, win_odds_vs_better=None, tie_odds_vs_better=None, lose_odds_vs_better=None, win_odds_vs_tied=None, tie_odds_vs_tied=None, lose_odds_vs_tied=None, win_odds_vs_worse=None, tie_odds_vs_worse=None, lose_odds_vs_worse=None, ), PlayerState( is_current_player=True, current_player_offset=0, current_hand_type=2, frac_better_hands=approx(0.02867715060710907, abs=0.1), frac_tied_hands=approx(0.005550416186451912, abs=0.1), frac_worse_hands=approx(0.9657724499702454, abs=0.1), win_odds=approx(0.8368927240371704, abs=0.1), tie_odds=approx(0.010364476591348648, abs=0.1), lose_odds=approx(0.15274283289909363, abs=0.1), win_odds_vs_better=approx(0.16899999976158142, abs=0.1), tie_odds_vs_better=approx(0.0020000000949949026, abs=0.1), lose_odds_vs_better=approx(0.8289999961853027, abs=0.1), win_odds_vs_tied=0.0, tie_odds_vs_tied=approx(0.9869999885559082, abs=0.1), lose_odds_vs_tied=approx(0.013000000268220901, abs=0.1), win_odds_vs_worse=approx(0.8840000033378601, abs=0.1), tie_odds_vs_worse=approx(0.004000000189989805, abs=0.1), lose_odds_vs_worse=approx(0.1120000034570694, abs=0.1), ), PlayerState( is_current_player=False, current_player_offset=1, current_hand_type=None, frac_better_hands=None, frac_tied_hands=None, frac_worse_hands=None, win_odds=None, tie_odds=None, lose_odds=None, win_odds_vs_better=None, tie_odds_vs_better=None, lose_odds_vs_better=None, win_odds_vs_tied=None, tie_odds_vs_tied=None, lose_odds_vs_tied=None, win_odds_vs_worse=None, tie_odds_vs_worse=None, lose_odds_vs_worse=None, ), PlayerState( is_current_player=True, current_player_offset=0, current_hand_type=2, frac_better_hands=approx(0.05603864789009094, abs=0.1), frac_tied_hands=approx(0.005797101650387049, abs=0.1), frac_worse_hands=approx(0.938164234161377, abs=0.1), win_odds=approx(0.8556057810783386, abs=0.1), tie_odds=approx(0.005797101650387049, abs=0.1), lose_odds=approx(0.13859710097312927, abs=0.1), win_odds_vs_better=0.0, tie_odds_vs_better=0.0, lose_odds_vs_better=1.0, win_odds_vs_tied=0.0, tie_odds_vs_tied=1.0, lose_odds_vs_tied=0.0, win_odds_vs_worse=approx(0.9120000004768372, abs=0.1), tie_odds_vs_worse=0.0, lose_odds_vs_worse=approx(0.08799999952316284, abs=0.1), ), PlayerState( is_current_player=False, current_player_offset=1, current_hand_type=None, frac_better_hands=None, frac_tied_hands=None, frac_worse_hands=None, win_odds=None, tie_odds=None, lose_odds=None, win_odds_vs_better=None, tie_odds_vs_better=None, lose_odds_vs_better=None, win_odds_vs_tied=None, tie_odds_vs_tied=None, lose_odds_vs_tied=None, win_odds_vs_worse=None, tie_odds_vs_worse=None, lose_odds_vs_worse=None, ), PlayerState( is_current_player=True, current_player_offset=0, current_hand_type=2, frac_better_hands=approx(0.14646464586257935, abs=0.1), frac_tied_hands=approx(0.0060606058686971664, abs=0.1), frac_worse_hands=approx(0.8474747538566589, abs=0.1), win_odds=approx(0.8474747538566589, abs=0.1), tie_odds=approx(0.0060606058686971664, abs=0.1), lose_odds=approx(0.14646464586257935, abs=0.1), win_odds_vs_better=0.0, tie_odds_vs_better=0.0, lose_odds_vs_better=1.0, win_odds_vs_tied=0.0, tie_odds_vs_tied=1.0, lose_odds_vs_tied=0.0, win_odds_vs_worse=1.0, tie_odds_vs_worse=0.0, lose_odds_vs_worse=0.0, ), PlayerState( is_current_player=False, current_player_offset=1, current_hand_type=None, frac_better_hands=None, frac_tied_hands=None, frac_worse_hands=None, win_odds=None, tie_odds=None, lose_odds=None, win_odds_vs_better=None, tie_odds_vs_better=None, lose_odds_vs_better=None, win_odds_vs_tied=None, tie_odds_vs_tied=None, lose_odds_vs_tied=None, win_odds_vs_worse=None, tie_odds_vs_worse=None, lose_odds_vs_worse=None, ), ]
def test_fold_preflop() -> None: # Player 3 wins with a flopped set of jacks. deal = FullDeal( hole_cards=[mkhand("AcAd"), mkhand("AsKh"), mkhand("JcJh")], board=Board(flop=mkflop("KsJs3d"), turn=mkcard("7s"), river=mkcard("6s")), ) game = GameRunner(starting_stacks=[200, 250, 300]) game.start_game() game.bet_raise(to=10) game.fold() game.fold() results = result.get_result(deal, game.game_view()) s = Stats() s.update_stats(game.game_view(), results, player_id=0) assert s == Stats( num_hands=1, reward=-1, num_wins=0, num_losses=1, num_flops=0, num_turns=0, num_rivers=0, num_showdowns=0, num_decisions=1, num_check=0, num_call=0, total_amount_called=0, num_bet=0, total_amount_bet=0, num_fold=1, ) s = Stats() s.update_stats(game.game_view(), results, player_id=1) assert s == Stats( num_hands=1, reward=-2, num_wins=0, num_losses=1, num_flops=0, num_turns=0, num_rivers=0, num_showdowns=0, num_decisions=1, num_check=0, num_call=0, total_amount_called=0, num_bet=0, total_amount_bet=0, num_fold=1, ) s = Stats() s.update_stats(game.game_view(), results, player_id=2) assert s == Stats( num_hands=1, reward=3, num_wins=1, num_losses=0, num_flops=0, num_turns=0, num_rivers=0, num_showdowns=0, num_decisions=1, num_check=0, num_call=0, total_amount_called=0, num_bet=1, total_amount_bet=10, num_fold=0, )
def test_wheel() -> None: hole_cards = mkhand("2c7d") board = Board(flop=mkflop("3h4c5s")) eval_result = evaluate_hand(hole_cards, board) assert eval_result == EvaluationResult(hand_type=HandType.HIGH, kicker=47)