diff --git a/pyfpdb/Card.py b/pyfpdb/Card.py index 75c742f9..ab6843c5 100755 --- a/pyfpdb/Card.py +++ b/pyfpdb/Card.py @@ -57,6 +57,21 @@ def fourStartCards(value1, suit1, value2, suit2, value3, suit3, value4, suit4): #AAKKs #AAKKr # Is probably what we are looking for + + # mct: + # my maths says there are 4 classes of suitedness + # SSSS SSSx SSxy SSHH + # encode them as follows: + # SSSS (K, J, 6, 3) + # - 13C4 = 715 possibilities + # SSSx (K, J, 6),(3) + # - 13C3 * 13 = 3718 possibilities + # SSxy (K, J),(6),(3) + # - 13C2 * 13*13 = 13182 possibilities + # SSHH (K, J),(6, 3) + # - 13C2 * 13C2 = 6084 possibilities + # Needless to say they won't fit on a 13x13 grid. + # The actual number of hands in each class is far greater return(0) def cardFromValueSuit(value, suit): @@ -70,7 +85,7 @@ def cardFromValueSuit(value, suit): def valueSuitFromCard(card): """ Function to convert a card stored in the database (int 0-52) into value and suit like 9s, 4c etc """ - if card < 0 or card > 52: + if card < 0 or card > 52 or not card: return('') else: return( ['', '2h', '3h', '4h', '5h', '6h', '7h', '8h', '9h', 'Th', 'Jh', 'Qh', 'Kh', 'Ah' diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 9582354a..b6c97a29 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -156,21 +156,13 @@ class Database: def get_cards(self, hand): """Get and return the cards for each player in the hand.""" - cards = {} # dict of cards, the key is the seat number example: {1: 'AcQd9hTs5d'} + cards = {} # dict of cards, the key is the seat number, + # the value is a tuple of the players cards + # example: {1: (0, 0, 20, 21, 22, 0 , 0)} c = self.connection.cursor() c.execute(self.sql.query['get_cards'], [hand]) - colnames = [desc[0] for desc in c.description] - cardnames = ['card1', 'card2', 'card3', 'card4', 'card5', 'card6', 'card7'] for row in c.fetchall(): - cs = ['', '', '', '', '', '', ''] - seat = -1 - for col,name in enumerate(colnames): - if name in cardnames: - cs[cardnames.index(name)] = Card.valueSuitFromCard(row[col]) - elif name == 'seat_number': - seat = row[col] - if seat != -1: - cards[seat] = ''.join(cs) + cards[row[0]] = row[1:] return cards def get_common_cards(self, hand): diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 2ffd057b..218707bd 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -34,10 +34,6 @@ import Options (options, sys.argv) = Options.fpdb_options() -print "HUD: dbname =", options.dbname -print "HUD: config =", options.config -print "HUD: logging =", options.errorsToConsole - if not options.errorsToConsole: print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_." errorFile = open('fpdb-error-log.txt', 'w', 0) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index bf9c23d7..6849a32c 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -39,15 +39,14 @@ class Hand: self.starttime = 0 self.handText = handText self.handid = 0 - self.tablename = "Slartibartfast" - self.hero = "Hiro" + self.tablename = "" + self.hero = "" self.maxseats = 10 self.counted_seats = 0 self.buttonpos = 0 self.seating = [] self.players = [] self.posted = [] - self.involved = True # Collections indexed by street names self.bets = {} @@ -55,23 +54,26 @@ class Hand: self.streets = {} self.actions = {} # [['mct','bets','$10'],['mika','folds'],['carlg','raises','$20']] self.board = {} # dict from street names to community cards - for street in self.streetList: + self.holecards = {} + for street in self.allStreets: self.streets[street] = "" # portions of the handText, filled by markStreets() self.bets[street] = {} self.lastBet[street] = 0 self.actions[street] = [] self.board[street] = [] + self.holecards[street] = {} # dict from player names to holecards # Collections indexed by player names - self.holecards = {} # dict from player names to dicts by street ... of tuples ... of holecards +# self.holecards = {} # dict from player names to dicts by street ... of tuples ... of holecards self.discards = {} # dict from player names to dicts by street ... of tuples ... of discarded holecards self.stacks = {} self.collected = [] #list of ? self.collectees = {} # dict from player names to amounts collected (?) # Sets of players - self.shown = set() self.folded = set() + self.dealt = set() # 'dealt to' line to be printed + self.shown = set() # cards were shown # self.action = [] # Things to do with money @@ -94,7 +96,7 @@ db: a connected fpdb_db object""" sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId) # HudCache data to come from DerivedStats class # HandsActions - all actions for all players for all streets - self.actions - # BoardCards - Skip - no longer necessary? + # BoardCards - Skip - no longer necessary # Hands - Summary information of hand indexed by handId - gameinfo #hh['siteHandNo'] = self.handid # gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), @@ -167,12 +169,10 @@ If a player has None chips he won't be added.""" if chips is not None: self.players.append([seat, name, chips]) self.stacks[name] = Decimal(chips) - self.holecards[name] = [] - self.discards[name] = [] self.pot.addPlayer(name) - for street in self.streetList: + for street in self.allStreets: self.bets[street][name] = [] - self.holecards[name] = {} # dict from street names. + #self.holecards[name] = {} # dict from street names. self.discards[name] = {} # dict from street names. @@ -411,32 +411,32 @@ Map the tuple self.gametype onto the pokerstars string describing it def printHand(self): self.writeHand(sys.stdout) - def printActionLine(self, act, fh): + def actionString(self, act): if act[1] == 'folds': - print >>fh, ("%s: folds " %(act[0])) + return ("%s: folds " %(act[0])) elif act[1] == 'checks': - print >>fh, ("%s: checks " %(act[0])) + return ("%s: checks " %(act[0])) elif act[1] == 'calls': - print >>fh, ("%s: calls $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else '')) + return ("%s: calls $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else '')) elif act[1] == 'bets': - print >>fh, ("%s: bets $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else '')) + return ("%s: bets $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else '')) elif act[1] == 'raises': - print >>fh, ("%s: raises $%s to $%s%s" %(act[0], act[2], act[3], ' and is all-in' if act[5] else '')) + return ("%s: raises $%s to $%s%s" %(act[0], act[2], act[3], ' and is all-in' if act[5] else '')) elif act[1] == 'completea': - print >>fh, ("%s: completes to $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else '')) + return ("%s: completes to $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else '')) elif act[1] == 'posts': if(act[2] == "small blind"): - print >>fh, ("%s: posts small blind $%s%s" %(act[0], act[3], ' and is all-in' if act[4] else '')) + return ("%s: posts small blind $%s%s" %(act[0], act[3], ' and is all-in' if act[4] else '')) elif(act[2] == "big blind"): - print >>fh, ("%s: posts big blind $%s%s" %(act[0], act[3], ' and is all-in' if act[4] else '')) + return ("%s: posts big blind $%s%s" %(act[0], act[3], ' and is all-in' if act[4] else '')) elif(act[2] == "both"): - print >>fh, ("%s: posts small & big blinds $%s%s" %(act[0], act[3], ' and is all-in' if act[4] else '')) + return ("%s: posts small & big blinds $%s%s" %(act[0], act[3], ' and is all-in' if act[4] else '')) elif act[1] == 'bringin': - print >>fh, ("%s: brings in for $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else '')) + return ("%s: brings in for $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else '')) elif act[1] == 'discards': - print >>fh, ("%s: discards %s %s%s" %(act[0], act[2], 'card' if act[2] == 1 else 'cards' , " [" + " ".join(self.discards[act[0]]['DRAWONE']) + "]" if self.hero == act[0] else '')) + return ("%s: discards %s %s%s" %(act[0], act[2], 'card' if act[2] == 1 else 'cards' , " [" + " ".join(self.discards[act[0]]['DRAWONE']) + "]" if self.hero == act[0] else '')) elif act[1] == 'stands pat': - print >>fh, ("%s: stands pat" %(act[0])) + return ("%s: stands pat" %(act[0])) class HoldemOmahaHand(Hand): @@ -444,9 +444,10 @@ class HoldemOmahaHand(Hand): if gametype['base'] != 'hold': pass # or indeed don't pass and complain instead logging.debug("HoldemOmahaHand") - self.streetList = ['BLINDSANTES', 'DEAL', 'PREFLOP','FLOP','TURN','RIVER'] # a list of the observed street names in order + self.allStreets = ['BLINDSANTES', 'PREFLOP','FLOP','TURN','RIVER'] + self.holeStreets = ['PREFLOP'] self.communityStreets = ['FLOP', 'TURN', 'RIVER'] - self.actionStreets = ['PREFLOP','FLOP','TURN','RIVER'] + self.actionStreets = ['BLINDSANTES','PREFLOP','FLOP','TURN','RIVER'] Hand.__init__(self, sitename, gametype, handText, builtFrom = "HHC") self.sb = gametype['sb'] self.bb = gametype['bb'] @@ -484,24 +485,32 @@ class HoldemOmahaHand(Hand): pass - def addHoleCards(self, cards, player, shown=False): + def addHoleCards(self, cards, player, shown=False, dealt=False): """\ Assigns observed holecards to a player. cards list of card bigrams e.g. ['2h','Jc'] player (string) name of player +shown whether they were revealed at showdown +dealt whether they were seen in a 'dealt to' line """ logging.debug("addHoleCards %s %s" % (cards, player)) try: self.checkPlayerExists(player) - cardset = set(self.card(c) for c in cards) - if shown and len(cardset) > 0: - self.shown.add(player) - if 'PREFLOP' in self.holecards[player]: - self.holecards[player]['PREFLOP'].update(cardset) - else: - self.holecards[player]['PREFLOP'] = cardset except FpdbParseError, e: print "[ERROR] Tried to add holecards for unknown player: %s" % (player,) + return + + cardset = set((self.card(c) for c in cards)) + if len(cardset) == 0: + return + if dealt: + self.dealt.add(player) + if shown: + self.shown.add(player) + if player in self.holecards['PREFLOP']: + self.holecards['PREFLOP'][player].update(cardset) + else: + self.holecards['PREFLOP'][player] = cardset def addShownCards(self, cards, player, holeandboard=None): """\ @@ -510,8 +519,7 @@ Card ranks will be uppercased """ logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard)) if cards is not None: - self.shown.add(player) - self.addHoleCards(cards,player) + self.addHoleCards(cards,player,shown=True) elif holeandboard is not None: holeandboard = set([self.card(c) for c in holeandboard]) board = set([c for s in self.board.values() for c in s]) @@ -523,7 +531,6 @@ Card ranks will be uppercased from nevow import flat players_who_act_preflop = (([x[0] for x in self.actions['PREFLOP']]+[x[0] for x in self.actions['BLINDSANTES']])) players_stacks = [x for x in self.players if x[1] in players_who_act_preflop] - action_streets = [x for x in self.actionStreets if len(self.actions[x]) > 0] def render_stack(context,data): pat = context.tag.patternGenerator('list_item') @@ -536,39 +543,82 @@ Card ranks will be uppercased def render_street(context,data): pat = context.tag.patternGenerator('list_item') for street in data: - actions = [ - T.h3['%s' % street], - T.ol(class_='actions', data=self.actions[street], - render=render_action)[ - T.li(pattern='list_item')[ T.slot(name='action')] - ] - ] - context.tag[ pat().fillSlots('street', actions)] + lines = [] + if street in self.holeStreets and self.holecards[street]: + lines.append( + T.ol(class_='dealclosed', data=street, + render=render_deal) [ + T.li(pattern='list_item')[ T.slot(name='deal') ] + ] + ) + if street in self.communityStreets and self.board[street]: + lines.append( + T.ol(class_='community', data=street, + render=render_deal_community)[ + T.li(pattern='list_item')[ T.slot(name='deal') ] + ] + ) + if street in self.actionStreets and self.actions[street]: + lines.append( + T.ol(class_='actions', data=self.actions[street], render=render_action) [ + T.li(pattern='list_item')[ T.slot(name='action') ] + ] + ) + if lines: + context.tag[ pat().fillSlots('street', [ T.h3[ street ] ]+lines)] return context.tag + def render_deal(context,data): + # data is streetname +# we can have open+closed, or just open, or just closed. + + if self.holecards[data]: + for player in self.holecards[data]: + somestuff = 'dealt to %s %s' % (player, self.holecards[data][player]) + pat = context.tag.patternGenerator('list_item') + context.tag[ pat().fillSlots('deal', somestuff)] + return context.tag + + def render_deal_community(context,data): + # data is streetname + if self.board[data]: + somestuff = '[' + ' '.join(self.board[data]) + ']' + pat = context.tag.patternGenerator('list_item') + context.tag[ pat().fillSlots('deal', somestuff)] + return context.tag def render_action(context,data): pat = context.tag.patternGenerator('list_item') for act in data: - x = "%s %s" % (act[0],act[1]) + x = self.actionString(act) context.tag[ pat().fillSlots('action', x)] return context.tag s = T.p[ - T.h1[ "%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, - self.getGameTypeAsString(), self.sb, self.bb, - datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET')) + 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') ] ], T.h2[ "Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos)], T.ol(class_='stacks', data = players_stacks, render=render_stack)[ T.li(pattern='list_item')[ T.slot(name='playerStack') ] ], - T.ol(class_='streets', data = action_streets, + T.ol(class_='streets', data = self.allStreets, render=render_street)[ T.li(pattern='list_item')[ T.slot(name='street')] ] ] - return flat.flatten(s) + import tidy + + options = dict(input_xml=True, + output_xhtml=True, + add_xml_decl=False, + doctype='omit', + indent='auto', + tidy_mark=False) + + return str(tidy.parseString(flat.flatten(s), **options)) def writeHand(self, fh=sys.__stdout__): @@ -584,33 +634,36 @@ Card ranks will be uppercased if self.actions['BLINDSANTES']: for act in self.actions['BLINDSANTES']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) print >>fh, ("*** HOLE CARDS ***") - if self.involved: - print >>fh, ("Dealt to %s [%s]" %(self.hero , " ".join(self.holecards[self.hero]['PREFLOP']))) + for player in self.dealt: + print >>fh, ("Dealt to %s [%s]" %(player, " ".join(self.holecards['PREFLOP'][player]))) + if self.hero == "": + for player in self.shown.difference(self.dealt): + print >>fh, ("Dealt to %s [%s]" %(player, " ".join(self.holecards['PREFLOP'][player]))) if self.actions['PREFLOP']: for act in self.actions['PREFLOP']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) if self.board['FLOP']: print >>fh, ("*** FLOP *** [%s]" %( " ".join(self.board['FLOP']))) if self.actions['FLOP']: for act in self.actions['FLOP']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) if self.board['TURN']: print >>fh, ("*** TURN *** [%s] [%s]" %( " ".join(self.board['FLOP']), " ".join(self.board['TURN']))) if self.actions['TURN']: for act in self.actions['TURN']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) if self.board['RIVER']: print >>fh, ("*** RIVER *** [%s] [%s]" %(" ".join(self.board['FLOP']+self.board['TURN']), " ".join(self.board['RIVER']) )) if self.actions['RIVER']: for act in self.actions['RIVER']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) #Some sites don't have a showdown section so we have to figure out if there should be one @@ -626,8 +679,8 @@ Card ranks will be uppercased numOfHoleCardsNeeded = 4 elif self.gametype['category'] in ('holdem'): numOfHoleCardsNeeded = 2 - if len(self.holecards[name]['PREFLOP']) == numOfHoleCardsNeeded: - print >>fh, ("%s shows [%s] (a hand...)" % (name, " ".join(self.holecards[name]['PREFLOP']))) + if len(self.holecards['PREFLOP'][name]) == numOfHoleCardsNeeded: + print >>fh, ("%s shows [%s] (a hand...)" % (name, " ".join(self.holecards['PREFLOP'][name]))) # Current PS format has the lines: # Uncalled bet ($111.25) returned to s0rrow @@ -654,7 +707,7 @@ Card ranks will be uppercased seatnum = player[0] name = player[1] if name in self.collectees and name in self.shown: - print >>fh, ("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards[name]['PREFLOP']), self.collectees[name])) + print >>fh, ("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards['PREFLOP'][name]), self.collectees[name])) elif name in self.collectees: print >>fh, ("Seat %d: %s collected ($%s)" % (seatnum, name, self.collectees[name])) #~ elif name in self.shown: @@ -663,7 +716,7 @@ Card ranks will be uppercased print >>fh, ("Seat %d: %s folded" % (seatnum, name)) else: if name in self.shown: - print >>fh, ("Seat %d: %s showed [%s] and lost with..." % (seatnum, name, " ".join(self.holecards[name]['PREFLOP']))) + print >>fh, ("Seat %d: %s showed [%s] and lost with..." % (seatnum, name, " ".join(self.holecards['PREFLOP'][name]))) else: print >>fh, ("Seat %d: %s mucked" % (seatnum, name)) @@ -796,12 +849,12 @@ Card ranks will be uppercased (nc,oc) = self.holecards[player]['DEAL'] print >>fh, _("Dealt to %s: [%s]") % (player, " ".join(nc)) for act in self.actions['DEAL']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) if 'DRAWONE' in self.actions: print >>fh, _("*** FIRST DRAW ***") for act in self.actions['DRAWONE']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) if act[0] == self.hero and act[1] == 'discards': (nc,oc) = self.holecards[act[0]]['DRAWONE'] dc = self.discards[act[0]]['DRAWONE'] @@ -811,7 +864,7 @@ Card ranks will be uppercased if 'DRAWTWO' in self.actions: print >>fh, _("*** SECOND DRAW ***") for act in self.actions['DRAWTWO']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) if act[0] == self.hero and act[1] == 'discards': (nc,oc) = self.holecards[act[0]]['DRAWTWO'] dc = self.discards[act[0]]['DRAWTWO'] @@ -821,7 +874,7 @@ Card ranks will be uppercased if 'DRAWTHREE' in self.actions: print >>fh, _("*** THIRD DRAW ***") for act in self.actions['DRAWTHREE']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) if act[0] == self.hero and act[1] == 'discards': (nc,oc) = self.holecards[act[0]]['DRAWTHREE'] dc = self.discards[act[0]]['DRAWTHREE'] @@ -961,7 +1014,7 @@ Add a complete on [street] by [player] to [amountTo] print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(closed) + "] " if closed else " ", "[" + " ".join(open) + "]" if open else "") for act in self.actions['THIRD']: #FIXME: Need some logic here for bringin vs completes - self.printActionLine(act, fh) + print >>fh, self.actionString(act) if 'FOURTH' in self.actions: dealt = 0 @@ -978,7 +1031,7 @@ Add a complete on [street] by [player] to [amountTo] print >>fh, _("*** 4TH STREET ***") print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(old) + "] " if old else " ", "[" + " ".join(new) + "]" if new else "") for act in self.actions['FOURTH']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) if 'FIFTH' in self.actions: dealt = 0 @@ -996,7 +1049,7 @@ Add a complete on [street] by [player] to [amountTo] print >>fh, _("*** 5TH STREET ***") print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(old) + "] " if old else " ", "[" + " ".join(new) + "]" if new else "") for act in self.actions['FIFTH']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) if 'SIXTH' in self.actions: dealt = 0 @@ -1014,7 +1067,7 @@ Add a complete on [street] by [player] to [amountTo] print >>fh, _("*** 6TH STREET ***") print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(old) + "] " if old else " ", "[" + " ".join(new) + "]" if new else "") for act in self.actions['SIXTH']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) if 'SEVENTH' in self.actions: # OK. It's possible that they're all in at an earlier street, but only closed cards are dealt. @@ -1033,7 +1086,7 @@ Add a complete on [street] by [player] to [amountTo] if new: print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(old) + "] " if old else " ", "[" + " ".join(new) + "]" if new else "") for act in self.actions['SEVENTH']: - self.printActionLine(act, fh) + print >>fh, self.actionString(act) #Some sites don't have a showdown section so we have to figure out if there should be one # The logic for a showdown is: at the end of river action there are at least two players in the hand @@ -1164,7 +1217,8 @@ class Pot(object): def assemble(cnxn, handid): c = cnxn.cursor() - # We need the following for the Hand.__init__ + # We need at least sitename, gametype, handid + # for the Hand.__init__ c.execute(""" select s.name, @@ -1178,22 +1232,19 @@ select round(g.smallBet / 100.0,2), round(g.bigBet / 100.0,2), s.currency, - bc.card1value, - bc.card1suit, - bc.card2value,bc.card2suit, - bc.card3value,bc.card3suit, - bc.card4value,bc.card4suit, - bc.card5value,bc.card5suit + h.boardcard1, + h.boardcard2, + h.boardcard3, + h.boardcard4, + h.boardcard5 from hands as h, - boardcards as bc, sites as s, gametypes as g, handsplayers as hp, players as p where h.id = %(handid)s -and bc.handid = h.id and g.id = h.gametypeid and hp.handid = h.id and p.id = hp.playerid @@ -1203,24 +1254,15 @@ limit 1""", {'handid':handid}) res = c.fetchone() gametype = {'category':res[1],'base':res[2],'type':res[3],'limitType':res[4],'hilo':res[5],'sb':res[6],'bb':res[7], 'currency':res[10]} h = HoldemOmahaHand(hhc = None, sitename=res[0], gametype = gametype, handText=None, builtFrom = "DB", handid=handid) - rank = {0:'X',1:'1',2:'2',3:'3',4:'4', - 5:'5',6:'6',7:'7',8:'8',9:'9', - 10:'T',11:'J',12:'Q',13:'K',14:'A'} - ranks = [rank[r] for r in res[11:21:2]] - cards = map("".join, zip(ranks, res[12:21:2])) - - if cards[0] != "Xx": + cards = map(Card.valueSuitFromCard, res[11:16] ) + if cards[0]: h.setCommunityCards('FLOP', cards[0:3]) - if cards[3] != "Xx": + if cards[3]: h.setCommunityCards('TURN', [cards[3]]) - if cards[4] != "Xx": + if cards[4]: h.setCommunityCards('RIVER', [cards[4]]) #[Card.valueSuitFromCard(x) for x in cards] - - #TODO : doesn't look like this is in the database; don't like the way Hand requires it - h.hero = 'mcturnbull' - # HandInfo : HID, TABLE # BUTTON - why is this treated specially in Hand? # answer: it is written out in hand histories @@ -1246,7 +1288,8 @@ SELECT round(hp.winnings / 100.0,2) as winnings, p.name, round(hp.startcash / 100.0,2) as chips, - hp.card1,hp.card2 + hp.card1,hp.card2, + hp.position FROM handsplayers as hp, players as p @@ -1254,12 +1297,16 @@ WHERE hp.handid = %(handid)s and p.id = hp.playerid """, {'handid':handid}) - for (seat, winnings, name, chips, card1,card2) in c.fetchall(): + for (seat, winnings, name, chips, card1,card2, position) in c.fetchall(): h.addPlayer(seat,name,chips) - h.addHoleCards(map(Card.valueSuitFromCard, (card1,card2)),name) + if card1 and card2: + h.addHoleCards(map(Card.valueSuitFromCard, (card1,card2)), name, dealt=True) if winnings > 0: h.addCollectPot(name, winnings) + if position == 'B': + h.buttonpos = seat + # actions c.execute(""" SELECT @@ -1283,7 +1330,7 @@ ORDER BY res = c.fetchall() for (actnum,player, streetnum, act, allin, amount) in res: act=act.strip() - street = h.streetList[streetnum+2] + street = h.allStreets[streetnum+1] if act==u'blind': h.addBlind(player, 'big blind', amount) # TODO: The type of blind is not recorded in the DB. diff --git a/pyfpdb/Mucked.py b/pyfpdb/Mucked.py index 93f6d102..8ae6bc60 100755 --- a/pyfpdb/Mucked.py +++ b/pyfpdb/Mucked.py @@ -35,6 +35,7 @@ import gobject # FreePokerTools modules import Configuration import Database +import Card class Aux_Window: def __init__(self, hud, params, config): @@ -67,19 +68,27 @@ class Aux_Window: # Some utility routines useful for Aux_Windows # def get_card_images(self): - card_images = {} - suits = ('S', 'H', 'D', 'C') - ranks = ('A', 'K', 'Q', 'J', 'T', '9', '8', '7', '6', '5', '4', '3', '2', 'B') + + card_images = 53 * [0] + suits = ('s', 'h', 'd', 'c') + ranks = (14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2) pb = gtk.gdk.pixbuf_new_from_file(self.config.execution_path(self.params['deck'])) - for j in range(0, 14): + for j in range(0, 13): for i in range(0, 4): - temp_pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, pb.get_has_alpha(), pb.get_bits_per_sample(), 30, 42) - pb.copy_area(30*j, 42*i, 30, 42, temp_pb, 0, 0) - card_images[(ranks[j], suits[i])] = temp_pb + card_images[Card.cardFromValueSuit(ranks[j], suits[i])] = self.cropper(pb, i, j) + temp_pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, pb.get_has_alpha(), pb.get_bits_per_sample(), 30, 42) +# also pick out a card back and store in [0] + card_images[0] = self.cropper(pb, 2, 13) return(card_images) # cards are 30 wide x 42 high + def cropper(self, pb, i, j): + """Crop out a card image given an FTP deck and the i, j position.""" + temp_pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, pb.get_has_alpha(), pb.get_bits_per_sample(), 30, 42) + pb.copy_area(30*j, 42*i, 30, 42, temp_pb, 0, 0) + return temp_pb + def split_cards(self, card): if card == 'xx': return ('B', 'S') return (card[0], card[1].upper()) @@ -108,9 +117,10 @@ class Stud_mucked(Aux_Window): def create(self): - self.container =gtk.Window() + self.container = gtk.Window() self.vbox = gtk.VBox() self.container.add(self.vbox) + self.container.set_title(self.hud.table.name) self.mucked_list.create(self.vbox) self.mucked_cards.create(self.vbox) @@ -207,7 +217,9 @@ class Stud_list: # find the hero's seat from the stat_dict for stat in self.parent.hud.stat_dict.itervalues(): if stat['screen_name'] == hero: - return self.parent.hud.cards[stat['seat']][0:6] + return Card.valueSuitFromCard(self.parent.hud.cards[stat['seat']][0]) +\ + Card.valueSuitFromCard(self.parent.hud.cards[stat['seat']][1]) +\ + Card.valueSuitFromCard(self.parent.hud.cards[stat['seat']][2]) return "xxxxxx" def update_gui(self, new_hand_id): @@ -240,7 +252,7 @@ class Stud_cards: for r in range(0, self.rows): for c in range(0, self.cols): - self.seen_cards[(c, r)] = gtk.image_new_from_pixbuf(self.card_images[('B', 'S')]) + self.seen_cards[(c, r)] = gtk.image_new_from_pixbuf(self.card_images[(0)]) self.eb[(c, r)]= gtk.EventBox() # set up the contents for the cells @@ -287,11 +299,11 @@ class Stud_cards: self.clear() for c, cards in self.parent.hud.cards.iteritems(): self.grid_contents[(1, c - 1)].set_text(self.get_screen_name(c)) - for i in ((0, cards[0:2]), (1, cards[2:4]), (2, cards[4:6]), (3, cards[6:8]), - (4, cards[8:10]), (5, cards[10:12]), (6, cards[12:14])): - if not i[1] == "xx": + for i in ((0, cards[0]), (1, cards[1]), (2, cards[2]), (3, cards[3]), + (4, cards[4]), (5, cards[5]), (6, cards[6])): + if not i[1] == 0: self.seen_cards[(i[0], c - 1)]. \ - set_from_pixbuf(self.card_images[self.parent.split_cards(i[1])]) + set_from_pixbuf(self.card_images[i[1]]) ## action in tool tips for 3rd street cards for c in (0, 1, 2): for r in range(0, self.rows): @@ -314,7 +326,7 @@ class Stud_cards: for r in range(0, self.rows): self.grid_contents[(1, r)].set_text(" ") for c in range(0, 7): - self.seen_cards[(c, r)].set_from_pixbuf(self.card_images[('B', 'S')]) + self.seen_cards[(c, r)].set_from_pixbuf(self.card_images[0]) self.eb[(c, r)].set_tooltip_text('') class Flop_Mucked(Aux_Window): @@ -459,29 +471,31 @@ class Flop_Mucked(Aux_Window): new_locs[i] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y) self.config.edit_aux_layout(self.params['name'], self.hud.max, locations = new_locs) -if __name__== "__main__": - - def destroy(*args): # call back for terminating the main eventloop - gtk.main_quit() # used only for testing +# This test program doesn't work - def process_new_hand(source, condition, db_connection): #callback from stdin watch -- testing only -# there is a new hand_id to be processed -# just read it and pass it to update - new_hand_id = sys.stdin.readline() - new_hand_id = new_hand_id.rstrip() # remove trailing whitespace - m.update_data(new_hand_id, db_connection) - m.update_gui(new_hand_id) - return(True) - - config = Configuration.Config() - db_connection = Database.Database(config, 'fpdb', '') - main_window = gtk.Window() - main_window.set_keep_above(True) - main_window.connect("destroy", destroy) - - aux_to_call = "stud_mucked" - aux_params = config.get_aux_parameters(aux_to_call) - m = eval("%s(main_window, None, config, aux_params)" % aux_params['class']) - - s_id = gobject.io_add_watch(sys.stdin, gobject.IO_IN, process_new_hand, db_connection) - gtk.main() +#if __name__== "__main__": +# +# def destroy(*args): # call back for terminating the main eventloop +# gtk.main_quit() # used only for testing +# +# def process_new_hand(source, condition, db_connection): #callback from stdin watch -- testing only +## there is a new hand_id to be processed +## just read it and pass it to update +# new_hand_id = sys.stdin.readline() +# new_hand_id = new_hand_id.rstrip() # remove trailing whitespace +# m.update_data(new_hand_id, db_connection) +# m.update_gui(new_hand_id) +# return(True) +# +# config = Configuration.Config() +# db_connection = Database.Database(config, 'fpdbTEST', '') +# main_window = gtk.Window() +# main_window.set_keep_above(True) +# main_window.connect("destroy", destroy) +# +# aux_to_call = "stud_mucked" +# aux_params = config.get_aux_parameters(aux_to_call) +# m = eval("%s(None, config, aux_params)" % aux_params['class']) +# +# s_id = gobject.io_add_watch(sys.stdin, gobject.IO_IN, process_new_hand, db_connection) +# gtk.main() diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 44bd88a2..5350713c 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -209,7 +209,7 @@ follow : whether to tail -f the input""" for a in self.re_PostBB.finditer(hand.handText): hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) for a in self.re_PostBoth.finditer(hand.handText): - hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB')) + hand.addBlind(a.group('PNAME'), 'both', a.group('SBBB')) def readHeroCards(self, hand): m = self.re_HeroCards.search(hand.handText) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index a36f812d..1a9deb60 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -528,7 +528,6 @@ class Sql: self.query['get_cards'] = """ select seatNo AS seat_number, - name AS screen_name, card1, /*card1Value, card1Suit, */ card2, /*card2Value, card2Suit, */ card3, /*card3Value, card3Suit, */ diff --git a/pyfpdb/fpdb_save_to_db.py b/pyfpdb/fpdb_save_to_db.py index 3870a6e9..e612a166 100644 --- a/pyfpdb/fpdb_save_to_db.py +++ b/pyfpdb/fpdb_save_to_db.py @@ -82,7 +82,8 @@ def ring_holdem_omaha(config, backend, db, cursor, base, category, site_hand_no, t2 = time() hands_id = fpdb_simple.storeHands(backend, db, cursor, site_hand_no, gametype_id - ,hand_start_time, names, tableName, maxSeats, hudImportData) + ,hand_start_time, names, tableName, maxSeats, + hudImportData, board_values, board_suits) t3 = time() hands_players_ids = fpdb_simple.store_hands_players_holdem_omaha( backend, db, cursor, category, hands_id, player_ids, start_cashes diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 2b6f248b..db201405 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -1147,10 +1147,13 @@ card5Value, card5Suit) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", #end def store_board_cards def storeHands(backend, conn, cursor, site_hand_no, gametype_id - ,hand_start_time, names, tableName, maxSeats, hudCache): + ,hand_start_time, names, tableName, maxSeats, hudCache, + board_values, board_suits): + cards = [Card.cardFromValueSuit(v,s) for v,s in zip(board_values,board_suits)] #stores into table hands: cursor.execute ("""INSERT INTO Hands (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats + ,boardcard1,boardcard2,boardcard3,boardcard4,boardcard5 ,playersVpi, playersAtStreet1, playersAtStreet2 ,playersAtStreet3, playersAtStreet4, playersAtShowdown ,street0Raises, street1Raises, street2Raises @@ -1159,9 +1162,11 @@ def storeHands(backend, conn, cursor, site_hand_no, gametype_id ,showdownPot ) VALUES - (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) """ , (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.datetime.today(), maxSeats + ,cards[0], cards[1], cards[2], cards[3], cards[4] ,hudCache['playersVpi'], hudCache['playersAtStreet1'], hudCache['playersAtStreet2'] ,hudCache['playersAtStreet3'], hudCache['playersAtStreet4'], hudCache['playersAtShowdown'] ,hudCache['street0Raises'], hudCache['street1Raises'], hudCache['street2Raises']