示例#1
0
 def parseSummary(self):
     if self.hhtype == "summary":
         self.parseSummaryFile()
     elif self.hhtype == "html":
         self.parseSummaryHtml()
     elif self.hhtype == "hh":
         self.parseSummaryFromHH()
     else:
         raise FpdbParseError(_("parseSummary FAIL"))
示例#2
0
 def parseSummary(self):
     if self.hhtype == "summary":
         self.parseSummaryFile()
     elif self.hhtype == "html":
         if self.header == self.summaryText:
             raise FpdbHandPartial
         self.parseSummaryHtml()
     elif self.hhtype == "hh":
         self.parseSummaryFromHH()
     else:
         raise FpdbParseError(_("parseSummary FAIL"))
    def readAction(self, hand, street):
        m = self.re_Action.finditer(hand.streets[street])
        for action in m:
            acts = action.groupdict()
            playerName = action.group('PNAME')
            amount = clearMoneyString(
                action.group('BET')) if action.group('BET') else None
            actionType = action.group('ATYPE')

            if actionType == 'is all-In':
                # party's allin can mean either raise or bet or call
                Bp = hand.lastBet[street]
                if Bp == 0:
                    actionType = 'bets'
                elif Bp < Decimal(amount):
                    actionType = 'raises'
                else:
                    actionType = 'calls'

            if actionType == 'raises':
                if street == 'PREFLOP' and \
                    playerName in [item[0] for item in hand.actions['BLINDSANTES'] if item[2]!='ante']:
                    # preflop raise from blind
                    hand.addCallandRaise(street, playerName, amount)
                else:
                    hand.addCallandRaise(street, playerName, amount)
            elif actionType == 'calls':
                hand.addCall(street, playerName, amount)
            elif actionType == 'bets':
                hand.addBet(street, playerName, amount)
            elif actionType == 'folds':
                hand.addFold(street, playerName)
            elif actionType == 'checks':
                hand.addCheck(street, playerName)
            else:
                raise FpdbParseError(
                    _("Unimplemented readAction: '%s' '%s'") % (
                        playerName,
                        actionType,
                    ),
                    hid=hand.hid,
                )
示例#4
0
    def parseSummary(self):
        m = self.re_TourneyInfo.search(self.summaryText)
        if m == None:
            tmp = self.summaryText[0:200]
            log.error("parseSummary: " + _("Unable to recognise Tourney Info: '%s'") % tmp)
            log.error("parseSummary: " + _("Raising FpdbParseError"))
            raise FpdbParseError(_("Unable to recognise Tourney Info: '%s'") % tmp)

        print "DEBUG: m.groupdict(): %s" % m.groupdict()

        mg = m.groupdict()
        self.tourNo = ''
        self.gametype['limitType'] = ''
        self.gametype['category']  = ''
        self.buyin = 0
        self.fee   = 0
        self.prizepool = 0
        self.entries   = 0
        #self.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S")

        self.currency = "USD"
示例#5
0
    def processHand(self, handText):
        gametype = self.determineGameType(handText)
        log.debug("gametype %s" % gametype)
        hand = None
        l = None
        if gametype is None:
            gametype = "unmatched"
            # TODO: not ideal, just trying to not error. Throw ParseException?
            self.numErrors += 1
        else:
            # See if gametype is supported.
            if 'mix' not in gametype: gametype['mix'] = 'none'
            type = gametype['type']
            base = gametype['base']
            limit = gametype['limitType']
            l = [type] + [base] + [limit]

        if l in self.readSupportedGames():
            if gametype['base'] == 'hold':
                log.debug(
                    "hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handtext)"
                )
                hand = Hand.HoldemOmahaHand(self.config, self, self.sitename,
                                            gametype, handText)
            elif gametype['base'] == 'stud':
                hand = Hand.StudHand(self.config, self, self.sitename,
                                     gametype, handText)
            elif gametype['base'] == 'draw':
                hand = Hand.DrawHand(self.config, self, self.sitename,
                                     gametype, handText)
        else:
            log.error(_("Unsupported game type: %s") % gametype)
            raise FpdbParseError(_("Unsupported game type: %s") % gametype)

        if hand:
            #hand.writeHand(self.out_fh)
            return hand
        else:
            log.error(_("Unsupported game type: %s") % gametype)
