Merge branch 'exp' of git://git.assembla.com/mctfpdb

This commit is contained in:
Worros 2008-12-07 14:04:00 +09:00
commit b1a9109190
2 changed files with 416 additions and 393 deletions

View File

@ -58,42 +58,45 @@ from HandHistoryConverter import *
# smaragdar calls [$ 34.50 USD] # smaragdar calls [$ 34.50 USD]
# ** Dealing Turn ** [ 2d ] # ** Dealing Turn ** [ 2d ]
# ** Dealing River ** [ 6c ] # ** Dealing River ** [ 6c ]
# dogge shows [ 9h, 9c ]a pair of nines
# spicybum shows [ 5d, 6d ]a straight, eight high
# harrydebeng does not show cards
# smaragdar wins $ 102 USD from main pot with a pair of aces [ ad, ah, qs, 8h, 6c ] # smaragdar wins $ 102 USD from main pot with a pair of aces [ ad, ah, qs, 8h, 6c ]
class Everleaf(HandHistoryConverter): class Everleaf(HandHistoryConverter):
def __init__(self, config, file): def __init__(self, config, file):
print "Initialising Everleaf converter class" print "Initialising Everleaf converter class"
HandHistoryConverter.__init__(self, config, file, "Everleaf") # Call super class init. HandHistoryConverter.__init__(self, config, file, "Everleaf") # Call super class init.
self.sitename = "Everleaf" self.sitename = "Everleaf"
self.setFileType("text") self.setFileType("text")
self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)') self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)')
self.rexx.setSplitHandRegex('\n\n\n\n') self.rexx.setSplitHandRegex('\n\n\n\n')
self.rexx.setHandInfoRegex('.*#(?P<HID>[0-9]+)\n.*\nBlinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>.*) - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+):(?P<SEC>[0-9]+)\nTable (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)') self.rexx.setHandInfoRegex('.*#(?P<HID>[0-9]+)\n.*\nBlinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>.*) - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+):(?P<SEC>[0-9]+)\nTable (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
self.rexx.setPlayerInfoRegex('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \( \$ (?P<CASH>[.0-9]+) USD \)') self.rexx.setPlayerInfoRegex('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \( \$ (?P<CASH>[.0-9]+) USD \)')
self.rexx.setPostSbRegex('.*\n(?P<PNAME>.*): posts small blind \[\$? (?P<SB>[.0-9]+)') self.rexx.setPostSbRegex('.*\n(?P<PNAME>.*): posts small blind \[\$? (?P<SB>[.0-9]+)')
self.rexx.setPostBbRegex('.*\n(?P<PNAME>.*): posts big blind \[\$? (?P<BB>[.0-9]+)') self.rexx.setPostBbRegex('.*\n(?P<PNAME>.*): posts big blind \[\$? (?P<BB>[.0-9]+)')
# mct : what about posting small & big blinds simultaneously? # mct : what about posting small & big blinds simultaneously?
self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<HOLE1>\S\S), (?P<HOLE2>\S\S) \]') self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<HOLE1>\S\S), (?P<HOLE2>\S\S) \]')
self.rexx.setActionStepRegex('.*\n(?P<PNAME>.*) (?P<ATYPE>bets|checks|raises|calls|folds)(\s\[\$ (?P<BET>[.\d]+) USD\])?') self.rexx.setActionStepRegex('.*\n(?P<PNAME>.*) (?P<ATYPE>bets|checks|raises|calls|folds)(\s\[\$ (?P<BET>[.\d]+) USD\])?')
self.rexx.compileRegexes() self.rexx.compileRegexes()
def readSupportedGames(self): def readSupportedGames(self):
pass pass
def determineGameType(self): def determineGameType(self):
# Cheating with this regex, only support nlhe at the moment # Cheating with this regex, only support nlhe at the moment
gametype = ["ring", "hold", "nl"] gametype = ["ring", "hold", "nl"]
m = self.rexx.game_info_re.search(self.obs) m = self.rexx.game_info_re.search(self.obs)
gametype = gametype + [m.group('SB')] gametype = gametype + [m.group('SB')]
gametype = gametype + [m.group('BB')] gametype = gametype + [m.group('BB')]
return gametype return gametype
def readHandInfo(self, hand): def readHandInfo(self, hand):
m = self.rexx.hand_info_re.search(hand.string) m = self.rexx.hand_info_re.search(hand.string)
hand.handid = m.group('HID') hand.handid = m.group('HID')
hand.tablename = m.group('TABLE') hand.tablename = m.group('TABLE')
# 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')
@ -106,70 +109,68 @@ class Everleaf(HandHistoryConverter):
# 2008/11/10 3:58:52 ET # 2008/11/10 3:58:52 ET
#TODO: Do conversion from GMT to ET #TODO: Do conversion from GMT to ET
#TODO: Need some date functions to convert to different timezones (Date::Manip for perl rocked for this) #TODO: Need some date functions to convert to different timezones (Date::Manip for perl rocked for this)
hand.starttime = "%d/%02d/%02d %d:%02d:%02d ET" %(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), hand.starttime = "%d/%02d/%02d %d:%02d:%02d ET" %(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')),
int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC'))) int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC')))
hand.buttonpos = int(m.group('BUTTON')) hand.buttonpos = int(m.group('BUTTON'))
def readPlayerStacks(self, hand): def readPlayerStacks(self, hand):
m = self.rexx.player_info_re.finditer(hand.string) m = self.rexx.player_info_re.finditer(hand.string)
players = [] players = []
for a in m: for a in m:
hand.addPlayer(a.group('SEAT'), a.group('PNAME'), a.group('CASH')) hand.addPlayer(a.group('SEAT'), a.group('PNAME'), a.group('CASH'))
#players = players + [[a.group('SEAT'), a.group('PNAME'), a.group('CASH')]]
#hand.players = players
def markStreets(self, hand): def markStreets(self, hand):
# PREFLOP = ** Dealing down cards ** # PREFLOP = ** Dealing down cards **
m = re.search('(\*\* Dealing down cards \*\*\n)(?P<PREFLOP>.*?\n\*\*)?( Dealing Flop \*\* \[ (?P<FLOP1>\S\S), (?P<FLOP2>\S\S), (?P<FLOP3>\S\S) \])?(?P<FLOP>.*?\*\*)?( Dealing Turn \*\* \[ (?P<TURN1>\S\S) \])?(?P<TURN>.*?\*\*)?( Dealing River \*\* \[ (?P<RIVER1>\S\S) \])?(?P<RIVER>.*)', hand.string,re.DOTALL) m = re.search('(\*\* Dealing down cards \*\*\n)(?P<PREFLOP>.*?\n\*\*)?( Dealing Flop \*\* \[ (?P<FLOP1>\S\S), (?P<FLOP2>\S\S), (?P<FLOP3>\S\S) \])?(?P<FLOP>.*?\*\*)?( Dealing Turn \*\* \[ (?P<TURN1>\S\S) \])?(?P<TURN>.*?\*\*)?( Dealing River \*\* \[ (?P<RIVER1>\S\S) \])?(?P<RIVER>.*)', hand.string,re.DOTALL)
# for street in m.groupdict(): # for street in m.groupdict():
# print "DEBUG: Street: %s\tspan: %s" %(street, str(m.span(street))) # print "DEBUG: Street: %s\tspan: %s" %(street, str(m.span(street)))
hand.streets = m hand.streets = m
def readBlinds(self, hand): def readBlinds(self, hand):
try: try:
m = self.rexx.small_blind_re.search(hand.string) m = self.rexx.small_blind_re.search(hand.string)
hand.addBlind(m.group('PNAME'), m.group('SB')) hand.addBlind(m.group('PNAME'), m.group('SB'))
#hand.posted = [m.group('PNAME')] #hand.posted = [m.group('PNAME')]
except: except:
hand.addBlind(None, 0) hand.addBlind(None, 0)
#hand.posted = ["FpdbNBP"] #hand.posted = ["FpdbNBP"]
m = self.rexx.big_blind_re.finditer(hand.string) m = self.rexx.big_blind_re.finditer(hand.string)
for a in m: for a in m:
hand.addBlind(a.group('PNAME'), a.group('BB')) hand.addBlind(a.group('PNAME'), a.group('BB'))
#hand.posted = hand.posted + [a.group('PNAME')] #hand.posted = hand.posted + [a.group('PNAME')]
def readHeroCards(self, hand): def readHeroCards(self, hand):
m = self.rexx.hero_cards_re.search(hand.string) m = self.rexx.hero_cards_re.search(hand.string)
if(m == None): if(m == None):
#Not involved in hand #Not involved in hand
hand.involved = False hand.involved = False
else: else:
hand.hero = m.group('PNAME') hand.hero = m.group('PNAME')
hand.addHoleCards(m.group('HOLE1'), m.group('HOLE2')) hand.addHoleCards(m.group('HOLE1'), m.group('HOLE2'))
def readAction(self, hand, street): def readAction(self, hand, street):
m = self.rexx.action_re.finditer(hand.streets.group(street)) m = self.rexx.action_re.finditer(hand.streets.group(street))
hand.actions[street] = [] hand.actions[street] = []
for action in m: for action in m:
if action.group('ATYPE') == 'raises': if action.group('ATYPE') == 'raises':
hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') ) hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == 'calls': elif action.group('ATYPE') == 'calls':
hand.addCall( street, action.group('PNAME'), action.group('BET') ) hand.addCall( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == 'bets': elif action.group('ATYPE') == 'bets':
hand.addBet( street, action.group('PNAME'), action.group('BET') ) hand.addBet( street, action.group('PNAME'), action.group('BET') )
# mct: do we need to keep bet distinct from raise? else:
# hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE'), action.group('BET')]] print "DEBUG: unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),)
else: hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE')]]
print "DEBUG: unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),)
hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE')]]
#print "DEBUG: readAction: %s " %(hand.actions)
def getRake(self, hand):
hand.rake = hand.totalpot * Decimal('0.05') # probably not quite right
if __name__ == "__main__": if __name__ == "__main__":
c = Configuration.Config() c = Configuration.Config()
e = Everleaf(c, "Speed_Kuala.txt") e = Everleaf(c, "Speed_Kuala.txt")
e.processFile() e.processFile()
print str(e) print str(e)

View File

@ -28,378 +28,400 @@ import operator
from xml.dom.minidom import Node from xml.dom.minidom import Node
class HandHistoryConverter: class HandHistoryConverter:
def __init__(self, config, file, sitename): def __init__(self, config, file, sitename):
print "HandHistory init called" print "HandHistory init called"
self.c = config self.c = config
self.sitename = sitename self.sitename = sitename
self.obs = "" # One big string self.obs = "" # One big string
self.filetype = "text" self.filetype = "text"
self.doc = None # For XML based HH files self.doc = None # For XML based HH files
self.file = file self.file = file
self.hhbase = self.c.get_import_parameters().get("hhArchiveBase") self.hhbase = self.c.get_import_parameters().get("hhArchiveBase")
self.hhbase = os.path.expanduser(self.hhbase) self.hhbase = os.path.expanduser(self.hhbase)
self.hhdir = os.path.join(self.hhbase,sitename) self.hhdir = os.path.join(self.hhbase,sitename)
self.gametype = [] self.gametype = []
# self.ofile = os.path.join(self.hhdir,file) # self.ofile = os.path.join(self.hhdir,file)
self.rexx = FpdbRegex.FpdbRegex() self.rexx = FpdbRegex.FpdbRegex()
def __str__(self): def __str__(self):
tmp = "HandHistoryConverter: '%s'\n" % (self.sitename) tmp = "HandHistoryConverter: '%s'\n" % (self.sitename)
tmp = tmp + "\thhbase: '%s'\n" % (self.hhbase) tmp = tmp + "\thhbase: '%s'\n" % (self.hhbase)
tmp = tmp + "\thhdir: '%s'\n" % (self.hhdir) tmp = tmp + "\thhdir: '%s'\n" % (self.hhdir)
tmp = tmp + "\tfiletype: '%s'\n" % (self.filetype) tmp = tmp + "\tfiletype: '%s'\n" % (self.filetype)
tmp = tmp + "\tinfile: '%s'\n" % (self.file) tmp = tmp + "\tinfile: '%s'\n" % (self.file)
# tmp = tmp + "\toutfile: '%s'\n" % (self.ofile) # tmp = tmp + "\toutfile: '%s'\n" % (self.ofile)
# tmp = tmp + "\tgametype: '%s'\n" % (self.gametype[0]) # tmp = tmp + "\tgametype: '%s'\n" % (self.gametype[0])
# tmp = tmp + "\tgamebase: '%s'\n" % (self.gametype[1]) # tmp = tmp + "\tgamebase: '%s'\n" % (self.gametype[1])
# tmp = tmp + "\tlimit: '%s'\n" % (self.gametype[2]) # tmp = tmp + "\tlimit: '%s'\n" % (self.gametype[2])
# tmp = tmp + "\tsb/bb: '%s/%s'\n" % (self.gametype[3], self.gametype[4]) # tmp = tmp + "\tsb/bb: '%s/%s'\n" % (self.gametype[3], self.gametype[4])
return tmp return tmp
def processFile(self): def processFile(self):
if not self.sanityCheck(): if not self.sanityCheck():
print "Cowardly refusing to continue after failed sanity check" print "Cowardly refusing to continue after failed sanity check"
return return
self.readFile(self.file) self.readFile(self.file)
self.gametype = self.determineGameType() self.gametype = self.determineGameType()
self.hands = self.splitFileIntoHands() self.hands = self.splitFileIntoHands()
for hand in self.hands: for hand in self.hands:
self.readHandInfo(hand) self.readHandInfo(hand)
self.readPlayerStacks(hand) self.readPlayerStacks(hand)
self.markStreets(hand) self.markStreets(hand)
self.readBlinds(hand) self.readBlinds(hand)
self.readHeroCards(hand) self.readHeroCards(hand)
# Read action (Note: no guarantee this is in hand order. # Read action (Note: no guarantee this is in hand order.
for street in hand.streets.groupdict(): for street in hand.streets.groupdict():
self.readAction(hand, street) self.readAction(hand, street)
if(hand.involved == True): # finalise it (total the pot)
#self.writeHand("output file", hand) hand.totalPot()
hand.printHand() self.getRake(hand)
else:
pass #Don't write out observed hands
# Functions to be implemented in the inheriting class if(hand.involved == True):
def readSupportedGames(self): abstract #self.writeHand("output file", hand)
hand.printHand()
else:
pass #Don't write out observed hands
# should return a list #####
# type base limit # These functions are parse actions that may be overridden by the inheriting class
# [ ring, hold, nl , sb, bb ] #
# Valid types specified in docs/tabledesign.html in Gametypes
def determineGameType(self): abstract
#TODO: Comment def readSupportedGames(self): abstract
def readHandInfo(self, hand): abstract
# Needs to return a list of lists in the format # should return a list
# [['seat#', 'player1name', 'stacksize'] ['seat#', 'player2name', 'stacksize'] [...]] # type base limit
def readPlayerStacks(self, hand): abstract # [ ring, hold, nl , sb, bb ]
# Valid types specified in docs/tabledesign.html in Gametypes
def determineGameType(self): abstract
# Needs to return a MatchObject with group names identifying the streets into the Hand object # Read any of:
def markStreets(self, hand): abstract # HID HandID
# TABLE Table name
# SB small blind
# BB big blind
# GAMETYPE gametype
# YEAR MON DAY HR MIN SEC datetime
# BUTTON button seat number
def readHandInfo(self, hand): abstract
#Needs to return a list in the format # Needs to return a list of lists in the format
# ['player1name', 'player2name', ...] where player1name is the sb and player2name is bb, # [['seat#', 'player1name', 'stacksize'] ['seat#', 'player2name', 'stacksize'] [...]]
# addtional players are assumed to post a bb oop def readPlayerStacks(self, hand): abstract
def readBlinds(self, hand): abstract
def readHeroCards(self, hand): abstract
def readAction(self, hand, street): abstract
def sanityCheck(self): # Needs to return a MatchObject with group names identifying the streets into the Hand object
sane = True # that is, pulls the chunks of preflop, flop, turn and river text into hand.streets MatchObject.
base_w = False def markStreets(self, hand): abstract
#Check if hhbase exists and is writable
#Note: Will not try to create the base HH directory
if not (os.access(self.hhbase, os.W_OK) and os.path.isdir(self.hhbase)):
print "HH Sanity Check: Directory hhbase '" + self.hhbase + "' doesn't exist or is not writable"
else:
#Check if hhdir exists and is writable
if not os.path.isdir(self.hhdir):
# In first pass, dir may not exist. Attempt to create dir
print "Creating directory: '%s'" % (self.hhdir)
os.mkdir(self.hhdir)
sane = True
elif os.access(self.hhdir, os.W_OK):
sane = True
else:
print "HH Sanity Check: Directory hhdir '" + self.hhdir + "' or its parent directory are not writable"
return sane #Needs to return a list in the format
# ['player1name', 'player2name', ...] where player1name is the sb and player2name is bb,
# addtional players are assumed to post a bb oop
def readBlinds(self, hand): abstract
def readHeroCards(self, hand): abstract
def readAction(self, hand, street): abstract
# Functions not necessary to implement in sub class # Some sites don't report the rake. This will be called at the end of the hand after the pot total has been calculated
def setFileType(self, filetype = "text"): # so that an inheriting class can calculate it for the specific site if need be.
self.filetype = filetype def getRake(self, hand): abstract
def splitFileIntoHands(self): def sanityCheck(self):
hands = [] sane = True
list = self.rexx.split_hand_re.split(self.obs) base_w = False
list.pop() #Last entry is empty #Check if hhbase exists and is writable
for l in list: #Note: Will not try to create the base HH directory
if not (os.access(self.hhbase, os.W_OK) and os.path.isdir(self.hhbase)):
print "HH Sanity Check: Directory hhbase '" + self.hhbase + "' doesn't exist or is not writable"
else:
#Check if hhdir exists and is writable
if not os.path.isdir(self.hhdir):
# In first pass, dir may not exist. Attempt to create dir
print "Creating directory: '%s'" % (self.hhdir)
os.mkdir(self.hhdir)
sane = True
elif os.access(self.hhdir, os.W_OK):
sane = True
else:
print "HH Sanity Check: Directory hhdir '" + self.hhdir + "' or its parent directory are not writable"
return sane
# Functions not necessary to implement in sub class
def setFileType(self, filetype = "text"):
self.filetype = filetype
def splitFileIntoHands(self):
hands = []
list = self.rexx.split_hand_re.split(self.obs)
list.pop() #Last entry is empty
for l in list:
# print "'" + l + "'" # print "'" + l + "'"
hands = hands + [Hand(self.sitename, self.gametype, l)] hands = hands + [Hand(self.sitename, self.gametype, l)]
return hands return hands
def readFile(self, filename): def readFile(self, filename):
"""Read file""" """Read file"""
print "Reading file: '%s'" %(filename) print "Reading file: '%s'" %(filename)
if(self.filetype == "text"): if(self.filetype == "text"):
infile=open(filename, "rU") infile=open(filename, "rU")
self.obs = infile.read() self.obs = infile.read()
infile.close() infile.close()
elif(self.filetype == "xml"): elif(self.filetype == "xml"):
try: try:
doc = xml.dom.minidom.parse(filename) doc = xml.dom.minidom.parse(filename)
self.doc = doc self.doc = doc
except: except:
traceback.print_exc(file=sys.stderr) traceback.print_exc(file=sys.stderr)
def writeHand(self, file, hand): def writeHand(self, file, hand):
"""Write out parsed data""" """Write out parsed data"""
print "DEBUG: *************************" print "DEBUG: *************************"
print "DEBUG: Start of print hand" print "DEBUG: Start of print hand"
print "DEBUG: *************************" print "DEBUG: *************************"
print "%s Game #%s: %s ($%s/$%s) - %s" %(hand.sitename, hand.handid, "XXXXhand.gametype", hand.sb, hand.bb, hand.starttime) print "%s Game #%s: %s ($%s/$%s) - %s" %(hand.sitename, hand.handid, "XXXXhand.gametype", hand.sb, hand.bb, hand.starttime)
print "Table '%s' %d-max Seat #%s is the button" %(hand.tablename, hand.maxseats, hand.buttonpos) print "Table '%s' %d-max Seat #%s is the button" %(hand.tablename, hand.maxseats, hand.buttonpos)
for player in hand.players: for player in hand.players:
print "Seat %s: %s ($%s)" %(player[0], player[1], player[2]) print "Seat %s: %s ($%s)" %(player[0], player[1], player[2])
if(hand.posted[0] == "FpdbNBP"): if(hand.posted[0] == "FpdbNBP"):
print "No small blind posted" print "No small blind posted"
else: else:
print "%s: posts small blind $%s" %(hand.posted[0], hand.sb) print "%s: posts small blind $%s" %(hand.posted[0], hand.sb)
#May be more than 1 bb posting #May be more than 1 bb posting
print "%s: posts big blind $%s" %(hand.posted[1], hand.bb) print "%s: posts big blind $%s" %(hand.posted[1], hand.bb)
if(len(hand.posted) > 2): if(len(hand.posted) > 2):
# Need to loop on all remaining big blinds - lazy # Need to loop on all remaining big blinds - lazy
print "XXXXXXXXX FIXME XXXXXXXX" print "XXXXXXXXX FIXME XXXXXXXX"
print "*** HOLE CARDS ***" print "*** HOLE CARDS ***"
print "Dealt to %s [%s %s]" %(hand.hero , hand.holecards[0], hand.holecards[1]) print "Dealt to %s [%s %s]" %(hand.hero , hand.holecards[0], hand.holecards[1])
# #
## ACTION STUFF ## ACTION STUFF
# This is no limit only at the moment # This is no limit only at the moment
for act in hand.actions['PREFLOP']: for act in hand.actions['PREFLOP']:
self.printActionLine(act, 0) self.printActionLine(act, 0)
if 'PREFLOP' in hand.actions: if 'PREFLOP' in hand.actions:
for act in hand.actions['PREFLOP']: for act in hand.actions['PREFLOP']:
print "PF action" print "PF action"
if 'FLOP' in hand.actions: if 'FLOP' in hand.actions:
print "*** FLOP *** [%s %s %s]" %(hand.streets.group("FLOP1"), hand.streets.group("FLOP2"), hand.streets.group("FLOP3")) print "*** FLOP *** [%s %s %s]" %(hand.streets.group("FLOP1"), hand.streets.group("FLOP2"), hand.streets.group("FLOP3"))
for act in hand.actions['FLOP']: for act in hand.actions['FLOP']:
self.printActionLine(act, 0) self.printActionLine(act, 0)
if 'TURN' in hand.actions: if 'TURN' in hand.actions:
print "*** TURN *** [%s %s %s] [%s]" %(hand.streets.group("FLOP1"), hand.streets.group("FLOP2"), hand.streets.group("FLOP3"), hand.streets.group("TURN1")) print "*** TURN *** [%s %s %s] [%s]" %(hand.streets.group("FLOP1"), hand.streets.group("FLOP2"), hand.streets.group("FLOP3"), hand.streets.group("TURN1"))
for act in hand.actions['TURN']: for act in hand.actions['TURN']:
self.printActionLine(act, 0) self.printActionLine(act, 0)
if 'RIVER' in hand.actions: if 'RIVER' in hand.actions:
print "*** RIVER *** [%s %s %s %s] [%s]" %(hand.streets.group("FLOP1"), hand.streets.group("FLOP2"), hand.streets.group("FLOP3"), hand.streets.group("TURN1"), hand.streets.group("RIVER1")) print "*** RIVER *** [%s %s %s %s] [%s]" %(hand.streets.group("FLOP1"), hand.streets.group("FLOP2"), hand.streets.group("FLOP3"), hand.streets.group("TURN1"), hand.streets.group("RIVER1"))
for act in hand.actions['RIVER']: for act in hand.actions['RIVER']:
self.printActionLine(act, 0) self.printActionLine(act, 0)
print "*** SUMMARY ***" print "*** SUMMARY ***"
print "XXXXXXXXXXXX Need sumary info XXXXXXXXXXX" print "XXXXXXXXXXXX Need sumary info XXXXXXXXXXX"
# print "Total pot $%s | Rake $%s)" %(hand.totalpot $" + hand.rake) # print "Total pot $%s | Rake $%s)" %(hand.totalpot $" + hand.rake)
# print "Board [" + boardcards + "]" # print "Board [" + boardcards + "]"
# #
# SUMMARY STUFF # SUMMARY STUFF
def printActionLine(self, act, pot): def printActionLine(self, act, pot):
if act[1] == 'folds' or act[1] == 'checks': if act[1] == 'folds' or act[1] == 'checks':
print "%s: %s " %(act[0], act[1]) print "%s: %s " %(act[0], act[1])
if act[1] == 'calls': if act[1] == 'calls':
print "%s: %s $%s" %(act[0], act[1], act[2]) print "%s: %s $%s" %(act[0], act[1], act[2])
if act[1] == 'raises': if act[1] == 'raises':
print "%s: %s $%s to XXXpottotalXXX" %(act[0], act[1], act[2]) print "%s: %s $%s to XXXpottotalXXX" %(act[0], act[1], act[2])
#takes a poker float (including , for thousand seperator and converts it to an int #takes a poker float (including , for thousand seperator and converts it to an int
def float2int (self, string): def float2int (self, string):
pos=string.find(",") pos=string.find(",")
if (pos!=-1): #remove , the thousand seperator if (pos!=-1): #remove , the thousand seperator
string=string[0:pos]+string[pos+1:] string=string[0:pos]+string[pos+1:]
pos=string.find(".") pos=string.find(".")
if (pos!=-1): #remove decimal point if (pos!=-1): #remove decimal point
string=string[0:pos]+string[pos+1:] string=string[0:pos]+string[pos+1:]
result = int(string) result = int(string)
if pos==-1: #no decimal point - was in full dollars - need to multiply with 100 if pos==-1: #no decimal point - was in full dollars - need to multiply with 100
result*=100 result*=100
return result return result
#end def float2int #end def float2int
class Hand: class Hand:
# def __init__(self, sitename, gametype, sb, bb, string): # def __init__(self, sitename, gametype, sb, bb, string):
UPS = {'a':'A', 't':'T', 'j':'J', 'q':'Q', 'k':'K'} UPS = {'a':'A', 't':'T', 'j':'J', 'q':'Q', 'k':'K'}
STREETS = ['BLINDS','PREFLOP','FLOP','TURN','RIVER'] STREETS = ['BLINDS','PREFLOP','FLOP','TURN','RIVER']
def __init__(self, sitename, gametype, string): def __init__(self, sitename, gametype, string):
self.sitename = sitename self.sitename = sitename
self.gametype = gametype self.gametype = gametype
self.string = string self.string = string
self.streets = None # A MatchObject using a groupnames to identify streets. self.streets = None # A MatchObject using a groupnames to identify streets.
self.actions = {} self.actions = {}
self.handid = 0 self.handid = 0
self.sb = gametype[3] self.sb = gametype[3]
self.bb = gametype[4] self.bb = gametype[4]
self.tablename = "Slartibartfast" self.tablename = "Slartibartfast"
self.maxseats = 10 self.maxseats = 10
self.counted_seats = 0 self.counted_seats = 0
self.buttonpos = 0 self.buttonpos = 0
self.seating = [] self.seating = []
self.players = [] self.players = []
self.posted = [] self.posted = []
self.involved = True self.involved = True
self.hero = "Hiro" self.hero = "Hiro"
self.holecards = "Xx Xx" self.holecards = "Xx Xx"
self.action = [] self.action = []
self.totalpot = None
self.rake = None
self.rake = 0 self.bets = {}
self.lastBet = {}
for street in self.STREETS:
self.bets[street] = {}
self.lastBet[street] = 0
self.bets = {} def addPlayer(self, seat, name, chips):
self.lastBet = {} """seat, an int indicating the seat
self.orderedBets = {} name, the player name
for street in self.STREETS: chips, the chips the player has at the start of the hand"""
self.bets[street] = {} #self.players.append(name)
self.lastBet[street] = 0 self.players.append([seat, name, chips])
#self.startChips[name] = chips
def addPlayer(self, seat, name, chips): #self.endChips[name] = chips
"""seat, an int indicating the seat #self.winners[name] = 0
name, the player name for street in self.STREETS:
chips, the chips the player has at the start of the hand""" self.bets[street][name] = []
#self.players.append(name)
self.players.append([seat, name, chips])
#self.startChips[name] = chips
#self.endChips[name] = chips
#self.winners[name] = 0
for street in self.STREETS:
self.bets[street][name] = [0]
def addHoleCards(self,h1,h2,seat=None): # generalise to add hole cards for a specific seat or player def addHoleCards(self,h1,h2,seat=None): # generalise to add hole cards for a specific seat or player
self.holecards = [self.card(h1), self.card(h2)] self.holecards = [self.card(h1), self.card(h2)]
def card(self,c): def card(self,c):
"""upper case the ranks but not suits, 'atjqk' => 'ATJQK'""" """upper case the ranks but not suits, 'atjqk' => 'ATJQK'"""
# don't know how to make this 'static' # don't know how to make this 'static'
for k,v in self.UPS.items(): for k,v in self.UPS.items():
c = c.replace(k,v) c = c.replace(k,v)
return c return c
def addBlind(self, player, amount): def addBlind(self, player, amount):
#self.bets['BLINDS'][player].append(Decimal(amount)) # if player is None, it's a missing small blind.
self.lastBet['PREFLOP'] = Decimal(amount) if player is not None:
self.posted += [player] self.bets['PREFLOP'][player].append(Decimal(amount))
self.lastBet['PREFLOP'] = Decimal(amount)
self.posted += [player]
def addCall(self, street, player=None, amount=0): def addCall(self, street, player=None, amount=None):
self.bets[street][player].append(Decimal(amount)) # Potentially calculate the amount of the call if not supplied
#self.lastBet[street] = Decimal(amount) # corner cases include if player would be all in
self.actions[street] += [[player, 'calls', amount]] if amount is not None:
self.bets[street][player].append(Decimal(amount))
#self.lastBet[street] = Decimal(amount)
self.actions[street] += [[player, 'calls', amount]]
def addRaiseTo(self, street, player, amountTo): def addRaiseTo(self, street, player, amountTo):
# amount is the amount raised to, not the amount raised.by # Given only the amount raised to, the amount of the raise can be calculated by
committedThisStreet = reduce(operator.add, self.bets[street][player], 0) # working out how much this player has already in the pot
amountToCall = self.lastBet[street] - committedThisStreet # (which is the sum of self.bets[street][player])
self.lastBet[street] = Decimal(amountTo) # and how much he needs to call to match the previous player
amountBy = Decimal(amountTo) - amountToCall # (which is tracked by self.lastBet)
self.bets[street][player].append(amountBy) committedThisStreet = reduce(operator.add, self.bets[street][player], 0)
self.actions[street] += [[player, 'raises', amountBy, amountTo]] amountToCall = self.lastBet[street] - committedThisStreet
self.lastBet[street] = Decimal(amountTo)
amountBy = Decimal(amountTo) - amountToCall
self.bets[street][player].append(amountBy+amountToCall)
self.actions[street] += [[player, 'raises', amountBy, amountTo]]
#def addRaiseTo(self, street, player=None, amountTo=None): def addBet(self, street, player=None, amount=0):
#self.amounts[street] += Decimal(amountTo) self.bets[street][name].append(Decimal(amount))
self.orderedBets[street].append(Decimal(amount))
self.actions[street] += [[player, 'bets', amount]]
def totalPot(self):
def addBet(self, street, player=None, amount=0): if self.totalpot is None:
self.bets[street][name].append(Decimal(amount)) self.totalpot = 0
self.orderedBets[street].append(Decimal(amount))
self.actions[street] += [[player, 'bets', amount]] # player names:
# print [x[1] for x in self.players]
for player in [x[1] for x in self.players]:
for street in self.STREETS:
print street, self.bets[street][player]
self.totalpot += reduce(operator.add, self.bets[street][player], 0)
def printHand(self): def printHand(self):
# PokerStars format. # PokerStars format.
print "### DEBUG ###" print "### DEBUG ###"
print "%s Game #%s: %s ($%s/$%s) - %s" %(self.sitename, self.handid, "XXXXhand.gametype", self.sb, self.bb, self.starttime) print "%s Game #%s: %s ($%s/$%s) - %s" %(self.sitename, self.handid, "XXXXhand.gametype", self.sb, self.bb, self.starttime)
print "Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos) print "Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos)
for player in self.players: for player in self.players:
print "Seat %s: %s ($%s)" %(player[0], player[1], player[2]) print "Seat %s: %s ($%s)" %(player[0], player[1], player[2])
if(self.posted[0] is None): if(self.posted[0] is None):
print "No small blind posted" print "No small blind posted"
else: else:
print "%s: posts small blind $%s" %(self.posted[0], self.sb) print "%s: posts small blind $%s" %(self.posted[0], self.sb)
#May be more than 1 bb posting #May be more than 1 bb posting
for a in self.posted[1:]: for a in self.posted[1:]:
print "%s: posts big blind $%s" %(self.posted[1], self.bb) print "%s: posts big blind $%s" %(self.posted[1], self.bb)
# What about big & small blinds? # What about big & small blinds?
print "*** HOLE CARDS ***" print "*** HOLE CARDS ***"
print "Dealt to %s [%s %s]" %(self.hero , self.holecards[0], self.holecards[1]) print "Dealt to %s [%s %s]" %(self.hero , self.holecards[0], self.holecards[1])
if 'PREFLOP' in self.actions: if 'PREFLOP' in self.actions:
for act in self.actions['PREFLOP']: for act in self.actions['PREFLOP']:
self.printActionLine(act) self.printActionLine(act)
if 'FLOP' in self.actions: if 'FLOP' in self.actions:
print "*** FLOP *** [%s %s %s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3")) print "*** FLOP *** [%s %s %s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"))
for act in self.actions['FLOP']: for act in self.actions['FLOP']:
self.printActionLine(act) self.printActionLine(act)
if 'TURN' in self.actions: if 'TURN' in self.actions:
print "*** TURN *** [%s %s %s] [%s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"), self.streets.group("TURN1")) print "*** TURN *** [%s %s %s] [%s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"), self.streets.group("TURN1"))
for act in self.actions['TURN']: for act in self.actions['TURN']:
self.printActionLine(act) self.printActionLine(act)
if 'RIVER' in self.actions: if 'RIVER' in self.actions:
print "*** RIVER *** [%s %s %s %s] [%s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"), self.streets.group("TURN1"), self.streets.group("RIVER1")) print "*** RIVER *** [%s %s %s %s] [%s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"), self.streets.group("TURN1"), self.streets.group("RIVER1"))
for act in self.actions['RIVER']: for act in self.actions['RIVER']:
self.printActionLine(act) self.printActionLine(act)
print "*** SUMMARY ***"
print "XXXXXXXXXXXX Need sumary info XXXXXXXXXXX"
# print "Total pot $%s | Rake $%s)" %(hand.totalpot $" + hand.rake)
# print "Board [" + boardcards + "]"
#
# SUMMARY STUFF
#print self.sitename #Some sites don't have a showdown section so we have to figure out if there should be one
#print self.gametype # The logic for a showdown is: at the end of river action there are at least two players in the hand
#print self.string if 'SHOWDOWN' in self.actions:
#print self.handid print "*** SHOW DOWN ***"
#print self.sb print "what do they show"
#print self.bb
#print self.tablename
#print self.maxseats
#print self.counted_seats
#print self.buttonpos
#print self.seating
#print self.players
#print self.posted
#print self.action
#print self.involved
#print self.hero
def printActionLine(self, act): print "*** SUMMARY ***"
if act[1] == 'folds' or act[1] == 'checks': print "Total pot $%s | Rake $%s)" % (self.totalpot, self.rake)
print "%s: %s " %(act[0], act[1]) print "Board [%s %s %s %s %s]" % (self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"), self.streets.group("TURN1"), self.streets.group("RIVER1"))
if act[1] == 'calls':
print "%s: %s $%s" %(act[0], act[1], act[2])
if act[1] == 'raises': def printActionLine(self, act):
print "%s: %s $%s to $%s" %(act[0], act[1], act[2], act[3]) if act[1] == 'folds' or act[1] == 'checks':
print "%s: %s " %(act[0], act[1])
if act[1] == 'calls':
print "%s: %s $%s" %(act[0], act[1], act[2])
if act[1] == 'raises':
print "%s: %s $%s to $%s" %(act[0], act[1], act[2], act[3])