Coverage for WinningToFpdb.py: 0%

627 statements  

« prev     ^ index     » next       coverage.py v7.6.3, created at 2024-10-14 11:07 +0000

1#!/usr/bin/env python 

2# -*- coding: utf-8 -*- 

3# 

4# Copyright 2016, Chaz Littlejohn 

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 

26# _ = L10n.get_translation() 

27from HandHistoryConverter import HandHistoryConverter, FpdbParseError, FpdbHandPartial 

28import re 

29import logging 

30import datetime 

31from decimal import Decimal 

32 

33 

34# Winning HH Format 

35log = logging.getLogger("parser") 

36 

37 

38class Winning(HandHistoryConverter): 

39 # Class Variables 

40 

41 version = 0 

42 sitename = "WinningPoker" 

43 filetype = "text" 

44 codepage = ("utf-16", "utf8", "cp1252") 

45 siteId = 24 # Needs to match id entry in Sites database 

46 sym = {"USD": "\$", "T$": "", "play": ""} 

47 substitutions = { 

48 "LEGAL_ISO": "USD|TB|CP", # legal ISO currency codes 

49 "LS": "\$|", # legal currency symbols - Euro(cp1252, utf-8) 

50 "PLYR": r"(?P<PNAME>.+?)", 

51 "NUM": ".,\dK", 

52 "CUR": "(\$|)", 

53 "BRKTS": r"(\(button\)\s|\(small\sblind\)\s|\(big\sblind\)\s|\(button\)\s\(small\sblind\)\s|\(button\)\s\(big\sblind\)\s)?", 

54 } 

55 games1 = { # base, category 

56 "Hold'em": ("hold", "holdem"), 

57 "Six Plus Hold'em": ("hold", "6_holdem"), 

58 "Omaha": ("hold", "omahahi"), 

59 "Omaha HiLow": ("hold", "omahahilo"), 

60 "5Card Omaha H/L": ("hold", "5_omaha8"), 

61 "5Card Omaha": ("hold", "5_omaha"), 

62 "Seven Cards Stud": ("stud", "studhi"), 

63 "Seven Cards Stud HiLow": ("stud", "studhilo"), 

64 } 

65 games2 = { # base, category 

66 "Holdem": ("hold", "holdem"), 

67 "Omaha": ("hold", "omahahi"), 

68 "Omaha H/L": ("hold", "omahahilo"), 

69 "5Card Omaha H/L": ("hold", "5_omaha8"), 

70 "5Card Omaha": ("hold", "5_omaha"), 

71 # "Six Plus Hold'em" : ('hold','6_holdem'), 

72 "7Stud": ("stud", "studhi"), 

73 "7Stud H/L": ("stud", "studhilo"), 

74 } 

75 limits = {"No Limit": "nl", "Pot Limit": "pl", "Fixed Limit": "fl", "All-in or Fold Limit": "al"} 

76 speeds = {"Turbo": "Turbo", "Hyper Turbo": "Hyper", "Regular": "Normal"} 

77 buyin = {"CAP": "cap", "Short": "shallow"} 

78 

79 SnG_Fee = { 

80 50: {"Hyper": 0, "Turbo": 0, "Normal": 5}, 

81 100: {"Hyper": 0, "Turbo": 0, "Normal": 10}, 

82 150: {"Hyper": 11, "Turbo": 12, "Normal": 15}, 

83 300: {"Hyper": 20, "Turbo": 25, "Normal": 30}, 

84 500: {"Hyper": 30, "Turbo": 45, "Normal": 50}, 

85 1000: {"Hyper": 55, "Turbo": 90, "Normal": 100}, 

86 1500: {"Hyper": 80, "Turbo": 140, "Normal": 150}, 

87 2000: {"Hyper": 100, "Turbo": 175, "Normal": 200}, 

88 3000: {"Hyper": 130, "Turbo": 275, "Normal": 300}, 

89 5000: {"Hyper": 205, "Turbo": 475, "Normal": 500}, 

90 8000: {"Hyper": 290, "Turbo": 650, "Normal": 800}, 

91 10000: {"Hyper": 370, "Turbo": 800, "Normal": 900}, 

92 } 

93 

94 HUSnG_Fee = { 

95 200: {"Hyper": 10, "Turbo": 0, "Normal": 17}, 

96 220: {"Hyper": 0, "Turbo": 16, "Normal": 0}, 

97 240: {"Hyper": 10, "Turbo": 0, "Normal": 0}, 

98 500: {"Hyper": 0, "Turbo": 0, "Normal": 25}, 

99 550: {"Hyper": 0, "Turbo": 25, "Normal": 0}, 

100 600: {"Hyper": 18, "Turbo": 0, "Normal": 0}, 

101 1000: {"Hyper": 25, "Turbo": 0, "Normal": 50}, 

102 1100: {"Hyper": 0, "Turbo": 50, "Normal": 0}, 

103 1200: {"Hyper": 25, "Turbo": 0, "Normal": 0}, 

104 2000: {"Hyper": 50, "Turbo": 0, "Normal": 100}, 

105 2200: {"Hyper": 0, "Turbo": 100, "Normal": 0}, 

106 2400: {"Hyper": 50, "Turbo": 0, "Normal": 0}, 

107 3000: {"Hyper": 70, "Turbo": 0, "Normal": 150}, 

108 3300: {"Hyper": 0, "Turbo": 150, "Normal": 0}, 

109 3600: {"Hyper": 75, "Turbo": 0, "Normal": 0}, 

110 5000: {"Hyper": 100, "Turbo": 0, "Normal": 250}, 

111 5500: {"Hyper": 0, "Turbo": 250, "Normal": 0}, 

112 6000: {"Hyper": 125, "Turbo": 0, "Normal": 0}, 

113 10000: {"Hyper": 200, "Turbo": 0, "Normal": 450}, 

114 11000: {"Hyper": 0, "Turbo": 450, "Normal": 0}, 

115 12000: {"Hyper": 225, "Turbo": 0, "Normal": 0}, 

116 15000: {"Hyper": 266, "Turbo": 0, "Normal": 0}, 

117 20000: {"Hyper": 400, "Turbo": 0, "Normal": 900}, 

118 22000: {"Hyper": 0, "Turbo": 900, "Normal": 0}, 

119 24000: {"Hyper": 450, "Turbo": 0, "Normal": 0}, 

120 30000: {"Hyper": 600, "Turbo": 0, "Normal": 1200}, 

121 33000: {"Hyper": 0, "Turbo": 1200, "Normal": 0}, 

122 36000: {"Hyper": 600, "Turbo": 0, "Normal": 0}, 

123 40000: {"Hyper": 800, "Turbo": 0, "Normal": 0}, 

124 50000: {"Hyper": 0, "Turbo": 0, "Normal": 5000}, 

125 55000: {"Hyper": 0, "Turbo": 2000, "Normal": 0}, 

126 60000: {"Hyper": 1000, "Turbo": 0, "Normal": 0}, 

127 110000: {"Hyper": 0, "Turbo": 3000, "Normal": 0}, 

128 120000: {"Hyper": 1500, "Turbo": 0, "Normal": 0}, 

129 } 

130 currencies = {"$": "USD", "": "T$"} 

131 

132 re_GameInfo1 = re.compile( 

133 """ 

134 Game\sID:\s(?P<HID>\d+)\s 

135 (?P<SB>[%(NUM)s]+)/(?P<BB>[%(NUM)s]+)\s 

136 (?P<TABLE>.+?)?\s 

137 \((?P<GAME>(Six\sPlus\s)?Hold\'em|Omaha|Omaha\sHiLow|Seven\sCards\sStud|Seven\sCards\sStud\sHiLow)\) 

138 (\s(?P<MAX>\d+\-max))?$ 

139 """ 

140 % substitutions, 

141 re.MULTILINE | re.VERBOSE, 

142 ) 