示例#6
0
 def parseSummaryHtml(self):
     raise FpdbParseError(
         _("PokerStarsSummary.parseSummaryHtml: This file format is not yet supported"
           ))
    def parseSummary(self):
        m = self.re_TourneyInfo.search(self.summaryText)
        if m == None:
            tmp = self.summaryText[0:200]
            log.error("parseSummary: " +
                      _("Unable to recognise Tourney Info: '%s'") % tmp)
            log.error("parseSummary: " + _("Raising FpdbParseError"))
            raise FpdbParseError(
                _("Unable to recognise Tourney Info: '%s'") % tmp)

        #print "DEBUG: m.groupdict(): %s" % m.groupdict()

        mg = m.groupdict()
        if 'TOURNO' in mg: self.tourNo = mg['TOURNO']
        if 'LIMIT' in mg: self.gametype['limitType'] = self.limits[mg['LIMIT']]
        if 'GAME' in mg: self.gametype['category'] = self.games[mg['GAME']][1]
        if mg['BUYIN'] != None:
            self.buyin = int(100 * Decimal(mg['BUYIN']))
        if mg['FEE'] != None:
            self.fee = int(100 * Decimal(mg['FEE']))
        if 'PRIZEPOOL' in mg: self.prizepool = mg['PRIZEPOOL']
        if 'ENTRIES' in mg: self.entries = mg['ENTRIES']

        datetimestr = "%s/%s/%s %s:%s:%s" % (mg['Y'], mg['M'], mg['D'],
                                             mg['H'], mg['MIN'], mg['S'])
        self.startTime = datetime.datetime.strptime(datetimestr,
                                                    "%Y/%m/%d %H:%M:%S")

        if 'TZ' in mg:
            self.startTime = HandHistoryConverter.changeTimezone(
                self.startTime, mg['TZ'], "UTC")

        m = self.re_Currency.search(self.summaryText)
        if m == None:
            log.error("parseSummary: " + _("Unable to locate currency"))
            log.error("parseSummary: " + _("Raising FpdbParseError"))
            raise FpdbParseError(_("Unable to locate currency"))
        #print "DEBUG: m.groupdict(): %s" % m.groupdict()

        mg = m.groupdict()
        if mg['CURRENCY'] == "$": self.currency = "USD"
        elif mg['CURRENCY'] == u"€": self.currency = "EUR"
        elif mg['CURRENCY'] == "FPP": self.currency = "PSFP"

        m = self.re_Player.finditer(self.summaryText)
        for a in m:
            mg = a.groupdict()
            #print "DEBUG: a.groupdict(): %s" % mg
            name = mg['NAME']
            rank = mg['RANK']
            winnings = 0

            if 'WINNINGS' in mg and mg['WINNINGS'] != None:
                winnings = int(100 * Decimal(mg['WINNINGS']))

            if 'STILLPLAYING' in mg and mg['STILLPLAYING'] != None:
                #print "stillplaying"
                rank = None
                winnings = None

            if 'TICKET' and mg['TICKET'] != None:
                #print "Tournament Ticket Level %s" % mg['LEVEL']
                step_values = {
                    '1': '750',  # Step 1 -    $7.50 USD
                    '2': '2750',  # Step 2 -   $27.00 USD
                    '3': '8200',  # Step 3 -   $82.00 USD
                    '4': '21500',  # Step 4 -  $215.00 USD
                    '5': '70000',  # Step 5 -  $700.00 USD
                    '6': '210000',  # Step 6 - $2100.00 USD
                }
                winnings = step_values[mg['LEVEL']]

            #TODO: currency, ko/addon/rebuy count -> need examples!
            #print "DEBUG: addPlayer(%s, %s, %s, %s, None, None, None)" %(rank, name, winnings, self.currency)
            #print "DEBUG: self.buyin: %s self.fee %s" %(self.buyin, self.fee)
            self.addPlayer(rank, name, winnings, self.currency, None, None,
                           None)
