Coverage for UnibetToFpdb.py: 0%

332 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-09-28 16:41 +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######################################################################## 

20 

21#import L10n 

22#_ = L10n.get_translation() 

23 

24# TODO: straighten out discards for draw games 

25 

26import sys 

27from HandHistoryConverter import * 

28from decimal_wrapper import Decimal 

29 

30# Unibet HH Format 

31 

32class Unibet(HandHistoryConverter): 

33 

34 # Class Variables 

35 

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 } 

48 

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 } 

80 

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'} 

93 

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) 

98 

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) 

102 

103 re_PlayerInfo2 = re.compile(u""" 

104 (?P<SITOUT>\w+)\s\((€|$|£)[,.0-9]+\)\s\(sitting\sout\)""" % substitutions, 

105 re.MULTILINE|re.VERBOSE) 

106 

107 re_HandInfo = re.compile(""" 

108 (?P<TABLE>\sTable\s(€|$|£)[0-9]+\s(PL|NL|FL))""", 

109 re.MULTILINE|re.VERBOSE) 

110 

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) 

121 

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) 

169 

170 re_STP = re.compile(u""" 

171 STP\sadded:\s%(CUR)s(?P<AMOUNT>[,\.0-9]+)""" 

172 % substitutions, re.MULTILINE|re.VERBOSE) 

173 

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 } 

184 

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) 

187 

188 def readSupportedGames(self): 

189 return [["ring", "hold", "nl"], 

190 ["ring", "hold", "pl"], 

191 ["ring", "hold", "fl"], 

192 ["ring", "hold", "pn"], 

193 

194 ["ring", "stud", "fl"], 

195 

196 ["ring", "draw", "fl"], 

197 ["ring", "draw", "pl"], 

198 ["ring", "draw", "nl"], 

199 

200 ["tour", "hold", "nl"], 

201 ["tour", "hold", "pl"], 

202 ["tour", "hold", "fl"], 

203 ["tour", "hold", "pn"], 

204 

205 ["tour", "stud", "fl"], 

206 

207 ["tour", "draw", "fl"], 

208 ["tour", "draw", "pl"], 

209 ["tour", "draw", "nl"], 

210 ] 

211 

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 

219 

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'] 

227 

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']] 

253 

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 

286 

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 

293 

294 if info.get('currency') in ('T$', None) and info['type']=='ring': 

295 info['currency'] = 'play' 

296 

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 

311 

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")) 

316 

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 

324 

325 info.update(m.groupdict()) 

326 info.update(m2.groupdict()) 

327 

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]) 

337 

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") 

349 

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 

389 

390 info['BIAMT'] = info['BIAMT'].strip(u'$€£FPPSC₹') 

391 

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 

403 

404 info['BIRAKE'] = info['BIRAKE'].strip(u'$€£₹') 

405 

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) 

438 

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')) 

450 

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: 

456 

457 for a in m: 

458 

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, 

476 

477 ) 

478 log.info("readPlayerStacks: '%s' '%s' '%s' '%s' '%s'" % int(a.group('SEAT')), a.group('PNAME'), self.clearMoneyString(a.group('CASH')), None) 

479 

480 

481 

482 def markStreets(self, hand): 

483 

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) 

496 

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") 

504 

505 

506 

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'))) 

513 

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'))) 

519 

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')))) 

542 

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')))) 

549 

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) 

567 

568 

569 

570 

571 

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'))) 

602 

603 

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')) 

610 

611 def readTourneyResults(self, hand): 

612 """Reads knockout bounties and add them to the koCounts dict""" 

613 pass 

614 

615 def readCollectPot(self,hand): 

616 hand.setUncalledBets(True) 

617 for m in self.re_CollectPot.finditer(hand.handText): 

618 

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')))))) 

621 

622 

623 def readShownCards(self,hand): 

624 pass 

625 

626 

627 @staticmethod 

628 def getTableTitleRe(type, table_name=None, tournament = None, table_number=None): 

629 pass 

630