143 

144 # Hand #78708209 - Omaha H/L(Fixed Limit) - $20.00/$40.00 - 2019/07/18 15:13:01 UTC 

145 # Hand #68217077 - Holdem(No Limit) - $0.05/$0.10 - 2019/06/28 02:38:17 UTC 

146 # Game Hand #80586589 - Tournament #11182752 - Holdem(No Limit) - Level 15 (250.00/500.00)- 2019/07/21 17:44:50 UTC 

147 # Game Hand #82980175 - Tournament #11212445 - Omaha H/L(Pot Limit) - Level 1 (250.00/500.00)- 2019/07/25 02:31:33 UTC 

148 

149 re_GameInfo2 = re.compile( 

150 """ 

151 (Game\s)?Hand\s\#(?P<HID>[0-9]+)\s\-\s 

152 ( 

153 (?P<TOUR>([\$.,\dK]+\sGTD\s)?Tournament\s\#(?P<TOURNO>\d+)\s\-\s) # open paren of tournament info 

154 )? 

155 # close paren of tournament info 

156 (?P<GAME>Holdem|Omaha|Omaha\sH/L|5Card\sOmaha\sH/L|5Card\sOmaha|7Stud|7Stud\sH/L) 

157 \((?P<LIMIT>No\sLimit|Fixed\sLimit|Pot\sLimit|All\-in\sor\sFold\sLimit)\)\s\-\s 

158 (Level\s(?P<LEVEL>[IVXLC\d]+)\s)? 

159 \(? # open paren of the stakes 

160 (?P<CURRENCY>%(LS)s|)? 

161 ((?P<SB>[.0-9]+)/(%(LS)s)?(?P<BB>[.0-9]+)) 

162 \)? # close paren of the stakes 

163 \s?\-\s 

164 (?P<DATETIME>.*$) 

165 """ 

166 % substitutions, 

167 re.MULTILINE | re.VERBOSE, 

168 ) 

169 

170 # Seat 6: puccini (5.34). 

171 re_PlayerInfo1 = re.compile( 

172 """ 

173 ^Seat\s(?P<SEAT>[0-9]+):\s 

174 (?P<PNAME>.*)\s 

175 \((?P<CASH>[%(NUM)s]+)\) 

176 \.$ 

177 """ 

178 % substitutions, 

179 re.MULTILINE | re.VERBOSE, 

180 ) 

181 

182 re_PlayerInfo2 = re.compile( 

183 """ 

184 ^\s?Seat\s(?P<SEAT>[0-9]+):\s 

185 (?P<PNAME>.*)\s 

186 \((%(LS)s)?(?P<CASH>[,.0-9]+) 

187 \) 

188 (?P<SITOUT>\sis\ssitting\sout)?""" 

189 % substitutions, 

190 re.MULTILINE | re.VERBOSE, 

191 ) 

192 

193 re_DateTime1 = re.compile( 

194 """ 

195 ^Game\sstarted\sat:\s 

196 (?P<Y>[0-9]{4})/(?P<M>[0-9]{1,2})/(?P<D>[0-9]{1,2})\s 

197 (?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+) 

198 $""", 

199 re.MULTILINE | re.VERBOSE, 

200 ) 

201 

202 # 2019/07/18 15:13:01 UTC 

203 re_DateTime2 = re.compile( 

204 """(?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]+)""", 

205 re.MULTILINE, 

206 ) 

207 

208 # $2.20 Turbo Heads-up, Table 1 

209 # $2.40 Hyper Turbo Heads-up, Table 1 

210 # $10 Freeroll - On Demand, Table 13 

211 # $25 GTD - On Demand, Table 1 

212 # $5 Regular 9-Max, Table 1 (Hold'em) 

213 

214 re_Table1 = re.compile( 

215 """ 

216 ^(?P<CURRENCY>[%(LS)s]|)?(?P<BUYIN>[%(NUM)s]+)\s 

217 ((?P<GAME>(Six\sPlus\s)?Holdem|PLO|PLO8|Omaha\sHi/Lo|Omaha|PL\sOmaha|PL\sOmaha\sHi/Lo|PLO\sHi/Lo)\s?)? 

218 ((?P<SPECIAL>(GTD|Freeroll|FREEBUY|Freebuy))\s?)? 

219 ((?P<SPEED>(Turbo|Hyper\sTurbo|Regular))\s?)? 

220 ((?P<MAX>(\d+\-Max|Heads\-up|Heads\-Up))\s?)? 

221 (?P<OTHER>.*?) 

222 ,\sTable\s(?P<TABLENO>\d+) 

223 """ 

224 % substitutions, 

225 re.VERBOSE | re.MULTILINE, 

226 ) 

227 

228 re_Table2 = re.compile("Table\s'(?P<TABLENO>\d+)'") 

229 

230 # St. Lucie 6-max Seat #1 is the button 

231 # Table '1' 9-max Seat #3 is the button 

232 # Blitz Poker 6-max Seat #1 is the button 

233 # Table '25' 9-max Seat #8 is the button 

234 

235 re_HandInfo = re.compile( 

236 """ 

237 ^(?P<TABLE>.+?)\s 

238 ((?P<MAX>\d+)-max\s) 

239 (?P<PLAY>\(Play\sMoney\)\s)? 

240 (Seat\s\#(?P<BUTTON>\d+)\sis\sthe\sbutton)?""", 

241 re.MULTILINE | re.VERBOSE, 

242 ) 

243 

244 re_TourneyName1 = re.compile("(?P<TOURNAME>.*),\sTable\s\d+") 

245 re_TourneyName2 = re.compile("TN\-(?P<TOURNAME>.+?)\sGAMETYPE") 

246 re_GTD = re.compile("(?P<GTD>[%(NUM)s]+)\sGTD" % substitutions) 

247 re_buyinType = re.compile("\((?P<BUYINTYPE>CAP|Short)\)", re.MULTILINE) 

248 re_buyin = re.compile("%(CUR)s(?P<BUYIN>[,.0-9]+)" % substitutions, re.MULTILINE) 

249 re_Step = re.compile("\sStep\s(?P<STEPNO>\d+)") 

250 

251 re_Identify = re.compile("Game\sID:\s\d+|Hand\s\#\d+\s\-\s") 

252 re_Identify_Old = re.compile("Game\sID:\s\d+") 

253 re_SplitHands = re.compile("\n\n") 

254 re_Button1 = re.compile("Seat (?P<BUTTON>\d+) is the button") 

255 re_Button2 = re.compile("Seat #(?P<BUTTON>\d+) is the button") 

256 re_Board = re.compile(r"\[(?P<CARDS>.+)\]") 

257 re_TourNo = re.compile("\sT(?P<TOURNO>\d+)\-") 

258 re_File1 = re.compile("HH\d{8}\s(T\d+\-)?G\d+") 

259 re_File2 = re.compile("(?P<TYPE>CASHID|SITGOID|RUSHID|SCHEDULEDID)") 

260 

261 re_PostSB1 = re.compile(r"^Player %(PLYR)s has small blind \((?P<SB>[%(NUM)s]+)\)" % substitutions, re.MULTILINE) 

262 re_PostBB1 = re.compile(r"^Player %(PLYR)s has big blind \((?P<BB>[%(NUM)s]+)\)" % substitutions, re.MULTILINE) 

263 re_Posts1 = re.compile(r"^Player %(PLYR)s posts \((?P<SBBB>[%(NUM)s]+)\)" % substitutions, re.MULTILINE) 

264 re_Antes1 = re.compile(r"^Player %(PLYR)s (posts )?ante \((?P<ANTE>[%(NUM)s]+)\)" % substitutions, re.MULTILINE) 

