More futzing

- made it so that Hand.__init__ calls the hhc readX methods in the right
  order for that kind of Hand (Stud or Holdem/Omaha)
- hhc.readX methods then callback Hand.addX methods
Why? WHY! I hear you ask. Actually I can see there's very little gain,
sorry about that; but it sort of makes sense. Now you just make the
right kind of Hand, give it the text and the right kind of HHC filter,
and it makes itself.
- apart from that, biggest actual thing done is probably in adding
  player cards for stud hands -- revamped and made it really clear (I
think) whats happening (see FullTilt.readStudPlayerCards)
When I run FullTiltToFpdf.py it goes through all the hands.
- Still have some print statements, have been changing them to
  logging.debug or logging.info as I come across them.
  You may find "tail -f logging.out" useful
Actually I'm not at all convinced about the use of logging except that
you can redirect it to stderr quite easily and then set the threshold
for what gets logged quite easily, so that might be a plus.
- Oh and the subclassing of Hand is getting clearer.
This commit is contained in:
Matt Turnbull 2009-03-02 21:48:30 +00:00
parent 5c26bb028d
commit 36befa43a8
4 changed files with 210 additions and 142 deletions

View File

@ -32,7 +32,6 @@ class Everleaf(HandHistoryConverter):
re_Button = re.compile(r"^Seat (?P<BUTTON>\d+) is the button", re.MULTILINE) re_Button = re.compile(r"^Seat (?P<BUTTON>\d+) is the button", re.MULTILINE)
re_PlayerInfo = re.compile(r"^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\s+(\$ (?P<CASH>[.0-9]+) USD|new player|All-in) \)", re.MULTILINE) re_PlayerInfo = re.compile(r"^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\s+(\$ (?P<CASH>[.0-9]+) USD|new player|All-in) \)", re.MULTILINE)
re_Board = re.compile(r"\[ (?P<CARDS>.+) \]") re_Board = re.compile(r"\[ (?P<CARDS>.+) \]")
splitstring = "\n\n\n"
def __init__(self, in_path = '-', out_path = '-', follow = False): def __init__(self, in_path = '-', out_path = '-', follow = False):
@ -67,7 +66,7 @@ follow : whether to tail -f the input"""
["ring", "omaha", "pl"] ["ring", "omaha", "pl"]
] ]
def determineGameType(self, handtext): def determineGameType(self, handText):
# Cheating with this regex, only support nlhe at the moment # Cheating with this regex, only support nlhe at the moment
# Blinds $0.50/$1 PL Omaha - 2008/12/07 - 21:59:48 # Blinds $0.50/$1 PL Omaha - 2008/12/07 - 21:59:48
# Blinds $0.05/$0.10 NL Hold'em - 2009/02/21 - 11:21:57 # Blinds $0.05/$0.10 NL Hold'em - 2009/02/21 - 11:21:57
@ -82,7 +81,7 @@ follow : whether to tail -f the input"""
structure = "" # nl, pl, cn, cp, fl structure = "" # nl, pl, cn, cp, fl
game = "" game = ""
m = self.re_GameInfo.search(handtext) m = self.re_GameInfo.search(handText)
if m == None: if m == None:
logging.debug("Gametype didn't match") logging.debug("Gametype didn't match")
return None return None

View File

