From 56bd7b37baedba73f5c45ee611150c2be86ef116 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Jul 2009 13:48:43 -0400 Subject: [PATCH 1/8] Parse Stars tournaments for flop and stud games. Tournaments are not correctly written in writehand(). Nor are stud games. --- pyfpdb/Hand.py | 5 +++++ pyfpdb/PokerStarsToFpdb.py | 39 +++++++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index db1d1197..d51424e6 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -1088,6 +1088,11 @@ Add a complete on [street] by [player] to [amountTo] def writeHand(self, fh=sys.__stdout__): # PokerStars format. # print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d - %H:%M:%S (ET)', self.starttime))) + +# TODO: +# Hole cards are not currently correctly written. Currently the down cards for non-heros +# are shown in the "dealt to" lines. They should be hidden in those lines. I tried to fix +# but mind got boggled, will try again. print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET'))) print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos)) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 45306281..3c2c959c 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -26,7 +26,18 @@ from HandHistoryConverter import * class PokerStars(HandHistoryConverter): # Static regexes - re_GameInfo = re.compile("PokerStars Game #(?P[0-9]+):\s+(?PHORSE|8\-Game|HOSE)? \(?(?PHold\'em|Razz|7 Card Stud|7 Card Stud Hi/Lo|Omaha|Omaha Hi/Lo|Badugi) (?PNo Limit|Limit|Pot Limit),? \(?(?P\$|)?(?P[.0-9]+)/\$?(?P[.0-9]+)\) - (?P.*$)", re.MULTILINE) +# re_GameInfo = re.compile("PokerStars Game #(?P[0-9]+):\s+(?PHORSE|8\-Game|HOSE)? \(?(?PHold\'em|Razz|7 Card Stud|7 Card Stud Hi/Lo|Omaha|Omaha Hi/Lo|Badugi) (?PNo Limit|Limit|Pot Limit),? \(?(?P\$|)?(?P[.0-9]+)/\$?(?P[.0-9]+)\) - (?P.*$)", re.MULTILINE) + re_GameInfo = re.compile("""PokerStars\sGame\s\#(?P[0-9]+):\s+ + (Tournament\s\#(?P\d+),\s(?P[\$\+\d\.]+)\s)? + (?PHORSE|8\-Game|HOSE)?\s?\(? + (?PHold\'em|Razz|7\sCard Stud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi)\s + (?PNo\sLimit|Limit|Pot\sLimit),?\s + (-\sLevel\s(?P[IVXLC]+)\s)?\(? + (?P\$|)? + (?P[.0-9]+)/\$? + (?P[.0-9]+)\)\s-\s + (?P.*$)""", + re.MULTILINE|re.VERBOSE) re_SplitHands = re.compile('\n\n+') re_TailSplitHands = re.compile('(\n\n\n+)') re_HandInfo = re.compile("^Table \'(?P[- a-zA-Z]+)\'(?P.+?$)?", re.MULTILINE) @@ -62,7 +73,8 @@ follow : whether to tail -f the input""" self.re_BringIn = re.compile(r"^%s: brings[- ]in( low|) for \$?(?P[.0-9]+)" % player_re, re.MULTILINE) self.re_PostBoth = re.compile(r"^%s: posts small \& big blinds \[\$? (?P[.0-9]+)" % player_re, re.MULTILINE) self.re_HeroCards = re.compile(r"^Dealt to %s(?: \[(?P.+?)\])?( \[(?P.+?)\])" % player_re, re.MULTILINE) - self.re_Action = re.compile(r"^%s:(?P bets| checks| raises| calls| folds| discards| stands pat)( \$(?P[.\d]+))?( to \$(?P[.\d]+))?( (?P\d) cards?( \[(?P.+?)\])?)?" % player_re, re.MULTILINE) +# self.re_Action = re.compile(r"^%s:(?P bets| checks| raises| calls| folds| discards| stands pat)( \$(?P[.\d]+))?( to \$(?P[.\d]+))?( (?P\d) cards?( \[(?P.+?)\])?)?" % player_re, re.MULTILINE) + self.re_Action = re.compile(r"^%s:(?P bets| checks| raises| calls| folds| discards| stands pat)( \$?(?P[.\d]+))?( to \$?(?P[.\d]+))?( (?P\d) cards?( \[(?P.+?)\])?)?" % player_re, re.MULTILINE) self.re_ShowdownAction = re.compile(r"^%s: shows \[(?P.*)\]" % player_re, re.MULTILINE) self.re_CollectPot = re.compile(r"Seat (?P[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$(?P[.\d]+)\)(, mucked| with.*|)" % player_re, re.MULTILINE) self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE) @@ -72,20 +84,26 @@ follow : whether to tail -f the input""" return [["ring", "hold", "nl"], ["ring", "hold", "pl"], ["ring", "hold", "fl"], + ["ring", "stud", "fl"], #["ring", "draw", "fl"], - ["ring", "omaha", "pl"] + + ["tour", "hold", "nl"], + ["tour", "hold", "pl"], + ["tour", "hold", "fl"], + + ["tour", "stud", "fl"], ] def determineGameType(self, handText): - info = {'type':'ring'} + info = {} m = self.re_GameInfo.search(handText) if not m: return None mg = m.groupdict() - + print "mg =", mg # translations from captured groups to our info strings limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' } mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} @@ -99,6 +117,10 @@ follow : whether to tail -f the input""" 'Badugi' : ('draw','badugi') } currencies = { u'€':'EUR', '$':'USD', '':'T$' } +# I don't think this is doing what we think. mg will always have all +# the expected keys, but the ones that didn't match in the regex will +# have a value of None. It is OK if it throws an exception when it +# runs across an unknown game or limit or whatever. if 'LIMIT' in mg: info['limitType'] = limits[mg['LIMIT']] if 'GAME' in mg: @@ -111,6 +133,13 @@ follow : whether to tail -f the input""" info['currency'] = currencies[mg['CURRENCY']] if 'MIXED' in mg and mg['MIXED'] != None: info['mixedType'] = mixes[mg['MIXED']] + info['tourNo'] = mg['TOURNO'] + if info['tourNo'] == None: + info['type'] = 'ring' + else: + info['type'] = 'tour' + info['buyin'] = mg['BUYIN'] + info['level'] = mg['LEVEL'] # NB: SB, BB must be interpreted as blinds or bets depending on limit type. return info From 4e952de82529b3e6ff8595998fbcee7e8e2c2672 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Jul 2009 14:15:36 -0400 Subject: [PATCH 2/8] Remove intermediate print. --- pyfpdb/PokerStarsToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 3c2c959c..580d5481 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -103,7 +103,7 @@ follow : whether to tail -f the input""" return None mg = m.groupdict() - print "mg =", mg +# print "mg =", mg # translations from captured groups to our info strings limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' } mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} From d8820ae1f7a5dbf5b963144b42d1dcfd60a20e8a Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jul 2009 13:44:32 -0400 Subject: [PATCH 3/8] Allow parsing of tournaments, draw and play money. Sorry about the massive commit. There are still numerous bugs parsing non-holdem hands and writehand() is broken for all but holdem cash games. --- pyfpdb/Hand.py | 76 ++++++++++++++++++++++++++--------- pyfpdb/PokerStarsToFpdb.py | 81 ++++++++++++++++++++++++-------------- 2 files changed, 108 insertions(+), 49 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index d51424e6..cc1dfd5a 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -45,6 +45,9 @@ class Hand: self.maxseats = 10 self.counted_seats = 0 self.buttonpos = 0 + self.tourNo = None + self.buyin = None + self.level = None self.seating = [] self.players = [] self.posted = [] @@ -56,17 +59,19 @@ class Hand: self.actions = {} # [['mct','bets','$10'],['mika','folds'],['carlg','raises','$20']] self.board = {} # dict from street names to community cards self.holecards = {} + self.discards = {} for street in self.allStreets: self.streets[street] = "" # portions of the handText, filled by markStreets() + self.actions[street] = [] + for street in self.actionStreets: self.bets[street] = {} self.lastBet[street] = 0 - self.actions[street] = [] self.board[street] = [] + for street in self.holeStreets: self.holecards[street] = {} # dict from player names to holecards - + self.discards[street] = {} # dict from player names to dicts by street ... of tuples ... of discarded holecards # Collections indexed by player names # self.holecards = {} # dict from player names to dicts by street ... of tuples ... of holecards - self.discards = {} # dict from player names to dicts by street ... of tuples ... of discarded holecards self.stacks = {} self.collected = [] #list of ? self.collectees = {} # dict from player names to amounts collected (?) @@ -93,6 +98,9 @@ class Hand: ("TABLE NAME", self.tablename), ("HERO", self.hero), ("MAXSEATS", self.maxseats), + ("TOURNAMENT NO", self.tourNo), + ("BUYIN", self.buyin), + ("LEVEL", self.level), ("LASTBET", self.lastBet), ("ACTION STREETS", self.actionStreets), ("STREETS", self.streets), @@ -221,10 +229,10 @@ If a player has None chips he won't be added.""" self.players.append([seat, name, chips]) self.stacks[name] = Decimal(chips) self.pot.addPlayer(name) - for street in self.allStreets: + for street in self.actionStreets: self.bets[street][name] = [] #self.holecards[name] = {} # dict from street names. - self.discards[name] = {} # dict from street names. + #self.discards[name] = {} # dict from street names. def addStreets(self, match): @@ -784,8 +792,10 @@ class DrawHand(Hand): if gametype['base'] != 'draw': pass # or indeed don't pass and complain instead self.streetList = ['BLINDSANTES', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE'] + self.allStreets = ['BLINDSANTES', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE'] self.holeStreets = ['DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE'] self.actionStreets = ['PREDEAL', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE'] + self.communityStreets = [] Hand.__init__(self, sitename, gametype, handText) self.sb = gametype['sb'] self.bb = gametype['bb'] @@ -849,18 +859,19 @@ player (string) name of player self.checkPlayerExists(player) # if shown and len(cardset) > 0: # self.shown.add(player) - self.holecards[player][street] = (newcards,oldcards) + self.holecards[street][player] = (newcards,oldcards) except FpdbParseError, e: print "[ERROR] Tried to add holecards for unknown player: %s" % (player,) def discardDrawHoleCards(self, cards, player, street): logging.debug("discardDrawHoleCards '%s' '%s' '%s'" % (cards, player, street)) - self.discards[player][street] = set([cards]) + self.discards[street][player] = set([cards]) def addDiscard(self, street, player, num, cards): self.checkPlayerExists(player) + print "street, player, num, cards =", street, player, num, cards if cards: act = (player, 'discards', num, cards) self.discardDrawHoleCards(cards, player, street) @@ -869,12 +880,12 @@ player (string) name of player self.actions[street].append(act) - def addShownCards(self, cards, player, holeandboard=None): - """\ -For when a player shows cards for any reason (for showdown or out of choice). -Card ranks will be uppercased -""" - logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard)) +# def addShownCards(self, cards, player, holeandboard=None, shown=False, mucked=False): +# """\ +#For when a player shows cards for any reason (for showdown or out of choice). +#Card ranks will be uppercased +#""" +# logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard)) # if cards is not None: # self.shown.add(player) # self.addHoleCards(cards,player) @@ -884,6 +895,33 @@ Card ranks will be uppercased # self.addHoleCards(holeandboard.difference(board),player,shown=True) + def addHoleCards(self, cards, player, shown, mucked, dealt=False): + """\ +Assigns observed holecards to a player. +cards list of card bigrams e.g. ['2h','Jc'] +player (string) name of player +shown whether they were revealed at showdown +mucked whether they were mucked at showdown +dealt whether they were seen in a 'dealt to' line +""" +# I think this only gets called for shown cards. + logging.debug("addHoleCards %s %s" % (cards, player)) + try: + self.checkPlayerExists(player) + except FpdbParseError, e: + print "[ERROR] Tried to add holecards for unknown player: %s" % (player,) + return + + if dealt: + self.dealt.add(player) + if shown: + self.shown.add(player) + if mucked: + self.mucked.add(player) + if player != self.hero: #skip hero, we know his cards + print "player, cards =", player, cards + self.holecards[self.holeStreets[-1]][player] = (cards, set([])) + def writeHand(self, fh=sys.__stdout__): # PokerStars format. print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d %H:%M:%S ET', self.starttime))) @@ -913,8 +951,8 @@ Card ranks will be uppercased for act in self.actions['DRAWONE']: print >>fh, self.actionString(act) if act[0] == self.hero and act[1] == 'discards': - (nc,oc) = self.holecards[act[0]]['DRAWONE'] - dc = self.discards[act[0]]['DRAWONE'] + (nc,oc) = self.holecards['DRAWONE'][act[0]] + dc = self.discards['DRAWONE'][act[0]] kc = oc - dc print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc))) @@ -923,8 +961,8 @@ Card ranks will be uppercased for act in self.actions['DRAWTWO']: print >>fh, self.actionString(act) if act[0] == self.hero and act[1] == 'discards': - (nc,oc) = self.holecards[act[0]]['DRAWTWO'] - dc = self.discards[act[0]]['DRAWTWO'] + (nc,oc) = self.holecards['DRAWTWO'][act[0]] + dc = self.discards['DRAWTWO'][act[0]] kc = oc - dc print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc))) @@ -933,8 +971,8 @@ Card ranks will be uppercased for act in self.actions['DRAWTHREE']: print >>fh, self.actionString(act) if act[0] == self.hero and act[1] == 'discards': - (nc,oc) = self.holecards[act[0]]['DRAWTHREE'] - dc = self.discards[act[0]]['DRAWTHREE'] + (nc,oc) = self.holecards['DRAWTHREE'][act[0]] + dc = self.discards['DRAWTHREE'][act[0]] kc = oc - dc print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc))) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 580d5481..80c16d07 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -30,7 +30,7 @@ class PokerStars(HandHistoryConverter): re_GameInfo = re.compile("""PokerStars\sGame\s\#(?P[0-9]+):\s+ (Tournament\s\#(?P\d+),\s(?P[\$\+\d\.]+)\s)? (?PHORSE|8\-Game|HOSE)?\s?\(? - (?PHold\'em|Razz|7\sCard Stud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi)\s + (?PHold\'em|Razz|7\sCard Stud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi|Triple\sDraw\s2\-7\sLowball)\s (?PNo\sLimit|Limit|Pot\sLimit),?\s (-\sLevel\s(?P[IVXLC]+)\s)?\(? (?P\$|)? @@ -40,7 +40,11 @@ class PokerStars(HandHistoryConverter): re.MULTILINE|re.VERBOSE) re_SplitHands = re.compile('\n\n+') re_TailSplitHands = re.compile('(\n\n\n+)') - re_HandInfo = re.compile("^Table \'(?P
[- a-zA-Z]+)\'(?P.+?$)?", re.MULTILINE) + re_HandInfo = re.compile("""^Table\s\'(?P
[-\ a-zA-Z\d]+)\'\s + ((?P\d+)-max\s)? + (?P\(Play\sMoney\)\s)? + (Seat\s\#(?P
[ a-zA-Z]+) - \$?(?P[.0-9]+)/\$?(?P[.0-9]+) - (?P.*) - (?P
[0-9]+):(?P[0-9]+) ET - (?P[0-9]+)/(?P[0-9]+)/(?P[0-9]+)Table (?P
[ a-zA-Z]+)\nSeat (?P