Merge branch 'master' of git://git.assembla.com/fpdboz

This commit is contained in:
sqlcoder 2009-01-03 17:10:58 +00:00
commit 26ad0ff91b
2 changed files with 79 additions and 114 deletions

View File

@ -72,14 +72,14 @@ class Everleaf(HandHistoryConverter):
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+') self.rexx.setSplitHandRegex('\n\n+')
self.rexx.setHandInfoRegex('.*#(?P<HID>[0-9]+)\n.*\nBlinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>.*) - (?P<DATETIME>\d\d\d\d/\d\d/\d\d - \d\d:\d\d:\d\d)\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<DATETIME>\d\d\d\d/\d\d/\d\d - \d\d:\d\d:\d\d)\nTable (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
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|€ (?P<CASH>[.0-9]+) EUR|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]+)') self.rexx.setPostBothRegex('.*\n(?P<PNAME>.*): posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)')
self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<CARDS>.*) \]') self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<CARDS>.*) \]')
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|EUR)\])?')
self.rexx.setShowdownActionRegex('.*\n(?P<PNAME>.*) shows \[ (?P<CARDS>.*) \]') self.rexx.setShowdownActionRegex('.*\n(?P<PNAME>.*) shows \[ (?P<CARDS>.*) \]')
self.rexx.setCollectPotRegex('.*\n(?P<PNAME>.*) wins \$ (?P<POT>[.\d]+) USD(.*?\[ (?P<CARDS>.*?) \])?') self.rexx.setCollectPotRegex('.*\n(?P<PNAME>.*) wins \$ (?P<POT>[.\d]+) (USD|EUR)(.*?\[ (?P<CARDS>.*?) \])?')
#self.rexx.setCollectPotRegex('.*\n(?P<PNAME>.*) wins \$ (?P<POT>[.\d]+) USD(.*\[ (?P<CARDS>) \S\S, \S\S, \S\S, \S\S, \S\S \])?') #self.rexx.setCollectPotRegex('.*\n(?P<PNAME>.*) wins \$ (?P<POT>[.\d]+) USD(.*\[ (?P<CARDS>) \S\S, \S\S, \S\S, \S\S, \S\S \])?')
self.rexx.sits_out_re = re.compile('(?P<PNAME>.*) sits out') self.rexx.sits_out_re = re.compile('(?P<PNAME>.*) sits out')
self.rexx.compileRegexes() self.rexx.compileRegexes()

View File

