Coverage for UnibetToFpdb.py: 0%
332 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-27 18:50 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-27 18:50 +0000
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Copyright 2008-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.
10#
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.
15#
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
19########################################################################
21#import L10n
22#_ = L10n.get_translation()
24# TODO: straighten out discards for draw games
26import sys
27from HandHistoryConverter import *
28from decimal_wrapper import Decimal
30# Unibet HH Format
32class Unibet(HandHistoryConverter):
34 # Class Variables
36 sitename = "Unibet"
37 filetype = "text"
38 codepage = ("utf8", "cp1252", "ISO-8859-1")
39 siteId = 30 # Needs to match id entry in Sites database
40 sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "\xe2\x82\xac", "GBP": "\£", "play": "", "INR": "\₹", "CNY": "\¥"} # ADD Euro, Sterling, etc HERE
41 substitutions = {
42 'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP|SC|INR|CNY", # legal ISO currency codes
43 'LS' : u"\$|\xe2\x82\xac|\u20ac|\£|\u20b9|\¥|", # legal currency symbols - Euro(cp1252, utf-8)
44 'PLYR': r'\s?(?P<PNAME>.+?)',
45 'CUR': u"(\$|\xe2\x82\xac|\u20ac||\£|\u20b9|\¥|)",
46 'BRKTS': r'(\(button\) |\(small blind\) |\(big blind\) |\(button blind\) |\(button\) \(small blind\) |\(small blind/button\) |\(button\) \(big blind\) )?',
47 }
49 # translations from captured groups to fpdb info strings
50 Lim_Blinds = { '0.04': ('0.01', '0.02'), '0.08': ('0.02', '0.04'),
51 '0.10': ('0.02', '0.05'), '0.20': ('0.05', '0.10'),
52 '0.40': ('0.10', '0.20'), '0.50': ('0.10', '0.25'),
53 '1.00': ('0.25', '0.50'), '1': ('0.25', '0.50'),
54 '2.00': ('0.50', '1.00'), '2': ('0.50', '1.00'),
55 '4.00': ('1.00', '2.00'), '4': ('1.00', '2.00'),
56 '6.00': ('1.00', '3.00'), '6': ('1.00', '3.00'),
57 '8.00': ('2.00', '4.00'), '8': ('2.00', '4.00'),
58 '10.00': ('2.00', '5.00'), '10': ('2.00', '5.00'),
59 '16.00': ('4.00', '8.00'), '16': ('4.00', '8.00'),
60 '20.00': ('5.00', '10.00'), '20': ('5.00', '10.00'),
61 '30.00': ('10.00', '15.00'), '30': ('10.00', '15.00'),
62 '40.00': ('10.00', '20.00'), '40': ('10.00', '20.00'),
63 '50.00': ('10.00', '25.00'), '50': ('10.00', '25.00'),
64 '60.00': ('15.00', '30.00'), '60': ('15.00', '30.00'),
65 '80.00': ('20.00', '40.00'), '80': ('20.00', '40.00'),
66 '100.00': ('25.00', '50.00'), '100': ('25.00', '50.00'),
67 '150.00': ('50.00', '75.00'), '150': ('50.00', '75.00'),
68 '200.00': ('50.00', '100.00'), '200': ('50.00', '100.00'),
69 '400.00': ('100.00', '200.00'), '400': ('100.00', '200.00'),
70 '500.00': ('100.00', '250.00'), '500': ('100.00', '250.00'),
71 '600.00': ('150.00', '300.00'), '600': ('150.00', '300.00'),
72 '800.00': ('200.00', '400.00'), '800': ('200.00', '400.00'),
73 '1000.00': ('250.00', '500.00'), '1000': ('250.00', '500.00'),
74 '2000.00': ('500.00', '1000.00'), '2000': ('500.00', '1000.00'),
75 '4000.00': ('1000.00', '2000.00'), '4000': ('1000.00', '2000.00'),
76 '10000.00': ('2500.00', '5000.00'), '10000': ('2500.00', '5000.00'),
77 '20000.00': ('5000.00', '10000.00'),'20000': ('5000.00', '10000.00'),
78 '40000.00': ('10000.00', '20000.00'),'40000': ('10000.00', '20000.00'),
79 }
81 limits = {
82 'No Limit':'nl',
83 'Pot Limit':'pl',
84 'Fixed Limit':'fl',
85 'Limit':'fl'
86 }
87 games = { # base, category
88 "Hold'em" : ('hold','holdem'),
89 'Omaha' : ('hold','omahahi'),
90 'Omaha Hi/Lo' : ('hold','omahahilo')
91 }
92 currencies = { u'€':'EUR', '$':'USD', '':'T$', u'£':'GBP', u'¥':'CNY', u'₹':'INR'}
94 # Static regexes
95 re_GameInfo = re.compile(u"""
96 Game\s\#(?P<HID>[0-9]+):\s+Table\s(?P<CURRENCY>€|$|£)[0-9]+\s(?P<LIMIT>PL|NL|FL)\s-\s(?P<SB>[.0-9]+)/(?P<BB>[.0-9]+)\s-\s(?P<GAME>Pot\sLimit\sOmaha|No\sLimit\sHold\'Em\sBanzai)\s-\s(?P<DATETIME>.*$)
97 """ % substitutions, re.MULTILINE|re.VERBOSE)
99 re_PlayerInfo = re.compile(u"""
100 Seat\s(?P<SEAT>[0-9]+):\s(?P<PNAME>\w+)\s\((€|$|£)(?P<CASH>[,.0-9]+)\)""" % substitutions,
101 re.MULTILINE|re.VERBOSE)
103 re_PlayerInfo2 = re.compile(u"""
104 (?P<SITOUT>\w+)\s\((€|$|£)[,.0-9]+\)\s\(sitting\sout\)""" % substitutions,
105 re.MULTILINE|re.VERBOSE)
107 re_HandInfo = re.compile("""
108 (?P<TABLE>\sTable\s(€|$|£)[0-9]+\s(PL|NL|FL))""",
109 re.MULTILINE|re.VERBOSE)
111 re_Identify = re.compile(u'Game\s\#\d+:\sTable\s(€|$|£)[0-9]+\s(PL|NL|FL)')
112 re_SplitHands = re.compile('(?:\s?\n){2,}')
113 re_TailSplitHands = re.compile('(\n\n\n+)')
114 re_Button = re.compile('(?P<BUTTON>\w+)\shas\sthe\sbutton', re.MULTILINE)
115 re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
116 re_Board2 = re.compile(r"\[(?P<C1>\S\S)\] \[(\S\S)?(?P<C2>\S\S) (?P<C3>\S\S)\]")
117 re_DateTime1 = re.compile("""(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)\s(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})""", re.MULTILINE)
118 re_DateTime2 = re.compile("""(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+)""", re.MULTILINE)
119 # revised re including timezone (not currently used):
120 #re_DateTime = re.compile("""(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+) \(?(?P<TZ>[A-Z0-9]+)""", re.MULTILINE)
122 # These used to be compiled per player, but regression tests say
123 # we don't have to, and it makes life faster.
124 re_PostSB = re.compile(r"%(PLYR)s:\sposts\ssmall\sblind\s%(CUR)s(?P<SB>[,.0-9]+)" % substitutions, re.MULTILINE)
125 re_PostBB = re.compile(r"%(PLYR)s:\sposts\sbig\sblind\s%(CUR)s(?P<BB>[,.0-9]+)" % substitutions, re.MULTILINE)
126 re_PostBUB = re.compile(r"%(PLYR)s:\sposts\sbutton\sblind\s%(CUR)s(?P<BUB>[,.0-9]+)" % substitutions, re.MULTILINE)
127 re_Antes = re.compile(r"%(PLYR)s:\sposts\sthe\sant\s%(CUR)s(?P<ANTE>[,.0-9]+)" % substitutions, re.MULTILINE)
128 re_BringIn = re.compile(r"%(PLYR)s:\sbrings[- ]in(\slow|)\sfo/%(CUR)s(?P<BRINGIN>[,.0-9]+)" % substitutions, re.MULTILINE)
129 re_PostBoth = re.compile(r"%(PLYR)s:\sposts\ssmall\s\&\sbig\sblinds\s%(CUR)s(?P<SBBB>[,.0-9]+)" % substitutions, re.MULTILINE)
130 re_PostStraddle = re.compile(r"%(PLYR)s:\sposts\sstraddle\s%(CUR)s(?P<STRADDLE>[,.0-9]+)" % substitutions, re.MULTILINE)
131 re_Action = re.compile(r"""
132 %(PLYR)s:(?P<ATYPE>\sbets|\schecks|\sraises|\scalls|\sfolds|\sdiscards|\sstands\spat)
133 (\s%(CUR)s(?P<BET>[,.\d]+))?(\sto\s%(CUR)s(?P<BETTO>[,.\d]+))?
134 \s*(and\sis\sall.in)?
135 (and\shas\sreached\sthe\s[%(CUR)s\d\.,]+\scap)?
136 (\son|\scards?)?
137 (\s\(disconnect\))?
138 (\s\[(?P<CARDS>.+?)\])?\s*$"""
139 % substitutions, re.MULTILINE|re.VERBOSE)
140 re_ShowdownAction = re.compile(r"%s: shows \[(?P<CARDS>.*)\]" % substitutions['PLYR'], re.MULTILINE)
141 re_sitsOut = re.compile("^%s sits out" % substitutions['PLYR'], re.MULTILINE)
142 re_HeroCards = re.compile(r"Dealt\sto\s%(PLYR)s\s(?:\[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % substitutions, re.MULTILINE)
143 #re_ShownCards = re.compile("^Seat (?P<SEAT>[0-9]+): %(PLYR)s %(BRKTS)s(?P<SHOWED>showed|mucked) \[(?P<CARDS>.*)\]( and (lost|(won|collected) \(%(CUR)s(?P<POT>[.\d]+)\)) with (?P<STRING>.+?)(,\sand\s(won\s\(%(CUR)s[.\d]+\)|lost)\swith\s(?P<STRING2>.*))?)?$" % substitutions, re.MULTILINE)
144 #re_CollectPot = re.compile(r"Seat (?P<SEAT>[0-9]+): %(PLYR)s %(BRKTS)s(collected|showed \[.*\] and (won|collected)) \(?%(CUR)s(?P<POT>[,.\d]+)\)?(, mucked| with.*|)" % substitutions, re.MULTILINE)
145 re_CollectPot = re.compile(r"Seat (?P<SEAT>[0-9]+):\s%(PLYR)s:\sbet\s(€|$|£)(?P<BET>[,.\d]+)\sand\swon\s(€|$|£)[\.0-9]+\W\snet\sresult:\s(€|$|£)(?P<POT>[,.\d]+)" % substitutions, re.MULTILINE)
146 #Vinsand88 cashed out the hand for $2.19 | Cash Out Fee $0.02
147 re_CollectPot2 = re.compile(u"%(PLYR)s (collected|cashed out the hand for) %(CUR)s(?P<POT>[,.\d]+)" % substitutions, re.MULTILINE)
148 re_CashedOut = re.compile(r"cashed\sout\sthe\shand")
149 re_WinningRankOne = re.compile(u"%(PLYR)s wins the tournament and receives %(CUR)s(?P<AMT>[,\.0-9]+) - congratulations!$" % substitutions, re.MULTILINE)
150 re_WinningRankOther = re.compile(u"%(PLYR)s finished the tournament in (?P<RANK>[0-9]+)(st|nd|rd|th) place and received %(CUR)s(?P<AMT>[,.0-9]+)\.$" % substitutions, re.MULTILINE)
151 re_RankOther = re.compile(u"%(PLYR)s finished the tournament in (?P<RANK>[0-9]+)(st|nd|rd|th) place$" % substitutions, re.MULTILINE)
152 re_Cancelled = re.compile('Hand\scancelled', re.MULTILINE)
153 re_Uncalled = re.compile('Uncalled\sbet\s\(%(CUR)s(?P<BET>[,.\d]+)\)\sreturned\sto' % substitutions, re.MULTILINE)
154 #APTEM-89 wins the $0.27 bounty for eliminating Hero
155 #ChazDazzle wins the 22000 bounty for eliminating berkovich609
156 #JKuzja, vecenta split the $50 bounty for eliminating ODYSSES
157 re_Bounty = re.compile(u"%(PLYR)s (?P<SPLIT>split|wins) the %(CUR)s(?P<AMT>[,\.0-9]+) bounty for eliminating (?P<ELIMINATED>.+?)$" % substitutions, re.MULTILINE)
158 #Amsterdam71 wins $19.90 for eliminating MuKoJla and their own bounty increases by $19.89 to $155.32
159 #Amsterdam71 wins $4.60 for splitting the elimination of Frimble11 and their own bounty increases by $4.59 to $41.32
160 #Amsterdam71 wins the tournament and receives $230.36 - congratulations!
161 re_Progressive = re.compile(u"""
162 %(PLYR)s\swins\s%(CUR)s(?P<AMT>[,\.0-9]+)\s
163 for\s(splitting\sthe\selimination\sof|eliminating)\s(?P<ELIMINATED>.+?)\s
164 and\stheir\sown\sbounty\sincreases\sby\s%(CUR)s(?P<INCREASE>[\.0-9]+)\sto\s%(CUR)s(?P<ENDAMT>[\.0-9]+)$"""
165 % substitutions, re.MULTILINE|re.VERBOSE)
166 re_Rake = re.compile(u"""
167 Total\spot\s%(CUR)s(?P<POT>[,\.0-9]+)(.+?)?\s\|\sRake\s%(CUR)s(?P<RAKE>[,\.0-9]+)"""
168 % substitutions, re.MULTILINE|re.VERBOSE)
170 re_STP = re.compile(u"""
171 STP\sadded:\s%(CUR)s(?P<AMOUNT>[,\.0-9]+)"""
172 % substitutions, re.MULTILINE|re.VERBOSE)
174 def compilePlayerRegexs(self, hand):
175 players = set([player[1] for player in hand.players])
176 if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
177 self.compiledPlayers = players
178 player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
179 subst = {
180 'PLYR': player_re,
181 'BRKTS': r'(\(button\) |\(small\sblind\) |\(big\blind\) |\(button\) \(small\sblind\) |\(button\) \(big\sblind\) )?',
182 'CUR': u"(\$|\xe2\x82\xac|\u20ac||\£|)"
183 }
185 self.re_HeroCards = re.compile(r"Dealt\sto\s%(PLYR)s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % subst, re.MULTILINE)
186 self.re_ShownCards = re.compile("Seat\s(?P<SEAT>[0-9]+):\s%(PLYR)s\s%(BRKTS)s(?P<SHOWED>showed|mucked)\s\[(?P<CARDS>.*)\](\sand\s(lost|(won|collected)\s \(%(CUR)s(?P<POT>[,\.\d]+)\))\swith\s(?P<STRING>.+?)(,\sand\s(won\s\(%(CUR)s[\.\d]+\)|lost)\swith\s(?P<STRING2>.*))?)?$" % subst, re.MULTILINE)
188 def readSupportedGames(self):
189 return [["ring", "hold", "nl"],
190 ["ring", "hold", "pl"],
191 ["ring", "hold", "fl"],
192 ["ring", "hold", "pn"],
194 ["ring", "stud", "fl"],
196 ["ring", "draw", "fl"],
197 ["ring", "draw", "pl"],
198 ["ring", "draw", "nl"],
200 ["tour", "hold", "nl"],
201 ["tour", "hold", "pl"],
202 ["tour", "hold", "fl"],
203 ["tour", "hold", "pn"],
205 ["tour", "stud", "fl"],
207 ["tour", "draw", "fl"],
208 ["tour", "draw", "pl"],
209 ["tour", "draw", "nl"],
210 ]
212 def determineGameType(self, handText):
213 info = {}
214 m = self.re_GameInfo.search(handText)
215 if not m:
216 tmp = handText[0:200]
217 log.error(("UnibetToFpdb.determineGameType: '%s'") % tmp)
218 raise FpdbParseError
220 mg = m.groupdict()
221 if 'LIMIT' in mg:
222 #print(mg['LIMIT'])
223 if mg['LIMIT'] == 'NL':
224 info['limitType'] = self.limits['No Limit']
225 elif mg['LIMIT'] == 'PL':
226 info['limitType'] = self.limits['Pot Limit']
228 #info['limitType'] = self.limits[mg['LIMIT']]
229 if 'GAME' in mg:
230 print(mg['GAME'])
231 if mg['GAME'] == 'No Limit Hold\'Em Banzai':
232 info['base'] = 'hold'
233 info['category'] = 'holdem'
234 info['type'] = 'ring'
235 info['split'] = False
236 elif mg['GAME'] == 'Pot Limit Omaha':
237 info['base'] = 'hold'
238 info['category'] = 'omahahi'
239 info['type'] = 'ring'
240 info['split'] = False
241 #(info['base'], info['category']) = self.games[mg['GAME']]
242 if 'SB' in mg and mg['SB'] is not None:
243 info['sb'] = mg['SB']
244 if 'BB' in mg and mg['BB'] is not None:
245 info['bb'] = mg['BB']
246 if 'BUB' in mg and mg['BUB'] is not None:
247 info['sb'] = '0'
248 info['bb'] = mg['BUB']
249 if 'CURRENCY1' in mg and mg['CURRENCY1'] is not None:
250 info['currency'] = self.currencies[mg['CURRENCY1']]
251 elif 'CURRENCY' in mg:
252 info['currency'] = self.currencies[mg['CURRENCY']]
254 # if 'Zoom' in mg['TITLE'] or 'Rush' in mg['TITLE']:
255 # info['fast'] = True
256 # else:
257 # info['fast'] = False
258 # if 'Home' in mg['TITLE']:
259 # info['homeGame'] = True
260 # else:
261 # info['homeGame'] = False
262 # if 'CAP' in mg and mg['CAP'] is not None:
263 # info['buyinType'] = 'cap'
264 # else:
265 # info['buyinType'] = 'regular'
266 # if 'SPLIT' in mg and mg['SPLIT'] == 'Split':
267 # info['split'] = True
268 # else:
269 # info['split'] = False
270 # if 'SITE' in mg:
271 # if mg['SITE'] == 'PokerMaster':
272 # self.sitename = "PokerMaster"
273 # self.siteId = 25
274 # m1 = self.re_HandInfo.search(handText,re.DOTALL)
275 # if m1 and '_5Cards_' in m1.group('TABLE'):
276 # info['category'] = '5_omahahi'
277 # elif mg['SITE'] == 'Run It Once Poker':
278 # self.sitename = "Run It Once Poker"
279 # self.siteId = 26
280 # elif mg['SITE'] == 'BetOnline':
281 # self.sitename = 'BetOnline'
282 # self.siteId = 19
283 # elif mg['SITE'] == 'PokerBros':
284 # self.sitename = 'PokerBros'
285 # self.siteId = 29
287 # if 'TOURNO' in mg and mg['TOURNO'] is None:
288 # info['type'] = 'ring'
289 # else:
290 # info['type'] = 'tour'
291 # if 'ZOOM' in mg['TOUR']:
292 # info['fast'] = True
294 if info.get('currency') in ('T$', None) and info['type']=='ring':
295 info['currency'] = 'play'
297 if info['limitType'] == 'fl' and info['bb'] is not None:
298 if info['type'] == 'ring':
299 try:
300 info['sb'] = self.Lim_Blinds[mg['BB']][0]
301 info['bb'] = self.Lim_Blinds[mg['BB']][1]
302 except KeyError:
303 tmp = handText[0:200]
304 log.error(("UnibetToFpdb.determineGameType: Lim_Blinds has no lookup for '%s' - '%s'") % (mg['BB'], tmp))
305 raise FpdbParseError
306 else:
307 info['sb'] = str((Decimal(mg['SB'])/2).quantize(Decimal("0.01")))
308 info['bb'] = str(Decimal(mg['SB']).quantize(Decimal("0.01")))
309 log.info(("UnibetToFpdb.determineGameType: '%s'") % info)
310 return info
312 def readHandInfo(self, hand):
313 #First check if partial
314 if hand.handText.count('*** Summary ***')!=1:
315 raise FpdbHandPartial(("Hand is not cleanly split into pre and post Summary"))
317 info = {}
318 m = self.re_HandInfo.search(hand.handText,re.DOTALL)
319 m2 = self.re_GameInfo.search(hand.handText)
320 if m is None or m2 is None:
321 tmp = hand.handText[0:200]
322 log.error(("UnibetToFpdb.readHandInfo: '%s'") % tmp)
323 raise FpdbParseError
325 info.update(m.groupdict())
326 info.update(m2.groupdict())
328 log.debug("readHandInfo: %s" % info)
329 for key in info:
330 if key == 'DATETIME':
331 #2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET] # (both dates are parsed so ET date overrides the other)
332 #2008/08/17 - 01:14:43 (ET)
333 #2008/09/07 06:23:14 ET
334 datetimestr = "00:00:00 2000/01/01" # default used if time not found
335 if self.siteId == 26:
336 m2 = self.re_DateTime2.finditer(info[key])
338 else:
339 m1 = self.re_DateTime1.finditer(info[key])
340 for a in m1:
341 datetimestr1 = str(a.group('H'))+":"+str(a.group('MIN'))+":"+str(a.group('S'))
342 datetimestr2 = str(a.group('Y'))+"/"+str(a.group('M'))+"/"+str(a.group('D'))
343 datetimestr = datetimestr2+" "+datetimestr1
344 print('datetimestr',datetimestr)
345 #tz = a.group('TZ') # just assume ET??
346 #print (" tz = ", tz, " datetime =", datetimestr)
347 hand.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET"
348 #hand.startTime = HandHistoryConverter.changeTimezone(hand.startTime, "ET", "UTC")
350 if key == 'HID':
351 hand.handid = info[key]
352 if key == 'TOURNO':
353 hand.tourNo = info[key]
354 if key == 'BUYIN':
355 if hand.tourNo!=None:
356 print ("DEBUG: info['BUYIN']: %s" % info['BUYIN'])
357 print ("DEBUG: info['BIAMT']: %s" % info['BIAMT'])
358 print ("DEBUG: info['BIRAKE']: %s" % info['BIRAKE'])
359 print ("DEBUG: info['BOUNTY']: %s" % info['BOUNTY'])
360 if info[key].strip() == 'Freeroll':
361 hand.buyin = 0
362 hand.fee = 0
363 hand.buyinCurrency = "FREE"
364 elif info[key].strip() == '':
365 hand.buyin = 0
366 hand.fee = 0
367 hand.buyinCurrency = "NA"
368 else:
369 if info[key].find("$")!=-1:
370 hand.buyinCurrency="USD"
371 elif info[key].find(u"£")!=-1:
372 hand.buyinCurrency="GBP"
373 elif info[key].find(u"€")!=-1:
374 hand.buyinCurrency="EUR"
375 elif info[key].find(u"₹")!=-1:
376 hand.buyinCurrency="INR"
377 elif info[key].find(u"¥")!=-1:
378 hand.buyinCurrency="CNY"
379 elif info[key].find("FPP")!=-1:
380 hand.buyinCurrency="PSFP"
381 elif info[key].find("SC")!=-1:
382 hand.buyinCurrency="PSFP"
383 elif re.match("^[0-9+]*$", info[key].strip()):
384 hand.buyinCurrency="play"
385 else:
386 #FIXME: handle other currencies, play money
387 log.error(("UnibetToFpdb.readHandInfo: Failed to detect currency.") + " Hand ID: %s: '%s'" % (hand.handid, info[key]))
388 raise FpdbParseError
390 info['BIAMT'] = info['BIAMT'].strip(u'$€£FPPSC₹')
392 if hand.buyinCurrency!="PSFP":
393 if info['BOUNTY'] != None:
394 # There is a bounty, Which means we need to switch BOUNTY and BIRAKE values
395 tmp = info['BOUNTY']
396 info['BOUNTY'] = info['BIRAKE']
397 info['BIRAKE'] = tmp
398 info['BOUNTY'] = info['BOUNTY'].strip(u'$€£₹') # Strip here where it isn't 'None'
399 hand.koBounty = int(100*Decimal(info['BOUNTY']))
400 hand.isKO = True
401 else:
402 hand.isKO = False
404 info['BIRAKE'] = info['BIRAKE'].strip(u'$€£₹')
406 hand.buyin = int(100*Decimal(info['BIAMT'])) + hand.koBounty
407 hand.fee = int(100*Decimal(info['BIRAKE']))
408 else:
409 hand.buyin = int(100*Decimal(info['BIAMT']))
410 hand.fee = 0
411 if 'Zoom' in info['TITLE'] or 'Rush' in info['TITLE']:
412 hand.isFast = True
413 else:
414 hand.isFast = False
415 if 'Home' in info['TITLE']:
416 hand.isHomeGame = True
417 else:
418 hand.isHomeGame = False
419 if key == 'LEVEL':
420 hand.level = info[key]
421 if key == 'SHOOTOUT' and info[key] != None:
422 hand.isShootout = True
423 if key == 'TABLE':
424 hand.tablename = info[key]
425 # if info['TOURNO'] is not None and info['HIVETABLE'] is not None:
426 # hand.tablename = info['HIVETABLE']
427 # elif hand.tourNo != None and len(tablesplit)>1:
428 # hand.tablename = tablesplit[1]
429 # else:
430 # hand.tablename = info[key]
431 if key == 'BUTTON':
432 hand.buttonpos = info[key]
433 if key == 'MAX' and info[key] != None:
434 hand.maxseats = int(info[key])
435 log.info("readHandInfo.hand: %s" % hand)
436 if self.re_Cancelled.search(hand.handText):
437 raise FpdbHandPartial(("Hand '%s' was cancelled.") % hand.handid)
439 def readButton(self, hand):
440 pre, post = hand.handText.split('*** Summary ***')
441 m = self.re_Button.search(hand.handText)
442 m2 = self.re_PlayerInfo.finditer(pre)
443 if m:
444 for b in m2:
445 if b.group('PNAME') == m.group('BUTTON'):
446 hand.buttonpos = int(b.group('SEAT'))
447 log.info("readHandInfo.readbutton: %s" % int(b.group('SEAT')))
448 else:
449 log.info('readButton: ' + ('not found'))
451 def readPlayerStacks(self, hand):
452 pre, post = hand.handText.split('*** Summary ***')
453 m = self.re_PlayerInfo.finditer(pre)
454 m2 = self.re_PlayerInfo2.finditer(pre)
455 for b in m2:
457 for a in m:
459 if a.group('PNAME') == b.group('SITOUT'):
460 hand.addPlayer(
461 int(a.group('SEAT')),
462 a.group('PNAME'),
463 self.clearMoneyString(a.group('CASH')),
464 None,
465 int(a.group('SEAT'))
466 #self.clearMoneyString(a.group('BOUNTY'))
467 )
468 log.info("readPlayerStacks: '%s' '%s' '%s' '%s' '%s'" % int(a.group('SEAT')), a.group('PNAME'), self.clearMoneyString(a.group('CASH')), None, int(a.group('SEAT')))
469 break
470 elif a.group('PNAME') != b.group('SITOUT'):
471 hand.addPlayer(
472 int(a.group('SEAT')),
473 a.group('PNAME'),
474 self.clearMoneyString(a.group('CASH')),
475 None,
477 )
478 log.info("readPlayerStacks: '%s' '%s' '%s' '%s' '%s'" % int(a.group('SEAT')), a.group('PNAME'), self.clearMoneyString(a.group('CASH')), None)
482 def markStreets(self, hand):
484 # There is no marker between deal and draw in Stars single draw games
485 # this upsets the accounting, incorrectly sets handsPlayers.cardxx and
486 # in consequence the mucked-display is incorrect.
487 # Attempt to fix by inserting a DRAW marker into the hand text attribute
488 # PREFLOP = ** Dealing down cards **
489 # This re fails if, say, river is missing; then we don't get the ** that starts the river.
490 m = re.search(r"\*\*\*\sHole\scards\s\*\*\*(?P<PREFLOP>(.+(?P<FLOPET>\[\S\S\]))?.+(?=\*\*\*\sFlop\s\*\*\*)|.+)"
491 r"(\*\*\*\sFlop\s\*\*\*(?P<FLOP>(\[\S\S\s])?\[(\S\S?)?\S\S\S\S\].+(?=\*\*\*\sTurn\s\*\*\*)|.+))?"
492 r"(\*\*\*\sTurn\s\*\*\*\s\[\S\S \S\S \S\S\](?P<TURN>\[\S\S\].+(?=\*\*\*\sRiver\s\*\*\*)|.+))?"
493 r"(\*\*\*\sRiver\s\*\*\*\s\[\S\S \S\S \S\S\]?\s\[?\S\S\]\s(?P<RIVER>\[\S\S\].+))?", hand.handText,re.DOTALL)
494 hand.addStreets(m)
495 log.info("markStreets.handaddstreets: %s" % hand)
497 def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand
498 m = self.re_Board.search(hand.streets[street])
499 if m:
500 hand.setCommunityCards(street, m.group('CARDS').split(' '))
501 log.info("readCommunityCards.setCommunityCards:' %s' " % street)
502 else:
503 log.error("readCommunityCards.setCommunityCards: none")
507 def readAntes(self, hand):
508 log.debug(("reading antes"))
509 m = self.re_Antes.finditer(hand.handText)
510 for player in m:
511 logging.info("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
512 hand.addAnte(player.group('PNAME'), self.clearMoneyString(player.group('ANTE')))
514 def readBringIn(self, hand):
515 m = self.re_BringIn.search(hand.handText,re.DOTALL)
516 if m:
517 logging.info("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
518 hand.addBringIn(m.group('PNAME'), self.clearMoneyString(m.group('BRINGIN')))
520 def readBlinds(self, hand):
521 liveBlind = True
522 for a in self.re_PostSB.finditer(hand.handText):
523 if liveBlind:
524 hand.addBlind(a.group('PNAME'), 'small blind', self.clearMoneyString(a.group('SB')))
525 logging.info("readBlinds: '%s' for '%s'" %(a.group('PNAME'), self.clearMoneyString(a.group('SB'))))
526 liveBlind = False
527 else:
528 names = [p[1] for p in hand.players]
529 if "Big Blind" in names or "Small Blind" in names or "Dealer" in names:
530 hand.addBlind(a.group('PNAME'), 'small blind', self.clearMoneyString(a.group('SB')))
531 logging.info("readBlinds: '%s' for '%s'" %(a.group('PNAME'), self.clearMoneyString(a.group('SB'))))
532 else:
533 # Post dead blinds as ante
534 hand.addBlind(a.group('PNAME'), 'secondsb', self.clearMoneyString(a.group('SB')))
535 logging.info("readBlinds: '%s' for '%s'" %(a.group('PNAME'), self.clearMoneyString(a.group('SB'))))
536 for a in self.re_PostBB.finditer(hand.handText):
537 hand.addBlind(a.group('PNAME'), 'big blind', self.clearMoneyString(a.group('BB')))
538 logging.info("readBlinds: '%s' for '%s'" %(a.group('PNAME'), self.clearMoneyString(a.group('BB'))))
539 for a in self.re_PostBoth.finditer(hand.handText):
540 hand.addBlind(a.group('PNAME'), 'both', self.clearMoneyString(a.group('SBBB')))
541 logging.info("readBlinds: '%s' for '%s'" %(a.group('PNAME'), self.clearMoneyString(a.group('SBBB'))))
543 for a in self.re_PostStraddle.finditer(hand.handText):
544 hand.addBlind(a.group('PNAME'), 'straddle', self.clearMoneyString(a.group('STRADDLE')))
545 logging.info("readBlinds: '%s' for '%s'" %(a.group('PNAME'), self.clearMoneyString(a.group('STRADDLE'))))
546 for a in self.re_PostBUB.finditer(hand.handText):
547 hand.addBlind(a.group('PNAME'), 'button blind', self.clearMoneyString(a.group('BUB')))
548 logging.info("readBlinds: '%s' for '%s'" %(a.group('PNAME'), self.clearMoneyString(a.group('BUB'))))
550 def readHoleCards(self, hand):
551# streets PREFLOP, PREDRAW, and THIRD are special cases beacause
552# we need to grab hero's cards
553 for street in ('PREFLOP', 'DEAL'):
554 if street in hand.streets.keys():
555 print(street)
556 m = self.re_HeroCards.finditer(hand.streets[street])
557 print(m)
558 for found in m:
559# if m == None:
560# hand.involved = False
561# else:
562 hand.hero = found.group('PNAME')
563 logging.info("readHoleCards: '%s'" %(found.group('PNAME')))
564 if 'cards' not in found.group('NEWCARDS'):
565 newcards = found.group('NEWCARDS').split(' ')
566 hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
572 def readAction(self, hand, street):
573 if hand.gametype['split'] and street in hand.communityStreets:
574 s = street + '2'
575 else:
576 s = street
577 if not hand.streets[s]:
578 return
579 m = self.re_Action.finditer(hand.streets[s])
580 for action in m:
581 acts = action.groupdict()
582 log.error("DEBUG: %s acts: %s" % (street, acts))
583 if action.group('ATYPE') == ' folds':
584 hand.addFold( street, action.group('PNAME'))
585 elif action.group('ATYPE') == ' checks':
586 hand.addCheck( street, action.group('PNAME'))
587 elif action.group('ATYPE') == ' calls':
588 hand.addCall( street, action.group('PNAME'), self.clearMoneyString(action.group('BET')) )
589 elif action.group('ATYPE') == ' raises':
590 if action.group('BETTO') is not None:
591 hand.addRaiseTo( street, action.group('PNAME'), self.clearMoneyString(action.group('BETTO')) )
592 elif action.group('BET') is not None:
593 hand.addCallandRaise( street, action.group('PNAME'), self.clearMoneyString(action.group('BET')) )
594 elif action.group('ATYPE') == ' bets':
595 hand.addBet( street, action.group('PNAME'), self.clearMoneyString(action.group('BET')) )
596 elif action.group('ATYPE') == ' discards':
597 hand.addDiscard(street, action.group('PNAME'), action.group('BET'), action.group('CARDS'))
598 elif action.group('ATYPE') == ' stands pat':
599 hand.addStandsPat( street, action.group('PNAME'), action.group('CARDS'))
600 else:
601 log.info(("DEBUG:") + " " + ("Unimplemented %s: '%s' '%s'") % ("readAction", action.group('PNAME'), action.group('ATYPE')))
604 def readShowdownActions(self, hand):
605 for shows in self.re_ShowdownAction.finditer(hand.handText):
606 cards = shows.group('CARDS').split(' ')
607 logging.debug("hand.readShowdownActions('%s','%s')" % cards, shows.group('PNAME'))
608 hand.addShownCards(cards, shows.group('PNAME'))
609 logging.info("hand.readShowdownActions('%s','%s')" % cards, shows.group('PNAME'))
611 def readTourneyResults(self, hand):
612 """Reads knockout bounties and add them to the koCounts dict"""
613 pass
615 def readCollectPot(self,hand):
616 hand.setUncalledBets(True)
617 for m in self.re_CollectPot.finditer(hand.handText):
619 hand.addCollectPot(player=m.group('PNAME'), pot=str(Decimal((m.group('POT')))))
620 logging.info("readCollectPot: '%s' for '%s'" %(m.group('PNAME'), str(Decimal((m.group('POT'))))))
623 def readShownCards(self,hand):
624 pass
627 @staticmethod
628 def getTableTitleRe(type, table_name=None, tournament = None, table_number=None):
629 pass