diff --git a/pyfpdb/EverestToFpdb.py b/pyfpdb/EverestToFpdb.py new file mode 100644 index 00000000..dbb588be --- /dev/null +++ b/pyfpdb/EverestToFpdb.py @@ -0,0 +1,259 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2011, Carl Gherardi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +######################################################################## + +import L10n +_ = L10n.get_translation() + +import sys +import logging +from HandHistoryConverter import * +from decimal import Decimal + + +class Everest(HandHistoryConverter): + sitename = "Everest" + filetype = "text" + codepage = "utf8" + siteID = 15 + + substitutions = { + 'LS' : u"\$|\xe2\x82\xac|\u20ac|", + 'TAB' : u"-\u2013'\s\da-zA-Z", # legal characters for tablename + } + + # Static regexes + re_SplitHands = re.compile(r'\n+(?=)') + re_GameInfo = re.compile(u""" + """ % substitutions, re.VERBOSE|re.MULTILINE) + re_HandInfo = re.compile(r'[0-9]+)"\/>') + re_PlayerInfo = re.compile(r'', re.MULTILINE) + re_Board = re.compile(r'(?P.+)<\/COMMUNITY>', re.MULTILINE) + + # The following are also static regexes: there is no need to call + # compilePlayerRegexes (which does nothing), since players are identified + # not by name but by seat number + re_PostSB = re.compile(r'timestamp="[0-9]+" )?player="(?P[0-9])" amount="(?P[.0-9]+)"/>', re.MULTILINE) + re_PostBB = re.compile(r'timestamp="[0-9]+" )?player="(?P[0-9])" amount="(?P[.0-9]+)"/>', re.MULTILINE) + re_PostBoth = re.compile(r'', re.MULTILINE) + #re_Antes = ??? + #re_BringIn = ??? + re_HeroCards = re.compile(r'timestamp="[0-9]+" )?player="(?P[0-9])"( amount="(?P[.0-9]+)")?/>', re.MULTILINE) + re_ShowdownAction = re.compile(r'', re.MULTILINE) + re_CollectPot = re.compile(r'', re.MULTILINE) + re_ShownCards = re.compile(r'', re.MULTILINE) + + def compilePlayerRegexs(self, hand): + pass + + def playerNameFromSeatNo(self, seatNo, hand): + # This special function is required because Carbon Poker records + # actions by seat number, not by the player's name + for p in hand.players: + if p[0] == int(seatNo): + return p[1] + + def readSupportedGames(self): + return [ + ["ring", "hold", "nl"], + ["ring", "hold", "pl"], + #["tour", "hold", "nl"] + ] + + def determineGameType(self, handText): + m = self.re_GameInfo.search(handText) + m2 = self.re_HandInfo.search(handText) + if not m: + # Information about the game type appears only at the beginning of + # a hand history file; hence it is not supplied with the second + # and subsequent hands. In these cases we use the value previously + # stored. + try: + self.info + return self.info + except AttributeError: + tmp = handText[0:100] + log.error(_("determineGameType: Unable to recognise gametype from: '%s'") % tmp) + log.error(_("determineGameType: Raising FpdbParseError")) + raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp) + + if not m2: + tmp = handText[0:100] + raise FpdbParseError(_("Unable to recognise handinfo from: '%s'") % tmp) + + self.info = {} + mg = m.groupdict() + mg.update(m2.groupdict()) + print "DEBUG: mg: %s" % mg + + limits = { 'No Limit':'nl', 'No Limit ':'nl', 'Limit':'fl', 'pot-limit':'pl' } + games = { # base, category + 'Holdem' : ('hold','holdem'), + 'Holdem Tournament' : ('hold','holdem'), + 'omaha-hi' : ('hold','omahahi'), + } + + if 'LIMIT' in mg: + self.info['limitType'] = limits[mg['LIMIT']] + if 'GAME' in mg: + (self.info['base'], self.info['category']) = games[mg['GAME']] + if 'SB' in mg: + self.info['sb'] = mg['SB'] + if 'BB' in mg: + self.info['bb'] = mg['BB'] + + self.info['type'] = 'ring' + if mg['CURRENCY'] == u'\u20ac': + self.info['currency'] = 'EUR' + + # HACK - tablename not in every hand. + self.info['TABLENAME'] = mg['TABLE'] + + print "DEBUG: self.info: %s" % self.info + + return self.info + + def readHandInfo(self, hand): + m = self.re_HandInfo.search(hand.handText) + if m is None: + logging.info(_("Didn't match re_HandInfo")) + logging.info(hand.handText) + raise FpdbParseError(_("No match in readHandInfo.")) + hand.handid = m.group('HID') + hand.tablename = self.info['TABLENAME'] + hand.maxseats = None + #FIXME: u'DATETIME': u'1291155932' + hand.startTime = datetime.datetime.strptime('201102091158', '%Y%m%d%H%M') + #hand.startTime = datetime.datetime.strptime(m.group('DATETIME')[:12], '%Y%m%d%H%M') + + def readPlayerStacks(self, hand): + m = self.re_PlayerInfo.finditer(hand.handText) + for a in m: + print "DEBUG: adding %s %s %s" % (a.group('SEAT'), a.group('PNAME'), a.group('CASH')) + hand.addPlayer(a.group('SEAT'), a.group('PNAME'), a.group('CASH')) + + def markStreets(self, hand): + #if hand.gametype['base'] == 'hold': + + m = re.search(r".+?(?=)|.+)" + r"((?P\S\S, \S\S, \S\S<\/COMMUNITY>.+?(?=)|.+))?" + r"((?P\S\S<\/COMMUNITY>.+?(?=)|.+))?" + r"((?P\S\S<\/COMMUNITY>.+))?", hand.handText,re.DOTALL) + #import pprint + #pp = pprint.PrettyPrinter(indent=4) + #pp.pprint(m.groupdict()) + hand.addStreets(m) + + def readCommunityCards(self, hand, street): + m = self.re_Board.search(hand.streets[street]) + print "DEBUG: hand.streets[street]: %s" % hand.streets[street] + if street == 'FLOP': + hand.setCommunityCards(street, m.group('CARDS').split(',')) + elif street in ('TURN','RIVER'): + hand.setCommunityCards(street, [m.group('CARDS').split(',')[-1]]) + + def readAntes(self, hand): + pass # ??? + + def readBringIn(self, hand): + pass # ??? + + def readBlinds(self, hand): + for a in self.re_PostSB.finditer(hand.handText): + #print "DEBUG: found sb: '%s' '%s'" %(self.playerNameFromSeatNo(a.group('PSEAT'), hand), a.group('SB')) + hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'), hand),'small blind', a.group('SB')) + + for a in self.re_PostBB.finditer(hand.handText): + #print "DEBUG: found bb: '%s' '%s'" %(self.playerNameFromSeatNo(a.group('PSEAT'), hand), a.group('BB')) + hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'), hand), 'big blind', a.group('BB')) + for a in self.re_PostBoth.finditer(hand.handText): + bb = Decimal(self.info['bb']) + amount = Decimal(a.group('SBBB')) + if amount < bb: + hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'), + hand), 'small blind', a.group('SBBB')) + elif amount == bb: + hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'), + hand), 'big blind', a.group('SBBB')) + else: + hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'), + hand), 'both', a.group('SBBB')) + + def readButton(self, hand): + hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON')) + + def readHeroCards(self, hand): + m = self.re_HeroCards.search(hand.handText) + if m: + hand.hero = self.playerNameFromSeatNo(m.group('PSEAT'), hand) + cards = m.group('CARDS').split(',') + hand.addHoleCards('PREFLOP', hand.hero, closed=cards, shown=False, + mucked=False, dealt=True) + + def readAction(self, hand, street): + logging.debug("readAction (%s)" % street) + m = self.re_Action.finditer(hand.streets[street]) + for action in m: + logging.debug("%s %s" % (action.group('ATYPE'), + action.groupdict())) + player = self.playerNameFromSeatNo(action.group('PSEAT'), hand) + if action.group('ATYPE') == 'RAISE': + hand.addCallandRaise(street, player, action.group('BET')) + elif action.group('ATYPE') == 'CALL': + hand.addCall(street, player, action.group('BET')) + elif action.group('ATYPE') == 'BET': + hand.addBet(street, player, action.group('BET')) + elif action.group('ATYPE') in ('FOLD', 'SIT_OUT'): + hand.addFold(street, player) + elif action.group('ATYPE') == 'CHECK': + hand.addCheck(street, player) + elif action.group('ATYPE') == 'ALL_IN': + hand.addAllIn(street, player, action.group('BET')) + else: + logging.debug(_("Unimplemented readAction: %s %s" + % (action.group('PSEAT'),action.group('ATYPE'),))) + + def readShowdownActions(self, hand): + for shows in self.re_ShowdownAction.finditer(hand.handText): + cards = shows.group('CARDS').split(',') + hand.addShownCards(cards, + self.playerNameFromSeatNo(shows.group('PSEAT'), + hand)) + + def readCollectPot(self, hand): + for m in self.re_CollectPot.finditer(hand.handText): + pots[int(m.group('PSEAT'))] += Decimal(m.group('POT')) + + def readShownCards(self, hand): + for m in self.re_ShownCards.finditer(hand.handText): + cards = m.group('CARDS').split(',') + hand.addShownCards(cards=cards, player=self.playerNameFromSeatNo(m.group('PSEAT'), hand)) +