示例#8
0
    def parseSummary(self):
        lines = self.summaryText.splitlines()

        self.tourNo = self.re_TourNo.findall(lines[0])[0][
            1:-1]  #ignore game and limit type as thats not recorded

        result = self.re_GameInfo.search(lines[0])
        result = result.groupdict()
        self.gametype['limitType'] = self.limits[result['LIMIT']]
        self.gametype['category'] = self.games[result['GAME']][1]

        if lines[1].find(
                "$"
        ) != -1:  #TODO: move this into a method and call that from PokerStarsToFpdb.py:269    if hand.buyinCurrency=="USD" etc.
            self.currency = "USD"
        elif lines[1].find(u"€") != -1:
            self.currency = "EUR"
        elif lines[1].find("FPP") != -1:
            self.currency = "PSFP"
        else:
            raise FpdbParseError(
                _("didn't recognise buyin currency in:") + lines[1])

        if self.currency == "USD" or self.currency == "EUR":
            result = self.re_BuyInFee.search(lines[1])
            result = result.groupdict()
            self.buyin = int(100 * Decimal(result['BUYIN']))
            self.fee = int(100 * Decimal(result['FEE']))
        elif self.currency == "PSFP":
            result = self.re_FPP.search(lines[1])
            result = result.groupdict()
            self.buyin = int(Decimal(result['FPP']))
            self.fee = 0

        currentLine = 2
        self.entries = self.re_Entries.findall(lines[currentLine])[0]
        currentLine += 1  #note that I chose to make the code keep state (the current line number)
        #as that means it'll fail rather than silently skip potentially valuable information
        #print "after entries lines[currentLine]", lines[currentLine]

        result = self.re_Added.search(lines[currentLine])
        if result:
            result = result.groupdict()
            self.added = 100 * int(Decimal(result['DOLLAR'])) + int(
                Decimal(result['CENT']))
            self.addedCurrency = result['CURRENCY']
            currentLine += 1
        else:
            self.added = 0
            self.addedCurrency = "NA"
        #print "after added/entries lines[currentLine]", lines[currentLine]

        result = self.re_Prizepool.findall(lines[currentLine])
        if result:
            self.prizepool = result[0]
            self.prizepool = self.prizepool[1:-3] + self.prizepool[-2:]
            currentLine += 1
        #print "after prizepool lines[currentLine]", lines[currentLine]

        useET = False
        result = self.re_DateTime.search(lines[currentLine])
        if not result:
            print _("in not result starttime")
            useET = True
            result = self.re_DateTimeET.search(lines[currentLine])
        result = result.groupdict()
        datetimestr = "%s/%s/%s %s:%s:%s" % (result['Y'], result['M'],
                                             result['D'], result['H'],
                                             result['MIN'], result['S'])
        self.startTime = datetime.datetime.strptime(
            datetimestr,
            "%Y/%m/%d %H:%M:%S")  # also timezone at end, e.g. " ET"
        self.startTime = HandHistoryConverter.changeTimezone(
            self.startTime, "ET", "UTC")
        currentLine += 1

        if useET:
            result = self.re_DateTimeET.search(lines[currentLine])
        else:
            result = self.re_DateTime.search(lines[currentLine])
        if result:
            result = result.groupdict()
            datetimestr = "%s/%s/%s %s:%s:%s" % (result['Y'], result['M'],
                                                 result['D'], result['H'],
                                                 result['MIN'], result['S'])
            self.endTime = datetime.datetime.strptime(
                datetimestr,
                "%Y/%m/%d %H:%M:%S")  # also timezone at end, e.g. " ET"
            self.endTime = HandHistoryConverter.changeTimezone(
                self.endTime, "ET", "UTC")
        currentLine += 1

        if lines[currentLine].find("Tournament is still in progress") != -1:
            currentLine += 1

        for i in range(currentLine,
                       len(lines) - 2):  #lines with rank and winnings info
            if lines[i].find(":") == -1:
                break
            result = self.re_Player.search(lines[i])
            result = result.groupdict()
            rank = result['RANK']
            name = result['NAME']
            winnings = result['WINNINGS']

            if winnings:
                winnings = int(100 * Decimal(winnings))
            else:
                winnings = 0

            if result['STILLPLAYING']:
                #print "stillplaying"
                rank = None
                winnings = None

            self.addPlayer(
                rank, name, winnings, self.currency, None, None,
                None)  #TODO: currency, ko/addon/rebuy count -> need examples!
    def parseSummary(self):
        m = self.re_TourneyInfo.search(self.summaryText[:2000])
        if m == None:
            tmp = self.summaryText[0:200]
            log.error("parseSummary: " +
                      _("Unable to recognise Tourney Info: '%s'") % tmp)
            log.error("parseSummary: " + _("Raising FpdbParseError"))
            raise FpdbParseError(
                _("Unable to recognise Tourney Info: '%s'") % tmp)

        #print "DEBUG: m.groupdict(): %s" % m.groupdict()

        mg = m.groupdict()
        if 'TOURNO' in mg: self.tourNo = mg['TOURNO']
        if 'LIMIT' in mg: self.gametype['limitType'] = self.limits[mg['LIMIT']]
        if 'GAME' in mg: self.gametype['category'] = self.games[mg['GAME']][1]
        if mg['BUYIN'] != None:
            self.buyin = int(100 * Decimal(mg['BUYIN']))
        if mg['FEE'] != None:
            self.fee = int(100 * Decimal(mg['FEE']))
        if 'PRIZEPOOL' in mg: self.prizepool = mg['PRIZEPOOL']
        if 'ENTRIES' in mg: self.entries = mg['ENTRIES']

        datetimestr = "%s/%s/%s %s:%s:%s" % (mg['Y'], mg['M'], mg['D'],
                                             mg['H'], mg['MIN'], mg['S'])
        self.startTime = datetime.datetime.strptime(datetimestr,
                                                    "%Y/%m/%d %H:%M:%S")

        if 'TZ' in mg:
            self.startTime = HandHistoryConverter.changeTimezone(
                self.startTime, mg['TZ'], "UTC")

        m = self.re_Currency.search(self.summaryText)
        if m == None:
            log.error("parseSummary: " + _("Unable to locate currency"))
            log.error("parseSummary: " + _("Raising FpdbParseError"))
            raise FpdbParseError(_("Unable to locate currency"))
        #print "DEBUG: m.groupdict(): %s" % m.groupdict()

        mg = m.groupdict()
        if mg['CURRENCY'] == "$": self.currency = "USD"
        elif mg['CURRENCY'] == u"€": self.currency = "EUR"
        elif mg['CURRENCY'] == "FPP": self.currency = "PSFP"

        m = self.re_Player.finditer(self.summaryText)
        playercount = 0
        for a in m:
            mg = a.groupdict()
            #print "DEBUG: a.groupdict(): %s" % mg
            name = mg['NAME']
            rank = mg['RANK']
            winnings = 0

            if 'WINNINGS' in mg and mg['WINNINGS'] != None:
                winnings = int(100 * Decimal(mg['WINNINGS']))
            self.addPlayer(rank, name, winnings, self.currency, None, None,
                           None)
            playercount += 1

        # Some files dont contain the normals lines, and only contain the line
        # <PLAYER> finished in XXXXrd place
        if playercount == 0:
            m = self.re_Finished.finditer(self.summaryText)
            for a in m:
                winnings = 0
                name = a.group('NAME')
                rank = a.group('RANK')
                self.addPlayer(rank, name, winnings, self.currency, None, None,
                               None)
