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_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>.+) \]")
splitstring = "\n\n\n"
def __init__(self, in_path = '-', out_path = '-', follow = False):
@ -67,7 +66,7 @@ follow : whether to tail -f the input"""
["ring", "omaha", "pl"]
]
def determineGameType(self, handtext):
def determineGameType(self, handText):
# Cheating with this regex, only support nlhe at the moment
# 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
@ -82,7 +81,7 @@ follow : whether to tail -f the input"""
structure = "" # nl, pl, cn, cp, fl
game = ""
m = self.re_GameInfo.search(handtext)
m = self.re_GameInfo.search(handText)
if m == None:
logging.debug("Gametype didn't match")
return None

View File

@ -17,7 +17,6 @@
########################################################################
import sys
import Configuration
from HandHistoryConverter import *
# 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_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$(?P<CASH>[.0-9]+)\)\n')
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):
print "Initialising FullTilt converter class"
HandHistoryConverter.__init__(self, config, file, sitename="FullTilt") # Call super class init.
self.sitename = "FullTilt"
self.setFileType("text", "cp1252")
def compilePlayerRegexs(self):
player_re = "(?P<PNAME>" + "|".join(map(re.escape, self.players)) + ")"
print "DEBUG player_re: " + player_re
self.re_PostSB = re.compile(r"^%s posts the small blind of \$?(?P<SB>[.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_Antes = re.compile(r"^%s antes \$?(?P<ANTE>[.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_PostBoth = re.compile(r"^%s posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)" % 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_Action = re.compile(r"^%s(?P<ATYPE> bets| checks| raises to| calls| folds)(\s\$(?P<BET>[.\d]+))?" % player_re, re.MULTILINE)
self.re_ShowdownAction = re.compile(r"^%s shows \[(?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 compilePlayerRegexs(self, players):
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
# we need to recompile the player regexs.
self.compiledPlayers = players
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
logging.debug("player_re: " + player_re)
self.re_PostSB = re.compile(r"^%s posts the small blind of \$?(?P<SB>[.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_Antes = re.compile(r"^%s antes \$?(?P<ANTE>[.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_PostBoth = re.compile(r"^%s posts small \& big blinds \[\$? (?P<SBBB>[.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_Action = re.compile(r"^%s(?P<ATYPE> bets| checks| raises to| calls| folds)(\s\$(?P<BET>[.\d]+))?" % player_re, re.MULTILINE)
self.re_ShowdownAction = re.compile(r"^%s shows \[(?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):
@ -61,16 +68,17 @@ class FullTilt(HandHistoryConverter):
["ring", "omaha", "pl"]
]
def determineGameType(self):
def determineGameType(self, handText):
# 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 #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 #10809877615: Table Danville - $0.50/$1 Ante $0.10 - Limit Razz - 21:47:27 ET - 2009/02/23
structure = "" # nl, pl, cn, cp, fl
game = ""
m = self.re_GameInfo.search(self.obs)
m = self.re_GameInfo.search(handText)
if m.group('LTYPE') == "No ":
structure = "nl"
elif m.group('LTYPE') == "Pot ":
@ -85,22 +93,22 @@ class FullTilt(HandHistoryConverter):
elif m.group('GAME') == "Razz":
game = "razz"
print m.groups()
logging.debug("HandInfo: %s", m.groupdict())
gametype = ["ring", game, structure, m.group('SB'), m.group('BB')]
return gametype
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()
hand.handid = m.group('HID')
hand.tablename = m.group('TABLE')
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.
# m.group('SB')
# m.group('BB')
# m.group('GAMETYPE')
# m.group('SB')
# m.group('BB')
# m.group('GAMETYPE')
# 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
@ -113,27 +121,26 @@ class FullTilt(HandHistoryConverter):
#FIXME: hand.buttonpos = int(m.group('BUTTON'))
def readPlayerStacks(self, hand):
m = self.re_PlayerInfo.finditer(hand.string)
m = self.re_PlayerInfo.finditer(hand.handText)
players = []
for a in m:
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
def markStreets(self, hand):
# PREFLOP = ** Dealing down cards **
# This re fails if, say, river is missing; then we don't get the ** that starts the river.
if self.gametype[1] == "hold" or self.gametype[1] == "omaha":
if hand.gametype[1] in ("hold", "omaha"):
m = re.search(r"\*\*\* HOLE CARDS \*\*\*(?P<PREFLOP>.+(?=\*\*\* FLOP \*\*\*)|.+)"
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"(\*\*\* RIVER \*\*\* \[\S\S \S\S \S\S \S\S] (?P<RIVER>\[\S\S\].+))?", hand.string,re.DOTALL)
elif self.gametype[1] == "razz":
r"(\*\*\* RIVER \*\*\* \[\S\S \S\S \S\S \S\S] (?P<RIVER>\[\S\S\].+))?", hand.handText,re.DOTALL)
elif hand.gametype[1] == "razz":
m = re.search(r"(?P<ANTES>.+(?=\*\*\* 3RD STREET \*\*\*)|.+)"
r"(\*\*\* 3RD STREET \*\*\*(?P<THIRD>.+(?=\*\*\* 4TH STREET \*\*\*)|.+))?"
r"(\*\*\* 4TH STREET \*\*\*(?P<FOURTH>.+(?=\*\*\* 5TH STREET \*\*\*)|.+))?"
r"(\*\*\* 5TH STREET \*\*\*(?P<FIFTH>.+(?=\*\*\* 6TH 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)
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):
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'))
except: # no small blind
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'))
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'))
def readAntes(self, hand):
print "DEBUG: reading antes"
m = self.re_Antes.finditer(hand.string)
logging.debug("reading antes")
m = self.re_Antes.finditer(hand.handText)
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'))
def readBringIn(self, hand):
print "DEBUG: reading bring in"
# print hand.string
m = self.re_BringIn.search(hand.string,re.DOTALL)
m = self.re_BringIn.search(hand.handText,re.DOTALL)
print "DEBUG: Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN'))
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
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):
m = self.re_HeroCards.search(hand.string)
m = self.re_HeroCards.search(hand.handText)
if(m == None):
#Not involved in hand
hand.involved = False
@ -181,25 +186,67 @@ class FullTilt(HandHistoryConverter):
# "2c, qh" -> set(["2c","qc"])
# Also works with Omaha hands.
cards = m.group('CARDS')
cards = set(cards.split(' '))
cards = [c.strip() for c in cards.split(' ')]
hand.addHoleCards(cards, m.group('PNAME'))
def readPlayerCards(self, hand, street):
#Used for stud hands - borrows the HeroCards regex for now.
m = self.re_HeroCards.finditer(hand.streets.group(street))
print "DEBUG: razz/stud readPlayerCards"
print hand.streets.group(street)
def readStudPlayerCards(self, hand, street):
# This could be the most tricky one to get right.
# It looks for cards dealt in 'street',
# which may or may not be in the section of the hand designated 'street' by markStreets earlier.
# 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:
print player.groups()
cards = player.group('CARDS')
if player.group('NEWCARD') != None:
print cards
cards = cards + " " + player.group('NEWCARD')
cards = set(cards.split(' '))
hand.addPlayerCards(cards, player.group('PNAME'))
logging.debug(player.groupdict())
(pname, oldcards, newcards) = (player.group('PNAME'), player.group('OLDCARDS'), player.group('NEWCARDS'))
if oldcards:
oldcards = [c.strip() for c in oldcards.split(' ')]
if newcards:
newcards = [c.strip() for c in newcards.split(' ')]
# 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):
m = self.re_Action.finditer(hand.streets.group(street))
m = self.re_Action.finditer(hand.streets[street])
for action in m:
if action.group('ATYPE') == ' raises to':
hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') )
@ -216,30 +263,38 @@ class FullTilt(HandHistoryConverter):
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 = set(cards.split(' '))
hand.addShownCards(cards, shows.group('PNAME'))
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'))
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:
cards = m.group('CARDS')
cards = set(cards.split(' '))
hand.addShownCards(cards=cards, player=m.group('PNAME'))
if __name__ == "__main__":
c = Configuration.Config()
if len(sys.argv) == 1:
testfile = "regression-test-files/fulltilt/razz/FT20090223 Danville - $0.50-$1 Ante $0.10 - Limit Razz.txt"
else:
testfile = sys.argv[1]
print "Converting: ", testfile
e = FullTilt(c, testfile)
e.processFile()
print str(e)
parser = OptionParser()
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")
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
parser.add_option("-q", "--quiet",
action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
parser.add_option("-v", "--verbose",
action="store_const", const=logging.INFO, dest="verbosity")
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.posted = []
self.involved = True
self.pot = Pot()
# Collections indexed by street names
self.bets = {}
@ -55,11 +55,10 @@ class Hand:
self.bets[street] = {}
self.lastBet[street] = 0
self.actions[street] = []
self.board = {} # dict from street names to community cards
# 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.collected = [] #list of ?
self.collectees = {} # dict from player names to amounts collected (?)
@ -68,13 +67,13 @@ class Hand:
self.shown = set()
self.folded = set()
self.action = []
# self.action = []
# Things to do with money
self.pot = Pot()
self.totalpot = None
self.totalcollected = None
self.rake = None
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)
for street in self.streetList:
self.bets[street][name] = []
self.holecards[name] = {}
def addStreets(self, match):
@ -99,50 +99,9 @@ If a player has None chips he won't be added."""
logging.debug(self.streets)
else:
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):
@ -362,8 +321,8 @@ Map the tuple self.gametype onto the pokerstars string describing it
return retstring
def writeHand(self, fh=sys.__stdout__):
print >>fh, "Override me"
#def writeHand(self, fh=sys.__stdout__):
# print >>fh, "Override me"
def printHand(self):
self.writeHand(sys.stdout)
@ -398,6 +357,9 @@ class HoldemOmahaHand(Hand):
self.sb = gametype[3]
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.readPlayerStacks(self)
hhc.compilePlayerRegexs(players = set([player[1] for player in self.players]))
@ -417,7 +379,34 @@ class HoldemOmahaHand(Hand):
hhc.readShownCards(self)
self.totalPot() # finalise it (total the pot)
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__):
# 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)))
@ -508,36 +497,59 @@ class StudHand(Hand):
if gametype[1] not in ["razz","stud","stud8"]:
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.holeStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH']
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.readPlayerStacks(self)
hhc.compilePlayerRegexs(players = set([player[1] for player in self.players]))
hhc.markStreets(self)
hhc.readAntes(self)
hhc.readBringIn(self)
hhc.readShowdownActions(self)
# hhc.readShowdownActions(self) # not done yet
# Read actions in street order
for street in self.streetList:
if self.streets[street]:
logging.debug(street)
logging.debug(hand.streets[street])
hhc.readPlayerCards(self, street)
logging.debug(self.streets[street])
hhc.readStudPlayerCards(self, street)
hhc.readAction(self, street)
hhc.readCollectPot(self)
hhc.readShownCards(self)
# hhc.readShownCards(self) # not done yet
self.totalPot() # finalise it (total the pot)
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:
self.bets['THIRD'][player].append(Decimal(ante))
self.stacks[player] -= Decimal(ante)
act = (player, 'bringin', "bringin", ante, self.stacks[player]==0)
logging.debug("Bringin: %s, %s" % (player , bringin))
self.bets['THIRD'][player].append(Decimal(bringin))
self.stacks[player] -= Decimal(bringin)
act = (player, 'bringin', "bringin", bringin, self.stacks[player]==0)
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.
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))
@ -554,8 +566,10 @@ class StudHand(Hand):
if 'THIRD' in self.actions:
print >>fh, _("*** 3RD STREET ***")
for player in [x for x in self.players if x[1] in players_who_post_antes]:
print >>fh, _("Dealt to ")
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
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']:
#FIXME: Need some logic here for bringin vs completes
self.printActionLine(act, fh)

View File

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