Everleaf uncalled bets; pot total; rake

This commit is contained in:
Matt Turnbull 2008-12-14 22:05:51 +00:00
parent 7926ac9def
commit 3dbb0e8376
3 changed files with 83 additions and 25 deletions

View File

@ -75,6 +75,7 @@ class Everleaf(HandHistoryConverter):
self.rexx.setPlayerInfoRegex('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\s+(\$ (?P<CASH>[.0-9]+) USD|new player|All-in) \)') self.rexx.setPlayerInfoRegex('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\s+(\$ (?P<CASH>[.0-9]+) USD|new player|All-in) \)')
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]+)')
self.rexx.setPostBothRegex('.*\n(?P<PNAME>.*): posts small \& big blinds \[\$? (?P<SBBB>[.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\])?')
@ -131,7 +132,8 @@ class Everleaf(HandHistoryConverter):
r"(\*\* Dealing Turn \*\* \[ \S\S \](?P<TURN>.+(?=\*\* Dealing River \*\*)|.+))?" r"(\*\* Dealing Turn \*\* \[ \S\S \](?P<TURN>.+(?=\*\* Dealing River \*\*)|.+))?"
r"(\*\* Dealing River \*\* \[ \S\S \](?P<RIVER>.+))?", hand.string,re.DOTALL) r"(\*\* Dealing River \*\* \[ \S\S \](?P<RIVER>.+))?", hand.string,re.DOTALL)
hand.streets = m hand.addStreets(m)
def readCommunityCards(self, hand): def readCommunityCards(self, hand):
# currently regex in wrong place pls fix my brain's fried # currently regex in wrong place pls fix my brain's fried
@ -146,15 +148,13 @@ class Everleaf(HandHistoryConverter):
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'), 'small blind', m.group('SB'))
#hand.posted = [m.group('PNAME')] except: # no small blind
except: hand.addBlind(None, None, None)
hand.addBlind(None, 0) for a in self.rexx.big_blind_re.finditer(hand.string):
#hand.posted = ["FpdbNBP"] hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
m = self.rexx.big_blind_re.finditer(hand.string) for a in self.rexx.both_blinds_re.finditer(hand.string):
for a in m: hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB'))
hand.addBlind(a.group('PNAME'), a.group('BB'))
#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)
@ -167,7 +167,6 @@ class Everleaf(HandHistoryConverter):
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] = []
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') )
@ -182,6 +181,7 @@ class Everleaf(HandHistoryConverter):
else: else:
print "DEBUG: unimplemented readAction: %s %s" %(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')]] #hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE')]]
# TODO: Everleaf does not record uncalled bets.
def readShowdownActions(self, hand): def readShowdownActions(self, hand):
@ -201,9 +201,6 @@ class Everleaf(HandHistoryConverter):
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT')) hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
def getRake(self, hand):
hand.rake = hand.totalpot - hand.totalcollected # * Decimal('0.05') # probably not quite right
if __name__ == "__main__": if __name__ == "__main__":
c = Configuration.Config() c = Configuration.Config()
e = Everleaf(c, "regression-test-files/everleaf/Speed_Kuala_full.txt") e = Everleaf(c, "regression-test-files/everleaf/Speed_Kuala_full.txt")

View File