@ -54,7 +54,8 @@ class Hand:
self.posted = [] self.posted = []
self.involved = True self.involved = True
self.pot = Pot()
# #
# Collections indexed by street names # Collections indexed by street names
# #
@ -111,6 +112,7 @@ If a player has None chips he won't be added."""
self.players.append([seat, name, chips]) self.players.append([seat, name, chips])
self.stacks[name] = Decimal(chips) self.stacks[name] = Decimal(chips)
self.holecards[name] = set() self.holecards[name] = set()
self.pot.addPlayer(name)
for street in self.streetList: for street in self.streetList:
self.bets[street][name] = [] self.bets[street][name] = []
@ -180,12 +182,24 @@ Card ranks will be uppercased
def addBlind(self, player, blindtype, 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.
# TODO:
# The situation we need to cover are:
# Player in small blind posts
# - this is a bet of 1 sb, as yet uncalled.
# Player in the big blind posts
# - this is a bet of 1 bb and is the new uncalled
#
# If a player posts a big & small blind
#
print "DEBUG addBlind: %s posts %s, %s" % (player, blindtype, amount) print "DEBUG addBlind: %s posts %s, %s" % (player, blindtype, amount)
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.stacks[player] -= Decimal(amount) self.stacks[player] -= Decimal(amount)
#print "DEBUG %s posts, stack %s" % (player, self.stacks[player]) #print "DEBUG %s posts, stack %s" % (player, self.stacks[player])
self.actions['PREFLOP'] += [(player, 'posts', blindtype, amount, self.stacks[player]==0)] act = (player, 'posts', blindtype, amount, self.stacks[player]==0)
self.actions['PREFLOP'].append(act)
self.pot.addMoney(player, Decimal(amount))
if blindtype == 'big blind': if blindtype == 'big blind':
self.lastBet['PREFLOP'] = Decimal(amount) self.lastBet['PREFLOP'] = Decimal(amount)
elif blindtype == 'small & big blinds': elif blindtype == 'small & big blinds':
@ -202,7 +216,9 @@ Card ranks will be uppercased
#self.lastBet[street] = Decimal(amount) #self.lastBet[street] = Decimal(amount)
self.stacks[player] -= Decimal(amount) self.stacks[player] -= Decimal(amount)
print "DEBUG %s calls %s, stack %s" % (player, amount, self.stacks[player]) print "DEBUG %s calls %s, stack %s" % (player, amount, self.stacks[player])
self.actions[street] += [(player, 'calls', amount, self.stacks[player]==0)] act = (player, 'calls', amount, self.stacks[player]==0)
self.actions[street].append(act)
self.pot.addMoney(player, Decimal(amount))
def addRaiseBy(self, street, player, amountBy): def addRaiseBy(self, street, player, amountBy):
"""\ """\
@ -243,13 +259,7 @@ For sites which by "raises x" mean "calls and raises putting a total of x in the
Rt = Bp + Rb Rt = Bp + Rb
self._addRaise(street, player, C, Rb, Rt) self._addRaise(street, player, C, Rb, Rt)
def _addRaise(self, street, player, C, Rb, Rt):
self.bets[street][player].append(C + Rb)
self.stacks[player] -= (C + Rb)
self.actions[street] += [(player, 'raises', Rb, Rt, C, self.stacks[player]==0)]
self.lastBet[street] = Rt
def addRaiseTo(self, street, player, amountTo): def addRaiseTo(self, street, player, amountTo):
"""\ """\
Add a raise on [street] by [player] to [amountTo] Add a raise on [street] by [player] to [amountTo]
@ -260,6 +270,15 @@ Add a raise on [street] by [player] to [amountTo]
C = Bp - Bc C = Bp - Bc
Rb = Rt - C Rb = Rt - C
self._addRaise(street, player, C, Rb, Rt) self._addRaise(street, player, C, Rb, Rt)
def _addRaise(self, street, player, C, Rb, Rt):
self.bets[street][player].append(C + Rb)
self.stacks[player] -= (C + Rb)
act = (player, 'raises', Rb, Rt, C, self.stacks[player]==0)
self.actions[street].append(act)
self.lastBet[street] = Rt # TODO check this is correct
self.pot.addMoney(player, C+Rb)
def addBet(self, street, player, amount): def addBet(self, street, player, amount):
@ -267,20 +286,24 @@ Add a raise on [street] by [player] to [amountTo]
self.bets[street][player].append(Decimal(amount)) self.bets[street][player].append(Decimal(amount))
self.stacks[player] -= Decimal(amount) self.stacks[player] -= Decimal(amount)
print "DEBUG %s bets %s, stack %s" % (player, amount, self.stacks[player]) print "DEBUG %s bets %s, stack %s" % (player, amount, self.stacks[player])
self.actions[street] += [(player, 'bets', amount, self.stacks[player]==0)] act = (player, 'bets', amount, self.stacks[player]==0)
self.actions[street].append(act)
self.lastBet[street] = Decimal(amount) self.lastBet[street] = Decimal(amount)
self.pot.addMoney(player, Decimal(amount))
def addFold(self, street, player): def addFold(self, street, player):
print "DEBUG: %s %s folded" % (street, player) print "DEBUG: %s %s folded" % (street, player)
self.checkPlayerExists(player) self.checkPlayerExists(player)
self.folded.add(player) self.folded.add(player)
self.actions[street] += [(player, 'folds')] self.pot.addFold(player)
self.actions[street].append((player, 'folds'))
def addCheck(self, street, player): def addCheck(self, street, player):
print "DEBUG: %s %s checked" % (street, player) print "DEBUG: %s %s checked" % (street, player)
self.checkPlayerExists(player) self.checkPlayerExists(player)
self.actions[street] += [(player, 'checks')] self.actions[street].append((player, 'checks'))
def addCollectPot(self,player, pot): def addCollectPot(self,player, pot):
print "DEBUG: %s collected %s" % (player, pot) print "DEBUG: %s collected %s" % (player, pot)
@ -293,81 +316,13 @@ Add a raise on [street] by [player] to [amountTo]
def totalPot(self): def totalPot(self):
"""If all bets and blinds have been added, totals up the total pot size""" """If all bets and blinds have been added, totals up the total pot size"""
# This gives us the total amount put in the pot
if self.totalpot is None: if self.totalpot is None:
self.totalpot = 0 self.pot.end()
self.totalpot = self.pot.total
for player in [x[1] for x in self.players]: # This gives us the amount collected, i.e. after rake
for street in self.streetList:
self.totalpot += reduce(operator.add, self.bets[street][player], 0)
print "DEBUG conventional totalpot:", self.totalpot
self.totalpot = 0
players_who_act_preflop = set([x[0] for x in self.actions['PREFLOP']])
self.pot = Pot(players_who_act_preflop)
# this can now be pruned substantially if Pot is working.
#for street in self.actions:
for street in [x for x in self.streetList if x 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
self.pot.addMoney(act[0], Decimal(act[2]))
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
self.pot.addMoney(act[0], Decimal(act[2])+Decimal(act[4]))
elif act[1] == 'calls': # [name, 'calls', amount]
self.totalpot += Decimal(act[2])
calls = calls + [Decimal(act[2])]
print "calls:", calls
self.pot.addMoney(act[0], Decimal(act[2]))
elif act[1] == 'posts':
self.totalpot += Decimal(act[3])
self.pot.addMoney(act[0], Decimal(act[3]))
if act[2] == 'big blind':
# the bb gets called by out-of-blinds posts; but sb+bb only calls bb
if uncalled == Decimal(act[3]): # a bb is already posted
calls = calls + [Decimal(act[3])]
elif 0 < uncalled < Decimal(act[3]): # a sb is already posted, btw wow python can do a<b<c.
# treat this as tho called & raised
calls = [0]
uncalled = Decimal(act[3]) - uncalled
else: # no blind yet posted.
uncalled = Decimal(act[3])
elif act[2] == 'small blind':
uncalled = Decimal(act[3])
calls = [0]
pass
elif act[1] == 'folds':
self.pot.addFold(act[0])
if uncalled > 0 and max(calls+[0]) < uncalled:
print "DEBUG returning some bet, calls:", calls
print "DEBUG returned: %.2f from %.2f" % ((uncalled - max(calls)), self.totalpot,)
self.totalpot -= (uncalled - max(calls))
print "DEBUG new totalpot:", self.totalpot
print "DEBUG new Pot.total:", self.pot
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():
@ -558,19 +513,28 @@ class FpdbParseError(Exception): pass
class Pot(object): class Pot(object):
def __init__(self, contenders):
self.contenders = contenders def __init__(self):
self.committed = dict([(player,Decimal(0)) for player in contenders]) self.contenders = set()
self.total = Decimal(0) self.committed = {}
self.total = None
def addPlayer(self,player):
self.committed[player] = Decimal(0)
def addFold(self, player): def addFold(self, player):
self.contenders.remove(player) # addFold must be called when a player folds
self.contenders.discard(player)
def addMoney(self, player, amount): def addMoney(self, player, amount):
# addMoney must be called for any actions that put money in the pot, in the order they occur
self.contenders.add(player)
self.committed[player] += amount self.committed[player] += amount
def __str__(self): def end(self):
self.total = sum(self.committed.values()) self.total = sum(self.committed.values())
# Return any uncalled bet.
committed = sorted([ (v,k) for (k,v) in self.committed.items()]) committed = sorted([ (v,k) for (k,v) in self.committed.items()])
lastbet = committed[-1][0] - committed[-2][0] lastbet = committed[-1][0] - committed[-2][0]
if lastbet > 0: # uncalled if lastbet > 0: # uncalled
@ -580,36 +544,37 @@ class Pot(object):
self.committed[returnto] -= lastbet self.committed[returnto] -= lastbet
# Work out side pots
# now: for those contenders still contending..
commitsall = sorted([(v,k) for (k,v) in self.committed.items() if v >0]) commitsall = sorted([(v,k) for (k,v) in self.committed.items() if v >0])
pots = [] self.pots = []
while len(commitsall) > 0: while len(commitsall) > 0:
commitslive = [(v,k) for (v,k) in commitsall if k in self.contenders] commitslive = [(v,k) for (v,k) in commitsall if k in self.contenders]
v1 = commitslive[0][0] v1 = commitslive[0][0]
pots += [sum([min(v,v1) for (v,k) in commitsall])] self.pots += [sum([min(v,v1) for (v,k) in commitsall])]
#print "all: ", commitsall
#print "live:", commitslive
commitsall = [((v-v1),k) for (v,k) in commitsall if v-v1 >0] commitsall = [((v-v1),k) for (v,k) in commitsall if v-v1 >0]
#print "[**]", pots
# TODO: I think rake gets taken out of the pots. # TODO: I think rake gets taken out of the pots.
# so it goes: # so it goes:
# total pot x. main pot y, side pot z. | rake r # total pot x. main pot y, side pot z. | rake r
# and y+z+r = x # and y+z+r = x
# for example: # for example:
# Total pot $124.30 Main pot $98.90. Side pot $23.40. | Rake $2 # Total pot $124.30 Main pot $98.90. Side pot $23.40. | Rake $2
# so....... that's tricky.
if len(pots) == 1: # (only use Total pot) def __str__(self):
#return "Main pot $%.2f." % pots[0] if self.total is None:
print "call Pot.end() before printing pot total"
# NB if I'm sure end() is idempotent, call it here.
raise FpdbParseError
if len(self.pots) == 1: # (only use Total pot)
return "Total pot $%.2f" % (self.total,) return "Total pot $%.2f" % (self.total,)
elif len(pots) == 2: elif len(self.pots) == 2:
return "Total pot $%.2f Main pot $%.2f. Side pot $%2.f." % (self.total, pots[0],pots[1]) return "Total pot $%.2f Main pot $%.2f. Side pot $%2.f." % (self.total, self.pots[0], self.pots[1])
elif len(pots) == 3: elif len(self.pots) == 3:
return "Total pot $%.2f Main pot $%.2f. Side pot-1 $%2.f. Side pot-2 $.2f." % (self.total, pots[0],pots[1],pots[2]) return "Total pot $%.2f Main pot $%.2f. Side pot-1 $%2.2f. Side pot-2 $%.2f." % (self.total, self.pots[0], self.pots[1], self.pots[2])
else: else:
return "too many pots.. fix me.", pots return "too many pots.. fix me.", self.pots