Carbon Poker offers a 5 card stud game that wasn't listed here. It's not available...
[fpdb-dooglus.git] / pyfpdb / EverestToFpdb.py
blobae6e775ff4eab0812bc5fe506beeed818492969e
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
4 # Copyright 2010-2011, Carl Gherardi
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 ########################################################################
22 import L10n
23 _ = L10n.get_translation()
25 import sys
26 import logging
27 from HandHistoryConverter import *
28 from decimal_wrapper import Decimal
31 class Everest(HandHistoryConverter):
32 sitename = "Everest"
33 filetype = "text"
34 codepage = "utf8"
35 siteId = 16
36 copyGameHeader = True
38 substitutions = {
39 'LS' : u"\$|\xe2\x82\xac|\u20ac|",
40 'TAB' : u"-\u2013'\s\da-zA-Z",
41 'NUM' : u"\d,\.",
44 # Static regexes
45 re_SplitHands = re.compile(r'</HAND>\n+(?=<HAND)')
46 re_TailSplitHands = re.compile(r'(</game>)')
47 re_GameInfo = re.compile(u"""<SESSION\stime="\d+"\s
48 tableName="(?P<TABLE>[%(TAB)s]+)"\s
49 id="[\d\.]+"\s
50 type="(?P<TYPE>[a-zA-Z ]+)"\s
51 money="(?P<CURRENCY>[%(LS)s])"\s
52 screenName="[a-zA-Z]+"\s
53 game="(?P<GAME>[-a-zA-Z ]+)"\s
54 gametype="(?P<LIMIT>[-a-zA-Z ]+)"/>
55 """ % substitutions, re.VERBOSE|re.MULTILINE)
56 re_HandInfo = re.compile(r'<HAND time="(?P<DATETIME>[0-9]+)" id="(?P<HID>[0-9]+)" index="\d+" blinds="((?P<SB>[%(NUM)s]+) (?P<CURRENCY>[%(LS)s])/(?P<BB>[%(NUM)s]+))' % substitutions, re.MULTILINE)
57 re_Button = re.compile(r'<DEALER position="(?P<BUTTON>[0-9]+)"\/>')
58 re_PlayerInfo = re.compile(r'<SEAT position="(?P<SEAT>[0-9]+)" name="(?P<PNAME>.+)" balance="(?P<CASH>[.0-9]+)"/>', re.MULTILINE)
59 re_Board = re.compile(r'(?P<CARDS>.+)<\/COMMUNITY>', re.MULTILINE)
61 # The following are also static regexes: there is no need to call
62 # compilePlayerRegexes (which does nothing), since players are identified
63 # not by name but by seat number
64 re_PostXB = re.compile(r'<BLIND position="(?P<PSEAT>[0-9]+)" amount="(?P<XB>[0-9]+)" penalty="(?P<PENALTY>[0-9]+)"\/>', re.MULTILINE)
65 #re_Antes = ???
66 #re_BringIn = ???
67 re_HeroCards = re.compile(r'<cards type="HOLE" cards="(?P<CARDS>.+)" player="(?P<PSEAT>[0-9])"', re.MULTILINE)
68 re_Action = re.compile(r'<(?P<ATYPE>FOLD|BET) position="(?P<PSEAT>[0-9])"( amount="(?P<BET>[.0-9]+)")?\/>', re.MULTILINE)
69 re_ShowdownAction = re.compile(r'<cards type="SHOWN" cards="(?P<CARDS>..,..)" player="(?P<PSEAT>[0-9])"/>', re.MULTILINE)
70 re_CollectPot = re.compile(r'<WIN position="(?P<PSEAT>[0-9])" amount="(?P<POT>[.0-9]+)" pot="[0-9]+"', re.MULTILINE)
71 re_SitsOut = re.compile(r'<event sequence="[0-9]+" type="SIT_OUT" player="(?P<PSEAT>[0-9])"/>', re.MULTILINE)
72 re_ShownCards = re.compile(r'<cards type="(SHOWN|MUCKED)" cards="(?P<CARDS>..,..)" player="(?P<PSEAT>[0-9])"/>', re.MULTILINE)
74 def compilePlayerRegexs(self, hand):
75 pass
77 def playerNameFromSeatNo(self, seatNo, hand):
78 # Actions recorded by seat number, not by the player's name
79 for p in hand.players:
80 if p[0] == seatNo:
81 return p[1]
83 def readSupportedGames(self):
84 return [
85 ["ring", "hold", "nl"],
86 ["ring", "hold", "pl"],
87 #["tour", "hold", "nl"]
90 def determineGameType(self, handText):
91 m = self.re_GameInfo.search(handText)
92 m2 = self.re_HandInfo.search(handText)
93 if not m:
94 # Information about the game type appears only at the beginning of
95 # a hand history file; hence it is not supplied with the second
96 # and subsequent hands. In these cases we use the value previously
97 # stored.
98 try:
99 self.info
100 return self.info
101 except AttributeError:
102 tmp = handText[0:100]
103 log.error(_("Unable to recognise gametype from: '%s'") % tmp)
104 log.error("determineGameType: " + _("Raising FpdbParseError"))
105 raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
107 if not m2:
108 tmp = handText[0:100]
109 log.error("determineGameType: " + _("Raising FpdbParseError"))
110 raise FpdbParseError(_("Unable to recognise hand info from: '%s'") % tmp)
112 self.info = {}
113 mg = m.groupdict()
114 mg.update(m2.groupdict())
115 #print "DEBUG: mg: %s" % mg
117 limits = { 'no-limit':'nl', 'limit':'fl', 'pot-limit':'pl' }
118 games = { # base, category
119 'hold-em' : ('hold','holdem'),
120 'Holdem Tournament' : ('hold','holdem'),
121 'omaha-hi' : ('hold','omahahi'),
124 if 'LIMIT' in mg:
125 self.info['limitType'] = limits[mg['LIMIT']]
126 if 'GAME' in mg:
127 (self.info['base'], self.info['category']) = games[mg['GAME']]
128 if 'SB' in mg:
129 sb = mg['SB'].replace(',','.')
130 self.info['sb'] = sb
131 if 'BB' in mg:
132 bb = mg['BB'].replace(',','.')
133 self.info['bb'] = bb
135 self.info['type'] = 'ring'
136 if mg['CURRENCY'] == u'\u20ac':
137 self.info['currency'] = 'EUR'
139 # HACK - tablename not in every hand.
140 self.info['TABLENAME'] = mg['TABLE']
142 #print "DEBUG: self.info: %s" % self.info
144 return self.info
146 def readHandInfo(self, hand):
147 m = self.re_HandInfo.search(hand.handText)
148 if m is None:
149 logging.info(_("No match in readHandInfo: '%s'") % hand.handText[0:100])
150 logging.info(hand.handText)
151 raise FpdbParseError(_("No match in readHandInfo: '%s'") % hand.handText[0:100])
152 hand.handid = m.group('HID')
153 hand.tablename = self.info['TABLENAME']
154 hand.maxseats = None
155 #FIXME: u'DATETIME': u'1291155932'
156 hand.startTime = datetime.datetime.strptime('201102091158', '%Y%m%d%H%M')
157 #hand.startTime = datetime.datetime.strptime(m.group('DATETIME')[:12], '%Y%m%d%H%M')
159 def readPlayerStacks(self, hand):
160 m = self.re_PlayerInfo.finditer(hand.handText)
161 for a in m:
162 hand.addPlayer(a.group('SEAT'), a.group('PNAME'), a.group('CASH'))
164 def markStreets(self, hand):
165 #if hand.gametype['base'] == 'hold':
167 m = re.search(r"<DEALER (?P<PREFLOP>.+?(?=<COMMUNITY>)|.+)"
168 r"(<COMMUNITY>(?P<FLOP>\S\S, \S\S, \S\S<\/COMMUNITY>.+?(?=<COMMUNITY>)|.+))?"
169 r"(<COMMUNITY>(?P<TURN>\S\S<\/COMMUNITY>.+?(?=<COMMUNITY>)|.+))?"
170 r"(<COMMUNITY>(?P<RIVER>\S\S<\/COMMUNITY>.+))?", hand.handText,re.DOTALL)
171 #import pprint
172 #pp = pprint.PrettyPrinter(indent=4)
173 #pp.pprint(m.groupdict())
174 hand.addStreets(m)
176 def readCommunityCards(self, hand, street):
177 m = self.re_Board.search(hand.streets[street])
178 if street == 'FLOP':
179 hand.setCommunityCards(street, m.group('CARDS').split(','))
180 elif street in ('TURN','RIVER'):
181 hand.setCommunityCards(street, [m.group('CARDS').split(',')[-1]])
183 def readAntes(self, hand):
184 pass # ???
186 def readBringIn(self, hand):
187 pass # ???
189 def readBlinds(self, hand):
190 for a in self.re_PostXB.finditer(hand.handText):
191 amount = "%.2f" % float(float(a.group('XB'))/100)
192 #print "DEBUG: readBlinds amount: %s" % amount
193 if Decimal(a.group('XB'))/100 == Decimal(self.info['sb']):
194 hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'), hand),'small blind', amount)
195 elif Decimal(a.group('XB'))/100 == Decimal(self.info['bb']):
196 hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'), hand),'big blind', amount)
198 def readButton(self, hand):
199 hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON'))
201 def readHeroCards(self, hand):
202 m = self.re_HeroCards.search(hand.handText)
203 if m:
204 hand.hero = self.playerNameFromSeatNo(m.group('PSEAT'), hand)
205 cards = m.group('CARDS').split(',')
206 hand.addHoleCards('PREFLOP', hand.hero, closed=cards, shown=False,
207 mucked=False, dealt=True)
209 def readAction(self, hand, street):
210 #print "DEBUG: readAction (%s)" % street
211 m = self.re_Action.finditer(hand.streets[street])
212 curr_pot = Decimal('0')
213 for action in m:
214 #print " DEBUG: %s %s" % (action.group('ATYPE'), action.groupdict())
215 player = self.playerNameFromSeatNo(action.group('PSEAT'), hand)
216 if action.group('ATYPE') == 'BET':
217 amount = Decimal(action.group('BET'))
218 amountstr = "%.2f" % float(int(action.group('BET'))/100)
219 #Gah! BET can mean check, bet, call or raise...
220 if amount > 0 and curr_pot == 0:
221 # Open
222 curr_pot = amount
223 hand.addBet(street, player, amountstr)
224 elif Decimal(action.group('BET')) > 0 and curr_pot > 0:
225 # Raise or call
226 if amount > curr_pot:
227 # Raise
228 curr_pot = amount
229 hand.addCallandRaise(street, player, amountstr)
230 elif amount <= curr_pot:
231 # Call
232 hand.addCall(street, player, amountstr)
233 if action.group('BET') == '0':
234 hand.addCheck(street, player)
235 elif action.group('ATYPE') in ('FOLD', 'SIT_OUT'):
236 hand.addFold(street, player)
237 else:
238 print (_("Unimplemented %s: '%s' '%s'") % ("readAction", action.group('PSEAT'), action.group('ATYPE')))
239 logging.debug(_("Unimplemented %s: '%s' '%s'") % ("readAction", action.group('PSEAT'), action.group('ATYPE')))
241 def readShowdownActions(self, hand):
242 for shows in self.re_ShowdownAction.finditer(hand.handText):
243 cards = shows.group('CARDS').split(',')
244 hand.addShownCards(cards,
245 self.playerNameFromSeatNo(shows.group('PSEAT'),
246 hand))
248 def readCollectPot(self, hand):
249 for m in self.re_CollectPot.finditer(hand.handText):
250 player = self.playerNameFromSeatNo(m.group('PSEAT'), hand)
251 #print "DEBUG: %s collects %s" % (player, m.group('POT'))
252 hand.addCollectPot(player, str(int(m.group('POT'))/100))
254 def readShownCards(self, hand):
255 for m in self.re_ShownCards.finditer(hand.handText):
256 cards = m.group('CARDS').split(',')
257 hand.addShownCards(cards=cards, player=self.playerNameFromSeatNo(m.group('PSEAT'), hand))