def calculate(self, hand_range_string, board_card_strings): """Calculate the probabilities of each hand type.""" for key in hand_types + draw_types + pair_types: self[key] = 0.0 board = list(map(eval7.Card, board_card_strings)) hr = hand_range.HandRange(hand_range_string) hr.exclude_cards(board) if len(board) < 3: raise ValueError("Not enough cards in board!") for hand, prob in hr.items(): if not prob == 0.0: cards = board + list(hand) result = eval7.evaluate(cards) hand_type = eval7.handtype(result) self[hand_type] += prob if len(cards) < 7 and hand_types.index(hand_type) < 5: # No flush or better, so there may be draws. if self.check_flush_draw(cards): self["Flush Draw"] += prob if hand_type != 'Straight': straight_draw_type = self.check_straight_draw(cards) if straight_draw_type is not None: self[straight_draw_type] += prob if hand_type == "Pair": # Break down pairs by type. self[self.pair_type(hand, board)] += prob
def calc_num_outs(curr_hand): # no outs pre flop if len(curr_hand) == 2: return 0 # calculate outs after flop and turn deck = eval7.Deck() remaining_cards = list(set(deck.cards) - set(curr_hand)) num_outs = 0 curr_strength = eval7.evaluate(curr_hand) curr_rank = eval7.handtype(curr_strength) for card in remaining_cards: hand = curr_hand + [card] hand_strength = eval7.evaluate(hand) hand_rank = eval7.handtype(hand_strength) if hand_strength > curr_strength and hand_rank != curr_rank: num_outs += 1 return num_outs
def rank_hand_py(self, player): print('Player ' + player.name + ' hand: ' + player.hole_cards_str()) cards = [eval7.Card(s) for s in (str(player.hole_cards[0]), str(player.hole_cards[1]), str(self.community[1][0]), str(self.community[1][1]), str(self.community[1][2]), str(self.community[2][0]), str(self.community[3][0]))] rank = eval7.evaluate(cards) handtype = eval7.handtype(rank) print(player.name + ' hand rank: ' + str(rank) + ', hand type: ' + handtype) return rank
def create_opp_hand_from_rank_distribution(opp_hand_rank_probas, public_cards, my_hand): deck = Deck() potential_hands = [] remaining_cards = list(set(deck.cards) - set(public_cards + my_hand)) selected_hand_rank = random.choices(['High Card', 'Pair', 'Two Pair', 'Trips', 'Straight', 'Flush', 'Nuts'], weights=opp_hand_rank_probas[0]) for hand in itertools.combinations(remaining_cards, 2): hand_strength = eval7.evaluate(public_cards + list(hand)) hand_rank = eval7.handtype(hand_strength) # print(selected_hand_rank) if hand_rank in selected_hand_rank: potential_hands.append(hand) elif selected_hand_rank == 'Nuts' and hand_rank in ['Quads', 'Full House', 'Straight Flush']: potential_hands.append(hand) return (remaining_cards[0], remaining_cards[1]) if len(potential_hands) == 0 else random.choice(potential_hands)
def handTypes(cards, board): hand = [eval7.Card(c) for c in cards + board] madeHand = eval7.handtype(eval7.evaluate(hand)) handRanks, handSuits = zip(*(cards + board)) handRanks = set(handRanks) suitCounts = Counter(handSuits) isOESD, isGSSD, isBDSD = straightDraws(handRanks) isFD, isBDFD = flushDraws(suitCounts) isOvercards = overcards(cards, board) draws = set() comboDraws = set() if isOvercards: draws.add('overcards') # if made hand is worse than a flush if madeHandTypes.index(madeHand) > madeHandTypes.index('Flush'): if isFD: draws.add('flush draw') if madeHand == 'Pair': comboDraws.add('FD+Pair') if isOESD: comboDraws.add('FD+OESD') elif isGSSD: comboDraws.add('FD+gutshot') elif isBDFD: if isBDSD: comboDraws.add('BDFD+BDSD') # if made hand is worse than a straight if madeHandTypes.index(madeHand) > madeHandTypes.index('Straight'): if isOESD: draws.add('OESD') if madeHand == 'Pair': comboDraws.add('OESD+Pair') elif isGSSD: draws.add('gutshot') if madeHand == 'Pair': comboDraws.add('gutshot+Pair') elif isBDSD: draws.add('BDSD') return madeHand, draws, comboDraws
def test_evaluate(self): cases = ( (['2c', '3d', '4h', '5s', '7s', '8d', '9c'], 484658, 'High Card'), (['2c', '3d', '4h', '4s', '7s', '8d', '9c'], 16938576, 'Pair'), (['2c', '3d', '4h', '4s', '7s', '7d', '9c'], 33892096, 'Two Pair'), (['2c', '3d', '4h', '7s', '7c', '7d', '9c'], 50688512, 'Trips'), (['2c', '3d', '4h', '5s', '7c', '7d', '6c'], 67436544, 'Straight'), (['Ac', '3h', '4h', '5s', '2h', 'Jh', 'Kd'], 67305472, 'Straight'), (['Ac', '3h', 'Th', '5s', 'Qh', 'Jh', 'Kd'], 67895296, 'Straight'), (['2c', '3h', '4h', '5s', 'Jh', '7h', '6h'], 84497441, 'Flush'), (['Ac', 'Th', 'Ts', 'Ks', 'Kh', 'Kd'], 101416960, 'Full House'), (['Ac', '3h', 'Th', 'Ks', 'Kh', 'Kd', 'Kc'], 118210560, 'Quads'), (['3c', '2c', '5c', 'Ac', '4c', 'Kc'], 134414336, 'Straight Flush'), ) for card_strs, expected_val, expected_type in cases: cards = tuple(map(eval7.Card, card_strs)) value = eval7.evaluate(cards) handtype = eval7.handtype(value) self.assertEqual(value, expected_val) self.assertEqual(handtype, expected_type)
def decide_showdown(table_cards: Iterable[TexasCard], assist=True): """ If table cards have duplicates, the eval7 implementation might go wrong! so check for it @param table_cards: five to seven cards @return: """ if len(set(table_cards)) < len(tuple(table_cards)): raise ValueError('Duplicated cards') table_cards: List[TexasCard] = TexasCard.sort_desc(table_cards) hand = [eval7.Card(c.to_eval7_str()) for c in table_cards] int_type = eval7.evaluate(hand) str_type = eval7.handtype(int_type) best_type = STR_MAP[str_type] if assist and best_type == StraightFlush: # check with my implementation best = detect.decide_showdown(table_cards) assert isinstance(best, StraightFlush) or isinstance(best, RoyalFlush) if best.__class__ == RoyalFlush: best_type = RoyalFlush return best_type
import eval7
def update(self, state): curr_public_cards = state['public_cards'] prev_public_cards = [] if self.prev_state is None else self.prev_state[ 'public_cards'] curr_hand = state['hand'] prev_hand = [] if self.prev_state is None else self.prev_state['hand'] self.prev_stage = self.stage # new hand if len(curr_public_cards) < len( prev_public_cards) or curr_hand != prev_hand: self.stage = 0 self.prev_stage = 0 self.opp_num_raises_total = 0 self.my_num_raises_total = 0 self.prev_opp_num_raises_total = 0 self.prev_my_num_raises_total = 0 self.opp_num_raises_curr_phase = 0 self.opp_stack_committed_curr_phase = 0 self.action = None self.prev_action = None self.my_last_action = None self.prev_my_last_action = None self.opp_last_action = None self.prev_opp_last_action = None self.highest_card = None self.prev_highest_card = None self.num_queens = None self.num_kings = None self.num_aces = None self.hand_rank = None self.hand_strength = None self.prev_hand_strength = None self.winning_prob = None self.prev_winning_prob = None self.num_outs = None self.prev_num_outs = None self.hand = state['hand'] self.prev_dealer = self.dealer if 'check' in state['legal_actions'] and sum( state['raise_nums']) == 0: self.dealer = True elif 'call' in state['legal_actions'] and sum( state['raise_nums']) == 1: self.dealer = True else: self.dealer = False # hand full_hand = list(map(rlcardtoeval7, curr_hand + curr_public_cards)) eval7_strength = eval7.evaluate(full_hand) self.prev_hand_strength = self.hand_strength self.hand_strength = eval7_strength / MAX_EVAL_HS # scales to between 0 and 1. Needed for P(win) self.hand_rank = eval7.handtype(eval7_strength) self.prev_num_outs = self.num_outs self.num_outs = calc_num_outs(full_hand) self.prev_winning_prob = self.winning_prob self.winning_prob = calc_win_prob( list(map(rlcardtoeval7, curr_public_cards)), list(map(rlcardtoeval7, curr_hand)), self.num_outs) # stage if len(curr_public_cards) == 0: self.stage = 0 elif len(curr_public_cards) == 3: self.stage = 1 elif len(curr_public_cards) == 4: self.stage = 2 else: self.stage = 3 if self.stage > self.prev_stage: self.opp_num_raises_curr_phase = 0 self.opp_stack_committed_curr_phase = 0 self.my_num_raises_curr_phase = 0 self.my_stack_committed_curr_phase = 0 # raises new_raises = np.subtract( state['raise_nums'], [0, 0, 0, 0]) if self.prev_state is None else np.subtract( state['raise_nums'], self.prev_state['raise_nums']) new_raises = np.sum(new_raises) if self.prev_action == 'raise': opp_raises = new_raises - 1 else: opp_raises = new_raises if self.opp_last_action == 'raise': my_raises = new_raises - 1 else: my_raises = new_raises self.prev_opp_num_raises_total = self.opp_num_raises_total self.prev_my_num_raises_total = self.my_num_raises_total self.opp_num_raises_total = self.opp_num_raises_total + opp_raises self.my_num_raises_total = self.my_num_raises_total + my_raises self.my_num_raises_curr_phase = self.my_num_raises_curr_phase + my_raises self.my_stack_committed_curr_phase = self.my_stack_committed_curr_phase + 1 \ if (my_raises == 0 and action_to_num(self.action)) == 1 else 0 self.opp_num_raises_curr_phase = self.opp_num_raises_curr_phase + opp_raises self.opp_stack_committed_curr_phase = self.opp_stack_committed_curr_phase + opp_raises self.opp_stack_committed_curr_phase = self.opp_stack_committed_curr_phase + 1 \ if (opp_raises == 0 and self.dealer and self.my_last_action == 'raise') else 0 # Action self.prev_opp_last_action = self.opp_last_action self.opp_last_action = 2 if opp_raises > 0 else 1 self.prev_action = self.opp_last_action self.my_last_action = self.action # Board Info num_aces, num_kings, num_queens = 0, 0, 0 eval7_cards = list(map(rlcardtoeval7, curr_public_cards)) highest_card = eval7_cards[0] if len(curr_public_cards) > 0 else None for card in eval7_cards: if card > highest_card: highest_card = card if 'A' in str(card): num_aces += 1 elif 'K' in str(card): num_kings += 1 elif 'Q' in str(card): num_queens += 1 self.prev_highest_card = self.highest_card self.highest_card = None if highest_card is None else highest_card.rank self.num_queens = num_queens self.num_kings = num_kings self.prev_num_aces = self.num_aces self.num_aces = num_aces