265 re_BringIn1 = re.compile(r"^Player %(PLYR)s bring in \((?P<BRINGIN>[%(NUM)s]+)\)" % substitutions, re.MULTILINE) 

266 re_HeroCards1 = re.compile(r"^Player %(PLYR)s received card: \[(?P<CARD>.+)\]" % substitutions, re.MULTILINE) 

267 

268 re_PostSB2 = re.compile(r"^%(PLYR)s posts the small blind %(CUR)s(?P<SB>[,.0-9]+)" % substitutions, re.MULTILINE) 

269 re_PostBB2 = re.compile(r"^%(PLYR)s posts the big blind %(CUR)s(?P<BB>[,.0-9]+)" % substitutions, re.MULTILINE) 

270 re_PostBoth2 = re.compile(r"^%(PLYR)s posts dead %(CUR)s(?P<SBBB>[,.0-9]+)" % substitutions, re.MULTILINE) 

271 re_Posts2 = re.compile(r"^%(PLYR)s posts %(CUR)s(?P<SBBB>[,.0-9]+)" % substitutions, re.MULTILINE) 

272 re_Antes2 = re.compile(r"^%(PLYR)s posts ante %(CUR)s(?P<ANTE>[,.0-9]+)" % substitutions, re.MULTILINE) 

273 re_BringIn2 = re.compile( 

274 r"^%(PLYR)s brings[- ]in( low|) %(CUR)s(?P<BRINGIN>[,.0-9]+)" % substitutions, re.MULTILINE 

275 ) 

276 re_HeroCards2 = re.compile( 

277 r"^Dealt to %(PLYR)s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % substitutions, re.MULTILINE 

278 ) 

279 re_Uncalled = re.compile("Uncalled bet \(%(CUR)s(?P<BET>[,.\d]+)\) returned to" % substitutions, re.MULTILINE) 

280 

281 re_Action1 = re.compile( 

282 r""" 

283 ^Player\s(%(PLYR)s)?\s(?P<ATYPE>bets|checks|raises|calls|folds|allin|straddle|caps|cap) 

284 (\s\((?P<BET>[%(NUM)s]+)\))? 

285 $""" 

286 % substitutions, 

287 re.MULTILINE | re.VERBOSE, 

288 ) 

289 

290 re_Action2 = re.compile( 

291 r""" 

292 ^%(PLYR)s(?P<ATYPE>\sbets|\schecks|\sraises|\scalls|\sfolds|\scaps|\scap|\sstraddle) 

293 (\s%(CUR)s(?P<BET>[,.\d]+))?(\sto\s%(CUR)s(?P<BETTO>[,.\d]+))?  

294 \s*(and\sis\sall\-in)?\s*$""" 

295 % substitutions, 

296 re.MULTILINE | re.VERBOSE, 

297 ) 

298 

299 # Player lessthanrocko shows: Two pairs. 8s and 5s [3s 3h]. Bets: 420. Collects: 0. Loses: 420. 

300 # *Player ChazDazzle shows: Full House (5/8) [7s 5s]. Bets: 420. Collects: 840. Wins: 420. 

301 # *Player fullstacker shows: Flush, A high [2s 8h 2h Jd] Low hand (A A 2 3 4 8 ).Bets: 0.50. Collects: 0.95. Wins: 0.45. 

302 

303 # *Player ChazDazzle shows: High card A [6h 10d 2c As 7d 4d 9s] Low hand (A A 2 4 6 7 ).Bets: 3.55. Collects: 3.53. Loses: 0.02. 

304 # *Player KickAzzJohnny shows: Two pairs. 8s and 3s [5d 3d 3s 6s 8s 8h Ad]. Bets: 3.55. Collects: 3.52. Loses: 0.03. 

305 

306 re_ShownCards1 = re.compile( 

307 r""" 

308 ^\*?Player\s%(PLYR)s\sshows:\s 

309 (?P<STRING>.+?)\s 

310 \[(?P<CARDS>.*)\] 

311 (\sLow\shand\s\((?P<STRING2>.+?)\s?\))? 

312 \.""" 

313 % substitutions, 

314 re.MULTILINE | re.VERBOSE, 

315 ) 

316 

317 # Seat 5: LitAF did not show and won $0.25 

318 # Seat 6: Thrash370 showed [Td Ad Qd 4s] and won 60600.00 with HI - a straight, Queen high [Qd Jh Td 9d 8d] | LO - [8,5,4,2,1] 

319 re_ShownCards2 = re.compile( 

320 r""" 

321 ^Seat\s(?P<SEAT>[0-9]+):\s%(PLYR)s\s%(BRKTS)s 

322 (?P<SHOWED>showed|mucked)\s\[(?P<CARDS>.+?)\](\sand\s(lost|(won|collected)\s%(CUR)s(?P<POT>[,\.\d]+)) 

323 \swith (?P<STRING>.+?) 

324 (,\sand\s(won\s\(%(CUR)s[\.\d]+\)|lost)\swith\s(?P<STRING2>.*))?)?  

325 $""" 

326 % substitutions, 

327 re.MULTILINE | re.VERBOSE, 

328 ) 

329 

330 re_CollectPot1 = re.compile( 

331 r""" 

332 ^\*?Player\s%(PLYR)s\s 

333 (does\snot\sshow|shows|mucks) 

334 .+?\.\s? 

335 Bets:\s[%(NUM)s]+\.\s 

336 Collects:\s(?P<POT>[%(NUM)s]+)\.\s 

337 (Wins|Loses):\s[%(NUM)s]+\.? 

338 $""" 

339 % substitutions, 

340 re.MULTILINE | re.VERBOSE, 

341 ) 

342 

343 # Seat 5: LitAF did not show and won $0.25 

344 # Seat 6: Thrash370 showed [Td Ad Qd 4s] and won 60600.00 with HI - a straight, Queen high [Qd Jh Td 9d 8d] | LO - [8,5,4,2,1] 

345 re_CollectPot2 = re.compile( 

346 r""" 

347 Seat\s(?P<SEAT>[0-9]+):\s%(PLYR)s\s%(BRKTS)s 

348 (did\snot\sshow\sand\swon|showed\s\[.+?\]\sand\s(won|collected))\s%(CUR)s(?P<POT>[,.\d]+) 

349 (,\smucked|\swith.*|) 

350 """ 

351 % substitutions, 

352 re.MULTILINE | re.VERBOSE, 

353 ) 

354 # AssFungus collected $92.25 from main pot 1 

355 re_CollectPot3 = re.compile(r"^%(PLYR)s collected %(CUR)s(?P<POT>[,.\d]+)" % substitutions, re.MULTILINE) 

356 

357 def compilePlayerRegexs(self, hand): 

358 pass 

359 

360 def readSupportedGames(self): 

361 return [ 

362 ["ring", "hold", "nl"], 

363 ["ring", "hold", "fl"], 

364 ["ring", "hold", "pl"], 

365 ["ring", "hold", "al"], 

366 ["ring", "stud", "fl"], 

367 ["tour", "hold", "nl"], 

368 ["tour", "hold", "fl"], 

369 ["tour", "hold", "pl"], 

370 ["tour", "hold", "al"], 

371 ["tour", "stud", "fl"], 

372 ] 

373 

374 def determineGameType(self, handText): 

375 if self.re_Identify_Old.search(handText): 

376 self.version = 1 

377 return self._determineGameType1(handText) 

378 else: 

379 self.version = 2 

380 return self._determineGameType2(handText) 

381 

382 def _determineGameType1(self, handText): 

383 info = {} 

384 if not self.re_File1.search(self.in_path): 

385 tmp = "Invalid filename: %s" % self.in_path 

386 log.debug(("WinningToFpdb.determineGameType: '%s'") % tmp) 

387 raise FpdbHandPartial(tmp) 

388 

