def get_all_pairs() -> List[CardsPair]: pairs: List[CardsPair] = [] for card1 in Card.cards_52(): for card2 in Card.cards_52(): if card1 > card2: pairs += [CardsPair(card1, card2)] return pairs
def process_flop(self, text: str) -> None: self.game.curr_hand.switch_to_step(Step.Flop) every_line = iter(text.strip().split('\n')) first_line = next(every_line) match = self.parser.find_flop.search(first_line) if match is None: raise ValueError(f'Bad first line in process flop: {text}') flop1 = Card(match.group(1).upper()) flop2 = Card(match.group(2).upper()) flop3 = Card(match.group(3).upper()) self.game.curr_hand.set_flop_cards(flop1, flop2, flop3) self.process_actions(every_line)
def process_flop(self, text: str): if self.is_broken_hand: return self.game.curr_hand.switch_to_step(Step.Flop) self.call_amount = 0 lines = iter(text.strip().split('\n')) line = next(lines) match = self.parser.find_flop.search(line) if match is None: raise ValueError(f'Bad first line in process flop: {text}') flop1 = Card(match.group(1).upper()) flop2 = Card(match.group(2).upper()) flop3 = Card(match.group(3).upper()) self.game.curr_hand.set_flop_cards(flop1, flop2, flop3) self.process_actions(lines)
def test_str_cards(self): self.assertEqual(Card('KD').card, 'KD') self.assertEqual(Card('QC').card, 'QC') self.assertEqual(Card('8H').card, '8H') self.assertEqual(Card('4C').card, '4C') self.assertEqual(Card('7S').card, '7S') self.assertEqual(Card('2H').card, '2H')
def test_short_cards(self): self.assertEqual(Card('4C').r, '4') self.assertEqual(Card('7C').r, '7') self.assertEqual(Card('JH').r, 'J') self.assertEqual(Card('4C').s, 'C') self.assertEqual(Card('7S').s, 'S') self.assertEqual(Card('JH').s, 'H')
def process_river(self, text: str) -> None: self.game.curr_hand.switch_to_step(Step.River) every_line = iter(text.strip().split('\n')) first_line = next(every_line) match = self.parser.find_river.search(first_line) if match is None: raise ValueError(f'Bad first line in process river: {text}') river_card = Card(match.group(1).upper()) self.game.curr_hand.set_river_card(river_card) self.process_actions(every_line)
def process_turn(self, text: str) -> None: self.game.curr_hand.switch_to_step(Step.Turn) self.call_amount = 0 every_line = iter(text.strip().split('\n')) first_line = next(every_line) match = self.parser.find_turn.search(first_line) if match is None: raise ValueError(f'Bad first line in process turn: {text}') turn_card = Card(match.group(1).upper()) self.game.curr_hand.set_turn_card(turn_card) self.process_actions(every_line)
def calculate_outs(hidden: CardsPair, common: Cards) -> Tuple[int, Cards]: if len(common) == 5 or not common: return 0, [] cards: Cards = [hidden.first, hidden.second] + common curr_hand_strength = HoldemPoker.fast_max_strength(cards) outs: int = 0 outs_cards = [] for card in Card.cards_52(): if card not in cards: new_hand_strength = HoldemPoker.fast_max_strength(cards + [card]) if new_hand_strength > curr_hand_strength: outs += 1 outs_cards += [card] return outs, outs_cards
def test_fast_hand_strength(self): cards = [Card('AS'), Card('8C'), Card('9D'), Card('2S'), Card('KD')] self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.Nothing) cards = [Card('AS'), Card('AC'), Card('9D'), Card('2S'), Card('KD')] self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.Pair) cards = [Card('AS'), Card('AC'), Card('9D'), Card('9S'), Card('KD')] self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.Pairs) cards = [Card('AS'), Card('KC'), Card('9D'), Card('9S'), Card('9H')] self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.Set) cards = [Card('JS'), Card('QC'), Card('KD'), Card('9S'), Card('TH')] self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.Straight) cards = [Card('AS'), Card('8S'), Card('9S'), Card('2S'), Card('KS')] self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.Flush) cards = [Card('AS'), Card('AC'), Card('9D'), Card('9S'), Card('9H')] self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.FullHouse) cards = [Card('AS'), Card('AH'), Card('9S'), Card('AC'), Card('AD')] self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.Quad) cards = [Card('QS'), Card('8S'), Card('9S'), Card('JS'), Card('TS')] self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.StraightFlush) cards = [Card('QS'), Card('AS'), Card('KS'), Card('JS'), Card('TS')] self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.RoyalFlush) deck = Deck() for _ in range(100): deck.shuffle() cards = [ deck.next(), deck.next(), deck.next(), deck.next(), deck.next() ] self.assertEqual(HoldemPoker.fast_hand_strength(cards), HandStrength.strength(*cards).strength)
def __str__(self): cards = self.get() return Card.str(cards) if cards else 'no cards'
def test_rank(self): self.assertEqual(Card('TH').rank, Rank.Ten) self.assertEqual(Card('5H').rank, Rank.Five) self.assertEqual(Card('AS').rank, Rank.Ace)
def test_equals(self): self.assertEqual(Card('AS'), Card('AS')) self.assertNotEqual(Card('AS'), Card('AC'))
def test_convert(self): for card1 in Card.cards_52(): for card2 in Card.cards_52(): self.assertEqual(card1 == card2, card1.convert() == card2.convert())
def test_compare_cards(self): self.assertGreater(Card('AD'), Card('KC')) self.assertGreater(Card('QD'), Card('2C')) self.assertGreater(Card('7H'), Card('4D')) self.assertGreater(Card('TS'), Card('9S'))
def test_there_is_all_cards_different(self): cards = Card.cards_52() self.assertEqual(len(set(cards)), 52)
def __init__(self): self.cards: Cards = Card.cards_52() self.used: Cards = []
def test_suit(self): self.assertEqual(Card('TH').suit, Suit.Hearts) self.assertEqual(Card('TC').suit, Suit.Clubs) self.assertEqual(Card('TD').suit, Suit.Diamonds) self.assertEqual(Card('TS').suit, Suit.Spades)
def process_actions(self, lines): while True: try: line = next(lines).strip() except StopIteration: return match = self.parser.find_dealt_cards.search(line) if match is not None: name = match.group(1) first_card = Card(match.group(2).upper()) second_card = Card(match.group(3).upper()) pair = CardsPair(first_card, second_card) self.game.curr_hand.set_cards(name, pair) continue match = self.parser.find_uncalled_bet.search(line) if match is not None: money = int(match.group(1)) name = match.group(2) self.game.curr_hand.add_decision(name, Event.ReturnMoney, money) continue match = self.parser.find_collect_pot.search(line) if match is not None: name = match.group(1) money = int(match.group(2)) self.game.curr_hand.add_decision(name, Event.WinMoney, money) continue match = self.parser.find_collect_side_pot.search(line) if match is not None: name = match.group(1) money = int(match.group(2)) self.game.curr_hand.add_decision(name, Event.WinMoney, money) continue match = self.parser.find_collect_side_pot_n.search(line) if match is not None: name = match.group(1) money = int(match.group(2)) self.game.curr_hand.add_decision(name, Event.WinMoney, money) continue match = self.parser.find_collect_main_pot.search(line) if match is not None: name = match.group(1) money = int(match.group(2)) self.game.curr_hand.add_decision(name, Event.WinMoney, money) continue match = self.parser.find_show_cards.search(line) if match is not None: name = match.group(1) cards = match.group(2) if len(cards) == 5: card1, card2 = map(str.upper, cards.split()) pair = CardsPair(Card(card1), Card(card2)) elif len(cards) == 2: only_card = Card(cards.upper()) pair = CardsPair(only_card) else: raise ValueError(f'Bad cards shown: {line}') self.game.curr_hand.set_cards(name, pair) continue match = self.parser.find_is_connected.search(line) if match is not None: name = match.group(1) self.game.curr_hand.add_decision(name, Event.Connected, 0) continue match = self.parser.find_is_disconnected.search(line) if match is not None: name = match.group(1) try: self.game.curr_hand.add_decision(name, Event.Disconnected, 0) except ValueError: pass continue match = self.parser.find_is_sitting_out.search(line) if match is not None: name = match.group(1) try: self.game.curr_hand.add_decision(name, Event.Disconnected, 0) except ValueError: pass continue match = self.parser.find_said.search(line) if match is not None: name = match.group(1) msg = match.group(2) try: self.game.curr_hand.add_decision(name, Event.ChatMessage, 0, msg) except ValueError: self.game.curr_hand.add_decision(name, Event.ObserverChatMessage, 0, msg) continue match = self.parser.find_observer_said.search(line) if match is not None: name = match.group(1) msg = match.group(2) self.game.curr_hand.add_decision(name, Event.ObserverChatMessage, 0, msg) continue match = self.parser.find_finished.search(line) if match is not None: name = match.group(1) place = match.group(2) self.game.curr_hand.add_decision(name, Event.FinishGame, 0, place) match = self.parser.find_place.search(place) self.game.curr_hand.players_left = int(match.group(1)) continue match = self.parser.find_received.search(line) if match is not None: name = match.group(1) place = match.group(2) earn = int(match.group(3).replace('.', '')) self.game.curr_hand.add_decision(name, Event.FinishGame, earn, place) match = self.parser.find_place.search(place) self.game.curr_hand.players_left = int(match.group(1)) continue match = self.parser.find_received_fpp.search(line) if match is not None: name = match.group(1) place = match.group(2) earn = int(match.group(3)) self.game.curr_hand.add_decision(name, Event.FinishGame, earn, place) match = self.parser.find_place.search(place) self.game.curr_hand.players_left = int(match.group(1)) continue match = self.parser.find_winner.search(line) if match is not None: name = match.group(1) earn = int(match.group(2).replace('.', '')) self.game.curr_hand.add_decision(name, Event.FinishGame, earn, '1st') continue match = self.parser.find_does_not_show.search(line) if match is not None: continue match = self.parser.find_has_returned.search(line) if match is not None: name = match.group(1) try: self.game.curr_hand.add_decision(name, Event.Connected, 0) except ValueError: pass continue match = self.parser.find_has_timed_out.search(line) if match is not None: continue match = self.parser.find_timed_disconnected.search(line) if match is not None: name = match.group(1) self.game.curr_hand.add_decision(name, Event.Disconnected, 0) continue match = self.parser.find_timed_being_disconnected.search(line) if match is not None: name = match.group(1) self.game.curr_hand.add_decision(name, Event.Disconnected, 0) continue match = self.parser.find_finished_the_tournament.search(line) if match is not None: continue match = self.parser.find_eliminated_and_bounty.search(line) if match is not None: continue match = self.parser.find_eliminated_and_bounty_first.search(line) if match is not None: continue match = self.parser.find_eliminated_and_bounty_split.search(line) if match is not None: continue match = self.parser.find_rebuy_and_receive_chips.search(line) if match is not None: continue match = self.parser.find_rebuy_for_starcoins.search(line) if match is not None: continue match = self.parser.find_addon_and_receive_chips.search(line) if match is not None: continue match = self.parser.find_addon_for_starcoins.search(line) if match is not None: continue match = self.parser.find_skip_break_and_resuming.search(line) if match is not None: continue match = self.parser.find_wins_entry_to_tournament.search(line) if match is not None: continue match = self.parser.find_add_chips.search(line) if match is not None: continue if match is not None: name = match.group(1) self.game.curr_hand.add_decision(name, Event.Disconnected, 0) continue match = self.parser.find_shows_in_show_down.search(line) if match is not None: name = match.group(1) card1 = Card(match.group(2).upper()) card2 = Card(match.group(3).upper()) self.game.curr_hand.set_cards(name, CardsPair(card1, card2)) continue match = self.parser.find_fold_showing_cards.search(line) if match is not None: name = match.group(1) cards = match.group(2) if len(cards) == 5: card1, card2 = map(str.upper, cards.split()) pair = CardsPair(Card(card1), Card(card2)) elif len(cards) == 2: only_card = Card(cards.upper()) pair = CardsPair(only_card) else: raise ValueError(f'Bad cards shown: {line}') self.game.curr_hand.set_cards(name, pair) continue match = self.parser.find_mucks_hand.search(line) if match is not None: continue match = self.parser.find_action.search(line) try: name = match.group(1) action = match.group(2) except AttributeError: print('Cannot parse line:', line) raise try: result, money = self.parse_action( self.game.curr_hand.get_player(name), self.game.curr_hand.curr_step, action) except ValueError: print('Bad action: ' + line) raise self.game.curr_hand.add_decision(name, result, money)
def process_actions(self, lines): while True: try: line = next(lines).strip() except StopIteration: return if not line: return match = self.parser.find_dealt_cards.search(line) if match is not None: name = match.group(1) first_card = Card(match.group(2).upper()) second_card = Card(match.group(3).upper()) pair = CardsPair(first_card, second_card) self.game.curr_hand.set_cards(name, pair) continue match = self.parser.find_fold.search(line) if match is not None: name = match.group(1) self.game.curr_hand.add_decision(name, Event.Fold, 0) continue match = self.parser.find_call.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace(',', '')) self.total_pot += money self.game.curr_hand.add_decision(name, Event.Call, self.call_amount) continue match = self.parser.find_call_2.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace('\xa0', '')) self.total_pot += money self.game.curr_hand.add_decision(name, Event.Call, self.call_amount) continue match = self.parser.find_check.search(line) if match is not None: name = match.group(1) self.game.curr_hand.add_decision(name, Event.Check, 0) continue match = self.parser.find_bet.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace(',', '')) self.call_amount = money self.total_pot += money self.game.curr_hand.add_decision(name, Event.Raise, money) continue match = self.parser.find_bet_2.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace('\xa0', '')) self.call_amount = money self.total_pot += money self.game.curr_hand.add_decision(name, Event.Raise, money) continue match = self.parser.find_raise.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace(',', '')) self.total_pot += money self.call_amount = self.game.curr_hand.get_player(name).gived( self.game.curr_hand.curr_step) + money try: self.game.curr_hand.add_decision(name, Event.Raise, self.call_amount) except ValueError: print('Can not add decision: ' + line) raise continue match = self.parser.find_raise_2.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace('\xa0', '')) self.total_pot += money self.call_amount = self.game.curr_hand.get_player(name).gived( self.game.curr_hand.curr_step) + money try: self.game.curr_hand.add_decision(name, Event.Raise, self.call_amount) except ValueError: print('Can not add decision: ' + line) raise continue match = self.parser.find_did_not_show.search(line) if match is not None: continue match = self.parser.find_win_money.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace(',', '')) self.game.curr_hand.add_decision(name, Event.WinMoney, money) self.game.curr_hand.add_winner(name) continue match = self.parser.find_win_money_2.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace('\xa0', '')) self.game.curr_hand.add_decision(name, Event.WinMoney, money) self.game.curr_hand.add_winner(name) continue match = self.parser.find_show_cards.search(line) if match is not None: name = match.group(1) card1 = Card(match.group(2).upper()) card2 = Card(match.group(3).upper()) pair = CardsPair(card1, card2) self.game.curr_hand.set_cards(name, pair) self.game.curr_hand.goes_to_showdown = True continue match = self.parser.find_muck_cards.search(line) if match is not None: name = match.group(1) card1 = Card(match.group(2).upper()) card2 = Card(match.group(3).upper()) pair = CardsPair(card1, card2) self.game.curr_hand.set_cards(name, pair) self.game.curr_hand.add_loser(name) continue raise ValueError('Undefined action: ' + line)
def process_summary(self, text: str) -> None: every_line = iter(text.strip().split('\n')) line = next(every_line).strip() if not line.startswith('Total pot'): raise ValueError(f'Bad first line of summary: {text}') if 'Main pot' in line: match = self.parser.find_total_pot_with_main_pot.search(line) else: match = self.parser.find_total_pot.search(line) try: total_pot = int(match.group(1)) except AttributeError: raise ValueError(f'Bad total pot: {line}') self.game.curr_hand.total_pot = total_pot line = next(every_line) if line.startswith('Board'): line = next(every_line) if not line.startswith('Seat'): raise ValueError(f'Bad second/third line of summary: {text}') while line.startswith('Seat'): if line.endswith("folded before Flop (didn't bet)") or \ line.endswith('folded before Flop') or \ line.endswith('folded on the Flop') or \ line.endswith('folded on the Turn') or \ line.endswith('folded on the River'): try: line = next(every_line) except StopIteration: return continue if ' (button) ' in line: line = line.replace(' (button) ', ' ') if ' (big blind) ' in line: line = line.replace(' (big blind) ', ' ') if ' (small blind) ' in line: line = line.replace(' (small blind) ', ' ') match = self.parser.find_collected_pot_summary.search(line) if match is not None: name = match.group(1) win_player_cards = self.game.curr_hand.get_player(name).cards if win_player_cards is not None and win_player_cards.initialized( ): self.game.curr_hand.add_winner(name) else: match = self.parser.find_lost.search(line) if match is not None: name = match.group(1) card1 = Card(match.group(2).upper()) card2 = Card(match.group(3).upper()) self.game.curr_hand.set_cards(name, CardsPair(card1, card2)) self.game.curr_hand.add_loser(name) else: match = self.parser.find_won.search(line) if match is not None: name = match.group(1) card1 = Card(match.group(2).upper()) card2 = Card(match.group(3).upper()) self.game.curr_hand.set_cards(name, CardsPair(card1, card2)) self.game.curr_hand.add_winner(name) else: match = self.parser.find_mucked_cards.search(line) if match is not None: name = match.group(1) card1 = Card(match.group(2).upper()) card2 = Card(match.group(3).upper()) self.game.curr_hand.set_cards( name, CardsPair(card1, card2)) self.game.curr_hand.add_loser(name) else: raise ValueError( f'Bad summary processing line: {line}') try: line = next(every_line) except StopIteration: return self.process_actions(every_line)
def test_str_cards_list(self): self.assertEqual(Card.str([Card('AS'), Card('QD'), Card('2C')]), 'AS QD 2C')
def process_actions(self, lines): while True: try: line = next(lines).strip() except StopIteration: return if not line: return match = self.parser.find_dealt_cards.search(line) if match is not None: name = match.group(1) first_card = Card(match.group(2).upper()) second_card = Card(match.group(3).upper()) pair = CardsPair(first_card, second_card) self.game.curr_hand.set_cards(name, pair) continue match = self.parser.find_fold.search(line) if match is not None: name = match.group(1) try: self.game.curr_hand.add_decision(name, Event.Fold, 0) except ValueError: pass continue match = self.parser.find_call.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace(',', '')) self.total_pot += money self.game.curr_hand.add_decision(name, Event.Call, self.call_amount) continue match = self.parser.find_check.search(line) if match is not None: name = match.group(1) self.game.curr_hand.add_decision(name, Event.Check, 0) continue match = self.parser.find_bet.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace(',', '')) self.call_amount = money self.total_pot += money self.game.curr_hand.add_decision(name, Event.Raise, money) continue match = self.parser.find_raise.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace(',', '')) self.total_pot += money self.call_amount = self.game.curr_hand.get_player(name).gived( self.game.curr_hand.curr_step) + money self.game.curr_hand.add_decision(name, Event.Raise, self.call_amount) continue match = self.parser.find_all_in.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace(',', '')) self.total_pot += money self.call_amount = self.game.curr_hand.get_player(name).gived( self.game.curr_hand.curr_step) + money self.game.curr_hand.add_decision(name, Event.Raise, self.call_amount) continue match = self.parser.find_did_not_show.search(line) if match is not None: continue match = self.parser.find_win_money.search(line) if match is not None: name = match.group(1) money = int(match.group(2).replace(',', '')) self.game.curr_hand.add_decision(name, Event.WinMoney, money) self.game.curr_hand.add_winner(name) continue match = self.parser.find_show_cards.search(line) if match is not None: name = match.group(1) card1 = Card(match.group(2).upper()) card2 = Card(match.group(3).upper()) pair = CardsPair(card1, card2) self.game.curr_hand.set_cards(name, pair) self.game.curr_hand.goes_to_showdown = True continue match = self.parser.find_finished.search(line) if match is not None: name = match.group(1) place = match.group(2) self.game.curr_hand.add_decision(name, Event.FinishGame, 0, place) continue match = self.parser.find_knocked_out.search(line) if match is not None: continue match = self.parser.find_join_game.search(line) if match is not None: continue match = self.parser.find_use_bank_time.search(line) if match is not None: continue match = self.parser.find_did_not_respond.search(line) if match is not None: continue match = self.parser.find_not_respond_disconnected.search(line) if match is not None: name = match.group(1) self.game.curr_hand.add_decision(name, Event.Disconnected, 0) continue match = self.parser.find_moved_from_other_table.search(line) if match is not None: continue match = self.parser.find_break.search(line) if match is not None: continue match = self.parser.find_activate_bank.search(line) if match is not None: continue match = self.parser.find_reconnected.search(line) if match is not None: continue match = self.parser.find_disconnected_wait.search(line) if match is not None: continue match = self.parser.find_level_moves.search(line) if match is not None: continue match = self.parser.find_chat_message.search(line) if match is not None: name = match.group(1) message = match.group(2) try: self.game.curr_hand.add_decision(name, Event.ChatMessage, 0, message) except ValueError: self.game.curr_hand.add_decision(name, Event.ObserverChatMessage, 0, message) continue match = self.parser.find_end_of_hand.search(line) if match is not None: self.game.curr_hand.total_pot = self.total_pot break raise ValueError('Undefined action: ' + line)