2 # -*- coding: utf-8 -*-
4 # Copyright 2010-2011, Carl Gherardi
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 ########################################################################
23 _
= L10n
.get_translation()
27 from HandHistoryConverter
import *
28 from decimal_wrapper
import Decimal
31 class Everest(HandHistoryConverter
):
39 'LS' : u
"\$|\xe2\x82\xac|\u20ac|",
40 'TAB' : u
"-\u2013'\s\da-zA-Z",
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
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
)
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
):
77 def playerNameFromSeatNo(self
, seatNo
, hand
):
78 # Actions recorded by seat number, not by the player's name
79 for p
in hand
.players
:
83 def readSupportedGames(self
):
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
)
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
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
)
108 tmp
= handText
[0:100]
109 log
.error("determineGameType: " + _("Raising FpdbParseError"))
110 raise FpdbParseError(_("Unable to recognise hand info from: '%s'") % tmp
)
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'),
125 self
.info
['limitType'] = limits
[mg
['LIMIT']]
127 (self
.info
['base'], self
.info
['category']) = games
[mg
['GAME']]
129 sb
= mg
['SB'].replace(',','.')
132 bb
= mg
['BB'].replace(',','.')
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
146 def readHandInfo(self
, hand
):
147 m
= self
.re_HandInfo
.search(hand
.handText
)
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']
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
)
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
)
172 #pp = pprint.PrettyPrinter(indent=4)
173 #pp.pprint(m.groupdict())
176 def readCommunityCards(self
, hand
, street
):
177 m
= self
.re_Board
.search(hand
.streets
[street
])
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
):
186 def readBringIn(self
, hand
):
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
)
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')
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:
223 hand
.addBet(street
, player
, amountstr
)
224 elif Decimal(action
.group('BET')) > 0 and curr_pot
> 0:
226 if amount
> curr_pot
:
229 hand
.addCallandRaise(street
, player
, amountstr
)
230 elif amount
<= curr_pot
:
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
)
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'),
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
))