389 m = self.re_GameInfo1.search(handText) 

390 if not m: 

391 tmp = handText[0:200] 

392 log.error(("WinningToFpdb.determineGameType: '%s'") % tmp) 

393 raise FpdbParseError 

394 

395 mg = m.groupdict() 

396 m1 = self.re_TourNo.search(self.in_path) 

397 if m1: 

398 mg.update(m1.groupdict()) 

399 

400 if "GAME" in mg: 

401 (info["base"], info["category"]) = self.games1[mg["GAME"]] 

402 if "SB" in mg: 

403 info["sb"] = mg["SB"] 

404 if "BB" in mg: 

405 info["bb"] = mg["BB"] 

406 

407 if info["base"] == "stud": 

408 info["limitType"] = "fl" 

409 else: 

410 m2 = self.re_PostBB1.search(handText) 

411 if m2: 

412 bb = self.clearMoneyString(m2.group("BB")) 

413 if Decimal(self.clearMoneyString(info["sb"])) == Decimal(bb): 

414 info["limitType"] = "fl" 

415 

416 if info.get("limitType") is None: 

417 if "omaha" in info["category"]: 

418 info["limitType"] = "pl" 

419 else: 

420 info["limitType"] = "nl" 

421 

422 if "TOURNO" in mg and mg["TOURNO"] is not None: 

423 info["type"] = "tour" 

424 else: 

425 info["type"] = "ring" 

426 

427 if "TABLE" in mg and mg["TABLE"] is not None: 

428 if re.match("PM\s", mg["TABLE"]): 

429 info["currency"] = "play" 

430 elif info["type"] == "tour": 

431 info["currency"] = "T$" 

432 else: 

433 info["currency"] = "USD" 

434 

435 if "(Cap)" in mg["TABLE"]: 

436 info["buyinType"] = "cap" 

437 elif "(Short)" in mg["TABLE"]: 

438 info["buyinType"] = "shallow" 

439 else: 

440 info["buyinType"] = "regular" 

441 else: 

442 info["currency"] = "T$" 

443 

444 if info["limitType"] == "fl" and info["bb"] is not None: 

445 info["sb"] = str((Decimal(mg["SB"]) / 2).quantize(Decimal("0.01"))) 

446 info["bb"] = str(Decimal(mg["SB"]).quantize(Decimal("0.01"))) 

447 

448 return info 

449 

450 def _determineGameType2(self, handText): 

451 info = {} 

452 m = self.re_GameInfo2.search(handText) 

453 if not m: 

454 tmp = handText[0:200] 

455 log.error(("WinningToFpdb._determineGameType2: '%s'") % tmp) 

456 raise FpdbParseError 

457 

458 mg = m.groupdict() 

459 

460 m1 = self.re_File2.search(self.in_path) 

461 if m1: 

462 mg.update(m1.groupdict()) 

463 

464 if "LIMIT" in mg: 

465 info["limitType"] = self.limits[mg["LIMIT"]] 

466 if "GAME" in mg: 

467 (info["base"], info["category"]) = self.games2[mg["GAME"]] 

468 if "SB" in mg: 

469 info["sb"] = mg["SB"] 

470 if "BB" in mg: 

471 info["bb"] = mg["BB"] 

472 if "CURRENCY" in mg and mg["CURRENCY"] is not None: 

473 info["currency"] = self.currencies[mg["CURRENCY"]] 

474 

475 if "TYPE" in mg and "RUSHID" == mg["TYPE"]: 

476 info["fast"] = True 

477 else: 

478 info["fast"] = False 

479 

480 if "TOURNO" in mg and mg["TOURNO"] is None: 

481 info["type"] = "ring" 

482 else: 

483 info["type"] = "tour" 

484 

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

486 info["currency"] = "play" 

487 

488 if info["limitType"] == "fl" and info["bb"] is not None: 

489 info["sb"] = str((Decimal(mg["SB"]) / 2).quantize(Decimal("0.01"))) 

490 info["bb"] = str(Decimal(mg["SB"]).quantize(Decimal("0.01"))) 

491 

492 return info 

493 

494 def readHandInfo(self, hand): 

495 if self.version == 1: 

496 self._readHandInfo1(hand) 

497 else: 

498 self._readHandInfo2(hand) 

499 

500 def _readHandInfo1(self, hand): 

501 # First check if partial 

502 if hand.handText.count("------ Summary ------") != 1: 

503 raise FpdbHandPartial(("Hand is not cleanly split into pre and post Summary")) 

504 

505 info = {} 

506 m = self.re_GameInfo1.search(hand.handText) 

507 m2 = self.re_DateTime1.search(hand.handText) 

508 if m is None or m2 is None: 

509 tmp = hand.handText[0:200] 

510 log.error(("WinningToFpdb.readHandInfo: '%s'") % tmp) 

511 raise FpdbParseError 

512 

513 info.update(m.groupdict()) 

514 

515 m1 = self.re_TourNo.search(self.in_path) 

516 if m1: 

517 info.update(m1.groupdict()) 

518 

519 datetimestr = "%s/%s/%s %s:%s:%s" % ( 

520 m2.group("Y"), 

521 m2.group("M"), 

522 m2.group("D"), 

523 m2.group("H"), 

524 m2.group("MIN"), 

525 m2.group("S"), 

526 ) 

527 hand.startTime = datetime.datetime.strptime( 

528 datetimestr, "%Y/%m/%d %H:%M:%S" 

529 ) # also timezone at end, e.g. " ET" 

530 hand.startTime = HandHistoryConverter.changeTimezone(hand.startTime, self.import_parameters["timezone"], "UTC") 

531 

532 if "TOURNO" in info: 

533 hand.tourNo = info["TOURNO"] 

534 

535 if "HID" in info: 

536 hand.handid = info["HID"] 

537 

538 if "MAX" in info and info["MAX"] is not None: 

539 hand.maxseats = int(info["MAX"].replace("-max", "")) 

540 

541 if not hand.maxseats: 

542 if hand.gametype["base"] == "stud": 

543 hand.maxseats = 8 

544 elif hand.gametype["type"] == "ring": 

545 hand.maxseats = 9 

546 else: 

547 hand.maxseats = 10 

548 

549 if "TABLE" in info and info["TABLE"] is not None: 

550 if hand.tourNo: 

551 hand.buyin = 0 

552 hand.fee = 0 

553 hand.buyinCurrency = "NA" 

554 hand.tablename = 1 

555 m3 = self.re_Table1.search(info["TABLE"]) 

556 if m3 is not None: 

557 tableinfo = m3.groupdict() 

558 if "SPECIAL" in tableinfo and tableinfo["SPECIAL"] is not None: 

559 if tableinfo["SPECIAL"] in ("Freeroll", "FREEBUY", "Freebuy"): 

560 hand.buyinCurrency = "FREE" 

561 hand.guaranteeAmt = int(100 * Decimal(self.clearMoneyString(tableinfo["BUYIN"]))) 

562 

563 if hand.guaranteeAmt == 0: 

564 hand.buyinCurrency = "USD" 

565 hand.buyin = int(100 * Decimal(self.clearMoneyString(tableinfo["BUYIN"]))) 

566 

567 if "MAX" in tableinfo and tableinfo["MAX"] is not None: 

568 n = tableinfo["MAX"].replace("-Max", "") 

569 if n in ("Heads-up", "Heads-Up"): 

570 hand.maxseats = 2 

571 else: 

572 hand.maxseats = int(n) 

573 

574 if "SPEED" in tableinfo and tableinfo["SPEED"] is not None: 

575 hand.speed = self.speeds[tableinfo["SPEED"]] 

576 if hand.maxseats == 2 and hand.buyin in self.HUSnG_Fee: 

577 hand.fee = self.HUSnG_Fee[hand.buyin][hand.speed] 