@ -88,6 +88,7 @@ class Hand:
self.action = [] self.action = []
self.totalpot = None self.totalpot = None
self.totalcollected = None self.totalcollected = None
self.rake = None self.rake = None
self.bets = {} self.bets = {}
@ -110,6 +111,17 @@ If a player has None chips he won't be added."""
self.bets[street][name] = [] self.bets[street][name] = []
def addStreets(self, match):
# go through m and initialise actions to empty list for each street.
if match is not None:
self.streets = match
for street in match.groupdict():
if match.group(street) is not None:
self.actions[street] = []
else:
print "empty markStreets match" # better to raise exception and put process hand in a try block
def addHoleCards(self, cards, player): def addHoleCards(self, cards, player):
"""\ """\
Assigns observed holecards to a player. Assigns observed holecards to a player.
@ -162,21 +174,27 @@ For when a player shows cards for any reason (for showdown or out of choice).
c = c.replace(k,v) c = c.replace(k,v)
return c return c
def addBlind(self, player, amount): def addBlind(self, player, blindtype, amount):
# if player is None, it's a missing small blind. # if player is None, it's a missing small blind.
if player is not None: if player is not None:
self.bets['PREFLOP'][player].append(Decimal(amount)) self.bets['PREFLOP'][player].append(Decimal(amount))
self.actions['PREFLOP'] += [(player, 'posts', blindtype, amount)]
if blindtype == 'big blind':
self.lastBet['PREFLOP'] = Decimal(amount) self.lastBet['PREFLOP'] = Decimal(amount)
elif blindtype == 'small & big blinds':
# extra small blind is 'dead'
self.lastBet['PREFLOP'] = Decimal(self.bb)
self.posted += [player] self.posted += [player]
def addCall(self, street, player=None, amount=None): def addCall(self, street, player=None, amount=None):
# Potentially calculate the amount of the call if not supplied # Potentially calculate the amount of the call if not supplied
# corner cases include if player would be all in # corner cases include if player would be all in
if amount is not None: if amount is not None:
self.bets[street][player].append(Decimal(amount)) self.bets[street][player].append(Decimal(amount))
#self.lastBet[street] = Decimal(amount) #self.lastBet[street] = Decimal(amount)
self.actions[street] += [[player, 'calls', amount]] self.actions[street] += [(player, 'calls', amount)]
def addRaiseTo(self, street, player, amountTo): def addRaiseTo(self, street, player, amountTo):
"""\ """\
@ -193,21 +211,22 @@ Add a raise on [street] by [player] to [amountTo]
self.lastBet[street] = Decimal(amountTo) self.lastBet[street] = Decimal(amountTo)
amountBy = Decimal(amountTo) - amountToCall amountBy = Decimal(amountTo) - amountToCall
self.bets[street][player].append(amountBy+amountToCall) self.bets[street][player].append(amountBy+amountToCall)
self.actions[street] += [[player, 'raises', amountBy, amountTo]] self.actions[street] += [(player, 'raises', amountBy, amountTo, amountToCall)]
def addBet(self, street, player, amount): def addBet(self, street, player, amount):
self.checkPlayerExists(player) self.checkPlayerExists(player)
self.bets[street][player].append(Decimal(amount)) self.bets[street][player].append(Decimal(amount))
self.actions[street] += [[player, 'bets', amount]] self.actions[street] += [(player, 'bets', amount)]
self.lastBet[street] = Decimal(amount)
def addFold(self, street, player): def addFold(self, street, player):
self.checkPlayerExists(player) self.checkPlayerExists(player)
self.folded.add(player) self.folded.add(player)
self.actions[street] += [[player, 'folds']] self.actions[street] += [(player, 'folds')]
def addCheck(self, street, player): def addCheck(self, street, player):
self.checkPlayerExists(player) self.checkPlayerExists(player)
self.actions[street] += [[player, 'checks']] self.actions[street] += [(player, 'checks')]
def addCollectPot(self,player, pot): def addCollectPot(self,player, pot):
self.checkPlayerExists(player) self.checkPlayerExists(player)
@ -231,12 +250,50 @@ Known bug: doesn't take into account side pots"""
for street in self.streetList: for street in self.streetList:
#print street, self.bets[street][player] #print street, self.bets[street][player]
self.totalpot += reduce(operator.add, self.bets[street][player], 0) self.totalpot += reduce(operator.add, self.bets[street][player], 0)
print "conventional totalpot:", self.totalpot
self.totalpot = 0
print self.actions
for street in self.actions:
uncalled = 0
calls = [0]
for act in self.actions[street]:
if act[1] == 'bets': # [name, 'bets', amount]
self.totalpot += Decimal(act[2])
uncalled = Decimal(act[2]) # only the last bet or raise can be uncalled
calls = [0]
print "uncalled: ", uncalled
elif act[1] == 'raises': # [name, 'raises', amountby, amountto, amountcalled]
print "calls %s and raises %s to %s" % (act[4],act[2],act[3])
self.totalpot += Decimal(act[2]) + Decimal(act[4])
calls = [0]
uncalled = Decimal(act[2])
print "uncalled: ", uncalled
elif act[1] == 'calls': # [name, 'calls', amount]
self.totalpot += Decimal(act[2])
calls = calls + [Decimal(act[2])]
print "calls:", calls
if act[1] == ('posts'):
self.totalpot += Decimal(act[3])
uncalled = Decimal(act[3])
if uncalled > 0 and max(calls+[0]) < uncalled:
print "returning some bet, calls:", calls
print "returned: %.2f from %.2f" % ((uncalled - max(calls)), self.totalpot,)
self.totalpot -= (uncalled - max(calls))
print "new totalpot:", self.totalpot
if self.totalcollected is None: if self.totalcollected is None:
self.totalcollected = 0; self.totalcollected = 0;
for amount in self.collected.values(): for amount in self.collected.values():
self.totalcollected += Decimal(amount) self.totalcollected += Decimal(amount)
# TODO: Some sites (Everleaf) don't record uncalled bets. Figure out if a bet is uncalled and subtract it from self.totalcollected.
# remember that portions of bets may be uncalled, so:
# bet followed by no call is an uncalled bet
# bet x followed by call y where y < x has x-y uncalled (and second player all in)
def getGameTypeAsString(self): def getGameTypeAsString(self):
"""\ """\
@ -316,7 +373,8 @@ Map the tuple self.gametype onto the pokerstars string describing it
print "what do they show" print "what do they show"
print "*** SUMMARY ***" print "*** SUMMARY ***"
print "Total pot $%s | Rake $%.2f" % (self.totalcollected, self.rake) # TODO side pots print "Total pot $%s | Rake $%.2f" % (self.totalcollected, self.rake) # TODO: side pots
board = [] board = []
for s in self.board.values(): for s in self.board.values():
board += s board += s

View File

@ -161,7 +161,8 @@ class HandHistoryConverter:
def readPlayerStacks(self, hand): abstract def readPlayerStacks(self, hand): abstract
# Needs to return a MatchObject with group names identifying the streets into the Hand object # Needs to return a MatchObject with group names identifying the streets into the Hand object
# that is, pulls the chunks of preflop, flop, turn and river text into hand.streets MatchObject. # so groups are called by street names 'PREFLOP', 'FLOP', 'STREET2' etc
# blinds are done seperately
def markStreets(self, hand): abstract def markStreets(self, hand): abstract
#Needs to return a list in the format #Needs to return a list in the format
@ -173,8 +174,10 @@ class HandHistoryConverter:
def readCollectPot(self, hand): abstract def readCollectPot(self, hand): abstract
# Some sites don't report the rake. This will be called at the end of the hand after the pot total has been calculated # Some sites don't report the rake. This will be called at the end of the hand after the pot total has been calculated
# so that an inheriting class can calculate it for the specific site if need be. # an inheriting class can calculate it for the specific site if need be.
def getRake(self, hand): abstract def getRake(self, hand):
hand.rake = hand.totalpot - hand.totalcollected # * Decimal('0.05') # probably not quite right
def sanityCheck(self): def sanityCheck(self):
sane = False sane = False