示例#10
0
    def readHandInfo(self, hand):
        info = {}
        try:
            info.update(self.re_Hid.search(hand.handText).groupdict())
        except:
            raise FpdbParseError(_("Cannot read HID for current hand"))

        try:
            info.update(
                self.re_HandInfo.search(hand.handText, re.DOTALL).groupdict())
        except:
            raise FpdbParseError(_("Cannot read Handinfo for current hand"),
                                 hid=info['HID'])

        try:
            info.update(self._getGameType(hand.handText).groupdict())
        except:
            raise FpdbParseError(_("Cannot read GameType for current hand"),
                                 hid=info['HID'])

        m = self.re_CountedSeats.search(hand.handText)
        if m: info.update(m.groupdict())

        # FIXME: it's dirty hack
        # party doesnt subtract uncalled money from commited money
        # so hand.totalPot calculation has to be redefined
        from Hand import Pot, HoldemOmahaHand

        def getNewTotalPot(origTotalPot):
            def totalPot(self):
                if self.totalpot is None:
                    self.pot.end()
                    self.totalpot = self.pot.total
                for i, v in enumerate(self.collected):
                    if v[0] in self.pot.returned:
                        self.collected[i][1] = Decimal(
                            v[1]) - self.pot.returned[v[0]]
                        self.collectees[v[0]] -= self.pot.returned[v[0]]
                        self.pot.returned[v[0]] = 0
                return origTotalPot()

            return totalPot

        instancemethod = type(hand.totalPot)
        hand.totalPot = instancemethod(getNewTotalPot(hand.totalPot), hand,
                                       HoldemOmahaHand)

        log.debug("readHandInfo: %s" % info)
        for key in info:
            if key == 'DATETIME':
                #Saturday, July 25, 07:53:52 EDT 2009
                #Thursday, July 30, 21:40:41 MSKS 2009
                #Sunday, October 25, 13:39:07 MSK 2009
                m2 = re.search(
                    "\w+, (?P<M>\w+) (?P<D>\d+), (?P<H>\d+):(?P<MIN>\d+):(?P<S>\d+) (?P<TZ>[A-Z]+) (?P<Y>\d+)",
                    info[key])
                # we cant use '%B' due to locale problems
                months = [
                    'January', 'February', 'March', 'April', 'May', 'June',
                    'July', 'August', 'September', 'October', 'November',
                    'December'
                ]
                month = months.index(m2.group('M')) + 1
                datetimestr = "%s/%s/%s %s:%s:%s" % (
                    m2.group('Y'), month, m2.group('D'), m2.group('H'),
                    m2.group('MIN'), m2.group('S'))
                hand.startTime = datetime.datetime.strptime(
                    datetimestr, "%Y/%m/%d %H:%M:%S")
                # FIXME: some timezone correction required
                #tzShift = defaultdict(lambda:0, {'EDT': -5, 'EST': -6, 'MSKS': 3})
                #hand.starttime -= datetime.timedelta(hours=tzShift[m2.group('TZ')])

            if key == 'HID':
                hand.handid = info[key]
            if key == 'TABLE':
                hand.tablename = info[key]
            if key == 'MTTTABLE':
                if info[key] != None:
                    hand.tablename = info[key]
                    hand.tourNo = info['TABLE']
            if key == 'BUTTON':
                hand.buttonpos = info[key]
            if key == 'TOURNO':
                hand.tourNo = info[key]
            if key == 'TABLE_ID_WRAPPER':
                if info[key] == '#':
                    # FIXME: there is no such property in Hand class
                    self.isSNG = True
            if key == 'BUYIN':
                # FIXME: it's dirty hack T_T
                # code below assumes that tournament rake is equal to zero
                if info[key] == None:
                    hand.buyin = '$0+$0'
                else:
                    cur = info[key][0] if info[key][
                        0] not in '0123456789' else ''
                    hand.buyin = info[key] + '+%s0' % cur
            if key == 'LEVEL':
                hand.level = info[key]
            if key == 'PLAY' and info['PLAY'] != 'Real':
                # if realy party doesn's save play money hh
                hand.gametype['currency'] = 'play'
            if key == 'MAX' and info[key] is not None:
                hand.maxseats = int(info[key])
