From 2fa08aa26353e3de65a2fdd07d58ae79a1ed164d Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 12 Nov 2010 10:41:54 +0800 Subject: [PATCH 01/17] Regression: NLHE Sample file for Win2day --- ...NLHE-USD-0.05-0.10-Date-unknown.Sample.txt | 37 +++ ...E-USD-0.05-0.10-Date-unknown.Sample.txt.hp | 282 ++++++++++++++++++ 2 files changed, 319 insertions(+) create mode 100644 pyfpdb/regression-test-files/cash/Win2day/Flop/NLHE-USD-0.05-0.10-Date-unknown.Sample.txt create mode 100644 pyfpdb/regression-test-files/cash/Win2day/Flop/NLHE-USD-0.05-0.10-Date-unknown.Sample.txt.hp diff --git a/pyfpdb/regression-test-files/cash/Win2day/Flop/NLHE-USD-0.05-0.10-Date-unknown.Sample.txt b/pyfpdb/regression-test-files/cash/Win2day/Flop/NLHE-USD-0.05-0.10-Date-unknown.Sample.txt new file mode 100644 index 00000000..fc40c75b --- /dev/null +++ b/pyfpdb/regression-test-files/cash/Win2day/Flop/NLHE-USD-0.05-0.10-Date-unknown.Sample.txt @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pyfpdb/regression-test-files/cash/Win2day/Flop/NLHE-USD-0.05-0.10-Date-unknown.Sample.txt.hp b/pyfpdb/regression-test-files/cash/Win2day/Flop/NLHE-USD-0.05-0.10-Date-unknown.Sample.txt.hp new file mode 100644 index 00000000..0ee07b2d --- /dev/null +++ b/pyfpdb/regression-test-files/cash/Win2day/Flop/NLHE-USD-0.05-0.10-Date-unknown.Sample.txt.hp @@ -0,0 +1,282 @@ +{ u'Hero': { 'card1': 8, + 'card2': 19, + 'card3': 0, + 'card4': 0, + 'card5': 0, + 'card6': 0, + 'card7': 0, + 'foldBbToStealChance': False, + 'foldSbToStealChance': False, + 'foldToOtherRaisedStreet0': False, + 'foldToOtherRaisedStreet1': False, + 'foldToOtherRaisedStreet2': True, + 'foldToOtherRaisedStreet3': False, + 'foldToOtherRaisedStreet4': False, + 'foldToStreet1CBChance': False, + 'foldToStreet1CBDone': False, + 'foldToStreet2CBChance': False, + 'foldToStreet2CBDone': False, + 'foldToStreet3CBChance': False, + 'foldToStreet3CBDone': False, + 'foldToStreet4CBChance': False, + 'foldToStreet4CBDone': False, + 'foldedBbToSteal': False, + 'foldedSbToSteal': False, + 'other3BStreet0': False, + 'other4BStreet0': False, + 'otherRaisedStreet0': False, + 'otherRaisedStreet1': True, + 'otherRaisedStreet2': True, + 'otherRaisedStreet3': False, + 'otherRaisedStreet4': False, + 'position': 'B', + 'raiseFirstInChance': False, + 'raisedFirstIn': False, + 'rake': 0, + 'sawShowdown': False, + 'seatNo': 4, + 'sitout': False, + 'startCards': 73, + 'startCash': 795, + 'street0Aggr': False, + 'street0Bets': 0, + 'street0Calls': 0, + 'street0Raises': 0, + 'street0VPI': False, + 'street0_3BChance': False, + 'street0_3BDone': False, + 'street0_4BChance': False, + 'street0_4BDone': False, + 'street1Aggr': False, + 'street1Bets': 0, + 'street1CBChance': False, + 'street1CBDone': False, + 'street1Calls': 1, + 'street1CheckCallRaiseChance': False, + 'street1CheckCallRaiseDone': False, + 'street1Raises': 0, + 'street1Seen': True, + 'street2Aggr': False, + 'street2Bets': 0, + 'street2CBChance': False, + 'street2CBDone': False, + 'street2Calls': 0, + 'street2CheckCallRaiseChance': False, + 'street2CheckCallRaiseDone': False, + 'street2Raises': 0, + 'street2Seen': True, + 'street3Aggr': False, + 'street3Bets': 0, + 'street3CBChance': False, + 'street3CBDone': False, + 'street3Calls': 0, + 'street3CheckCallRaiseChance': False, + 'street3CheckCallRaiseDone': False, + 'street3Raises': 0, + 'street3Seen': False, + 'street4Aggr': False, + 'street4Bets': 0, + 'street4CBChance': False, + 'street4CBDone': False, + 'street4Calls': 0, + 'street4CheckCallRaiseChance': False, + 'street4CheckCallRaiseDone': False, + 'street4Raises': 0, + 'street4Seen': False, + 'totalProfit': -30, + 'tourneyTypeId': None, + 'tourneysPlayersIds': None, + 'winnings': 0, + 'wonAtSD': 0.0, + 'wonWhenSeenStreet1': 0.0, + 'wonWhenSeenStreet2': 0.0, + 'wonWhenSeenStreet3': 0.0, + 'wonWhenSeenStreet4': 0.0}, + u'Player2': { 'card1': 0, + 'card2': 0, + 'card3': 0, + 'card4': 0, + 'card5': 0, + 'card6': 0, + 'card7': 0, + 'foldBbToStealChance': False, + 'foldSbToStealChance': False, + 'foldToOtherRaisedStreet0': False, + 'foldToOtherRaisedStreet1': False, + 'foldToOtherRaisedStreet2': False, + 'foldToOtherRaisedStreet3': False, + 'foldToOtherRaisedStreet4': False, + 'foldToStreet1CBChance': False, + 'foldToStreet1CBDone': False, + 'foldToStreet2CBChance': False, + 'foldToStreet2CBDone': False, + 'foldToStreet3CBChance': False, + 'foldToStreet3CBDone': False, + 'foldToStreet4CBChance': False, + 'foldToStreet4CBDone': False, + 'foldedBbToSteal': False, + 'foldedSbToSteal': False, + 'other3BStreet0': False, + 'other4BStreet0': False, + 'otherRaisedStreet0': False, + 'otherRaisedStreet1': False, + 'otherRaisedStreet2': False, + 'otherRaisedStreet3': False, + 'otherRaisedStreet4': False, + 'position': 0, + 'raiseFirstInChance': True, + 'raisedFirstIn': False, + 'rake': 0, + 'sawShowdown': False, + 'seatNo': 1, + 'sitout': False, + 'startCards': 0, + 'startCash': 1960, + 'street0Aggr': False, + 'street0Bets': 0, + 'street0Calls': 0, + 'street0Raises': 0, + 'street0VPI': False, + 'street0_3BChance': False, + 'street0_3BDone': False, + 'street0_4BChance': False, + 'street0_4BDone': False, + 'street1Aggr': False, + 'street1Bets': 0, + 'street1CBChance': False, + 'street1CBDone': False, + 'street1Calls': 0, + 'street1CheckCallRaiseChance': False, + 'street1CheckCallRaiseDone': False, + 'street1Raises': 0, + 'street1Seen': False, + 'street2Aggr': False, + 'street2Bets': 0, + 'street2CBChance': False, + 'street2CBDone': False, + 'street2Calls': 0, + 'street2CheckCallRaiseChance': False, + 'street2CheckCallRaiseDone': False, + 'street2Raises': 0, + 'street2Seen': False, + 'street3Aggr': False, + 'street3Bets': 0, + 'street3CBChance': False, + 'street3CBDone': False, + 'street3Calls': 0, + 'street3CheckCallRaiseChance': False, + 'street3CheckCallRaiseDone': False, + 'street3Raises': 0, + 'street3Seen': False, + 'street4Aggr': False, + 'street4Bets': 0, + 'street4CBChance': False, + 'street4CBDone': False, + 'street4Calls': 0, + 'street4CheckCallRaiseChance': False, + 'street4CheckCallRaiseDone': False, + 'street4Raises': 0, + 'street4Seen': False, + 'totalProfit': 0, + 'tourneyTypeId': None, + 'tourneysPlayersIds': None, + 'winnings': 0, + 'wonAtSD': 0.0, + 'wonWhenSeenStreet1': 0.0, + 'wonWhenSeenStreet2': 0.0, + 'wonWhenSeenStreet3': 0.0, + 'wonWhenSeenStreet4': 0.0}, + u'Villain': { 'card1': 0, + 'card2': 0, + 'card3': 0, + 'card4': 0, + 'card5': 0, + 'card6': 0, + 'card7': 0, + 'foldBbToStealChance': False, + 'foldSbToStealChance': False, + 'foldToOtherRaisedStreet0': False, + 'foldToOtherRaisedStreet1': False, + 'foldToOtherRaisedStreet2': False, + 'foldToOtherRaisedStreet3': False, + 'foldToOtherRaisedStreet4': False, + 'foldToStreet1CBChance': False, + 'foldToStreet1CBDone': False, + 'foldToStreet2CBChance': False, + 'foldToStreet2CBDone': False, + 'foldToStreet3CBChance': False, + 'foldToStreet3CBDone': False, + 'foldToStreet4CBChance': False, + 'foldToStreet4CBDone': False, + 'foldedBbToSteal': False, + 'foldedSbToSteal': False, + 'other3BStreet0': False, + 'other4BStreet0': False, + 'otherRaisedStreet0': False, + 'otherRaisedStreet1': False, + 'otherRaisedStreet2': False, + 'otherRaisedStreet3': False, + 'otherRaisedStreet4': False, + 'position': 'S', + 'raiseFirstInChance': True, + 'raisedFirstIn': False, + 'rake': 3, + 'sawShowdown': False, + 'seatNo': 2, + 'sitout': False, + 'startCards': 0, + 'startCash': 993, + 'street0Aggr': False, + 'street0Bets': 0, + 'street0Calls': 1, + 'street0Raises': 0, + 'street0VPI': True, + 'street0_3BChance': False, + 'street0_3BDone': False, + 'street0_4BChance': False, + 'street0_4BDone': False, + 'street1Aggr': True, + 'street1Bets': 1, + 'street1CBChance': False, + 'street1CBDone': False, + 'street1Calls': 0, + 'street1CheckCallRaiseChance': False, + 'street1CheckCallRaiseDone': False, + 'street1Raises': 0, + 'street1Seen': True, + 'street2Aggr': True, + 'street2Bets': 1, + 'street2CBChance': True, + 'street2CBDone': True, + 'street2Calls': 0, + 'street2CheckCallRaiseChance': False, + 'street2CheckCallRaiseDone': False, + 'street2Raises': 0, + 'street2Seen': True, + 'street3Aggr': False, + 'street3Bets': 0, + 'street3CBChance': False, + 'street3CBDone': False, + 'street3Calls': 0, + 'street3CheckCallRaiseChance': False, + 'street3CheckCallRaiseDone': False, + 'street3Raises': 0, + 'street3Seen': False, + 'street4Aggr': False, + 'street4Bets': 0, + 'street4CBChance': False, + 'street4CBDone': False, + 'street4Calls': 0, + 'street4CheckCallRaiseChance': False, + 'street4CheckCallRaiseDone': False, + 'street4Raises': 0, + 'street4Seen': False, + 'totalProfit': 27, + 'tourneyTypeId': None, + 'tourneysPlayersIds': None, + 'winnings': 57, + 'wonAtSD': 0.0, + 'wonWhenSeenStreet1': 1.0, + 'wonWhenSeenStreet2': 1.0, + 'wonWhenSeenStreet3': 0.0, + 'wonWhenSeenStreet4': 0.0}} From d895ab0d2127e3d48bb2f7de3be05aa401b2ad40 Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 12 Nov 2010 11:12:18 +0800 Subject: [PATCH 02/17] Regression: PartyPoker NLHE cash hand and .hp --- .../Flop/NLHE-USD-0.01-0.02-201008.Sample.txt | Bin 0 -> 1165 bytes .../NLHE-USD-0.01-0.02-201008.Sample.txt.hp | 565 ++++++++++++++++++ 2 files changed, 565 insertions(+) create mode 100644 pyfpdb/regression-test-files/cash/PartyPoker/Flop/NLHE-USD-0.01-0.02-201008.Sample.txt create mode 100644 pyfpdb/regression-test-files/cash/PartyPoker/Flop/NLHE-USD-0.01-0.02-201008.Sample.txt.hp diff --git a/pyfpdb/regression-test-files/cash/PartyPoker/Flop/NLHE-USD-0.01-0.02-201008.Sample.txt b/pyfpdb/regression-test-files/cash/PartyPoker/Flop/NLHE-USD-0.01-0.02-201008.Sample.txt new file mode 100644 index 0000000000000000000000000000000000000000..b55ca77262d5cb9ffc5ff971d108fe16b77c2ff3 GIT binary patch literal 1165 zcma)5QE%EX7~FHD{D+gMw60<-2@oJ}mAb8}x=NJn3H8BA46z7y6g#8r*Y9(ZLYSs% zyoI~_eD|IG;XB)N3>MRQ5KR4GI)yf@GJ51Xt}|%BCxr+-g6rJaAMTmVa4)n`)e#$2 zp<(xk4b63~0{mRv;pq`Ee`Ol?s>nX_JwD@yk{LS=aa(U|Z7}wR@WaTPN8SQo?_va= z@3~IQl7eGZa-Lz}&%(tlSm64Zv%(JG$4{=a;>;j~&@eeiQX8Wr36&v^toI48pf)HA zcI1_&G~t&8I@Kb=qtM4v?TB=ZtMO<$Yy6(ZMu=5q)Nd{`Wf{T9pIk8J5prG^%Cx8# zUZ8%2QW>$UYi)6FG`UnyB2;R>W0g!=eC}Q7XAyKQQXz#mwgkU7;0%;X8x6f@MS-Lc z)XbWW@_ak$h05#H+l)4%=WtoFQ$wWn;w<+~tUvSK&eeLJCZ=xmb@qr@! kOSG){-?D>{+FtK)+FaiaUFzmF?wOGG1>hh|j(3Os0j_>k!T Date: Sat, 13 Nov 2010 12:04:13 +0800 Subject: [PATCH 03/17] Stars: Fix re_GameInfo to parse AAMS section of .it hands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only have the one example from a Tournament hand: PokerStars Game #52486342403: Tournament #324732603, €0.82+€0.18 EUR Hold'em No Limit - Level I (10/20) [AAMS ID: L284A006CB1E33ZO] - 2010/11/10 20:59:53 CET [2010/11/10 14:59:53 ET] Hopefully the same for cash games --- pyfpdb/PokerStarsToFpdb.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index c86fc157..061a88fc 100644 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -99,7 +99,9 @@ class PokerStars(HandHistoryConverter): (?P[.0-9]+) (?P\s-\s[%(LS)s\d\.]+\sCap\s-\s)? # Optional Cap part \s?(?P%(LEGAL_ISO)s)? - \)\s-\s # close paren of the stakes + \) # close paren of the stakes + (?P\s\[AAMS\sID:\s[A-Z0-9]+\]) # AAMS ID: in .it HH's + \s-\s (?P.*$) """ % substitutions, re.MULTILINE|re.VERBOSE) From f7f8122af84d4ad9fdfe49b2f1435ec119896014 Mon Sep 17 00:00:00 2001 From: Worros Date: Mon, 15 Nov 2010 13:39:36 +0800 Subject: [PATCH 04/17] GTI: Add utf16 file handling --- pyfpdb/GuiTourneyImport.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyfpdb/GuiTourneyImport.py b/pyfpdb/GuiTourneyImport.py index d8fe6ec5..3f24996b 100755 --- a/pyfpdb/GuiTourneyImport.py +++ b/pyfpdb/GuiTourneyImport.py @@ -238,7 +238,7 @@ class SummaryImporter: self.filelist = {} def readFile(self, tsc, filename): - codepage = ["utf8"] + codepage = ["utf8", "utf16"] whole_file = None tsc.codepage @@ -248,7 +248,8 @@ class SummaryImporter: whole_file = in_fh.read() in_fh.close() break - except: + except UnicodeDecodeError, e: + log.warn(_("GTI.readFile: '%s'") % e) pass return whole_file From bc55042ed4dd8268a0232dad1c1fb6618b27f42b Mon Sep 17 00:00:00 2001 From: Worros Date: Mon, 15 Nov 2010 13:40:10 +0800 Subject: [PATCH 05/17] Configs: Add FTP summary parsing defaults --- pyfpdb/HUD_config.test.xml | 2 +- pyfpdb/HUD_config.xml.example | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/HUD_config.test.xml b/pyfpdb/HUD_config.test.xml index 11fa1be8..556bbede 100644 --- a/pyfpdb/HUD_config.test.xml +++ b/pyfpdb/HUD_config.test.xml @@ -567,7 +567,7 @@ Left-Drag to Move" - + diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index 8c43397f..9ac66289 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -778,7 +778,7 @@ Left-Drag to Move" - + From 9c2c18f5cacf0954afee5ec901a4f478744c5c45 Mon Sep 17 00:00:00 2001 From: Worros Date: Mon, 15 Nov 2010 13:40:57 +0800 Subject: [PATCH 06/17] TourneySummary: Add alternate lookup for FTP --- pyfpdb/TourneySummary.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/TourneySummary.py b/pyfpdb/TourneySummary.py index 9ca4c27b..4ed91b65 100644 --- a/pyfpdb/TourneySummary.py +++ b/pyfpdb/TourneySummary.py @@ -49,7 +49,7 @@ class TourneySummary(object): LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'} # SAL- TO KEEP ?? SYMBOL = {'USD': '$', 'EUR': u'$', 'T$': '', 'play': ''} MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose' : 'HOSE', 'ha': 'HA'} - SITEIDS = {'Fulltilt':1, 'PokerStars':2, 'Everleaf':3, 'Win2day':4, 'OnGame':5, 'UltimateBet':6, 'Betfair':7, 'Absolute':8, 'PartyPoker':9 } + SITEIDS = {'Fulltilt':1, 'Full Tilt Poker':1, 'PokerStars':2, 'Everleaf':3, 'Win2day':4, 'OnGame':5, 'UltimateBet':6, 'Betfair':7, 'Absolute':8, 'PartyPoker':9 } def __init__(self, db, config, siteName, summaryText, builtFrom = "HHC"): From d69c9dc33ff0a4ea4a1ef6b6c2c1774118a0002f Mon Sep 17 00:00:00 2001 From: Worros Date: Mon, 15 Nov 2010 14:24:31 +0800 Subject: [PATCH 07/17] TSI: Add FTP support --- pyfpdb/TestSummaryImport.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyfpdb/TestSummaryImport.py b/pyfpdb/TestSummaryImport.py index 88a2cd7e..2aa2a81b 100755 --- a/pyfpdb/TestSummaryImport.py +++ b/pyfpdb/TestSummaryImport.py @@ -128,7 +128,7 @@ def main(argv=None): importer = SummaryImporter(config, sql, None) PokerStarsErrors = FpdbError('PokerStars') - #FTPErrors = FpdbError('Full Tilt Poker') + FTPErrors = FpdbError('Full Tilt Poker') #PartyPokerErrors = FpdbError('Party Poker') #BetfairErrors = FpdbError('Betfair') #OnGameErrors = FpdbError('OnGame') @@ -142,7 +142,7 @@ def main(argv=None): ErrorsList = [ PokerStarsErrors, - #FTPErrors, PartyPokerErrors, + FTPErrors, #PartyPokerErrors, #BetfairErrors, OnGameErrors, AbsoluteErrors, #EverleafErrors, CarbonErrors, PKRErrors, #iPokerErrors, WinamaxErrors, UltimateBetErrors, @@ -150,7 +150,7 @@ def main(argv=None): sites = { 'PokerStars' : True, - #'Full Tilt Poker' : True, + 'Full Tilt Poker' : True, #'PartyPoker' : True, #'Betfair' : True, #'OnGame' : True, @@ -165,8 +165,8 @@ def main(argv=None): if sites['PokerStars'] == True: walk_testfiles("regression-test-files/summaries/Stars/", compare, importer, PokerStarsErrors, "PokerStars") - #if sites['Full Tilt Poker'] == True: - # walk_testfiles("regression-test-files/cash/FTP/", compare, importer, FTPErrors, "Full Tilt Poker") + if sites['Full Tilt Poker'] == True: + walk_testfiles("regression-test-files/summaries/FTP/", compare, importer, FTPErrors, "Full Tilt Poker") # walk_testfiles("regression-test-files/tour/FTP/", compare, importer, FTPErrors, "Full Tilt Poker") #if sites['PartyPoker'] == True: # walk_testfiles("regression-test-files/cash/PartyPoker/", compare, importer, PartyPokerErrors, "PartyPoker") From 147cc6c95035164c48e12f0e2719fce228f0c959 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 16 Nov 2010 11:57:09 +0800 Subject: [PATCH 08/17] Absolute: Deal with ','s in blinds --- pyfpdb/AbsoluteToFpdb.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pyfpdb/AbsoluteToFpdb.py b/pyfpdb/AbsoluteToFpdb.py index e0ceed48..59f75a8f 100755 --- a/pyfpdb/AbsoluteToFpdb.py +++ b/pyfpdb/AbsoluteToFpdb.py @@ -54,7 +54,7 @@ class Absolute(HandHistoryConverter): (?P\(1\son\s1\)|Single\ Tournament|Multi\ Normal\ Tournament|)\s* (?PNo\ Limit|Pot\ Limit|Normal|)\s? (?P\$|\s€|) - (?P[.0-9]+)/?(?:\$|\s€|)(?P[.0-9]+)? + (?P[.,0-9]+)/?(?:\$|\s€|)(?P[.,0-9]+)? \s+-\s+ (?P\d\d\d\d-\d\d-\d\d\ \d\d:\d\d:\d\d)\s+ (?: \( (?P[A-Z]+) \)\s+ )? @@ -95,10 +95,10 @@ class Absolute(HandHistoryConverter): player_re = "(?P" + "|".join(map(re.escape, players)) + ")" logging.debug("player_re: "+ player_re) #(?P\$| €|)(?P[0-9]*[.0-9]+) - self.re_PostSB = re.compile(ur"^%s - Posts small blind (?:\$| €|)(?P[0-9]*[.0-9]+)" % player_re, re.MULTILINE) - self.re_PostBB = re.compile(ur"^%s - Posts big blind (?:\$| €|)(?P[0-9]*[.0-9]+)" % player_re, re.MULTILINE) + self.re_PostSB = re.compile(ur"^%s - Posts small blind (?:\$| €|)(?P[,.0-9]+)" % player_re, re.MULTILINE) + self.re_PostBB = re.compile(ur"^%s - Posts big blind (?:\$| €|)(?P[.,0-9]+)" % player_re, re.MULTILINE) # TODO: Absolute posting when coming in new: %s - Posts $0.02 .. should that be a new Post line? where do we need to add support for that? *confused* - self.re_PostBoth = re.compile(ur"^%s - Posts dead (?:\$| €|)(?P[0-9]*[.0-9]+)" % player_re, re.MULTILINE) + self.re_PostBoth = re.compile(ur"^%s - Posts dead (?:\$| €|)(?P[,.0-9]+)" % player_re, re.MULTILINE) self.re_Action = re.compile(ur"^%s - (?PBets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P[0-9]*[.0-9]+)?" % player_re, re.MULTILINE) self.re_ShowdownAction = re.compile(ur"^%s - Shows \[(?P.*)\]" % player_re, re.MULTILINE) self.re_CollectPot = re.compile(ur"^Seat [0-9]: %s(?: \(dealer\)|)(?: \(big blind\)| \(small blind\)|) (?:won|collected) Total \((?:\$| €|)(?P[0-9]*[.0-9]+)\)" % player_re, re.MULTILINE) @@ -175,11 +175,13 @@ class Absolute(HandHistoryConverter): if info['currency'] == 'T$': info['type'] = 'tour' if 'SB' in mg: + mg['SB'] = mg['SB'].replace(',', '') info['sb'] = mg['SB'] if 'BB' in mg: info['bb'] = mg['BB'] # NB: SB, BB must be interpreted as blinds or bets depending on limit type. if info['bb'] is None: + mg['SB'] = mg['SB'].replace(',', '') info['bb'] = mg['SB'] info['sb'] = str(float(mg['SB']) * 0.5) # TODO: AP does provide Small BET for Limit .. I think? at least 1-on-1 limit they do.. sigh From 41da3e6f65a25d587f51fcab0299389148768fa5 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 16 Nov 2010 12:07:08 +0800 Subject: [PATCH 09/17] Absolute: Deal with ','s in Action, Antes and Collect --- pyfpdb/AbsoluteToFpdb.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyfpdb/AbsoluteToFpdb.py b/pyfpdb/AbsoluteToFpdb.py index 59f75a8f..a45119d8 100755 --- a/pyfpdb/AbsoluteToFpdb.py +++ b/pyfpdb/AbsoluteToFpdb.py @@ -99,10 +99,10 @@ class Absolute(HandHistoryConverter): self.re_PostBB = re.compile(ur"^%s - Posts big blind (?:\$| €|)(?P[.,0-9]+)" % player_re, re.MULTILINE) # TODO: Absolute posting when coming in new: %s - Posts $0.02 .. should that be a new Post line? where do we need to add support for that? *confused* self.re_PostBoth = re.compile(ur"^%s - Posts dead (?:\$| €|)(?P[,.0-9]+)" % player_re, re.MULTILINE) - self.re_Action = re.compile(ur"^%s - (?PBets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P[0-9]*[.0-9]+)?" % player_re, re.MULTILINE) + self.re_Action = re.compile(ur"^%s - (?PBets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P[,.0-9]+)?" % player_re, re.MULTILINE) self.re_ShowdownAction = re.compile(ur"^%s - Shows \[(?P.*)\]" % player_re, re.MULTILINE) - self.re_CollectPot = re.compile(ur"^Seat [0-9]: %s(?: \(dealer\)|)(?: \(big blind\)| \(small blind\)|) (?:won|collected) Total \((?:\$| €|)(?P[0-9]*[.0-9]+)\)" % player_re, re.MULTILINE) - self.re_Antes = re.compile(ur"^%s - Ante \[(?:\$| €|)(?P[.0-9]+)" % player_re, re.MULTILINE) + self.re_CollectPot = re.compile(ur"^Seat [0-9]: %s(?: \(dealer\)|)(?: \(big blind\)| \(small blind\)|) (?:won|collected) Total \((?:\$| €|)(?P[,.0-9]+)\)" % player_re, re.MULTILINE) + self.re_Antes = re.compile(ur"^%s - Ante \[(?:\$| €|)(?P[,.0-9]+)" % player_re, re.MULTILINE) #self.re_BringIn = re.compile(ur"^%s posts bring-in (?:\$| €|)(?P[.0-9]+)\." % player_re, re.MULTILINE) self.re_HeroCards = re.compile(ur"^Dealt to %s \[(?P.*)\]" % player_re, re.MULTILINE) From 55aa2df1deb0d4ab349393aa64324c1002fbf202 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 16 Nov 2010 12:50:36 +0800 Subject: [PATCH 10/17] Stars: Fix AAMS portion of GameInfo regex. Somewhere along the line I removed the ? making it optional. --- pyfpdb/PokerStarsToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 061a88fc..16c4091e 100644 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -100,7 +100,7 @@ class PokerStars(HandHistoryConverter): (?P\s-\s[%(LS)s\d\.]+\sCap\s-\s)? # Optional Cap part \s?(?P%(LEGAL_ISO)s)? \) # close paren of the stakes - (?P\s\[AAMS\sID:\s[A-Z0-9]+\]) # AAMS ID: in .it HH's + (?P\s\[AAMS\sID:\s[A-Z0-9]+\])? # AAMS ID: in .it HH's \s-\s (?P.*$) """ % substitutions, re.MULTILINE|re.VERBOSE) From a33a947deec6eed8e233a8c6de3e080adbb88dc7 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 16 Nov 2010 12:59:00 +0800 Subject: [PATCH 11/17] Absolute: Fix more ',' breakage --- pyfpdb/AbsoluteToFpdb.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pyfpdb/AbsoluteToFpdb.py b/pyfpdb/AbsoluteToFpdb.py index a45119d8..d55f4710 100755 --- a/pyfpdb/AbsoluteToFpdb.py +++ b/pyfpdb/AbsoluteToFpdb.py @@ -332,17 +332,21 @@ class Absolute(HandHistoryConverter): for action in m: logging.debug("%s %s" % (action.group('ATYPE'), action.groupdict())) if action.group('ATYPE') == 'Raises ' or action.group('ATYPE') == 'All-In(Raise) ': - hand.addCallandRaise( street, action.group('PNAME'), action.group('BET') ) + bet = action.group('BET').replace(',', '') + hand.addCallandRaise( street, action.group('PNAME'), bet) elif action.group('ATYPE') == 'Calls ': - hand.addCall( street, action.group('PNAME'), action.group('BET') ) + bet = action.group('BET').replace(',', '') + hand.addCall( street, action.group('PNAME'), bet) elif action.group('ATYPE') == 'Bets ' or action.group('ATYPE') == 'All-In ': - hand.addBet( street, action.group('PNAME'), action.group('BET') ) + bet = action.group('BET').replace(',', '') + hand.addBet( street, action.group('PNAME'), bet) elif action.group('ATYPE') == 'Folds': hand.addFold( street, action.group('PNAME')) elif action.group('ATYPE') == 'Checks': hand.addCheck( street, action.group('PNAME')) elif action.group('ATYPE') == ' complete to': # TODO: not supported yet ? - hand.addComplete( street, action.group('PNAME'), action.group('BET')) + bet = action.group('BET').replace(',', '') + hand.addComplete( street, action.group('PNAME'), bet) else: logging.debug(_("Unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),))) @@ -359,7 +363,8 @@ class Absolute(HandHistoryConverter): def readCollectPot(self,hand): for m in self.re_CollectPot.finditer(hand.handText): - hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT')) + pot = m.group('POT').replace(',','') + hand.addCollectPot(player=m.group('PNAME'),pot=pot) def readShownCards(self,hand): """Reads lines where hole & board cards are mixed to form a hand (summary lines)""" From bccadd2a4ddbc21192d8d4c5b867f6dea8b8fddf Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 18 Nov 2010 13:09:38 +0800 Subject: [PATCH 12/17] Stove.py: Command line pokerstove like application. Build on top of pypoker-eval, grabbed unchanged from Bostiks other OS project 'pokerstats' http://bostik.iki.fi/pokerstats/ --- pyfpdb/Stove.py | 308 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100755 pyfpdb/Stove.py diff --git a/pyfpdb/Stove.py b/pyfpdb/Stove.py new file mode 100755 index 00000000..ffbdff4f --- /dev/null +++ b/pyfpdb/Stove.py @@ -0,0 +1,308 @@ +#!/usr/bin/python +# -*- coding: iso-8859-15 +# +# stove.py +# Simple Hold'em equity calculator +# Copyright (C) 2007-2008 Mika Boström +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# + +import sys, random +import pokereval + +SUITS = ['h', 'd', 's', 'c'] + +ANY = 0 +SUITED = 1 +OFFSUIT = 2 + +ev = pokereval.PokerEval() + +holder = None + +class Holder: + def __init__(self): + self.hand = None + self.board = None + self.range = None + + +class Cards: + def __init__(self, c1, c2): + self.c1 = c1 + self.c2 = c2 + + def get(self): + return [c1, c2] + +class Board: + def __init__(self, b1=None, b2=None, b3=None, b4=None, b5=None): + self.b1 = b1 + self.b2 = b2 + self.b3 = b3 + self.b4 = b4 + self.b5 = b5 + + def get(self): + b = [] + if self.b3 is not None: + b.append(self.b1) + b.append(self.b2) + b.append(self.b3) + else: + b.extend(["__", "__", "__"]) + + if self.b4 is not None: + b.append(self.b4) + else: + b.append("__") + + if self.b5 is not None: + b.append(self.b5) + else: + b.append("__") + + return b + +class Range: + def __init__(self): + self.__hands = set() + + def add(self, hand): + self.__hands.add(hand) + + def expand(self, hands): + self.__hands.update(set(hands)) + + def get(self): + return sorted(self.__hands) + + + +class EV: + def __init__(self, plays, win, tie, lose): + self.n_hands = plays + self.n_wins = win + self.n_ties = tie + self.n_losses = lose + + +class SumEV: + def __init__(self): + self.n_hands = 0 + self.n_wins = 0 + self.n_ties = 0 + self.n_losses = 0 + + def add(self, ev): + self.n_hands += ev.n_hands + self.n_wins += ev.n_wins + self.n_ties += ev.n_ties + self.n_losses += ev.n_losses + + def show(self, hand, range): + win_pct = 100 * (float(self.n_wins) / float(self.n_hands)) + lose_pct = 100 * (float(self.n_losses) / float(self.n_hands)) + tie_pct = 100 * (float(self.n_ties) / float(self.n_hands)) + print 'Enumerated %d possible plays.' % self.n_hands + print 'Your hand: (%s %s)' % (hand.c1, hand.c2) + print 'Against the range: %s\n' % cards_from_range(range) + print ' Win Lose Tie' + print ' %5.2f%% %5.2f%% %5.2f%%' % (win_pct, lose_pct, tie_pct) + + +def usage(me): + print """Texas Hold'Em odds calculator +Calculates odds against a range of hands. + +To use: %s '' '' '' [...] + +Separate cards with space. +Separate hands in range with commas. +""" % me + +def cards_from_range(range): + s = '{' + for h in range: + if h.c1 == '__' and h.c2 == '__': + s += 'random, ' + else: + s += '%s%s, ' % (h.c1, h.c2) + s = s.rstrip(', ') + s += '}' + return s + + +# Expands hand abbreviations such as JJ and AK to full hand ranges. +# Takes into account cards already known to be in player's hand and/or +# board. +def expand_hands(abbrev, hand, board): + selection = -1 + known_cards = set() + known_cards.update(set([hand.c2, hand.c2])) + known_cards.update(set([board.b1, board.b2, board.b3, board.b4, board.b5])) + + # Card ranks may be different + r1 = abbrev[0] + r2 = abbrev[1] + # There may be a specifier: 's' for 'suited'; 'o' for 'off-suit' + if len(abbrev) == 3: + ltr = abbrev[2] + if ltr == 'o': + selection = OFFSUIT + elif ltr == 's': + selection = SUITED + else: + selection = ANY + + range = [] + considered = set() + for s1 in SUITS: + c1 = r1 + s1 + if c1 in known_cards: + continue + considered.add(c1) + for s2 in SUITS: + c2 = r2 + s2 + if selection == SUITED and s1 != s2: + continue + elif selection == OFFSUIT and s1 == s2: + continue + if c2 not in considered and c2 not in known_cards: + range.append(Cards(c1, c2)) + return range + + + + + +def parse_args(args, container): + # args[0] is the path being executed; need 3 more args + if len(args) < 4: + return False + + board = Board() + + # Board + b = args[1].strip().split() + if len(b) > 4: + board.b5 = b[4] + if len(b) > 3: + board.b4 = b[3] + if len(b) > 2: + board.b1 = b[0] + board.b2 = b[1] + board.b3 = b[2] + + # Our pocket cards + cc = args[2].strip().split() + c1 = cc[0] + c2 = cc[1] + pocket_cards = Cards(c1, c2) + + # Villain's range + range = Range() + hands_in_range = args[3].strip().split(',') + for h in hands_in_range: + _h = h.strip() + if len(_h) > 3: + cc = _h.split() + r1 = cc[0] + r2 = cc[1] + vp = Cards(r1, r2) + range.add(vp) + else: + range.expand(expand_hands(_h, pocket_cards, board)) + + holder.hand = pocket_cards + holder.range = range + holder.board = board + + return True + + +def odds_for_hand(hand1, hand2, board, iterations): + res = ev.poker_eval(game='holdem', + pockets = [ + hand1, + hand2 + ], + dead = [], + board = board, + iterations = iterations + ) + + plays = int(res['info'][0]) + eval = res['eval'][0] + + win = int(eval['winhi']) + lose = int(eval['losehi']) + tie = int(eval['tiehi']) + + _ev = EV(plays, win, tie, lose) + return _ev + + +def odds_for_range(holder): + sev = SumEV() + monte_carlo = False + + # Construct board list + b = [] + board = holder.board + if board.b3 is not None: + b.extend([board.b1, board.b2, board.b3]) + else: + b.extend(['__', '__', '__']) + monte_carlo = True + if board.b4 is not None: + b.append(board.b4) + else: + b.append("__") + if board.b5 is not None: + b.append(board.b5) + else: + b.append("__") + + if monte_carlo: + print 'No board given. Using Monte-Carlo simulation...' + iters = random.randint(25000, 125000) + else: + iters = -1 + for h in holder.range.get(): + e = odds_for_hand( + [holder.hand.c1, holder.hand.c2], + [h.c1, h.c2], + b, + iterations=iters + ) + sev.add(e) + + sev.show(holder.hand, holder.range.get()) + + + +holder = Holder() +if not parse_args(sys.argv, holder): + usage(sys.argv[0]) + sys.exit(2) +odds_for_range(holder) + +# debugs +#print '%s, %s' % ( holder.hand.c1, holder.hand.c2) +#print '%s %s %s %s %s' % (holder.board.b1, holder.board.b2, +# holder.board.b3, holder.board.b4, holder.board.b5) +#while True: +# try: +# vl = holder.range.get() +# v = vl.pop() +# print '\t%s %s' % (v.c1, v.c2) +# except IndexError: +# break + + + + From 990e3d2ed1326752744568c9d6c55f4ae708ad3b Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Thu, 18 Nov 2010 17:44:56 -0500 Subject: [PATCH 13/17] remove spurious ( ) from carbon/merge hh detection --- pyfpdb/CarbonToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/CarbonToFpdb.py b/pyfpdb/CarbonToFpdb.py index cf8794da..e11d1591 100644 --- a/pyfpdb/CarbonToFpdb.py +++ b/pyfpdb/CarbonToFpdb.py @@ -66,7 +66,7 @@ class Carbon(HandHistoryConverter): # Static regexes re_SplitHands = re.compile(r'\n+(?=)') - re_GameInfo = re.compile(r'', re.MULTILINE) + re_GameInfo = re.compile(r'', re.MULTILINE) re_HandInfo = re.compile(r'[0-9]+)">') re_PlayerInfo = re.compile(r'', re.MULTILINE) From 742347c5c78ad8c5e08f13e6e43f28899cb8ab03 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Thu, 18 Nov 2010 17:54:19 -0500 Subject: [PATCH 14/17] undo my last change as it breaks merge 4.x --- pyfpdb/CarbonToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/CarbonToFpdb.py b/pyfpdb/CarbonToFpdb.py index e11d1591..1a1541ee 100644 --- a/pyfpdb/CarbonToFpdb.py +++ b/pyfpdb/CarbonToFpdb.py @@ -66,7 +66,7 @@ class Carbon(HandHistoryConverter): # Static regexes re_SplitHands = re.compile(r'\n+(?=)') - re_GameInfo = re.compile(r'', re.MULTILINE) + re_GameInfo = re.compile(r'', re.MULTILINE) re_HandInfo = re.compile(r'[0-9]+)">') re_PlayerInfo = re.compile(r'', re.MULTILINE) From 8368a002ffe861051d92b36e145909dd930108eb Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 19 Nov 2010 08:11:25 +0800 Subject: [PATCH 15/17] Regression: TS file for FTP - Hero losing --- ...LHE-USD-SnG-9man-2-200910.Hero.lost.Sample.txt | Bin 0 -> 868 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 pyfpdb/regression-test-files/summaries/FTP/LHE-USD-SnG-9man-2-200910.Hero.lost.Sample.txt diff --git a/pyfpdb/regression-test-files/summaries/FTP/LHE-USD-SnG-9man-2-200910.Hero.lost.Sample.txt b/pyfpdb/regression-test-files/summaries/FTP/LHE-USD-SnG-9man-2-200910.Hero.lost.Sample.txt new file mode 100644 index 0000000000000000000000000000000000000000..97f8321e721998001af209c44e2146d811b34592 GIT binary patch literal 868 zcmb7>%Syvw5QWcL@E!hzctNU3wU=b6s1;lkninWq+hEg58W;89)o&(NiWMRJ{I@f6 z=5prq<5q8)vw||^+!e2(mU_`drK3wcN-Z>20k&|D5m><*V_D;Mpf=~JzapLS>+l{C z(c&Gl?}!<6tk_paJw@N^1bl#Xt|uLlq2T`jvvBsl_H;$IwOYC-dy4h1Y`^`2t~DdV zt5(j5smL;#UqXx<@1(?If`_3QHB@wDS`6tc*E_aa4Xdus9IOB1y{pU0Bb1yIx-mxE zvnD#H?}#(<>{d Date: Sat, 20 Nov 2010 09:05:52 +0100 Subject: [PATCH 16/17] add TODO to gettextify stove --- pyfpdb/Stove.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyfpdb/Stove.py b/pyfpdb/Stove.py index ffbdff4f..eb939c0f 100755 --- a/pyfpdb/Stove.py +++ b/pyfpdb/Stove.py @@ -9,6 +9,7 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, version 3 of the License. # +#TODO: gettextify import sys, random import pokereval From da800b7abb5e205f340d833a1b9982d9b4b23afc Mon Sep 17 00:00:00 2001 From: Steffen Schaumburg Date: Mon, 22 Nov 2010 04:25:31 +0100 Subject: [PATCH 17/17] restore HUD executable flag --- pyfpdb/HUD_main.pyw | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 pyfpdb/HUD_main.pyw diff --git a/pyfpdb/HUD_main.pyw b/pyfpdb/HUD_main.pyw old mode 100644 new mode 100755