Coverage for WinningToFpdb.py: 0%
627 statements
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-14 11:07 +0000
« 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########################################################################
21# import L10n
22# _ = L10n.get_translation()
24# TODO: straighten out discards for draw games
26# _ = L10n.get_translation()
27from HandHistoryConverter import HandHistoryConverter, FpdbParseError, FpdbHandPartial
28import re
29import logging
30import datetime
31from decimal import Decimal
34# Winning HH Format
35log = logging.getLogger("parser")
38class Winning(HandHistoryConverter):
39 # Class Variables
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"}
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 }
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$"}
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 )
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
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 )
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 )
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 )
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 )
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 )
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)
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 )
228 re_Table2 = re.compile("Table\s'(?P<TABLENO>\d+)'")
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
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 )
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+)")
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)")
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)
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)
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 )
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 )
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.
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.
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 )
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 )
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 )
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)
357 def compilePlayerRegexs(self, hand):
358 pass
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 ]
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)
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)
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
395 mg = m.groupdict()
396 m1 = self.re_TourNo.search(self.in_path)
397 if m1:
398 mg.update(m1.groupdict())
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"]
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"
416 if info.get("limitType") is None:
417 if "omaha" in info["category"]:
418 info["limitType"] = "pl"
419 else:
420 info["limitType"] = "nl"
422 if "TOURNO" in mg and mg["TOURNO"] is not None:
423 info["type"] = "tour"
424 else:
425 info["type"] = "ring"
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"
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$"
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")))
448 return info
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
458 mg = m.groupdict()
460 m1 = self.re_File2.search(self.in_path)
461 if m1:
462 mg.update(m1.groupdict())
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"]]
475 if "TYPE" in mg and "RUSHID" == mg["TYPE"]:
476 info["fast"] = True
477 else:
478 info["fast"] = False
480 if "TOURNO" in mg and mg["TOURNO"] is None:
481 info["type"] = "ring"
482 else:
483 info["type"] = "tour"
485 if info.get("currency") in ("T$", None) and info["type"] == "ring":
486 info["currency"] = "play"
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")))
492 return info
494 def readHandInfo(self, hand):
495 if self.version == 1:
496 self._readHandInfo1(hand)
497 else:
498 self._readHandInfo2(hand)
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"))
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
513 info.update(m.groupdict())
515 m1 = self.re_TourNo.search(self.in_path)
516 if m1:
517 info.update(m1.groupdict())
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")
532 if "TOURNO" in info:
533 hand.tourNo = info["TOURNO"]
535 if "HID" in info:
536 hand.handid = info["HID"]
538 if "MAX" in info and info["MAX"] is not None:
539 hand.maxseats = int(info["MAX"].replace("-max", ""))
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
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"])))
563 if hand.guaranteeAmt == 0:
564 hand.buyinCurrency = "USD"
565 hand.buyin = int(100 * Decimal(self.clearMoneyString(tableinfo["BUYIN"])))
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)
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
583 hand.tablename = int(m3.group("TABLENO"))
585 if "On Demand" in info["TABLE"]:
586 hand.isOnDemand = True
588 if " KO" in info["TABLE"] or "Knockout" in info["TABLE"]:
589 hand.isKO = True
591 if "R/A" in info["TABLE"]:
592 hand.isRebuy = True
593 hand.isAddOn = True
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
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"))
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
622 info.update(m.groupdict())
623 info.update(m1.groupdict())
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
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])
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
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"
690 hand.speed = self.speeds[speed]
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"))))
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]
702 m5 = self.re_Step.search(hand.tourneyName)
703 if m5:
704 hand.isStep = True
705 hand.stepNo = int(m5.group("STEPNO"))
707 elif "RUSHID" in self.in_path:
708 (hand.gametype["fast"], hand.isFast) = (True, True)
710 def readButton(self, hand):
711 if self.version == 1:
712 self._readButton1(hand)
713 else:
714 self._readButton2(hand)
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"))
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"))
730 def readPlayerStacks(self, hand):
731 if self.version == 1:
732 self._readPlayerStacks1(hand)
733 else:
734 self._readPlayerStacks2(hand)
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")))
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")))
748 def markStreets(self, hand):
749 if self.version == 1:
750 self._markStreets1(hand)
751 else:
752 self._markStreets2(hand)
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)
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)
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
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
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
829 def readAntes(self, hand):
830 if self.version == 1:
831 self._readAntes1(hand)
832 else:
833 self._readAntes2(hand)
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"))
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"))
849 def readBringIn(self, hand):
850 if self.version == 1:
851 self._readBringIn1(hand)
852 else:
853 self._readBringIn2(hand)
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"))
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"))
867 def readBlinds(self, hand):
868 if self.version == 1:
869 self._readBlinds1(hand)
870 else:
871 self._readBlinds2(hand)
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"))
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"))
911 def readHoleCards(self, hand):
912 if self.version == 1:
913 self._readHoleCards1(hand)
914 else:
915 self._readHoleCards2(hand)
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)
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"))
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)
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)
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(" ")
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 )
998 def readAction(self, hand, street):
999 if self.version == 1:
1000 self._readAction1(hand, street)
1001 else:
1002 self._readAction2(hand, street)
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
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 )
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 )
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)
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"))
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)
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)
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"))
1121 def readShowdownActions(self, hand):
1122 # TODO: pick up mucks also??
1123 pass
1125 def readShownCards(self, hand):
1126 if self.version == 1:
1127 self._readShownCards1(hand)
1128 else:
1129 self._readShownCards2(hand)
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")
1142 (shown, mucked) = (False, False)
1143 # if m.group('SHOWED') == "showed": shown = True
1144 # elif m.group('SHOWED') == "mucked": mucked = True
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)
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")
1158 (shown, mucked) = (False, False)
1159 if m.group("SHOWED") == "showed":
1160 shown = True
1161 elif m.group("SHOWED") == "mucked":
1162 mucked = True
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)
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