578 hand.isSng = True 

579 if hand.maxseats != 2 and hand.buyin in self.SnG_Fee: 

580 hand.fee = self.SnG_Fee[hand.buyin][hand.speed] 

581 hand.isSng = True 

582 

583 hand.tablename = int(m3.group("TABLENO")) 

584 

585 if "On Demand" in info["TABLE"]: 

586 hand.isOnDemand = True 

587 

588 if " KO" in info["TABLE"] or "Knockout" in info["TABLE"]: 

589 hand.isKO = True 

590 

591 if "R/A" in info["TABLE"]: 

592 hand.isRebuy = True 

593 hand.isAddOn = True 

594 

595 m4 = self.re_TourneyName1.search(info["TABLE"]) 

596 if m4: 

597 hand.tourneyName = m4.group("TOURNAME") 

598 else: 

599 hand.tablename = info["TABLE"] 

600 buyin_type = self.re_buyinType.search(info["TABLE"]) 

601 if buyin_type: 

602 hand.gametype["buyinType"] = self.buyin[buyin_type.group("BUYINTYPE")] 

603 else: 

604 hand.buyin = 0 

605 hand.fee = 0 

606 hand.buyinCurrency = "NA" 

607 hand.tablename = 1 

608 

609 def _readHandInfo2(self, hand): 

610 # First check if partial 

611 if hand.handText.count("*** SUMMARY ***") != 1: 

612 raise FpdbHandPartial(("Hand is not cleanly split into pre and post Summary")) 

613 

614 info = {} 

615 m = self.re_GameInfo2.search(hand.handText) 

616 m1 = self.re_HandInfo.search(hand.handText) 

617 if m is None or m1 is None: 

618 tmp = hand.handText[0:200] 

619 log.error(("WinningToFpdb.readHandInfo: '%s'") % tmp) 

620 raise FpdbParseError 

621 

622 info.update(m.groupdict()) 

623 info.update(m1.groupdict()) 

624 

625 for key in info: 

626 if key == "DATETIME": 

627 datetimestr = "2000/01/01 00:00:00" # default used if time not found 

628 m2 = self.re_DateTime2.finditer(info[key]) 

629 for a in m2: 

630 datetimestr = "%s/%s/%s %s:%s:%s" % ( 

631 a.group("Y"), 

632 a.group("M"), 

633 a.group("D"), 

634 a.group("H"), 

635 a.group("MIN"), 

636 a.group("S"), 

637 ) 

638 # tz = a.group('TZ') # just assume ET?? 

639 # print " tz = ", tz, " datetime =", datetimestr 

640 hand.startTime = datetime.datetime.strptime( 

641 datetimestr, "%Y/%m/%d %H:%M:%S" 

642 ) # also timezone at end, e.g. " ET" 

643 if key == "HID": 

644 hand.handid = info[key] 

645 if key == "TOURNO": 

646 hand.tourNo = info[key] 

647 if key == "LEVEL": 

648 hand.level = info[key] 

649 if key == "TABLE": 

650 if info["TOURNO"] is not None: 

651 hand.buyin = 0 

652 hand.fee = 0 

653 hand.buyinCurrency = "FREE" # FIXME 

654 

655 m2 = self.re_Table2.match(info[key]) 

656 if m2: 

657 hand.tablename = m2.group("TABLENO") 

658 else: 

659 hand.tablename = info[key] 

660 if key == "BUTTON": 

661 hand.buttonpos = info[key] 

662 if key == "MAX" and info[key] is not None: 

663 hand.maxseats = int(info[key]) 

664 

665 if "SCHEDULEDID" in self.in_path: 

666 m3 = self.re_TourneyName2.search(self.in_path) 

667 if m3: 

668 hand.tourneyName = m3.group("TOURNAME").replace("{BACKSLASH}", "\\") 

669 m4 = self.re_GTD.search(hand.tourneyName) 

670 if m4: 

671 hand.isGuarantee = True 

672 hand.guaranteeAmt = int(100 * Decimal(self.clearMoneyString(m4.group("GTD")))) 

673 if "Satellite" in hand.tourneyName: 

674 hand.isSatellite = True 

675 if "Shootout" in hand.tourneyName: 

676 hand.isShootout = True 

677 

678 elif "SITGOID" in self.in_path: 

679 hand.isSng = True 

680 m3 = self.re_TourneyName2.search(self.in_path) 

681 if m3: 

682 hand.tourneyName = m3.group("TOURNAME").replace("{BACKSLASH}", "\\") 

683 if " Hyper Turbo " in hand.tourneyName: 

684 speed = "Hyper Turbo" 

685 elif " Turbo " in hand.tourneyName: 

686 speed = "Turbo" 

687 else: 

688 speed = "Regular" 

689 

690 hand.speed = self.speeds[speed] 

691 

692 m4 = self.re_buyin.match(hand.tourneyName) 

693 if m4: 

694 hand.buyinCurrency = "USD" 

695 hand.buyin = int(100 * Decimal(self.clearMoneyString(m4.group("BUYIN")))) 

696 

697 if hand.maxseats == 2 and hand.buyin in self.HUSnG_Fee: 

698 hand.fee = self.HUSnG_Fee[hand.buyin][hand.speed] 

699 if hand.maxseats != 2 and hand.buyin in self.SnG_Fee: 

700 hand.fee = self.SnG_Fee[hand.buyin][hand.speed] 

701 

702 m5 = self.re_Step.search(hand.tourneyName) 

703 if m5: 

704 hand.isStep = True 

705 hand.stepNo = int(m5.group("STEPNO")) 

706 

707 elif "RUSHID" in self.in_path: 

708 (hand.gametype["fast"], hand.isFast) = (True, True) 

709 

710 def readButton(self, hand): 

711 if self.version == 1: 

712 self._readButton1(hand) 

713 else: 

714 self._readButton2(hand) 

715 

716 def _readButton1(self, hand): 

717 m = self.re_Button1.search(hand.handText) 

718 if m: 

719 hand.buttonpos = int(m.group("BUTTON")) 

720 else: 

721 log.info("readButton: " + ("not found")) 

722 

723 def _readButton2(self, hand): 

724 m = self.re_Button2.search(hand.handText) 

725 if m: 

726 hand.buttonpos = int(m.group("BUTTON")) 

727 else: 

728 log.info("readButton: " + ("not found")) 

729 

730 def readPlayerStacks(self, hand): 

731 if self.version == 1: 

732 self._readPlayerStacks1(hand) 

733 else: 

734 self._readPlayerStacks2(hand) 

735 

736 def _readPlayerStacks1(self, hand): 

737 pre, post = hand.handText.split("------ Summary ------") 

738 m = self.re_PlayerInfo1.finditer(pre) 

739 for a in m: 

740 hand.addPlayer(int(a.group("SEAT")), a.group("PNAME"), self.clearMoneyString(a.group("CASH"))) 

741 

742 def _readPlayerStacks2(self, hand): 

743 pre, post = hand.handText.split("*** SUMMARY ***") 

744 m = self.re_PlayerInfo2.finditer(pre) 

745 for a in m: 

746 hand.addPlayer(int(a.group("SEAT")), a.group("PNAME"), self.clearMoneyString(a.group("CASH"))) 

747 

748 def markStreets(self, hand): 

749 if self.version == 1: 

750 self._markStreets1(hand) 

751 else: 

752 self._markStreets2(hand) 

753 

754 def _markStreets1(self, hand): 

755 if hand.gametype["base"] in ("hold"): 