class PartyPoker(HandHistoryConverter):
    sitename = "PartyPoker"
    codepage = "utf8"
    siteId = 9
    filetype = "text"
    sym = {'USD': "\$", 'EUR': u"\u20ac", 'T$': ""}
    currencies = {
        "\$": "USD",
        "$": "USD",
        u"\xe2\x82\xac": "EUR",
        u"\u20ac": "EUR",
        '': "T$"
    }
    substitutions = {
        'LEGAL_ISO': "USD|EUR",  # legal ISO currency codes
        'LS':
        u"\$|\u20ac|\xe2\x82\xac|",  # Currency symbols - Euro(cp1252, utf-8)
        'NUM': u".,\d",
    }

    # Static regexes
    # $5 USD NL Texas Hold'em - Saturday, July 25, 07:53:52 EDT 2009
    # NL Texas Hold'em $1 USD Buy-in Trny:45685440 Level:8  Blinds-Antes(600/1 200 -50) - Sunday, May 17, 11:25:07 MSKS 2009
    re_GameInfoRing = re.compile(
        u"""
            (?P<CURRENCY>[%(LS)s])\s*(?P<RINGLIMIT>[.,0-9]+)([.,0-9/$]+)?\s*(?:%(LEGAL_ISO)s)?\s*
            (?P<LIMIT>(NL|PL|))\s*
            (?P<GAME>(Texas\ Hold\'em|Omaha|7\ Card\ Stud\ Hi-Lo))
            \s*\-\s*
            (?P<DATETIME>.+)
            """ % substitutions, re.VERBOSE | re.UNICODE)
    re_GameInfoTrny = re.compile(
        """
            (?P<LIMIT>(NL|PL|))\s*
            (?P<GAME>(Texas\ Hold\'em|Omaha))\s+
            (?:(?P<BUYIN>\$?[.,0-9]+)\s*(?P<BUYIN_CURRENCY>%(LEGAL_ISO)s)?\s*Buy-in\s+)?
            Trny:\s?(?P<TOURNO>\d+)\s+
            Level:\s*(?P<LEVEL>\d+)\s+
            ((Blinds|Stakes)(?:-Antes)?)\(
                (?P<SB>[.,0-9 ]+)\s*
                /(?P<BB>[.,0-9 ]+)
                (?:\s*-\s*(?P<ANTE>[.,0-9 ]+)\$?)?
            \)
            \s*\-\s*
            (?P<DATETIME>.+)
            """ % substitutions, re.VERBOSE | re.UNICODE)
    re_Hid = re.compile("Game \#(?P<HID>\d+) starts.")

    re_PlayerInfo = re.compile(
        u"""
          Seat\s(?P<SEAT>\d+):\s
          (?P<PNAME>.*)\s
          \(\s*[%(LS)s]?(?P<CASH>[%(NUM)s]+)\s*(?:%(LEGAL_ISO)s|)\s*\)
          """ % substitutions, re.VERBOSE | re.UNICODE)

    re_HandInfo = re.compile(
        """
            ^Table\s+(?P<TTYPE>[$a-zA-Z0-9 ]+)?\s+
            (?: \#|\(|)(?P<TABLE>\d+)\)?\s+
            (?:[a-zA-Z0-9 ]+\s+\#(?P<MTTTABLE>\d+).+)?
            (\(No\sDP\)\s)?
            \((?P<PLAY>Real|Play)\s+Money\)\s+ # FIXME: check if play money is correct
            Seat\s+(?P<BUTTON>\d+)\sis\sthe\sbutton
            \s+Total\s+number\s+of\s+players\s+\:\s+(?P<PLYRS>\d+)/?(?P<MAX>\d+)?
            """, re.VERBOSE | re.MULTILINE | re.DOTALL)

    re_CountedSeats = re.compile(
        "^Total\s+number\s+of\s+players\s*:\s*(?P<COUNTED_SEATS>\d+)",
        re.MULTILINE)
    re_SplitHands = re.compile('\x00+')
    re_TailSplitHands = re.compile('(\x00+)')
    lineSplitter = '\n'
    re_Button = re.compile('Seat (?P<BUTTON>\d+) is the button', re.MULTILINE)
    re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
    re_NoSmallBlind = re.compile(
        '^There is no Small Blind in this hand as the Big Blind '
        'of the previous hand left the table', re.MULTILINE)
    re_20BBmin = re.compile(r"Table 20BB Min")

    def allHandsAsList(self):
        list = HandHistoryConverter.allHandsAsList(self)
        if list is None:
            return []
        return filter(lambda text: len(text.strip()), list)

    def guessMaxSeats(self, hand):
        """Return a guess at max_seats when not specified in HH."""
        mo = self.maxOccSeat(hand)
        if mo == 10: return mo
        if mo == 2: return 2
        if mo <= 6: return 6
        # there are 9-max tables for cash and 10-max for tournaments
        return 9 if hand.gametype['type'] == 'ring' else 10

    def compilePlayerRegexs(self, hand):
        players = set([player[1] for player in hand.players])
        if not players <= self.compiledPlayers:  # x <= y means 'x is subset of y'

            self.compiledPlayers = players
            player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
            subst = {
                'PLYR':
                player_re,
                'CUR_SYM':
                self.sym[hand.gametype['currency']],
                'CUR':
                hand.gametype['currency']
                if hand.gametype['currency'] != 'T$' else ''
            }
            self.re_PostSB = re.compile(
                r"^%(PLYR)s posts small blind \[%(CUR_SYM)s(?P<SB>[.,0-9]+) ?%(CUR)s\]\."
                % subst, re.MULTILINE)
            self.re_PostBB = re.compile(
                u"%(PLYR)s posts big blind \[%(CUR_SYM)s(?P<BB>[.,0-9]+) ?%(CUR)s\]\."
                % subst, re.MULTILINE)
            self.re_PostDead = re.compile(
                r"^%(PLYR)s posts big blind + dead \[(?P<BBNDEAD>[.,0-9]+) ?%(CUR_SYM)s\]\."
                % subst, re.MULTILINE)
            self.re_Antes = re.compile(
                r"^%(PLYR)s posts ante \[%(CUR_SYM)s(?P<ANTE>[.,0-9]+) ?%(CUR)s\]"
                % subst, re.MULTILINE)
            self.re_HeroCards = re.compile(
                r"^Dealt to %(PLYR)s \[\s*(?P<NEWCARDS>.+)\s*\]" % subst,
                re.MULTILINE)
            self.re_Action = re.compile(
                u"""
                ^%(PLYR)s\s+(?P<ATYPE>bets|checks|raises|calls|folds|is\sall-In)
                (?:\s+\[%(CUR_SYM)s(?P<BET>[.,\d]+)\s*%(CUR)s\])?
                """ % subst, re.MULTILINE | re.VERBOSE)
            self.re_ShownCards = re.compile(
                r"^%s (?P<SHOWED>(?:doesn\'t )?shows?) " % player_re +
                r"\[ *(?P<CARDS>.+) *\](?P<COMBINATION>.+)\.", re.MULTILINE)
            self.re_CollectPot = re.compile(
                r"""^%(PLYR)s \s+ wins \s+
                %(CUR_SYM)s(?P<POT>[.,\d]+)\s*%(CUR)s""" % subst,
                re.MULTILINE | re.VERBOSE)

    def readSupportedGames(self):
        return [
            ["ring", "hold", "nl"],
            ["ring", "hold", "pl"],
            ["ring", "hold", "fl"],
            ["tour", "hold", "nl"],
            ["tour", "hold", "pl"],
            ["tour", "hold", "fl"],
        ]

    def _getGameType(self, handText):
        if not hasattr(self, '_gameType'):
            self._gameType = None
        if self._gameType is None:
            # let's determine whether hand is trny
            # and whether 5-th line contains head line
            headLine = handText.split(self.lineSplitter)[4]
            for headLineContainer in headLine, handText:
                for regexp in self.re_GameInfoTrny, self.re_GameInfoRing:
                    m = regexp.search(headLineContainer)
                    if m is not None:
                        self._gameType = m
                        return self._gameType
        return self._gameType

    def determineGameType(self, handText):
        """inspect the handText and return the gametype dict

        gametype dict is:
        {'limitType': xxx, 'base': xxx, 'category': xxx}"""

        info = {}
        m = self._getGameType(handText)
        m_20BBmin = self.re_20BBmin.search(handText)
        if m is None:
            tmp = handText[0:100]
            log.error(_("Unable to recognise gametype from: '%s'") % tmp)
            log.error("determineGameType: " + _("Raising FpdbParseError"))
            raise FpdbParseError(
                _("Unable to recognise gametype from: '%s'") % tmp)

        mg = m.groupdict()
        # translations from captured groups to fpdb info strings
        limits = {'NL': 'nl', 'PL': 'pl', '': 'fl'}
        games = {                          # base, category
                         "Texas Hold'em" : ('hold','holdem'),
                                'Omaha' : ('hold','omahahi'),
                     "7 Card Stud Hi-Lo" : ('stud','studhi'),
               }

        for expectedField in ['LIMIT', 'GAME']:
            if mg[expectedField] is None:
                raise FpdbParseError(
                    _("Cannot fetch field '%s'") % expectedField)
        try:
            info['limitType'] = limits[mg['LIMIT'].strip()]
        except:
            raise FpdbParseError(_("Unknown limit '%s'") % mg['LIMIT'])

        try:
            (info['base'], info['category']) = games[mg['GAME']]
        except:
            raise FpdbParseError(_("Unknown game type '%s'") % mg['GAME'])

        if 'TOURNO' in mg:
            info['type'] = 'tour'
        else:
            info['type'] = 'ring'

        if info['type'] == 'ring':
            if m_20BBmin is None:
                bb = float(mg['RINGLIMIT']) / 100.0
            else:
                bb = float(mg['RINGLIMIT']) / 40.0

            if bb == 0.25:
                sb = 0.10
            else:
                sb = bb / 2.0

            info['bb'] = "%.2f" % (bb)
            info['sb'] = "%.2f" % (sb)
            info['currency'] = self.currencies[mg['CURRENCY']]
        else:
            info['sb'] = self.clearMoneyString(mg['SB'])
            info['bb'] = self.clearMoneyString(mg['BB'])
            info['currency'] = 'T$'

        return info

    def readHandInfo(self, hand):
        info = {}
        try:
            info.update(self.re_Hid.search(hand.handText).groupdict())
        except AttributeError, e:
            raise FpdbParseError(_("Cannot read HID for current hand: %s") % e)

        try:
            info.update(
                self.re_HandInfo.search(hand.handText, re.DOTALL).groupdict())
        except:
            raise FpdbParseError(_("Cannot read Handinfo for current hand"),
                                 hid=info['HID'])

        try:
            info.update(self._getGameType(hand.handText).groupdict())
        except:
            raise FpdbParseError(_("Cannot read GameType for current hand"),
                                 hid=info['HID'])

        m = self.re_CountedSeats.search(hand.handText)
        if m: info.update(m.groupdict())

        # FIXME: it's dirty hack
        # party doesnt subtract uncalled money from commited money
        # so hand.totalPot calculation has to be redefined
        from Hand import Pot, HoldemOmahaHand

        def getNewTotalPot(origTotalPot):
            def totalPot(self):
                if self.totalpot is None:
                    self.pot.end()
                    self.totalpot = self.pot.total
                for i, v in enumerate(self.collected):
                    if v[0] in self.pot.returned:
                        self.collected[i][1] = Decimal(
                            v[1]) - self.pot.returned[v[0]]
                        self.collectees[v[0]] -= self.pot.returned[v[0]]
                        self.pot.returned[v[0]] = 0
                return origTotalPot()

            return totalPot

        instancemethod = type(hand.totalPot)
        hand.totalPot = instancemethod(getNewTotalPot(hand.totalPot), hand,
                                       HoldemOmahaHand)

        log.debug("readHandInfo: %s" % info)
        for key in info:
            if key == 'DATETIME':
                #Saturday, July 25, 07:53:52 EDT 2009
                #Thursday, July 30, 21:40:41 MSKS 2009
                #Sunday, October 25, 13:39:07 MSK 2009
                m2 = re.search(
                    r"\w+,\s+(?P<M>\w+)\s+(?P<D>\d+),\s+(?P<H>\d+):(?P<MIN>\d+):(?P<S>\d+)\s+(?P<TZ>[A-Z]+)\s+(?P<Y>\d+)",
                    info[key], re.UNICODE)
                months = [
                    'January', 'February', 'March', 'April', 'May', 'June',
                    'July', 'August', 'September', 'October', 'November',
                    'December'
                ]
                if m2.group('M') not in months:
                    raise FpdbParseError("Only english hh is supported",
                                         hid=info["HID"])
                month = months.index(m2.group('M')) + 1
                datetimestr = "%s/%s/%s %s:%s:%s" % (
                    m2.group('Y'), month, m2.group('D'), m2.group('H'),
                    m2.group('MIN'), m2.group('S'))
                hand.startTime = datetime.datetime.strptime(
                    datetimestr, "%Y/%m/%d %H:%M:%S")
                # FIXME: some timezone correction required
                #tzShift = defaultdict(lambda:0, {'EDT': -5, 'EST': -6, 'MSKS': 3})
                #hand.starttime -= datetime.timedelta(hours=tzShift[m2.group('TZ')])

            if key == 'HID':
                hand.handid = info[key]
            if key == 'TABLE':
                hand.tablename = info[key]
            if key == 'MTTTABLE':
                if info[key] != None:
                    hand.tablename = info[key]
                    hand.tourNo = info['TABLE']
            if key == 'BUTTON':
                hand.buttonpos = info[key]
            if key == 'TOURNO':
                hand.tourNo = info[key]
            if key == 'TABLE_ID_WRAPPER':
                if info[key] == '#':
                    # FIXME: there is no such property in Hand class
                    self.isSNG = True
            if key == 'BUYIN':
                if info[key] == None:
                    # Freeroll tourney
                    hand.buyin = 0
                    hand.fee = 0
                    hand.buyinCurrency = "FREE"
                    hand.isKO = False
                elif hand.tourNo != None:
                    hand.buyin = 0
                    hand.fee = 0
                    hand.buyinCurrency = "FREE"
                    hand.isKO = False
                    if info[key].find("$") != -1:
                        hand.buyinCurrency = "USD"
                    elif info[key].find(u"€") != -1:
                        hand.buyinCurrency = "EUR"
                    else:
                        raise FpdbParseError(
                            _("Failed to detect currency.") + " " +
                            _("Hand ID: %s: '%s'") % (hand.handid, info[key]))
                    info[key] = info[key].strip(u'$€')
                    hand.buyin = int(100 * Decimal(info[key]))
            if key == 'LEVEL':
                hand.level = info[key]
            if key == 'PLAY' and info['PLAY'] != 'Real':
                # if realy party doesn's save play money hh
                hand.gametype['currency'] = 'play'
            if key == 'MAX' and info[key] is not None:
                hand.maxseats = int(info[key])
 def readHandInfo(self, hand):
     info = {}
     try:
         info.update(self.re_Hid.search(hand.handText).groupdict())
     except AttributeError, e:
         raise FpdbParseError(_("Cannot read HID for current hand: %s") % e)
    def determineGameType(self, handText):
        """inspect the handText and return the gametype dict

        gametype dict is:
        {'limitType': xxx, 'base': xxx, 'category': xxx}"""

        info = {}
        m = self._getGameType(handText)
        m_20BBmin = self.re_20BBmin.search(handText)
        if m is None:
            tmp = handText[0:100]
            log.error(_("Unable to recognise gametype from: '%s'") % tmp)
            log.error("determineGameType: " + _("Raising FpdbParseError"))
            raise FpdbParseError(
                _("Unable to recognise gametype from: '%s'") % tmp)

        mg = m.groupdict()
        # translations from captured groups to fpdb info strings
        limits = {'NL': 'nl', 'PL': 'pl', '': 'fl'}
        games = {                          # base, category
                         "Texas Hold'em" : ('hold','holdem'),
                                'Omaha' : ('hold','omahahi'),
                     "7 Card Stud Hi-Lo" : ('stud','studhi'),
               }

        for expectedField in ['LIMIT', 'GAME']:
            if mg[expectedField] is None:
                raise FpdbParseError(
                    _("Cannot fetch field '%s'") % expectedField)
        try:
            info['limitType'] = limits[mg['LIMIT'].strip()]
        except:
            raise FpdbParseError(_("Unknown limit '%s'") % mg['LIMIT'])

        try:
            (info['base'], info['category']) = games[mg['GAME']]
        except:
            raise FpdbParseError(_("Unknown game type '%s'") % mg['GAME'])

        if 'TOURNO' in mg:
            info['type'] = 'tour'
        else:
            info['type'] = 'ring'

        if info['type'] == 'ring':
            if m_20BBmin is None:
                bb = float(mg['RINGLIMIT']) / 100.0
            else:
                bb = float(mg['RINGLIMIT']) / 40.0

            if bb == 0.25:
                sb = 0.10
            else:
                sb = bb / 2.0

            info['bb'] = "%.2f" % (bb)
            info['sb'] = "%.2f" % (sb)
            info['currency'] = self.currencies[mg['CURRENCY']]
        else:
            info['sb'] = self.clearMoneyString(mg['SB'])
            info['bb'] = self.clearMoneyString(mg['BB'])
            info['currency'] = 'T$'

        return info