@ -17,7 +17,6 @@
######################################################################## ########################################################################
import sys import sys
import Configuration
from HandHistoryConverter import * from HandHistoryConverter import *
# FullTilt HH Format converter # FullTilt HH Format converter
@ -31,27 +30,35 @@ class FullTilt(HandHistoryConverter):
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE) re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$(?P<CASH>[.0-9]+)\)\n') re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$(?P<CASH>[.0-9]+)\)\n')
re_Board = re.compile(r"\[(?P<CARDS>.+)\]") re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
def __init__(self, in_path = '-', out_path = '-', follow = False):
"""\
in_path (default '-' = sys.stdin)
out_path (default '-' = sys.stdout)
follow : whether to tail -f the input"""
HandHistoryConverter.__init__(self, in_path, out_path, sitename="FullTilt", follow=follow)
logging.info("Initialising FullTilt converter class")
self.filetype = "text"
self.codepage = "cp1252"
self.start()
def __init__(self, config, file): def compilePlayerRegexs(self, players):
print "Initialising FullTilt converter class" if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
HandHistoryConverter.__init__(self, config, file, sitename="FullTilt") # Call super class init. # we need to recompile the player regexs.
self.sitename = "FullTilt" self.compiledPlayers = players
self.setFileType("text", "cp1252") player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
logging.debug("player_re: " + player_re)
def compilePlayerRegexs(self): self.re_PostSB = re.compile(r"^%s posts the small blind of \$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
player_re = "(?P<PNAME>" + "|".join(map(re.escape, self.players)) + ")" self.re_PostBB = re.compile(r"^%s posts (the big blind of )?\$?(?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
print "DEBUG player_re: " + player_re self.re_Antes = re.compile(r"^%s antes \$?(?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostSB = re.compile(r"^%s posts the small blind of \$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE) self.re_BringIn = re.compile(r"^%s brings in for \$?(?P<BRINGIN>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBB = re.compile(r"^%s posts (the big blind of )?\$?(?P<BB>[.0-9]+)" % player_re, re.MULTILINE) self.re_PostBoth = re.compile(r"^%s posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_Antes = re.compile(r"^%s antes \$?(?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE) self.re_HeroCards = re.compile(r"^Dealt to %s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % player_re, re.MULTILINE)
self.re_BringIn = re.compile(r"^%s brings in for \$?(?P<BRINGIN>[.0-9]+)" % player_re, re.MULTILINE) self.re_Action = re.compile(r"^%s(?P<ATYPE> bets| checks| raises to| calls| folds)(\s\$(?P<BET>[.\d]+))?" % player_re, re.MULTILINE)
self.re_PostBoth = re.compile(r"^%s posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE) self.re_ShowdownAction = re.compile(r"^%s shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
self.re_HeroCards = re.compile(r"^Dealt to %s \[(?P<CARDS>[AKQJT0-9hcsd ]+)\]( \[(?P<NEWCARD>[AKQJT0-9hcsd ]+)\])?" % player_re, re.MULTILINE) self.re_CollectPot = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$(?P<POT>[.\d]+)\)(, mucked| with.*)" % player_re, re.MULTILINE)
self.re_Action = re.compile(r"^%s(?P<ATYPE> bets| checks| raises to| calls| folds)(\s\$(?P<BET>[.\d]+))?" % player_re, re.MULTILINE) self.re_SitsOut = re.compile(r"^%s sits out" % player_re, re.MULTILINE)
self.re_ShowdownAction = re.compile(r"^%s shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE) self.re_ShownCards = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s \(.*\) showed \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
self.re_CollectPot = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$(?P<POT>[.\d]+)\)(, mucked| with.*)" % player_re, re.MULTILINE)
self.re_SitsOut = re.compile(r"^%s sits out" % player_re, re.MULTILINE)
self.re_ShownCards = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s \(.*\) showed \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
def readSupportedGames(self): def readSupportedGames(self):
@ -61,16 +68,17 @@ class FullTilt(HandHistoryConverter):
["ring", "omaha", "pl"] ["ring", "omaha", "pl"]
] ]
def determineGameType(self): def determineGameType(self, handText):
# Cheating with this regex, only support nlhe at the moment # Cheating with this regex, only support nlhe at the moment
# Full Tilt Poker Game #10777181585: Table Deerfly (deep 6) - $0.01/$0.02 - Pot Limit Omaha Hi - 2:24:44 ET - 2009/02/22 # Full Tilt Poker Game #10777181585: Table Deerfly (deep 6) - $0.01/$0.02 - Pot Limit Omaha Hi - 2:24:44 ET - 2009/02/22
# Full Tilt Poker Game #10773265574: Table Butte (6 max) - $0.01/$0.02 - Pot Limit Hold'em - 21:33:46 ET - 2009/02/21 # Full Tilt Poker Game #10773265574: Table Butte (6 max) - $0.01/$0.02 - Pot Limit Hold'em - 21:33:46 ET - 2009/02/21
# Full Tilt Poker Game #9403951181: Table CR - tay - $0.05/$0.10 - No Limit Hold'em - 9:40:20 ET - 2008/12/09 # Full Tilt Poker Game #9403951181: Table CR - tay - $0.05/$0.10 - No Limit Hold'em - 9:40:20 ET - 2008/12/09
# Full Tilt Poker Game #10809877615: Table Danville - $0.50/$1 Ante $0.10 - Limit Razz - 21:47:27 ET - 2009/02/23
structure = "" # nl, pl, cn, cp, fl structure = "" # nl, pl, cn, cp, fl
game = "" game = ""
m = self.re_GameInfo.search(self.obs) m = self.re_GameInfo.search(handText)
if m.group('LTYPE') == "No ": if m.group('LTYPE') == "No ":
structure = "nl" structure = "nl"
elif m.group('LTYPE') == "Pot ": elif m.group('LTYPE') == "Pot ":
@ -85,22 +93,22 @@ class FullTilt(HandHistoryConverter):
elif m.group('GAME') == "Razz": elif m.group('GAME') == "Razz":
game = "razz" game = "razz"
print m.groups() logging.debug("HandInfo: %s", m.groupdict())
gametype = ["ring", game, structure, m.group('SB'), m.group('BB')] gametype = ["ring", game, structure, m.group('SB'), m.group('BB')]
return gametype return gametype
def readHandInfo(self, hand): def readHandInfo(self, hand):
m = self.re_HandInfo.search(hand.string,re.DOTALL) m = self.re_HandInfo.search(hand.handText,re.DOTALL)
#print m.groups() #print m.groups()
hand.handid = m.group('HID') hand.handid = m.group('HID')
hand.tablename = m.group('TABLE') hand.tablename = m.group('TABLE')
hand.starttime = time.strptime(m.group('DATETIME'), "%H:%M:%S ET - %Y/%m/%d") hand.starttime = time.strptime(m.group('DATETIME'), "%H:%M:%S ET - %Y/%m/%d")
# These work, but the info is already in the Hand class - should be used for tourneys though. # These work, but the info is already in the Hand class - should be used for tourneys though.
# m.group('SB') # m.group('SB')
# m.group('BB') # m.group('BB')
# m.group('GAMETYPE') # m.group('GAMETYPE')
# Stars format (Nov 10 2008): 2008/11/07 12:38:49 CET [2008/11/07 7:38:49 ET] # Stars format (Nov 10 2008): 2008/11/07 12:38:49 CET [2008/11/07 7:38:49 ET]
# or : 2008/11/07 12:38:49 ET # or : 2008/11/07 12:38:49 ET
@ -113,27 +121,26 @@ class FullTilt(HandHistoryConverter):
#FIXME: hand.buttonpos = int(m.group('BUTTON')) #FIXME: hand.buttonpos = int(m.group('BUTTON'))
def readPlayerStacks(self, hand): def readPlayerStacks(self, hand):
m = self.re_PlayerInfo.finditer(hand.string) m = self.re_PlayerInfo.finditer(hand.handText)
players = [] players = []
for a in m: for a in m:
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH')) hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
def markStreets(self, hand): def markStreets(self, hand):
# PREFLOP = ** Dealing down cards ** # PREFLOP = ** Dealing down cards **
# This re fails if, say, river is missing; then we don't get the ** that starts the river.
if hand.gametype[1] in ("hold", "omaha"):
if self.gametype[1] == "hold" or self.gametype[1] == "omaha":
m = re.search(r"\*\*\* HOLE CARDS \*\*\*(?P<PREFLOP>.+(?=\*\*\* FLOP \*\*\*)|.+)" m = re.search(r"\*\*\* HOLE CARDS \*\*\*(?P<PREFLOP>.+(?=\*\*\* FLOP \*\*\*)|.+)"
r"(\*\*\* FLOP \*\*\*(?P<FLOP> \[\S\S \S\S \S\S\].+(?=\*\*\* TURN \*\*\*)|.+))?" r"(\*\*\* FLOP \*\*\*(?P<FLOP> \[\S\S \S\S \S\S\].+(?=\*\*\* TURN \*\*\*)|.+))?"
r"(\*\*\* TURN \*\*\* \[\S\S \S\S \S\S] (?P<TURN>\[\S\S\].+(?=\*\*\* RIVER \*\*\*)|.+))?" r"(\*\*\* TURN \*\*\* \[\S\S \S\S \S\S] (?P<TURN>\[\S\S\].+(?=\*\*\* RIVER \*\*\*)|.+))?"
r"(\*\*\* RIVER \*\*\* \[\S\S \S\S \S\S \S\S] (?P<RIVER>\[\S\S\].+))?", hand.string,re.DOTALL) r"(\*\*\* RIVER \*\*\* \[\S\S \S\S \S\S \S\S] (?P<RIVER>\[\S\S\].+))?", hand.handText,re.DOTALL)
elif self.gametype[1] == "razz": elif hand.gametype[1] == "razz":
m = re.search(r"(?P<ANTES>.+(?=\*\*\* 3RD STREET \*\*\*)|.+)" m = re.search(r"(?P<ANTES>.+(?=\*\*\* 3RD STREET \*\*\*)|.+)"
r"(\*\*\* 3RD STREET \*\*\*(?P<THIRD>.+(?=\*\*\* 4TH STREET \*\*\*)|.+))?" r"(\*\*\* 3RD STREET \*\*\*(?P<THIRD>.+(?=\*\*\* 4TH STREET \*\*\*)|.+))?"
r"(\*\*\* 4TH STREET \*\*\*(?P<FOURTH>.+(?=\*\*\* 5TH STREET \*\*\*)|.+))?" r"(\*\*\* 4TH STREET \*\*\*(?P<FOURTH>.+(?=\*\*\* 5TH STREET \*\*\*)|.+))?"
r"(\*\*\* 5TH STREET \*\*\*(?P<FIFTH>.+(?=\*\*\* 6TH STREET \*\*\*)|.+))?" r"(\*\*\* 5TH STREET \*\*\*(?P<FIFTH>.+(?=\*\*\* 6TH STREET \*\*\*)|.+))?"
r"(\*\*\* 6TH STREET \*\*\*(?P<SIXTH>.+(?=\*\*\* 7TH STREET \*\*\*)|.+))?" r"(\*\*\* 6TH STREET \*\*\*(?P<SIXTH>.+(?=\*\*\* 7TH STREET \*\*\*)|.+))?"
r"(\*\*\* 7TH STREET \*\*\*(?P<SEVENTH>.+))?", hand.string,re.DOTALL) r"(\*\*\* 7TH STREET \*\*\*(?P<SEVENTH>.+))?", hand.handText,re.DOTALL)
hand.addStreets(m) hand.addStreets(m)
def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand
@ -145,34 +152,32 @@ class FullTilt(HandHistoryConverter):
def readBlinds(self, hand): def readBlinds(self, hand):
try: try:
m = self.re_PostSB.search(hand.string) m = self.re_PostSB.search(hand.handText)
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
except: # no small blind except: # no small blind
hand.addBlind(None, None, None) hand.addBlind(None, None, None)
for a in self.re_PostBB.finditer(hand.string): for a in self.re_PostBB.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
for a in self.re_PostBoth.finditer(hand.string): for a in self.re_PostBoth.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB')) hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB'))
def readAntes(self, hand): def readAntes(self, hand):
print "DEBUG: reading antes" logging.debug("reading antes")
m = self.re_Antes.finditer(hand.string) m = self.re_Antes.finditer(hand.handText)
for player in m: for player in m:
print "DEBUG: hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')) logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
hand.addAnte(player.group('PNAME'), player.group('ANTE')) hand.addAnte(player.group('PNAME'), player.group('ANTE'))
def readBringIn(self, hand): def readBringIn(self, hand):
print "DEBUG: reading bring in" m = self.re_BringIn.search(hand.handText,re.DOTALL)
# print hand.string
m = self.re_BringIn.search(hand.string,re.DOTALL)
print "DEBUG: Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')) print "DEBUG: Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN'))
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN')) hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
def readButton(self, hand): def readButton(self, hand):
hand.buttonpos = int(self.re_Button.search(hand.string).group('BUTTON')) hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON'))
def readHeroCards(self, hand): def readHeroCards(self, hand):
m = self.re_HeroCards.search(hand.string) m = self.re_HeroCards.search(hand.handText)
if(m == None): if(m == None):
#Not involved in hand #Not involved in hand
hand.involved = False hand.involved = False
@ -181,25 +186,67 @@ class FullTilt(HandHistoryConverter):
# "2c, qh" -> set(["2c","qc"]) # "2c, qh" -> set(["2c","qc"])
# Also works with Omaha hands. # Also works with Omaha hands.
cards = m.group('CARDS') cards = m.group('CARDS')
cards = set(cards.split(' ')) cards = [c.strip() for c in cards.split(' ')]
hand.addHoleCards(cards, m.group('PNAME')) hand.addHoleCards(cards, m.group('PNAME'))
def readPlayerCards(self, hand, street): def readStudPlayerCards(self, hand, street):
#Used for stud hands - borrows the HeroCards regex for now. # This could be the most tricky one to get right.
m = self.re_HeroCards.finditer(hand.streets.group(street)) # It looks for cards dealt in 'street',
print "DEBUG: razz/stud readPlayerCards" # which may or may not be in the section of the hand designated 'street' by markStreets earlier.
print hand.streets.group(street) # Here's an example at FTP of what 'THIRD' and 'FOURTH' look like to hero PokerAscetic
#
#"*** 3RD STREET ***
#Dealt to BFK23 [Th]
#Dealt to cutiepr1nnymaid [8c]
#Dealt to PokerAscetic [7c 8s] [3h]
#..."
#
#"*** 4TH STREET ***
#Dealt to cutiepr1nnymaid [8c] [2s]
#Dealt to PokerAscetic [7c 8s 3h] [5s]
#..."
#Note that hero's first two holecards are only reported at 3rd street as 'old' cards.
logging.debug("readStudPlayerCards")
m = self.re_HeroCards.finditer(hand.streets[street])
for player in m: for player in m:
print player.groups() logging.debug(player.groupdict())
cards = player.group('CARDS') (pname, oldcards, newcards) = (player.group('PNAME'), player.group('OLDCARDS'), player.group('NEWCARDS'))
if player.group('NEWCARD') != None: if oldcards:
print cards oldcards = [c.strip() for c in oldcards.split(' ')]
cards = cards + " " + player.group('NEWCARD') if newcards:
cards = set(cards.split(' ')) newcards = [c.strip() for c in newcards.split(' ')]
hand.addPlayerCards(cards, player.group('PNAME')) # options here:
# (1) we trust the hand will know what to do -- probably check that the old cards match what it already knows, and add the newcards to this street.
# (2) we're the experts at this particular history format and we know how we're going to be called (once for each street in Hand.streetList)
# so call addPlayerCards with the appropriate information.
# I favour (2) here but I'm afraid it is rather stud7-specific.
# in the following, the final list of cards will be in 'newcards' whilst if the first list exists (most of the time it does) it will be in 'oldcards'
if street=='ANTES':
return
elif street=='THIRD':
# we'll have observed hero holecards in CARDS and thirdstreet open cards in 'NEWCARDS'
# hero: [xx][o]
# others: [o]
hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = oldcards, open = newcards)
elif street in ('FOURTH', 'FIFTH', 'SIXTH'):
# 4th:
# hero: [xxo] [o]
# others: [o] [o]
# 5th:
# hero: [xxoo] [o]
# others: [oo] [o]
# 6th:
# hero: [xxooo] [o]
# others: [ooo] [o]
hand.addPlayerCards(player = player.group('PNAME'), street = street, open = newcards)
# we may additionally want to check the earlier streets tally with what we have but lets trust it for now.
elif street=='SEVENTH' and newcards:
# hero: [xxoooo] [x]
# others: not reported.
hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = newcards)
def readAction(self, hand, street): def readAction(self, hand, street):
m = self.re_Action.finditer(hand.streets.group(street)) m = self.re_Action.finditer(hand.streets[street])
for action in m: for action in m:
if action.group('ATYPE') == ' raises to': if action.group('ATYPE') == ' raises to':
hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') ) hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') )
@ -216,30 +263,38 @@ class FullTilt(HandHistoryConverter):
def readShowdownActions(self, hand): def readShowdownActions(self, hand):
for shows in self.re_ShowdownAction.finditer(hand.string): for shows in self.re_ShowdownAction.finditer(hand.handText):
cards = shows.group('CARDS') cards = shows.group('CARDS')
cards = set(cards.split(' ')) cards = set(cards.split(' '))
hand.addShownCards(cards, shows.group('PNAME')) hand.addShownCards(cards, shows.group('PNAME'))
def readCollectPot(self,hand): def readCollectPot(self,hand):
for m in self.re_CollectPot.finditer(hand.string): for m in self.re_CollectPot.finditer(hand.handText):
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT')) hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
def readShownCards(self,hand): def readShownCards(self,hand):
for m in self.re_ShownCards.finditer(hand.string): for m in self.re_ShownCards.finditer(hand.handText):
if m.group('CARDS') is not None: if m.group('CARDS') is not None:
cards = m.group('CARDS') cards = m.group('CARDS')
cards = set(cards.split(' ')) cards = set(cards.split(' '))
hand.addShownCards(cards=cards, player=m.group('PNAME')) hand.addShownCards(cards=cards, player=m.group('PNAME'))
if __name__ == "__main__": if __name__ == "__main__":
c = Configuration.Config() parser = OptionParser()
if len(sys.argv) == 1: parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="regression-test-files/fulltilt/razz/FT20090223 Danville - $0.50-$1 Ante $0.10 - Limit Razz.txt")
testfile = "regression-test-files/fulltilt/razz/FT20090223 Danville - $0.50-$1 Ante $0.10 - Limit Razz.txt" parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
else: parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
testfile = sys.argv[1] parser.add_option("-q", "--quiet",
print "Converting: ", testfile action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
e = FullTilt(c, testfile) parser.add_option("-v", "--verbose",
e.processFile() action="store_const", const=logging.INFO, dest="verbosity")
print str(e) parser.add_option("--vv",
action="store_const", const=logging.DEBUG, dest="verbosity")
(options, args) = parser.parse_args()
LOG_FILENAME = './logging.out'
logging.basicConfig(filename=LOG_FILENAME,level=options.verbosity)
e = FullTilt(in_path = options.ipath, out_path = options.opath, follow = options.follow)

View File

@ -43,7 +43,7 @@ class Hand:
self.players = [] self.players = []
self.posted = [] self.posted = []
self.involved = True self.involved = True
self.pot = Pot()
# Collections indexed by street names # Collections indexed by street names
self.bets = {} self.bets = {}
@ -55,11 +55,10 @@ class Hand:
self.bets[street] = {} self.bets[street] = {}
self.lastBet[street] = 0 self.lastBet[street] = 0
self.actions[street] = [] self.actions[street] = []
self.board = {} # dict from street names to community cards self.board = {} # dict from street names to community cards
# Collections indexed by player names # Collections indexed by player names
self.holecards = {} # dict from player names to lists of hole cards self.holecards = {} # dict from player names to dicts by street ... of tuples ... of holecards
self.stacks = {} self.stacks = {}
self.collected = [] #list of ? self.collected = [] #list of ?
self.collectees = {} # dict from player names to amounts collected (?) self.collectees = {} # dict from player names to amounts collected (?)
@ -68,13 +67,13 @@ class Hand:
self.shown = set() self.shown = set()
self.folded = set() self.folded = set()
self.action = [] # self.action = []
# Things to do with money
self.pot = Pot()
self.totalpot = None self.totalpot = None
self.totalcollected = None self.totalcollected = None
self.rake = None self.rake = None
def addPlayer(self, seat, name, chips): def addPlayer(self, seat, name, chips):
"""\ """\
@ -90,6 +89,7 @@ If a player has None chips he won't be added."""
self.pot.addPlayer(name) self.pot.addPlayer(name)
for street in self.streetList: for street in self.streetList:
self.bets[street][name] = [] self.bets[street][name] = []
self.holecards[name] = {}
def addStreets(self, match): def addStreets(self, match):
@ -99,50 +99,9 @@ If a player has None chips he won't be added."""
logging.debug(self.streets) logging.debug(self.streets)
else: else:
logging.error("markstreets didn't match") logging.error("markstreets didn't match")
def addHoleCards(self, cards, player):
"""\
Assigns observed holecards to a player.
cards list of card bigrams e.g. ['2h','Jc']
player (string) name of player
"""
#print "DEBUG: addHoleCards", cards,player
try:
self.checkPlayerExists(player)
cards = set([self.card(c) for c in cards])
self.holecards[player].extend(cards)
except FpdbParseError, e:
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
def addPlayerCards(self, cards, player):
"""\
Assigns observed cards to a player.
cards list of card bigrams e.g. ['2h','Jc']
player (string) name of player
Should probably be merged with addHoleCards
"""
logging.debug("addPlayerCards %s, %s" % ( cards,player))
try:
self.checkPlayerExists(player)
cards = set([self.card(c) for c in cards])
self.holecards[player].update(cards)
except FpdbParseError, e:
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
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
"""
if cards is not None:
self.shown.add(player)
self.addHoleCards(cards,player)
elif holeandboard is not None:
holeandboard = set([self.card(c) for c in holeandboard])
board = set([c for s in self.board.values() for c in s])
self.addHoleCards(holeandboard.difference(board),player)
def checkPlayerExists(self,player): def checkPlayerExists(self,player):
@ -362,8 +321,8 @@ Map the tuple self.gametype onto the pokerstars string describing it
return retstring return retstring
def writeHand(self, fh=sys.__stdout__): #def writeHand(self, fh=sys.__stdout__):
print >>fh, "Override me" # print >>fh, "Override me"
def printHand(self): def printHand(self):
self.writeHand(sys.stdout) self.writeHand(sys.stdout)
@ -398,6 +357,9 @@ class HoldemOmahaHand(Hand):
self.sb = gametype[3] self.sb = gametype[3]
self.bb = gametype[4] self.bb = gametype[4]
#Populate a HoldemOmahaHand
#Generally, we call 'read' methods here, which get the info according to the particular filter (hhc)
# which then invokes a 'addXXX' callback
hhc.readHandInfo(self) hhc.readHandInfo(self)
hhc.readPlayerStacks(self) hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(players = set([player[1] for player in self.players])) hhc.compilePlayerRegexs(players = set([player[1] for player in self.players]))
@ -417,7 +379,34 @@ class HoldemOmahaHand(Hand):
hhc.readShownCards(self) hhc.readShownCards(self)
self.totalPot() # finalise it (total the pot) self.totalPot() # finalise it (total the pot)
hhc.getRake(self) hhc.getRake(self)
def addHoleCards(self, cards, player):
"""\
Assigns observed holecards to a player.
cards list of card bigrams e.g. ['2h','Jc']
player (string) name of player
"""
#print "DEBUG: addHoleCards", cards,player
try:
self.checkPlayerExists(player)
self.holecards[player] = set(self.card(c) for c in cards)
except FpdbParseError, e:
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
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
"""
if cards is not None:
self.shown.add(player)
self.addHoleCards(cards,player)
elif holeandboard is not None:
holeandboard = set([self.card(c) for c in holeandboard])
board = set([c for s in self.board.values() for c in s])
self.addHoleCards(holeandboard.difference(board),player)
def writeHand(self, fh=sys.__stdout__): def writeHand(self, fh=sys.__stdout__):
# PokerStars format. # 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))) 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)))
@ -508,36 +497,59 @@ class StudHand(Hand):
if gametype[1] not in ["razz","stud","stud8"]: if gametype[1] not in ["razz","stud","stud8"]:
pass # or indeed don't pass and complain instead pass # or indeed don't pass and complain instead
self.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order self.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order
self.holeStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH']
Hand.__init__(self, sitename, gametype, handText) Hand.__init__(self, sitename, gametype, handText)
self.sb = gametype[3]
self.bb = gametype[4]
#Populate the StudHand
#Generally, we call a 'read' method here, which gets the info according to the particular filter (hhc)
# which then invokes a 'addXXX' callback
hhc.readHandInfo(self) hhc.readHandInfo(self)
hhc.readPlayerStacks(self) hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(players = set([player[1] for player in self.players])) hhc.compilePlayerRegexs(players = set([player[1] for player in self.players]))
hhc.markStreets(self) hhc.markStreets(self)
hhc.readAntes(self) hhc.readAntes(self)
hhc.readBringIn(self) hhc.readBringIn(self)
hhc.readShowdownActions(self) # hhc.readShowdownActions(self) # not done yet
# Read actions in street order # Read actions in street order
for street in self.streetList: for street in self.streetList:
if self.streets[street]: if self.streets[street]:
logging.debug(street) logging.debug(street)
logging.debug(hand.streets[street]) logging.debug(self.streets[street])
hhc.readPlayerCards(self, street) hhc.readStudPlayerCards(self, street)
hhc.readAction(self, street) hhc.readAction(self, street)
hhc.readCollectPot(self) hhc.readCollectPot(self)
hhc.readShownCards(self) # hhc.readShownCards(self) # not done yet
self.totalPot() # finalise it (total the pot) self.totalPot() # finalise it (total the pot)
hhc.getRake(self) hhc.getRake(self)
def addBringIn(self, player, ante): def addPlayerCards(self, player, street, open=[], closed=[]):
"""\
Assigns observed cards to a player.
player (string) name of player
street (string) the street name (in streetList)
open list of card bigrams e.g. ['2h','Jc'], dealt face up
closed likewise, but known only to player
"""
logging.debug("addPlayerCards %s, o%s x%s" % (player, open, closed))
try:
self.checkPlayerExists(player)
self.holecards[player][street] = (open, closed)
# cards = set([self.card(c) for c in cards])
# self.holecards[player].update(cards)
except FpdbParseError, e:
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
def addBringIn(self, player, bringin):
if player is not None: if player is not None:
self.bets['THIRD'][player].append(Decimal(ante)) logging.debug("Bringin: %s, %s" % (player , bringin))
self.stacks[player] -= Decimal(ante) self.bets['THIRD'][player].append(Decimal(bringin))
act = (player, 'bringin', "bringin", ante, self.stacks[player]==0) self.stacks[player] -= Decimal(bringin)
act = (player, 'bringin', "bringin", bringin, self.stacks[player]==0)
self.actions['THIRD'].append(act) self.actions['THIRD'].append(act)
self.pot.addMoney(player, Decimal(ante)) self.pot.addMoney(player, Decimal(bringin))
def writeStudHand(self, fh=sys.__stdout__): def writeHand(self, fh=sys.__stdout__):
# PokerStars format. # 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))) 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)))
print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos)) print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos))
@ -554,8 +566,10 @@ class StudHand(Hand):
if 'THIRD' in self.actions: if 'THIRD' in self.actions:
print >>fh, _("*** 3RD STREET ***") print >>fh, _("*** 3RD STREET ***")
for player in [x for x in self.players if x[1] in players_who_post_antes]: for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
print >>fh, _("Dealt to ") print player, self.holecards[player]
(closed, open) = self.holecards[player]['THIRD']
print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(closed) + "]" if closed else " ", " [" + " ".join(open) + "]" if open else " ")
for act in self.actions['THIRD']: for act in self.actions['THIRD']:
#FIXME: Need some logic here for bringin vs completes #FIXME: Need some logic here for bringin vs completes
self.printActionLine(act, fh) self.printActionLine(act, fh)

View File

@ -136,7 +136,7 @@ class HandHistoryConverter(threading.Thread):
if self.obs == "" or self.obs == None: if self.obs == "" or self.obs == None:
logging.info("Read no hands.") logging.info("Read no hands.")
return return
return self.obs.split(self.splitstring) return re.split(self.re_SplitHands, self.obs)
def processHand(self, handtext): def processHand(self, handtext):
gametype = self.determineGameType(handtext) gametype = self.determineGameType(handtext)