Coverage for PacificPokerToFpdb.py: 0%

307 statements  

« 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-2010, 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 

22#import L10n 

23#_ = L10n.get_translation() 

24 

25import sys 

26from HandHistoryConverter import * 

27from decimal_wrapper import Decimal 

28 

29# PacificPoker HH Format 

30 

31class PacificPoker(HandHistoryConverter): 

32 

33 # Class Variables 

34 

35 sitename = "PacificPoker" 

36 filetype = "text" 

37 codepage = ("utf8", "cp1252") 

38 siteId = 10 # Needs to match id entry in Sites database 

39 

40 mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} # Legal mixed games 

41 sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "€", "GBP": "\xa3", "play": ""} # ADD Euro, Sterling, etc HERE 

42 substitutions = { 

43 'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes 

44 'PLYR': r'(?P<PNAME>.+?)', 

45 'LS' : u"\$|€|", # legal currency symbols - Euro(cp1252, utf-8) 

46 'NUM' : u"\s.,\d\xa0", 

47 'CUR' : u"(\$|€|)" 

48 } 

49 

50 # translations from captured groups to fpdb info strings 

51 # not needed for PacificPoker 

52 #Lim_Blinds = { '0.01': ('0.01', '0.02'), 

53 # '0.02': ('0.02', '0.04'), 

54 # '0.03': ('0.03', '0.06'), 

55 # '0.05': ('0.05', '0.10'), 

56 # '0.12': ('0.12', '0.25'), 

57 # '0.25': ('0.25', '0.50'), 

58 # '0.50': ('0.50', '1.00'), 

59 # '1.00': ('1.00', '2.00'), '1': ('1.00', '2.00'), 

60 # '2.00': ('2.00', '4.00'), '2': ('2.00', '4.00'), 

61 # '3.00': ('3.00', '6.00'), '3': ('3.00', '6.00'), 

62 # '5.00': ('5.00', '10.00'), '5': ('5.00', '10.00'), 

63 # '10.00': ('10.00', '20.00'), '10': ('10.00', '20.00'), 

64 # '15.00': ('15.00', '30.00'), '15': ('15.00', '30.00'), 

65 # '30.00': ('30.00', '60.00'), '30': ('30.00', '60.00'), 

66 # '50.00': ('50.00', '100.00'), '50': ('50.00', '100.00'), 

67 # '75.00': ('75.00', '150.00'), '75': ('75.00', '150.00'), 

68 # '100.00': ('100.00', '200.00'), '100': ('100.00', '200.00'), 

69 # '200.00': ('200.00', '400.00'), '200': ('200.00', '400.00'), 

70 # '250.00': ('250.00', '500.00'), '250': ('250.00', '500.00') 

71 # } 

72 

73 limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl', 'LIMIT':'fl', 'Fix Limit':'fl' } 

74 

75 games = { # base, category 

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

77 'Holdem' : ('hold','holdem'), 

78 'Omaha' : ('hold','omahahi'), 

79 'Omaha Hi/Lo' : ('hold','omahahilo'), 

80 'OmahaHL' : ('hold','omahahilo') 

81 } 

82 

83 currencies = { u'€':'EUR', '$':'USD', '':'T$' } 

84 

85 # Static regexes 

86 re_GameInfo = re.compile(u""" 

87 (\#Game\sNo\s:\s[0-9]+\\n)? 

88 \*\*\*\*\*?\s(Cassava|888poker|888)(\.[a-z]{2})?(\-[a-z]{2})?\s(?P<FAST>Snap\sPoker\s)?(BLAST\s)?Hand\sHistory\sfor\sGame\s(?P<HID>[0-9]+)\s\*\*\*\*\*\\n 

89 (?P<CURRENCY1>%(LS)s)?\s?(?P<SB>[%(NUM)s]+)\s?(?P<CURRENCY2>%(LS)s)?/(%(LS)s)?\s?(?P<BB>[%(NUM)s]+)\s?(%(LS)s)?\sBlinds\s 

90 (?P<LIMIT>No\sLimit|Fix\sLimit|Pot\sLimit)\s 

91 (?P<GAME>Holdem|Omaha|OmahaHL|Hold\'em|Omaha\sHi/Lo|OmahaHL) 

92 (\sJackpot\stable)? 

93 \s-\s\*\*\*\s 

94 (?P<DATETIME>.*$)\s 

95 (Tournament\s\#(?P<TOURNO>\d+))? 

96 """ % substitutions, re.MULTILINE|re.VERBOSE) 

97 

98 re_PlayerInfo = re.compile(u""" 

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

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

101 \(\s(%(LS)s)?\s?(?P<CASH>[%(NUM)s]+)\s?(%(LS)s)?\s\)""" % substitutions, 

102 re.MULTILINE|re.VERBOSE) 

103 

104 re_HandInfo = re.compile(""" 

105 ^( 

106 (Table\s(?P<TABLE>[-\ \#a-zA-Z\d]+?)\s) 

107 | 

108 (Tournament\s\#(?P<TOURNO>\d+)\s 

109 ( 

110 (?P<BUYIN>( 

111 ((?P<BIAMT>(%(LS)s)?\s?[%(NUM)s]+\s?(%(LS)s)?)(\s\+\s?(?P<BIRAKE>(%(LS)s)?\s?[%(NUM)s]+\s?(%(LS)s)?))?) 

112 | 

113 (Free) 

114 | 

115 (.+?) 

116 )) 

117 ) 

118 (\s-\sTable\s\#(?P<TABLEID>\d+))?\s 

119 ) 

120 ) 

121 ((?P<MAX>\d+)\sMax\s)? 

122 (\(Real\sMoney\))? 

123 (?P<PLAY>\((Practice\sPlay|Play\sMoney)\))? 

124 \\n 

125 Seat\s(?P<BUTTON>[0-9]+)\sis\sthe\sbutton 

126 """ % substitutions, re.MULTILINE|re.VERBOSE) 

127 

128 re_Identify = re.compile(u'\*{4,5}\s(Cassava|888poker|888)(\.[a-z]{2})?(\-[a-z]{2})?\s(Snap\sPoker\s|BLAST\s)?Hand\sHistory\sfor\sGame\s\d+\s') 

129 re_SplitHands = re.compile('\n\n+') 

130 re_TailSplitHands = re.compile('(\n\n\n+)') 

131 re_Button = re.compile('Seat (?P<BUTTON>\d+) is the button', re.MULTILINE) 

132 re_Board = re.compile(u"\[\s(?P<CARDS>.+)\s\]") 

133 re_Spanish_10 = re.compile(u'D([tpeo])') 

134 

135 re_DateTime = re.compile("""(?P<D>[0-9]{2})\s(?P<M>[0-9]{2})\s(?P<Y>[0-9]{4})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)""", re.MULTILINE) 

136 

137 short_subst = {'PLYR': r'(?P<PNAME>.+?)', 'CUR': '\$?', 'NUM' : u".,\d\xa0"} 

138 re_PostSB = re.compile(r"^%(PLYR)s posts small blind \[(%(CUR)s)?\s?(?P<SB>[%(NUM)s]+)\s?(%(CUR)s)?\]" % substitutions, re.MULTILINE) 

139 re_PostBB = re.compile(r"^%(PLYR)s posts big blind \[(%(CUR)s)?\s?(?P<BB>[%(NUM)s]+)\s?(%(CUR)s)?\]" % substitutions, re.MULTILINE) 

140 re_Antes = re.compile(r"^%(PLYR)s posts (the\s)?ante \[(%(CUR)s)?\s?(?P<ANTE>[%(NUM)s]+)\s?(%(CUR)s)?\]" % substitutions, re.MULTILINE) 

141 # TODO: unknown in available hand histories for pacificpoker: 

142 re_BringIn = re.compile(r"^%(PLYR)s: brings[- ]in( low|) for (%(CUR)s)?\s?(?P<BRINGIN>[%(NUM)s]+)\s?(%(CUR)s)?" % substitutions, re.MULTILINE) 

143 re_PostBoth = re.compile(r"^%(PLYR)s posts dead blind \[(%(CUR)s)?\s?(?P<SB>[%(NUM)s]+)\s?(%(CUR)s)?\s\+\s(%(CUR)s)?\s?(?P<BB>[%(NUM)s]+)\s?(%(CUR)s)?\]" % substitutions, re.MULTILINE) 

144 re_HeroCards = re.compile(r"^Dealt to %(PLYR)s( \[\s(?P<NEWCARDS>.+?)\s\])" % substitutions, re.MULTILINE) 

145 re_Action = re.compile(r""" 

146 ^%(PLYR)s(?P<ATYPE>\sbets|\schecks|\sraises|\scalls|\sfolds|\sdiscards|\sstands\spat) 

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

148 (\s*and\sis\sall.in)? 

149 (\s*and\shas\sreached\sthe\s[%(CUR)s\s?\d\.]+\scap)? 

150 (\s*cards?(\s\[(?P<DISCARDED>.+?)\])?)?\s*$""" 

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

152 re_ShowdownAction = re.compile(r"^%s shows \[(?P<CARDS>.*)\]" % substitutions['PLYR'], re.MULTILINE) 

153 re_sitsOut = re.compile("^%s sits out" % substitutions['PLYR'], re.MULTILINE) 

154 re_ShownCards = re.compile("^%s ?(?P<SHOWED>shows|mucks) \[ (?P<CARDS>.*) \]$" % substitutions['PLYR'], re.MULTILINE) 

155 re_CollectPot = re.compile(r"^%(PLYR)s collected \[ (%(CUR)s)?\s?(?P<POT>[%(NUM)s]+)\s?(%(CUR)s)? \]$" % substitutions, re.MULTILINE) 

156 

157 def compilePlayerRegexs(self, hand): 

158 pass 

159 

160 def readSupportedGames(self): 

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

162 ["ring", "hold", "pl"], 

163 ["ring", "hold", "fl"], 

164 

165 ["tour", "hold", "nl"], 

166 ["tour", "hold", "pl"], 

167 ["tour", "hold", "fl"], 

168 ] 

169 

170 def determineGameType(self, handText): 

171 info = {} 

172 m = self.re_GameInfo.search(handText) 

173 if not m: 

174 tmp = handText[0:200] 

175 log.error(("PacificPokerToFpdb.determineGameType: '%s'") % tmp) 

176 raise FpdbParseError 

177 

178 mg = m.groupdict() 

179 #print "DEBUG: mg: ", mg 

180 if 'LIMIT' in mg: 

181 #print "DEBUG: re_GameInfo[LIMIT] \'", mg['LIMIT'], "\'" 

182 info['limitType'] = self.limits[mg['LIMIT']] 

183 if 'GAME' in mg: 

184 #print "DEBUG: re_GameInfo[GAME] \'", mg['GAME'], "\'" 

185 (info['base'], info['category']) = self.games[mg['GAME']] 

186 if 'SB' in mg: 

187 #print "DEBUG: re_GameInfo[SB] \'", mg['SB'], "\'" 

188 info['sb'] = self.clearMoneyString(mg['SB']) 

189 if 'BB' in mg: 

190 #print "DEBUG: re_GameInfo[BB] \'", mg['BB'], "\'" 

191 info['bb'] = self.clearMoneyString(mg['BB']) 

192 if 'CURRENCY1' in mg: 

193 #print "DEBUG: re_GameInfo[CURRENCY] \'", mg['CURRENCY'], "\'" 

194 info['currency'] = self.currencies[mg['CURRENCY1']] 

195 if 'CURRENCY2' in mg and mg['CURRENCY2']: 

196 #print "DEBUG: re_GameInfo[CURRENCY] \'", mg['CURRENCY'], "\'" 

197 info['currency'] = self.currencies[mg['CURRENCY2']] 

198 if 'FAST' in mg and mg['FAST'] is not None: 

199 info['fast'] = True 

200 

201 if 'TOURNO' in mg and mg['TOURNO'] is not None: 

202 info['type'] = 'tour' 

203 info['currency'] = 'T$' 

204 else: 

205 info['type'] = 'ring' 

206 

207 # Pacific Poker includes the blind levels in the gametype, the following is not needed. 

208 #if info['limitType'] == 'fl' and info['bb'] is not None and info['type'] == 'ring' and info['base'] != 'stud': 

209 # try: 

210 # info['sb'] = self.Lim_Blinds[mg['BB']][0] 

211 # info['bb'] = self.Lim_Blinds[mg['BB']][1] 

212 # except KeyError: 

213 # log.error(("determineGameType: Lim_Blinds has no lookup for '%s'" % mg['BB'])) 

214 # log.error(("determineGameType: Raising FpdbParseError")) 

215 # raise FpdbParseError(("Lim_Blinds has no lookup for '%s'") % mg['BB']) 

216 

217 return info 

218 

219 def readHandInfo(self, hand): 

220 info = {} 

221 m = self.re_HandInfo.search(hand.handText,re.DOTALL) 

222 if m is None: 

223 log.error("re_HandInfo could not be parsed") 

224 m2 = self.re_GameInfo.search(hand.handText) 

225 if m2 is None: 

226 log.error("re_GameInfo could not be parsed") 

227 if m is None or m2 is None: 

228 tmp = hand.handText[0:200] 

229 log.error(("PacificPokerToFpdb.readHandInfo: '%s'") % tmp) 

230 raise FpdbParseError 

231 

232 info.update(m.groupdict()) 

233 info.update(m2.groupdict()) 

234 

235 #log.debug("readHandInfo: %s" % info) 

236 for key in info: 

237 if key == 'DATETIME': 

238 # 28 11 2011 19:05:11 

239 m1 = self.re_DateTime.finditer(info[key]) 

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

241 for a in m1: 

242 datetimestr = "%s/%s/%s %s:%s:%s" % (a.group('Y'), a.group('M'),a.group('D'),a.group('H'),a.group('MIN'),a.group('S')) 

243 hand.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") 

244 hand.startTime = HandHistoryConverter.changeTimezone(hand.startTime, "ET", "UTC") 

245 hand.newFormat = datetime.datetime.strptime('20220908000000', '%Y%m%d%H%M%S') # this is a guess 

246 hand.newFormat = HandHistoryConverter.changeTimezone(hand.newFormat, "ET", "UTC") 

247 if key == 'HID': 

248 hand.handid = info[key] 

249 if key == 'TOURNO' and info['TOURNO'] != None: 

250 hand.tourNo = info[key] 

251 hand.isKO = False 

252 if key == 'BUYIN' and info['BUYIN'] != None: 

253 if info[key] == 'Free' or info['BIAMT'] is None: 

254 hand.buyin = 0 

255 hand.fee = 0 

256 hand.buyinCurrency = "FREE" 

257 else: 

258 if info['BUYIN'].find("$")!=-1: 

259 hand.buyinCurrency="USD" 

260 elif info['BUYIN'].find(u"€")!=-1: 

261 hand.buyinCurrency="EUR" 

262 elif 'PLAY' in info and info['PLAY'] != "Practice Play" and info['PLAY'] != "Play Money": 

263 hand.buyinCurrency="FREE" 

264 else: 

265 #FIXME: handle other currencies, FPP, play money 

266 log.error(("PacificPokerToFpdb.readHandInfo: Failed to detect currency.") + " Hand ID: %s: '%s'" % (hand.handid, info[key])) 

267 raise FpdbParseError 

268 

269 info['BIAMT'] = self.clearMoneyString(info['BIAMT'].strip(u'$€')) 

270 hand.buyin = int(100*Decimal(info['BIAMT'])) 

271 

272 if info['BIRAKE'] is None: 

273 hand.fee = 0 

274 else: 

275 info['BIRAKE'] = self.clearMoneyString(info['BIRAKE'].strip(u'$€')) 

276 hand.fee = int(100*Decimal(info['BIRAKE'])) 

277 

278 if key == 'TABLE' and info['TABLE'] != None: 

279 hand.tablename = info[key] 

280 if key == 'TABLEID' and info['TABLEID'] != None: 

281 hand.tablename = info[key] 

282 if key == 'BUTTON': 

283 hand.buttonpos = info[key] 

284 if key == 'MAX' and info['MAX'] != None: 

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

286 

287 if key == 'PLAY' and info['PLAY'] is not None: 

288 #hand.currency = 'play' # overrides previously set value 

289 hand.gametype['currency'] = 'play' 

290 

291 if 'TOURNO' in info and info['TOURNO'] is not None and hand.tablename == "": 

292 hand.tablename = 1 

293 

294 def readButton(self, hand): 

295 m = self.re_Button.search(hand.handText) 

296 if m: 

297 hand.buttonpos = int(m.group('BUTTON')) 

298 else: 

299 log.info('readButton: ' + ('not found')) 

300 

301 def readPlayerStacks(self, hand): 

302 m = self.re_PlayerInfo.finditer(hand.handText) 

303 for a in m: 

304 if (len(a.group('PNAME'))==0): 

305 log.error("PacificPokerToFpdb.readPlayerStacks: Player name empty %s" % hand.handid) 

306 raise FpdbParseError 

307 hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), self.clearMoneyString(a.group('CASH'))) 

308 

309 def markStreets(self, hand): 

310 # PREFLOP = ** Dealing down cards ** (observed hands don't have this line) 

311 # This re fails if, say, river is missing; then we don't get the ** that starts the river. 

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

313 m = re.search(r"(?P<PREFLOP>.+(?=\*\* Dealing flop \*\*)|.+)" 

314 r"(\*\* Dealing flop \*\* (?P<FLOP>\[ \S\S, \S\S, \S\S \].+(?=\*\* Dealing turn \*\*)|.+))?" 

315 r"(\*\* Dealing turn \*\* (?P<TURN>\[ \S\S \].+(?=\*\* Dealing river \*\*)|.+))?" 

316 r"(\*\* Dealing river \*\* (?P<RIVER>\[ \S\S \].+?(?=\*\* Summary \*\*)|.+))?" 

317 , hand.handText,re.DOTALL) 

318 if m is None: 

319 log.error(("PacificPokerToFpdb.markStreets: Unable to recognise streets %s" % hand.handid)) 

320 raise FpdbParseError 

321 else: 

322 #print "DEBUG: Matched markStreets" 

323 mg = m.groupdict() 

324# if 'PREFLOP' in mg: 

325# print "DEBUG: PREFLOP: ", [mg['PREFLOP']] 

326# if 'FLOP' in mg: 

327# print "DEBUG: FLOP: ", [mg['FLOP']] 

328# if 'TURN' in mg: 

329# print "DEBUG: TURN: ", [mg['TURN']] 

330# if 'RIVER' in mg: 

331# print "DEBUG: RIVER: ", [mg['RIVER']] 

332 

333 hand.addStreets(m) 

334 

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

336 if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP) 

337 #print "DEBUG readCommunityCards:", street, hand.streets.group(street) 

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

339 cards = self.splitCards(m.group('CARDS')) 

340 hand.setCommunityCards(street, cards) 

341 

342 def readAntes(self, hand): 

343 m = self.re_Antes.finditer(hand.handText) 

344 for player in m: 

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

346 hand.addAnte(player.group('PNAME'), self.clearMoneyString(player.group('ANTE'))) 

347 self.allInBlind(hand, 'PREFLOP', player, 'ante') 

348 

349 def readBringIn(self, hand): 

350 m = self.re_BringIn.search(hand.handText,re.DOTALL) 

351 if m: 

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

353 hand.addBringIn(m.group('PNAME'), m.group('BRINGIN')) 

354 

355 def readBlinds(self, hand): 

356 if hand.startTime < hand.newFormat: 

357 hand.setUncalledBets(True) 

358 liveBlind, hand.allInBlind = True, False 

359 for a in self.re_PostSB.finditer(hand.handText): 

360 if a.group('PNAME') in hand.stacks: 

361 if liveBlind: 

362 hand.addBlind(a.group('PNAME'), 'small blind', self.clearMoneyString(a.group('SB'))) 

363 liveBlind = False 

364 else: 

365 # Post dead blinds as ante 

366 hand.addBlind(a.group('PNAME'), 'secondsb', self.clearMoneyString(a.group('SB'))) 

367 self.allInBlind(hand, 'PREFLOP', a, 'secondsb') 

368 else: 

369 log.error("PacificPokerToFpdb.readBlinds (SB): '%s', '%s' not in hand.stacks" % (hand.handid, a.group('PNAME'))) 

370 raise FpdbParseError 

371 for a in self.re_PostBB.finditer(hand.handText): 

372 if a.group('PNAME') in hand.stacks: 

373 hand.addBlind(a.group('PNAME'), 'big blind', self.clearMoneyString(a.group('BB'))) 