756 m = re.search( 

757 r"(?P<PREFLOP>.+(?=\*\*\* FLOP \*\*\*:)|.+)" 

758 r"(\*\*\* FLOP \*\*\*:(?P<FLOP> (\[\S\S\S?] )?\[\S\S\S? ?\S\S\S? \S\S\S?].+(?=\*\*\* TURN \*\*\*:)|.+))?" 

759 r"(\*\*\* TURN \*\*\*: \[\S\S\S? \S\S\S? \S\S\S?] (?P<TURN>\[\S\S\S?\].+(?=\*\*\* RIVER \*\*\*:)|.+))?" 

760 r"(\*\*\* RIVER \*\*\*: \[\S\S\S? \S\S\S? \S\S\S? \S\S\S?] ?(?P<RIVER>\[\S\S\S?\].+))?", 

761 hand.handText, 

762 re.DOTALL, 

763 ) 

764 elif hand.gametype["base"] in ("stud"): 

765 m = re.search( 

766 r"(?P<THIRD>.+(?=\*\*\* Third street \*\*\*)|.+)" 

767 r"(\*\*\* Third street \*\*\*(?P<FOURTH>.+(?=\*\*\* Fourth street \*\*\*)|.+))?" 

768 r"(\*\*\* Fourth street \*\*\*(?P<FIFTH>.+(?=\*\*\* Fifth street \*\*\*)|.+))?" 

769 r"(\*\*\* Fifth street \*\*\*(?P<SIXTH>.+(?=\*\*\* Sixth street \*\*\*)|.+))?" 

770 r"(\*\*\* Sixth street \*\*\*(?P<SEVENTH>.+))?", 

771 hand.handText, 

772 re.DOTALL, 

773 ) 

774 hand.addStreets(m) 

775 

776 def _markStreets2(self, hand): 

777 if hand.gametype["base"] in ("hold"): 

778 m = re.search( 

779 r"\*\*\* HOLE CARDS \*\*\*(?P<PREFLOP>(.+(?P<FLOPET>\[\S\S\]))?.+(?=\*\*\* (FLOP|FIRST FLOP|FLOP 1) \*\*\*)|.+)" 

780 r"(\*\*\* FLOP \*\*\*(?P<FLOP> (\[\S\S\] )?\[(\S\S ?)?\S\S \S\S\].+(?=\*\*\* (TURN|FIRST TURN|TURN 1) \*\*\*)|.+))?" 

781 r"(\*\*\* TURN \*\*\* \[\S\S \S\S \S\S] (?P<TURN>\[\S\S\].+(?=\*\*\* (RIVER|FIRST RIVER|RIVER 1) \*\*\*)|.+))?" 

782 r"(\*\*\* RIVER \*\*\* \[\S\S \S\S \S\S \S\S] (?P<RIVER>\[\S\S\].+))?" 

783 r"(\*\*\* (FIRST FLOP|FLOP 1) \*\*\*(?P<FLOP1> (\[\S\S\] )?\[(\S\S ?)?\S\S \S\S\].+(?=\*\*\* (FIRST TURN|TURN 1) \*\*\*)|.+))?" 

784 r"(\*\*\* (FIRST TURN|TURN 1) \*\*\* \[\S\S \S\S \S\S] (?P<TURN1>\[\S\S\].+(?=\*\*\* (FIRST RIVER|RIVER 1) \*\*\*)|.+))?" 

785 r"(\*\*\* (FIRST RIVER|RIVER 1) \*\*\* \[\S\S \S\S \S\S \S\S] (?P<RIVER1>\[\S\S\].+?(?=\*\*\* (SECOND (FLOP|TURN|RIVER)|(FLOP|TURN|RIVER) 2) \*\*\*)|.+))?" 

786 r"(\*\*\* (SECOND FLOP|FLOP 2) \*\*\*(?P<FLOP2> (\[\S\S\] )?\[\S\S ?\S\S \S\S\].+(?=\*\*\* (SECOND TURN|TURN 2) \*\*\*)|.+))?" 

787 r"(\*\*\* (SECOND TURN|TURN 2) \*\*\* \[\S\S \S\S \S\S] (?P<TURN2>\[\S\S\].+(?=\*\*\* (SECOND RIVER|RIVER 2) \*\*\*)|.+))?" 

788 r"(\*\*\* (SECOND RIVER|RIVER 2) \*\*\* \[\S\S \S\S \S\S \S\S] (?P<RIVER2>\[\S\S\].+))?", 

789 hand.handText, 

790 re.DOTALL, 

791 ) 

792 elif hand.gametype["base"] in ("stud"): 

793 m = re.search( 

794 r"(?P<ANTES>.+(?=\*\*\* 3rd STREET \*\*\*)|.+)" 

795 r"(\*\*\* 3rd STREET \*\*\*(?P<THIRD>.+(?=\*\*\* 4th STREET \*\*\*)|.+))?" 

796 r"(\*\*\* 4th STREET \*\*\*(?P<FOURTH>.+(?=\*\*\* 5th STREET \*\*\*)|.+))?" 

797 r"(\*\*\* 5th STREET \*\*\*(?P<FIFTH>.+(?=\*\*\* 6th STREET \*\*\*)|.+))?" 

798 r"(\*\*\* 6th STREET \*\*\*(?P<SIXTH>.+(?=\*\*\* 7th STREET \*\*\*)|.+))?" 

799 r"(\*\*\* 7th STREET \*\*\*(?P<SEVENTH>.+))?", 

800 hand.handText, 

801 re.DOTALL, 

802 ) 

803 hand.addStreets(m) 

804 

805 def readCommunityCards(self, hand, street): 

806 if self.version == 1: 

807 self._readCommunityCards1(hand, street) 

808 else: 

809 self._readCommunityCards2(hand, street) 

810 if street in ("FLOP1", "TURN1", "RIVER1", "FLOP2", "TURN2", "RIVER2"): 

811 hand.runItTimes = 2 

812 

813 def _readCommunityCards1(self, hand, street): # street has been matched by markStreets, so exists in this hand 

814 m = self.re_Board.search(hand.streets[street]) 

815 if m: 

816 hand.setCommunityCards(street, [c.replace("10", "T") for c in m.group("CARDS").split(" ")]) 

817 else: 

818 log.error("WinningToFpdb._readCommunityCards1: No community cards found on %s %s" % (street, hand.handid)) 

819 raise FpdbParseError 

820 

821 def _readCommunityCards2(self, hand, street): # street has been matched by markStreets, so exists in this hand 

822 m = self.re_Board.search(hand.streets[street]) 

823 if m: 

824 hand.setCommunityCards(street, m.group("CARDS").split(" ")) 

825 else: 

826 log.error("WinningToFpdb._readCommunityCards2: No community cards found on %s %s" % (street, hand.handid)) 

827 raise FpdbParseError 

828 

829 def readAntes(self, hand): 

830 if self.version == 1: 

831 self._readAntes1(hand) 

832 else: 

833 self._readAntes2(hand) 

834 

835 def _readAntes1(self, hand): 

836 log.debug(("reading antes")) 

837 m = self.re_Antes1.finditer(hand.handText) 

838 for player in m: 

839 # ~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE'))) 

840 hand.addAnte(player.group("PNAME"), player.group("ANTE")) 

841 

842 def _readAntes2(self, hand): 

843 log.debug(("reading antes")) 

844 m = self.re_Antes2.finditer(hand.handText) 

845 for player in m: 

846 # ~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE'))) 

847 hand.addAnte(player.group("PNAME"), player.group("ANTE")) 

848 

849 def readBringIn(self, hand): 

850 if self.version == 1: 

851 self._readBringIn1(hand) 

852 else: 

853 self._readBringIn2(hand) 

854 

855 def _readBringIn1(self, hand): 

856 m = self.re_BringIn1.search(hand.handText, re.DOTALL) 

857 if m: 

858 # ~ logging.debug("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN'))) 

859 hand.addBringIn(m.group("PNAME"), m.group("BRINGIN")) 

860 

861 def _readBringIn2(self, hand): 

