diff --git a/packaging/debian/control b/packaging/debian/control index 93660791..784c4b40 100644 --- a/packaging/debian/control +++ b/packaging/debian/control @@ -6,7 +6,7 @@ Build-Depends: debhelper, python-support Standards-Version: 3.8.0 Package: python-fpdb -Architecture: any +Architecture: all Section: games Priority: extra Depends: ${python:Depends}, python-gtk2, python-matplotlib, diff --git a/pyfpdb/BetfairToFpdb.py b/pyfpdb/BetfairToFpdb.py index 59344991..f4d8bf9b 100755 --- a/pyfpdb/BetfairToFpdb.py +++ b/pyfpdb/BetfairToFpdb.py @@ -105,7 +105,7 @@ class Betfair(HandHistoryConverter): logging.debug("HID %s, Table %s" % (m.group('HID'), m.group('TABLE'))) hand.handid = m.group('HID') hand.tablename = m.group('TABLE') - hand.starttime = time.strptime(m.group('DATETIME'), "%A, %B %d, %H:%M:%S GMT %Y") + hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%A, %B %d, %H:%M:%S GMT %Y") #hand.buttonpos = int(m.group('BUTTON')) def readPlayerStacks(self, hand): @@ -144,6 +144,7 @@ class Betfair(HandHistoryConverter): def readAntes(self, hand): logging.debug("reading antes") + m = self.re_Antes.finditer(hand.handText) for player in m: logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE'))) hand.addAnte(player.group('PNAME'), player.group('ANTE')) @@ -160,17 +161,15 @@ class Betfair(HandHistoryConverter): hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON')) def readHeroCards(self, hand): - m = self.re_HeroCards.search(hand.handText) - if(m == None): - #Not involved in hand - hand.involved = False - else: - hand.hero = m.group('PNAME') - # "2c, qh" -> set(["2c","qc"]) - # Also works with Omaha hands. - cards = m.group('CARDS') - cards = [c.strip() for c in cards.split(',')] - hand.addHoleCards(cards, m.group('PNAME')) + # streets PREFLOP, PREDRAW, and THIRD are special cases beacause + # we need to grab hero's cards + for street in ('PREFLOP', 'DEAL'): + if street in hand.streets.keys(): + m = self.re_HeroCards.finditer(hand.streets[street]) + for found in m: + hand.hero = found.group('PNAME') + newcards = [c.strip() for c in found.group('CARDS').split(',')] + hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True) def readStudPlayerCards(self, hand, street): # balh blah blah diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index b8022a45..924d6584 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -278,6 +278,28 @@ class Import: return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \ % (self.interval, self.callFpdbHud, self.hhArchiveBase, self.saveActions, self.fastStoreHudCache) +class HudUI: + def __init__(self, node): + self.node = node + self.label = node.getAttribute('label') + # + self.aggregate_ring = fix_tf(node.getAttribute('aggregate_ring_game_stats')) + self.aggregate_tour = fix_tf(node.getAttribute('aggregate_tourney_stats')) + self.hud_style = node.getAttribute('stat_aggregation_range') + self.hud_days = node.getAttribute('aggregation_days') + self.agg_bb_mult = node.getAttribute('aggregation_level_multiplier') + # + self.h_aggregate_ring = fix_tf(node.getAttribute('aggregate_hero_ring_game_stats')) + self.h_aggregate_tour = fix_tf(node.getAttribute('aggregate_hero_tourney_stats')) + self.h_hud_style = node.getAttribute('hero_stat_aggregation_range') + self.h_hud_days = node.getAttribute('hero_aggregation_days') + self.h_agg_bb_mult = node.getAttribute('hero_aggregation_level_multiplier') + + + def __str__(self): + return " label = %s\n" % self.label + + class Tv: def __init__(self, node): self.combinedStealFold = node.getAttribute("combinedStealFold") @@ -311,13 +333,21 @@ class Config: pass if file == None: # that didn't work either, just die - print "No HUD_config_xml found. Exiting" - sys.stderr.write("No HUD_config_xml found. Exiting") + print "No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting" + sys.stderr.write("No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting") + print "press enter to continue" + sys.stdin.readline() sys.exit() # Parse even if there was no real config file found and we are using the example # If using the example, we'll edit it later +# sc 2009/10/04 Example already copied to main filename, is this ok? log.info("Reading configuration file %s" % file) + if os.sep in file: + print "\nReading configuration file %s\n" % file + else: + print "\nReading configuration file %s" % file + print "in %s\n" % os.getcwd() try: doc = xml.dom.minidom.parse(file) except: @@ -389,6 +419,10 @@ class Config: imp = Import(node = imp_node) self.imp = imp + for hui_node in doc.getElementsByTagName('hud_ui'): + hui = HudUI(node = hui_node) + self.ui = hui + for tv_node in doc.getElementsByTagName("tv"): tv = Tv(node = tv_node) self.tv = tv @@ -405,6 +439,8 @@ class Config: db_pass = df_parms['db-password']) self.save(file=os.path.join(self.default_config_path, "HUD_config.xml")) + print "" + def set_hhArchiveBase(self, path): self.imp.node.setAttribute("hhArchiveBase", path) @@ -454,11 +490,15 @@ class Config: def find_example_config(self): if os.path.exists('HUD_config.xml.example'): # there is a HUD_config in the cwd - file = 'HUD_config.xml.example' # so we use it + file = 'HUD_config.xml' # so we use it + try: + shutil.copyfile(file+'.example', file) + except: + file = '' print "No HUD_config.xml found, using HUD_config.xml.example.\n", \ - "A HUD_config.xml will be written. You will probably have to edit it." + "A HUD_config.xml has been created. You will probably have to edit it." sys.stderr.write("No HUD_config.xml found, using HUD_config.xml.example.\n" + \ - "A HUD_config.xml will be written. You will probably have to edit it.") + "A HUD_config.xml has been created. You will probably have to edit it.") else: file = None return file @@ -598,6 +638,53 @@ class Config: try: tv['combinedPostflop'] = self.tv.combinedPostflop except: tv['combinedPostflop'] = True return tv + + # Allow to change the menu appearance + def get_hud_ui_parameters(self): + hui = {} + + default_text = 'FPDB Menu - Right click\nLeft-Drag to Move' + try: + hui['label'] = self.ui.label + if self.ui.label == '': # Empty menu label is a big no-no + hui['label'] = default_text + except: + hui['label'] = default_text + + try: hui['aggregate_ring'] = self.ui.aggregate_ring + except: hui['aggregate_ring'] = False + + try: hui['aggregate_tour'] = self.ui.aggregate_tour + except: hui['aggregate_tour'] = True + + try: hui['hud_style'] = self.ui.hud_style + except: hui['hud_style'] = 'A' + + try: hui['hud_days'] = int(self.ui.hud_days) + except: hui['hud_days'] = 90 + + try: hui['agg_bb_mult'] = self.ui.agg_bb_mult + except: hui['agg_bb_mult'] = 1 + + # Hero specific + + try: hui['h_aggregate_ring'] = self.ui.h_aggregate_ring + except: hui['h_aggregate_ring'] = False + + try: hui['h_aggregate_tour'] = self.ui.h_aggregate_tour + except: hui['h_aggregate_tour'] = True + + try: hui['h_hud_style'] = self.ui.h_hud_style + except: hui['h_hud_style'] = 'S' + + try: hui['h_hud_days'] = int(self.ui.h_hud_days) + except: hui['h_hud_days'] = 30 + + try: hui['h_agg_bb_mult'] = self.ui.h_agg_bb_mult + except: hui['h_agg_bb_mult'] = 1 + + return hui + def get_import_parameters(self): imp = {} diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index b9ec62f4..828efba0 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -188,14 +188,7 @@ class Database: log.info("Creating Database instance, sql = %s" % sql) self.config = c self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql - self.fdb.do_connect(c) - self.connection = self.fdb.db - - db_params = c.get_db_parameters() - self.import_options = c.get_import_parameters() - self.type = db_params['db-type'] - self.backend = db_params['db-backend'] - self.db_server = db_params['db-server'] + self.do_connect(c) if self.backend == self.PGSQL: from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE @@ -206,14 +199,14 @@ class Database: # where possible avoid creating new SQL instance by using the global one passed in if sql is None: - self.sql = SQL.Sql(type = self.type, db_server = db_params['db-server']) + self.sql = SQL.Sql(type = self.type, db_server = self.db_server) else: self.sql = sql - if self.backend == self.SQLITE and db_params['db-databaseName'] == ':memory:' and self.fdb.wrongDbVersion: + if self.backend == self.SQLITE and self.database == ':memory:' and self.wrongDbVersion: log.info("sqlite/:memory: - creating") self.recreate_tables() - self.fdb.wrongDbVersion = False + self.wrongDbVersion = False self.pcache = None # PlayerId cache self.cachemiss = 0 # Delete me later - using to count player cache misses @@ -245,6 +238,16 @@ class Database: def do_connect(self, c): self.fdb.do_connect(c) + self.connection = self.fdb.db + self.wrongDbVersion = self.fdb.wrongDbVersion + + db_params = c.get_db_parameters() + self.import_options = c.get_import_parameters() + self.type = db_params['db-type'] + self.backend = db_params['db-backend'] + self.db_server = db_params['db-server'] + self.database = db_params['db-databaseName'] + self.host = db_params['db-host'] def commit(self): self.fdb.db.commit() @@ -389,7 +392,7 @@ class Database: print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) else: if row and row[0]: - self.hand_1_day_ago = row[0] + self.hand_1day_ago = int(row[0]) d = timedelta(days=hud_days) now = datetime.utcnow() - d @@ -431,6 +434,7 @@ class Database: if hud_style == 'S' or h_hud_style == 'S': self.get_stats_from_hand_session(hand, stat_dict, hero_id, hud_style, h_hud_style) + if hud_style == 'S' and h_hud_style == 'S': return stat_dict @@ -452,10 +456,10 @@ class Database: #elif h_hud_style == 'H': # h_stylekey = date_nhands_ago needs array by player here ... - #if aggregate: always use aggreagte query now: use agg_bb_mult of 1 for no aggregation: + #if aggregate: always use aggregate query now: use agg_bb_mult of 1 for no aggregation: query = 'get_stats_from_hand_aggregated' subs = (hand, hero_id, stylekey, agg_bb_mult, agg_bb_mult, hero_id, h_stylekey, h_agg_bb_mult, h_agg_bb_mult) - print "agg query subs:", subs + #print "agg query subs:", subs #else: # query = 'get_stats_from_hand' # subs = (hand, stylekey) @@ -467,11 +471,13 @@ class Database: c.execute(self.sql.query[query], subs) colnames = [desc[0] for desc in c.description] for row in c.fetchall(): - t_dict = {} - for name, val in zip(colnames, row): - t_dict[name.lower()] = val -# print t_dict - stat_dict[t_dict['player_id']] = t_dict + playerid = row[0] + if (playerid == hero_id and h_hud_style != 'S') or (playerid != hero_id and hud_style != 'S'): + t_dict = {} + for name, val in zip(colnames, row): + t_dict[name.lower()] = val +# print t_dict + stat_dict[t_dict['player_id']] = t_dict return stat_dict @@ -501,10 +507,10 @@ class Database: row = c.fetchone() if colnames[0].lower() == 'player_id': - playerid = row[0] # Loop through stats adding them to appropriate stat_dict: while row: + playerid = row[0] if (playerid == hero_id and h_hud_style == 'S') or (playerid != hero_id and hud_style == 'S'): for name, val in zip(colnames, row): if not playerid in stat_dict: @@ -535,6 +541,16 @@ class Database: else: return None + def get_player_names(self, config, site_id=None, like_player_name="%"): + """Fetch player names from players. Use site_id and like_player_name if provided""" + + if site_id == None: + site_id = -1 + c = self.get_cursor() + c.execute(self.sql.query['get_player_names'], (like_player_name, site_id, site_id)) + rows = c.fetchall() + return rows + #returns the SQL ids of the names given in an array # TODO: if someone gets industrious, they should make the parts that use the output of this function deal with a dict # { playername: id } instead of depending on it's relation to the positions list @@ -1131,7 +1147,7 @@ class Database: elif self.backend == self.MYSQL_INNODB: c.execute("""insert into TourneyTypes(id, siteId, buyin, fee, maxSeats, knockout ,rebuyOrAddon, speed, headsUp, shootout, matrix) - values (1, 1, 0, 0, 0, False, False, null, False, False, False);""") + values (DEFAULT, 1, 0, 0, 0, False, False, null, False, False, False);""") #end def fillDefaultData @@ -1362,174 +1378,288 @@ class Database: def storeHand(self, p): #stores into table hands: - q = """INSERT INTO Hands ( - tablename, - gametypeid, - sitehandno, - handstart, - importtime, - seats, - maxseats, - boardcard1, - boardcard2, - boardcard3, - boardcard4, - boardcard5, - street1Pot, - street2Pot, - street3Pot, - street4Pot, - showdownPot - ) - VALUES - (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s)""" -#--- texture, -#-- playersVpi, -#-- playersAtStreet1, -#-- playersAtStreet2, -#-- playersAtStreet3, -#-- playersAtStreet4, -#-- playersAtShowdown, -#-- street0Raises, -#-- street1Raises, -#-- street2Raises, -#-- street3Raises, -#-- street4Raises, -#-- seats, + q = self.sql.query['store_hand'] q = q.replace('%s', self.sql.query['placeholder']) - print "DEBUG: p: %s" %p - print "DEBUG: gtid: %s" % p['gameTypeId'] + self.cursor.execute(q, ( p['tableName'], p['gameTypeId'], p['siteHandNo'], p['handStart'], datetime.today(), #importtime -# len(p['names']), #seats - p['maxSeats'], p['seats'], + p['maxSeats'], + p['texture'], + p['playersVpi'], p['boardcard1'], p['boardcard2'], p['boardcard3'], p['boardcard4'], p['boardcard5'], -# hudCache['playersVpi'], -# hudCache['playersAtStreet1'], -# hudCache['playersAtStreet2'], -# hudCache['playersAtStreet3'], -# hudCache['playersAtStreet4'], -# hudCache['playersAtShowdown'], -# hudCache['street0Raises'], -# hudCache['street1Raises'], -# hudCache['street2Raises'], -# hudCache['street3Raises'], -# hudCache['street4Raises'], + p['playersAtStreet1'], + p['playersAtStreet2'], + p['playersAtStreet3'], + p['playersAtStreet4'], + p['playersAtShowdown'], + p['street0Raises'], + p['street1Raises'], + p['street2Raises'], + p['street3Raises'], + p['street4Raises'], p['street1Pot'], p['street2Pot'], p['street3Pot'], p['street4Pot'], p['showdownPot'] )) - #return getLastInsertId(backend, conn, cursor) + return self.get_last_insert_id(self.cursor) # def storeHand - def storeHandsPlayers(self, p): - #def store_hands_players_holdem_omaha(self, backend, category, hands_id, player_ids, start_cashes - # ,positions, card_values, card_suits, winnings, rakes, seatNos, hudCache): - # result=[] - # - # # postgres (and others?) needs the booleans converted to ints before saving: - # # (or we could just save them as boolean ... but then we can't sum them so easily in sql ???) - # # NO - storing booleans for now so don't need this - # #hudCacheInt = {} - # #for k,v in hudCache.iteritems(): - # # if k in ('wonWhenSeenStreet1', 'wonAtSD', 'totalProfit'): - # # hudCacheInt[k] = v - # # else: - # # hudCacheInt[k] = map(lambda x: 1 if x else 0, v) - # - # try: - # inserts = [] - # for i in xrange(len(player_ids)): - # card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0]) - # card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1]) - # - # if (category=="holdem"): - # startCards = Card.twoStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1]) - # card3 = None - # card4 = None - # elif (category=="omahahi" or category=="omahahilo"): - # startCards = Card.fourStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1] - # ,card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3]) - # card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2]) - # card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3]) - # else: - # raise FpdbError("invalid category") - # - # inserts.append( ( - # hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid - needed for hudcache - # card1, card2, card3, card4, startCards, - # winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i], - # hudCache['street0VPI'][i], hudCache['street0Aggr'][i], - # hudCache['street0_3BChance'][i], hudCache['street0_3BDone'][i], - # hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i], - # hudCache['street4Seen'][i], hudCache['sawShowdown'][i], - # hudCache['street1Aggr'][i], hudCache['street2Aggr'][i], hudCache['street3Aggr'][i], hudCache['street4Aggr'][i], - # hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i], - # hudCache['otherRaisedStreet3'][i], hudCache['otherRaisedStreet4'][i], - # hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i], - # hudCache['foldToOtherRaisedStreet3'][i], hudCache['foldToOtherRaisedStreet4'][i], - # hudCache['wonWhenSeenStreet1'][i], hudCache['wonAtSD'][i], - # hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i], - # hudCache['foldedBbToSteal'][i], hudCache['foldSbToStealChance'][i], hudCache['foldedSbToSteal'][i], - # hudCache['street1CBChance'][i], hudCache['street1CBDone'][i], hudCache['street2CBChance'][i], hudCache['street2CBDone'][i], - # hudCache['street3CBChance'][i], hudCache['street3CBDone'][i], hudCache['street4CBChance'][i], hudCache['street4CBDone'][i], - # hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i], - # hudCache['foldToStreet2CBChance'][i], hudCache['foldToStreet2CBDone'][i], - # hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i], - # hudCache['foldToStreet4CBChance'][i], hudCache['foldToStreet4CBDone'][i], - # hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], - # hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i], - # hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i], - # hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i], - # hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i], - # hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i] - # ) ) - # c = self.get_cursor() - # c.executemany (""" - # INSERT INTO HandsPlayers - # (handId, playerId, startCash, position, tourneyTypeId, - # card1, card2, card3, card4, startCards, winnings, rake, seatNo, totalProfit, - # street0VPI, street0Aggr, street0_3BChance, street0_3BDone, - # street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, - # street1Aggr, street2Aggr, street3Aggr, street4Aggr, - # otherRaisedStreet1, otherRaisedStreet2, otherRaisedStreet3, otherRaisedStreet4, - # foldToOtherRaisedStreet1, foldToOtherRaisedStreet2, foldToOtherRaisedStreet3, foldToOtherRaisedStreet4, - # wonWhenSeenStreet1, wonAtSD, - # stealAttemptChance, stealAttempted, foldBbToStealChance, foldedBbToSteal, foldSbToStealChance, foldedSbToSteal, - # street1CBChance, street1CBDone, street2CBChance, street2CBDone, - # street3CBChance, street3CBDone, street4CBChance, street4CBDone, - # foldToStreet1CBChance, foldToStreet1CBDone, foldToStreet2CBChance, foldToStreet2CBDone, - # foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone, - # street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone, - # street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone, - # street0Calls, street1Calls, street2Calls, street3Calls, street4Calls, - # street0Bets, street1Bets, street2Bets, street3Bets, street4Bets - # ) - # 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, %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)""".replace('%s', self.sql.query['placeholder']) - # ,inserts ) - # result.append( self.get_last_insert_id(c) ) # wrong? not used currently - # except: - # raise FpdbError( "store_hands_players_holdem_omaha error: " + str(sys.exc_value) ) - # - # return result + def storeHandsPlayers(self, hid, pids, pdata): + #print "DEBUG: %s %s %s" %(hid, pids, pdata) + inserts = [] + for p in pdata: + inserts.append( (hid, + pids[p], + pdata[p]['startCash'], + pdata[p]['seatNo'], + pdata[p]['street0Aggr'], + pdata[p]['street1Aggr'], + pdata[p]['street2Aggr'], + pdata[p]['street3Aggr'], + pdata[p]['street4Aggr'] + ) ) - pass + q = """INSERT INTO HandsPlayers ( + handId, + playerId, + startCash, + seatNo, + street0Aggr, + street1Aggr, + street2Aggr, + street3Aggr, + street4Aggr + ) + VALUES ( + %s, %s, %s, %s, %s, + %s, %s, %s, %s + )""" + +# position, +# tourneyTypeId, +# card1, +# card2, +# card3, +# card4, +# startCards, +# winnings, +# rake, +# totalProfit, +# street0VPI, +# street0_3BChance, +# street0_3BDone, +# street1Seen, +# street2Seen, +# street3Seen, +# street4Seen, +# sawShowdown, +# otherRaisedStreet1, +# otherRaisedStreet2, +# otherRaisedStreet3, +# otherRaisedStreet4, +# foldToOtherRaisedStreet1, +# foldToOtherRaisedStreet2, +# foldToOtherRaisedStreet3, +# foldToOtherRaisedStreet4, +# wonWhenSeenStreet1, +# wonAtSD, +# stealAttemptChance, +# stealAttempted, +# foldBbToStealChance, +# foldedBbToSteal, +# foldSbToStealChance, +# foldedSbToSteal, +# street1CBChance, +# street1CBDone, +# street2CBChance, +# street2CBDone, +# street3CBChance, +# street3CBDone, +# street4CBChance, +# street4CBDone, +# foldToStreet1CBChance, +# foldToStreet1CBDone, +# foldToStreet2CBChance, +# foldToStreet2CBDone, +# foldToStreet3CBChance, +# foldToStreet3CBDone, +# foldToStreet4CBChance, +# foldToStreet4CBDone, +# street1CheckCallRaiseChance, +# street1CheckCallRaiseDone, +# street2CheckCallRaiseChance, +# street2CheckCallRaiseDone, +# street3CheckCallRaiseChance, +# street3CheckCallRaiseDone, +# street4CheckCallRaiseChance, +# street4CheckCallRaiseDone, +# street0Calls, +# street1Calls, +# street2Calls, +# street3Calls, +# street4Calls, +# street0Bets, +# street1Bets, +# street2Bets, +# street3Bets, +# street4Bets + + q = q.replace('%s', self.sql.query['placeholder']) + + #print "DEBUG: inserts: %s" %inserts + self.cursor.executemany(q, inserts) + + def storeHudCacheNew(self, gid, pid, hc): + q = """INSERT INTO HudCache ( + gametypeId, + playerId + ) + VALUES ( + %s, %s + )""" + +# gametypeId, +# playerId, +# activeSeats, +# position, +# tourneyTypeId, +# styleKey, +# HDs, +# street0VPI, +# street0Aggr, +# street0_3BChance, +# street0_3BDone, +# street1Seen, +# street2Seen, +# street3Seen, +# street4Seen, +# sawShowdown, +# street1Aggr, +# street2Aggr, +# street3Aggr, +# street4Aggr, +# otherRaisedStreet1, +# otherRaisedStreet2, +# otherRaisedStreet3, +# otherRaisedStreet4, +# foldToOtherRaisedStreet1, +# foldToOtherRaisedStreet2, +# foldToOtherRaisedStreet3, +# foldToOtherRaisedStreet4, +# wonWhenSeenStreet1, +# wonAtSD, +# stealAttemptChance, +# stealAttempted, +# foldBbToStealChance, +# foldedBbToSteal, +# foldSbToStealChance, +# foldedSbToSteal, +# street1CBChance, +# street1CBDone, +# street2CBChance, +# street2CBDone, +# street3CBChance, +# street3CBDone, +# street4CBChance, +# street4CBDone, +# foldToStreet1CBChance, +# foldToStreet1CBDone, +# foldToStreet2CBChance, +# foldToStreet2CBDone, +# foldToStreet3CBChance, +# foldToStreet3CBDone, +# foldToStreet4CBChance, +# foldToStreet4CBDone, +# totalProfit, +# street1CheckCallRaiseChance, +# street1CheckCallRaiseDone, +# street2CheckCallRaiseChance, +# street2CheckCallRaiseDone, +# street3CheckCallRaiseChance, +# street3CheckCallRaiseDone, +# street4CheckCallRaiseChance, +# street4CheckCallRaiseDone) + + q = q.replace('%s', self.sql.query['placeholder']) + + self.cursor.execute(q, ( + gid, + pid + )) + +# gametypeId, +# playerId, +# activeSeats, +# position, +# tourneyTypeId, +# styleKey, +# HDs, +# street0VPI, +# street0Aggr, +# street0_3BChance, +# street0_3BDone, +# street1Seen, +# street2Seen, +# street3Seen, +# street4Seen, +# sawShowdown, +# street1Aggr, +# street2Aggr, +# street3Aggr, +# street4Aggr, +# otherRaisedStreet1, +# otherRaisedStreet2, +# otherRaisedStreet3, +# otherRaisedStreet4, +# foldToOtherRaisedStreet1, +# foldToOtherRaisedStreet2, +# foldToOtherRaisedStreet3, +# foldToOtherRaisedStreet4, +# wonWhenSeenStreet1, +# wonAtSD, +# stealAttemptChance, +# stealAttempted, +# foldBbToStealChance, +# foldedBbToSteal, +# foldSbToStealChance, +# foldedSbToSteal, +# street1CBChance, +# street1CBDone, +# street2CBChance, +# street2CBDone, +# street3CBChance, +# street3CBDone, +# street4CBChance, +# street4CBDone, +# foldToStreet1CBChance, +# foldToStreet1CBDone, +# foldToStreet2CBChance, +# foldToStreet2CBDone, +# foldToStreet3CBChance, +# foldToStreet3CBDone, +# foldToStreet4CBChance, +# foldToStreet4CBDone, +# totalProfit, +# street1CheckCallRaiseChance, +# street1CheckCallRaiseDone, +# street2CheckCallRaiseChance, +# street2CheckCallRaiseDone, +# street3CheckCallRaiseChance, +# street3CheckCallRaiseDone, +# street4CheckCallRaiseChance, +# street4CheckCallRaiseDone) ################################# diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 3de15ee5..106bd038 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -22,76 +22,6 @@ class DerivedStats(): def __init__(self, hand): self.hand = hand - self.activeSeats = 0 - self.position = 0 - self.tourneyTypeId = 0 - - self.HDs = 0 - self.street0VPI = 0 - self.street0Aggr = 0 - self.street0_3BChance = 0 - self.street0_3BDone = 0 - self.street0_4BChance = 0 - self.street0_4BDone = 0 - - self.street1Seen = 0 - self.street2Seen = 0 - self.street3Seen = 0 - self.street4Seen = 0 - self.sawShowdown = 0 - - self.street1Aggr = 0 - self.street2Aggr = 0 - self.street3Aggr = 0 - self.street4Aggr = 0 - - self.otherRaisedStreet1 = 0 - self.otherRaisedStreet2 = 0 - self.otherRaisedStreet3 = 0 - self.otherRaisedStreet4 = 0 - self.foldToOtherRaisedStreet1 = 0 - self.foldToOtherRaisedStreet2 = 0 - self.foldToOtherRaisedStreet3 = 0 - self.foldToOtherRaisedStreet4 = 0 - self.wonWhenSeenStreet1 = 0 - self.wonAtSD = 0 - - self.stealAttemptChance = 0 - self.stealAttempted = 0 - self.foldBbToStealChance = 0 - self.foldedBbToSteal = 0 - self.foldSbToStealChance = 0 - self.foldedSbToSteal = 0 - - self.street1CBChance = 0 - self.street1CBDone = 0 - self.street2CBChance = 0 - self.street2CBDone = 0 - self.street3CBChance = 0 - self.street3CBDone = 0 - self.street4CBChance = 0 - self.street4CBDone = 0 - - self.foldToStreet1CBChance = 0 - self.foldToStreet1CBDone = 0 - self.foldToStreet2CBChance = 0 - self.foldToStreet2CBDone = 0 - self.foldToStreet3CBChance = 0 - self.foldToStreet3CBDone = 0 - self.foldToStreet4CBChance = 0 - self.foldToStreet4CBDone = 0 - - self.totalProfit = 0 - - self.street1CheckCallRaiseChance = 0 - self.street1CheckCallRaiseDone = 0 - self.street2CheckCallRaiseChance = 0 - self.street2CheckCallRaiseDone = 0 - self.street3CheckCallRaiseChance = 0 - self.street3CheckCallRaiseDone = 0 - self.street4CheckCallRaiseChance = 0 - self.street4CheckCallRaiseDone = 0 - self.hands = {} self.handsplayers = {} @@ -99,6 +29,8 @@ class DerivedStats(): for player in hand.players: self.handsplayers[player[1]] = {} + #Init vars that may not be used, but still need to be inserted. + self.handsplayers[player[1]]['street4Aggr'] = False self.assembleHands(self.hand) self.assembleHandsPlayers(self.hand) @@ -106,6 +38,12 @@ class DerivedStats(): print "hands =", self.hands print "handsplayers =", self.handsplayers + def getHands(self): + return self.hands + + def getHandsPlayers(self): + return self.handsplayers + def assembleHands(self, hand): self.hands['tableName'] = hand.tablename self.hands['siteHandNo'] = hand.handid @@ -114,35 +52,796 @@ class DerivedStats(): self.hands['importTime'] = None self.hands['seats'] = self.countPlayers(hand) self.hands['maxSeats'] = hand.maxseats - self.hands['boardcard1'] = None - self.hands['boardcard2'] = None - self.hands['boardcard3'] = None - self.hands['boardcard4'] = None - self.hands['boardcard5'] = None + self.hands['texture'] = None # No calculation done for this yet. - boardCard = 1 - for street in hand.communityStreets: - for card in hand.board[street]: - self.hands['boardcard%s' % str(boardCard)] = Card.encodeCard(card) - boardCard += 1 + # This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and + # those values remain default in stud. + boardcards = hand.board['FLOP'] + hand.board['TURN'] + hand.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] + cards = [Card.encodeCard(c) for c in boardcards[0:5]] + self.hands['boardcard1'] = cards[0] + self.hands['boardcard2'] = cards[1] + self.hands['boardcard3'] = cards[2] + self.hands['boardcard4'] = cards[3] + self.hands['boardcard5'] = cards[4] + + #print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % hand.getStreetTotals() + #FIXME: Pot size still in decimal, needs to be converted to cents + (self.hands['street1Pot'], + self.hands['street2Pot'], + self.hands['street3Pot'], + self.hands['street4Pot'], + self.hands['showdownPot']) = hand.getStreetTotals() + + self.vpip(hand) # Gives playersVpi (num of players vpip) + #print "DEBUG: vpip: %s" %(self.hands['playersVpi']) + self.playersAtStreetX(hand) # Gives playersAtStreet1..4 and Showdown + #print "DEBUG: playersAtStreet 1:'%s' 2:'%s' 3:'%s' 4:'%s'" %(self.hands['playersAtStreet1'],self.hands['playersAtStreet2'],self.hands['playersAtStreet3'],self.hands['playersAtStreet4']) + self.streetXRaises(hand) # Empty function currently + + # comment TEXT, + # commentTs DATETIME def assembleHandsPlayers(self, hand): - self.vpip(self.hand) + #hand.players = [[seat, name, chips],[seat, name, chips]] + for player in hand.players: + self.handsplayers[player[1]]['seatNo'] = player[0] + self.handsplayers[player[1]]['startCash'] = player[2] + for i, street in enumerate(hand.actionStreets[1:]): self.aggr(self.hand, i) + + def assembleHudCache(self, hand): +# # def generateHudCacheData(player_ids, base, category, action_types, allIns, actionTypeByNo +# # ,winnings, totalWinnings, positions, actionTypes, actionAmounts, antes): +# #"""calculates data for the HUD during import. IMPORTANT: if you change this method make +# # sure to also change the following storage method and table_viewer.prepare_data if necessary +# #""" +# #print "generateHudCacheData, len(player_ids)=", len(player_ids) +# #setup subarrays of the result dictionary. +# street0VPI=[] +# street0Aggr=[] +# street0_3BChance=[] +# street0_3BDone=[] +# street1Seen=[] +# street2Seen=[] +# street3Seen=[] +# street4Seen=[] +# sawShowdown=[] +# street1Aggr=[] +# street2Aggr=[] +# street3Aggr=[] +# street4Aggr=[] +# otherRaisedStreet1=[] +# otherRaisedStreet2=[] +# otherRaisedStreet3=[] +# otherRaisedStreet4=[] +# foldToOtherRaisedStreet1=[] +# foldToOtherRaisedStreet2=[] +# foldToOtherRaisedStreet3=[] +# foldToOtherRaisedStreet4=[] +# wonWhenSeenStreet1=[] +# +# wonAtSD=[] +# stealAttemptChance=[] +# stealAttempted=[] +# hudDataPositions=[] +# +# street0Calls=[] +# street1Calls=[] +# street2Calls=[] +# street3Calls=[] +# street4Calls=[] +# street0Bets=[] +# street1Bets=[] +# street2Bets=[] +# street3Bets=[] +# street4Bets=[] +# #street0Raises=[] +# #street1Raises=[] +# #street2Raises=[] +# #street3Raises=[] +# #street4Raises=[] +# +# # Summary figures for hand table: +# result={} +# result['playersVpi']=0 +# result['playersAtStreet1']=0 +# result['playersAtStreet2']=0 +# result['playersAtStreet3']=0 +# result['playersAtStreet4']=0 +# result['playersAtShowdown']=0 +# result['street0Raises']=0 +# result['street1Raises']=0 +# result['street2Raises']=0 +# result['street3Raises']=0 +# result['street4Raises']=0 +# result['street1Pot']=0 +# result['street2Pot']=0 +# result['street3Pot']=0 +# result['street4Pot']=0 +# result['showdownPot']=0 +# +# firstPfRaiseByNo=-1 +# firstPfRaiserId=-1 +# firstPfRaiserNo=-1 +# firstPfCallByNo=-1 +# firstPfCallerId=-1 +# +# for i, action in enumerate(actionTypeByNo[0]): +# if action[1] == "bet": +# firstPfRaiseByNo = i +# firstPfRaiserId = action[0] +# for j, pid in enumerate(player_ids): +# if pid == firstPfRaiserId: +# firstPfRaiserNo = j +# break +# break +# for i, action in enumerate(actionTypeByNo[0]): +# if action[1] == "call": +# firstPfCallByNo = i +# firstPfCallerId = action[0] +# break +# firstPlayId = firstPfCallerId +# if firstPfRaiseByNo <> -1: +# if firstPfRaiseByNo < firstPfCallByNo or firstPfCallByNo == -1: +# firstPlayId = firstPfRaiserId +# +# +# cutoffId=-1 +# buttonId=-1 +# sbId=-1 +# bbId=-1 +# if base=="hold": +# for player, pos in enumerate(positions): +# if pos == 1: +# cutoffId = player_ids[player] +# if pos == 0: +# buttonId = player_ids[player] +# if pos == 'S': +# sbId = player_ids[player] +# if pos == 'B': +# bbId = player_ids[player] +# +# someoneStole=False +# +# #run a loop for each player preparing the actual values that will be commited to SQL +# for player in xrange(len(player_ids)): +# #set default values +# myStreet0VPI=False +# myStreet0Aggr=False +# myStreet0_3BChance=False +# myStreet0_3BDone=False +# myStreet1Seen=False +# myStreet2Seen=False +# myStreet3Seen=False +# myStreet4Seen=False +# mySawShowdown=False +# myStreet1Aggr=False +# myStreet2Aggr=False +# myStreet3Aggr=False +# myStreet4Aggr=False +# myOtherRaisedStreet1=False +# myOtherRaisedStreet2=False +# myOtherRaisedStreet3=False +# myOtherRaisedStreet4=False +# myFoldToOtherRaisedStreet1=False +# myFoldToOtherRaisedStreet2=False +# myFoldToOtherRaisedStreet3=False +# myFoldToOtherRaisedStreet4=False +# myWonWhenSeenStreet1=0.0 +# myWonAtSD=0.0 +# myStealAttemptChance=False +# myStealAttempted=False +# myStreet0Calls=0 +# myStreet1Calls=0 +# myStreet2Calls=0 +# myStreet3Calls=0 +# myStreet4Calls=0 +# myStreet0Bets=0 +# myStreet1Bets=0 +# myStreet2Bets=0 +# myStreet3Bets=0 +# myStreet4Bets=0 +# #myStreet0Raises=0 +# #myStreet1Raises=0 +# #myStreet2Raises=0 +# #myStreet3Raises=0 +# #myStreet4Raises=0 +# +# #calculate VPIP and PFR +# street=0 +# heroPfRaiseCount=0 +# for currentAction in action_types[street][player]: # finally individual actions +# if currentAction == "bet": +# myStreet0Aggr = True +# if currentAction == "bet" or currentAction == "call": +# myStreet0VPI = True +# +# if myStreet0VPI: +# result['playersVpi'] += 1 +# myStreet0Calls = action_types[street][player].count('call') +# myStreet0Bets = action_types[street][player].count('bet') +# # street0Raises = action_types[street][player].count('raise') bet count includes raises for now +# result['street0Raises'] += myStreet0Bets +# +# #PF3BChance and PF3B +# pfFold=-1 +# pfRaise=-1 +# if firstPfRaiseByNo != -1: +# for i, actionType in enumerate(actionTypeByNo[0]): +# if actionType[0] == player_ids[player]: +# if actionType[1] == "bet" and pfRaise == -1 and i > firstPfRaiseByNo: +# pfRaise = i +# if actionType[1] == "fold" and pfFold == -1: +# pfFold = i +# if pfFold == -1 or pfFold > firstPfRaiseByNo: +# myStreet0_3BChance = True +# if pfRaise > firstPfRaiseByNo: +# myStreet0_3BDone = True +# +# #steal calculations +# if base=="hold": +# if len(player_ids)>=3: # no point otherwise # was 5, use 3 to match pokertracker definition +# if positions[player]==1: +# if firstPfRaiserId==player_ids[player] \ +# and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo): +# myStealAttempted=True +# myStealAttemptChance=True +# if firstPlayId==cutoffId or firstPlayId==buttonId or firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1: +# myStealAttemptChance=True +# if positions[player]==0: +# if firstPfRaiserId==player_ids[player] \ +# and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo): +# myStealAttempted=True +# myStealAttemptChance=True +# if firstPlayId==buttonId or firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1: +# myStealAttemptChance=True +# if positions[player]=='S': +# if firstPfRaiserId==player_ids[player] \ +# and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo): +# myStealAttempted=True +# myStealAttemptChance=True +# if firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1: +# myStealAttemptChance=True +# if positions[player]=='B': +# pass +# +# if myStealAttempted: +# someoneStole=True +# +# +# #calculate saw* values +# isAllIn = False +# if any(i for i in allIns[0][player]): +# isAllIn = True +# if (len(action_types[1][player])>0 or isAllIn): +# myStreet1Seen = True +# +# if any(i for i in allIns[1][player]): +# isAllIn = True +# if (len(action_types[2][player])>0 or isAllIn): +# myStreet2Seen = True +# +# if any(i for i in allIns[2][player]): +# isAllIn = True +# if (len(action_types[3][player])>0 or isAllIn): +# myStreet3Seen = True +# +# #print "base:", base +# if base=="hold": +# mySawShowdown = True +# if any(actiontype == "fold" for actiontype in action_types[3][player]): +# mySawShowdown = False +# else: +# #print "in else" +# if any(i for i in allIns[3][player]): +# isAllIn = True +# if (len(action_types[4][player])>0 or isAllIn): +# #print "in if" +# myStreet4Seen = True +# +# mySawShowdown = True +# if any(actiontype == "fold" for actiontype in action_types[4][player]): +# mySawShowdown = False +# +# if myStreet1Seen: +# result['playersAtStreet1'] += 1 +# if myStreet2Seen: +# result['playersAtStreet2'] += 1 +# if myStreet3Seen: +# result['playersAtStreet3'] += 1 +# if myStreet4Seen: +# result['playersAtStreet4'] += 1 +# if mySawShowdown: +# result['playersAtShowdown'] += 1 +# +# #flop stuff +# street=1 +# if myStreet1Seen: +# if any(actiontype == "bet" for actiontype in action_types[street][player]): +# myStreet1Aggr = True +# +# myStreet1Calls = action_types[street][player].count('call') +# myStreet1Bets = action_types[street][player].count('bet') +# # street1Raises = action_types[street][player].count('raise') bet count includes raises for now +# result['street1Raises'] += myStreet1Bets +# +# for otherPlayer in xrange(len(player_ids)): +# if player==otherPlayer: +# pass +# else: +# for countOther in xrange(len(action_types[street][otherPlayer])): +# if action_types[street][otherPlayer][countOther]=="bet": +# myOtherRaisedStreet1=True +# for countOtherFold in xrange(len(action_types[street][player])): +# if action_types[street][player][countOtherFold]=="fold": +# myFoldToOtherRaisedStreet1=True +# +# #turn stuff - copy of flop with different vars +# street=2 +# if myStreet2Seen: +# if any(actiontype == "bet" for actiontype in action_types[street][player]): +# myStreet2Aggr = True +# +# myStreet2Calls = action_types[street][player].count('call') +# myStreet2Bets = action_types[street][player].count('bet') +# # street2Raises = action_types[street][player].count('raise') bet count includes raises for now +# result['street2Raises'] += myStreet2Bets +# +# for otherPlayer in xrange(len(player_ids)): +# if player==otherPlayer: +# pass +# else: +# for countOther in xrange(len(action_types[street][otherPlayer])): +# if action_types[street][otherPlayer][countOther]=="bet": +# myOtherRaisedStreet2=True +# for countOtherFold in xrange(len(action_types[street][player])): +# if action_types[street][player][countOtherFold]=="fold": +# myFoldToOtherRaisedStreet2=True +# +# #river stuff - copy of flop with different vars +# street=3 +# if myStreet3Seen: +# if any(actiontype == "bet" for actiontype in action_types[street][player]): +# myStreet3Aggr = True +# +# myStreet3Calls = action_types[street][player].count('call') +# myStreet3Bets = action_types[street][player].count('bet') +# # street3Raises = action_types[street][player].count('raise') bet count includes raises for now +# result['street3Raises'] += myStreet3Bets +# +# for otherPlayer in xrange(len(player_ids)): +# if player==otherPlayer: +# pass +# else: +# for countOther in xrange(len(action_types[street][otherPlayer])): +# if action_types[street][otherPlayer][countOther]=="bet": +# myOtherRaisedStreet3=True +# for countOtherFold in xrange(len(action_types[street][player])): +# if action_types[street][player][countOtherFold]=="fold": +# myFoldToOtherRaisedStreet3=True +# +# #stud river stuff - copy of flop with different vars +# street=4 +# if myStreet4Seen: +# if any(actiontype == "bet" for actiontype in action_types[street][player]): +# myStreet4Aggr=True +# +# myStreet4Calls = action_types[street][player].count('call') +# myStreet4Bets = action_types[street][player].count('bet') +# # street4Raises = action_types[street][player].count('raise') bet count includes raises for now +# result['street4Raises'] += myStreet4Bets +# +# for otherPlayer in xrange(len(player_ids)): +# if player==otherPlayer: +# pass +# else: +# for countOther in xrange(len(action_types[street][otherPlayer])): +# if action_types[street][otherPlayer][countOther]=="bet": +# myOtherRaisedStreet4=True +# for countOtherFold in xrange(len(action_types[street][player])): +# if action_types[street][player][countOtherFold]=="fold": +# myFoldToOtherRaisedStreet4=True +# +# if winnings[player] != 0: +# if myStreet1Seen: +# myWonWhenSeenStreet1 = winnings[player] / float(totalWinnings) +# if mySawShowdown: +# myWonAtSD=myWonWhenSeenStreet1 +# +# #add each value to the appropriate array +# street0VPI.append(myStreet0VPI) +# street0Aggr.append(myStreet0Aggr) +# street0_3BChance.append(myStreet0_3BChance) +# street0_3BDone.append(myStreet0_3BDone) +# street1Seen.append(myStreet1Seen) +# street2Seen.append(myStreet2Seen) +# street3Seen.append(myStreet3Seen) +# street4Seen.append(myStreet4Seen) +# sawShowdown.append(mySawShowdown) +# street1Aggr.append(myStreet1Aggr) +# street2Aggr.append(myStreet2Aggr) +# street3Aggr.append(myStreet3Aggr) +# street4Aggr.append(myStreet4Aggr) +# otherRaisedStreet1.append(myOtherRaisedStreet1) +# otherRaisedStreet2.append(myOtherRaisedStreet2) +# otherRaisedStreet3.append(myOtherRaisedStreet3) +# otherRaisedStreet4.append(myOtherRaisedStreet4) +# foldToOtherRaisedStreet1.append(myFoldToOtherRaisedStreet1) +# foldToOtherRaisedStreet2.append(myFoldToOtherRaisedStreet2) +# foldToOtherRaisedStreet3.append(myFoldToOtherRaisedStreet3) +# foldToOtherRaisedStreet4.append(myFoldToOtherRaisedStreet4) +# wonWhenSeenStreet1.append(myWonWhenSeenStreet1) +# wonAtSD.append(myWonAtSD) +# stealAttemptChance.append(myStealAttemptChance) +# stealAttempted.append(myStealAttempted) +# if base=="hold": +# pos=positions[player] +# if pos=='B': +# hudDataPositions.append('B') +# elif pos=='S': +# hudDataPositions.append('S') +# elif pos==0: +# hudDataPositions.append('D') +# elif pos==1: +# hudDataPositions.append('C') +# elif pos>=2 and pos<=4: +# hudDataPositions.append('M') +# elif pos>=5 and pos<=8: +# hudDataPositions.append('E') +# ### RHH Added this elif to handle being a dead hand before the BB (pos==9) +# elif pos==9: +# hudDataPositions.append('X') +# else: +# raise FpdbError("invalid position") +# elif base=="stud": +# #todo: stud positions and steals +# pass +# +# street0Calls.append(myStreet0Calls) +# street1Calls.append(myStreet1Calls) +# street2Calls.append(myStreet2Calls) +# street3Calls.append(myStreet3Calls) +# street4Calls.append(myStreet4Calls) +# street0Bets.append(myStreet0Bets) +# street1Bets.append(myStreet1Bets) +# street2Bets.append(myStreet2Bets) +# street3Bets.append(myStreet3Bets) +# street4Bets.append(myStreet4Bets) +# #street0Raises.append(myStreet0Raises) +# #street1Raises.append(myStreet1Raises) +# #street2Raises.append(myStreet2Raises) +# #street3Raises.append(myStreet3Raises) +# #street4Raises.append(myStreet4Raises) +# +# #add each array to the to-be-returned dictionary +# result['street0VPI']=street0VPI +# result['street0Aggr']=street0Aggr +# result['street0_3BChance']=street0_3BChance +# result['street0_3BDone']=street0_3BDone +# result['street1Seen']=street1Seen +# result['street2Seen']=street2Seen +# result['street3Seen']=street3Seen +# result['street4Seen']=street4Seen +# result['sawShowdown']=sawShowdown +# +# result['street1Aggr']=street1Aggr +# result['otherRaisedStreet1']=otherRaisedStreet1 +# result['foldToOtherRaisedStreet1']=foldToOtherRaisedStreet1 +# result['street2Aggr']=street2Aggr +# result['otherRaisedStreet2']=otherRaisedStreet2 +# result['foldToOtherRaisedStreet2']=foldToOtherRaisedStreet2 +# result['street3Aggr']=street3Aggr +# result['otherRaisedStreet3']=otherRaisedStreet3 +# result['foldToOtherRaisedStreet3']=foldToOtherRaisedStreet3 +# result['street4Aggr']=street4Aggr +# result['otherRaisedStreet4']=otherRaisedStreet4 +# result['foldToOtherRaisedStreet4']=foldToOtherRaisedStreet4 +# result['wonWhenSeenStreet1']=wonWhenSeenStreet1 +# result['wonAtSD']=wonAtSD +# result['stealAttemptChance']=stealAttemptChance +# result['stealAttempted']=stealAttempted +# result['street0Calls']=street0Calls +# result['street1Calls']=street1Calls +# result['street2Calls']=street2Calls +# result['street3Calls']=street3Calls +# result['street4Calls']=street4Calls +# result['street0Bets']=street0Bets +# result['street1Bets']=street1Bets +# result['street2Bets']=street2Bets +# result['street3Bets']=street3Bets +# result['street4Bets']=street4Bets +# #result['street0Raises']=street0Raises +# #result['street1Raises']=street1Raises +# #result['street2Raises']=street2Raises +# #result['street3Raises']=street3Raises +# #result['street4Raises']=street4Raises +# +# #now the various steal values +# foldBbToStealChance=[] +# foldedBbToSteal=[] +# foldSbToStealChance=[] +# foldedSbToSteal=[] +# for player in xrange(len(player_ids)): +# myFoldBbToStealChance=False +# myFoldedBbToSteal=False +# myFoldSbToStealChance=False +# myFoldedSbToSteal=False +# +# if base=="hold": +# if someoneStole and (positions[player]=='B' or positions[player]=='S') and firstPfRaiserId!=player_ids[player]: +# street=0 +# for count in xrange(len(action_types[street][player])):#individual actions +# if positions[player]=='B': +# myFoldBbToStealChance=True +# if action_types[street][player][count]=="fold": +# myFoldedBbToSteal=True +# if positions[player]=='S': +# myFoldSbToStealChance=True +# if action_types[street][player][count]=="fold": +# myFoldedSbToSteal=True +# +# +# foldBbToStealChance.append(myFoldBbToStealChance) +# foldedBbToSteal.append(myFoldedBbToSteal) +# foldSbToStealChance.append(myFoldSbToStealChance) +# foldedSbToSteal.append(myFoldedSbToSteal) +# result['foldBbToStealChance']=foldBbToStealChance +# result['foldedBbToSteal']=foldedBbToSteal +# result['foldSbToStealChance']=foldSbToStealChance +# result['foldedSbToSteal']=foldedSbToSteal +# +# #now CB +# street1CBChance=[] +# street1CBDone=[] +# didStreet1CB=[] +# for player in xrange(len(player_ids)): +# myStreet1CBChance=False +# myStreet1CBDone=False +# +# if street0VPI[player]: +# myStreet1CBChance=True +# if street1Aggr[player]: +# myStreet1CBDone=True +# didStreet1CB.append(player_ids[player]) +# +# street1CBChance.append(myStreet1CBChance) +# street1CBDone.append(myStreet1CBDone) +# result['street1CBChance']=street1CBChance +# result['street1CBDone']=street1CBDone +# +# #now 2B +# street2CBChance=[] +# street2CBDone=[] +# didStreet2CB=[] +# for player in xrange(len(player_ids)): +# myStreet2CBChance=False +# myStreet2CBDone=False +# +# if street1CBDone[player]: +# myStreet2CBChance=True +# if street2Aggr[player]: +# myStreet2CBDone=True +# didStreet2CB.append(player_ids[player]) +# +# street2CBChance.append(myStreet2CBChance) +# street2CBDone.append(myStreet2CBDone) +# result['street2CBChance']=street2CBChance +# result['street2CBDone']=street2CBDone +# +# #now 3B +# street3CBChance=[] +# street3CBDone=[] +# didStreet3CB=[] +# for player in xrange(len(player_ids)): +# myStreet3CBChance=False +# myStreet3CBDone=False +# +# if street2CBDone[player]: +# myStreet3CBChance=True +# if street3Aggr[player]: +# myStreet3CBDone=True +# didStreet3CB.append(player_ids[player]) +# +# street3CBChance.append(myStreet3CBChance) +# street3CBDone.append(myStreet3CBDone) +# result['street3CBChance']=street3CBChance +# result['street3CBDone']=street3CBDone +# +# #and 4B +# street4CBChance=[] +# street4CBDone=[] +# didStreet4CB=[] +# for player in xrange(len(player_ids)): +# myStreet4CBChance=False +# myStreet4CBDone=False +# +# if street3CBDone[player]: +# myStreet4CBChance=True +# if street4Aggr[player]: +# myStreet4CBDone=True +# didStreet4CB.append(player_ids[player]) +# +# street4CBChance.append(myStreet4CBChance) +# street4CBDone.append(myStreet4CBDone) +# result['street4CBChance']=street4CBChance +# result['street4CBDone']=street4CBDone +# +# +# result['position']=hudDataPositions +# +# foldToStreet1CBChance=[] +# foldToStreet1CBDone=[] +# foldToStreet2CBChance=[] +# foldToStreet2CBDone=[] +# foldToStreet3CBChance=[] +# foldToStreet3CBDone=[] +# foldToStreet4CBChance=[] +# foldToStreet4CBDone=[] +# +# for player in xrange(len(player_ids)): +# myFoldToStreet1CBChance=False +# myFoldToStreet1CBDone=False +# foldToStreet1CBChance.append(myFoldToStreet1CBChance) +# foldToStreet1CBDone.append(myFoldToStreet1CBDone) +# +# myFoldToStreet2CBChance=False +# myFoldToStreet2CBDone=False +# foldToStreet2CBChance.append(myFoldToStreet2CBChance) +# foldToStreet2CBDone.append(myFoldToStreet2CBDone) +# +# myFoldToStreet3CBChance=False +# myFoldToStreet3CBDone=False +# foldToStreet3CBChance.append(myFoldToStreet3CBChance) +# foldToStreet3CBDone.append(myFoldToStreet3CBDone) +# +# myFoldToStreet4CBChance=False +# myFoldToStreet4CBDone=False +# foldToStreet4CBChance.append(myFoldToStreet4CBChance) +# foldToStreet4CBDone.append(myFoldToStreet4CBDone) +# +# if len(didStreet1CB)>=1: +# generateFoldToCB(1, player_ids, didStreet1CB, street1CBDone, foldToStreet1CBChance, foldToStreet1CBDone, actionTypeByNo) +# +# if len(didStreet2CB)>=1: +# generateFoldToCB(2, player_ids, didStreet2CB, street2CBDone, foldToStreet2CBChance, foldToStreet2CBDone, actionTypeByNo) +# +# if len(didStreet3CB)>=1: +# generateFoldToCB(3, player_ids, didStreet3CB, street3CBDone, foldToStreet3CBChance, foldToStreet3CBDone, actionTypeByNo) +# +# if len(didStreet4CB)>=1: +# generateFoldToCB(4, player_ids, didStreet4CB, street4CBDone, foldToStreet4CBChance, foldToStreet4CBDone, actionTypeByNo) +# +# result['foldToStreet1CBChance']=foldToStreet1CBChance +# result['foldToStreet1CBDone']=foldToStreet1CBDone +# result['foldToStreet2CBChance']=foldToStreet2CBChance +# result['foldToStreet2CBDone']=foldToStreet2CBDone +# result['foldToStreet3CBChance']=foldToStreet3CBChance +# result['foldToStreet3CBDone']=foldToStreet3CBDone +# result['foldToStreet4CBChance']=foldToStreet4CBChance +# result['foldToStreet4CBDone']=foldToStreet4CBDone +# +# +# totalProfit=[] +# +# street1CheckCallRaiseChance=[] +# street1CheckCallRaiseDone=[] +# street2CheckCallRaiseChance=[] +# street2CheckCallRaiseDone=[] +# street3CheckCallRaiseChance=[] +# street3CheckCallRaiseDone=[] +# street4CheckCallRaiseChance=[] +# street4CheckCallRaiseDone=[] +# #print "b4 totprof calc, len(playerIds)=", len(player_ids) +# for pl in xrange(len(player_ids)): +# #print "pl=", pl +# myTotalProfit=winnings[pl] # still need to deduct other costs +# if antes: +# myTotalProfit=winnings[pl] - antes[pl] +# for i in xrange(len(actionTypes)): #iterate through streets +# #for j in xrange(len(actionTypes[i])): #iterate through names (using pl loop above) +# for k in xrange(len(actionTypes[i][pl])): #iterate through individual actions of that player on that street +# myTotalProfit -= actionAmounts[i][pl][k] +# +# myStreet1CheckCallRaiseChance=False +# myStreet1CheckCallRaiseDone=False +# myStreet2CheckCallRaiseChance=False +# myStreet2CheckCallRaiseDone=False +# myStreet3CheckCallRaiseChance=False +# myStreet3CheckCallRaiseDone=False +# myStreet4CheckCallRaiseChance=False +# myStreet4CheckCallRaiseDone=False +# +# #print "myTotalProfit=", myTotalProfit +# totalProfit.append(myTotalProfit) +# #print "totalProfit[]=", totalProfit +# +# street1CheckCallRaiseChance.append(myStreet1CheckCallRaiseChance) +# street1CheckCallRaiseDone.append(myStreet1CheckCallRaiseDone) +# street2CheckCallRaiseChance.append(myStreet2CheckCallRaiseChance) +# street2CheckCallRaiseDone.append(myStreet2CheckCallRaiseDone) +# street3CheckCallRaiseChance.append(myStreet3CheckCallRaiseChance) +# street3CheckCallRaiseDone.append(myStreet3CheckCallRaiseDone) +# street4CheckCallRaiseChance.append(myStreet4CheckCallRaiseChance) +# street4CheckCallRaiseDone.append(myStreet4CheckCallRaiseDone) +# +# result['totalProfit']=totalProfit +# #print "res[totalProfit]=", result['totalProfit'] +# +# result['street1CheckCallRaiseChance']=street1CheckCallRaiseChance +# result['street1CheckCallRaiseDone']=street1CheckCallRaiseDone +# result['street2CheckCallRaiseChance']=street2CheckCallRaiseChance +# result['street2CheckCallRaiseDone']=street2CheckCallRaiseDone +# result['street3CheckCallRaiseChance']=street3CheckCallRaiseChance +# result['street3CheckCallRaiseDone']=street3CheckCallRaiseDone +# result['street4CheckCallRaiseChance']=street4CheckCallRaiseChance +# result['street4CheckCallRaiseDone']=street4CheckCallRaiseDone +# return result +# #end def generateHudCacheData + pass + def vpip(self, hand): vpipers = set() for act in hand.actions[hand.actionStreets[1]]: if act[1] in ('calls','bets', 'raises'): vpipers.add(act[0]) + self.hands['playersVpi'] = len(vpipers) + for player in hand.players: if player[1] in vpipers: self.handsplayers[player[1]]['vpip'] = True else: self.handsplayers[player[1]]['vpip'] = False - self.hands['playersVpi'] = len(vpipers) + + def playersAtStreetX(self, hand): + """ playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4/draw1 */""" + # self.actions[street] is a list of all actions in a tuple, contining the player name first + # [ (player, action, ....), (player2, action, ...) ] + # The number of unique players in the list per street gives the value for playersAtStreetXXX + + # FIXME?? - This isn't couting people that are all in - at least showdown needs to reflect this + + self.hands['playersAtStreet1'] = 0 + self.hands['playersAtStreet2'] = 0 + self.hands['playersAtStreet3'] = 0 + self.hands['playersAtStreet4'] = 0 + self.hands['playersAtShowdown'] = 0 + + for street in hand.actionStreets: + actors = {} + for act in hand.actions[street]: + actors[act[0]] = 1 + #print "len(actors.keys(%s)): %s" % ( street, len(actors.keys())) + if hand.gametype['base'] in ("hold"): + if street in "FLOP": self.hands['playersAtStreet1'] = len(actors.keys()) + elif street in "TURN": self.hands['playersAtStreet2'] = len(actors.keys()) + elif street in "RIVER": self.hands['playersAtStreet3'] = len(actors.keys()) + elif hand.gametype['base'] in ("stud"): + if street in "FOURTH": self.hands['playersAtStreet1'] = len(actors.keys()) + elif street in "FIFTH": self.hands['playersAtStreet2'] = len(actors.keys()) + elif street in "SIXTH": self.hands['playersAtStreet3'] = len(actors.keys()) + elif street in "SEVENTH": self.hands['playersAtStreet4'] = len(actors.keys()) + elif hand.gametype['base'] in ("draw"): + if street in "DRAWONE": self.hands['playersAtStreet1'] = len(actors.keys()) + elif street in "DRAWTWO": self.hands['playersAtStreet2'] = len(actors.keys()) + elif street in "DRAWTHREE": self.hands['playersAtStreet3'] = len(actors.keys()) + + #Need playersAtShowdown + + + def streetXRaises(self, hand): + # self.actions[street] is a list of all actions in a tuple, contining the action as the second element + # [ (player, action, ....), (player2, action, ...) ] + # No idea what this value is actually supposed to be + # In theory its "num small bets paid to see flop/street4, including blind" which makes sense for limit. Not so useful for nl + # Leaving empty for the moment, + self.hands['street0Raises'] = 0 # /* num small bets paid to see flop/street4, including blind */ + self.hands['street1Raises'] = 0 # /* num small bets paid to see turn/street5 */ + self.hands['street2Raises'] = 0 # /* num big bets paid to see river/street6 */ + self.hands['street3Raises'] = 0 # /* num big bets paid to see sd/street7 */ + self.hands['street4Raises'] = 0 # /* num big bets paid to see showdown */ def aggr(self, hand, i): aggrers = set() @@ -157,4 +856,4 @@ class DerivedStats(): self.handsplayers[player[1]]['street%sAggr' % i] = False def countPlayers(self, hand): - pass \ No newline at end of file + pass diff --git a/pyfpdb/Exceptions.py b/pyfpdb/Exceptions.py index f3d75e89..eaf5d798 100644 --- a/pyfpdb/Exceptions.py +++ b/pyfpdb/Exceptions.py @@ -17,5 +17,8 @@ class FpdbParseError(FpdbError): class FpdbDatabaseError(FpdbError): pass +class FpdbMySQLFailedError(FpdbDatabaseError): + pass + class DuplicateError(FpdbError): pass diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py index 9ded56b4..08581c83 100644 --- a/pyfpdb/Filters.py +++ b/pyfpdb/Filters.py @@ -23,6 +23,7 @@ import os import sys from optparse import OptionParser from time import * +import gobject #import pokereval import Configuration @@ -31,19 +32,20 @@ import FpdbSQLQueries class Filters(threading.Thread): def __init__(self, db, config, qdict, display = {}, debug=True): - self.debug=debug + # config and qdict are now redundant + self.debug = debug #print "start of GraphViewer constructor" - self.db=db - self.cursor=db.cursor - self.sql=qdict - self.conf = config + self.db = db + self.cursor = db.cursor + self.sql = db.sql + self.conf = db.config self.display = display self.sites = {} self.games = {} self.limits = {} self.seats = {} - self.groups = {} + self.groups = {} self.siteid = {} self.heroes = {} self.boxes = {} @@ -53,6 +55,8 @@ class Filters(threading.Thread): ,'seatsbetween':'Between:', 'seatsand':'And:', 'seatsshow':'Show Number of _Players' ,'limitstitle':'Limits:', 'seatstitle':'Number of Players:' ,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:' + ,'groupsall':'All Players' + ,'limitsFL':'FL', 'limitsNL':'NL', 'ring':'Ring', 'tour':'Tourney' } # For use in date ranges. @@ -61,6 +65,10 @@ class Filters(threading.Thread): self.start_date.set_property('editable', False) self.end_date.set_property('editable', False) + # For use in groups etc + self.sbGroups = {} + self.numHands = 0 + # Outer Packing box self.mainVBox = gtk.VBox(False, 0) @@ -68,7 +76,7 @@ class Filters(threading.Thread): playerFrame.set_label_align(0.0, 0.0) vbox = gtk.VBox(False, 0) - self.fillPlayerFrame(vbox) + self.fillPlayerFrame(vbox, self.display) playerFrame.add(vbox) self.boxes['player'] = vbox @@ -97,6 +105,11 @@ class Filters(threading.Thread): self.cbLimits = {} self.cbNoLimits = None self.cbAllLimits = None + self.cbFL = None + self.cbNL = None + self.rb = {} # radio buttons for ring/tour + self.type = None # ring/tour + self.types = {} # list of all ring/tour values self.fillLimitsFrame(vbox, self.display) limitsFrame.add(vbox) @@ -114,7 +127,6 @@ class Filters(threading.Thread): groupsFrame = gtk.Frame() groupsFrame.show() vbox = gtk.VBox(False, 0) - self.sbGroups = {} self.fillGroupsFrame(vbox, self.display) groupsFrame.add(vbox) @@ -173,6 +185,9 @@ class Filters(threading.Thread): return self.mainVBox #end def get_vbox + def getNumHands(self): + return self.numHands + def getSites(self): return self.sites @@ -189,6 +204,9 @@ class Filters(threading.Thread): ltuple.append(l) return ltuple + def getType(self): + return(self.type) + def getSeats(self): if 'from' in self.sbSeats: self.seats['from'] = self.sbSeats['from'].get_value_as_int() @@ -228,7 +246,16 @@ class Filters(threading.Thread): pname.set_width_chars(20) hbox.pack_start(pname, False, True, 0) pname.connect("changed", self.__set_hero_name, site) - #TODO: Look at GtkCompletion - to fill out usernames + + # Added EntryCompletion but maybe comboBoxEntry is more flexible? (e.g. multiple choices) + completion = gtk.EntryCompletion() + pname.set_completion(completion) + liststore = gtk.ListStore(gobject.TYPE_STRING) + completion.set_model(liststore) + completion.set_text_column(0) + names = self.db.get_player_names(self.conf) # (config=self.conf, site_id=None, like_player_name="%") + for n in names: + liststore.append(n) self.__set_hero_name(pname, site) @@ -236,6 +263,13 @@ class Filters(threading.Thread): self.heroes[site] = w.get_text() # print "DEBUG: setting heroes[%s]: %s"%(site, self.heroes[site]) + def __set_num_hands(self, w, val): + try: + self.numHands = int(w.get_text()) + except: + self.numHands = 0 +# print "DEBUG: setting numHands:", self.numHands + def createSiteLine(self, hbox, site): cb = gtk.CheckButton(site) cb.connect('clicked', self.__set_site_select, site) @@ -269,21 +303,99 @@ class Filters(threading.Thread): #print w.get_active() self.limits[limit] = w.get_active() print "self.limit[%s] set to %s" %(limit, self.limits[limit]) - if str(limit).isdigit(): + if limit.isdigit() or (len(limit) > 2 and limit[-2:] == 'nl'): if self.limits[limit]: if self.cbNoLimits != None: self.cbNoLimits.set_active(False) else: if self.cbAllLimits != None: self.cbAllLimits.set_active(False) + if not self.limits[limit]: + if limit.isdigit(): + self.cbFL.set_active(False) + else: + self.cbNL.set_active(False) elif limit == "all": if self.limits[limit]: - for cb in self.cbLimits.values(): - cb.set_active(True) + #for cb in self.cbLimits.values(): + # cb.set_active(True) + if self.cbFL != None: + self.cbFL.set_active(True) + if self.cbNL != None: + self.cbNL.set_active(True) elif limit == "none": if self.limits[limit]: for cb in self.cbLimits.values(): cb.set_active(False) + self.cbNL.set_active(False) + self.cbFL.set_active(False) + elif limit == "fl": + if not self.limits[limit]: + # only toggle all fl limits off if they are all currently on + # this stops turning one off from cascading into 'fl' box off + # and then all fl limits being turned off + all_fl_on = True + for cb in self.cbLimits.values(): + t = cb.get_children()[0].get_text() + if t.isdigit(): + if not cb.get_active(): + all_fl_on = False + found = {'ring':False, 'tour':False} + for cb in self.cbLimits.values(): + #print "cb label: ", cb.children()[0].get_text() + t = cb.get_children()[0].get_text() + if t.isdigit(): + if self.limits[limit] or all_fl_on: + cb.set_active(self.limits[limit]) + found[self.types[t]] = True + if self.limits[limit]: + if not found[self.type]: + if self.type == 'ring': + if 'tour' in self.rb: + self.rb['tour'].set_active(True) + elif self.type == 'tour': + if 'ring' in self.rb: + self.rb['ring'].set_active(True) + elif limit == "nl": + if not self.limits[limit]: + # only toggle all nl limits off if they are all currently on + # this stops turning one off from cascading into 'nl' box off + # and then all nl limits being turned off + all_nl_on = True + for cb in self.cbLimits.values(): + t = cb.get_children()[0].get_text() + if "nl" in t and len(t) > 2: + if not cb.get_active(): + all_nl_on = False + found = {'ring':False, 'tour':False} + for cb in self.cbLimits.values(): + t = cb.get_children()[0].get_text() + if "nl" in t and len(t) > 2: + if self.limits[limit] or all_nl_on: + cb.set_active(self.limits[limit]) + found[self.types[t]] = True + if self.limits[limit]: + if not found[self.type]: + if self.type == 'ring': + self.rb['tour'].set_active(True) + elif self.type == 'tour': + self.rb['ring'].set_active(True) + elif limit == "ring": + print "set", limit, "to", self.limits[limit] + if self.limits[limit]: + self.type = "ring" + for cb in self.cbLimits.values(): + #print "cb label: ", cb.children()[0].get_text() + if self.types[cb.get_children()[0].get_text()] == 'tour': + cb.set_active(False) + elif limit == "tour": + print "set", limit, "to", self.limits[limit] + if self.limits[limit]: + self.type = "tour" + for cb in self.cbLimits.values(): + #print "cb label: ", cb.children()[0].get_text() + if self.types[cb.get_children()[0].get_text()] == 'ring': + cb.set_active(False) def __set_seat_select(self, w, seat): #print "__set_seat_select: seat =", seat, "active =", w.get_active() @@ -295,13 +407,32 @@ class Filters(threading.Thread): self.groups[group] = w.get_active() print "self.groups[%s] set to %s" %(group, self.groups[group]) - def fillPlayerFrame(self, vbox): + def fillPlayerFrame(self, vbox, display): for site in self.conf.get_supported_sites(): - pathHBox = gtk.HBox(False, 0) - vbox.pack_start(pathHBox, False, True, 0) + hBox = gtk.HBox(False, 0) + vbox.pack_start(hBox, False, True, 0) player = self.conf.supported_sites[site].screen_name - self.createPlayerLine(pathHBox, site, player) + self.createPlayerLine(hBox, site, player) + + if "GroupsAll" in display and display["GroupsAll"] == True: + hbox = gtk.HBox(False, 0) + vbox.pack_start(hbox, False, False, 0) + cb = gtk.CheckButton(self.filterText['groupsall']) + cb.connect('clicked', self.__set_group_select, 'allplayers') + hbox.pack_start(cb, False, False, 0) + self.sbGroups['allplayers'] = cb + self.groups['allplayers'] = False + + lbl = gtk.Label('Min # Hands:') + lbl.set_alignment(xalign=1.0, yalign=0.5) + hbox.pack_start(lbl, expand=True, padding=3) + + phands = gtk.Entry() + phands.set_text('0') + phands.set_width_chars(8) + hbox.pack_start(phands, False, False, 0) + phands.connect("changed", self.__set_num_hands, site) def fillSitesFrame(self, vbox): for site in self.conf.get_supported_sites(): @@ -328,22 +459,23 @@ class Filters(threading.Thread): print "INFO: No games returned from database" def fillLimitsFrame(self, vbox, display): - hbox = gtk.HBox(False, 0) - vbox.pack_start(hbox, False, False, 0) + top_hbox = gtk.HBox(False, 0) + vbox.pack_start(top_hbox, False, False, 0) lbl_title = gtk.Label(self.filterText['limitstitle']) lbl_title.set_alignment(xalign=0.0, yalign=0.5) - hbox.pack_start(lbl_title, expand=True, padding=3) + top_hbox.pack_start(lbl_title, expand=True, padding=3) showb = gtk.Button(label="hide", stock=None, use_underline=True) showb.set_alignment(xalign=1.0, yalign=0.5) showb.connect('clicked', self.__toggle_box, 'limits') - hbox.pack_start(showb, expand=False, padding=1) vbox1 = gtk.VBox(False, 0) vbox.pack_start(vbox1, False, False, 0) self.boxes['limits'] = vbox1 - self.cursor.execute(self.sql.query['getLimits']) + self.cursor.execute(self.sql.query['getLimits2']) + # selects limitType, bigBlind result = self.db.cursor.fetchall() + fl, nl = False, False if len(result) >= 1: hbox = gtk.HBox(True, 0) vbox1.pack_start(hbox, False, False, 0) @@ -351,26 +483,72 @@ class Filters(threading.Thread): hbox.pack_start(vbox2, False, False, 0) vbox3 = gtk.VBox(False, 0) hbox.pack_start(vbox3, False, False, 0) + found = {'nl':False, 'fl':False, 'ring':False, 'tour':False} for i, line in enumerate(result): + if "UseType" in self.display: + if line[0] != self.display["UseType"]: + continue hbox = gtk.HBox(False, 0) if i <= len(result)/2: vbox2.pack_start(hbox, False, False, 0) else: vbox3.pack_start(hbox, False, False, 0) - self.cbLimits[line[0]] = self.createLimitLine(hbox, line[0], line[0]) + if line[1] == 'fl': + name = str(line[2]) + found['fl'] = True + else: + name = str(line[2])+line[1] + found['nl'] = True + self.cbLimits[name] = self.createLimitLine(hbox, name, name) + self.types[name] = line[0] + found[line[0]] = True # type is ring/tour + self.type = line[0] # if only one type, set it now if "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2: + hbox = gtk.HBox(True, 0) + vbox1.pack_start(hbox, False, False, 0) + vbox2 = gtk.VBox(False, 0) + hbox.pack_start(vbox2, False, False, 0) + vbox3 = gtk.VBox(False, 0) + hbox.pack_start(vbox3, False, False, 0) + hbox = gtk.HBox(False, 0) - vbox1.pack_start(hbox, False, True, 0) + vbox2.pack_start(hbox, False, False, 0) self.cbAllLimits = self.createLimitLine(hbox, 'all', self.filterText['limitsall']) hbox = gtk.HBox(False, 0) - vbox1.pack_start(hbox, False, True, 0) + vbox2.pack_start(hbox, False, False, 0) self.cbNoLimits = self.createLimitLine(hbox, 'none', self.filterText['limitsnone']) - hbox = gtk.HBox(False, 0) - vbox1.pack_start(hbox, False, True, 0) - cb = self.createLimitLine(hbox, 'show', self.filterText['limitsshow']) + + dest = vbox3 # for ring/tour buttons + if "LimitType" in display and display["LimitType"] == True and found['nl'] and found['fl']: + #if found['fl']: + hbox = gtk.HBox(False, 0) + vbox3.pack_start(hbox, False, False, 0) + self.cbFL = self.createLimitLine(hbox, 'fl', self.filterText['limitsFL']) + #if found['nl']: + hbox = gtk.HBox(False, 0) + vbox3.pack_start(hbox, False, False, 0) + self.cbNL = self.createLimitLine(hbox, 'nl', self.filterText['limitsNL']) + dest = vbox2 # for ring/tour buttons else: print "INFO: No games returned from database" + if "Type" in display and display["Type"] == True and found['ring'] and found['tour']: + rb1 = gtk.RadioButton(None, self.filterText['ring']) + rb1.connect('clicked', self.__set_limit_select, 'ring') + rb2 = gtk.RadioButton(rb1, self.filterText['tour']) + rb2.connect('clicked', self.__set_limit_select, 'tour') + top_hbox.pack_start(rb1, False, False, 0) # (child, expand, fill, padding) + top_hbox.pack_start(rb2, True, True, 0) # child uses expand space if fill is true + + self.rb['ring'] = rb1 + self.rb['tour'] = rb2 + #print "about to set ring to true" + rb1.set_active(True) + # set_active doesn't seem to call this for some reason so call manually: + self.__set_limit_select(rb1, 'ring') + self.type = 'ring' + top_hbox.pack_start(showb, expand=False, padding=1) + def fillSeatsFrame(self, vbox, display): hbox = gtk.HBox(False, 0) vbox.pack_start(hbox, False, False, 0) @@ -401,15 +579,6 @@ class Filters(threading.Thread): hbox.pack_start(lbl_to, expand=False, padding=3) hbox.pack_start(sb2, False, False, 0) - if "SeatSep" in display and display["SeatSep"] == True: - hbox = gtk.HBox(False, 0) - vbox1.pack_start(hbox, False, True, 0) - cb = gtk.CheckButton(self.filterText['seatsshow']) - cb.connect('clicked', self.__set_seat_select, 'show') - hbox.pack_start(cb, False, False, 0) - self.sbSeats['show'] = cb - self.seats['show'] = False - self.sbSeats['from'] = sb1 self.sbSeats['to'] = sb2 @@ -429,14 +598,26 @@ class Filters(threading.Thread): self.boxes['groups'] = vbox1 hbox = gtk.HBox(False, 0) - vbox1.pack_start(hbox, False, True, 0) + vbox1.pack_start(hbox, False, False, 0) + cb = self.createLimitLine(hbox, 'show', self.filterText['limitsshow']) + hbox = gtk.HBox(False, 0) + vbox1.pack_start(hbox, False, True, 0) cb = gtk.CheckButton(self.filterText['posnshow']) cb.connect('clicked', self.__set_group_select, 'posn') hbox.pack_start(cb, False, False, 0) self.sbGroups['posn'] = cb self.groups['posn'] = False + if "SeatSep" in display and display["SeatSep"] == True: + hbox = gtk.HBox(False, 0) + vbox1.pack_start(hbox, False, True, 0) + cb = gtk.CheckButton(self.filterText['seatsshow']) + cb.connect('clicked', self.__set_seat_select, 'show') + hbox.pack_start(cb, False, False, 0) + self.sbSeats['show'] = cb + self.seats['show'] = False + def fillCardsFrame(self, vbox): hbox1 = gtk.HBox(True,0) hbox1.show() diff --git a/pyfpdb/GuiBulkImport.py b/pyfpdb/GuiBulkImport.py index 21f9e050..9cb54d50 100755 --- a/pyfpdb/GuiBulkImport.py +++ b/pyfpdb/GuiBulkImport.py @@ -40,21 +40,6 @@ class GuiBulkImport(): # CONFIGURATION - update these as preferred: allowThreads = True # set to True to try out the threads field - # not used - def import_dir(self): - """imports a directory, non-recursive. todo: move this to fpdb_import so CLI can use it""" - - self.path = self.inputFile - self.importer.addImportDirectory(self.path) - self.importer.setCallHud(False) - starttime = time() - if not self.importer.settings['threads'] > 1: - (stored, dups, partial, errs, ttime) = self.importer.runImport() - print 'GuiBulkImport.import_dir done: Stored: %d Duplicates: %d Partial: %d Errors: %d in %s seconds - %d/sec'\ - % (stored, dups, partial, errs, ttime, stored / ttime) - else: - self.importer.RunImportThreaded() - def dopulse(self): self.progressbar.pulse() return True @@ -77,7 +62,7 @@ class GuiBulkImport(): self.timer = gobject.timeout_add(100, self.dopulse) # get the dir to import from the chooser - self.inputFile = self.chooser.get_filename() + selected = self.chooser.get_filenames() # get the import settings from the gui and save in the importer self.importer.setHandCount(int(self.spin_hands.get_text())) @@ -103,7 +88,8 @@ class GuiBulkImport(): self.importer.setDropHudCache("auto") sitename = self.cbfilter.get_model()[self.cbfilter.get_active()][0] - self.importer.addBulkImportImportFileOrDir(self.inputFile, site = sitename) + for selection in selected: + self.importer.addBulkImportImportFileOrDir(selection, site = sitename) self.importer.setCallHud(False) starttime = time() # try: @@ -151,6 +137,7 @@ class GuiBulkImport(): self.chooser = gtk.FileChooserWidget() self.chooser.set_filename(self.settings['bulkImport-defaultPath']) + self.chooser.set_select_multiple(True) self.vbox.add(self.chooser) self.chooser.show() @@ -317,8 +304,20 @@ def main(argv=None): help="If this option is passed it quits when it encounters any error") parser.add_option("-m", "--minPrint", "--status", dest="minPrint", default="0", type="int", help="How often to print a one-line status report (0 (default) means never)") + parser.add_option("-u", "--usage", action="store_true", dest="usage", default=False, + help="Print some useful one liners") (options, sys.argv) = parser.parse_args(args = argv) + if options.usage == True: + #Print usage examples and exit + print "USAGE:" + print 'PokerStars converter: ./GuiBulkImport -c PokerStars -f filename' + print 'Full Tilt converter: ./GuiBulkImport -c "Full Tilt Poker" -f filename' + print "Everleaf converter: ./GuiBulkImport -c Everleaf -f filename" + print "Absolute converter: ./GuiBulkImport -c Absolute -f filename" + print "PartyPoker converter: ./GuiBulkImport -c PartyPoker -f filename" + sys.exit(0) + config = Configuration.Config() settings = {} @@ -350,8 +349,10 @@ def main(argv=None): importer.setThreads(-1) importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername) importer.setCallHud(False) - importer.runImport() + (stored, dups, partial, errs, ttime) = importer.runImport() importer.clearFileList() + print 'GuiBulkImport done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %.0f/sec'\ + % (stored, dups, partial, errs, ttime, (stored+0.0) / ttime) if __name__ == '__main__': diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index f5beadcf..f91c9870 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -53,20 +53,26 @@ class GuiGraphViewer (threading.Thread): self.db = Database.Database(self.conf, sql=self.sql) - filters_display = { "Heroes" : True, - "Sites" : True, - "Games" : True, - "Limits" : True, - "Seats" : False, - "Dates" : True, - "Button1" : True, - "Button2" : True + filters_display = { "Heroes" : True, + "Sites" : True, + "Games" : True, + "Limits" : True, + "LimitSep" : True, + "LimitType" : True, + "Type" : False, + "UseType" : 'ring', + "Seats" : False, + "SeatSep" : False, + "Dates" : True, + "Groups" : False, + "Button1" : True, + "Button2" : True } self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display) - self.filters.registerButton1Name("Refresh Graph") + self.filters.registerButton1Name("Refresh _Graph") self.filters.registerButton1Callback(self.generateGraph) - self.filters.registerButton2Name("Export to File") + self.filters.registerButton2Name("_Export to File") self.filters.registerButton2Callback(self.exportGraph) self.mainHBox = gtk.HBox(False, 0) @@ -146,10 +152,8 @@ class GuiGraphViewer (threading.Thread): raise def generateGraph(self, widget, data): - print "generateGraph: start" try: self.clearGraphData() - print "after cleardata" sitenos = [] playerids = [] @@ -158,15 +162,18 @@ class GuiGraphViewer (threading.Thread): heroes = self.filters.getHeroes() siteids = self.filters.getSiteIds() limits = self.filters.getLimits() - print "got filter data" + for i in ('show', 'none'): + if i in limits: + limits.remove(i) # Which sites are selected? for site in sites: if sites[site] == True: sitenos.append(siteids[site]) - self.db.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) - result = self.db.cursor.fetchall() + c = self.db.get_cursor() + c.execute(self.sql.query['getPlayerId'], (heroes[site],)) + result = c.fetchall() if len(result) == 1: - playerids.append(result[0][0]) + playerids.append( int(result[0][0]) ) if not sitenos: #Should probably pop up here. @@ -182,12 +189,10 @@ class GuiGraphViewer (threading.Thread): return #Set graph properties - print "add_subplot" self.ax = self.fig.add_subplot(111) #Get graph data from DB starttime = time() - print "get line: playerids =", playerids, "sitenos =", sitenos, "limits =", limits line = self.getRingProfitGraph(playerids, sitenos, limits) print "Graph generated in: %s" %(time() - starttime) @@ -234,12 +239,31 @@ class GuiGraphViewer (threading.Thread): # [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829) nametest = str(tuple(names)) sitetest = str(tuple(sites)) - limittest = str(tuple(limits)) - nametest = nametest.replace("L", "") - nametest = nametest.replace(",)",")") - sitetest = sitetest.replace(",)",")") - limittest = limittest.replace("L", "") - limittest = limittest.replace(",)",")") + #nametest = nametest.replace("L", "") + + lims = [int(x) for x in limits if x.isdigit()] + nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl'] + limittest = "and ( (gt.limitType = 'fl' and gt.bigBlind in " + # and ( (limit and bb in()) or (nolimit and bb in ()) ) + if lims: + blindtest = str(tuple(lims)) + blindtest = blindtest.replace("L", "") + blindtest = blindtest.replace(",)",")") + limittest = limittest + blindtest + ' ) ' + else: + limittest = limittest + '(-1) ) ' + limittest = limittest + " or (gt.limitType = 'nl' and gt.bigBlind in " + if nolims: + blindtest = str(tuple(nolims)) + blindtest = blindtest.replace("L", "") + blindtest = blindtest.replace(",)",")") + limittest = limittest + blindtest + ' ) )' + else: + limittest = limittest + '(-1) ) )' + if type == 'ring': + limittest = limittest + " and gt.type = 'ring' " + elif type == 'tour': + limittest = limittest + " and gt.type = 'tour' " #Must be a nicer way to deal with tuples of size 1 ie. (2,) - which makes sql barf tmp = tmp.replace("", nametest) @@ -247,6 +271,7 @@ class GuiGraphViewer (threading.Thread): tmp = tmp.replace("", start_date) tmp = tmp.replace("", end_date) tmp = tmp.replace("", limittest) + tmp = tmp.replace(",)", ")") #print "DEBUG: sql query:" #print tmp @@ -255,10 +280,10 @@ class GuiGraphViewer (threading.Thread): winnings = self.db.cursor.fetchall() self.db.rollback() - if(winnings == ()): + if winnings == (): return None - y=map(lambda x:float(x[3]), winnings) + y = map(lambda x:float(x[1]), winnings) line = cumsum(y) return line/100 #end of def getRingProfitGraph diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index add46bef..e51ff4a3 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -54,17 +54,20 @@ class GuiPlayerStats (threading.Thread): self.filterText = {'handhead':'Hand Breakdown for all levels listed above' } - filters_display = { "Heroes" : True, - "Sites" : True, - "Games" : False, - "Limits" : True, - "LimitSep" : True, - "Seats" : True, - "SeatSep" : True, - "Dates" : True, - "Groups" : True, - "Button1" : True, - "Button2" : True + filters_display = { "Heroes" : True, + "Sites" : True, + "Games" : False, + "Limits" : True, + "LimitSep" : True, + "LimitType" : True, + "Type" : True, + "Seats" : True, + "SeatSep" : True, + "Dates" : True, + "Groups" : True, + "GroupsAll" : True, + "Button1" : True, + "Button2" : True } self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display) @@ -80,6 +83,7 @@ class GuiPlayerStats (threading.Thread): self.columns = [ ["game", True, "Game", 0.0, "%s"] , ["hand", False, "Hand", 0.0, "%s"] # true not allowed for this line , ["plposition", False, "Posn", 1.0, "%s"] # true not allowed for this line (set in code) + , ["pname", False, "Name", 0.0, "%s"] # true not allowed for this line (set in code) , ["n", True, "Hds", 1.0, "%d"] , ["avgseats", False, "Seats", 1.0, "%3.1f"] , ["vpip", True, "VPIP", 1.0, "%3.1f"] @@ -123,8 +127,9 @@ class GuiPlayerStats (threading.Thread): self.stats_vbox = None self.detailFilters = [] # the data used to enhance the sql select - self.main_hbox = gtk.HBox(False, 0) - self.main_hbox.show() + #self.main_hbox = gtk.HBox(False, 0) + #self.main_hbox.show() + self.main_hbox = gtk.HPaned() self.stats_frame = gtk.Frame() self.stats_frame.show() @@ -134,8 +139,11 @@ class GuiPlayerStats (threading.Thread): self.stats_frame.add(self.stats_vbox) # self.fillStatsFrame(self.stats_vbox) - self.main_hbox.pack_start(self.filters.get_vbox()) - self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True) + #self.main_hbox.pack_start(self.filters.get_vbox()) + #self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True) + self.main_hbox.pack1(self.filters.get_vbox()) + self.main_hbox.pack2(self.stats_frame) + self.main_hbox.show() # make sure Hand column is not displayed [x for x in self.columns if x[0] == 'hand'][0][1] = False @@ -147,7 +155,8 @@ class GuiPlayerStats (threading.Thread): def refreshStats(self, widget, data): try: self.stats_vbox.destroy() except AttributeError: pass - self.stats_vbox = gtk.VBox(False, 0) + #self.stats_vbox = gtk.VBox(False, 0) + self.stats_vbox = gtk.VPaned() self.stats_vbox.show() self.stats_frame.add(self.stats_vbox) self.fillStatsFrame(self.stats_vbox) @@ -157,6 +166,7 @@ class GuiPlayerStats (threading.Thread): heroes = self.filters.getHeroes() siteids = self.filters.getSiteIds() limits = self.filters.getLimits() + type = self.filters.getType() seats = self.filters.getSeats() groups = self.filters.getGroups() dates = self.filters.getDates() @@ -185,45 +195,47 @@ class GuiPlayerStats (threading.Thread): print "No limits found" return - self.createStatsTable(vbox, playerids, sitenos, limits, seats, groups, dates) + self.createStatsTable(vbox, playerids, sitenos, limits, type, seats, groups, dates) - def createStatsTable(self, vbox, playerids, sitenos, limits, seats, groups, dates): + def createStatsTable(self, vbox, playerids, sitenos, limits, type, seats, groups, dates): starttime = time() + # Scrolled window for summary table + swin = gtk.ScrolledWindow(hadjustment=None, vadjustment=None) + swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + swin.show() + vbox.pack1(swin) + # Display summary table at top of page # 3rd parameter passes extra flags, currently includes: # holecards - whether to display card breakdown (True/False) - flags = [False] - self.addTable(vbox, 'playerDetailedStats', flags, playerids, sitenos, limits, seats, groups, dates) + # numhands - min number hands required when displaying all players + flags = [False, self.filters.getNumHands()] + self.addTable(swin, 'playerDetailedStats', flags, playerids, sitenos, limits, type, seats, groups, dates) # Separator - sep = gtk.HSeparator() - vbox.pack_start(sep, expand=False, padding=3) - sep.show_now() - vbox.show_now() + vbox2 = gtk.VBox(False, 0) heading = gtk.Label(self.filterText['handhead']) heading.show() - vbox.pack_start(heading, expand=False, padding=3) + vbox2.pack_start(heading, expand=False, padding=3) # Scrolled window for detailed table (display by hand) swin = gtk.ScrolledWindow(hadjustment=None, vadjustment=None) swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) swin.show() - vbox.pack_start(swin, expand=True, padding=3) - - vbox1 = gtk.VBox(False, 0) - vbox1.show() - swin.add_with_viewport(vbox1) + vbox2.pack_start(swin, expand=True, padding=3) + vbox.pack2(vbox2) + vbox2.show() # Detailed table - flags = [True] - self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats, groups, dates) + flags[0] = True + self.addTable(swin, 'playerDetailedStats', flags, playerids, sitenos, limits, type, seats, groups, dates) self.db.rollback() print "Stats page displayed in %4.2f seconds" % (time() - starttime) #end def fillStatsFrame(self, vbox): - def addTable(self, vbox, query, flags, playerids, sitenos, limits, seats, groups, dates): + def addTable(self, vbox, query, flags, playerids, sitenos, limits, type, seats, groups, dates): row = 0 sqlrow = 0 colalias,colshow,colheading,colxalign,colformat = 0,1,2,3,4 @@ -231,7 +243,7 @@ class GuiPlayerStats (threading.Thread): else: holecards = flags[0] tmp = self.sql.query[query] - tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, seats, groups, dates) + tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, type, seats, groups, dates) self.cursor.execute(tmp) result = self.cursor.fetchall() colnames = [desc[0].lower() for desc in self.cursor.description] @@ -243,7 +255,8 @@ class GuiPlayerStats (threading.Thread): liststore = gtk.ListStore(*([str] * len(cols_to_show))) view = gtk.TreeView(model=liststore) view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH) - vbox.pack_start(view, expand=False, padding=3) + #vbox.pack_start(view, expand=False, padding=3) + vbox.add(view) textcell = gtk.CellRendererText() textcell50 = gtk.CellRendererText() textcell50.set_property('xalign', 0.5) @@ -317,19 +330,45 @@ class GuiPlayerStats (threading.Thread): row += 1 vbox.show_all() - #end def addTable(self, query, vars, playerids, sitenos, limits, seats): + #end def addTable(self, query, vars, playerids, sitenos, limits, type, seats, groups, dates): - def refineQuery(self, query, flags, playerids, sitenos, limits, seats, groups, dates): - if not flags: holecards = False - else: holecards = flags[0] - - if playerids: - nametest = str(tuple(playerids)) - nametest = nametest.replace("L", "") - nametest = nametest.replace(",)",")") - query = query.replace("", nametest) + def refineQuery(self, query, flags, playerids, sitenos, limits, type, seats, groups, dates): + having = '' + if not flags: + holecards = False + numhands = 0 else: - query = query.replace("", "1 = 2") + holecards = flags[0] + numhands = flags[1] + + if 'allplayers' in groups and groups['allplayers']: + nametest = "(hp.playerId)" + if holecards or groups['posn']: + pname = "'all players'" + # set flag in self.columns to not show player name column + [x for x in self.columns if x[0] == 'pname'][0][1] = False + # can't do this yet (re-write doing more maths in python instead of sql?) + if numhands: + nametest = "(-1)" + else: + pname = "p.name" + # set flag in self.columns to show player name column + [x for x in self.columns if x[0] == 'pname'][0][1] = True + if numhands: + having = ' and count(1) > %d ' % (numhands,) + else: + if playerids: + nametest = str(tuple(playerids)) + nametest = nametest.replace("L", "") + nametest = nametest.replace(",)",")") + else: + nametest = "1 = 2" + pname = "p.name" + # set flag in self.columns to not show player name column + [x for x in self.columns if x[0] == 'pname'][0][1] = False + query = query.replace("", nametest) + query = query.replace("", pname) + query = query.replace("", having) if seats: query = query.replace('', 'between ' + str(seats['from']) + ' and ' + str(seats['to'])) @@ -344,17 +383,37 @@ class GuiPlayerStats (threading.Thread): query = query.replace('', '') query = query.replace('', '') - if [x for x in limits if str(x).isdigit()]: - blindtest = str(tuple([x for x in limits if str(x).isdigit()])) + lims = [int(x) for x in limits if x.isdigit()] + nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl'] + bbtest = "and ( (gt.limitType = 'fl' and gt.bigBlind in " + # and ( (limit and bb in()) or (nolimit and bb in ()) ) + if lims: + blindtest = str(tuple(lims)) blindtest = blindtest.replace("L", "") blindtest = blindtest.replace(",)",")") - query = query.replace("", " and gt.bigBlind in " + blindtest + " ") + bbtest = bbtest + blindtest + ' ) ' else: - query = query.replace("", "") + bbtest = bbtest + '(-1) ) ' + bbtest = bbtest + " or (gt.limitType = 'nl' and gt.bigBlind in " + if nolims: + blindtest = str(tuple(nolims)) + blindtest = blindtest.replace("L", "") + blindtest = blindtest.replace(",)",")") + bbtest = bbtest + blindtest + ' ) )' + else: + bbtest = bbtest + '(-1) ) )' + if type == 'ring': + bbtest = bbtest + " and gt.type = 'ring' " + elif type == 'tour': + bbtest = bbtest + " and gt.type = 'tour' " + query = query.replace("", bbtest) - if holecards: # pinch level variables for hole card query + if holecards: # re-use level variables for hole card query query = query.replace("", "hp.startcards") - query = query.replace("", ",hgameTypeId desc") + query = query.replace("" + , ",case when floor(hp.startcards/13) >= mod(hp.startcards,13) then hp.startcards + 0.1 " + + " else 13*mod(hp.startcards,13) + floor(hp.startcards/13) " + + " end desc ") else: query = query.replace("", "") groupLevels = "show" not in str(limits) diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index adc8141c..34a8f16d 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -4,359 +4,496 @@ - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + bgcolor="#000000" + fgcolor="#FFFFFF" + hudopacity="1.0" + font="Sans" + font_size="8" + supported_games="holdem,razz,omahahi,omahahilo,studhi,studhilo"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + bgcolor="#000000" + fgcolor="#FFFFFF" + hudopacity="1.0" + font="Sans" + font_size="8" + supported_games="holdem,razz,omahahi,omahahilo,studhi,studhilo"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + supported_games="holdem"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + supported_games="holdem"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + supported_games="holdem"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + supported_games="holdem"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - + - + @@ -376,50 +513,50 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -429,6 +566,7 @@ + diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 23c1ef03..77d8312d 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -59,9 +59,11 @@ import Hud # HUD params: # - Set aggregate_ring and/or aggregate_tour to True is you want to include stats from other blind levels in the HUD display -# - If aggregation is used, the value of agg_bb_mult determines how what levels are included, e.g. +# - If aggregation is used, the value of agg_bb_mult determines what levels are included. If +# agg_bb_mult is M and current blind level is L, blinds between L/M and L*M are included. e.g. # if agg_bb_mult is 100, almost all levels are included in all HUD displays -# if agg_bb_mult is 2.1, levels from half to double the current blind level are included in the HUD +# if agg_bb_mult is 2, levels from half to double the current blind level are included in the HUD +# if agg_bb_mult is 1 only the current level is included # - Set hud_style to A to see stats for all-time # Set hud_style to S to only see stats for current session (currently this shows stats for the last 24 hours) # Set hud_style to T to only see stats for the last N days (uses value in hud_days) @@ -71,14 +73,14 @@ def_hud_params = { # Settings for all players apart from program owner ('hero') , 'aggregate_tour' : True , 'hud_style' : 'A' , 'hud_days' : 90 - , 'agg_bb_mult' : 1 # 1 means no aggregation + , 'agg_bb_mult' : 10000 # 1 means no aggregation # , 'hud_session_gap' : 30 not currently used # Second set of variables for hero - these settings only apply to the program owner , 'h_aggregate_ring' : False , 'h_aggregate_tour' : True , 'h_hud_style' : 'S' # A(ll) / S(ession) / T(ime in days) - , 'h_hud_days' : 30 - , 'h_agg_bb_mult' : 1 # 1 means no aggregation + , 'h_hud_days' : 60 + , 'h_agg_bb_mult' : 10000 # 1 means no aggregation # , 'h_hud_session_gap' : 30 not currently used } @@ -91,7 +93,7 @@ class HUD_main(object): self.db_name = db_name self.config = Configuration.Config(file=options.config, dbname=options.dbname) self.hud_dict = {} - self.hud_params = def_hud_params + self.hud_params = self.config.get_hud_ui_parameters() # a thread to read stdin gobject.threads_init() # this is required diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index bd905036..602a6a1a 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -194,67 +194,36 @@ dealt whether they were seen in a 'dealt to' line """ Function to insert Hand into database Should not commit, and do minimal selects. Callers may want to cache commits db: a connected fpdb_db object""" - # TODO: + + ##### + # Players, Gametypes, TourneyTypes are all shared functions that are needed for additional tables + # These functions are intended for prep insert eventually + ##### # Players - base playerid and siteid tuple sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId) #Gametypes gtid = db.getGameTypeId(self.siteId, self.gametype) - # HudCache data to come from DerivedStats class + self.stats.getStats(self) + + ##### + # End prep functions + ##### + # HandsActions - all actions for all players for all streets - self.actions + # HudCache data can be generated from HandsActions (HandsPlayers?) + # Hands - Summary information of hand indexed by handId - gameinfo - #This should be moved to prepInsert - hh = {} - hh['siteHandNo'] = self.handid - hh['handStart'] = self.starttime + hh = self.stats.getHands() hh['gameTypeId'] = gtid # seats TINYINT NOT NULL, - hh['tableName'] = self.tablename - hh['maxSeats'] = self.maxseats hh['seats'] = len(sqlids) - # Flop turn and river may all be empty - add (likely) too many elements and trim with range - boardcards = self.board['FLOP'] + self.board['TURN'] + self.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] - cards = [Card.encodeCard(c) for c in boardcards[0:5]] - hh['boardcard1'] = cards[0] - hh['boardcard2'] = cards[1] - hh['boardcard3'] = cards[2] - hh['boardcard4'] = cards[3] - hh['boardcard5'] = cards[4] - # texture smallint, - # playersVpi SMALLINT NOT NULL, /* num of players vpi */ - # Needs to be recorded - # playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */ - # Needs to be recorded - # playersAtStreet2 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtStreet3 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtStreet4 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtShowdown SMALLINT NOT NULL, - # Needs to be recorded - # street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */ - # Needs to be recorded - # street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */ - # Needs to be recorded - # street2Raises TINYINT NOT NULL, /* num big bets paid to see river/street6 */ - # Needs to be recorded - # street3Raises TINYINT NOT NULL, /* num big bets paid to see sd/street7 */ - # Needs to be recorded - # street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */ - # Needs to be recorded - - #print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % self.getStreetTotals() - #FIXME: Pot size still in decimal, needs to be converted to cents - (hh['street1Pot'], hh['street2Pot'], hh['street3Pot'], hh['street4Pot'], hh['showdownPot']) = self.getStreetTotals() - - # comment TEXT, - # commentTs DATETIME #print hh handid = db.storeHand(hh) # HandsPlayers - ? ... Do we fix winnings? + db.storeHandsPlayers(handid, sqlids, self.stats.getHandsPlayers()) # Tourneys ? # TourneysPlayers @@ -603,7 +572,11 @@ Map the tuple self.gametype onto the pokerstars string describing it return gs + timestr def writeTableLine(self): - table_string = "Table \'%s\' %s-max" % (self.tablename, self.maxseats) + table_string = "Table " + if self.gametype['type'] == 'tour': + table_string = table_string + "\'%s %s\' %s-max" % (self.tourNo, self.tablename, self.maxseats) + else: + table_string = table_string + "\'%s\' %s-max" % (self.tablename, self.maxseats) if self.gametype['currency'] == 'play': table_string = table_string + " (Play Money)" if self.buttonpos != None and self.buttonpos != 0: diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 2c83ccd0..38402f8f 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -82,6 +82,7 @@ class Hud: (font, font_size) = config.get_default_font(self.table.site) self.colors = config.get_default_colors(self.table.site) + self.hud_ui = config.get_hud_ui_parameters() self.backgroundcolor = gtk.gdk.color_parse(self.colors['hudbgcolor']) self.foregroundcolor = gtk.gdk.color_parse(self.colors['hudfgcolor']) @@ -116,7 +117,7 @@ class Hud: win.set_opacity(self.colors["hudopacity"]) eventbox = gtk.EventBox() - label = gtk.Label("FPDB Menu - Right click\nLeft-Drag to Move") + label = gtk.Label(self.hud_ui['label']) win.add(eventbox) eventbox.add(label) @@ -146,14 +147,65 @@ class Hud: menu.append(repositem) repositem.connect("activate", self.reposition_windows) - aggitem = gtk.MenuItem('Show Stats') + aggitem = gtk.MenuItem('Show Player Stats') menu.append(aggitem) self.aggMenu = gtk.Menu() aggitem.set_submenu(self.aggMenu) # set agg_bb_mult to 1 to stop aggregation item = gtk.CheckMenuItem('For This Blind Level Only') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 1) + item.connect("activate", self.set_aggregation, ('P',1)) + setattr(self, 'h_aggBBmultItem1', item) + # + item = gtk.MenuItem('For Multiple Blind Levels:') + self.aggMenu.append(item) + # + item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('P',2)) + setattr(self, 'h_aggBBmultItem2', item) + # + item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('P',3)) + setattr(self, 'h_aggBBmultItem3', item) + # + item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('P',10)) + setattr(self, 'h_aggBBmultItem10', item) + # + item = gtk.CheckMenuItem(' All Levels') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('P',10000)) + setattr(self, 'h_aggBBmultItem10000', item) + # + item = gtk.MenuItem('Since:') + self.aggMenu.append(item) + # + item = gtk.CheckMenuItem(' All Time') + self.aggMenu.append(item) + item.connect("activate", self.set_hud_style, ('P','A')) + setattr(self, 'h_hudStyleOptionA', item) + # + item = gtk.CheckMenuItem(' Session') + self.aggMenu.append(item) + item.connect("activate", self.set_hud_style, ('P','S')) + setattr(self, 'h_hudStyleOptionS', item) + # + item = gtk.CheckMenuItem(' %s Days' % (self.hud_params['h_hud_days'])) + self.aggMenu.append(item) + item.connect("activate", self.set_hud_style, ('P','T')) + setattr(self, 'h_hudStyleOptionT', item) + + aggitem = gtk.MenuItem('Show Opponent Stats') + menu.append(aggitem) + self.aggMenu = gtk.Menu() + aggitem.set_submenu(self.aggMenu) + # set agg_bb_mult to 1 to stop aggregation + item = gtk.CheckMenuItem('For This Blind Level Only') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('O',1)) setattr(self, 'aggBBmultItem1', item) # item = gtk.MenuItem('For Multiple Blind Levels:') @@ -161,44 +213,54 @@ class Hud: # item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 2) + item.connect("activate", self.set_aggregation, ('O',2)) setattr(self, 'aggBBmultItem2', item) # item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 3) + item.connect("activate", self.set_aggregation, ('O',3)) setattr(self, 'aggBBmultItem3', item) # item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 10) + item.connect("activate", self.set_aggregation, ('O',10)) setattr(self, 'aggBBmultItem10', item) # item = gtk.CheckMenuItem(' All Levels') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 10000) + item.connect("activate", self.set_aggregation, ('O',10000)) setattr(self, 'aggBBmultItem10000', item) # - item = gtk.MenuItem('For Hero:') + item = gtk.MenuItem('Since:') self.aggMenu.append(item) - setattr(self, 'showStatsMenuItem7', item) # item = gtk.CheckMenuItem(' All Time') self.aggMenu.append(item) - item.connect("activate", self.set_hud_style, 'HA') - setattr(self, 'HAStyleOption', item) + item.connect("activate", self.set_hud_style, ('O','A')) + setattr(self, 'hudStyleOptionA', item) # item = gtk.CheckMenuItem(' Session') self.aggMenu.append(item) - item.connect("activate", self.set_hud_style, 'HS') - setattr(self, 'HSStyleOption', item) + item.connect("activate", self.set_hud_style, ('O','S')) + setattr(self, 'hudStyleOptionS', item) # item = gtk.CheckMenuItem(' %s Days' % (self.hud_params['h_hud_days'])) self.aggMenu.append(item) - item.connect("activate", self.set_hud_style, 'HT') - setattr(self, 'HTStyleOption', item) + item.connect("activate", self.set_hud_style, ('O','T')) + setattr(self, 'hudStyleOptionT', item) # set active on current options: + if self.hud_params['h_agg_bb_mult'] == 1: + getattr(self, 'h_aggBBmultItem1').set_active(True) + elif self.hud_params['h_agg_bb_mult'] == 2: + getattr(self, 'h_aggBBmultItem2').set_active(True) + elif self.hud_params['h_agg_bb_mult'] == 3: + getattr(self, 'h_aggBBmultItem3').set_active(True) + elif self.hud_params['h_agg_bb_mult'] == 10: + getattr(self, 'h_aggBBmultItem10').set_active(True) + elif self.hud_params['h_agg_bb_mult'] > 9000: + getattr(self, 'h_aggBBmultItem10000').set_active(True) + # if self.hud_params['agg_bb_mult'] == 1: getattr(self, 'aggBBmultItem1').set_active(True) elif self.hud_params['agg_bb_mult'] == 2: @@ -208,13 +270,21 @@ class Hud: elif self.hud_params['agg_bb_mult'] == 10: getattr(self, 'aggBBmultItem10').set_active(True) elif self.hud_params['agg_bb_mult'] > 9000: - getattr(self, 'aggBBmultItemAll').set_active(True) + getattr(self, 'aggBBmultItem10000').set_active(True) + # if self.hud_params['h_hud_style'] == 'A': - getattr(self, 'HAStyleOption').set_active(True) + getattr(self, 'h_hudStyleOptionA').set_active(True) elif self.hud_params['h_hud_style'] == 'S': - getattr(self, 'HSStyleOption').set_active(True) + getattr(self, 'h_hudStyleOptionS').set_active(True) elif self.hud_params['h_hud_style'] == 'T': - getattr(self, 'HTStyleOption').set_active(True) + getattr(self, 'h_hudStyleOptionT').set_active(True) + # + if self.hud_params['hud_style'] == 'A': + getattr(self, 'hudStyleOptionA').set_active(True) + elif self.hud_params['hud_style'] == 'S': + getattr(self, 'hudStyleOptionS').set_active(True) + elif self.hud_params['hud_style'] == 'T': + getattr(self, 'hudStyleOptionT').set_active(True) eventbox.connect_object("button-press-event", self.on_button_press, menu) @@ -254,41 +324,53 @@ class Hud: pass def set_aggregation(self, widget, val): - # try setting these to true all the time, and set the multiplier to 1 to turn agg off: - self.hud_params['aggregate_ring'] = True - self.hud_params['aggregate_tour'] = True - self.hud_params['h_aggregate_ring'] = True - self.hud_params['h_aggregate_tour'] = True + (player_opp, num) = val + if player_opp == 'P': + # set these true all the time, set the multiplier to 1 to turn agg off: + self.hud_params['h_aggregate_ring'] = True + self.hud_params['h_aggregate_tour'] = True - if self.hud_params['agg_bb_mult'] != val \ - and getattr(self, 'aggBBmultItem'+str(val)).get_active(): - print 'set_aggregation', val - self.hud_params['agg_bb_mult'] = val - self.hud_params['h_agg_bb_mult'] = val - for mult in ('1', '2', '3', '10', '10000'): - if mult != str(val): - getattr(self, 'aggBBmultItem'+mult).set_active(False) + if self.hud_params['h_agg_bb_mult'] != num \ + and getattr(self, 'h_aggBBmultItem'+str(num)).get_active(): + print 'set_player_aggregation', num + self.hud_params['h_agg_bb_mult'] = num + for mult in ('1', '2', '3', '10', '10000'): + if mult != str(num): + getattr(self, 'h_aggBBmultItem'+mult).set_active(False) + else: + self.hud_params['aggregate_ring'] = True + self.hud_params['aggregate_tour'] = True + + if self.hud_params['agg_bb_mult'] != num \ + and getattr(self, 'aggBBmultItem'+str(num)).get_active(): + print 'set_opponent_aggregation', num + self.hud_params['agg_bb_mult'] = num + for mult in ('1', '2', '3', '10', '10000'): + if mult != str(num): + getattr(self, 'aggBBmultItem'+mult).set_active(False) def set_hud_style(self, widget, val): - # try setting these to true all the time, and set the multiplier to 1 to turn agg off: - if val[0] == 'H': + (player_opp, style) = val + if player_opp == 'P': param = 'h_hud_style' + prefix = 'h_' else: param = 'hud_style' + prefix = '' - if val[1] == 'A' and getattr(self, 'HAStyleOption').get_active(): + if style == 'A' and getattr(self, prefix+'hudStyleOptionA').get_active(): self.hud_params[param] = 'A' - getattr(self, 'HSStyleOption').set_active(False) - getattr(self, 'HTStyleOption').set_active(False) - elif val[1] == 'S' and getattr(self, 'HSStyleOption').get_active(): + getattr(self, prefix+'hudStyleOptionS').set_active(False) + getattr(self, prefix+'hudStyleOptionT').set_active(False) + elif style == 'S' and getattr(self, prefix+'hudStyleOptionS').get_active(): self.hud_params[param] = 'S' - getattr(self, 'HAStyleOption').set_active(False) - getattr(self, 'HTStyleOption').set_active(False) - elif val[1] == 'T' and self.HTStyleOption.get_active(): + getattr(self, prefix+'hudStyleOptionA').set_active(False) + getattr(self, prefix+'hudStyleOptionT').set_active(False) + elif style == 'T' and getattr(self, prefix+'hudStyleOptionT').get_active(): self.hud_params[param] = 'T' - getattr(self, 'HAStyleOption').set_active(False) - getattr(self, 'HSStyleOption').set_active(False) - print "setting self.hud_params[%s] = %s" % (param, val[1]) + getattr(self, prefix+'hudStyleOptionA').set_active(False) + getattr(self, prefix+'hudStyleOptionS').set_active(False) + print "setting self.hud_params[%s] = %s" % (param, style) def update_table_position(self): if os.name == 'nt': diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 0c551634..251a56fa 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1235,6 +1235,13 @@ class Sql: and Players.siteId = Sites.id """ + self.query['get_player_names'] = """ + select p.name + from Players p + where lower(p.name) like lower(%s) + and (p.siteId = %s or %s = -1) + """ + self.query['getSiteId'] = """SELECT id from Sites where name = %s""" self.query['get_stats_from_hand'] = """ @@ -1713,10 +1720,14 @@ class Sql: self.query['getSiteId'] = """SELECT id from Sites where name = %s""" self.query['getGames'] = """SELECT DISTINCT category from Gametypes""" self.query['getLimits'] = """SELECT DISTINCT bigBlind from Gametypes ORDER by bigBlind DESC""" + self.query['getLimits2'] = """SELECT DISTINCT type, limitType, bigBlind + from Gametypes + ORDER by type, limitType DESC, bigBlind DESC""" if db_server == 'mysql': self.query['playerDetailedStats'] = """ select AS hgametypeid + , AS pname ,gt.base ,gt.category ,upper(gt.limitType) AS limittype @@ -1767,21 +1778,23 @@ class Sql: inner join Hands h on (h.id = hp.handId) inner join Gametypes gt on (gt.Id = h.gameTypeId) inner join Sites s on (s.Id = gt.siteId) + inner join Players p on (p.Id = hp.playerId) where hp.playerId in - and hp.tourneysPlayersId IS NULL + /*and hp.tourneysPlayersId IS NULL*/ and h.seats and date_format(h.handStart, '%Y-%m-%d') group by hgameTypeId - ,hp.playerId + ,pname ,gt.base ,gt.category ,plposition ,upper(gt.limitType) ,s.name - order by hp.playerId + having 1 = 1 + order by pname ,gt.base ,gt.category @@ -1790,11 +1803,95 @@ class Sql: else concat('Z', ) end + ,upper(gt.limitType) desc ,maxbigblind desc - ,upper(gt.limitType) ,s.name """ - else: # assume postgresql + elif db_server == 'postgresql': + self.query['playerDetailedStats'] = """ + select AS hgametypeid + , AS pname + ,gt.base + ,gt.category + ,upper(gt.limitType) AS limittype + ,s.name + ,min(gt.bigBlind) AS minbigblind + ,max(gt.bigBlind) AS maxbigblind + /*, AS gtid*/ + , AS plposition + ,count(1) AS n + ,100.0*sum(cast(hp.street0VPI as integer))/count(1) AS vpip + ,100.0*sum(cast(hp.street0Aggr as integer))/count(1) AS pfr + ,case when sum(cast(hp.street0_3Bchance as integer)) = 0 then -999 + else 100.0*sum(cast(hp.street0_3Bdone as integer))/sum(cast(hp.street0_3Bchance as integer)) + end AS pf3 + ,case when sum(cast(hp.stealattemptchance as integer)) = 0 then -999 + else 100.0*sum(cast(hp.stealattempted as integer))/sum(cast(hp.stealattemptchance as integer)) + end AS steals + ,100.0*sum(cast(hp.street1Seen as integer))/count(1) AS saw_f + ,100.0*sum(cast(hp.sawShowdown as integer))/count(1) AS sawsd + ,case when sum(cast(hp.street1Seen as integer)) = 0 then -999 + else 100.0*sum(cast(hp.sawShowdown as integer))/sum(cast(hp.street1Seen as integer)) + end AS wtsdwsf + ,case when sum(cast(hp.sawShowdown as integer)) = 0 then -999 + else 100.0*sum(cast(hp.wonAtSD as integer))/sum(cast(hp.sawShowdown as integer)) + end AS wmsd + ,case when sum(cast(hp.street1Seen as integer)) = 0 then -999 + else 100.0*sum(cast(hp.street1Aggr as integer))/sum(cast(hp.street1Seen as integer)) + end AS flafq + ,case when sum(cast(hp.street2Seen as integer)) = 0 then -999 + else 100.0*sum(cast(hp.street2Aggr as integer))/sum(cast(hp.street2Seen as integer)) + end AS tuafq + ,case when sum(cast(hp.street3Seen as integer)) = 0 then -999 + else 100.0*sum(cast(hp.street3Aggr as integer))/sum(cast(hp.street3Seen as integer)) + end AS rvafq + ,case when sum(cast(hp.street1Seen as integer))+sum(cast(hp.street2Seen as integer))+sum(cast(hp.street3Seen as integer)) = 0 then -999 + else 100.0*(sum(cast(hp.street1Aggr as integer))+sum(cast(hp.street2Aggr as integer))+sum(cast(hp.street3Aggr as integer))) + /(sum(cast(hp.street1Seen as integer))+sum(cast(hp.street2Seen as integer))+sum(cast(hp.street3Seen as integer))) + end AS pofafq + ,sum(hp.totalProfit)/100.0 AS net + ,sum(hp.rake)/100.0 AS rake + ,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100 + ,avg(hp.totalProfit)/100.0 AS profitperhand + ,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr + ,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr + ,avg(h.seats+0.0) AS avgseats + ,variance(hp.totalProfit/100.0) AS variance + from HandsPlayers hp + inner join Hands h on (h.id = hp.handId) + inner join Gametypes gt on (gt.Id = h.gameTypeId) + inner join Sites s on (s.Id = gt.siteId) + inner join Players p on (p.Id = hp.playerId) + where hp.playerId in + /*and hp.tourneysPlayersId IS NULL*/ + and h.seats + + + and to_char(h.handStart, 'YYYY-MM-DD') + group by hgameTypeId + ,pname + ,gt.base + ,gt.category + + ,plposition + ,upper(gt.limitType) + ,s.name + having 1 = 1 + order by pname + ,gt.base + ,gt.category + + ,case when 'B' then 'B' + when 'S' then 'S' + when '0' then 'Y' + else 'Z'|| + end + + ,upper(gt.limitType) desc + ,maxbigblind desc + ,s.name + """ + elif db_server == 'sqlite': self.query['playerDetailedStats'] = """ select AS hgametypeid ,gt.base @@ -1848,7 +1945,7 @@ class Sql: inner join Gametypes gt on (gt.Id = h.gameTypeId) inner join Sites s on (s.Id = gt.siteId) where hp.playerId in - and hp.tourneysPlayersId IS NULL + /*and hp.tourneysPlayersId IS NULL*/ and h.seats @@ -1871,12 +1968,10 @@ class Sql: else 'Z'|| end + ,upper(gt.limitType) desc ,maxbigblind desc - ,upper(gt.limitType) ,s.name """ - #elif db_server == 'sqlite': - # self.query['playerDetailedStats'] = """ """ if db_server == 'mysql': self.query['playerStats'] = """ @@ -2366,16 +2461,16 @@ class Sql: # self.query['playerStatsByPosition'] = """ """ self.query['getRingProfitAllHandsPlayerIdSite'] = """ - SELECT hp.handId, hp.totalProfit, hp.totalProfit, hp.totalProfit + SELECT hp.handId, hp.totalProfit FROM HandsPlayers hp - INNER JOIN Players pl ON (hp.playerId = pl.id) - INNER JOIN Hands h ON (h.id = hp.handId) - INNER JOIN Gametypes g ON (h.gametypeId = g.id) - where pl.id in + INNER JOIN Players pl ON (pl.id = hp.playerId) + INNER JOIN Hands h ON (h.id = hp.handId) + INNER JOIN Gametypes gt ON (gt.id = h.gametypeId) + WHERE pl.id in AND pl.siteId in AND h.handStart > '' AND h.handStart < '' - AND g.bigBlind in + AND hp.tourneysPlayersId IS NULL GROUP BY h.handStart, hp.handId, hp.totalProfit ORDER BY h.handStart""" @@ -3021,6 +3116,44 @@ class Sql: self.query['handsPlayersTTypeId_joiner'] = " OR TourneysPlayersId+0=" self.query['handsPlayersTTypeId_joiner_id'] = " OR id=" + self.query['store_hand'] = """INSERT INTO Hands ( + tablename, + gametypeid, + sitehandno, + handstart, + importtime, + seats, + maxseats, + texture, + playersVpi, + boardcard1, + boardcard2, + boardcard3, + boardcard4, + boardcard5, + playersAtStreet1, + playersAtStreet2, + playersAtStreet3, + playersAtStreet4, + playersAtShowdown, + street0Raises, + street1Raises, + street2Raises, + street3Raises, + street4Raises, + street1Pot, + street2Pot, + street3Pot, + street4Pot, + 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)""" + + + if db_server == 'mysql': diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py index d9efff6a..e725d5b8 100755 --- a/pyfpdb/Tables.py +++ b/pyfpdb/Tables.py @@ -257,6 +257,10 @@ def discover_nt_tournament(c, tour_number, tab_number): titles ={} win32gui.EnumWindows(win_enum_handler, titles) for hwnd in titles: + if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows + if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window + if 'HUD:' in titles[hwnd]: continue # FPDB HUD window + if re.search(search_string, titles[hwnd]): return decode_windows(c, titles[hwnd], hwnd) return None diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 4703d96d..18bc65d9 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -44,6 +44,7 @@ else: print "Python " + sys.version[0:3] + '...\n' +import traceback import threading import Options import string @@ -64,7 +65,6 @@ import gtk import interlocks -import fpdb_simple import GuiBulkImport import GuiPlayerStats import GuiPositionalStats @@ -234,13 +234,13 @@ class fpdb: dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables") diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database " \ - +self.db.fdb.database+" on "+self.db.fdb.host+" they will be deleted." + +self.db.database+" on "+self.db.host+" they will be deleted." dia_confirm.format_secondary_text(diastring)#todo: make above string with bold for db, host and deleted response = dia_confirm.run() dia_confirm.destroy() if response == gtk.RESPONSE_YES: - #if self.db.fdb.backend == self.fdb_lock.fdb.MYSQL_INNODB: + #if self.db.backend == self.fdb_lock.fdb.MYSQL_INNODB: # mysql requires locks on all tables or none - easier to release this lock # than lock all the other tables # ToDo: lock all other tables so that lock doesn't have to be released @@ -453,9 +453,25 @@ class fpdb: self.db.disconnect() self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) - self.db = Database.Database(self.config, sql = self.sql) + try: + self.db = Database.Database(self.config, sql = self.sql) + except FpdbMySQLFailedError: + self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR") + exit() + except FpdbError: + #print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) + self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR") + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) + sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) + except: + #print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) + self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR") + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) + sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) - if self.db.fdb.wrongDbVersion: + if self.db.wrongDbVersion: diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) label = gtk.Label("An invalid DB version or missing tables have been detected.") @@ -474,14 +490,14 @@ class fpdb: diaDbVersionWarning.destroy() if self.status_bar == None: - self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host)) + self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.database, self.db.host)) self.main_vbox.pack_end(self.status_bar, False, True, 0) self.status_bar.show() else: - self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host)) + self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.database, self.db.host)) # Database connected to successfully, load queries to pass on to other classes - self.db.connection.rollback() + self.db.rollback() self.validate_config() diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 428aa173..986c747f 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -80,7 +80,7 @@ class fpdb_db: try: self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) except: - raise FpdbError("MySQL connection failed") + raise FpdbMySQLFailedError("MySQL connection failed") elif backend==fpdb_db.PGSQL: import psycopg2 import psycopg2.extensions @@ -111,7 +111,7 @@ class fpdb_db: password = password, database = database) except: - msg = "PostgreSQL connection to database (%s) user (%s) failed." % (database, user) + msg = "PostgreSQL connection to database (%s) user (%s) failed. Are you sure the DB is running?" % (database, user) print msg raise FpdbError(msg) elif backend == fpdb_db.SQLITE: