Coverage for WinningToFpdb.py: 0%
618 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-28 16:41 +0000
« 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 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########################################################################
21#import L10n
22#_ = L10n.get_translation()
24# TODO: straighten out discards for draw games
26import sys
27from HandHistoryConverter import *
28from decimal_wrapper import Decimal
30# Winning HH Format
32class Winning(HandHistoryConverter):
34 # Class Variables
36 version = 0
37 sitename = "WinningPoker"
38 filetype = "text"
39 codepage = ("utf-16", "utf8", "cp1252")
40 siteId = 24 # Needs to match id entry in Sites database
41 sym = {
42 'USD': "\$",
43 'T$': "",
44 "play": ""
45 }
46 substitutions = {
47 'LEGAL_ISO': "USD|TB|CP", # legal ISO currency codes
48 'LS': u"\$|", # legal currency symbols - Euro(cp1252, utf-8)
49 'PLYR': r'(?P<PNAME>.+?)',
50 'NUM':u".,\dK",
51 'CUR': u"(\$|)",
52 'BRKTS': r'(\(button\)\s|\(small\sblind\)\s|\(big\sblind\)\s|\(button\)\s\(small\sblind\)\s|\(button\)\s\(big\sblind\)\s)?',
53 }
54 games1 = {# base, category
55 "Hold'em": ('hold', 'holdem'),
56 "Six Plus Hold'em": ('hold', '6_holdem'),
57 'Omaha': ('hold', 'omahahi'),
58 'Omaha HiLow': ('hold', 'omahahilo'),
59 '5Card Omaha H/L': ('hold', '5_omaha8'),
60 '5Card Omaha': ('hold', '5_omaha'),
61 'Seven Cards Stud': ('stud', 'studhi'),
62 'Seven Cards Stud HiLow': ('stud', 'studhilo')
63 }
64 games2 = {# base, category
65 "Holdem": ('hold', 'holdem'),
66 'Omaha': ('hold', 'omahahi'),
67 'Omaha H/L': ('hold', 'omahahilo'),
68 '5Card Omaha H/L': ('hold', '5_omaha8'),
69 '5Card Omaha': ('hold', '5_omaha'),
70 #"Six Plus Hold'em" : ('hold','6_holdem'),
71 '7Stud': ('stud', 'studhi'),
72 '7Stud H/L': ('stud', 'studhilo')
73 }
74 limits = {
75 'No Limit': 'nl',
76 'Pot Limit': 'pl',
77 'Fixed Limit': 'fl',
78 'All-in or Fold Limit': 'al'
79 }
80 speeds = {
81 'Turbo': 'Turbo',
82 'Hyper Turbo': 'Hyper',
83 'Regular': 'Normal'
84 }
85 buyin = {
86 'CAP': 'cap',
87 'Short': 'shallow'
88 }
90 SnG_Fee = {
91 50: {'Hyper': 0, 'Turbo': 0, 'Normal': 5},
92 100: {'Hyper': 0, 'Turbo': 0, 'Normal': 10},
93 150: {'Hyper': 11, 'Turbo': 12, 'Normal': 15},
94 300: {'Hyper': 20, 'Turbo': 25, 'Normal': 30},
95 500: {'Hyper': 30, 'Turbo': 45, 'Normal': 50},
96 1000: {'Hyper': 55, 'Turbo': 90, 'Normal': 100},
97 1500: {'Hyper': 80, 'Turbo': 140, 'Normal': 150},
98 2000: {'Hyper': 100, 'Turbo': 175, 'Normal': 200},
99 3000: {'Hyper': 130, 'Turbo': 275, 'Normal': 300},
100 5000: {'Hyper': 205, 'Turbo': 475, 'Normal': 500},
101 8000: {'Hyper': 290, 'Turbo': 650, 'Normal': 800},
102 10000: {'Hyper': 370, 'Turbo': 800, 'Normal': 900}
103 }
105 HUSnG_Fee = {
106 200: {'Hyper': 10, 'Turbo': 0, 'Normal': 17},
107 220: {'Hyper': 0, 'Turbo': 16, 'Normal': 0},
108 240: {'Hyper': 10, 'Turbo': 0, 'Normal': 0},
109 500: {'Hyper': 0, 'Turbo': 0, 'Normal': 25},
110 550: {'Hyper': 0, 'Turbo': 25, 'Normal': 0},
111 600: {'Hyper': 18, 'Turbo': 0, 'Normal': 0},
112 1000: {'Hyper': 25, 'Turbo': 0, 'Normal': 50},
113 1100: {'Hyper': 0, 'Turbo': 50, 'Normal': 0},
114 1200: {'Hyper': 25, 'Turbo': 0, 'Normal': 0},
115 2000: {'Hyper': 50, 'Turbo': 0, 'Normal': 100},
116 2200: {'Hyper': 0, 'Turbo': 100, 'Normal': 0},
117 2400: {'Hyper': 50, 'Turbo': 0, 'Normal': 0},
118 3000: {'Hyper': 70, 'Turbo': 0, 'Normal': 150},
119 3300: {'Hyper': 0, 'Turbo': 150, 'Normal': 0},
120 3600: {'Hyper': 75, 'Turbo': 0, 'Normal': 0},
121 5000: {'Hyper': 100, 'Turbo': 0, 'Normal': 250},
122 5500: {'Hyper': 0, 'Turbo': 250, 'Normal': 0},
123 6000: {'Hyper': 125, 'Turbo': 0, 'Normal': 0},
124 10000: {'Hyper': 200, 'Turbo': 0, 'Normal': 450},
125 11000: {'Hyper': 0, 'Turbo': 450, 'Normal': 0},
126 12000: {'Hyper': 225, 'Turbo': 0, 'Normal': 0},
127 15000: {'Hyper': 266, 'Turbo': 0, 'Normal': 0},
128 20000: {'Hyper': 400, 'Turbo': 0, 'Normal': 900},
129 22000: {'Hyper': 0, 'Turbo': 900, 'Normal': 0},
130 24000: {'Hyper': 450, 'Turbo': 0, 'Normal': 0},
131 30000: {'Hyper': 600, 'Turbo': 0, 'Normal': 1200},
132 33000: {'Hyper': 0, 'Turbo': 1200, 'Normal': 0},
133 36000: {'Hyper': 600, 'Turbo': 0, 'Normal': 0},
134 40000: {'Hyper': 800, 'Turbo': 0, 'Normal': 0},
135 50000: {'Hyper': 0, 'Turbo': 0, 'Normal': 5000},
136 55000: {'Hyper': 0, 'Turbo': 2000, 'Normal': 0},
137 60000: {'Hyper': 1000, 'Turbo': 0, 'Normal': 0},
138 110000: {'Hyper': 0, 'Turbo': 3000, 'Normal': 0},
139 120000: {'Hyper': 1500, 'Turbo': 0, 'Normal': 0}
140 }
141 currencies = { '$':'USD', '':'T$'}
143 re_GameInfo1 = re.compile(u"""
144 Game\sID:\s(?P<HID>\d+)\s
145 (?P<SB>[%(NUM)s]+)/(?P<BB>[%(NUM)s]+)\s
146 (?P<TABLE>.+?)?\s
147 \((?P<GAME>(Six\sPlus\s)?Hold\'em|Omaha|Omaha\sHiLow|Seven\sCards\sStud|Seven\sCards\sStud\sHiLow)\)
148 (\s(?P<MAX>\d+\-max))?$
149 """ % substitutions,
150 re.MULTILINE|re.VERBOSE
151 )
153 #Hand #78708209 - Omaha H/L(Fixed Limit) - $20.00/$40.00 - 2019/07/18 15:13:01 UTC
154 #Hand #68217077 - Holdem(No Limit) - $0.05/$0.10 - 2019/06/28 02:38:17 UTC
155 #Game Hand #80586589 - Tournament #11182752 - Holdem(No Limit) - Level 15 (250.00/500.00)- 2019/07/21 17:44:50 UTC
156 #Game Hand #82980175 - Tournament #11212445 - Omaha H/L(Pot Limit) - Level 1 (250.00/500.00)- 2019/07/25 02:31:33 UTC
158 re_GameInfo2 = re.compile(u"""
159 (Game\s)?Hand\s\#(?P<HID>[0-9]+)\s\-\s
160 (
161 (?P<TOUR>([\$.,\dK]+\sGTD\s)?Tournament\s\#(?P<TOURNO>\d+)\s\-\s) # open paren of tournament info
162 )?
163 # close paren of tournament info
164 (?P<GAME>Holdem|Omaha|Omaha\sH/L|5Card\sOmaha\sH/L|5Card\sOmaha|7Stud|7Stud\sH/L)
165 \((?P<LIMIT>No\sLimit|Fixed\sLimit|Pot\sLimit|All\-in\sor\sFold\sLimit)\)\s\-\s
166 (Level\s(?P<LEVEL>[IVXLC\d]+)\s)?
167 \(? # open paren of the stakes
168 (?P<CURRENCY>%(LS)s|)?
169 ((?P<SB>[.0-9]+)/(%(LS)s)?(?P<BB>[.0-9]+))
170 \)? # close paren of the stakes
171 \s?\-\s
172 (?P<DATETIME>.*$)
173 """ % substitutions, re.MULTILINE|re.VERBOSE)
175 #Seat 6: puccini (5.34).
176 re_PlayerInfo1 = re.compile(u"""
177 ^Seat\s(?P<SEAT>[0-9]+):\s
178 (?P<PNAME>.*)\s
179 \((?P<CASH>[%(NUM)s]+)\)
180 \.$
181 """ % substitutions,
182 re.MULTILINE|re.VERBOSE
183 )
185 re_PlayerInfo2 = re.compile(u"""
186 ^\s?Seat\s(?P<SEAT>[0-9]+):\s
187 (?P<PNAME>.*)\s
188 \((%(LS)s)?(?P<CASH>[,.0-9]+)
189 \)
190 (?P<SITOUT>\sis\ssitting\sout)?""" % substitutions,
191 re.MULTILINE|re.VERBOSE
192 )
194 re_DateTime1 = re.compile("""
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 )
202 #2019/07/18 15:13:01 UTC
203 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]+):(?P<S>[0-9]+)""", re.MULTILINE)
205 #$2.20 Turbo Heads-up, Table 1
206 #$2.40 Hyper Turbo Heads-up, Table 1
207 #$10 Freeroll - On Demand, Table 13
208 #$25 GTD - On Demand, Table 1
209 #$5 Regular 9-Max, Table 1 (Hold'em)
211 re_Table1 = re.compile(u"""
212 ^(?P<CURRENCY>[%(LS)s]|)?(?P<BUYIN>[%(NUM)s]+)\s
213 ((?P<GAME>(Six\sPlus\s)?Holdem|PLO|PLO8|Omaha\sHi/Lo|Omaha|PL\sOmaha|PL\sOmaha\sHi/Lo|PLO\sHi/Lo)\s?)?
214 ((?P<SPECIAL>(GTD|Freeroll|FREEBUY|Freebuy))\s?)?
215 ((?P<SPEED>(Turbo|Hyper\sTurbo|Regular))\s?)?
216 ((?P<MAX>(\d+\-Max|Heads\-up|Heads\-Up))\s?)?
217 (?P<OTHER>.*?)
218 ,\sTable\s(?P<TABLENO>\d+)
219 """ % substitutions,
220 re.VERBOSE|re.MULTILINE
221 )
223 re_Table2 = re.compile("Table\s\'(?P<TABLENO>\d+)\'")
225 #St. Lucie 6-max Seat #1 is the button
226 #Table '1' 9-max Seat #3 is the button
227 #Blitz Poker 6-max Seat #1 is the button
228 #Table '25' 9-max Seat #8 is the button
230 re_HandInfo = re.compile("""
231 ^(?P<TABLE>.+?)\s
232 ((?P<MAX>\d+)-max\s)
233 (?P<PLAY>\(Play\sMoney\)\s)?
234 (Seat\s\#(?P<BUTTON>\d+)\sis\sthe\sbutton)?""",
235 re.MULTILINE|re.VERBOSE)
237 re_TourneyName1 = re.compile(u"(?P<TOURNAME>.*),\sTable\s\d+")
238 re_TourneyName2 = re.compile(u"TN\-(?P<TOURNAME>.+?)\sGAMETYPE")
239 re_GTD = re.compile(u"(?P<GTD>[%(NUM)s]+)\sGTD" % substitutions)
240 re_buyinType = re.compile("\((?P<BUYINTYPE>CAP|Short)\)", re.MULTILINE)
241 re_buyin = re.compile("%(CUR)s(?P<BUYIN>[,.0-9]+)" % substitutions, re.MULTILINE)
242 re_Step = re.compile("\sStep\s(?P<STEPNO>\d+)")
244 re_Identify = re.compile(u'Game\sID:\s\d+|Hand\s\#\d+\s\-\s')
245 re_Identify_Old = re.compile(u'Game\sID:\s\d+')
246 re_SplitHands = re.compile('\n\n')
247 re_Button1 = re.compile('Seat (?P<BUTTON>\d+) is the button')
248 re_Button2 = re.compile('Seat #(?P<BUTTON>\d+) is the button')
249 re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
250 re_TourNo = re.compile("\sT(?P<TOURNO>\d+)\-")
251 re_File1 = re.compile("HH\d{8}\s(T\d+\-)?G\d+")
252 re_File2 = re.compile("(?P<TYPE>CASHID|SITGOID|RUSHID|SCHEDULEDID)")
254 re_PostSB1 = re.compile(r"^Player %(PLYR)s has small blind \((?P<SB>[%(NUM)s]+)\)" % substitutions, re.MULTILINE)
255 re_PostBB1 = re.compile(r"^Player %(PLYR)s has big blind \((?P<BB>[%(NUM)s]+)\)" % substitutions, re.MULTILINE)
256 re_Posts1 = re.compile(r"^Player %(PLYR)s posts \((?P<SBBB>[%(NUM)s]+)\)" % substitutions, re.MULTILINE)
257 re_Antes1 = re.compile(r"^Player %(PLYR)s (posts )?ante \((?P<ANTE>[%(NUM)s]+)\)" % substitutions, re.MULTILINE)
258 re_BringIn1 = re.compile(r"^Player %(PLYR)s bring in \((?P<BRINGIN>[%(NUM)s]+)\)" % substitutions, re.MULTILINE)
259 re_HeroCards1 = re.compile(r"^Player %(PLYR)s received card: \[(?P<CARD>.+)\]" % substitutions, re.MULTILINE)
261 re_PostSB2 = re.compile(r"^%(PLYR)s posts the small blind %(CUR)s(?P<SB>[,.0-9]+)" % substitutions, re.MULTILINE)
262 re_PostBB2 = re.compile(r"^%(PLYR)s posts the big blind %(CUR)s(?P<BB>[,.0-9]+)" % substitutions, re.MULTILINE)
263 re_PostBoth2 = re.compile(r"^%(PLYR)s posts dead %(CUR)s(?P<SBBB>[,.0-9]+)" % substitutions, re.MULTILINE)
264 re_Posts2 = re.compile(r"^%(PLYR)s posts %(CUR)s(?P<SBBB>[,.0-9]+)" % substitutions, re.MULTILINE)
265 re_Antes2 = re.compile(r"^%(PLYR)s posts ante %(CUR)s(?P<ANTE>[,.0-9]+)" % substitutions, re.MULTILINE)
266 re_BringIn2 = re.compile(r"^%(PLYR)s brings[- ]in( low|) %(CUR)s(?P<BRINGIN>[,.0-9]+)" % substitutions, re.MULTILINE)
267 re_HeroCards2 = re.compile(r"^Dealt to %(PLYR)s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % substitutions, re.MULTILINE)
268 re_Uncalled = re.compile('Uncalled bet \(%(CUR)s(?P<BET>[,.\d]+)\) returned to' % substitutions, re.MULTILINE)
270 re_Action1 = re.compile(r"""
271 ^Player\s(%(PLYR)s)?\s(?P<ATYPE>bets|checks|raises|calls|folds|allin|straddle|caps|cap)
272 (\s\((?P<BET>[%(NUM)s]+)\))?
273 $""" % substitutions,
274 re.MULTILINE|re.VERBOSE
275 )
277 re_Action2 = re.compile(r"""
278 ^%(PLYR)s(?P<ATYPE>\sbets|\schecks|\sraises|\scalls|\sfolds|\scaps|\scap|\sstraddle)
279 (\s%(CUR)s(?P<BET>[,.\d]+))?(\sto\s%(CUR)s(?P<BETTO>[,.\d]+))?
280 \s*(and\sis\sall\-in)?\s*$"""
281 % substitutions, re.MULTILINE|re.VERBOSE
282 )
284 #Player lessthanrocko shows: Two pairs. 8s and 5s [3s 3h]. Bets: 420. Collects: 0. Loses: 420.
285 #*Player ChazDazzle shows: Full House (5/8) [7s 5s]. Bets: 420. Collects: 840. Wins: 420.
286 #*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.
288 #*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.
289 #*Player KickAzzJohnny shows: Two pairs. 8s and 3s [5d 3d 3s 6s 8s 8h Ad]. Bets: 3.55. Collects: 3.52. Loses: 0.03.
291 re_ShownCards1 = re.compile(r"""
292 ^\*?Player\s%(PLYR)s\sshows:\s
293 (?P<STRING>.+?)\s
294 \[(?P<CARDS>.*)\]
295 (\sLow\shand\s\((?P<STRING2>.+?)\s?\))?
296 \.""" % substitutions,
297 re.MULTILINE|re.VERBOSE
298 )
300 #Seat 5: LitAF did not show and won $0.25
301 #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]
302 re_ShownCards2 = re.compile(r"""
303 ^Seat\s(?P<SEAT>[0-9]+):\s%(PLYR)s\s%(BRKTS)s
304 (?P<SHOWED>showed|mucked)\s\[(?P<CARDS>.+?)\](\sand\s(lost|(won|collected)\s%(CUR)s(?P<POT>[,\.\d]+))
305 \swith (?P<STRING>.+?)
306 (,\sand\s(won\s\(%(CUR)s[\.\d]+\)|lost)\swith\s(?P<STRING2>.*))?)?
307 $"""
308 % substitutions,
309 re.MULTILINE|re.VERBOSE
310 )
312 re_CollectPot1 = re.compile(r"""
313 ^\*?Player\s%(PLYR)s\s
314 (does\snot\sshow|shows|mucks)
315 .+?\.\s?
316 Bets:\s[%(NUM)s]+\.\s
317 Collects:\s(?P<POT>[%(NUM)s]+)\.\s
318 (Wins|Loses):\s[%(NUM)s]+\.?
319 $""" % substitutions,
320 re.MULTILINE|re.VERBOSE
321 )
323 #Seat 5: LitAF did not show and won $0.25
324 #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]
325 re_CollectPot2 = re.compile(r"""
326 Seat\s(?P<SEAT>[0-9]+):\s%(PLYR)s\s%(BRKTS)s
327 (did\snot\sshow\sand\swon|showed\s\[.+?\]\sand\s(won|collected))\s%(CUR)s(?P<POT>[,.\d]+)
328 (,\smucked|\swith.*|)
329 """ % substitutions,
330 re.MULTILINE|re.VERBOSE
331 )
332 #AssFungus collected $92.25 from main pot 1
333 re_CollectPot3 = re.compile(r"^%(PLYR)s collected %(CUR)s(?P<POT>[,.\d]+)" % substitutions, re.MULTILINE)
335 def compilePlayerRegexs(self, hand):
336 pass
338 def readSupportedGames(self):
339 return [
340 ["ring", "hold", "nl"],
341 ["ring", "hold", "fl"],
342 ["ring", "hold", "pl"],
343 ["ring", "hold", "al"],
345 ["ring", "stud", "fl"],
347 ["tour", "hold", "nl"],
348 ["tour", "hold", "fl"],
349 ["tour", "hold", "pl"],
350 ["tour", "hold", "al"],
352 ["tour", "stud", "fl"]
353 ]
355 def determineGameType(self, handText):
356 if self.re_Identify_Old.search(handText):
357 self.version = 1
358 return self._determineGameType1(handText)
359 else:
360 self.version = 2
361 return self._determineGameType2(handText)
363 def _determineGameType1(self, handText):
364 info = {}
365 if not self.re_File1.search(self.in_path):
366 tmp = "Invalid filename: %s" % self.in_path
367 log.debug(("WinningToFpdb.determineGameType: '%s'") % tmp)
368 raise FpdbHandPartial(tmp)
370 m = self.re_GameInfo1.search(handText)
371 if not m:
372 tmp = handText[0:200]
373 log.error(("WinningToFpdb.determineGameType: '%s'") % tmp)
374 raise FpdbParseError
376 mg = m.groupdict()
377 m1 = self.re_TourNo.search(self.in_path)
378 if m1: mg.update(m1.groupdict())
380 if 'GAME' in mg:
381 (info['base'], info['category']) = self.games1[mg['GAME']]
382 if 'SB' in mg:
383 info['sb'] = mg['SB']
384 if 'BB' in mg:
385 info['bb'] = mg['BB']
387 if info['base'] == 'stud':
388 info['limitType'] = 'fl'
389 else:
390 m2 = self.re_PostBB1.search(handText)
391 if m2:
392 bb = self.clearMoneyString(m2.group('BB'))
393 if Decimal(self.clearMoneyString(info['sb'])) == Decimal(bb):
394 info['limitType'] = 'fl'
396 if info.get('limitType') == None:
397 if 'omaha' in info['category']:
398 info['limitType'] = 'pl'
399 else:
400 info['limitType'] = 'nl'
402 if 'TOURNO' in mg and mg['TOURNO'] is not None:
403 info['type'] = 'tour'
404 else:
405 info['type'] = 'ring'
407 if 'TABLE' in mg and mg['TABLE'] is not None:
408 if re.match('PM\s',mg['TABLE']):
409 info['currency'] = 'play'
410 elif info['type'] == 'tour':
411 info['currency'] = 'T$'
412 else:
413 info['currency'] = 'USD'
415 if '(Cap)' in mg['TABLE']:
416 info['buyinType'] = 'cap'
417 elif '(Short)' in mg['TABLE']:
418 info['buyinType'] = 'shallow'
419 else:
420 info['buyinType'] = 'regular'
421 else:
422 info['currency'] = 'T$'
424 if info['limitType'] == 'fl' and info['bb'] is not None:
425 info['sb'] = str((Decimal(mg['SB'])/2).quantize(Decimal("0.01")))
426 info['bb'] = str(Decimal(mg['SB']).quantize(Decimal("0.01")))
428 return info
430 def _determineGameType2(self, handText):
431 info = {}
432 m = self.re_GameInfo2.search(handText)
433 if not m:
434 tmp = handText[0:200]
435 log.error(("WinningToFpdb._determineGameType2: '%s'") % tmp)
436 raise FpdbParseError
438 mg = m.groupdict()
440 m1 = self.re_File2.search(self.in_path)
441 if m1: mg.update(m1.groupdict())
443 if 'LIMIT' in mg:
444 info['limitType'] = self.limits[mg['LIMIT']]
445 if 'GAME' in mg:
446 (info['base'], info['category']) = self.games2[mg['GAME']]
447 if 'SB' in mg:
448 info['sb'] = mg['SB']
449 if 'BB' in mg:
450 info['bb'] = mg['BB']
451 if 'CURRENCY' in mg and mg['CURRENCY'] is not None:
452 info['currency'] = self.currencies[mg['CURRENCY']]
454 if 'TYPE' in mg and 'RUSHID' == mg['TYPE']:
455 info['fast'] = True
456 else:
457 info['fast'] = False
459 if 'TOURNO' in mg and mg['TOURNO'] is None:
460 info['type'] = 'ring'
461 else:
462 info['type'] = 'tour'
464 if info.get('currency') in ('T$', None) and info['type']=='ring':
465 info['currency'] = 'play'
467 if info['limitType'] == 'fl' and info['bb'] is not None:
468 info['sb'] = str((Decimal(mg['SB'])/2).quantize(Decimal("0.01")))
469 info['bb'] = str(Decimal(mg['SB']).quantize(Decimal("0.01")))
471 return info
473 def readHandInfo(self, hand):
474 if self.version == 1:
475 self._readHandInfo1(hand)
476 else:
477 self._readHandInfo2(hand)
479 def _readHandInfo1(self, hand):
480 #First check if partial
481 if hand.handText.count('------ Summary ------')!=1:
482 raise FpdbHandPartial(("Hand is not cleanly split into pre and post Summary"))
484 info = {}
485 m = self.re_GameInfo1.search(hand.handText)
486 m2 = self.re_DateTime1.search(hand.handText)
487 if m is None or m2 is None:
488 tmp = hand.handText[0:200]
489 log.error(("WinningToFpdb.readHandInfo: '%s'") % tmp)
490 raise FpdbParseError
492 info.update(m.groupdict())
494 m1 = self.re_TourNo.search(self.in_path)
495 if m1: info.update(m1.groupdict())
497 datetimestr = "%s/%s/%s %s:%s:%s" % (m2.group('Y'), m2.group('M'), m2.group('D'), m2.group('H'), m2.group('MIN'), m2.group('S'))
498 hand.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET"
499 hand.startTime = HandHistoryConverter.changeTimezone(hand.startTime, self.import_parameters['timezone'], "UTC")
501 if 'TOURNO' in info:
502 hand.tourNo = info['TOURNO']
504 if 'HID' in info:
505 hand.handid = info['HID']
507 if 'MAX' in info and info['MAX'] != None:
508 hand.maxseats = int(info['MAX'].replace('-max', ''))
510 if not hand.maxseats:
511 if hand.gametype['base'] == 'stud':
512 hand.maxseats = 8
513 elif hand.gametype['type'] == 'ring':
514 hand.maxseats = 9
515 else:
516 hand.maxseats = 10
518 if 'TABLE' in info and info['TABLE'] is not None:
519 if hand.tourNo:
520 hand.buyin = 0
521 hand.fee = 0
522 hand.buyinCurrency="NA"
523 hand.tablename = 1
524 m3 = self.re_Table1.search(info['TABLE'])
525 if m3 is not None:
526 tableinfo = m3.groupdict()
527 if 'SPECIAL' in tableinfo and tableinfo['SPECIAL'] != None:
528 if tableinfo['SPECIAL'] in ('Freeroll', 'FREEBUY', 'Freebuy'):
529 hand.buyinCurrency="FREE"
530 hand.guaranteeAmt = int(100*Decimal(self.clearMoneyString(tableinfo['BUYIN'])))
532 if hand.guaranteeAmt == 0:
533 hand.buyinCurrency="USD"
534 hand.buyin = int(100*Decimal(self.clearMoneyString(tableinfo['BUYIN'])))
536 if 'MAX' in tableinfo and tableinfo['MAX'] != None:
537 n = tableinfo['MAX'].replace('-Max', '')
538 if n in ('Heads-up', 'Heads-Up'):
539 hand.maxseats = 2
540 else:
541 hand.maxseats = int(n)
543 if 'SPEED' in tableinfo and tableinfo['SPEED'] != None:
544 hand.speed = self.speeds[tableinfo['SPEED']]
545 if hand.maxseats==2 and hand.buyin in self.HUSnG_Fee:
546 hand.fee = self.HUSnG_Fee[hand.buyin][hand.speed]
547 hand.isSng = True
548 if hand.maxseats!=2 and hand.buyin in self.SnG_Fee:
549 hand.fee = self.SnG_Fee[hand.buyin][hand.speed]
550 hand.isSng = True
552 hand.tablename = int(m3.group('TABLENO'))
554 if "On Demand" in info['TABLE']:
555 hand.isOnDemand = True
557 if " KO" in info['TABLE'] or "Knockout" in info['TABLE']:
558 hand.isKO = True
560 if "R/A" in info['TABLE']:
561 hand.isRebuy = True
562 hand.isAddOn = True
564 m4 = self.re_TourneyName1.search(info['TABLE'])
565 if m4:
566 hand.tourneyName = m4.group('TOURNAME')
567 else:
568 hand.tablename = info['TABLE']
569 buyin_type = self.re_buyinType.search(info['TABLE'])
570 if buyin_type:
571 hand.gametype['buyinType'] = self.buyin[buyin_type.group('BUYINTYPE')]
572 else:
573 hand.buyin = 0
574 hand.fee = 0
575 hand.buyinCurrency="NA"
576 hand.tablename = 1
578 def _readHandInfo2(self, hand):
579 #First check if partial
580 if hand.handText.count('*** SUMMARY ***')!=1:
581 raise FpdbHandPartial(("Hand is not cleanly split into pre and post Summary"))
583 info = {}
584 m = self.re_GameInfo2.search(hand.handText)
585 m1 = self.re_HandInfo.search(hand.handText)
586 if m is None or m1 is None:
587 tmp = hand.handText[0:200]
588 log.error(("WinningToFpdb.readHandInfo: '%s'") % tmp)
589 raise FpdbParseError
591 info.update(m.groupdict())
592 info.update(m1.groupdict())
594 for key in info:
595 if key == 'DATETIME':
596 datetimestr = "2000/01/01 00:00:00" # default used if time not found
597 m2 = self.re_DateTime2.finditer(info[key])
598 for a in m2:
599 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'))
600 #tz = a.group('TZ') # just assume ET??
601 #print " tz = ", tz, " datetime =", datetimestr
602 hand.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET"
603 if key == 'HID':
604 hand.handid = info[key]
605 if key == 'TOURNO':
606 hand.tourNo = info[key]
607 if key == 'LEVEL':
608 hand.level = info[key]
609 if key == 'TABLE':
610 if info['TOURNO'] is not None:
611 hand.buyin = 0
612 hand.fee = 0
613 hand.buyinCurrency = "FREE" #FIXME
615 m2 = self.re_Table2.match(info[key])
616 if m2:
617 hand.tablename = m2.group('TABLENO')
618 else:
619 hand.tablename = info[key]
620 if key == 'BUTTON':
621 hand.buttonpos = info[key]
622 if key == 'MAX' and info[key] != None:
623 hand.maxseats = int(info[key])
625 if 'SCHEDULEDID' in self.in_path:
626 m3 = self.re_TourneyName2.search(self.in_path)
627 if m3:
628 hand.tourneyName = m3.group('TOURNAME').replace('{BACKSLASH}', '\\')
629 m4 = self.re_GTD.search(hand.tourneyName)
630 if m4:
631 hand.isGuarantee = True
632 hand.guaranteeAmt = int(100*Decimal(self.clearMoneyString(m4.group('GTD'))))
633 if 'Satellite' in hand.tourneyName:
634 hand.isSatellite = True
635 if 'Shootout' in hand.tourneyName:
636 hand.isShootout = True
638 elif 'SITGOID' in self.in_path:
639 hand.isSng = True
640 m3 = self.re_TourneyName2.search(self.in_path)
641 if m3:
642 hand.tourneyName = m3.group('TOURNAME').replace('{BACKSLASH}', '\\')
643 if ' Hyper Turbo ' in hand.tourneyName:
644 speed = 'Hyper Turbo'
645 elif ' Turbo ' in hand.tourneyName:
646 speed = 'Turbo'
647 else:
648 speed = 'Regular'
650 hand.speed = self.speeds[speed]
652 m4 = self.re_buyin.match(hand.tourneyName)
653 if m4:
654 hand.buyinCurrency="USD"
655 hand.buyin = int(100*Decimal(self.clearMoneyString(m4.group('BUYIN'))))
657 if hand.maxseats==2 and hand.buyin in self.HUSnG_Fee:
658 hand.fee = self.HUSnG_Fee[hand.buyin][hand.speed]
659 if hand.maxseats!=2 and hand.buyin in self.SnG_Fee:
660 hand.fee = self.SnG_Fee[hand.buyin][hand.speed]
662 m5 = self.re_Step.search(hand.tourneyName)
663 if m5:
664 hand.isStep = True
665 hand.stepNo = int(m5.group('STEPNO'))
667 elif 'RUSHID' in self.in_path:
668 (hand.gametype['fast'], hand.isFast) = (True, True)
670 def readButton(self, hand):
671 if self.version == 1:
672 self._readButton1(hand)
673 else:
674 self._readButton2(hand)
676 def _readButton1(self, hand):
677 m = self.re_Button1.search(hand.handText)
678 if m:
679 hand.buttonpos = int(m.group('BUTTON'))
680 else:
681 log.info('readButton: ' + ('not found'))
683 def _readButton2(self, hand):
684 m = self.re_Button2.search(hand.handText)
685 if m:
686 hand.buttonpos = int(m.group('BUTTON'))
687 else:
688 log.info('readButton: ' + ('not found'))
690 def readPlayerStacks(self, hand):
691 if self.version == 1:
692 self._readPlayerStacks1(hand)
693 else:
694 self._readPlayerStacks2(hand)
696 def _readPlayerStacks1(self, hand):
697 pre, post = hand.handText.split('------ Summary ------')
698 m = self.re_PlayerInfo1.finditer(pre)
699 for a in m:
700 hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), self.clearMoneyString(a.group('CASH')))
702 def _readPlayerStacks2(self, hand):
703 pre, post = hand.handText.split('*** SUMMARY ***')
704 m = self.re_PlayerInfo2.finditer(pre)
705 for a in m:
706 hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), self.clearMoneyString(a.group('CASH')))
708 def markStreets(self, hand):
709 if self.version ==1:
710 self._markStreets1(hand)
711 else:
712 self._markStreets2(hand)
714 def _markStreets1(self, hand):
715 if hand.gametype['base'] in ("hold"):
716 m = re.search(r"(?P<PREFLOP>.+(?=\*\*\* FLOP \*\*\*:)|.+)"
717 r"(\*\*\* FLOP \*\*\*:(?P<FLOP> (\[\S\S\S?] )?\[\S\S\S? ?\S\S\S? \S\S\S?].+(?=\*\*\* TURN \*\*\*:)|.+))?"
718 r"(\*\*\* TURN \*\*\*: \[\S\S\S? \S\S\S? \S\S\S?] (?P<TURN>\[\S\S\S?\].+(?=\*\*\* RIVER \*\*\*:)|.+))?"
719 r"(\*\*\* RIVER \*\*\*: \[\S\S\S? \S\S\S? \S\S\S? \S\S\S?] ?(?P<RIVER>\[\S\S\S?\].+))?", hand.handText,re.DOTALL)
720 elif hand.gametype['base'] in ("stud"):
721 m = re.search(r"(?P<THIRD>.+(?=\*\*\* Third street \*\*\*)|.+)"
722 r"(\*\*\* Third street \*\*\*(?P<FOURTH>.+(?=\*\*\* Fourth street \*\*\*)|.+))?"
723 r"(\*\*\* Fourth street \*\*\*(?P<FIFTH>.+(?=\*\*\* Fifth street \*\*\*)|.+))?"
724 r"(\*\*\* Fifth street \*\*\*(?P<SIXTH>.+(?=\*\*\* Sixth street \*\*\*)|.+))?"
725 r"(\*\*\* Sixth street \*\*\*(?P<SEVENTH>.+))?", hand.handText,re.DOTALL)
726 hand.addStreets(m)
728 def _markStreets2(self, hand):
729 if hand.gametype['base'] in ("hold"):
730 m = re.search(r"\*\*\* HOLE CARDS \*\*\*(?P<PREFLOP>(.+(?P<FLOPET>\[\S\S\]))?.+(?=\*\*\* (FLOP|FIRST FLOP|FLOP 1) \*\*\*)|.+)"
731 r"(\*\*\* FLOP \*\*\*(?P<FLOP> (\[\S\S\] )?\[(\S\S ?)?\S\S \S\S\].+(?=\*\*\* (TURN|FIRST TURN|TURN 1) \*\*\*)|.+))?"
732 r"(\*\*\* TURN \*\*\* \[\S\S \S\S \S\S] (?P<TURN>\[\S\S\].+(?=\*\*\* (RIVER|FIRST RIVER|RIVER 1) \*\*\*)|.+))?"
733 r"(\*\*\* RIVER \*\*\* \[\S\S \S\S \S\S \S\S] (?P<RIVER>\[\S\S\].+))?"
734 r"(\*\*\* (FIRST FLOP|FLOP 1) \*\*\*(?P<FLOP1> (\[\S\S\] )?\[(\S\S ?)?\S\S \S\S\].+(?=\*\*\* (FIRST TURN|TURN 1) \*\*\*)|.+))?"
735 r"(\*\*\* (FIRST TURN|TURN 1) \*\*\* \[\S\S \S\S \S\S] (?P<TURN1>\[\S\S\].+(?=\*\*\* (FIRST RIVER|RIVER 1) \*\*\*)|.+))?"
736 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) \*\*\*)|.+))?"
737 r"(\*\*\* (SECOND FLOP|FLOP 2) \*\*\*(?P<FLOP2> (\[\S\S\] )?\[\S\S ?\S\S \S\S\].+(?=\*\*\* (SECOND TURN|TURN 2) \*\*\*)|.+))?"
738 r"(\*\*\* (SECOND TURN|TURN 2) \*\*\* \[\S\S \S\S \S\S] (?P<TURN2>\[\S\S\].+(?=\*\*\* (SECOND RIVER|RIVER 2) \*\*\*)|.+))?"
739 r"(\*\*\* (SECOND RIVER|RIVER 2) \*\*\* \[\S\S \S\S \S\S \S\S] (?P<RIVER2>\[\S\S\].+))?", hand.handText,re.DOTALL)
740 elif hand.gametype['base'] in ("stud"):
741 m = re.search(r"(?P<ANTES>.+(?=\*\*\* 3rd STREET \*\*\*)|.+)"
742 r"(\*\*\* 3rd STREET \*\*\*(?P<THIRD>.+(?=\*\*\* 4th STREET \*\*\*)|.+))?"
743 r"(\*\*\* 4th STREET \*\*\*(?P<FOURTH>.+(?=\*\*\* 5th STREET \*\*\*)|.+))?"
744 r"(\*\*\* 5th STREET \*\*\*(?P<FIFTH>.+(?=\*\*\* 6th STREET \*\*\*)|.+))?"
745 r"(\*\*\* 6th STREET \*\*\*(?P<SIXTH>.+(?=\*\*\* 7th STREET \*\*\*)|.+))?"
746 r"(\*\*\* 7th STREET \*\*\*(?P<SEVENTH>.+))?", hand.handText,re.DOTALL)
747 hand.addStreets(m)
749 def readCommunityCards(self, hand, street):
750 if self.version == 1:
751 self._readCommunityCards1(hand, street)
752 else:
753 self._readCommunityCards2(hand, street)
754 if street in ('FLOP1', 'TURN1', 'RIVER1', 'FLOP2', 'TURN2', 'RIVER2'):
755 hand.runItTimes = 2
757 def _readCommunityCards1(self, hand, street): # street has been matched by markStreets, so exists in this hand
758 m = self.re_Board.search(hand.streets[street])
759 if m:
760 hand.setCommunityCards(street, [c.replace("10", "T") for c in m.group('CARDS').split(' ')])
761 else:
762 log.error("WinningToFpdb._readCommunityCards1: No community cards found on %s %s" % (street, hand.handid))
763 raise FpdbParseError
765 def _readCommunityCards2(self, hand, street): # street has been matched by markStreets, so exists in this hand
766 m = self.re_Board.search(hand.streets[street])
767 if m:
768 hand.setCommunityCards(street, m.group('CARDS').split(' '))
769 else:
770 log.error("WinningToFpdb._readCommunityCards2: No community cards found on %s %s" % (street, hand.handid))
771 raise FpdbParseError
773 def readAntes(self, hand):
774 if self.version == 1:
775 self._readAntes1(hand)
776 else:
777 self._readAntes2(hand)
779 def _readAntes1(self, hand):
780 log.debug(("reading antes"))
781 m = self.re_Antes1.finditer(hand.handText)
782 for player in m:
783 #~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
784 hand.addAnte(player.group('PNAME'), player.group('ANTE'))
786 def _readAntes2(self, hand):
787 log.debug(("reading antes"))
788 m = self.re_Antes2.finditer(hand.handText)
789 for player in m:
790 #~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
791 hand.addAnte(player.group('PNAME'), player.group('ANTE'))
793 def readBringIn(self, hand):
794 if self.version == 1:
795 self._readBringIn1(hand)
796 else:
797 self._readBringIn2(hand)
799 def _readBringIn1(self, hand):
800 m = self.re_BringIn1.search(hand.handText,re.DOTALL)
801 if m:
802 #~ logging.debug("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
803 hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
805 def _readBringIn2(self, hand):
806 m = self.re_BringIn2.search(hand.handText,re.DOTALL)
807 if m:
808 #~ logging.debug("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
809 hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
811 def readBlinds(self, hand):
812 if self.version == 1:
813 self._readBlinds1(hand)
814 else:
815 self._readBlinds2(hand)
817 def _readBlinds1(self, hand):
818 liveBlind = True
819 for a in self.re_PostSB1.finditer(hand.handText):
820 if liveBlind:
821 hand.addBlind(a.group('PNAME'), 'small blind', a.group('SB'))
822 liveBlind = False
823 else:
824 pass
825 # Post dead blinds as ante
826 #hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SB'))
827 for a in self.re_PostBB1.finditer(hand.handText):
828 hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
829 for a in self.re_Posts1.finditer(hand.handText):
830 if Decimal(self.clearMoneyString(a.group('SBBB'))) == Decimal(hand.bb):
831 hand.addBlind(a.group('PNAME'), 'big blind', a.group('SBBB'))
832 else:
833 hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SBBB'))
835 def _readBlinds2(self, hand):
836 liveBlind = True
837 for a in self.re_PostSB2.finditer(hand.handText):
838 if liveBlind:
839 hand.addBlind(a.group('PNAME'), 'small blind', a.group('SB'))
840 liveBlind = False
841 else:
842 pass
843 # Post dead blinds as ante
844 #hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SB'))
845 for a in self.re_PostBB2.finditer(hand.handText):
846 hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
847 for a in self.re_PostBoth2.finditer(hand.handText):
848 hand.addBlind(a.group('PNAME'), 'both', self.clearMoneyString(a.group('SBBB')))
849 for a in self.re_Posts2.finditer(hand.handText):
850 if Decimal(self.clearMoneyString(a.group('SBBB'))) == Decimal(hand.bb):
851 hand.addBlind(a.group('PNAME'), 'big blind', a.group('SBBB'))
852 else:
853 hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SBBB'))
855 def readHoleCards(self, hand):
856 if self.version == 1:
857 self._readHoleCards1(hand)
858 else:
859 self._readHoleCards2(hand)
861 def _readHoleCards1(self, hand):
862# streets PREFLOP, PREDRAW, and THIRD are special cases beacause
863# we need to grab hero's cards
864 for street in ('PREFLOP', 'DEAL'):
865 if street in hand.streets.keys():
866 newcards = []
867 m = self.re_HeroCards1.finditer(hand.streets[street])
868 for found in m:
869 hand.hero = found.group('PNAME')
870 newcards.append(found.group('CARD').replace("10", "T"))
871 if hand.hero:
872 hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
874 for street, text in list(hand.streets.items()):
875 if not text or street in ('PREFLOP', 'DEAL'): continue # already done these
876 m = self.re_HeroCards1.finditer(hand.streets[street])
877 players = {}
878 for found in m:
879 player = found.group('PNAME')
880 if players.get(player) == None:
881 players[player] = []
882 players[player].append(found.group('CARD').replace("10", "T"))
884 for player, cards in list(players.items()):
885 if street == 'THIRD': # hero in stud game
886 hand.dealt.add(player) # need this for stud??
887 if len(cards)==3:
888 hand.hero = player
889 hand.addHoleCards(street, player, closed=cards[0:2], open=[cards[2]], shown=False, mucked=False, dealt=False)
890 else:
891 hand.addHoleCards(street, player, closed=[], open=cards, shown=False, mucked=False, dealt=False)
892 elif street == 'SEVENTH':
893 if hand.hero==player:
894 hand.addHoleCards(street, player, open=cards, closed=[], shown=False, mucked=False, dealt=False)
895 else:
896 hand.addHoleCards(street, player, open=[], closed=cards, shown=False, mucked=False, dealt=False)
897 else:
898 hand.addHoleCards(street, player, open=cards, closed=[], shown=False, mucked=False, dealt=False)
900 def _readHoleCards2(self, hand):
901# streets PREFLOP, PREDRAW, and THIRD are special cases beacause
902# we need to grab hero's cards
903 for street in ('PREFLOP', 'DEAL'):
904 if street in hand.streets.keys():
905 newcards = []
906 m = self.re_HeroCards2.finditer(hand.streets[street])
907 for found in m:
908 hand.hero = found.group('PNAME')
909 newcards = found.group('NEWCARDS').split(' ')
910 if hand.hero:
911 hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
913 for street, text in list(hand.streets.items()):
914 if not text or street in ('PREFLOP', 'DEAL'): continue # already done these
915 m = self.re_HeroCards2.finditer(hand.streets[street])
916 for found in m:
917 player = found.group('PNAME')
918 if found.group('NEWCARDS') is None:
919 newcards = []
920 else:
921 newcards = found.group('NEWCARDS').split(' ')
922 if found.group('OLDCARDS') is None:
923 oldcards = []
924 else:
925 oldcards = found.group('OLDCARDS').split(' ')
927 if street == 'THIRD' and len(newcards) == 3: # hero in stud game
928 hand.hero = player
929 hand.dealt.add(player) # need this for stud??
930 hand.addHoleCards(street, player, closed=newcards[0:2], open=[newcards[2]], shown=False, mucked=False, dealt=False)
931 else:
932 hand.addHoleCards(street, player, open=newcards, closed=oldcards, shown=False, mucked=False, dealt=False)
934 def readAction(self, hand, street):
935 if self.version == 1:
936 self._readAction1(hand, street)
937 else:
938 self._readAction2(hand, street)
940 def _readAction1(self, hand, street):
941 m = self.re_Action1.finditer(hand.streets[street])
942 for action in m:
943 acts = action.groupdict()
944 if action.group('PNAME') == None:
945 log.error("WinningToFpdb.readAction: Unknown player %s %s" % (action.group('ATYPE'), hand.handid))
946 raise FpdbParseError
948 if action.group('ATYPE') == 'folds':
949 hand.addFold( street, action.group('PNAME'))
950 elif action.group('ATYPE') == 'checks':
951 hand.addCheck( street, action.group('PNAME'))
952 elif action.group('ATYPE') == 'calls':
953 hand.addCall( street, action.group('PNAME'), self.clearMoneyString(action.group('BET')) )
954 elif action.group('ATYPE') in ('raises', 'straddle', 'caps', 'cap'):
955 hand.addCallandRaise( street, action.group('PNAME'), self.clearMoneyString(action.group('BET')) )
956 elif action.group('ATYPE') == 'bets':
957 hand.addBet( street, action.group('PNAME'), self.clearMoneyString(action.group('BET')) )
958 elif action.group('ATYPE') == 'allin':
959 player = action.group('PNAME')
960 # disconnected all in
961 if action.group('BET') == None:
962 amount = str(hand.stacks[player])
963 else:
964 amount = self.clearMoneyString(action.group('BET')).replace(u',', u'') #some sites have commas
965 Ai = Decimal(amount)
966 Bp = hand.lastBet[street]
967 Bc = sum(hand.bets[street][player])
968 C = Bp - Bc
969 if Ai <= C:
970 hand.addCall(street, player, amount)
971 elif Bp == 0:
972 hand.addBet(street, player, amount)
973 else:
974 hand.addCallandRaise(street, player, amount)
975 else:
976 log.debug(("DEBUG:") + " " + ("Unimplemented %s: '%s' '%s'") % ("readAction", action.group('PNAME'), action.group('ATYPE')))
978 def _readAction2(self, hand, street):
979 m = self.re_Action2.finditer(hand.streets[street])
980 for action in m:
981 acts = action.groupdict()
982 #log.error("DEBUG: %s acts: %s" % (street, acts))
983 if action.group('ATYPE') == ' folds':
984 hand.addFold( street, action.group('PNAME'))
985 elif action.group('ATYPE') == ' checks':
986 hand.addCheck( street, action.group('PNAME'))
987 elif action.group('ATYPE') == ' calls':
988 hand.addCall( street, action.group('PNAME'), self.clearMoneyString(action.group('BET')) )
989 elif action.group('ATYPE') in (' raises', ' straddle', ' caps', ' cap'):
990 if action.group('BETTO') is not None:
991 hand.addRaiseTo( street, action.group('PNAME'), self.clearMoneyString(action.group('BETTO')) )
992 elif action.group('BET') is not None:
993 hand.addCallandRaise( street, action.group('PNAME'), self.clearMoneyString(action.group('BET')) )
994 elif action.group('ATYPE') == ' bets':
995 hand.addBet( street, action.group('PNAME'), self.clearMoneyString(action.group('BET')) )
996 else:
997 log.debug(("DEBUG:") + " " + ("Unimplemented %s: '%s' '%s'") % ("readAction", action.group('PNAME'), action.group('ATYPE')))
999 def readCollectPot(self,hand):
1000 if self.version == 1:
1001 self._readCollectPot1(hand)
1002 elif hand.runItTimes == 2:
1003 self._readCollectPot3(hand)
1004 else:
1005 self._readCollectPot2(hand)
1007 def _readCollectPot1(self,hand):
1008 for m in self.re_CollectPot1.finditer(hand.handText):
1009 if Decimal(self.clearMoneyString(m.group('POT'))) > 0:
1010 hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
1012 def _readCollectPot2(self,hand):
1013 pre, post = hand.handText.split('*** SUMMARY ***')
1014 acts, bovadaUncalled_v1, bovadaUncalled_v2, blindsantes, adjustment = hand.actions.get('PREFLOP'), False, False, 0, 0
1015 names = [p[1] for p in hand.players]
1016 if acts != None and len([a for a in acts if a[1] != 'folds']) == 0:
1017 m0 = self.re_Uncalled.search(hand.handText)
1018 if m0 and Decimal(m0.group('BET')) == Decimal(hand.bb):
1019 bovadaUncalled_v2 = True
1020 elif m0 == None:
1021 bovadaUncalled_v1 = True
1022 has_sb = len([a[2] for a in hand.actions.get('BLINDSANTES') if a[1] == 'small blind']) > 0
1023 adjustment = (Decimal(hand.bb) - Decimal(hand.sb)) if has_sb else Decimal(hand.bb)
1024 blindsantes = sum([a[2] for a in hand.actions.get('BLINDSANTES')])
1025 else:
1026 m0 = self.re_Uncalled.search(hand.handText)
1027 if not m0:
1028 hand.setUncalledBets(True)
1030 for m in self.re_CollectPot2.finditer(post):
1031 pot = self.clearMoneyString(m.group('POT'))
1032 if bovadaUncalled_v1 and Decimal(pot) == (blindsantes):
1033 hand.addCollectPot(player=m.group('PNAME'),pot=str(Decimal(pot) - adjustment))
1034 elif bovadaUncalled_v2:
1035 hand.addCollectPot(player=m.group('PNAME'),pot=str(Decimal(pot)*2))
1036 else:
1037 hand.addCollectPot(player=m.group('PNAME'),pot=pot)
1039 def _readCollectPot3(self,hand):
1040 for m in self.re_CollectPot3.finditer(hand.handText):
1041 hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
1043 def readShowdownActions(self, hand):
1044 # TODO: pick up mucks also??
1045 pass
1047 def readShownCards(self,hand):
1048 if self.version == 1:
1049 self._readShownCards1(hand)
1050 else:
1051 self._readShownCards2(hand)
1053 def _readShownCards1(self,hand):
1054 for m in self.re_ShownCards1.finditer(hand.handText):
1055 if m.group('CARDS') is not None:
1056 cards = m.group('CARDS')
1057 cards = [c.replace("10", "T") for c in cards.split(' ')] # needs to be a list, not a set--stud needs the order
1058 string = m.group('STRING')
1059 if m.group('STRING2'):
1060 string += '|' + m.group('STRING2')
1062 (shown, mucked) = (False, False)
1063 #if m.group('SHOWED') == "showed": shown = True
1064 #elif m.group('SHOWED') == "mucked": mucked = True
1066 #print "DEBUG: hand.addShownCards(%s, %s, %s, %s)" %(cards, m.group('PNAME'), shown, mucked)
1067 hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked, string=string)
1069 def _readShownCards2(self,hand):
1070 for m in self.re_ShownCards2.finditer(hand.handText):
1071 if m.group('CARDS') is not None:
1072 cards = m.group('CARDS')
1073 cards = cards.split(' ') # needs to be a list, not a set--stud needs the order
1074 string = m.group('STRING')
1075 if m.group('STRING2'):
1076 string += '|' + m.group('STRING2')
1078 (shown, mucked) = (False, False)
1079 if m.group('SHOWED') == "showed": shown = True
1080 elif m.group('SHOWED') == "mucked": mucked = True
1082 #print "DEBUG: hand.addShownCards(%s, %s, %s, %s)" %(cards, m.group('PNAME'), shown, mucked)
1083 hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked, string=string)
1085 @staticmethod
1086 def getTableTitleRe(type, table_name=None, tournament = None, table_number=None):
1087 "Returns string to search in windows titles"
1088 regex = re.escape(str(table_name))
1089 if type=="tour":
1090 regex = ", Table " + re.escape(str(table_number)) + "\s\-.*\s\(" + re.escape(str(tournament)) + "\)"
1091 log.info("Winning.getTableTitleRe: table_name='%s' tournament='%s' table_number='%s'" % (table_name, tournament, table_number))
1092 log.info("Winning.getTableTitleRe: returns: '%s'" % (regex))
1093 return regex