862 m = self.re_BringIn2.search(hand.handText, re.DOTALL) 

863 if m: 

864 # ~ logging.debug("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN'))) 

865 hand.addBringIn(m.group("PNAME"), m.group("BRINGIN")) 

866 

867 def readBlinds(self, hand): 

868 if self.version == 1: 

869 self._readBlinds1(hand) 

870 else: 

871 self._readBlinds2(hand) 

872 

873 def _readBlinds1(self, hand): 

874 liveBlind = True 

875 for a in self.re_PostSB1.finditer(hand.handText): 

876 if liveBlind: 

877 hand.addBlind(a.group("PNAME"), "small blind", a.group("SB")) 

878 liveBlind = False 

879 else: 

880 pass 

881 # Post dead blinds as ante 

882 # hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SB')) 

883 for a in self.re_PostBB1.finditer(hand.handText): 

884 hand.addBlind(a.group("PNAME"), "big blind", a.group("BB")) 

885 for a in self.re_Posts1.finditer(hand.handText): 

886 if Decimal(self.clearMoneyString(a.group("SBBB"))) == Decimal(hand.bb): 

887 hand.addBlind(a.group("PNAME"), "big blind", a.group("SBBB")) 

888 else: 

889 hand.addBlind(a.group("PNAME"), "secondsb", a.group("SBBB")) 

890 

891 def _readBlinds2(self, hand): 

892 liveBlind = True 

893 for a in self.re_PostSB2.finditer(hand.handText): 

894 if liveBlind: 

895 hand.addBlind(a.group("PNAME"), "small blind", a.group("SB")) 

896 liveBlind = False 

897 else: 

898 pass 

899 # Post dead blinds as ante 

900 # hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SB')) 

901 for a in self.re_PostBB2.finditer(hand.handText): 

902 hand.addBlind(a.group("PNAME"), "big blind", a.group("BB")) 

903 for a in self.re_PostBoth2.finditer(hand.handText): 

904 hand.addBlind(a.group("PNAME"), "both", self.clearMoneyString(a.group("SBBB"))) 

905 for a in self.re_Posts2.finditer(hand.handText): 

906 if Decimal(self.clearMoneyString(a.group("SBBB"))) == Decimal(hand.bb): 

907 hand.addBlind(a.group("PNAME"), "big blind", a.group("SBBB")) 

908 else: 

909 hand.addBlind(a.group("PNAME"), "secondsb", a.group("SBBB")) 

910 

911 def readHoleCards(self, hand): 

912 if self.version == 1: 

913 self._readHoleCards1(hand) 

914 else: 

915 self._readHoleCards2(hand) 

916 

917 def _readHoleCards1(self, hand): 

918 # streets PREFLOP, PREDRAW, and THIRD are special cases beacause 

919 # we need to grab hero's cards 

920 for street in ("PREFLOP", "DEAL"): 

921 if street in hand.streets.keys(): 

922 newcards = [] 

923 m = self.re_HeroCards1.finditer(hand.streets[street]) 

924 for found in m: 

925 hand.hero = found.group("PNAME") 

926 newcards.append(found.group("CARD").replace("10", "T")) 

927 if hand.hero: 

928 hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True) 

929 

930 for street, text in list(hand.streets.items()): 

931 if not text or street in ("PREFLOP", "DEAL"): 

932 continue # already done these 

933 m = self.re_HeroCards1.finditer(hand.streets[street]) 

934 players = {} 

935 for found in m: 

936 player = found.group("PNAME") 

937 if players.get(player) is None: 

938 players[player] = [] 

939 players[player].append(found.group("CARD").replace("10", "T")) 

940 

941 for player, cards in list(players.items()): 

942 if street == "THIRD": # hero in stud game 

943 hand.dealt.add(player) # need this for stud?? 

944 if len(cards) == 3: 

945 hand.hero = player 

946 hand.addHoleCards( 

947 street, player, closed=cards[0:2], open=[cards[2]], shown=False, mucked=False, dealt=False 

948 ) 

949 else: 

950 hand.addHoleCards(street, player, closed=[], open=cards, shown=False, mucked=False, dealt=False) 

951 elif street == "SEVENTH": 

952 if hand.hero == player: 

953 hand.addHoleCards(street, player, open=cards, closed=[], shown=False, mucked=False, dealt=False) 

954 else: 

955 hand.addHoleCards(street, player, open=[], closed=cards, shown=False, mucked=False, dealt=False) 

956 else: 

957 hand.addHoleCards(street, player, open=cards, closed=[], shown=False, mucked=False, dealt=False) 

958 

959 def _readHoleCards2(self, hand): 

960 # streets PREFLOP, PREDRAW, and THIRD are special cases beacause 

961 # we need to grab hero's cards 

962 for street in ("PREFLOP", "DEAL"): 

963 if street in hand.streets.keys(): 

964 newcards = [] 

965 m = self.re_HeroCards2.finditer(hand.streets[street]) 

966 for found in m: 

967 hand.hero = found.group("PNAME") 

968 newcards = found.group("NEWCARDS").split(" ") 

969 if hand.hero: 

970 hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True) 

971 

972 for street, text in list(hand.streets.items()): 

973 if not text or street in ("PREFLOP", "DEAL"): 

974 continue # already done these 

975 m = self.re_HeroCards2.finditer(hand.streets[street]) 

976 for found in m: 

977 player = found.group("PNAME") 

978 if found.group("NEWCARDS") is None: 

979 newcards = [] 

980 else: 

981 newcards = found.group("NEWCARDS").split(" ") 

982 if found.group("OLDCARDS") is None: 

983 oldcards = [] 

984 else: 

985 oldcards = found.group("OLDCARDS").split(" ") 

986 

987 if street == "THIRD" and len(newcards) == 3: # hero in stud game 

988 hand.hero = player 

989 hand.dealt.add(player) # need this for stud?? 

990 hand.addHoleCards( 

991 street, player, closed=newcards[0:2], open=[newcards[2]], shown=False, mucked=False, dealt=False 

992 ) 

993 else: 

994 hand.addHoleCards( 

995 street, player, open=newcards, closed=oldcards, shown=False, mucked=False, dealt=False 

996 ) 

997 

998 def readAction(self, hand, street): 

999 if self.version == 1: 

1000 self._readAction1(hand, street) 

1001 else: 

1002 self._readAction2(hand, street) 

1003 

1004 def _readAction1(self, hand, street): 

1005 m = self.re_Action1.finditer(hand.streets[street]) 

1006 for action in m: 

1007 action.groupdict() 

1008 if action.group("PNAME") is None: 

1009 log.error("WinningToFpdb.readAction: Unknown player %s %s" % (action.group("ATYPE"), hand.handid)) 

1010 raise FpdbParseError 

1011 

1012 if action.group("ATYPE") == "folds": 

1013 hand.addFold(street, action.group("PNAME")) 

1014 elif action.group("ATYPE") == "checks": 

1015 hand.addCheck(street, action.group("PNAME")) 

1016 elif action.group("ATYPE") == "calls": 

1017 hand.addCall(street, action.group("PNAME"), self.clearMoneyString(action.group("BET"))) 

1018 elif action.group("ATYPE") in ("raises", "straddle", "caps", "cap"): 

1019 hand.addCallandRaise(street, action.group("PNAME"), self.clearMoneyString(action.group("BET"))) 

1020 elif action.group("ATYPE") == "bets": 

1021 hand.addBet(street, action.group("PNAME"), self.clearMoneyString(action.group("BET"))) 

1022 elif action.group("ATYPE") == "allin": 

1023 player = action.group("PNAME") 

1024 # disconnected all in 

1025 if action.group("BET") is None: 

1026 amount = str(hand.stacks[player]) 

1027 else: 