374 self.allInBlind(hand, 'PREFLOP', a, 'big blind') 

375 else: 

376 log.error("PacificPokerToFpdb.readBlinds (BB): '%s', '%s' not in hand.stacks" % (hand.handid, a.group('PNAME'))) 

377 raise FpdbParseError 

378 for a in self.re_PostBoth.finditer(hand.handText): 

379 if a.group('PNAME') in hand.stacks: 

380 if Decimal(self.clearMoneyString(a.group('BB')))>0: 

381 bb = self.clearMoneyString(a.group('BB')) 

382 sb = self.clearMoneyString(a.group('SB')) 

383 both = str(Decimal(bb) + Decimal(sb)) 

384 hand.addBlind(a.group('PNAME'), 'both', both) 

385 else: 

386 hand.addBlind(a.group('PNAME'), 'secondsb', self.clearMoneyString(a.group('SB'))) 

387 self.allInBlind(hand, 'PREFLOP', a, 'both') 

388 else: 

389 log.error("PacificPokerToFpdb.readBlinds (Both): '%s', '%s' not in hand.stacks" % (hand.handid, a.group('PNAME'))) 

390 raise FpdbParseError 

391 

392 def readHoleCards(self, hand): 

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

394# we need to grab hero's cards 

395 for street in ('PREFLOP', 'DEAL'): 

396 if street in list(hand.streets.keys()): 

397 m = self.re_HeroCards.finditer(hand.streets[street]) 

398 for found in m: 

399# if m == None: 

400# hand.involved = False 

401# else: 

402 hand.hero = found.group('PNAME') 

403 newcards = self.splitCards(found.group('NEWCARDS')) 

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

405 

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

407 if not text or street in ('PREFLOP', 'DEAL'): continue # already done these 

408 m = self.re_HeroCards.finditer(hand.streets[street]) 

409 for found in m: 

410 player = found.group('PNAME') 

411 if found.group('NEWCARDS') is None: 

412 newcards = [] 

413 else: 

414 newcards = self.splitCards(found.group('NEWCARDS')) 

415 if found.group('OLDCARDS') is None: 

416 oldcards = [] 

417 else: 

418 oldcards = self.splitCards(found.group('OLDCARDS')) 

419 

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

421 hand.hero = player 

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

423 hand.addHoleCards(street, player, closed=newcards[0:2], open=[newcards[2]], shown=False, mucked=False, dealt=False) 

424 else: 

425 hand.addHoleCards(street, player, open=newcards, closed=oldcards, shown=False, mucked=False, dealt=False) 

426 

427 

428 def readAction(self, hand, street): 

429 m = self.re_Action.finditer(hand.streets[street]) 

430 for action in m: 

431 acts = action.groupdict() 

432 if street not in ('PREFLOP', 'DEAL'): 

433 hand.setUncalledBets(False) 

434 #print "DEBUG: acts: %s" %acts 

435 bet = self.clearMoneyString(action.group('BET')) if action.group('BET') else None 

436 if action.group('PNAME') in hand.stacks: 

437 if action.group('ATYPE') == ' folds': 

438 hand.addFold( street, action.group('PNAME')) 

439 elif action.group('ATYPE') == ' checks': 

440 hand.addCheck( street, action.group('PNAME')) 

441 elif action.group('ATYPE') == ' calls': 

442 hand.addCall( street, action.group('PNAME'), bet) 

443 elif action.group('ATYPE') == ' raises': 

444 hand.addCallandRaise( street, action.group('PNAME'), bet) 

445 elif action.group('ATYPE') == ' bets': 

446 hand.addBet( street, action.group('PNAME'), bet ) 

447 elif action.group('ATYPE') == ' discards': 

448 hand.addDiscard(street, action.group('PNAME'), bet, action.group('DISCARDED')) 

449 elif action.group('ATYPE') == ' stands pat': 

450 hand.addStandsPat( street, action.group('PNAME')) 

451 else: 

452 log.debug(("DEBUG:") + " " + "Unimplemented %s: '%s' '%s'") % ("readAction", action.group('PNAME'), action.group('ATYPE')) 

453 

454 if action.group('ATYPE') not in (' checks', ' folds'): 

455 if not hand.allInBlind: 

