From 45c297465fdac2f57d4fce2b88d5b5e24a3f1a8d Mon Sep 17 00:00:00 2001 From: kakty3 Date: Wed, 13 Jul 2016 15:28:10 +0600 Subject: [PATCH] store hh._Action in hh.*_action attributes closes #2 --- poker/room/pokerstars.py | 102 ++++++++++++++++++++++++++++++-- tests/handhistory/test_stars.py | 99 ++++++++++++++++--------------- 2 files changed, 148 insertions(+), 53 deletions(-) diff --git a/poker/room/pokerstars.py b/poker/room/pokerstars.py index 21310d6..889380c 100644 --- a/poker/room/pokerstars.py +++ b/poker/room/pokerstars.py @@ -112,6 +112,96 @@ def _parse_connected(self, line): name = splited[0] return name, Action.CONNECTED, None + +class ActionParser(object): + _player_action_re = re.compile(r'^(?P.+):\s+(?P.+?\b)\s*(?:[^\d]*?(?P\d+(?:\.\d+)?))?') + _uncalled_re = re.compile(r'^Uncalled bet \([^\d]*?(?P\d+(?:\.\d+)?)\) returned to\s+(?P.+)$') + _collected_re = re.compile(r'^(?P.+?) collected [^\d]*?(?P\d+(?:\.\d+)?)') + + # @classmethod + def parse(self, action_str): + if action_str.startswith('Uncalled bet'): + action = self._parse_uncalled(action_str) + elif ' collected ' in action_str: + action = self._parse_collected(action_str) + elif "doesn't show hand" in action_str: + action = self._parse_muck(action_str) + elif ' said, "' in action_str: # skip chat lines + action = None + elif ':' in action_str: + action = self._parse_player_action(action_str) + elif 'joins the table' in action_str: + action = self._parse_join_table(action_str) + elif 'leaves the table' in action_str: + action = self._parse_leave_table(action_str) + elif 'has timed out' in action_str: + action = self._parse_timed_out(action_str) + elif 'is connected' in action_str: + action = self._parse_connected(action_str) + elif 'is disconnected' in action_str: + action = self._parse_disconnected(action_str) + else: + raise RuntimeError("Unknown action: " + action_str) + + return hh._PlayerAction(*action) + + def _parse_uncalled(self, line): + match = self._uncalled_re.match(line) + name = match.group('name') + amount = match.group('amount') + return name, Action.RETURN, Decimal(amount) + + def _parse_collected(self, line): + match = self._collected_re.match(line) + name = match.group('name') + amount = match.group('amount') + self.pot = Decimal(amount) + return name, Action.WIN, self.pot + + def _parse_muck(self, line): + colon_index = line.find(':') + name = line[:colon_index] + return name, Action.MUCK, None + + def _parse_player_action(self, line): + match = self._player_action_re.match(line) + name = match.group('name') + action = Action(match.group('action')) + amount = match.group('amount') + try: + amount = Decimal(amount) + except TypeError: + pass + + return name, action, amount + + def _parse_join_table(self, line): + splited = line.split() + name = splited[0] + seat = splited[-1][1:] + return name, Action.JOIN, seat + + def _parse_leave_table(self, line): + splited = line.split() + name = splited[0] + return name, Action.LEAVE, None + + def _parse_timed_out(self, line): + splited = line.split() + name = splited[0] + return name, Action.TIMED_OUT, None + + def _parse_disconnected(self, line): + splited = line.split() + name = splited[0] + return name, Action.DISCONNECTED, None + + def _parse_connected(self, line): + splited = line.split() + name = splited[0] + return name, Action.CONNECTED, None + + @implementer(hh.IHandHistory) class PokerStarsHandHistory(hh._SplittableHandHistoryMixin, hh._BaseHandHistory): """Parses PokerStars Tournament hands.""" @@ -264,7 +354,8 @@ def _parse_hero(self): def _parse_preflop(self): start = self._sections[0] + 3 stop = self._sections[1] - self.preflop_actions = tuple(self._splitted[start:stop]) + ap = ActionParser() + self.preflop_actions = tuple(ap.parse(action_str) for action_str in self._splitted[start:stop]) def _parse_flop(self): try: @@ -277,15 +368,16 @@ def _parse_flop(self): self.flop = _Street(floplines) def _parse_street(self, street): + street_attr = '%s_actions' % street.lower() try: start = self._splitted.index(street.upper()) + 2 stop = self._splitted.index('', start) - street_actions = self._splitted[start:stop] - setattr(self, "{}_actions".format(street.lower()), - tuple(street_actions) if street_actions else None) + ap = ActionParser() + street_actions = [ap.parse(action_str) for action_str in self._splitted[start:stop]] + setattr(self, street_attr, tuple(street_actions) if street_actions else None) except ValueError: setattr(self, street, None) - setattr(self, '{}_actions'.format(street.lower()), None) + setattr(self, street_attr, None) def _parse_showdown(self): self.show_down = 'SHOW DOWN' in self._splitted diff --git a/tests/handhistory/test_stars.py b/tests/handhistory/test_stars.py index 4467398..4f0e0fd 100644 --- a/tests/handhistory/test_stars.py +++ b/tests/handhistory/test_stars.py @@ -218,15 +218,15 @@ def test_values_after_header_parsed(self, hand_header, attribute, expected_value ('river', None), ('board', (Card('2s'), Card('6d'), Card('6h'))), ('preflop_actions', ( - "strongi82: folds", - "W2lkm2n: raises 40 to 60", - "MISTRPerfect: calls 60", - "blak_douglas: folds", - "sinus91: folds", - "STBIJUJA: folds", - "flettl2: folds", - "santy312: folds", - "flavio766: folds" + _PlayerAction(name=u'strongi82', action=Action('fold'), amount=None), + _PlayerAction(name=u'W2lkm2n', action=Action('raise'), amount=Decimal(40)), + _PlayerAction(name=u'MISTRPerfect', action=Action('calls'), amount=Decimal(60)), + _PlayerAction(name=u'blak_douglas', action=Action('folds'), amount=None), + _PlayerAction(name=u'sinus91', action=Action('folds'), amount=None), + _PlayerAction(name=u'STBIJUJA', action=Action('folds'), amount=None), + _PlayerAction(name=u'flettl2', action=Action('folds'), amount=None), + _PlayerAction(name=u'santy312', action=Action('folds'), amount=None), + _PlayerAction(name=u'flavio766', action=Action('folds'), amount=None), )), ('turn_actions', None), ('river_actions', None), @@ -305,16 +305,17 @@ def test_values_after_header_parsed(self, hand_header, attribute, expected_value ('river', Card('Ks')), ('board', (Card('3c'), Card('6s'), Card('9d'), Card('8d'), Card('Ks'))), ('preflop_actions', ( - "lkenny44: folds", - "Newfie_187: raises 155 to 955 and is all-in", - "Hokolix: folds", - "pmmr: folds", - "costamar: raises 12040 to 12995 and is all-in", - "RichFatWhale: folds", - "W2lkm2n: calls 11740 and is all-in", - "Labahra: folds", - "Lean Abadia: folds", - "Uncalled bet (1255) returned to costamar")), + _PlayerAction(name=u'lkenny44', action=Action('fold'), amount=None), + _PlayerAction(name=u'Newfie_187', action=Action('raise'), amount=Decimal(155)), + _PlayerAction(name=u'Hokolix', action=Action('fold'), amount=None), + _PlayerAction(name=u'pmmr', action=Action('fold'), amount=None), + _PlayerAction(name=u'costamar', action=Action('raise'), amount=Decimal(12040)), + _PlayerAction(name=u'RichFatWhale', action=Action('fold'), amount=None), + _PlayerAction(name=u'W2lkm2n', action=Action('call'), amount=Decimal(11740)), + _PlayerAction(name=u'Labahra', action=Action('fold'), amount=None), + _PlayerAction(name=u'Lean Abadia', action=Action('fold'), amount=None), + _PlayerAction(name=u'costamar', action=Action('return'), amount=Decimal(1255)) + )), ('turn_actions', None), ('river_actions', None), ('total_pot', Decimal(26310)), @@ -398,17 +399,17 @@ def test_values_after_header_parsed(self, hand_header, attribute, expected_value ('river', None), ('board', None), ('preflop_actions', ( - 'EuSh0wTelm0: folds', - 'panost3: folds', - 'Samovlyblen: folds', - 'Theralion: raises 600 to 1200', - 'wrsport1015: folds', - 'W2lkm2n: folds', - 'fischero68: folds', - 'snelle_jel: folds', - 'Uncalled bet (600) returned to Theralion', - 'Theralion collected 1900 from pot', - "Theralion: doesn't show hand" + _PlayerAction(name=u'EuSh0wTelm0', action=Action('fold'), amount=None), + _PlayerAction(name=u'panost3', action=Action('fold'), amount=None), + _PlayerAction(name=u'Samovlyblen', action=Action('fold'), amount=None), + _PlayerAction(name=u'Theralion', action=Action('raise'), amount=Decimal(600)), + _PlayerAction(name=u'wrsport1015', action=Action('fold'), amount=None), + _PlayerAction(name=u'W2lkm2n', action=Action('fold'), amount=None), + _PlayerAction(name=u'fischero68', action=Action('fold'), amount=None), + _PlayerAction(name=u'snelle_jel', action=Action('fold'), amount=None), + _PlayerAction(name=u'Theralion', action=Action('return'), amount=Decimal(600)), + _PlayerAction(name=u'Theralion', action=Action('collected'), amount=Decimal(1900)), + _PlayerAction(name=u'Theralion', action=Action('did not show'), amount=None), )), ('turn_actions', None), ('river_actions', None), @@ -463,26 +464,28 @@ def test_values_after_header_parsed(self, hand_header, attribute, expected_value ('river', Card('Kd')), ('board', (Card('6s'), Card('4d'), Card('3s'), Card('8c'), Card('Kd'))), ('preflop_actions', ( - 'sinus91: folds', - 'STBIJUJA: folds', - 'flettl2: raises 125 to 225', - 'santy312: folds', - 'flavio766: folds', - 'strongi82: folds', - 'W2lkm2n: folds', - 'MISTRPerfect: folds', - 'blak_douglas: calls 125')), + _PlayerAction('sinus91', Action.FOLD, None), + _PlayerAction('STBIJUJA', Action.FOLD, None), + _PlayerAction('flettl2', Action.RAISE, Decimal(125)), + _PlayerAction('santy312', Action.FOLD, None), + _PlayerAction('flavio766', Action.FOLD, None), + _PlayerAction('strongi82', Action.FOLD, None), + _PlayerAction('W2lkm2n', Action.FOLD, None), + _PlayerAction('MISTRPerfect', Action.FOLD, None), + _PlayerAction('blak_douglas', Action.CALL, Decimal(125)), + )), ('turn_actions', ( - 'blak_douglas: checks', - 'flettl2: bets 250', - 'blak_douglas: calls 250')), + _PlayerAction('blak_douglas', Action.CHECK, None), + _PlayerAction('flettl2', Action.BET, Decimal(250)), + _PlayerAction('blak_douglas', Action.CALL, Decimal(250)) + )), ('river_actions', ( - 'blak_douglas: checks', - 'flettl2: bets 1300', - 'blak_douglas: folds', - 'Uncalled bet (1300) returned to flettl2', - 'flettl2 collected 1300 from pot', - "flettl2: doesn't show hand" + _PlayerAction('blak_douglas', Action.CHECK, None), + _PlayerAction('flettl2', Action.BET, Decimal(1300)), + _PlayerAction('blak_douglas', Action.FOLD, None), + _PlayerAction('flettl2', Action.RETURN, Decimal(1300)), + _PlayerAction('flettl2', Action.WIN, Decimal(1300)), + _PlayerAction('flettl2', Action.MUCK, None), )), ('total_pot', Decimal(1300)), ('show_down', False),