Merge branch 'master' of git://git.assembla.com/mctfpdb.git
This commit is contained in:
commit
c974864e13
185
pyfpdb/Hand.py
185
pyfpdb/Hand.py
|
@ -54,6 +54,7 @@ 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):
|
||||||
"""\
|
"""\
|
||||||
|
@ -244,12 +260,6 @@ For sites which by "raises x" mean "calls and raises putting a total of x in the
|
||||||
|
|
||||||
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]
|
||||||
|
@ -261,26 +271,39 @@ Add a raise on [street] by [player] to [amountTo]
|
||||||
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):
|
||||||
self.checkPlayerExists(player)
|
self.checkPlayerExists(player)
|
||||||
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]:
|
|
||||||
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
|
|
||||||
|
|
||||||
|
# This gives us the amount collected, i.e. after rake
|
||||||
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,39 @@ 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:
|
||||||
return "Total pot $%.2f" % (self.total,)
|
print "call Pot.end() before printing pot total"
|
||||||
elif len(pots) == 2:
|
# NB if I'm sure end() is idempotent, call it here.
|
||||||
return "Total pot $%.2f Main pot $%.2f. Side pot $%2.f." % (self.total, pots[0],pots[1])
|
raise FpdbParseError
|
||||||
elif len(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])
|
|
||||||
else:
|
|
||||||
return "too many pots.. fix me.", pots
|
if len(self.pots) == 1: # (only use Total pot)
|
||||||
|
return "Total pot $%.2f" % (self.total,)
|
||||||
|
elif len(self.pots) == 2:
|
||||||
|
return "Total pot $%.2f Main pot $%.2f. Side pot $%2.f." % (self.total, self.pots[0], self.pots[1])
|
||||||
|
elif len(self.pots) == 3:
|
||||||
|
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:
|
||||||
|
return "maybe no pot.. or too many pots.. no small blind and walk in bb?."
|
||||||
|
# I don't know stars format for a walk in the bb when sb doesn't post.
|
||||||
|
# The thing to do here is raise a Hand error like fpdb import does and file it into errors.txt
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user