From 9d193f236efb42a40933add6fba4552ae3b79dbf Mon Sep 17 00:00:00 2001 From: grindi Date: Wed, 12 Aug 2009 01:13:07 +0400 Subject: [PATCH 01/10] Hand: removed trailing spaces --- pyfpdb/Hand.py | 120 ++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 2c5045a2..97767b0d 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -4,12 +4,12 @@ #This program is free software: you can redistribute it and/or modify #it under the terms of the GNU Affero General Public License as published by #the Free Software Foundation, version 3 of the License. -# +# #This program is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #GNU General Public License for more details. -# +# #You should have received a copy of the GNU Affero General Public License #along with this program. If not, see . #In the "official" distribution you can find the license in @@ -120,7 +120,7 @@ class Hand(object): ("MIXED", self.mixed), ("LASTBET", self.lastBet), ("ACTION STREETS", self.actionStreets), - ("STREETS", self.streets), + ("STREETS", self.streets), ("ALL STREETS", self.allStreets), ("COMMUNITY STREETS", self.communityStreets), ("HOLE STREETS", self.holeStreets), @@ -133,7 +133,7 @@ class Hand(object): ("RAKE", self.rake), ("START TIME", self.starttime), ) - + structs = ( ("PLAYERS", self.players), ("STACKS", self.stacks), ("POSTED", self.posted), @@ -200,10 +200,10 @@ db: a connected fpdb_db object""" elif self.gametype['category'] in ['razz','27_3draw','badugi']: hilo = "l" - gtid = db.insertGameTypes( (self.siteId, self.gametype['type'], self.gametype['base'], + gtid = db.insertGameTypes( (self.siteId, self.gametype['type'], self.gametype['base'], self.gametype['category'], self.gametype['limitType'], hilo, int(Decimal(self.gametype['sb'])*100), int(Decimal(self.gametype['bb'])*100), 0, 0) ) - + # HudCache data to come from DerivedStats class # HandsActions - all actions for all players for all streets - self.actions @@ -275,8 +275,8 @@ db: a connected fpdb_db object""" def select(self, handId): """ Function to create Hand object from database """ - - + + def addPlayer(self, seat, name, chips): @@ -332,7 +332,7 @@ If a player has None chips he won't be added.""" self.stacks[player] -= Decimal(ante) act = (player, 'posts', "ante", ante, self.stacks[player]==0) self.actions['ANTES'].append(act) - #~ self.lastBet['ANTES'] = Decimal(ante) + #~ self.lastBet['ANTES'] = Decimal(ante) self.pot.addMoney(player, Decimal(ante)) def addBlind(self, player, blindtype, amount): @@ -377,22 +377,22 @@ If a player has None chips he won't be added.""" 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): """\ -Add a raise by amountBy on [street] by [player] +Add a raise by amountBy on [street] by [player] """ #Given only the amount raised by, the amount of the raise can be calculated by - # working out how much this player has already in the pot + # working out how much this player has already in the pot # (which is the sum of self.bets[street][player]) - # and how much he needs to call to match the previous player + # and how much he needs to call to match the previous player # (which is tracked by self.lastBet) - # let Bp = previous bet + # let Bp = previous bet # Bc = amount player has committed so far # Rb = raise by # then: C = Bp - Bc (amount to call) # Rt = Bp + Rb (raise to) - # + # amountBy = re.sub(u',', u'', amountBy) #some sites have commas self.checkPlayerExists(player) Rb = Decimal(amountBy) @@ -400,7 +400,7 @@ Add a raise by amountBy on [street] by [player] Bc = reduce(operator.add, self.bets[street][player], 0) C = Bp - Bc Rt = Bp + Rb - + self._addRaise(street, player, C, Rb, Rt) #~ self.bets[street][player].append(C + Rb) #~ self.stacks[player] -= (C + Rb) @@ -418,7 +418,7 @@ For sites which by "raises x" mean "calls and raises putting a total of x in the C = Bp - Bc Rb = CRb - C Rt = Bp + Rb - + self._addRaise(street, player, C, Rb, Rt) def addRaiseTo(self, street, player, amountTo): @@ -443,9 +443,9 @@ Add a raise on [street] by [player] to [amountTo] 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): log.debug("%s %s bets %s" %(street, player, amount)) amount = re.sub(u',', u'', amount) #some sites have commas @@ -463,7 +463,7 @@ Add a raise on [street] by [player] to [amountTo] self.checkPlayerExists(player) act = (player, 'stands pat') self.actions[street].append(act) - + def addFold(self, street, player): log.debug("%s %s folds" % (street, player)) @@ -471,7 +471,7 @@ Add a raise on [street] by [player] to [amountTo] self.folded.add(player) self.pot.addFold(player) self.actions[street].append((player, 'folds')) - + def addCheck(self, street, player): #print "DEBUG: %s %s checked" % (street, player) @@ -506,7 +506,7 @@ Card ranks will be uppercased def totalPot(self): """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: self.pot.end() @@ -590,14 +590,14 @@ Map the tuple self.gametype onto the pokerstars string describing it def writeGameLine(self): """Return the first HH line for the current hand.""" gs = "PokerStars Game #%s: " % self.handid - + if self.tourNo != None and self.mixed != None: # mixed tournament gs = gs + "Tournament #%s, %s %s (%s) - Level %s (%s) - " % (self.tourNo, self.buyin, self.MS[self.mixed], self.getGameTypeAsString(), self.level, self.getStakesAsString()) elif self.tourNo != None: # all other tournaments - gs = gs + "Tournament #%s, %s %s - Level %s (%s) - " % (self.tourNo, + gs = gs + "Tournament #%s, %s %s - Level %s (%s) - " % (self.tourNo, self.buyin, self.getGameTypeAsString(), self.level, self.getStakesAsString()) elif self.mixed != None: # all other mixed games - gs = gs + " %s (%s, %s) - " % (self.MS[self.mixed], + gs = gs + " %s (%s, %s) - " % (self.MS[self.mixed], self.getGameTypeAsString(), self.getStakesAsString()) else: # non-mixed cash games gs = gs + " %s (%s) - " % (self.getGameTypeAsString(), self.getStakesAsString()) @@ -616,8 +616,8 @@ Map the tuple self.gametype onto the pokerstars string describing it def writeHand(self, fh=sys.__stdout__): # PokerStars format. - print >>fh, self.writeGameLine() - print >>fh, self.writeTableLine() + print >>fh, self.writeGameLine() + print >>fh, self.writeTableLine() class HoldemOmahaHand(Hand): @@ -632,9 +632,9 @@ class HoldemOmahaHand(Hand): Hand.__init__(self, sitename, gametype, handText, builtFrom = "HHC") self.sb = gametype['sb'] self.bb = gametype['bb'] - + #Populate a HoldemOmahaHand - #Generally, we call 'read' methods here, which get the info according to the particular filter (hhc) + #Generally, we call 'read' methods here, which get the info according to the particular filter (hhc) # which then invokes a 'addXXX' callback if builtFrom == "HHC": hhc.readHandInfo(self) @@ -667,7 +667,7 @@ class HoldemOmahaHand(Hand): else: log.warning("HoldemOmahaHand.__init__:Neither HHC nor DB+handid provided") pass - + def addShownCards(self, cards, player, shown=True, mucked=False, dealt=False): if player == self.hero: # we have hero's cards just update shown/mucked @@ -710,7 +710,7 @@ class HoldemOmahaHand(Hand): ] ) if street in self.actionStreets and self.actions[street]: - lines.append( + lines.append( T.ol(class_='actions', data=self.actions[street], render=render_action) [ T.li(pattern='list_item')[ T.slot(name='action') ] ] @@ -744,8 +744,8 @@ class HoldemOmahaHand(Hand): context.tag[ pat().fillSlots('action', x)] return context.tag - s = T.p[ - T.h1[ + s = T.p[ + T.h1[ T.span(class_='site')["%s Game #%s]" % ('PokerStars', self.handid)], T.span(class_='type_limit')[ "%s ($%s/$%s)" %(self.getGameTypeAsString(), self.sb, self.bb) ], T.span(class_='date')[ datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET') ] @@ -771,7 +771,7 @@ class HoldemOmahaHand(Hand): return str(tidy.parseString(flat.flatten(s), **options)) - + def writeHand(self, fh=sys.__stdout__): # PokerStars format. super(HoldemOmahaHand, self).writeHand(fh) @@ -785,7 +785,7 @@ class HoldemOmahaHand(Hand): if self.actions['BLINDSANTES']: for act in self.actions['BLINDSANTES']: print >>fh, self.actionString(act) - + print >>fh, ("*** HOLE CARDS ***") for player in self.dealt: print >>fh, ("Dealt to %s [%s]" %(player, " ".join(self.holecards['PREFLOP'][player][1]))) @@ -831,7 +831,7 @@ class HoldemOmahaHand(Hand): numOfHoleCardsNeeded = 2 if len(self.holecards['PREFLOP'][name]) == numOfHoleCardsNeeded: print >>fh, ("%s shows [%s] (a hand...)" % (name, " ".join(self.holecards['PREFLOP'][name][1]))) - + # Current PS format has the lines: # Uncalled bet ($111.25) returned to s0rrow # s0rrow collected $5.15 from side pot @@ -873,7 +873,7 @@ class HoldemOmahaHand(Hand): print >>fh, ("Seat %d: %s mucked" % (seatnum, name)) print >>fh, "\n\n" - + class DrawHand(Hand): def __init__(self, hhc, sitename, gametype, handText, builtFrom = "HHC"): if gametype['base'] != 'draw': @@ -918,8 +918,8 @@ class DrawHand(Hand): # - this is a bet of 1 sb, as yet uncalled. # Player in the big blind posts # - this is a call of 1 sb and a raise to 1 bb - # - + # + log.debug("addBlind: %s posts %s, %s" % (player, blindtype, amount)) if player is not None: self.bets['DEAL'][player].append(Decimal(amount)) @@ -929,7 +929,7 @@ class DrawHand(Hand): self.actions['BLINDSANTES'].append(act) self.pot.addMoney(player, Decimal(amount)) if blindtype == 'big blind': - self.lastBet['DEAL'] = Decimal(amount) + self.lastBet['DEAL'] = Decimal(amount) elif blindtype == 'both': # extra small blind is 'dead' self.lastBet['DEAL'] = Decimal(self.bb) @@ -1051,7 +1051,7 @@ class StudHand(Hand): self.sb = gametype['sb'] self.bb = gametype['bb'] #Populate the StudHand - #Generally, we call a 'read' method here, which gets the info according to the particular filter (hhc) + #Generally, we call a 'read' method here, which gets the info according to the particular filter (hhc) # which then invokes a 'addXXX' callback if builtFrom == "HHC": hhc.readHandInfo(self) @@ -1126,7 +1126,7 @@ Add a complete on [street] by [player] to [amountTo] #~ self.actions[street].append(act) #~ self.lastBet[street] = Rt # TODO check this is correct #~ self.pot.addMoney(player, C+Rb) - + def addBringIn(self, player, bringin): if player is not None: log.debug("Bringin: %s, %s" % (player , bringin)) @@ -1137,12 +1137,12 @@ Add a complete on [street] by [player] to [amountTo] self.lastBet['THIRD'] = Decimal(bringin) self.pot.addMoney(player, Decimal(bringin)) - + def writeHand(self, fh=sys.__stdout__): # PokerStars format. super(StudHand, self).writeHand(fh) - + players_who_post_antes = set([x[0] for x in self.actions['ANTES']]) for player in [x for x in self.players if x[1] in players_who_post_antes]: @@ -1273,7 +1273,7 @@ Add a complete on [street] by [player] to [amountTo] else: return hc + " ".join(self.holecards[street][player][0]) + ']' - if street == 'SEVENTH' and player != self.hero: return # only write 7th st line for hero, LDO + if street == 'SEVENTH' and player != self.hero: return # only write 7th st line for hero, LDO return hc + " ".join(self.holecards[street][player][1]) + "] [" + " ".join(self.holecards[street][player][0]) + "]" def join_holecards(self, player): @@ -1303,14 +1303,14 @@ class Pot(object): def setSym(self, sym): self.sym = sym - + def addPlayer(self,player): self.committed[player] = Decimal(0) - + def addFold(self, player): # addFold must be called when a player folds self.contenders.discard(player) - + 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) @@ -1318,7 +1318,7 @@ class Pot(object): def end(self): self.total = sum(self.committed.values()) - + # Return any uncalled bet. committed = sorted([ (v,k) for (k,v) in self.committed.items()]) lastbet = committed[-1][0] - committed[-2][0] @@ -1336,7 +1336,7 @@ class Pot(object): self.pots = [] while len(commitsall) > 0: commitslive = [(v,k) for (v,k) in commitsall if k in self.contenders] - v1 = commitslive[0][0] + v1 = commitslive[0][0] self.pots += [sum([min(v,v1) for (v,k) in commitsall])] commitsall = [((v-v1),k) for (v,k) in commitsall if v-v1 >0] @@ -1346,7 +1346,7 @@ class Pot(object): # and y+z+r = x # for example: # Total pot $124.30 Main pot $98.90. Side pot $23.40. | Rake $2 - + def __str__(self): if self.sym is None: self.sym = "C" @@ -1354,17 +1354,17 @@ class Pot(object): print "call Pot.end() before printing pot total" # NB if I'm sure end() is idempotent, call it here. raise FpdbParseError - + ret = "Total pot %s%.2f" % (self.sym, self.total) if len(self.pots) < 2: return ret; ret += " Main pot %s%.2f" % (self.sym, self.pots[0]) - + return ret + ''.join([ (" Side pot %s%.2f." % (self.sym, self.pots[x]) ) for x in xrange(1, len(self.pots)) ]) def assemble(cnxn, handid): c = cnxn.cursor() - + # We need at least sitename, gametype, handid # for the Hand.__init__ c.execute(""" @@ -1407,10 +1407,10 @@ limit 1""", {'handid':handid}) h.setCommunityCards('FLOP', cards[0:3]) if cards[3]: h.setCommunityCards('TURN', [cards[3]]) - if cards[4]: + if cards[4]: h.setCommunityCards('RIVER', [cards[4]]) #[Card.valueSuitFromCard(x) for x in cards] - + # HandInfo : HID, TABLE # BUTTON - why is this treated specially in Hand? # answer: it is written out in hand histories @@ -1428,7 +1428,7 @@ WHERE h.id = %(handid)s h.handid = res[0] h.tablename = res[1] h.starttime = res[2] # automatically a datetime - + # PlayerStacks c.execute(""" SELECT @@ -1453,7 +1453,7 @@ and p.id = hp.playerid h.addCollectPot(name, winnings) if position == 'B': h.buttonpos = seat - + # actions c.execute(""" @@ -1501,7 +1501,7 @@ ORDER BY #hc.readShownCards(self) h.totalPot() h.rake = h.totalpot - h.totalcollected - + return h From 39d55e093d15bac394b60b19e9397e4d32324dd8 Mon Sep 17 00:00:00 2001 From: grindi Date: Wed, 12 Aug 2009 01:19:01 +0400 Subject: [PATCH 02/10] Hand: improved BB+SB blind type support; added common money feature to the Pot --- pyfpdb/Hand.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 97767b0d..dfd7be13 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -347,19 +347,19 @@ If a player has None chips he won't be added.""" log.debug("addBlind: %s posts %s, %s" % (player, blindtype, amount)) if player is not None: amount = re.sub(u',', u'', amount) #some sites have commas - self.bets['PREFLOP'][player].append(Decimal(amount)) self.stacks[player] -= Decimal(amount) - #print "DEBUG %s posts, stack %s" % (player, self.stacks[player]) act = (player, 'posts', blindtype, amount, self.stacks[player]==0) self.actions['BLINDSANTES'].append(act) + + if blindtype == 'both': + amount = self.bb + self.bets['BLINDSANTES'][player].append(Decimal(self.sb)) + self.pot.addCommonMoney(Decimal(self.sb)) + + self.bets['PREFLOP'][player].append(Decimal(amount)) self.pot.addMoney(player, Decimal(amount)) - if blindtype == 'big blind': - self.lastBet['PREFLOP'] = Decimal(amount) - elif blindtype == 'both': - # extra small blind is 'dead' - self.lastBet['PREFLOP'] = Decimal(self.bb) + self.lastBet['PREFLOP'] = Decimal(amount) self.posted = self.posted + [[player,blindtype]] - #print "DEBUG: self.posted: %s" %(self.posted) @@ -1297,6 +1297,7 @@ class Pot(object): def __init__(self): self.contenders = set() self.committed = {} + self.common = Decimal(0) self.total = None self.returned = {} self.sym = u'$' # this is the default currency symbol @@ -1311,13 +1312,16 @@ class Pot(object): # addFold must be called when a player folds self.contenders.discard(player) + def addCommonMoney(self, amount): + self.common += 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 def end(self): - self.total = sum(self.committed.values()) + self.total = sum(self.committed.values()) + self.common # Return any uncalled bet. committed = sorted([ (v,k) for (k,v) in self.committed.items()]) From f18d0e10cf4b96714e2fe0b8897a84190fa3c055 Mon Sep 17 00:00:00 2001 From: grindi Date: Wed, 12 Aug 2009 02:30:08 +0400 Subject: [PATCH 03/10] Hand: added ante support --- pyfpdb/Hand.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index dfd7be13..c1ceba1b 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -325,14 +325,13 @@ If a player has None chips he won't be added.""" return c def addAnte(self, player, ante): - log.debug("%s %s antes %s" % ('ANTES', player, ante)) + log.debug("%s %s antes %s" % ('BLINDSANTES', player, ante)) if player is not None: ante = re.sub(u',', u'', ante) #some sites have commas - self.bets['ANTES'][player].append(Decimal(ante)) + self.bets['BLINDSANTES'][player].append(Decimal(ante)) self.stacks[player] -= Decimal(ante) act = (player, 'posts', "ante", ante, self.stacks[player]==0) - self.actions['ANTES'].append(act) - #~ self.lastBet['ANTES'] = Decimal(ante) + self.actions['BLINDSANTES'].append(act) self.pot.addMoney(player, Decimal(ante)) def addBlind(self, player, blindtype, amount): @@ -495,6 +494,7 @@ Add a raise on [street] by [player] to [amountTo] For when a player shows cards for any reason (for showdown or out of choice). Card ranks will be uppercased """ + import sys; sys.exit(1) log.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard)) if cards is not None: self.addHoleCards(cards,player,shown, mucked) @@ -576,6 +576,8 @@ Map the tuple self.gametype onto the pokerstars string describing it return ("%s: posts big blind %s%s%s" %(act[0], self.sym, act[3], ' and is all-in' if act[4] else '')) elif(act[2] == "both"): return ("%s: posts small & big blinds %s%s%s" %(act[0], self.sym, act[3], ' and is all-in' if act[4] else '')) + elif(act[2] == "ante"): + return ("%s: posts ante %s%s%s" %(act[0], self.sym, act[3], ' and is all-in' if act[4] else '')) elif act[1] == 'bringin': return ("%s: brings in for %s%s%s" %(act[0], self.sym, act[2], ' and is all-in' if act[3] else '')) elif act[1] == 'discards': @@ -642,6 +644,7 @@ class HoldemOmahaHand(Hand): hhc.compilePlayerRegexs(self) hhc.markStreets(self) hhc.readBlinds(self) + hhc.readAntes(self) hhc.readButton(self) hhc.readHeroCards(self) hhc.readShowdownActions(self) @@ -893,6 +896,7 @@ class DrawHand(Hand): hhc.compilePlayerRegexs(self) hhc.markStreets(self) hhc.readBlinds(self) + hhc.readAntes(self) hhc.readButton(self) hhc.readHeroCards(self) hhc.readShowdownActions(self) @@ -1041,11 +1045,11 @@ class StudHand(Hand): if gametype['base'] != 'stud': pass # or indeed don't pass and complain instead - self.allStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] + self.allStreets = ['BLINDSANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] self.communityStreets = [] - self.actionStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] + self.actionStreets = ['BLINDSANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] - self.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order + self.streetList = ['BLINDSANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order self.holeStreets = ['THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] Hand.__init__(self, sitename, gametype, handText) self.sb = gametype['sb'] @@ -1063,7 +1067,7 @@ class StudHand(Hand): hhc.readHeroCards(self) # Read actions in street order for street in self.actionStreets: - if street == 'ANTES': continue # OMG--sometime someone folds in the ante round + if street == 'BLINDSANTES': continue # OMG--sometime someone folds in the ante round if self.streets[street]: log.debug(street + self.streets[street]) hhc.readAction(self, street) @@ -1143,14 +1147,14 @@ Add a complete on [street] by [player] to [amountTo] super(StudHand, self).writeHand(fh) - players_who_post_antes = set([x[0] for x in self.actions['ANTES']]) + players_who_post_antes = set([x[0] for x in self.actions['BLINDSANTES']]) for player in [x for x in self.players if x[1] in players_who_post_antes]: #Only print stacks of players who do something preflop print >>fh, _("Seat %s: %s (%s%s in chips)" %(player[0], player[1], self.sym, player[2])) - if 'ANTES' in self.actions: - for act in self.actions['ANTES']: + if 'BLINDSANTES' in self.actions: + for act in self.actions['BLINDSANTES']: print >>fh, _("%s: posts the ante %s%s" %(act[0], self.sym, act[3])) if 'THIRD' in self.actions: From 56a6d77e9c66b80a914e48e18ade6121b5efdd72 Mon Sep 17 00:00:00 2001 From: grindi Date: Wed, 12 Aug 2009 01:19:01 +0400 Subject: [PATCH 04/10] Hand: added ante support --- pyfpdb/Hand.py | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 97767b0d..fdb92edb 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -325,14 +325,13 @@ If a player has None chips he won't be added.""" return c def addAnte(self, player, ante): - log.debug("%s %s antes %s" % ('ANTES', player, ante)) + log.debug("%s %s antes %s" % ('BLINDSANTES', player, ante)) if player is not None: ante = re.sub(u',', u'', ante) #some sites have commas - self.bets['ANTES'][player].append(Decimal(ante)) + self.bets['BLINDSANTES'][player].append(Decimal(ante)) self.stacks[player] -= Decimal(ante) act = (player, 'posts', "ante", ante, self.stacks[player]==0) - self.actions['ANTES'].append(act) - #~ self.lastBet['ANTES'] = Decimal(ante) + self.actions['BLINDSANTES'].append(act) self.pot.addMoney(player, Decimal(ante)) def addBlind(self, player, blindtype, amount): @@ -347,19 +346,19 @@ If a player has None chips he won't be added.""" log.debug("addBlind: %s posts %s, %s" % (player, blindtype, amount)) if player is not None: amount = re.sub(u',', u'', amount) #some sites have commas - self.bets['PREFLOP'][player].append(Decimal(amount)) self.stacks[player] -= Decimal(amount) - #print "DEBUG %s posts, stack %s" % (player, self.stacks[player]) act = (player, 'posts', blindtype, amount, self.stacks[player]==0) self.actions['BLINDSANTES'].append(act) + + if blindtype == 'both': + amount = self.bb + self.bets['BLINDSANTES'][player].append(Decimal(self.sb)) + self.pot.addCommonMoney(Decimal(self.sb)) + + self.bets['PREFLOP'][player].append(Decimal(amount)) self.pot.addMoney(player, Decimal(amount)) - if blindtype == 'big blind': - self.lastBet['PREFLOP'] = Decimal(amount) - elif blindtype == 'both': - # extra small blind is 'dead' - self.lastBet['PREFLOP'] = Decimal(self.bb) + self.lastBet['PREFLOP'] = Decimal(amount) self.posted = self.posted + [[player,blindtype]] - #print "DEBUG: self.posted: %s" %(self.posted) @@ -495,6 +494,7 @@ Add a raise on [street] by [player] to [amountTo] For when a player shows cards for any reason (for showdown or out of choice). Card ranks will be uppercased """ + import sys; sys.exit(1) log.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard)) if cards is not None: self.addHoleCards(cards,player,shown, mucked) @@ -576,6 +576,8 @@ Map the tuple self.gametype onto the pokerstars string describing it return ("%s: posts big blind %s%s%s" %(act[0], self.sym, act[3], ' and is all-in' if act[4] else '')) elif(act[2] == "both"): return ("%s: posts small & big blinds %s%s%s" %(act[0], self.sym, act[3], ' and is all-in' if act[4] else '')) + elif(act[2] == "ante"): + return ("%s: posts the ante %s%s%s" %(act[0], self.sym, act[3], ' and is all-in' if act[4] else '')) elif act[1] == 'bringin': return ("%s: brings in for %s%s%s" %(act[0], self.sym, act[2], ' and is all-in' if act[3] else '')) elif act[1] == 'discards': @@ -642,6 +644,7 @@ class HoldemOmahaHand(Hand): hhc.compilePlayerRegexs(self) hhc.markStreets(self) hhc.readBlinds(self) + hhc.readAntes(self) hhc.readButton(self) hhc.readHeroCards(self) hhc.readShowdownActions(self) @@ -893,6 +896,7 @@ class DrawHand(Hand): hhc.compilePlayerRegexs(self) hhc.markStreets(self) hhc.readBlinds(self) + hhc.readAntes(self) hhc.readButton(self) hhc.readHeroCards(self) hhc.readShowdownActions(self) @@ -1041,11 +1045,11 @@ class StudHand(Hand): if gametype['base'] != 'stud': pass # or indeed don't pass and complain instead - self.allStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] + self.allStreets = ['BLINDSANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] self.communityStreets = [] - self.actionStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] + self.actionStreets = ['BLINDSANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] - self.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order + self.streetList = ['BLINDSANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order self.holeStreets = ['THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] Hand.__init__(self, sitename, gametype, handText) self.sb = gametype['sb'] @@ -1063,7 +1067,7 @@ class StudHand(Hand): hhc.readHeroCards(self) # Read actions in street order for street in self.actionStreets: - if street == 'ANTES': continue # OMG--sometime someone folds in the ante round + if street == 'BLINDSANTES': continue # OMG--sometime someone folds in the ante round if self.streets[street]: log.debug(street + self.streets[street]) hhc.readAction(self, street) @@ -1143,14 +1147,14 @@ Add a complete on [street] by [player] to [amountTo] super(StudHand, self).writeHand(fh) - players_who_post_antes = set([x[0] for x in self.actions['ANTES']]) + players_who_post_antes = set([x[0] for x in self.actions['BLINDSANTES']]) for player in [x for x in self.players if x[1] in players_who_post_antes]: #Only print stacks of players who do something preflop print >>fh, _("Seat %s: %s (%s%s in chips)" %(player[0], player[1], self.sym, player[2])) - if 'ANTES' in self.actions: - for act in self.actions['ANTES']: + if 'BLINDSANTES' in self.actions: + for act in self.actions['BLINDSANTES']: print >>fh, _("%s: posts the ante %s%s" %(act[0], self.sym, act[3])) if 'THIRD' in self.actions: @@ -1297,6 +1301,7 @@ class Pot(object): def __init__(self): self.contenders = set() self.committed = {} + self.common = Decimal(0) self.total = None self.returned = {} self.sym = u'$' # this is the default currency symbol @@ -1311,13 +1316,16 @@ class Pot(object): # addFold must be called when a player folds self.contenders.discard(player) + def addCommonMoney(self, amount): + self.common += 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 def end(self): - self.total = sum(self.committed.values()) + self.total = sum(self.committed.values()) + self.common # Return any uncalled bet. committed = sorted([ (v,k) for (k,v) in self.committed.items()]) From 442d96b8628bff1b697c2f0ea0970d97966ce96f Mon Sep 17 00:00:00 2001 From: grindi Date: Wed, 12 Aug 2009 14:30:54 +0400 Subject: [PATCH 05/10] Removed hack in FTP parser --- pyfpdb/FulltiltToFpdb.py | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index 1fd251ca..89b85193 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -29,7 +29,7 @@ class Fulltilt(HandHistoryConverter): sitename = "Fulltilt" filetype = "text" - codepage = "cp1252" + codepage = "utf-16" siteId = 1 # Needs to match id entry in Sites database # Static regexes @@ -135,24 +135,6 @@ class Fulltilt(HandHistoryConverter): if info['type'] == "tour": return None # importer is screwed on tournies, pass on those hands so we don't interrupt other autoimporting return info - #Following function is a hack, we should be dealing with this in readFile (i think correct codepage....) - # Same function as parent class, removing the 2 end characters. - CG - def allHandsAsList(self): - """Return a list of handtexts in the file at self.in_path""" - #TODO : any need for this to be generator? e.g. stars support can email one huge file of all hands in a year. Better to read bit by bit than all at once. - self.readFile() - - # FIXME: it's a hack - if self.obs[:2] == u'\xff\xfe': - self.obs = self.obs[2:].replace('\x00', '') - - self.obs = self.obs.strip() - self.obs = self.obs.replace('\r\n', '\n') - if self.obs == "" or self.obs == None: - logging.info("Read no hands.") - return [] - return re.split(self.re_SplitHands, self.obs) - def readHandInfo(self, hand): m = self.re_HandInfo.search(hand.handText) if(m == None): From bdfc6ef83f90314f64b017c92f15ce1396c07785 Mon Sep 17 00:00:00 2001 From: grindi Date: Wed, 12 Aug 2009 21:55:19 +0400 Subject: [PATCH 06/10] Unified locale handling. Added support for importing filenames containig non-latin symbols --- pyfpdb/Tables.py | 10 ++-------- pyfpdb/fpdb_import.py | 3 ++- pyfpdb/fpdb_simple.py | 19 ++++++++++--------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py index 9fdc8630..082bc171 100755 --- a/pyfpdb/Tables.py +++ b/pyfpdb/Tables.py @@ -39,6 +39,7 @@ if os.name == 'nt': # FreePokerTools modules import Configuration +from fpdb_simple import LOCALE_ENCODING # Each TableWindow object must have the following attributes correctly populated: # tw.name = the table name from the title bar, which must to match the table name @@ -230,20 +231,13 @@ def discover_nt_by_name(c, tablename): """Finds poker client window with the given table name.""" titles = {} win32gui.EnumWindows(win_enum_handler, titles) - - def getDefaultEncoding(): - # FIXME: if somebody know better place fot this function - move it - # FIXME: it's better to use GetCPInfo for windows http://msdn.microsoft.com/en-us/library/dd318078(VS.85).aspx - # but i have no idea, how to call it - import locale - return locale.getpreferredencoding() for hwnd in titles: #print "Tables.py: tablename =", tablename, "title =", titles[hwnd] try: # maybe it's better to make global titles[hwnd] decoding? # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html - if not tablename.lower() in titles[hwnd].decode(getDefaultEncoding()).lower(): continue + if not tablename.lower() in titles[hwnd].decode(LOCALE_ENCODING).lower(): continue except: continue if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 6b4994b6..63928119 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -380,8 +380,9 @@ class Importer: conv = None (stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, 0) + file = file.decode(fpdb_simple.LOCALE_ENCODING) + # Load filter, process file, pass returned filename to import_fpdb_file - if self.settings['threads'] > 0 and self.writeq != None: print "\nConverting " + file + " (" + str(q.qsize()) + ")" else: diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index c12d38ca..086f2bbb 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -38,7 +38,7 @@ MYSQL_INNODB = 2 PGSQL = 3 SQLITE = 4 -(localename, encoding) = locale.getdefaultlocale() +LOCALE_ENCODING = locale.getdefaultlocale()[1] class DuplicateError(Exception): def __init__(self, value): @@ -51,7 +51,7 @@ class FpdbError(Exception): self.value = value def __str__(self): return repr(self.value) - + #returns an array of the total money paid. intending to add rebuys/addons here def calcPayin(count, buyin, fee): return [buyin + fee for i in xrange(count)] @@ -546,7 +546,7 @@ def parseActionType(line): #parses the ante out of the given line and checks which player paid it, updates antes accordingly. def parseAnteLine(line, isTourney, names, antes): for i, name in enumerate(names): - if line.startswith(name.encode(encoding)): + if line.startswith(name.encode(LOCALE_ENCODING)): pos = line.rfind("$") + 1 if not isTourney: antes[i] += float2int(line[pos:]) @@ -708,7 +708,7 @@ def parseHandStartTime(topline): def findName(line): pos1 = line.find(":") + 2 pos2 = line.rfind("(") - 1 - return unicode(line[pos1:pos2], encoding) + return unicode(line[pos1:pos2], LOCALE_ENCODING) def parseNames(lines): return [findName(line) for line in lines] @@ -825,7 +825,7 @@ def parseTourneyNo(topline): def parseWinLine(line, names, winnings, isTourney): #print "parseWinLine: line:",line for i,n in enumerate(names): - n = n.encode(encoding) + n = n.encode(LOCALE_ENCODING) if line.startswith(n): if isTourney: pos1 = line.rfind("collected ") + 10 @@ -1035,14 +1035,15 @@ def recognisePlayerIDs(db, names, site_id): def recognisePlayerNo(line, names, atype): #print "recogniseplayerno, names:",names for i in xrange(len(names)): + encodedName = names[i].encode(LOCALE_ENCODING) if (atype=="unbet"): - if (line.endswith(names[i].encode(encoding))): + if (line.endswith(encodedName)): return (i) elif (line.startswith("Dealt to ")): #print "recognisePlayerNo, card precut, line:",line tmp=line[9:] #print "recognisePlayerNo, card postcut, tmp:",tmp - if (tmp.startswith(names[i].encode(encoding))): + if (tmp.startswith(encodedName)): return (i) elif (line.startswith("Seat ")): if (line.startswith("Seat 10")): @@ -1050,10 +1051,10 @@ def recognisePlayerNo(line, names, atype): else: tmp=line[8:] - if (tmp.startswith(names[i].encode(encoding))): + if (tmp.startswith(encodedName)): return (i) else: - if (line.startswith(names[i].encode(encoding))): + if (line.startswith(encodedName)): return (i) #if we're here we mustve failed raise FpdbError ("failed to recognise player in: "+line+" atype:"+atype) From 53eaee4d7c2a775d4a5a1aae0f90b0301d63ec64 Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 15 Aug 2009 10:44:04 +0300 Subject: [PATCH 07/10] Fix mucked cards' position update When menu->reposition is called, only the HUD windows were moved to their new positions. The auxiliary windows used for mucked cards remained where they were at the time the HUD instance was created. This caused mucked cards to appear in wrong places after the poker table was moved. Split positioning code in Mucked.py to its own method. Now the same routine that moves HUD windows to their new places also invokes code to reposition auxiliary windows. Now the mucked cards are displayed at correct screen coordinates too. --- pyfpdb/Hud.py | 5 +++++ pyfpdb/Mucked.py | 25 ++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 8a7aa740..bdc0cdc8 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -181,6 +181,11 @@ class Hud: for i, w in enumerate(self.stat_windows.itervalues()): (x, y) = loc[adj[i+1]] w.relocate(x, y) + + # While we're at it, fix the positions of mucked cards too + for aux in self.aux_windows: + aux.update_card_positions() + return True def on_button_press(self, widget, event): diff --git a/pyfpdb/Mucked.py b/pyfpdb/Mucked.py index 3bd84cb7..ebe31b3a 100755 --- a/pyfpdb/Mucked.py +++ b/pyfpdb/Mucked.py @@ -345,6 +345,22 @@ class Aux_Seats(Aux_Window): def create_contents(self): pass def update_contents(self): pass + def update_card_positions(self): + # self.adj does not exist until .create() has been run + try: + adj = self.adj + except AttributeError: + return + loc = self.config.get_aux_locations(self.params['name'], int(self.hud.max)) + for i in (range(1, self.hud.max + 1) + ['common']): + if i == 'common': + (x, y) = self.params['layout'][self.hud.max].common + else: + (x, y) = loc[adj[i]] + self.positions[i] = self.card_positions(x, self.hud.table.x, y, self.hud.table.y) + self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) + + def create(self): self.adj = self.hud.adj_seats(0, self.config) # move adj_seats to aux and get rid of it in Hud.py loc = self.config.get_aux_locations(self.params['name'], int(self.hud.max)) @@ -362,7 +378,7 @@ class Aux_Seats(Aux_Window): self.m_windows[i].set_transient_for(self.hud.main_window) self.m_windows[i].set_focus_on_map(False) self.m_windows[i].connect("configure_event", self.configure_event_cb, i) - self.positions[i] = (int(x) + self.hud.table.x, int(y) + self.hud.table.y) + self.positions[i] = self.card_positions(x, self.hud.table.x, y, self.hud.table.y) self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) if self.params.has_key('opacity'): self.m_windows[i].set_opacity(float(self.params['opacity'])) @@ -374,6 +390,13 @@ class Aux_Seats(Aux_Window): if self.uses_timer: self.m_windows[i].hide() + + def card_positions(self, x, table_x, y, table_y): + _x = int(x) + int(table_x) + _y = int(y) + int(table_y) + return (_x, _y) + + def update_gui(self, new_hand_id): """Update the gui, LDO.""" for i in self.m_windows.keys(): From b79f0ddccf29ed2684506cca5174f6f3c36641b3 Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 15 Aug 2009 14:27:20 +0300 Subject: [PATCH 08/10] Actually call position update on reposition Forgot to commit the call that does hud and aux window repositioning --- pyfpdb/Hud.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index bdc0cdc8..1ec7f0d5 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -210,6 +210,7 @@ class Hud: self.aux_windows = [] def reposition_windows(self, *args): + self.update_table_position() for w in self.stat_windows.itervalues(): if type(w) == int: # print "in reposition, w =", w From c5aedf321fa1163ef406437cdff141dfc67b08e9 Mon Sep 17 00:00:00 2001 From: PassThePeas Date: Sun, 16 Aug 2009 20:01:36 +0200 Subject: [PATCH 09/10] Modification to FulltiltToFpdb.py mostly for tourneys contexts modified: FulltiltToFpdb.py - Sitting out players are no longer considered out of a hand (in a tourney context, they can act even if out at the beggining of the hand) - re_CollectPot modified to take into account Tournament context (no $ in the pot) - Try to read buy-in/fee from topline in Tournament context - Deal with commas in pot size (readCollectPot) --- pyfpdb/FulltiltToFpdb.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index e476dc30..18f32bb4 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -57,7 +57,7 @@ class Fulltilt(HandHistoryConverter): (?:.*?\n(?PHand\s\#(?P=HID)\shas\sbeen\scanceled))? ''', re.VERBOSE|re.DOTALL) re_Button = re.compile('^The button is in seat #(?P