456 if not (hand.stacks[action.group('PNAME')]==0 and action.group('ATYPE') ==' calls' ): 

457 hand.setUncalledBets(False) 

458 if (hand.stacks[action.group('PNAME')]==0 and action.group('ATYPE') ==' raises' ): 

459 hand.checkForUncalled = True 

460 else: 

461 log.error("PacificPokerToFpdb.readAction: '%s', '%s' not in hand.stacks" % (hand.handid, action.group('PNAME'))) 

462 raise FpdbParseError 

463 

464 def allInBlind(self, hand, street, action, actiontype): 

465 if street in ('PREFLOP', 'DEAL'): 

466 if hand.stacks[action.group('PNAME')]==0: 

467 if actiontype=='ante': 

468 if action.group('PNAME') in [p for (p,b) in hand.posted]: 

469 hand.setUncalledBets(False) 

470 hand.checkForUncalled = True 

471 hand.allInBlind = True 

472 elif actiontype in ('secondsb', 'big blind', 'both') and not self.re_Antes.search(hand.handText): 

473 hand.setUncalledBets(False) 

474 hand.checkForUncalled = True 

475 hand.allInBlind = True 

476 

477 def readShowdownActions(self, hand): 

478 # TODO: pick up mucks also?? 

479 for shows in self.re_ShowdownAction.finditer(hand.handText): 

480 cards = shows.group('CARDS').split(', ') 

481 hand.addShownCards(cards, shows.group('PNAME')) 

482 

483 def readCollectPot(self,hand): 

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

485 #print "DEBUG: hand.addCollectPot(player=", m.group('PNAME'), ", pot=", m.group('POT'), ")" 

486 hand.addCollectPot(player=m.group('PNAME'),pot=self.clearMoneyString(m.group('POT'))) 

487 

488 def readShownCards(self,hand): 

489 for m in self.re_ShownCards.finditer(hand.handText): 

490 if m.group('CARDS') is not None: 

491 cards = m.group('CARDS') 

492 cards = self.splitCards(cards) 

493 

494 (shown, mucked) = (False, False) 

495 if m.group('SHOWED') == "shows": shown = True 

496 elif m.group('SHOWED') == "mucks": mucked = True 

497 

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

499 hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked) 

500 

501 def splitCards(self, cards): 

502 #Polish 

503 cards = cards.replace(u'Kreuz', 'c') 

504 cards = cards.replace(u'Karo', 'd') 

505 cards = cards.replace(u'Pik', 's') 

506 cards = cards.replace(u'Herz', 'h') 

507 cards = cards.replace(u'10', 'T') 

508 #Russian 

509 cards = cards.replace(u'\xd2', 'Q') 

510 cards = cards.replace(u'\xc2', 'A') 

511 cards = cards.replace(u'\xc4', 'J') 

512 #Spanish 

513 cards = self.re_Spanish_10.sub('T\g<1>', cards) 

514 cards = cards.replace(u't', 'h') 

515 cards = cards.replace(u'p', 's') 

516 cards = cards.replace(u'e', 'd') 

517 cards = cards.replace(u'o', 'h') 

518 #Dutch 

519 cards = cards.replace(u'B', 'J') 

520 cards = cards.replace(u'V', 'Q') 

521 cards = cards.replace(u'H', 'K') 

522 #Swedish 

523 cards = cards.replace(u'Kn', 'J') 

524 cards = cards.replace(u'D', 'Q') 

525 cards = cards.replace(u'E', 'A') 

526 cards = cards.split(', ') 

527 return cards 

528 

529 @staticmethod 

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

531 # Tournament tables look like: 

532 # Tour NLH 50+5 Brouhaha ID #28353026 Table #7 Blinds: 200/400 

533 log.info("Pacific.getTableTitleRe: table_name='%s' tournament='%s' table_number='%s'" % (table_name, tournament, table_number)) 

534 regex = "%s" % (table_name) 

535 if tournament: 

536 regex = "%s Table #%s" % (tournament, table_number) 

537 

538 log.info("Pacific.getTableTitleRe: returns: '%s'" % (regex)) 

539 return regex 

540 

541 def readSummaryInfo(self, summaryInfoList): 

542 self.status = True 

543 return self.status