1028 amount = self.clearMoneyString(action.group("BET")).replace(",", "") # some sites have commas 

1029 Ai = Decimal(amount) 

1030 Bp = hand.lastBet[street] 

1031 Bc = sum(hand.bets[street][player]) 

1032 C = Bp - Bc 

1033 if Ai <= C: 

1034 hand.addCall(street, player, amount) 

1035 elif Bp == 0: 

1036 hand.addBet(street, player, amount) 

1037 else: 

1038 hand.addCallandRaise(street, player, amount) 

1039 else: 

1040 log.debug( 

1041 ("DEBUG:") 

1042 + " " 

1043 + ("Unimplemented %s: '%s' '%s'") % ("readAction", action.group("PNAME"), action.group("ATYPE")) 

1044 ) 

1045 

1046 def _readAction2(self, hand, street): 

1047 m = self.re_Action2.finditer(hand.streets[street]) 

1048 for action in m: 

1049 action.groupdict() 

1050 # log.error("DEBUG: %s acts: %s" % (street, acts)) 

1051 if action.group("ATYPE") == " folds": 

1052 hand.addFold(street, action.group("PNAME")) 

1053 elif action.group("ATYPE") == " checks": 

1054 hand.addCheck(street, action.group("PNAME")) 

1055 elif action.group("ATYPE") == " calls": 

1056 hand.addCall(street, action.group("PNAME"), self.clearMoneyString(action.group("BET"))) 

1057 elif action.group("ATYPE") in (" raises", " straddle", " caps", " cap"): 

1058 if action.group("BETTO") is not None: 

1059 hand.addRaiseTo(street, action.group("PNAME"), self.clearMoneyString(action.group("BETTO"))) 

1060 elif action.group("BET") is not None: 

1061 hand.addCallandRaise(street, action.group("PNAME"), self.clearMoneyString(action.group("BET"))) 

1062 elif action.group("ATYPE") == " bets": 

1063 hand.addBet(street, action.group("PNAME"), self.clearMoneyString(action.group("BET"))) 

1064 else: 

1065 log.debug( 

1066 ("DEBUG:") 

1067 + " " 

1068 + ("Unimplemented %s: '%s' '%s'") % ("readAction", action.group("PNAME"), action.group("ATYPE")) 

1069 ) 

1070 

1071 def readCollectPot(self, hand): 

1072 if self.version == 1: 

1073 self._readCollectPot1(hand) 

1074 elif hand.runItTimes == 2: 

1075 self._readCollectPot3(hand) 

1076 else: 

1077 self._readCollectPot2(hand) 

1078 

1079 def _readCollectPot1(self, hand): 

1080 for m in self.re_CollectPot1.finditer(hand.handText): 

1081 if Decimal(self.clearMoneyString(m.group("POT"))) > 0: 

1082 hand.addCollectPot(player=m.group("PNAME"), pot=m.group("POT")) 

1083 

1084 def _readCollectPot2(self, hand): 

1085 pre, post = hand.handText.split("*** SUMMARY ***") 

1086 acts, bovadaUncalled_v1, bovadaUncalled_v2, blindsantes, adjustment = ( 

1087 hand.actions.get("PREFLOP"), 

1088 False, 

1089 False, 

1090 0, 

1091 0, 

1092 ) 

1093 # names = [p[1] for p in hand.players] 

1094 if acts is not None and len([a for a in acts if a[1] != "folds"]) == 0: 

1095 m0 = self.re_Uncalled.search(hand.handText) 

1096 if m0 and Decimal(m0.group("BET")) == Decimal(hand.bb): 

1097 bovadaUncalled_v2 = True 

1098 elif m0 is None: 

1099 bovadaUncalled_v1 = True 

1100 has_sb = len([a[2] for a in hand.actions.get("BLINDSANTES") if a[1] == "small blind"]) > 0 

1101 adjustment = (Decimal(hand.bb) - Decimal(hand.sb)) if has_sb else Decimal(hand.bb) 

1102 blindsantes = sum([a[2] for a in hand.actions.get("BLINDSANTES")]) 

1103 else: 

1104 m0 = self.re_Uncalled.search(hand.handText) 

1105 if not m0: 

1106 hand.setUncalledBets(True) 

1107 

1108 for m in self.re_CollectPot2.finditer(post): 

1109 pot = self.clearMoneyString(m.group("POT")) 

1110 if bovadaUncalled_v1 and Decimal(pot) == (blindsantes): 

1111 hand.addCollectPot(player=m.group("PNAME"), pot=str(Decimal(pot) - adjustment)) 

1112 elif bovadaUncalled_v2: 

1113 hand.addCollectPot(player=m.group("PNAME"), pot=str(Decimal(pot) * 2)) 

1114 else: 

1115 hand.addCollectPot(player=m.group("PNAME"), pot=pot) 

1116 

1117 def _readCollectPot3(self, hand): 

1118 for m in self.re_CollectPot3.finditer(hand.handText): 

1119 hand.addCollectPot(player=m.group("PNAME"), pot=m.group("POT")) 

1120 

1121 def readShowdownActions(self, hand): 

1122 # TODO: pick up mucks also?? 

1123 pass 

1124 

1125 def readShownCards(self, hand): 

1126 if self.version == 1: 

1127 self._readShownCards1(hand) 

1128 else: 

1129 self._readShownCards2(hand) 

1130 

1131 def _readShownCards1(self, hand): 

1132 for m in self.re_ShownCards1.finditer(hand.handText): 

1133 if m.group("CARDS") is not None: 

1134 cards = m.group("CARDS") 

1135 cards = [ 

1136 c.replace("10", "T") for c in cards.split(" ") 

1137 ] # needs to be a list, not a set--stud needs the order 

1138 string = m.group("STRING") 

1139 if m.group("STRING2"): 

1140 string += "|" + m.group("STRING2") 

1141 

1142 (shown, mucked) = (False, False) 

1143 # if m.group('SHOWED') == "showed": shown = True 

1144 # elif m.group('SHOWED') == "mucked": mucked = True 

1145 

1146 # print "DEBUG: hand.addShownCards(%s, %s, %s, %s)" %(cards, m.group('PNAME'), shown, mucked) 

1147 hand.addShownCards(cards=cards, player=m.group("PNAME"), shown=shown, mucked=mucked, string=string) 

1148 

1149 def _readShownCards2(self, hand): 

1150 for m in self.re_ShownCards2.finditer(hand.handText): 

1151 if m.group("CARDS") is not None: 

1152 cards = m.group("CARDS") 

1153 cards = cards.split(" ") # needs to be a list, not a set--stud needs the order 

1154 string = m.group("STRING") 

1155 if m.group("STRING2"): 

1156 string += "|" + m.group("STRING2") 

1157 

1158 (shown, mucked) = (False, False) 

1159 if m.group("SHOWED") == "showed": 

1160 shown = True 

1161 elif m.group("SHOWED") == "mucked": 

1162 mucked = True 

1163 

1164 # print "DEBUG: hand.addShownCards(%s, %s, %s, %s)" %(cards, m.group('PNAME'), shown, mucked) 

1165 hand.addShownCards(cards=cards, player=m.group("PNAME"), shown=shown, mucked=mucked, string=string) 

1166 

1167 @staticmethod 

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

1169 "Returns string to search in windows titles" 

1170 regex = re.escape(str(table_name)) 

1171 if type == "tour": 

1172 regex = ", Table " + re.escape(str(table_number)) + "\s\-.*\s\(" + re.escape(str(tournament)) + "\)" 

1173 log.info( 

1174 "Winning.getTableTitleRe: table_name='%s' tournament='%s' table_number='%s'" 

1175 % (table_name, tournament, table_number) 

1176 ) 

1177 log.info("Winning.getTableTitleRe: returns: '%s'" % (regex)) 

1178 return regex