diff --git a/pyfpdb/Card.py b/pyfpdb/Card.py new file mode 100755 index 00000000..75c742f9 --- /dev/null +++ b/pyfpdb/Card.py @@ -0,0 +1,83 @@ +#!/usr/bin/python + +#Copyright 2008 Carl Gherardi +#This program is free software: you can redistribute it and/or modify +#it under the terms of the GNU Affero General Public License as published by +#the Free Software Foundation, version 3 of the License. +# +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +# +#You should have received a copy of the GNU Affero General Public License +#along with this program. If not, see . +#In the "official" distribution you can find the license in +#agpl-3.0.txt in the docs folder of the package. + + + + +def twoStartCards(value1, suit1, value2, suit2): + """ Function to convert 2 value,suit pairs into a Holdem style starting hand e.g. AQo + Hand is stored as an int 13 * x + y where (x+2) represents rank of 1st card and + (y+2) represents rank of second card (2=2 .. 14=Ace) + If x > y then pair is suited, if x < y then unsuited""" + if value1 < 2 or value2 < 2: + return(0) + if (suit1 == suit2 and value1 < value2) or (suit1 != suit2 and value2 > value1): + return(13 * (value2-2) + (value1-1)) + else: + return(13 * (value1-2) + (value2-1)) + +def twoStartCardString(card): + """ Function to convert an int representing 2 holdem hole cards (as created by twoStartCards) + into a string like AQo """ + if card <= 0: + return 'xx' + else: + card -= 1 + s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A') + x = card/13 + y = card - 13*x + if x == y: return(s[x] + s[y]) + elif x > y: return(s[x] + s[y] + 's') + else: return(s[y] + s[x] + 'o') + +def fourStartCards(value1, suit1, value2, suit2, value3, suit3, value4, suit4): + """ Function to convert 4 value,suit pairs into a Omaha style starting hand, + haven't decided how to encode this yet """ + # This doesn't actually do anything yet - CG + + # What combinations do we need to store? just cards: AA23? some suits as well e.g. when + # double suited ATcKTd? Lots more possible combos than holdem :-( 270K vs 1326? not sure + # Probably need to use this field as a key into some other table - sc + + #AAKKds + #AAKKs + #AAKKr + # Is probably what we are looking for + return(0) + +def cardFromValueSuit(value, suit): + """ 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As """ + if suit == 'h': return(value-1) + elif suit == 'd': return(value+12) + elif suit == 'c': return(value+25) + elif suit == 's': return(value+38) + else: return(0) + +def valueSuitFromCard(card): + """ Function to convert a card stored in the database (int 0-52) into value + and suit like 9s, 4c etc """ + if card < 0 or card > 52: + return('') + else: + return( ['', '2h', '3h', '4h', '5h', '6h', '7h', '8h', '9h', 'Th', 'Jh', 'Qh', 'Kh', 'Ah' + , '2d', '3d', '4d', '5d', '6d', '7d', '8d', '9d', 'Td', 'Jd', 'Qd', 'Kd', 'Ad' + , '2c', '3c', '4c', '5c', '6c', '7c', '8c', '9c', 'Tc', 'Jc', 'Qc', 'Kc', 'Ac' + , '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', 'Ts', 'Js', 'Qs', 'Ks', 'As' + ][card] ) + + + diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 47617023..06d4f5d8 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -197,6 +197,15 @@ class Aux_window: temp = temp + "%s" % self.layout[layout] return temp +class HHC: + def __init__(self, node): + self.site = node.getAttribute("site") + self.converter = node.getAttribute("converter") + + def __str__(self): + return "%s:\t%s" % (self.site, self.converter) + + class Popup: def __init__(self, node): self.name = node.getAttribute("pu_name") @@ -277,6 +286,7 @@ class Config: self.supported_games = {} self.supported_databases = {} self.aux_windows = {} + self.hhcs = {} self.popup_windows = {} # s_sites = doc.getElementsByTagName("supported_sites") @@ -299,6 +309,11 @@ class Config: aw = Aux_window(node = aw_node) self.aux_windows[aw.name] = aw +# s_dbs = doc.getElementsByTagName("mucked_windows") + for hhc_node in doc.getElementsByTagName("hhc"): + hhc = HHC(node = hhc_node) + self.hhcs[hhc.site] = hhc + # s_dbs = doc.getElementsByTagName("popup_windows") for pu_node in doc.getElementsByTagName("pu"): pu = Popup(node = pu_node) @@ -703,6 +718,11 @@ if __name__== "__main__": for w in c.aux_windows.keys(): print c.aux_windows[w] print "----------- END AUX WINDOW FORMATS -----------" + + print "\n----------- HAND HISTORY CONVERTERS -----------" + for w in c.hhcs.keys(): + print c.hhcs[w] + print "----------- END HAND HISTORY CONVERTERS -----------" print "\n----------- POPUP WINDOW FORMATS -----------" for w in c.popup_windows.keys(): diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 3fba5c5e..ca4e5996 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -26,12 +26,14 @@ Create and manage the database objects. # Standard Library modules import sys import traceback +from datetime import datetime, date, time, timedelta # pyGTK modules # FreePokerTools modules import Configuration import SQL +import Card class Database: def __init__(self, c, db_name, game): @@ -76,9 +78,40 @@ class Database: print "press enter to continue" sys.exit() + self.db_server = c.supported_databases[db_name].db_server self.type = c.supported_databases[db_name].db_type - self.sql = SQL.Sql(game = game, type = self.type) + self.sql = SQL.Sql(game = game, type = self.type, db_server = self.db_server) + self.connection.rollback() + # To add to config: + self.hud_style = 'T' # A=All-time + # S=Session + # T=timed (last n days) + # Future values may also include: + # H=Hands (last n hands) + self.hud_hands = 1000 # Max number of hands from each player to use for hud stats + self.hud_days = 90 # Max number of days from each player to use for hud stats + self.hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of session + # (hands every 2 mins for 1 hour = one session, if followed + # by a 40 minute gap and then more hands on same table that is + # a new session) + cur = self.connection.cursor() + + self.hand_1day_ago = 0 + cur.execute(self.sql.query['get_hand_1day_ago']) + row = cur.fetchone() + if row and row[0]: + self.hand_1day_ago = row[0] + #print "hand 1day ago =", self.hand_1day_ago + + d = timedelta(days=self.hud_days) + now = datetime.utcnow() - d + self.date_ndays_ago = "d%02d%02d%02d" % (now.year-2000, now.month, now.day) + + self.hand_nhands_ago = 0 # todo + #cur.execute(self.sql.query['get_table_name'], (hand_id, )) + #row = cur.fetchone() + def close_connection(self): self.connection.close() @@ -120,20 +153,26 @@ class Database: """Get and return the cards for each player in the hand.""" cards = {} # dict of cards, the key is the seat number example: {1: 'AcQd9hTs5d'} c = self.connection.cursor() - c.execute(self.sql.query['get_cards'], hand) + c.execute(self.sql.query['get_cards'], [hand]) colnames = [desc[0] for desc in c.description] + cardnames = ['card1', 'card2', 'card3', 'card4', 'card5', 'card6', 'card7'] for row in c.fetchall(): - s_dict = {} - for name, val in zip(colnames, row): - s_dict[name] = val - cards[s_dict['seat_number']] = (self.convert_cards(s_dict)) + cs = ['', '', '', '', '', '', ''] + seat = -1 + for col,name in enumerate(colnames): + if name in cardnames: + cs[cardnames.index(name)] = Card.valueSuitFromCard(row[col]) + elif name == 'seat_number': + seat = row[col] + if seat != -1: + cards[seat] = ''.join(cs) return cards def get_common_cards(self, hand): """Get and return the community cards for the specified hand.""" cards = {} c = self.connection.cursor() - c.execute(self.sql.query['get_common_cards'], hand) + c.execute(self.sql.query['get_common_cards'], [hand]) colnames = [desc[0] for desc in c.description] for row in c.fetchall(): s_dict = {} @@ -184,24 +223,79 @@ class Database: return winners def get_stats_from_hand(self, hand, aggregate = False): + if self.hud_style == 'S': + return( self.get_stats_from_hand_session(hand) ) + else: # self.hud_style == A + if aggregate: + query = 'get_stats_from_hand_aggregated' + else: + query = 'get_stats_from_hand' + + if self.hud_style == 'T': + stylekey = self.date_ndays_ago + else: # assume A (all-time) + stylekey = '0000000' # all stylekey values should be higher than this + + subs = (hand, hand, stylekey) + #print "get stats: hud style =", self.hud_style, "subs =", subs c = self.connection.cursor() - if aggregate: - query = 'get_stats_from_hand_aggregated' - subs = (hand, hand, hand) - else: - query = 'get_stats_from_hand' - subs = (hand, hand) - -# now get the stats +# now get the stats c.execute(self.sql.query[query], subs) colnames = [desc[0] for desc in c.description] stat_dict = {} for row in c.fetchall(): t_dict = {} for name, val in zip(colnames, row): - t_dict[name] = val + t_dict[name.lower()] = val +# print t_dict stat_dict[t_dict['player_id']] = t_dict + + return stat_dict + + # uses query on handsplayers instead of hudcache to get stats on just this session + def get_stats_from_hand_session(self, hand): + + if self.hud_style == 'S': + query = self.sql.query['get_stats_from_hand_session'] + if self.db_server == 'mysql': + query = query.replace("", 'signed ') + else: + query = query.replace("", '') + else: # self.hud_style == A + return None + + subs = (self.hand_1day_ago, hand) + c = self.connection.cursor() + + # now get the stats + #print "sess_stats: subs =", subs, "subs[0] =", subs[0] + c.execute(query, subs) + colnames = [desc[0] for desc in c.description] + n,stat_dict = 0,{} + row = c.fetchone() + while row: + if colnames[0].lower() == 'player_id': + playerid = row[0] + else: + print "ERROR: query %s result does not have player_id as first column" % (query,) + break + + for name, val in zip(colnames, row): + if not playerid in stat_dict: + stat_dict[playerid] = {} + stat_dict[playerid][name.lower()] = val + elif not name.lower() in stat_dict[playerid]: + stat_dict[playerid][name.lower()] = val + elif name.lower() not in ('hand_id', 'player_id', 'seat', 'screen_name', 'seats'): + stat_dict[playerid][name.lower()] += val + n += 1 + if n >= 4000: break # todo: don't think this is needed so set nice and high + # for now - comment out or remove? + row = c.fetchone() + #print " %d rows fetched, len(stat_dict) = %d" % (n, len(stat_dict)) + + #print "session stat_dict =", stat_dict return stat_dict def get_player_id(self, config, site, player_name): @@ -209,7 +303,10 @@ class Database: c = self.connection.cursor() c.execute(self.sql.query['get_player_id'], {'player': player_name, 'site': site}) row = c.fetchone() - return row[0] + if row: + return row[0] + else: + return None if __name__=="__main__": c = Configuration.Config() @@ -225,16 +322,17 @@ if __name__=="__main__": print "last hand = ", h hero = db_connection.get_player_id(c, 'PokerStars', 'nutOmatic') - print "nutOmatic is id_player = %d" % hero + if hero: + print "nutOmatic is id_player = %d" % hero stat_dict = db_connection.get_stats_from_hand(h) for p in stat_dict.keys(): print p, " ", stat_dict[p] - print "nutOmatics stats:" - stat_dict = db_connection.get_stats_from_hand(h, hero) - for p in stat_dict.keys(): - print p, " ", stat_dict[p] + #print "nutOmatics stats:" + #stat_dict = db_connection.get_stats_from_hand(h, hero) + #for p in stat_dict.keys(): + # print p, " ", stat_dict[p] print "cards =", db_connection.get_cards(73525) db_connection.close_connection diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index b526632a..68bc8d8f 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -26,8 +26,10 @@ class DerivedStats(): self.HDs = 0 self.street0VPI = 0 self.street0Aggr = 0 - self.street0_3B4BChance = 0 - self.street0_3B4BDone = 0 + self.street0_3BChance = 0 + self.street0_3BDone = 0 + self.street0_4BChance = 0 + self.street0_4BDone = 0 self.street1Seen = 0 self.street2Seen = 0 diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py new file mode 100644 index 00000000..3a5f0365 --- /dev/null +++ b/pyfpdb/Filters.py @@ -0,0 +1,540 @@ +#!/usr/bin/python + +#Copyright 2008 Steffen Jobbagy-Felso +#This program is free software: you can redistribute it and/or modify +#it under the terms of the GNU Affero General Public License as published by +#the Free Software Foundation, version 3 of the License. +# +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +# +#You should have received a copy of the GNU Affero General Public License +#along with this program. If not, see . +#In the "official" distribution you can find the license in +#agpl-3.0.txt in the docs folder of the package. + +import threading +import pygtk +pygtk.require('2.0') +import gtk +import os +import sys +from optparse import OptionParser +from time import * +#import pokereval + +import Configuration +import fpdb_db +import FpdbSQLQueries + +class Filters(threading.Thread): + def __init__(self, db, settings, config, qdict, display = {},debug=True): + self.debug=debug + #print "start of GraphViewer constructor" + self.db=db + self.cursor=db.cursor + self.settings=settings + self.sql=qdict + self.conf = config + self.display = display + + self.sites = {} + self.games = {} + self.limits = {} + self.seats = {} + self.siteid = {} + self.heroes = {} + self.boxes = {} + + # text used on screen stored here so that it can be configured + self.filterText = {'limitsall':'All', 'limitsnone':'None', 'limitsshow':'Show _Limits' + ,'seatsbetween':'Between:', 'seatsand':'And:', 'seatsshow':'Show Number of _Players' + ,'limitstitle':'Limits:', 'seatstitle':'Number of Players:' + } + + # For use in date ranges. + self.start_date = gtk.Entry(max=12) + self.end_date = gtk.Entry(max=12) + self.start_date.set_property('editable', False) + self.end_date.set_property('editable', False) + + # Outer Packing box + self.mainVBox = gtk.VBox(False, 0) + + playerFrame = gtk.Frame("Hero:") + playerFrame.set_label_align(0.0, 0.0) + vbox = gtk.VBox(False, 0) + + self.fillPlayerFrame(vbox) + playerFrame.add(vbox) + self.boxes['player'] = vbox + + sitesFrame = gtk.Frame("Sites:") + sitesFrame.set_label_align(0.0, 0.0) + vbox = gtk.VBox(False, 0) + + self.fillSitesFrame(vbox) + sitesFrame.add(vbox) + self.boxes['sites'] = vbox + + # Game types + gamesFrame = gtk.Frame("Games:") + gamesFrame.set_label_align(0.0, 0.0) + gamesFrame.show() + vbox = gtk.VBox(False, 0) + + self.fillGamesFrame(vbox) + gamesFrame.add(vbox) + self.boxes['games'] = vbox + + # Limits + limitsFrame = gtk.Frame() + limitsFrame.show() + vbox = gtk.VBox(False, 0) + self.cbLimits = {} + self.cbNoLimits = None + self.cbAllLimits = None + + self.fillLimitsFrame(vbox, self.display) + limitsFrame.add(vbox) + + # Seats + seatsFrame = gtk.Frame() + seatsFrame.show() + vbox = gtk.VBox(False, 0) + self.sbSeats = {} + + self.fillSeatsFrame(vbox, self.display) + seatsFrame.add(vbox) + + # Date + dateFrame = gtk.Frame("Date:") + dateFrame.set_label_align(0.0, 0.0) + dateFrame.show() + vbox = gtk.VBox(False, 0) + + self.fillDateFrame(vbox) + dateFrame.add(vbox) + self.boxes['date'] = vbox + + # Buttons + self.Button1=gtk.Button("Unnamed 1") + self.Button1.set_sensitive(False) + + self.Button2=gtk.Button("Unnamed 2") + self.Button2.set_sensitive(False) + + self.mainVBox.add(playerFrame) + self.mainVBox.add(sitesFrame) + self.mainVBox.add(gamesFrame) + self.mainVBox.add(limitsFrame) + self.mainVBox.add(seatsFrame) + self.mainVBox.add(dateFrame) + self.mainVBox.add(self.Button1) + self.mainVBox.add(self.Button2) + + self.mainVBox.show_all() + + # Should do this cleaner + if "Heroes" not in self.display or self.display["Heroes"] == False: + playerFrame.hide() + if "Sites" not in self.display or self.display["Sites"] == False: + sitesFrame.hide() + if "Games" not in self.display or self.display["Games"] == False: + gamesFrame.hide() + if "Limits" not in self.display or self.display["Limits"] == False: + limitsFrame.hide() + if "Seats" not in self.display or self.display["Seats"] == False: + seatsFrame.hide() + if "Dates" not in self.display or self.display["Dates"] == False: + dateFrame.hide() + if "Button1" not in self.display or self.display["Button1"] == False: + self.Button1.hide() + if "Button2" not in self.display or self.display["Button2"] == False: + self.Button2.hide() + + def get_vbox(self): + """returns the vbox of this thread""" + return self.mainVBox + #end def get_vbox + + def getSites(self): + return self.sites + + def getSiteIds(self): + return self.siteid + + def getHeroes(self): + return self.heroes + + def getLimits(self): + ltuple = [] + for l in self.limits: + if self.limits[l] == True: + ltuple.append(l) + return ltuple + + def getSeats(self): + if 'from' in self.sbSeats: + self.seats['from'] = self.sbSeats['from'].get_value_as_int() + if 'to' in self.sbSeats: + self.seats['to'] = self.sbSeats['to'].get_value_as_int() + return self.seats + + def getDates(self): + return self.__get_dates() + + def registerButton1Name(self, title): + self.Button1.set_label(title) + + def registerButton1Callback(self, callback): + self.Button1.connect("clicked", callback, "clicked") + self.Button1.set_sensitive(True) + + def registerButton2Name(self, title): + self.Button2.set_label(title) + + def registerButton2Callback(self, callback): + self.Button2.connect("clicked", callback, "clicked") + self.Button2.set_sensitive(True) + + def cardCallback(self, widget, data=None): + print "DEBUG: %s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()]) + + def createPlayerLine(self, hbox, site, player): + label = gtk.Label(site +" id:") + hbox.pack_start(label, False, False, 0) + + pname = gtk.Entry() + pname.set_text(player) + 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 + + self.__set_hero_name(pname, site) + + def __set_hero_name(self, w, site): + self.heroes[site] = w.get_text() +# print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site]) + + def createSiteLine(self, hbox, site): + cb = gtk.CheckButton(site) + cb.connect('clicked', self.__set_site_select, site) + cb.set_active(True) + hbox.pack_start(cb, False, False, 0) + + def createGameLine(self, hbox, game): + cb = gtk.CheckButton(game) + cb.connect('clicked', self.__set_game_select, game) + hbox.pack_start(cb, False, False, 0) + + def createLimitLine(self, hbox, limit, ltext): + cb = gtk.CheckButton(str(ltext)) + cb.connect('clicked', self.__set_limit_select, limit) + hbox.pack_start(cb, False, False, 0) + if limit != "none": + cb.set_active(True) + return(cb) + + def __set_site_select(self, w, site): + #print w.get_active() + self.sites[site] = w.get_active() + print "self.sites[%s] set to %s" %(site, self.sites[site]) + + def __set_game_select(self, w, game): + #print w.get_active() + self.games[game] = w.get_active() + print "self.games[%s] set to %s" %(game, self.games[game]) + + def __set_limit_select(self, w, limit): + #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 self.limits[limit]: + if self.cbNoLimits != None: + self.cbNoLimits.set_active(False) + else: + if self.cbAllLimits != None: + self.cbAllLimits.set_active(False) + elif limit == "all": + if self.limits[limit]: + for cb in self.cbLimits.values(): + cb.set_active(True) + elif limit == "none": + if self.limits[limit]: + for cb in self.cbLimits.values(): + cb.set_active(False) + + def __set_seat_select(self, w, seat): + #print "__set_seat_select: seat =", seat, "active =", w.get_active() + self.seats[seat] = w.get_active() + print "self.seats[%s] set to %s" %(seat, self.seats[seat]) + + def fillPlayerFrame(self, vbox): + for site in self.conf.get_supported_sites(): + pathHBox = gtk.HBox(False, 0) + vbox.pack_start(pathHBox, False, True, 0) + + player = self.conf.supported_sites[site].screen_name + self.createPlayerLine(pathHBox, site, player) + + def fillSitesFrame(self, vbox): + for site in self.conf.get_supported_sites(): + hbox = gtk.HBox(False, 0) + vbox.pack_start(hbox, False, True, 0) + self.createSiteLine(hbox, site) + #Get db site id for filtering later + self.cursor.execute(self.sql.query['getSiteId'], (site,)) + result = self.db.cursor.fetchall() + if len(result) == 1: + self.siteid[site] = result[0][0] + else: + print "Either 0 or more than one site matched - EEK" + + def fillGamesFrame(self, vbox): + self.cursor.execute(self.sql.query['getGames']) + result = self.db.cursor.fetchall() + if len(result) >= 1: + for line in result: + hbox = gtk.HBox(False, 0) + vbox.pack_start(hbox, False, True, 0) + self.createGameLine(hbox, line[0]) + else: + print "INFO: No games returned from database" + + def fillLimitsFrame(self, vbox, display): + hbox = gtk.HBox(False, 0) + vbox.pack_start(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) + 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']) + result = self.db.cursor.fetchall() + if len(result) >= 1: + 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) + for i, line in enumerate(result): + 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 "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2: + hbox = gtk.HBox(False, 0) + vbox1.pack_start(hbox, False, True, 0) + self.cbAllLimits = self.createLimitLine(hbox, 'all', self.filterText['limitsall']) + hbox = gtk.HBox(False, 0) + vbox1.pack_start(hbox, False, True, 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']) + else: + print "INFO: No games returned from database" + + def fillSeatsFrame(self, vbox, display): + hbox = gtk.HBox(False, 0) + vbox.pack_start(hbox, False, False, 0) + lbl_title = gtk.Label(self.filterText['seatstitle']) + lbl_title.set_alignment(xalign=0.0, yalign=0.5) + 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, 'seats') + hbox.pack_start(showb, expand=False, padding=1) + + vbox1 = gtk.VBox(False, 0) + vbox.pack_start(vbox1, False, False, 0) + self.boxes['seats'] = vbox1 + + hbox = gtk.HBox(False, 0) + vbox1.pack_start(hbox, False, True, 0) + + lbl_from = gtk.Label(self.filterText['seatsbetween']) + lbl_to = gtk.Label(self.filterText['seatsand']) + adj1 = gtk.Adjustment(value=2, lower=2, upper=10, step_incr=1, page_incr=1, page_size=0) + sb1 = gtk.SpinButton(adjustment=adj1, climb_rate=0.0, digits=0) + adj2 = gtk.Adjustment(value=10, lower=2, upper=10, step_incr=1, page_incr=1, page_size=0) + sb2 = gtk.SpinButton(adjustment=adj2, climb_rate=0.0, digits=0) + + hbox.pack_start(lbl_from, expand=False, padding=3) + hbox.pack_start(sb1, False, False, 0) + 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 + + def fillCardsFrame(self, vbox): + hbox1 = gtk.HBox(True,0) + hbox1.show() + vbox.pack_start(hbox1, True, True, 0) + + cards = [ "A", "K","Q","J","T","9","8","7","6","5","4","3","2" ] + + for j in range(0, len(cards)): + hbox1 = gtk.HBox(True,0) + hbox1.show() + vbox.pack_start(hbox1, True, True, 0) + for i in range(0, len(cards)): + if i < (j + 1): + suit = "o" + else: + suit = "s" + button = gtk.ToggleButton("%s%s%s" %(cards[i], cards[j], suit)) + button.connect("toggled", self.cardCallback, "%s%s%s" %(cards[i], cards[j], suit)) + hbox1.pack_start(button, True, True, 0) + button.show() + + def fillDateFrame(self, vbox): + # Hat tip to Mika Bostrom - calendar code comes from PokerStats + hbox = gtk.HBox() + vbox.pack_start(hbox, False, True, 0) + + lbl_start = gtk.Label('From:') + + btn_start = gtk.Button() + btn_start.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)) + btn_start.connect('clicked', self.__calendar_dialog, self.start_date) + + hbox.pack_start(lbl_start, expand=False, padding=3) + hbox.pack_start(btn_start, expand=False, padding=3) + hbox.pack_start(self.start_date, expand=False, padding=2) + + #New row for end date + hbox = gtk.HBox() + vbox.pack_start(hbox, False, True, 0) + + lbl_end = gtk.Label(' To:') + btn_end = gtk.Button() + btn_end.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)) + btn_end.connect('clicked', self.__calendar_dialog, self.end_date) + + btn_clear = gtk.Button(label=' Clear Dates ') + btn_clear.connect('clicked', self.__clear_dates) + + hbox.pack_start(lbl_end, expand=False, padding=3) + hbox.pack_start(btn_end, expand=False, padding=3) + hbox.pack_start(self.end_date, expand=False, padding=2) + + hbox.pack_start(btn_clear, expand=False, padding=15) + + def __toggle_box(self, widget, entry): + if "Limits" not in self.display or self.display["Limits"] == False: + self.boxes[entry].hide() + elif self.boxes[entry].props.visible: + self.boxes[entry].hide() + widget.set_label("show") + else: + self.boxes[entry].show() + widget.set_label("hide") + + def __calendar_dialog(self, widget, entry): + d = gtk.Window(gtk.WINDOW_TOPLEVEL) + d.set_title('Pick a date') + + vb = gtk.VBox() + cal = gtk.Calendar() + vb.pack_start(cal, expand=False, padding=0) + + btn = gtk.Button('Done') + btn.connect('clicked', self.__get_date, cal, entry, d) + + vb.pack_start(btn, expand=False, padding=4) + + d.add(vb) + d.set_position(gtk.WIN_POS_MOUSE) + d.show_all() + + def __clear_dates(self, w): + self.start_date.set_text('') + self.end_date.set_text('') + + def __get_dates(self): + t1 = self.start_date.get_text() + t2 = self.end_date.get_text() + + if t1 == '': + t1 = '1970-01-01' + if t2 == '': + t2 = '2020-12-12' + + return (t1, t2) + + def __get_date(self, widget, calendar, entry, win): +# year and day are correct, month is 0..11 + (year, month, day) = calendar.get_date() + month += 1 + ds = '%04d-%02d-%02d' % (year, month, day) + entry.set_text(ds) + win.destroy() + +def main(argv=None): + """main can also be called in the python interpreter, by supplying the command line as the argument.""" + if argv is None: + argv = sys.argv[1:] + + def destroy(*args): # call back for terminating the main eventloop + gtk.main_quit() + + parser = OptionParser() + (options, sys.argv) = parser.parse_args(args = argv) + + config = Configuration.Config() + db = None + + settings = {} + + settings.update(config.get_db_parameters()) + settings.update(config.get_tv_parameters()) + settings.update(config.get_import_parameters()) + settings.update(config.get_default_paths()) + + db = fpdb_db.fpdb_db() + db.connect(settings['db-backend'], + settings['db-host'], + settings['db-databaseName'], + settings['db-user'], + settings['db-password']) + + qdict = FpdbSQLQueries.FpdbSQLQueries(db.get_backend_name()) + + i = Filters(db, settings, config, qdict) + main_window = gtk.Window() + main_window.connect('destroy', destroy) + main_window.add(i.get_vbox()) + main_window.show() + gtk.main() + +if __name__ == '__main__': + sys.exit(main()) + + diff --git a/pyfpdb/FpdbSQLQueries.py b/pyfpdb/FpdbSQLQueries.py index 24948986..a85c2491 100644 --- a/pyfpdb/FpdbSQLQueries.py +++ b/pyfpdb/FpdbSQLQueries.py @@ -41,8 +41,8 @@ class FpdbSQLQueries: self.query['list_tables'] = """ """ ################################################################## - # Drop Tables - MySQL, PostgreSQL and SQLite all share same syntax - ################################################################## + # Drop Tables - MySQL, PostgreSQL and SQLite all share same syntax + ################################################################## if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): self.query['drop_table'] = """DROP TABLE IF EXISTS """ @@ -183,23 +183,67 @@ class FpdbSQLQueries: gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), handStart DATETIME NOT NULL, importTime DATETIME NOT NULL, - seats SMALLINT NOT NULL, - maxSeats SMALLINT NOT NULL, + seats TINYINT NOT NULL, + maxSeats TINYINT NOT NULL, + boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */ + boardcard2 smallint, + boardcard3 smallint, + boardcard4 smallint, + boardcard5 smallint, + texture smallint, + playersVpi SMALLINT NOT NULL, /* num of players vpi */ + playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */ + playersAtStreet2 SMALLINT NOT NULL, + playersAtStreet3 SMALLINT NOT NULL, + playersAtStreet4 SMALLINT NOT NULL, + playersAtShowdown SMALLINT NOT NULL, + street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */ + street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */ + street2Raises TINYINT NOT NULL, /* num big bets paid to see river/street6 */ + street3Raises TINYINT NOT NULL, /* num big bets paid to see sd/street7 */ + street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */ + street1Pot INT, /* pot size at flop/street4 */ + street2Pot INT, /* pot size at turn/street5 */ + street3Pot INT, /* pot size at river/street6 */ + street4Pot INT, /* pot size at sd/street7 */ + showdownPot INT, /* pot size at sd/street7 */ comment TEXT, commentTs DATETIME) ENGINE=INNODB""" elif(self.dbname == 'PostgreSQL'): self.query['createHandsTable'] = """CREATE TABLE Hands ( - id BIGSERIAL, PRIMARY KEY (id), - tableName VARCHAR(20), - siteHandNo BIGINT, - gametypeId INT, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), - handStart timestamp without time zone, - importTime timestamp without time zone, - seats SMALLINT, - maxSeats SMALLINT, - comment TEXT, - commentTs timestamp without time zone)""" + id BIGSERIAL, PRIMARY KEY (id), + tableName VARCHAR(20) NOT NULL, + siteHandNo BIGINT NOT NULL, + gametypeId INT NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), + handStart timestamp without time zone NOT NULL, + importTime timestamp without time zone NOT NULL, + seats SMALLINT NOT NULL, + maxSeats SMALLINT NOT NULL, + boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */ + boardcard2 smallint, + boardcard3 smallint, + boardcard4 smallint, + boardcard5 smallint, + texture smallint, + playersVpi SMALLINT NOT NULL, /* num of players vpi */ + playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */ + playersAtStreet2 SMALLINT NOT NULL, + playersAtStreet3 SMALLINT NOT NULL, + playersAtStreet4 SMALLINT NOT NULL, + playersAtShowdown SMALLINT NOT NULL, + street0Raises SMALLINT NOT NULL, /* num small bets paid to see flop/street4, including blind */ + street1Raises SMALLINT NOT NULL, /* num small bets paid to see turn/street5 */ + street2Raises SMALLINT NOT NULL, /* num big bets paid to see river/street6 */ + street3Raises SMALLINT NOT NULL, /* num big bets paid to see sd/street7 */ + street4Raises SMALLINT NOT NULL, /* num big bets paid to see showdown */ + street1Pot INT, /* pot size at flop/street4 */ + street2Pot INT, /* pot size at turn/street5 */ + street3Pot INT, /* pot size at river/street6 */ + street4Pot INT, /* pot size at sd/street7 */ + showdownPot INT, /* pot size at sd/street7 */ + comment TEXT, + commentTs timestamp without time zone)""" elif(self.dbname == 'SQLite'): self.query['createHandsTable'] = """ """ @@ -306,60 +350,233 @@ class FpdbSQLQueries: startCash INT NOT NULL, position CHAR(1), seatNo SMALLINT NOT NULL, + + card1 smallint NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */ + card2 smallint NOT NULL, + card3 smallint, + card4 smallint, + card5 smallint, + card6 smallint, + card7 smallint, + startCards smallint, + ante INT, - - card1Value smallint NOT NULL, - card1Suit char(1) NOT NULL, - card2Value smallint NOT NULL, - card2Suit char(1) NOT NULL, - card3Value smallint, - card3Suit char(1), - card4Value smallint, - card4Suit char(1), - card5Value smallint, - card5Suit char(1), - card6Value smallint, - card6Suit char(1), - card7Value smallint, - card7Suit char(1), - winnings int NOT NULL, rake int NOT NULL, + totalProfit INT NOT NULL, comment text, commentTs DATETIME, - - tourneysPlayersId BIGINT UNSIGNED, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id)) + tourneysPlayersId BIGINT UNSIGNED, + tourneyTypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), + + wonWhenSeenStreet1 FLOAT NOT NULL, + wonWhenSeenStreet2 FLOAT, + wonWhenSeenStreet3 FLOAT, + wonWhenSeenStreet4 FLOAT, + wonAtSD FLOAT NOT NULL, + + street0VPI BOOLEAN NOT NULL, + street0Aggr BOOLEAN NOT NULL, + street0_3BChance BOOLEAN NOT NULL, + street0_3BDone BOOLEAN NOT NULL, + street0_4BChance BOOLEAN, + street0_4BDone BOOLEAN, + other3BStreet0 BOOLEAN, + other4BStreet0 BOOLEAN, + + street1Seen BOOLEAN NOT NULL, + street2Seen BOOLEAN NOT NULL, + street3Seen BOOLEAN NOT NULL, + street4Seen BOOLEAN NOT NULL, + sawShowdown BOOLEAN NOT NULL, + + street1Aggr BOOLEAN NOT NULL, + street2Aggr BOOLEAN NOT NULL, + street3Aggr BOOLEAN NOT NULL, + street4Aggr BOOLEAN NOT NULL, + + otherRaisedStreet0 BOOLEAN, + otherRaisedStreet1 BOOLEAN NOT NULL, + otherRaisedStreet2 BOOLEAN NOT NULL, + otherRaisedStreet3 BOOLEAN NOT NULL, + otherRaisedStreet4 BOOLEAN NOT NULL, + foldToOtherRaisedStreet0 BOOLEAN, + foldToOtherRaisedStreet1 BOOLEAN NOT NULL, + foldToOtherRaisedStreet2 BOOLEAN NOT NULL, + foldToOtherRaisedStreet3 BOOLEAN NOT NULL, + foldToOtherRaisedStreet4 BOOLEAN NOT NULL, + + stealAttemptChance BOOLEAN NOT NULL, + stealAttempted BOOLEAN NOT NULL, + foldBbToStealChance BOOLEAN NOT NULL, + foldedBbToSteal BOOLEAN NOT NULL, + foldSbToStealChance BOOLEAN NOT NULL, + foldedSbToSteal BOOLEAN NOT NULL, + + street1CBChance BOOLEAN NOT NULL, + street1CBDone BOOLEAN NOT NULL, + street2CBChance BOOLEAN NOT NULL, + street2CBDone BOOLEAN NOT NULL, + street3CBChance BOOLEAN NOT NULL, + street3CBDone BOOLEAN NOT NULL, + street4CBChance BOOLEAN NOT NULL, + street4CBDone BOOLEAN NOT NULL, + + foldToStreet1CBChance BOOLEAN NOT NULL, + foldToStreet1CBDone BOOLEAN NOT NULL, + foldToStreet2CBChance BOOLEAN NOT NULL, + foldToStreet2CBDone BOOLEAN NOT NULL, + foldToStreet3CBChance BOOLEAN NOT NULL, + foldToStreet3CBDone BOOLEAN NOT NULL, + foldToStreet4CBChance BOOLEAN NOT NULL, + foldToStreet4CBDone BOOLEAN NOT NULL, + + street1CheckCallRaiseChance BOOLEAN NOT NULL, + street1CheckCallRaiseDone BOOLEAN NOT NULL, + street2CheckCallRaiseChance BOOLEAN NOT NULL, + street2CheckCallRaiseDone BOOLEAN NOT NULL, + street3CheckCallRaiseChance BOOLEAN NOT NULL, + street3CheckCallRaiseDone BOOLEAN NOT NULL, + street4CheckCallRaiseChance BOOLEAN NOT NULL, + street4CheckCallRaiseDone BOOLEAN NOT NULL, + + street0Calls TINYINT, + street1Calls TINYINT, + street2Calls TINYINT, + street3Calls TINYINT, + street4Calls TINYINT, + street0Bets TINYINT, + street1Bets TINYINT, + street2Bets TINYINT, + street3Bets TINYINT, + street4Bets TINYINT, + street0Raises TINYINT, + street1Raises TINYINT, + street2Raises TINYINT, + street3Raises TINYINT, + street4Raises TINYINT, + + actionString VARCHAR(15), + + FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id)) ENGINE=INNODB""" elif(self.dbname == 'PostgreSQL'): self.query['createHandsPlayersTable'] = """CREATE TABLE HandsPlayers ( id BIGSERIAL, PRIMARY KEY (id), - handId BIGINT, FOREIGN KEY (handId) REFERENCES Hands(id), - playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id), - startCash INT, + handId BIGINT NOT NULL, FOREIGN KEY (handId) REFERENCES Hands(id), + playerId INT NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), + startCash INT NOT NULL, position CHAR(1), - seatNo SMALLINT, + seatNo SMALLINT NOT NULL, + + card1 smallint NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */ + card2 smallint NOT NULL, + card3 smallint, + card4 smallint, + card5 smallint, + card6 smallint, + card7 smallint, + startCards smallint, + ante INT, - - card1Value smallint, - card1Suit char(1), - card2Value smallint, - card2Suit char(1), - card3Value smallint, - card3Suit char(1), - card4Value smallint, - card4Suit char(1), - card5Value smallint, - card5Suit char(1), - card6Value smallint, - card6Suit char(1), - card7Value smallint, - card7Suit char(1), - - winnings int, - rake int, + winnings int NOT NULL, + rake int NOT NULL, + totalProfit INT NOT NULL, comment text, commentTs timestamp without time zone, - tourneysPlayersId BIGINT, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id))""" + tourneysPlayersId BIGINT, + tourneyTypeId INT NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), + + wonWhenSeenStreet1 FLOAT NOT NULL, + wonWhenSeenStreet2 FLOAT, + wonWhenSeenStreet3 FLOAT, + wonWhenSeenStreet4 FLOAT, + wonAtSD FLOAT NOT NULL, + + street0VPI BOOLEAN NOT NULL, + street0Aggr BOOLEAN NOT NULL, + street0_3BChance BOOLEAN NOT NULL, + street0_3BDone BOOLEAN NOT NULL, + street0_4BChance BOOLEAN, + street0_4BDone BOOLEAN, + other3BStreet0 BOOLEAN, + other4BStreet0 BOOLEAN, + + street1Seen BOOLEAN NOT NULL, + street2Seen BOOLEAN NOT NULL, + street3Seen BOOLEAN NOT NULL, + street4Seen BOOLEAN NOT NULL, + sawShowdown BOOLEAN NOT NULL, + + street1Aggr BOOLEAN NOT NULL, + street2Aggr BOOLEAN NOT NULL, + street3Aggr BOOLEAN NOT NULL, + street4Aggr BOOLEAN NOT NULL, + + otherRaisedStreet0 BOOLEAN, + otherRaisedStreet1 BOOLEAN NOT NULL, + otherRaisedStreet2 BOOLEAN NOT NULL, + otherRaisedStreet3 BOOLEAN NOT NULL, + otherRaisedStreet4 BOOLEAN NOT NULL, + foldToOtherRaisedStreet0 BOOLEAN, + foldToOtherRaisedStreet1 BOOLEAN NOT NULL, + foldToOtherRaisedStreet2 BOOLEAN NOT NULL, + foldToOtherRaisedStreet3 BOOLEAN NOT NULL, + foldToOtherRaisedStreet4 BOOLEAN NOT NULL, + + stealAttemptChance BOOLEAN NOT NULL, + stealAttempted BOOLEAN NOT NULL, + foldBbToStealChance BOOLEAN NOT NULL, + foldedBbToSteal BOOLEAN NOT NULL, + foldSbToStealChance BOOLEAN NOT NULL, + foldedSbToSteal BOOLEAN NOT NULL, + + street1CBChance BOOLEAN NOT NULL, + street1CBDone BOOLEAN NOT NULL, + street2CBChance BOOLEAN NOT NULL, + street2CBDone BOOLEAN NOT NULL, + street3CBChance BOOLEAN NOT NULL, + street3CBDone BOOLEAN NOT NULL, + street4CBChance BOOLEAN NOT NULL, + street4CBDone BOOLEAN NOT NULL, + + foldToStreet1CBChance BOOLEAN NOT NULL, + foldToStreet1CBDone BOOLEAN NOT NULL, + foldToStreet2CBChance BOOLEAN NOT NULL, + foldToStreet2CBDone BOOLEAN NOT NULL, + foldToStreet3CBChance BOOLEAN NOT NULL, + foldToStreet3CBDone BOOLEAN NOT NULL, + foldToStreet4CBChance BOOLEAN NOT NULL, + foldToStreet4CBDone BOOLEAN NOT NULL, + + street1CheckCallRaiseChance BOOLEAN NOT NULL, + street1CheckCallRaiseDone BOOLEAN NOT NULL, + street2CheckCallRaiseChance BOOLEAN NOT NULL, + street2CheckCallRaiseDone BOOLEAN NOT NULL, + street3CheckCallRaiseChance BOOLEAN NOT NULL, + street3CheckCallRaiseDone BOOLEAN NOT NULL, + street4CheckCallRaiseChance BOOLEAN NOT NULL, + street4CheckCallRaiseDone BOOLEAN NOT NULL, + + street0Calls SMALLINT, + street1Calls SMALLINT, + street2Calls SMALLINT, + street3Calls SMALLINT, + street4Calls SMALLINT, + street0Bets SMALLINT, + street1Bets SMALLINT, + street2Bets SMALLINT, + street3Bets SMALLINT, + street4Bets SMALLINT, + street0Raises SMALLINT, + street1Raises SMALLINT, + street2Raises SMALLINT, + street3Raises SMALLINT, + street4Raises SMALLINT, + + actionString VARCHAR(15), + + FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id))""" elif(self.dbname == 'SQLite'): self.query['createHandsPlayersTable'] = """ """ @@ -400,7 +617,7 @@ class FpdbSQLQueries: if(self.dbname == 'MySQL InnoDB'): self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions ( id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - handPlayerId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handPlayerId) REFERENCES HandsPlayers(id), + handsPlayerId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handsPlayerId) REFERENCES HandsPlayers(id), street SMALLINT NOT NULL, actionNo SMALLINT NOT NULL, action CHAR(5) NOT NULL, @@ -412,7 +629,7 @@ class FpdbSQLQueries: elif(self.dbname == 'PostgreSQL'): self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions ( id BIGSERIAL, PRIMARY KEY (id), - handPlayerId BIGINT, FOREIGN KEY (handPlayerId) REFERENCES HandsPlayers(id), + handsPlayerId BIGINT, FOREIGN KEY (handsPlayerId) REFERENCES HandsPlayers(id), street SMALLINT, actionNo SMALLINT, action CHAR(5), @@ -436,13 +653,24 @@ class FpdbSQLQueries: activeSeats SMALLINT NOT NULL, position CHAR(1), tourneyTypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), - + styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ HDs INT NOT NULL, + + wonWhenSeenStreet1 FLOAT NOT NULL, + wonWhenSeenStreet2 FLOAT, + wonWhenSeenStreet3 FLOAT, + wonWhenSeenStreet4 FLOAT, + wonAtSD FLOAT NOT NULL, + street0VPI INT NOT NULL, street0Aggr INT NOT NULL, - street0_3B4BChance INT NOT NULL, - street0_3B4BDone INT NOT NULL, - + street0_3BChance INT NOT NULL, + street0_3BDone INT NOT NULL, + street0_4BChance INT, + street0_4BDone INT, + other3BStreet0 INT, + other4BStreet0 INT, + street1Seen INT NOT NULL, street2Seen INT NOT NULL, street3Seen INT NOT NULL, @@ -453,17 +681,17 @@ class FpdbSQLQueries: street2Aggr INT NOT NULL, street3Aggr INT NOT NULL, street4Aggr INT NOT NULL, - + + otherRaisedStreet0 INT, otherRaisedStreet1 INT NOT NULL, otherRaisedStreet2 INT NOT NULL, otherRaisedStreet3 INT NOT NULL, otherRaisedStreet4 INT NOT NULL, + foldToOtherRaisedStreet0 INT, foldToOtherRaisedStreet1 INT NOT NULL, foldToOtherRaisedStreet2 INT NOT NULL, foldToOtherRaisedStreet3 INT NOT NULL, foldToOtherRaisedStreet4 INT NOT NULL, - wonWhenSeenStreet1 FLOAT NOT NULL, - wonAtSD FLOAT NOT NULL, stealAttemptChance INT NOT NULL, stealAttempted INT NOT NULL, @@ -471,7 +699,7 @@ class FpdbSQLQueries: foldedBbToSteal INT NOT NULL, foldSbToStealChance INT NOT NULL, foldedSbToSteal INT NOT NULL, - + street1CBChance INT NOT NULL, street1CBDone INT NOT NULL, street2CBChance INT NOT NULL, @@ -499,7 +727,24 @@ class FpdbSQLQueries: street3CheckCallRaiseChance INT NOT NULL, street3CheckCallRaiseDone INT NOT NULL, street4CheckCallRaiseChance INT NOT NULL, - street4CheckCallRaiseDone INT NOT NULL) + street4CheckCallRaiseDone INT NOT NULL, + + street0Calls INT, + street1Calls INT, + street2Calls INT, + street3Calls INT, + street4Calls INT, + street0Bets INT, + street1Bets INT, + street2Bets INT, + street3Bets INT, + street4Bets INT, + street0Raises INT, + street1Raises INT, + street2Raises INT, + street3Raises INT, + street4Raises INT) + ENGINE=INNODB""" elif(self.dbname == 'PostgreSQL'): self.query['createHudCacheTable'] = """CREATE TABLE HudCache ( @@ -509,12 +754,24 @@ class FpdbSQLQueries: activeSeats SMALLINT, position CHAR(1), tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), - + styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ HDs INT, - street0VPI INT, + + wonWhenSeenStreet1 FLOAT NOT NULL, + wonWhenSeenStreet2 FLOAT, + wonWhenSeenStreet3 FLOAT, + wonWhenSeenStreet4 FLOAT, + wonAtSD FLOAT NOT NULL, + + street0VPI INT NOT NULL, street0Aggr INT, - street0_3B4BChance INT, - street0_3B4BDone INT, + street0_3BChance INT NOT NULL, + street0_3BDone INT NOT NULL, + street0_4BChance INT, + street0_4BDone INT, + other3BStreet0 INT, + other4BStreet0 INT, + street1Seen INT, street2Seen INT, street3Seen INT, @@ -524,16 +781,17 @@ class FpdbSQLQueries: street2Aggr INT, street3Aggr INT, street4Aggr INT, + + otherRaisedStreet0 INT, otherRaisedStreet1 INT, otherRaisedStreet2 INT, otherRaisedStreet3 INT, otherRaisedStreet4 INT, + foldToOtherRaisedStreet0 INT, foldToOtherRaisedStreet1 INT, foldToOtherRaisedStreet2 INT, foldToOtherRaisedStreet3 INT, foldToOtherRaisedStreet4 INT, - wonWhenSeenStreet1 FLOAT, - wonAtSD FLOAT, stealAttemptChance INT, stealAttempted INT, @@ -569,7 +827,24 @@ class FpdbSQLQueries: street3CheckCallRaiseChance INT, street3CheckCallRaiseDone INT, street4CheckCallRaiseChance INT, - street4CheckCallRaiseDone INT)""" + street4CheckCallRaiseDone INT, + + street0Calls INT, + street1Calls INT, + street2Calls INT, + street3Calls INT, + street4Calls INT, + street0Bets INT, + street1Bets INT, + street2Bets INT, + street3Bets INT, + street4Bets INT, + street0Raises INT, + street1Raises INT, + street2Raises INT, + street3Raises INT, + street4Raises INT) + """ elif(self.dbname == 'SQLite'): self.query['createHudCacheTable'] = """ """ @@ -609,51 +884,111 @@ class FpdbSQLQueries: elif(self.dbname == 'SQLite'): self.query['getSiteId'] = """SELECT id from Sites where name = %s""" - if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL'): + if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): self.query['getRingProfitAllHandsPlayerIdSite'] = """ - SELECT hp.handId, hp.winnings, coalesce(hp.ante,0) + SUM(ha.amount) - , hp.winnings - (coalesce(hp.ante,0) + SUM(ha.amount)) + SELECT hp.handId, hp.totalProfit, hp.totalProfit, 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 HandsActions ha ON ha.handPlayerId = hp.id + INNER JOIN Gametypes g ON h.gametypeId = g.id 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 hp.handId, hp.winnings, h.handStart, hp.ante + GROUP BY h.handStart, hp.handId, hp.totalProfit ORDER BY h.handStart""" + + if self.dbname in ['MySQL InnoDB', 'PostgreSQL']: + self.query['playerDetailedStats'] = """ + select AS hgametypeid + ,gt.base + ,gt.category + ,upper(gt.limitType) AS limittype + ,s.name + ,min(gt.bigBlind) AS minbigblind + ,max(gt.bigBlind) AS maxbigblind + /*, AS gtid*/ + ,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) + where hp.playerId in + and hp.tourneysPlayersId IS NULL + and h.seats + + + group by hgameTypeId + ,hp.playerId + ,gt.base + ,gt.category + + ,upper(gt.limitType) + ,s.name + order by hp.playerId + ,gt.base + ,gt.category + + + ,maxbigblind desc + ,upper(gt.limitType) + ,s.name + """ elif(self.dbname == 'SQLite'): - #Probably doesn't work. - self.query['getRingProfitAllHandsPlayerIdSite'] = """ - SELECT hp.handId, hp.winnings, SUM(ha.amount), hp.winnings - SUM(ha.amount) - FROM HandsPlayers hp - INNER JOIN Players pl ON hp.playerId = pl.id - INNER JOIN Hands h ON h.id = hp.handId - INNER JOIN HandsActions ha ON ha.handPlayerId = hp.id - where pl.id in - AND pl.siteId in - AND h.handStart > '' - AND h.handStart < '' - AND hp.tourneysPlayersId IS NULL - GROUP BY hp.handId, hp.winnings, h.handStart - ORDER BY h.handStart""" + self.query['playerDetailedStats'] = """ """ if(self.dbname == 'MySQL InnoDB'): self.query['playerStats'] = """ SELECT concat(upper(stats.limitType), ' ' ,concat(upper(substring(stats.category,1,1)),substring(stats.category,2) ), ' ' - ,stats.name, ' $' - ,cast(trim(leading ' ' from - case when stats.bigBlind < 100 then format(stats.bigBlind/100.0,2) - else format(stats.bigBlind/100.0,0) - end ) as char) + ,stats.name, ' ' + ,cast(stats.bigBlindDesc as char) ) AS Game ,stats.n ,stats.vpip ,stats.pfr + ,stats.pf3 + ,stats.steals ,stats.saw_f ,stats.sawsd ,stats.wtsdwsf @@ -662,184 +997,194 @@ class FpdbSQLQueries: ,stats.TuAFq ,stats.RvAFq ,stats.PoFAFq - /* if you have handsactions data the next 3 fields should give same answer as - following 3 commented out fields */ ,stats.Net ,stats.BBper100 ,stats.Profitperhand - /*,format(hprof2.sum_profit/100.0,2) AS Net - ,format((hprof2.sum_profit/(stats.bigBlind+0.0)) / (stats.n/100.0),2) - AS BBlPer100 - ,hprof2.profitperhand AS Profitperhand - */ - ,format(hprof2.variance,2) AS Variance + ,case when hprof2.variance = -999 then '-' + else format(hprof2.variance, 2) + end AS Variance + ,stats.AvgSeats FROM (select /* stats from hudcache */ gt.base ,gt.category ,upper(gt.limitType) as limitType ,s.name - ,gt.bigBlind - ,hc.gametypeId + , AS bigBlindDesc + , AS gtId ,sum(HDs) AS n - ,format(100.0*sum(street0VPI)/sum(HDs),1) AS vpip - ,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr - ,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f - ,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd - ,case when sum(street1Seen) = 0 then 'oo' + ,format(100.0*sum(street0VPI)/sum(HDs),1) AS vpip + ,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr + ,case when sum(street0_3Bchance) = 0 then '0' + else format(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),1) + end AS pf3 + ,case when sum(stealattemptchance) = 0 then '-' + else format(100.0*sum(stealattempted)/sum(stealattemptchance),1) + end AS steals + ,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f + ,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd + ,case when sum(street1Seen) = 0 then '-' else format(100.0*sum(sawShowdown)/sum(street1Seen),1) end AS wtsdwsf - ,case when sum(sawShowdown) = 0 then 'oo' + ,case when sum(sawShowdown) = 0 then '-' else format(100.0*sum(wonAtSD)/sum(sawShowdown),1) end AS wmsd - ,case when sum(street1Seen) = 0 then 'oo' + ,case when sum(street1Seen) = 0 then '-' else format(100.0*sum(street1Aggr)/sum(street1Seen),1) end AS FlAFq - ,case when sum(street2Seen) = 0 then 'oo' + ,case when sum(street2Seen) = 0 then '-' else format(100.0*sum(street2Aggr)/sum(street2Seen),1) end AS TuAFq - ,case when sum(street3Seen) = 0 then 'oo' + ,case when sum(street3Seen) = 0 then '-' else format(100.0*sum(street3Aggr)/sum(street3Seen),1) end AS RvAFq - ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then 'oo' + ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-' else format(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr)) /(sum(street1Seen)+sum(street2Seen)+sum(street3Seen)),1) end AS PoFAFq ,format(sum(totalProfit)/100.0,2) AS Net - ,format((sum(totalProfit)/(gt.bigBlind+0.0)) / (sum(HDs)/100.0),2) + ,format((sum(totalProfit/(gt.bigBlind+0.0))) / (sum(HDs)/100.0),2) AS BBper100 ,format( (sum(totalProfit)/100.0) / sum(HDs), 4) AS Profitperhand + ,format( sum(activeSeats*HDs)/(sum(HDs)+0.0), 2) AS AvgSeats from Gametypes gt inner join Sites s on s.Id = gt.siteId inner join HudCache hc on hc.gameTypeId = gt.Id where hc.playerId in - # use here ? + and + and hc.activeSeats + and concat( '20', substring(hc.styleKey,2,2), '-', substring(hc.styleKey,4,2), '-' + , substring(hc.styleKey,6,2) ) group by gt.base ,gt.category ,upper(gt.limitType) ,s.name - ,gt.bigBlind - ,hc.gametypeId + + ,gtId ) stats inner join ( select # profit from handsplayers/handsactions - hprof.gameTypeId, sum(hprof.profit) sum_profit, + hprof.gtId, sum(hprof.profit) sum_profit, avg(hprof.profit/100.0) profitperhand, - variance(hprof.profit/100.0) variance + case when hprof.gtId = -1 then -999 + else variance(hprof.profit/100.0) + end as variance from - (select hp.handId, h.gameTypeId, hp.winnings, SUM(ha.amount) - costs, hp.winnings - SUM(ha.amount) profit - from HandsPlayers hp - inner join Hands h ON h.id = hp.handId - left join HandsActions ha ON ha.handPlayerId = hp.id - where hp.playerId in - # use here ? - and hp.tourneysPlayersId IS NULL - group by hp.handId, h.gameTypeId, hp.position, hp.winnings - ) hprof - group by hprof.gameTypeId + (select hp.handId, as gtId, hp.totalProfit as profit + from HandsPlayers hp + inner join Hands h ON h.id = hp.handId + where hp.playerId in + and hp.tourneysPlayersId IS NULL + and date_format(h.handStart, '%Y-%m-%d') + group by hp.handId, gtId, hp.totalProfit + ) hprof + group by hprof.gtId ) hprof2 - on hprof2.gameTypeId = stats.gameTypeId - order by stats.category, stats.limittype, stats.bigBlind""" + on hprof2.gtId = stats.gtId + order by stats.category, stats.limittype, stats.bigBlindDesc desc """ elif(self.dbname == 'PostgreSQL'): self.query['playerStats'] = """ SELECT upper(stats.limitType) || ' ' || initcap(stats.category) || ' ' - || stats.name || ' $' - || trim(leading ' ' from - case when stats.bigBlind < 100 then to_char(stats.bigBlind/100.0,'0D00') - else to_char(stats.bigBlind/100.0,'99990') - end ) AS Game - ,stats.n - ,stats.vpip - ,stats.pfr - ,stats.saw_f - ,stats.sawsd - ,stats.wtsdwsf - ,stats.wmsd - ,stats.FlAFq - ,stats.TuAFq - ,stats.RvAFq - ,stats.PoFAFq - /* if you have handsactions data the next 3 fields should give same answer as - following 3 commented out fields */ - ,stats.Net - ,stats.BBper100 - ,stats.Profitperhand - /*,to_char(hprof2.sum_profit/100.0,'9G999G990D00') AS Net - ,to_char((hprof2.sum_profit/(stats.bigBlind+0.0)) / (stats.n/100.0), '990D00') - AS BBper100 - ,hprof2.profitperhand AS Profitperhand - */ - ,round(hprof2.variance,2) AS Variance + || stats.name || ' ' + || stats.bigBlindDesc AS Game + ,stats.n + ,stats.vpip + ,stats.pfr + ,stats.pf3 + ,stats.steals + ,stats.saw_f + ,stats.sawsd + ,stats.wtsdwsf + ,stats.wmsd + ,stats.FlAFq + ,stats.TuAFq + ,stats.RvAFq + ,stats.PoFAFq + ,stats.Net + ,stats.BBper100 + ,stats.Profitperhand + ,case when hprof2.variance = -999 then '-' + else to_char(hprof2.variance, '0D00') + end AS Variance + ,AvgSeats FROM (select gt.base ,gt.category - ,upper(gt.limitType) as limitType + ,upper(gt.limitType) AS limitType ,s.name - ,gt.bigBlind - ,hc.gametypeId + , AS bigBlindDesc + , AS gtId ,sum(HDs) as n - ,to_char(100.0*sum(street0VPI)/sum(HDs),'90D0') AS vpip - ,to_char(100.0*sum(street0Aggr)/sum(HDs),'90D0') AS pfr - ,to_char(100.0*sum(street1Seen)/sum(HDs),'90D0') AS saw_f - ,to_char(100.0*sum(sawShowdown)/sum(HDs),'90D0') AS sawsd - ,case when sum(street1Seen) = 0 then 'oo' + ,to_char(100.0*sum(street0VPI)/sum(HDs),'990D0') AS vpip + ,to_char(100.0*sum(street0Aggr)/sum(HDs),'90D0') AS pfr + ,case when sum(street0_3Bchance) = 0 then '0' + else to_char(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),'90D0') + end AS pf3 + ,case when sum(stealattemptchance) = 0 then '-' + else to_char(100.0*sum(stealattempted)/sum(stealattemptchance),'90D0') + end AS steals + ,to_char(100.0*sum(street1Seen)/sum(HDs),'90D0') AS saw_f + ,to_char(100.0*sum(sawShowdown)/sum(HDs),'90D0') AS sawsd + ,case when sum(street1Seen) = 0 then '-' else to_char(100.0*sum(sawShowdown)/sum(street1Seen),'90D0') end AS wtsdwsf - ,case when sum(sawShowdown) = 0 then 'oo' + ,case when sum(sawShowdown) = 0 then '-' else to_char(100.0*sum(wonAtSD)/sum(sawShowdown),'90D0') end AS wmsd - ,case when sum(street1Seen) = 0 then 'oo' + ,case when sum(street1Seen) = 0 then '-' else to_char(100.0*sum(street1Aggr)/sum(street1Seen),'90D0') end AS FlAFq - ,case when sum(street2Seen) = 0 then 'oo' + ,case when sum(street2Seen) = 0 then '-' else to_char(100.0*sum(street2Aggr)/sum(street2Seen),'90D0') end AS TuAFq - ,case when sum(street3Seen) = 0 then 'oo' + ,case when sum(street3Seen) = 0 then '-' else to_char(100.0*sum(street3Aggr)/sum(street3Seen),'90D0') end AS RvAFq - ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then 'oo' + ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-' else to_char(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr)) /(sum(street1Seen)+sum(street2Seen)+sum(street3Seen)),'90D0') end AS PoFAFq ,round(sum(totalProfit)/100.0,2) AS Net - ,to_char((sum(totalProfit)/(gt.bigBlind+0.0)) / (sum(HDs)/100.0), '990D00') + ,to_char((sum(totalProfit/(gt.bigBlind+0.0))) / (sum(HDs)/100.0), '990D00') AS BBper100 ,to_char(sum(totalProfit/100.0) / (sum(HDs)+0.0), '990D0000') AS Profitperhand + ,to_char(sum(activeSeats*HDs)/(sum(HDs)+0.0),'90D00') AS AvgSeats from Gametypes gt inner join Sites s on s.Id = gt.siteId inner join HudCache hc on hc.gameTypeId = gt.Id where hc.playerId in + and + and hc.activeSeats + and '20' || SUBSTR(hc.styleKey,2,2) || '-' || SUBSTR(hc.styleKey,4,2) || '-' + || SUBSTR(hc.styleKey,6,2) group by gt.base ,gt.category ,upper(gt.limitType) ,s.name - ,gt.bigBlind - ,hc.gametypeId + + ,gtId ) stats inner join ( select - hprof.gameTypeId, sum(hprof.profit) AS sum_profit, + hprof.gtId, sum(hprof.profit) AS sum_profit, avg(hprof.profit/100.0) AS profitperhand, - variance(hprof.profit/100.0) AS variance + case when hprof.gtId = -1 then -999 + else variance(hprof.profit/100.0) + end as variance from - (select hp.handId, - h.gameTypeId, - hp.winnings, - SUM(ha.amount) as costs, - hp.winnings - SUM(ha.amount) as profit - from HandsPlayers hp - inner join Hands h ON (h.id = hp.handId) - left join HandsActions ha ON (ha.handPlayerId = hp.id) - where hp.playerId in - and hp.tourneysPlayersId IS NULL - group by hp.handId, h.gameTypeId, hp.position, hp.winnings - ) hprof - group by hprof.gameTypeId + (select hp.handId, as gtId, hp.totalProfit as profit + from HandsPlayers hp + inner join Hands h ON (h.id = hp.handId) + where hp.playerId in + and hp.tourneysPlayersId IS NULL + and to_char(h.handStart, 'YYYY-MM-DD') + group by hp.handId, gtId, hp.totalProfit + ) hprof + group by hprof.gtId ) hprof2 - on hprof2.gameTypeId = stats.gameTypeId - order by stats.base, stats.limittype, stats.bigBlind""" + on hprof2.gtId = stats.gtId + order by stats.base, stats.limittype, stats.bigBlindDesc desc """ elif(self.dbname == 'SQLite'): self.query['playerStats'] = """ """ @@ -848,11 +1193,8 @@ class FpdbSQLQueries: SELECT concat(upper(stats.limitType), ' ' ,concat(upper(substring(stats.category,1,1)),substring(stats.category,2) ), ' ' - ,stats.name, ' $' - ,cast(trim(leading ' ' from - case when stats.bigBlind < 100 then format(stats.bigBlind/100.0,2) - else format(stats.bigBlind/100.0,0) - end ) as char) + ,stats.name, ' ' + ,cast(stats.bigBlindDesc as char) ) AS Game ,case when stats.PlPosition = -2 then 'BB' when stats.PlPosition = -1 then 'SB' @@ -865,6 +1207,8 @@ class FpdbSQLQueries: ,stats.n ,stats.vpip ,stats.pfr + ,stats.pf3 + ,stats.steals ,stats.saw_f ,stats.sawsd ,stats.wtsdwsf @@ -873,25 +1217,21 @@ class FpdbSQLQueries: ,stats.TuAFq ,stats.RvAFq ,stats.PoFAFq - /* if you have handsactions data the next 3 fields should give same answer as - following 3 commented out fields */ ,stats.Net ,stats.BBper100 ,stats.Profitperhand - /*,format(hprof2.sum_profit/100.0,2) AS Net - ,format((hprof2.sum_profit/(stats.bigBlind+0.0)) / (stats.n/100.0),2) - AS BBlPer100 - ,hprof2.profitperhand AS Profitperhand - */ - ,format(hprof2.variance,2) AS Variance + ,case when hprof2.variance = -999 then '-' + else format(hprof2.variance, 2) + end AS Variance + ,stats.AvgSeats FROM (select /* stats from hudcache */ gt.base ,gt.category - ,upper(gt.limitType) as limitType + ,upper(gt.limitType) AS limitType ,s.name - ,gt.bigBlind - ,hc.gametypeId + , AS bigBlindDesc + , AS gtId ,case when hc.position = 'B' then -2 when hc.position = 'S' then -1 when hc.position = 'D' then 0 @@ -901,49 +1241,60 @@ class FpdbSQLQueries: else 9 end as PlPosition ,sum(HDs) AS n - ,format(100.0*sum(street0VPI)/sum(HDs),1) AS vpip - ,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr - ,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f - ,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd - ,case when sum(street1Seen) = 0 then 'oo' + ,format(100.0*sum(street0VPI)/sum(HDs),1) AS vpip + ,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr + ,case when sum(street0_3Bchance) = 0 then '0' + else format(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),1) + end AS pf3 + ,case when sum(stealattemptchance) = 0 then '-' + else format(100.0*sum(stealattempted)/sum(stealattemptchance),1) + end AS steals + ,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f + ,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd + ,case when sum(street1Seen) = 0 then '-' else format(100.0*sum(sawShowdown)/sum(street1Seen),1) end AS wtsdwsf - ,case when sum(sawShowdown) = 0 then 'oo' + ,case when sum(sawShowdown) = 0 then '-' else format(100.0*sum(wonAtSD)/sum(sawShowdown),1) end AS wmsd - ,case when sum(street1Seen) = 0 then 'oo' + ,case when sum(street1Seen) = 0 then '-' else format(100.0*sum(street1Aggr)/sum(street1Seen),1) end AS FlAFq - ,case when sum(street2Seen) = 0 then 'oo' + ,case when sum(street2Seen) = 0 then '-' else format(100.0*sum(street2Aggr)/sum(street2Seen),1) end AS TuAFq - ,case when sum(street3Seen) = 0 then 'oo' + ,case when sum(street3Seen) = 0 then '-' else format(100.0*sum(street3Aggr)/sum(street3Seen),1) end AS RvAFq - ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then 'oo' + ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-' else format(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr)) /(sum(street1Seen)+sum(street2Seen)+sum(street3Seen)),1) end AS PoFAFq ,format(sum(totalProfit)/100.0,2) AS Net - ,format((sum(totalProfit)/(gt.bigBlind+0.0)) / (sum(HDs)/100.0),2) + ,format((sum(totalProfit/(gt.bigBlind+0.0))) / (sum(HDs)/100.0),2) AS BBper100 ,format( (sum(totalProfit)/100.0) / sum(HDs), 4) AS Profitperhand + ,format( sum(activeSeats*HDs)/(sum(HDs)+0.0), 2) AS AvgSeats from Gametypes gt inner join Sites s on s.Id = gt.siteId inner join HudCache hc on hc.gameTypeId = gt.Id where hc.playerId in - # use here ? + and + and hc.activeSeats + and concat( '20', substring(hc.styleKey,2,2), '-', substring(hc.styleKey,4,2), '-' + , substring(hc.styleKey,6,2) ) group by gt.base ,gt.category ,upper(gt.limitType) ,s.name - ,gt.bigBlind - ,hc.gametypeId + + ,gtId + ,PlPosition ) stats inner join ( select # profit from handsplayers/handsactions - hprof.gameTypeId, + hprof.gtId, case when hprof.position = 'B' then -2 when hprof.position = 'S' then -1 when hprof.position in ('3','4') then 2 @@ -952,73 +1303,162 @@ class FpdbSQLQueries: end as PlPosition, sum(hprof.profit) as sum_profit, avg(hprof.profit/100.0) as profitperhand, - variance(hprof.profit/100.0) as variance + case when hprof.gtId = -1 then -999 + else variance(hprof.profit/100.0) + end as variance from - (select hp.handId, h.gameTypeId, hp.position, hp.winnings, SUM(ha.amount) - costs, hp.winnings - SUM(ha.amount) profit - from HandsPlayers hp - inner join Hands h ON h.id = hp.handId - left join HandsActions ha ON ha.handPlayerId = hp.id - where hp.playerId in - # use here ? - and hp.tourneysPlayersId IS NULL - group by hp.handId, h.gameTypeId, hp.position, hp.winnings - ) hprof - group by hprof.gameTypeId, PlPosition + (select hp.handId, as gtId, hp.position + , hp.totalProfit as profit + from HandsPlayers hp + inner join Hands h ON (h.id = hp.handId) + where hp.playerId in + and hp.tourneysPlayersId IS NULL + and date_format(h.handStart, '%Y-%m-%d') + group by hp.handId, gtId, hp.position, hp.totalProfit + ) hprof + group by hprof.gtId, PlPosition ) hprof2 - on ( hprof2.gameTypeId = stats.gameTypeId + on ( hprof2.gtId = stats.gtId and hprof2.PlPosition = stats.PlPosition) - order by stats.category, stats.limittype, stats.bigBlind, cast(stats.PlPosition as signed) + order by stats.category, stats.limitType, stats.bigBlindDesc desc + , cast(stats.PlPosition as signed) """ elif(self.dbname == 'PostgreSQL'): self.query['playerStatsByPosition'] = """ select /* stats from hudcache */ - hc.position AS pl_position - ,sum(HDs) as n - ,to_char(round(100.0*sum(street0VPI)/sum(HDs)),'90D0') AS vpip - ,to_char(round(100.0*sum(street0Aggr)/sum(HDs)),'90D0') AS pfr - ,to_char(round(100.0*sum(street1Seen)/sum(HDs)),'90D0') AS saw_f - ,to_char(round(100.0*sum(sawShowdown)/sum(HDs)),'90D0') AS sawsd - ,case when sum(street1Seen) = 0 then 'oo' - else to_char(round(100.0*sum(sawShowdown)/sum(street1Seen)),'90D0') - end AS wtsdwsf - ,case when sum(sawShowdown) = 0 then 'oo' - else to_char(round(100.0*sum(wonAtSD)/sum(sawShowdown)),'90D0') - end AS wmsd - ,case when sum(street1Seen) = 0 then 'oo' - else to_char(round(100.0*sum(street1Aggr)/sum(street1Seen)),'90D0') - end AS FlAFq - ,case when sum(street2Seen) = 0 then 'oo' - else to_char(round(100.0*sum(street2Aggr)/sum(street2Seen)),'90D0') - end AS TuAFq - ,case when sum(street3Seen) = 0 then 'oo' - else to_char(round(100.0*sum(street3Aggr)/sum(street3Seen)),'90D0') - end AS RvAFq - ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then 'oo' - else to_char(round(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr)) - /(sum(street1Seen)+sum(street2Seen)+sum(street3Seen))),'90D0') - end AS PoFAFq - ,to_char(sum(totalProfit)/100.0,'9G999G990D00') AS Net - ,case when sum(HDs) = 0 then 'oo' - else to_char((sum(totalProfit)/(gt.bigBlind+0.0)) / (sum(HDs)/100.0), '990D00') - end AS BBper100 - from Gametypes gt - inner join Sites s on (s.Id = gt.siteId) - inner join HudCache hc on (hc.gameTypeId = gt.Id) - inner join Players p on (p.id = hc.playerId) - where hc.playerId in - and gt.type = 'ring' - and gt.id = /* must specify gametypeid */ - /* and stats.n > 100 optional stat-based queries */ - group by pl_position, gt.bigblind - order by case when hc.position = 'B' then -2 - when hc.position = 'S' then -1 - when hc.position = 'D' then 0 - when hc.position = 'C' then 1 - when hc.position = 'M' then 2 - when hc.position = 'E' then 5 - else 9 - end + upper(stats.limitType) || ' ' + || upper(substr(stats.category,1,1)) || substr(stats.category,2) || ' ' + || stats.name || ' ' + || stats.bigBlindDesc AS Game + ,case when stats.PlPosition = -2 then 'BB' + when stats.PlPosition = -1 then 'SB' + when stats.PlPosition = 0 then 'Btn' + when stats.PlPosition = 1 then 'CO' + when stats.PlPosition = 2 then 'MP' + when stats.PlPosition = 5 then 'EP' + else '??' + end AS PlPosition + ,stats.n + ,stats.vpip + ,stats.pfr + ,stats.pf3 + ,stats.steals + ,stats.saw_f + ,stats.sawsd + ,stats.wtsdwsf + ,stats.wmsd + ,stats.FlAFq + ,stats.TuAFq + ,stats.RvAFq + ,stats.PoFAFq + ,stats.Net + ,stats.BBper100 + ,stats.Profitperhand + ,case when hprof2.variance = -999 then '-' + else to_char(hprof2.variance, '0D00') + end AS Variance + ,stats.AvgSeats + FROM + (select /* stats from hudcache */ + gt.base + ,gt.category + ,upper(gt.limitType) AS limitType + ,s.name + , AS bigBlindDesc + , AS gtId + ,case when hc.position = 'B' then -2 + when hc.position = 'S' then -1 + when hc.position = 'D' then 0 + when hc.position = 'C' then 1 + when hc.position = 'M' then 2 + when hc.position = 'E' then 5 + else 9 + end AS PlPosition + ,sum(HDs) AS n + ,to_char(round(100.0*sum(street0VPI)/sum(HDs)),'990D0') AS vpip + ,to_char(round(100.0*sum(street0Aggr)/sum(HDs)),'90D0') AS pfr + ,case when sum(street0_3Bchance) = 0 then '0' + else to_char(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),'90D0') + end AS pf3 + ,case when sum(stealattemptchance) = 0 then '-' + else to_char(100.0*sum(stealattempted)/sum(stealattemptchance),'90D0') + end AS steals + ,to_char(round(100.0*sum(street1Seen)/sum(HDs)),'90D0') AS saw_f + ,to_char(round(100.0*sum(sawShowdown)/sum(HDs)),'90D0') AS sawsd + ,case when sum(street1Seen) = 0 then '-' + else to_char(round(100.0*sum(sawShowdown)/sum(street1Seen)),'90D0') + end AS wtsdwsf + ,case when sum(sawShowdown) = 0 then '-' + else to_char(round(100.0*sum(wonAtSD)/sum(sawShowdown)),'90D0') + end AS wmsd + ,case when sum(street1Seen) = 0 then '-' + else to_char(round(100.0*sum(street1Aggr)/sum(street1Seen)),'90D0') + end AS FlAFq + ,case when sum(street2Seen) = 0 then '-' + else to_char(round(100.0*sum(street2Aggr)/sum(street2Seen)),'90D0') + end AS TuAFq + ,case when sum(street3Seen) = 0 then '-' + else to_char(round(100.0*sum(street3Aggr)/sum(street3Seen)),'90D0') + end AS RvAFq + ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-' + else to_char(round(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr)) + /(sum(street1Seen)+sum(street2Seen)+sum(street3Seen))),'90D0') + end AS PoFAFq + ,to_char(sum(totalProfit)/100.0,'9G999G990D00') AS Net + ,case when sum(HDs) = 0 then '0' + else to_char(sum(totalProfit/(gt.bigBlind+0.0)) / (sum(HDs)/100.0), '990D00') + end AS BBper100 + ,case when sum(HDs) = 0 then '0' + else to_char( (sum(totalProfit)/100.0) / sum(HDs), '90D0000') + end AS Profitperhand + ,to_char(sum(activeSeats*HDs)/(sum(HDs)+0.0),'90D00') AS AvgSeats + from Gametypes gt + inner join Sites s on (s.Id = gt.siteId) + inner join HudCache hc on (hc.gameTypeId = gt.Id) + where hc.playerId in + and + and hc.activeSeats + and '20' || SUBSTR(hc.styleKey,2,2) || '-' || SUBSTR(hc.styleKey,4,2) || '-' + || SUBSTR(hc.styleKey,6,2) + group by gt.base + ,gt.category + ,upper(gt.limitType) + ,s.name + + ,gtId + + ,PlPosition + ) stats + inner join + ( select /* profit from handsplayers/handsactions */ + hprof.gtId, + case when hprof.position = 'B' then -2 + when hprof.position = 'S' then -1 + when hprof.position in ('3','4') then 2 + when hprof.position in ('6','7') then 5 + else cast(hprof.position as smallint) + end as PlPosition, + sum(hprof.profit) as sum_profit, + avg(hprof.profit/100.0) as profitperhand, + case when hprof.gtId = -1 then -999 + else variance(hprof.profit/100.0) + end as variance + from + (select hp.handId, as gtId, hp.position + , hp.totalProfit as profit + from HandsPlayers hp + inner join Hands h ON (h.id = hp.handId) + where hp.playerId in + and hp.tourneysPlayersId IS NULL + and to_char(h.handStart, 'YYYY-MM-DD') + group by hp.handId, gameTypeId, hp.position, hp.totalProfit + ) hprof + group by hprof.gtId, PlPosition + ) hprof2 + on ( hprof2.gtId = stats.gtId + and hprof2.PlPosition = stats.PlPosition) + order by stats.category, stats.limitType, stats.bigBlindDesc desc + , cast(stats.PlPosition as smallint) """ elif(self.dbname == 'SQLite'): self.query['playerStatsByPosition'] = """ """ @@ -1084,24 +1524,24 @@ class FpdbSQLQueries: ,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr ,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f ,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd - ,case when sum(street1Seen) = 0 then 'oo' + ,case when sum(street1Seen) = 0 then '-' else format(100.0*sum(sawShowdown)/sum(street1Seen),1) end AS wtsdwsf - ,case when sum(sawShowdown) = 0 then 'oo' + ,case when sum(sawShowdown) = 0 then '-' end AS wtsdwsf - ,case when sum(sawShowdown) = 0 then 'oo' + ,case when sum(sawShowdown) = 0 then '-' else format(100.0*sum(wonAtSD)/sum(sawShowdown),1) end AS wmsd - ,case when sum(street1Seen) = 0 then 'oo' + ,case when sum(street1Seen) = 0 then '-' else format(100.0*sum(street1Aggr)/sum(street1Seen),1) end AS FlAFq - ,case when sum(street2Seen) = 0 then 'oo' + ,case when sum(street2Seen) = 0 then '-' else format(100.0*sum(street2Aggr)/sum(street2Seen),1) end AS TuAFq - ,case when sum(street3Seen) = 0 then 'oo' + ,case when sum(street3Seen) = 0 then '-' else format(100.0*sum(street3Aggr)/sum(street3Seen),1) end AS RvAFq - ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then 'oo' + ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-' else format(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr)) /(sum(street1Seen)+sum(street2Seen)+sum(street3Seen)),1) end AS PoFAFq @@ -1136,11 +1576,11 @@ class FpdbSQLQueries: variance(hprof.profit/100.0) as variance, count(*) as n from - (select hp.handId, h.gameTypeId, hp.position, hp.winnings, SUM(ha.amount) - costs, hp.winnings - SUM(ha.amount) profit + (select hp.handId, h.gameTypeId, hp.position, hp.winnings, SUM(ha.amount) as costs + , hp.winnings - SUM(ha.amount) as profit from HandsPlayers hp - inner join Hands h ON h.id = hp.handId - left join HandsActions ha ON ha.handPlayerId = hp.id + inner join Hands h ON h.id = hp.handId + left join HandsActions ha ON ha.handsPlayerId = hp.id where hp.playerId in # use here ? and hp.tourneysPlayersId IS NULL @@ -1153,6 +1593,317 @@ class FpdbSQLQueries: and hprof2.PlPosition = stats.PlPosition) order by stats.category, stats.limittype, stats.bigBlind, cast(stats.PlPosition as signed) """ + if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): + self.query['getGames'] = """SELECT DISTINCT category from Gametypes""" + + if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): + self.query['getLimits'] = """SELECT DISTINCT bigBlind from Gametypes ORDER by bigBlind DESC""" + + + #################################### + # Queries to rebuild/modify hudcache + #################################### + + if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): + self.query['clearHudCache'] = """DELETE FROM HudCache""" + + if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): + self.query['rebuildHudCache'] = """ + INSERT INTO HudCache + (gametypeId + ,playerId + ,activeSeats + ,position + ,tourneyTypeId + ,styleKey + ,HDs + ,wonWhenSeenStreet1 + ,wonAtSD + ,street0VPI + ,street0Aggr + ,street0_3BChance + ,street0_3BDone + ,street1Seen + ,street2Seen + ,street3Seen + ,street4Seen + ,sawShowdown + ,street1Aggr + ,street2Aggr + ,street3Aggr + ,street4Aggr + ,otherRaisedStreet1 + ,otherRaisedStreet2 + ,otherRaisedStreet3 + ,otherRaisedStreet4 + ,foldToOtherRaisedStreet1 + ,foldToOtherRaisedStreet2 + ,foldToOtherRaisedStreet3 + ,foldToOtherRaisedStreet4 + ,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 + ) + SELECT h.gametypeId + ,hp.playerId + ,h.seats + ,case when hp.position = 'B' then 'B' + when hp.position = 'S' then 'S' + when hp.position = '0' then 'D' + when hp.position = '1' then 'C' + when hp.position = '2' then 'M' + when hp.position = '3' then 'M' + when hp.position = '4' then 'M' + when hp.position = '5' then 'E' + when hp.position = '6' then 'E' + when hp.position = '7' then 'E' + when hp.position = '8' then 'E' + when hp.position = '9' then 'E' + else 'E' + end AS hc_position + ,hp.tourneyTypeId + ,date_format(h.handStart, 'd%y%m%d') + ,count(1) + ,sum(wonWhenSeenStreet1) + ,sum(wonAtSD) + ,sum(CAST(street0VPI as integer)) + ,sum(CAST(street0Aggr as integer)) + ,sum(CAST(street0_3BChance as integer)) + ,sum(CAST(street0_3BDone as integer)) + ,sum(CAST(street1Seen as integer)) + ,sum(CAST(street2Seen as integer)) + ,sum(CAST(street3Seen as integer)) + ,sum(CAST(street4Seen as integer)) + ,sum(CAST(sawShowdown as integer)) + ,sum(CAST(street1Aggr as integer)) + ,sum(CAST(street2Aggr as integer)) + ,sum(CAST(street3Aggr as integer)) + ,sum(CAST(street4Aggr as integer)) + ,sum(CAST(otherRaisedStreet1 as integer)) + ,sum(CAST(otherRaisedStreet2 as integer)) + ,sum(CAST(otherRaisedStreet3 as integer)) + ,sum(CAST(otherRaisedStreet4 as integer)) + ,sum(CAST(foldToOtherRaisedStreet1 as integer)) + ,sum(CAST(foldToOtherRaisedStreet2 as integer)) + ,sum(CAST(foldToOtherRaisedStreet3 as integer)) + ,sum(CAST(foldToOtherRaisedStreet4 as integer)) + ,sum(CAST(stealAttemptChance as integer)) + ,sum(CAST(stealAttempted as integer)) + ,sum(CAST(foldBbToStealChance as integer)) + ,sum(CAST(foldedBbToSteal as integer)) + ,sum(CAST(foldSbToStealChance as integer)) + ,sum(CAST(foldedSbToSteal as integer)) + ,sum(CAST(street1CBChance as integer)) + ,sum(CAST(street1CBDone as integer)) + ,sum(CAST(street2CBChance as integer)) + ,sum(CAST(street2CBDone as integer)) + ,sum(CAST(street3CBChance as integer)) + ,sum(CAST(street3CBDone as integer)) + ,sum(CAST(street4CBChance as integer)) + ,sum(CAST(street4CBDone as integer)) + ,sum(CAST(foldToStreet1CBChance as integer)) + ,sum(CAST(foldToStreet1CBDone as integer)) + ,sum(CAST(foldToStreet2CBChance as integer)) + ,sum(CAST(foldToStreet2CBDone as integer)) + ,sum(CAST(foldToStreet3CBChance as integer)) + ,sum(CAST(foldToStreet3CBDone as integer)) + ,sum(CAST(foldToStreet4CBChance as integer)) + ,sum(CAST(foldToStreet4CBDone as integer)) + ,sum(CAST(totalProfit as integer)) + ,sum(CAST(street1CheckCallRaiseChance as integer)) + ,sum(CAST(street1CheckCallRaiseDone as integer)) + ,sum(CAST(street2CheckCallRaiseChance as integer)) + ,sum(CAST(street2CheckCallRaiseDone as integer)) + ,sum(CAST(street3CheckCallRaiseChance as integer)) + ,sum(CAST(street3CheckCallRaiseDone as integer)) + ,sum(CAST(street4CheckCallRaiseChance as integer)) + ,sum(CAST(street4CheckCallRaiseDone as integer)) + FROM HandsPlayers hp + INNER JOIN Hands h ON (h.id = hp.handId) + GROUP BY h.gametypeId + ,hp.playerId + ,h.seats + ,hc_position + ,hp.tourneyTypeId + ,date_format(h.handStart, 'd%y%m%d') +""" + elif (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): + self.query['rebuildHudCache'] = """ + INSERT INTO HudCache + (gametypeId + ,playerId + ,activeSeats + ,position + ,tourneyTypeId + ,styleKey + ,HDs + ,wonWhenSeenStreet1 + ,wonAtSD + ,street0VPI + ,street0Aggr + ,street0_3BChance + ,street0_3BDone + ,street1Seen + ,street2Seen + ,street3Seen + ,street4Seen + ,sawShowdown + ,street1Aggr + ,street2Aggr + ,street3Aggr + ,street4Aggr + ,otherRaisedStreet1 + ,otherRaisedStreet2 + ,otherRaisedStreet3 + ,otherRaisedStreet4 + ,foldToOtherRaisedStreet1 + ,foldToOtherRaisedStreet2 + ,foldToOtherRaisedStreet3 + ,foldToOtherRaisedStreet4 + ,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 + ) + SELECT h.gametypeId + ,hp.playerId + ,h.seats + ,case when hp.position = 'B' then 'B' + when hp.position = 'S' then 'S' + when hp.position = '0' then 'D' + when hp.position = '1' then 'C' + when hp.position = '2' then 'M' + when hp.position = '3' then 'M' + when hp.position = '4' then 'M' + when hp.position = '5' then 'E' + when hp.position = '6' then 'E' + when hp.position = '7' then 'E' + when hp.position = '8' then 'E' + when hp.position = '9' then 'E' + else 'E' + end AS hc_position + ,hp.tourneyTypeId + ,'d' || to_char(h.handStart, 'YYMMDD') + ,count(1) + ,sum(wonWhenSeenStreet1) + ,sum(wonAtSD) + ,sum(CAST(street0VPI as integer)) + ,sum(CAST(street0Aggr as integer)) + ,sum(CAST(street0_3BChance as integer)) + ,sum(CAST(street0_3BDone as integer)) + ,sum(CAST(street1Seen as integer)) + ,sum(CAST(street2Seen as integer)) + ,sum(CAST(street3Seen as integer)) + ,sum(CAST(street4Seen as integer)) + ,sum(CAST(sawShowdown as integer)) + ,sum(CAST(street1Aggr as integer)) + ,sum(CAST(street2Aggr as integer)) + ,sum(CAST(street3Aggr as integer)) + ,sum(CAST(street4Aggr as integer)) + ,sum(CAST(otherRaisedStreet1 as integer)) + ,sum(CAST(otherRaisedStreet2 as integer)) + ,sum(CAST(otherRaisedStreet3 as integer)) + ,sum(CAST(otherRaisedStreet4 as integer)) + ,sum(CAST(foldToOtherRaisedStreet1 as integer)) + ,sum(CAST(foldToOtherRaisedStreet2 as integer)) + ,sum(CAST(foldToOtherRaisedStreet3 as integer)) + ,sum(CAST(foldToOtherRaisedStreet4 as integer)) + ,sum(CAST(stealAttemptChance as integer)) + ,sum(CAST(stealAttempted as integer)) + ,sum(CAST(foldBbToStealChance as integer)) + ,sum(CAST(foldedBbToSteal as integer)) + ,sum(CAST(foldSbToStealChance as integer)) + ,sum(CAST(foldedSbToSteal as integer)) + ,sum(CAST(street1CBChance as integer)) + ,sum(CAST(street1CBDone as integer)) + ,sum(CAST(street2CBChance as integer)) + ,sum(CAST(street2CBDone as integer)) + ,sum(CAST(street3CBChance as integer)) + ,sum(CAST(street3CBDone as integer)) + ,sum(CAST(street4CBChance as integer)) + ,sum(CAST(street4CBDone as integer)) + ,sum(CAST(foldToStreet1CBChance as integer)) + ,sum(CAST(foldToStreet1CBDone as integer)) + ,sum(CAST(foldToStreet2CBChance as integer)) + ,sum(CAST(foldToStreet2CBDone as integer)) + ,sum(CAST(foldToStreet3CBChance as integer)) + ,sum(CAST(foldToStreet3CBDone as integer)) + ,sum(CAST(foldToStreet4CBChance as integer)) + ,sum(CAST(foldToStreet4CBDone as integer)) + ,sum(CAST(totalProfit as integer)) + ,sum(CAST(street1CheckCallRaiseChance as integer)) + ,sum(CAST(street1CheckCallRaiseDone as integer)) + ,sum(CAST(street2CheckCallRaiseChance as integer)) + ,sum(CAST(street2CheckCallRaiseDone as integer)) + ,sum(CAST(street3CheckCallRaiseChance as integer)) + ,sum(CAST(street3CheckCallRaiseDone as integer)) + ,sum(CAST(street4CheckCallRaiseChance as integer)) + ,sum(CAST(street4CheckCallRaiseDone as integer)) + FROM HandsPlayers hp + INNER JOIN Hands h ON (h.id = hp.handId) + GROUP BY h.gametypeId + ,hp.playerId + ,h.seats + ,hc_position + ,hp.tourneyTypeId + ,to_char(h.handStart, 'YYMMDD') +""" + if __name__== "__main__": from optparse import OptionParser diff --git a/pyfpdb/GuiAutoImport.py b/pyfpdb/GuiAutoImport.py index 872c5c67..2b4c8b76 100755 --- a/pyfpdb/GuiAutoImport.py +++ b/pyfpdb/GuiAutoImport.py @@ -57,28 +57,55 @@ class GuiAutoImport (threading.Thread): self.database=settings['db-databaseName'] self.mainVBox=gtk.VBox(False,1) - self.mainVBox.show() - self.settingsHBox = gtk.HBox(False, 0) - self.mainVBox.pack_start(self.settingsHBox, False, True, 0) - self.settingsHBox.show() + hbox = gtk.HBox(True, 0) # contains 2 equal vboxes + self.mainVBox.pack_start(hbox, False, False, 0) + + vbox1 = gtk.VBox(True, 0) + hbox.pack_start(vbox1, True, True, 0) + vbox2 = gtk.VBox(True, 0) + hbox.pack_start(vbox2, True, True, 0) - self.intervalLabel = gtk.Label("Interval (ie. break) between imports in seconds:") - self.settingsHBox.pack_start(self.intervalLabel) - self.intervalLabel.show() + self.intervalLabel = gtk.Label("Time between imports in seconds:") + self.intervalLabel.set_alignment(xalign=1.0, yalign=0.5) + vbox1.pack_start(self.intervalLabel, True, True, 0) - self.intervalEntry=gtk.Entry() + hbox = gtk.HBox(False, 0) + vbox2.pack_start(hbox, True, True, 0) + self.intervalEntry = gtk.Entry() self.intervalEntry.set_text(str(self.config.get_import_parameters().get("interval"))) - self.settingsHBox.pack_start(self.intervalEntry) - self.intervalEntry.show() + hbox.pack_start(self.intervalEntry, False, False, 0) + lbl1 = gtk.Label() + hbox.pack_start(lbl1, expand=True, fill=True) - self.addSites(self.mainVBox) + lbl = gtk.Label('') + vbox1.pack_start(lbl, expand=True, fill=True) + lbl = gtk.Label('') + vbox2.pack_start(lbl, expand=True, fill=True) + + self.addSites(vbox1, vbox2) + + hbox = gtk.HBox(False, 0) + self.mainVBox.pack_start(hbox, expand=True, padding=3) + + hbox = gtk.HBox(False, 0) + self.mainVBox.pack_start(hbox, expand=False, padding=3) + + lbl1 = gtk.Label() + hbox.pack_start(lbl1, expand=True, fill=False) self.doAutoImportBool = False - self.startButton=gtk.ToggleButton("Start Autoimport") + self.startButton = gtk.ToggleButton(" _Start Autoimport ") self.startButton.connect("clicked", self.startClicked, "start clicked") - self.mainVBox.add(self.startButton) - self.startButton.show() + hbox.pack_start(self.startButton, expand=False, fill=False) + + lbl2 = gtk.Label() + hbox.pack_start(lbl2, expand=True, fill=False) + + hbox = gtk.HBox(False, 0) + hbox.show() + self.mainVBox.pack_start(hbox, expand=True, padding=3) + self.mainVBox.show_all() #end of GuiAutoImport.__init__ @@ -127,7 +154,7 @@ class GuiAutoImport (threading.Thread): # to watch. if widget.get_active(): # toggled on self.doAutoImportBool = True - widget.set_label(u'Stop Autoimport') + widget.set_label(u' _Stop Autoimport ') if self.pipe_to_hud is None: if os.name == 'nt': command = "python HUD_main.py" + " %s" % (self.database) @@ -163,7 +190,7 @@ class GuiAutoImport (threading.Thread): #print >>self.pipe_to_hud.stdin, "\n" self.pipe_to_hud.communicate('\n') # waits for process to terminate self.pipe_to_hud = None - self.startButton.set_label(u'Start Autoimport') + self.startButton.set_label(u' _Start Autoimport ') @@ -177,40 +204,41 @@ class GuiAutoImport (threading.Thread): #Create the site line given required info and setup callbacks #enabling and disabling sites from this interface not possible #expects a box to layout the line horizontally - def createSiteLine(self, hbox, site, iconpath, hhpath, filter_name, active = True): + def createSiteLine(self, hbox1, hbox2, site, iconpath, hhpath, filter_name, active = True): label = gtk.Label(site + " auto-import:") - hbox.pack_start(label, False, False, 0) + hbox1.pack_start(label, False, False, 3) label.show() dirPath=gtk.Entry() dirPath.set_text(hhpath) - hbox.pack_start(dirPath, False, True, 0) + hbox1.pack_start(dirPath, True, True, 3) dirPath.show() browseButton=gtk.Button("Browse...") browseButton.connect("clicked", self.browseClicked, [site] + [dirPath]) - hbox.pack_start(browseButton, False, False, 0) + hbox2.pack_start(browseButton, False, False, 3) browseButton.show() - label = gtk.Label(site + " filter:") - hbox.pack_start(label, False, False, 0) + label = gtk.Label(' ' + site + " filter:") + hbox2.pack_start(label, False, False, 3) label.show() filter=gtk.Entry() filter.set_text(filter_name) - hbox.pack_start(filter, False, True, 0) + hbox2.pack_start(filter, True, True, 3) filter.show() - def addSites(self, vbox): + def addSites(self, vbox1, vbox2): the_sites = self.config.get_supported_sites() for site in the_sites: - pathHBox = gtk.HBox(False, 0) - vbox.pack_start(pathHBox, False, True, 0) - pathHBox.show() + pathHBox1 = gtk.HBox(False, 0) + vbox1.pack_start(pathHBox1, False, True, 0) + pathHBox2 = gtk.HBox(False, 0) + vbox2.pack_start(pathHBox2, False, True, 0) params = self.config.get_site_parameters(site) paths = self.config.get_default_paths(site) - self.createSiteLine(pathHBox, site, False, paths['hud-defaultPath'], params['converter'], params['enabled']) + self.createSiteLine(pathHBox1, pathHBox2, site, False, paths['hud-defaultPath'], params['converter'], params['enabled']) self.input_settings[site] = [paths['hud-defaultPath']] + [params['converter']] if __name__== "__main__": diff --git a/pyfpdb/GuiBulkImport.py b/pyfpdb/GuiBulkImport.py index 5284ae9e..77dee9b7 100755 --- a/pyfpdb/GuiBulkImport.py +++ b/pyfpdb/GuiBulkImport.py @@ -30,7 +30,6 @@ import gtk # fpdb/FreePokerTools modules import fpdb_simple import fpdb_import -import fpdb_db import Configuration class GuiBulkImport(): @@ -66,13 +65,16 @@ class GuiBulkImport(): self.importer.setDropIndexes(cb_model[cb_index][0]) else: self.importer.setDropIndexes("auto") - hhc=self.cbfilter.get_model()[self.cbfilter.get_active()][0] + sitename = self.cbfilter.get_model()[self.cbfilter.get_active()][0] self.lab_info.set_text("Importing") - self.importer.addBulkImportImportFileOrDir(self.inputFile,filter=hhc) + self.importer.addBulkImportImportFileOrDir(self.inputFile, site = sitename) self.importer.setCallHud(False) starttime = time() (stored, dups, partial, errs, ttime) = self.importer.runImport() + ttime = time() - starttime + if ttime == 0: + ttime = 1 print 'GuiBulkImport.import_dir done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %d/sec'\ % (stored, dups, partial, errs, ttime, stored / ttime) self.importer.clearFileList() @@ -83,8 +85,7 @@ class GuiBulkImport(): """returns the vbox of this thread""" return self.vbox - def __init__(self, db, settings, config): - self.db = db # this is an instance of fpdb_db + def __init__(self, settings, config): self.settings = settings self.config = config self.importer = fpdb_import.Importer(self, self.settings, @@ -175,11 +176,9 @@ class GuiBulkImport(): # ComboBox - filter self.cbfilter = gtk.combo_box_new_text() - self.cbfilter.append_text("passthrough") - self.cbfilter.append_text("BetfairToFpdb") - self.cbfilter.append_text("EverleafToFpdb") - self.cbfilter.append_text("FulltiltToFpdb") - self.cbfilter.append_text("PokerStarsToFpdb") + for w in self.config.hhcs: + print w + self.cbfilter.append_text(w) self.cbfilter.set_active(0) self.table.attach(self.cbfilter, 3, 4, 2, 3, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK) self.cbfilter.show() @@ -220,8 +219,8 @@ def main(argv=None): help="Input file in quiet mode") parser.add_option("-q", "--quiet", action="store_false", dest="gui", default=True, help="don't start gui; deprecated (just give a filename with -f).") - parser.add_option("-c", "--convert", dest="filtername", default="passthrough", metavar="FILTER", - help="Conversion filter (*passthrough, FullTiltToFpdb, PokerStarsToFpdb, EverleafToFpdb)") + parser.add_option("-c", "--convert", dest="filtername", default="PokerStars", metavar="FILTER", + help="Conversion filter (*Full Tilt Poker, PokerStars, Everleaf)") parser.add_option("-x", "--failOnError", action="store_true", default=False, 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", @@ -229,7 +228,6 @@ def main(argv=None): (options, sys.argv) = parser.parse_args(args = argv) config = Configuration.Config() - db = None settings = {} settings['minPrint'] = options.minPrint @@ -245,7 +243,7 @@ def main(argv=None): print '-q is deprecated. Just use "-f filename" instead' # This is because -q on its own causes an error, so -f is necessary and sufficient for cmd line use if not options.filename: - i = GuiBulkImport(db, settings, config) + i = GuiBulkImport(settings, config) main_window = gtk.Window() main_window.connect('destroy', destroy) main_window.add(i.vbox) @@ -256,7 +254,7 @@ def main(argv=None): importer = fpdb_import.Importer(False,settings, config) importer.setDropIndexes("auto") importer.setFailOnError(options.failOnError) - importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), filter=options.filtername) + importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername) importer.setCallHud(False) importer.runImport() importer.clearFileList() diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index 5afc4a92..cec91e61 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -39,269 +39,9 @@ except: import fpdb_import import fpdb_db +import Filters class GuiGraphViewer (threading.Thread): - def get_vbox(self): - """returns the vbox of this thread""" - return self.mainHBox - #end def get_vbox - - def clearGraphData(self): - self.fig.clf() - if self.canvas is not None: - self.canvas.destroy() - - self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea - - def generateGraph(self, widget, data): - self.clearGraphData() - - sitenos = [] - playerids = [] - - # Which sites are selected? - for site in self.sites: - if self.sites[site] == True: - sitenos.append(self.siteid[site]) - self.cursor.execute(self.sql.query['getPlayerId'], (self.heroes[site],)) - result = self.db.cursor.fetchall() - if len(result) == 1: - playerids.append(result[0][0]) - - if not sitenos: - #Should probably pop up here. - print "No sites selected - defaulting to PokerStars" - sitenos = [2] - - - if not playerids: - print "No player ids found" - return - - - #Set graph properties - self.ax = self.fig.add_subplot(111) - - #Get graph data from DB - starttime = time() - line = self.getRingProfitGraph(playerids, sitenos) - print "Graph generated in: %s" %(time() - starttime) - - self.ax.set_title("Profit graph for ring games") - - #Set axis labels and grid overlay properites - self.ax.set_xlabel("Hands", fontsize = 12) - self.ax.set_ylabel("$", fontsize = 12) - self.ax.grid(color='g', linestyle=':', linewidth=0.2) - if(line == None): - #TODO: Do something useful like alert user - print "No hands returned by graph query" - else: -# text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) - text = "All Hands, " + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) - - self.ax.annotate(text, - xy=(10, -10), - xycoords='axes points', - horizontalalignment='left', verticalalignment='top', - fontsize=10) - - #Draw plot - self.ax.plot(line,) - - self.graphBox.add(self.canvas) - self.canvas.show() - self.exportButton.set_sensitive(True) - #end of def showClicked - - def getRingProfitGraph(self, names, sites): - tmp = self.sql.query['getRingProfitAllHandsPlayerIdSite'] -# print "DEBUG: getRingProfitGraph" - start_date, end_date = self.__get_dates() - - if start_date == '': - start_date = '1970-01-01' - if end_date == '': - end_date = '2020-12-12' - - #Buggered if I can find a way to do this 'nicely' take a list of intergers and longs - # and turn it into a tuple readale by sql. - # [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829) - nametest = str(tuple(names)) - sitetest = str(tuple(sites)) - nametest = nametest.replace("L", "") - nametest = nametest.replace(",)",")") - sitetest = sitetest.replace(",)",")") - - #Must be a nicer way to deal with tuples of size 1 ie. (2,) - which makes sql barf - tmp = tmp.replace("", nametest) - tmp = tmp.replace("", sitetest) - tmp = tmp.replace("", start_date) - tmp = tmp.replace("", end_date) - -# print "DEBUG: sql query:" -# print tmp - self.cursor.execute(tmp) - #returns (HandId,Winnings,Costs,Profit) - winnings = self.db.cursor.fetchall() - - if(winnings == ()): - return None - - y=map(lambda x:float(x[3]), winnings) - line = cumsum(y) - return line/100 - #end of def getRingProfitGraph - - def createPlayerLine(self, hbox, site, player): - label = gtk.Label(site +" id:") - hbox.pack_start(label, False, False, 0) - label.show() - - pname = gtk.Entry() - pname.set_text(player) - 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 - pname.show() - - self.__set_hero_name(pname, site) - - def __set_hero_name(self, w, site): - self.heroes[site] = w.get_text() -# print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site]) - - def createSiteLine(self, hbox, site): - cb = gtk.CheckButton(site) - cb.connect('clicked', self.__set_site_select, site) - hbox.pack_start(cb, False, False, 0) - cb.show() - - def __set_site_select(self, w, site): - # This doesn't behave as intended - self.site only allows 1 site for the moment. - print w.get_active() - self.sites[site] = w.get_active() - print "self.sites[%s] set to %s" %(site, self.sites[site]) - - def fillPlayerFrame(self, vbox): - for site in self.conf.supported_sites.keys(): - pathHBox = gtk.HBox(False, 0) - vbox.pack_start(pathHBox, False, True, 0) - pathHBox.show() - - player = self.conf.supported_sites[site].screen_name - self.createPlayerLine(pathHBox, site, player) - - def fillSitesFrame(self, vbox): - for site in self.conf.supported_sites.keys(): - hbox = gtk.HBox(False, 0) - vbox.pack_start(hbox, False, True, 0) - hbox.show() - self.createSiteLine(hbox, site) - #Get db site id for filtering later - self.cursor.execute(self.sql.query['getSiteId'], (site,)) - result = self.db.cursor.fetchall() - if len(result) == 1: - self.siteid[site] = result[0][0] - else: - print "Either 0 or more than one site matched - EEK" - - def fillDateFrame(self, vbox): - # Hat tip to Mika Bostrom - calendar code comes from PokerStats - hbox = gtk.HBox() - vbox.pack_start(hbox, False, True, 0) - hbox.show() - - lbl_start = gtk.Label('From:') - lbl_start.show() - - btn_start = gtk.Button() - btn_start.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)) - btn_start.connect('clicked', self.__calendar_dialog, self.start_date) - btn_start.show() - - hbox.pack_start(lbl_start, expand=False, padding=3) - hbox.pack_start(btn_start, expand=False, padding=3) - hbox.pack_start(self.start_date, expand=False, padding=2) - self.start_date.show() - - #New row for end date - hbox = gtk.HBox() - vbox.pack_start(hbox, False, True, 0) - hbox.show() - - lbl_end = gtk.Label(' To:') - lbl_end.show() - btn_end = gtk.Button() - btn_end.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)) - btn_end.connect('clicked', self.__calendar_dialog, self.end_date) - btn_end.show() - - btn_clear = gtk.Button(label=' Clear Dates ') - btn_clear.connect('clicked', self.__clear_dates) - btn_clear.show() - - hbox.pack_start(lbl_end, expand=False, padding=3) - hbox.pack_start(btn_end, expand=False, padding=3) - hbox.pack_start(self.end_date, expand=False, padding=2) - self.end_date.show() - - hbox.pack_start(btn_clear, expand=False, padding=15) - - def __calendar_dialog(self, widget, entry): - d = gtk.Window(gtk.WINDOW_TOPLEVEL) - d.set_title('Pick a date') - - vb = gtk.VBox() - cal = gtk.Calendar() - vb.pack_start(cal, expand=False, padding=0) - - btn = gtk.Button('Done') - btn.connect('clicked', self.__get_date, cal, entry, d) - - vb.pack_start(btn, expand=False, padding=4) - - d.add(vb) - d.set_position(gtk.WIN_POS_MOUSE) - d.show_all() - - def __clear_dates(self, w): - self.start_date.set_text('') - self.end_date.set_text('') - - def __get_dates(self): - t1 = self.start_date.get_text() - t2 = self.end_date.get_text() - return (t1, t2) - - def __get_date(self, widget, calendar, entry, win): -# year and day are correct, month is 0..11 - (year, month, day) = calendar.get_date() - month += 1 - ds = '%04d-%02d-%02d' % (year, month, day) - entry.set_text(ds) - win.destroy() - - def exportGraph (self, widget, data): - if self.fig is None: - return # Might want to disable export button until something has been generated. - dia_chooser = gtk.FileChooserDialog(title="Please choose the directory you wish to export to:", - action=gtk.FILE_CHOOSER_ACTION_OPEN, - buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) - #TODO: Suggest path and filename to start with - - response = dia_chooser.run() - if response == gtk.RESPONSE_OK: - self.exportDir = dia_chooser.get_filename() - print "DEBUG: self.exportDir = %s" %(self.exportDir) - elif response == gtk.RESPONSE_CANCEL: - print 'Closed, no graph exported' - dia_chooser.destroy() - #TODO: Check to see if file exists - #NOTE: Dangerous - will happily overwrite any file we have write access too - #TODO: This asks for a directory but will take a filename and overwrite it. - self.fig.savefig(self.exportDir, format="png") def __init__(self, db, settings, querylist, config, debug=True): """Constructor for GraphViewer""" @@ -313,21 +53,28 @@ class GuiGraphViewer (threading.Thread): self.sql=querylist self.conf = config - self.sites = {} - self.siteid = {} - self.heroes = {} + filters_display = { "Heroes" : True, + "Sites" : True, + "Games" : True, + "Limits" : True, + "Seats" : False, + "Dates" : True, + "Button1" : True, + "Button2" : True + } + + self.filters = Filters.Filters(db, settings, config, querylist, display = filters_display) + self.filters.registerButton1Name("Refresh Graph") + self.filters.registerButton1Callback(self.generateGraph) + self.filters.registerButton2Name("Export to File") + self.filters.registerButton2Callback(self.exportGraph) - # For use in date ranges. - self.start_date = gtk.Entry(max=12) - self.end_date = gtk.Entry(max=12) - self.start_date.set_property('editable', False) - self.end_date.set_property('editable', False) - self.mainHBox = gtk.HBox(False, 0) self.mainHBox.show() - self.leftPanelBox = gtk.VBox(False, 0) + self.leftPanelBox = self.filters.get_vbox() self.graphBox = gtk.VBox(False, 0) + self.graphBox.show() self.hpane = gtk.HPaned() self.hpane.pack1(self.leftPanelBox) @@ -336,55 +83,15 @@ class GuiGraphViewer (threading.Thread): self.mainHBox.add(self.hpane) - playerFrame = gtk.Frame("Hero:") - playerFrame.set_label_align(0.0, 0.0) - playerFrame.show() - vbox = gtk.VBox(False, 0) - vbox.show() - - self.fillPlayerFrame(vbox) - playerFrame.add(vbox) - - sitesFrame = gtk.Frame("Sites:") - sitesFrame.set_label_align(0.0, 0.0) - sitesFrame.show() - vbox = gtk.VBox(False, 0) - vbox.show() - - self.fillSitesFrame(vbox) - sitesFrame.add(vbox) - - dateFrame = gtk.Frame("Date:") - dateFrame.set_label_align(0.0, 0.0) - dateFrame.show() - vbox = gtk.VBox(False, 0) - vbox.show() - - self.fillDateFrame(vbox) - dateFrame.add(vbox) - - graphButton=gtk.Button("Generate Graph") - graphButton.connect("clicked", self.generateGraph, "cliced data") - graphButton.show() - self.fig = None - self.exportButton=gtk.Button("Export to File") - self.exportButton.connect("clicked", self.exportGraph, "show clicked") - self.exportButton.set_sensitive(False) - self.exportButton.show() - - self.leftPanelBox.add(playerFrame) - self.leftPanelBox.add(sitesFrame) - self.leftPanelBox.add(dateFrame) - self.leftPanelBox.add(graphButton) - self.leftPanelBox.add(self.exportButton) - - self.leftPanelBox.show() - self.graphBox.show() + #self.exportButton.set_sensitive(False) self.fig = Figure(figsize=(5,4), dpi=100) self.canvas = None + + self.db.db.rollback() + ################################# # # self.db.cursor.execute("""select UNIX_TIMESTAMP(handStart) as time, id from Hands ORDER BY time""") @@ -412,3 +119,144 @@ class GuiGraphViewer (threading.Thread): # print "Total: ", total ################################# + + def get_vbox(self): + """returns the vbox of this thread""" + return self.mainHBox + #end def get_vbox + + def clearGraphData(self): + self.fig.clf() + if self.canvas is not None: + self.canvas.destroy() + + self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea + + def generateGraph(self, widget, data): + self.clearGraphData() + + sitenos = [] + playerids = [] + + sites = self.filters.getSites() + heroes = self.filters.getHeroes() + siteids = self.filters.getSiteIds() + limits = self.filters.getLimits() + # Which sites are selected? + for site in sites: + if sites[site] == True: + sitenos.append(siteids[site]) + self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) + result = self.db.cursor.fetchall() + if len(result) == 1: + playerids.append(result[0][0]) + + if not sitenos: + #Should probably pop up here. + print "No sites selected - defaulting to PokerStars" + sitenos = [2] + + if not playerids: + print "No player ids found" + return + + if not limits: + print "No limits found" + return + + #Set graph properties + self.ax = self.fig.add_subplot(111) + + #Get graph data from DB + starttime = time() + line = self.getRingProfitGraph(playerids, sitenos, limits) + print "Graph generated in: %s" %(time() - starttime) + + self.ax.set_title("Profit graph for ring games") + + #Set axis labels and grid overlay properites + self.ax.set_xlabel("Hands", fontsize = 12) + self.ax.set_ylabel("$", fontsize = 12) + self.ax.grid(color='g', linestyle=':', linewidth=0.2) + if line == None or line == []: + + #TODO: Do something useful like alert user + print "No hands returned by graph query" + else: +# text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) + text = "All Hands, " + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) + + self.ax.annotate(text, + xy=(10, -10), + xycoords='axes points', + horizontalalignment='left', verticalalignment='top', + fontsize=10) + + #Draw plot + self.ax.plot(line,) + + self.graphBox.add(self.canvas) + self.canvas.show() + #self.exportButton.set_sensitive(True) + #end of def showClicked + + def getRingProfitGraph(self, names, sites, limits): + tmp = self.sql.query['getRingProfitAllHandsPlayerIdSite'] +# print "DEBUG: getRingProfitGraph" + start_date, end_date = self.filters.getDates() + + #Buggered if I can find a way to do this 'nicely' take a list of intergers and longs + # and turn it into a tuple readale by sql. + # [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(",)",")") + + #Must be a nicer way to deal with tuples of size 1 ie. (2,) - which makes sql barf + tmp = tmp.replace("", nametest) + tmp = tmp.replace("", sitetest) + tmp = tmp.replace("", start_date) + tmp = tmp.replace("", end_date) + tmp = tmp.replace("", limittest) + + #print "DEBUG: sql query:" + #print tmp + self.cursor.execute(tmp) + #returns (HandId,Winnings,Costs,Profit) + winnings = self.db.cursor.fetchall() + self.db.db.rollback() + + if(winnings == ()): + return None + + y=map(lambda x:float(x[3]), winnings) + line = cumsum(y) + return line/100 + #end of def getRingProfitGraph + + def exportGraph (self, widget, data): + if self.fig is None: + return # Might want to disable export button until something has been generated. + dia_chooser = gtk.FileChooserDialog(title="Please choose the directory you wish to export to:", + action=gtk.FILE_CHOOSER_ACTION_OPEN, + buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) + #TODO: Suggest path and filename to start with + + response = dia_chooser.run() + if response == gtk.RESPONSE_OK: + self.exportDir = dia_chooser.get_filename() + print "DEBUG: self.exportDir = %s" %(self.exportDir) + elif response == gtk.RESPONSE_CANCEL: + print 'Closed, no graph exported' + dia_chooser.destroy() + #TODO: Check to see if file exists + #NOTE: Dangerous - will happily overwrite any file we have write access too + #TODO: This asks for a directory but will take a filename and overwrite it. + self.fig.savefig(self.exportDir, format="png") + + diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index b2eb0108..311d9a10 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -20,158 +20,421 @@ import pygtk pygtk.require('2.0') import gtk import os - +from time import time, strftime + +import Card import fpdb_import import fpdb_db +import Filters import FpdbSQLQueries class GuiPlayerStats (threading.Thread): - def get_vbox(self): - """returns the vbox of this thread""" - return self.main_hbox - - def toggleCallback(self, widget, data=None): -# print "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()]) - self.activesite = data - print "DEBUG: activesite set to %s" %(self.activesite) - - def refreshStats(self, widget, data): - try: self.stats_table.destroy() - except AttributeError: pass - self.fillStatsFrame(self.stats_frame) - - def fillStatsFrame(self, vbox): - # Get currently active site and grab playerid - tmp = self.sql.query['playerStats'] - - result = self.cursor.execute(self.sql.query['getPlayerId'], (self.heroes[self.activesite],)) - result = self.cursor.fetchall() - if not result == (): - pid = result[0][0] - pid = result[0][0] - tmp = tmp.replace("", "(" + str(pid) + ")") - self.cursor.execute(tmp) - result = self.cursor.fetchall() - cols = 16 - rows = len(result)+1 # +1 for title row - self.stats_table = gtk.Table(rows, cols, False) - self.stats_table.set_col_spacings(4) - self.stats_table.show() - vbox.add(self.stats_table) - - # Create header row - titles = ("Game", "Hands", "VPIP", "PFR", "Saw_F", "SawSD", "WtSDwsF", "W$SD", "FlAFq", "TuAFq", "RvAFq", "PoFAFq", "Net($)", "BB/100", "$/hand", "Variance") - - col = 0 - row = 0 - for t in titles: - l = gtk.Label(titles[col]) - l.show() - self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK) - col +=1 - - for row in range(rows-1): - if(row%2 == 0): - bgcolor = "white" - else: - bgcolor = "lightgrey" - for col in range(cols): - eb = gtk.EventBox() - eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor)) - if result[row][col]: - l = gtk.Label(result[row][col]) - else: - l = gtk.Label(' ') - if col == 0: - l.set_alignment(xalign=0.0, yalign=0.5) - else: - l.set_alignment(xalign=1.0, yalign=0.5) - eb.add(l) - self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK) - l.show() - eb.show() - self.fdb.db.commit() - #end def fillStatsFrame(self, vbox): - - def fillPlayerFrame(self, vbox): - for site in self.conf.supported_sites.keys(): - hbox = gtk.HBox(False, 0) - vbox.pack_start(hbox, False, True, 0) - hbox.show() - - player = self.conf.supported_sites[site].screen_name - self.createPlayerLine(hbox, site, player) - hbox = gtk.HBox(False, 0) - button = gtk.Button("Refresh") - button.connect("clicked", self.refreshStats, False) - button.show() - hbox.add(button) - vbox.pack_start(hbox, False, True, 0) - hbox.show() - - def createPlayerLine(self, hbox, site, player): - if(self.buttongroup == None): - button = gtk.RadioButton(None, site + " id:") - button.set_active(True) - self.buttongroup = button - self.activesite = site - else: - button = gtk.RadioButton(self.buttongroup, site + " id:") - hbox.pack_start(button, True, True, 0) - button.connect("toggled", self.toggleCallback, site) - button.show() - - pname = gtk.Entry() - pname.set_text(player) - 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 - pname.show() - self.__set_hero_name(pname, site) - - def __set_hero_name(self, w, site): - self.heroes[site] = w.get_text() - - def __init__(self, db, config, querylist, debug=True): + def __init__(self, config, querylist, mainwin, debug=True): self.debug=debug self.conf=config + self.main_window=mainwin + self.MYSQL_INNODB = 2 + self.PGSQL = 3 + self.SQLITE = 4 # create new db connection to avoid conflicts with other threads - self.fdb = fpdb_db.fpdb_db() - self.fdb.do_connect(self.conf) - self.cursor=self.fdb.cursor - + self.db = fpdb_db.fpdb_db() + self.db.do_connect(self.conf) + self.cursor=self.db.cursor self.sql = querylist - self.activesite = None - self.buttongroup = None + settings = {} + settings.update(config.get_db_parameters()) + settings.update(config.get_tv_parameters()) + settings.update(config.get_import_parameters()) + settings.update(config.get_default_paths()) + + # text used on screen stored here so that it can be configured + 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" : False, + "Groups" : True, + "Button1" : True, + "Button2" : True + } + + self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display) + self.filters.registerButton1Name("_Filters") + self.filters.registerButton1Callback(self.showDetailFilter) + self.filters.registerButton2Name("_Refresh") + self.filters.registerButton2Callback(self.refreshStats) + + # ToDo: store in config + # ToDo: create popup to adjust column config + # columns to display, keys match column name returned by sql, values in tuple are: + # is column displayed, column heading, xalignment, formatting + self.columns = [ ("game", True, "Game", 0.0, "%s") + , ("hand", False, "Hand", 0.0, "%s") # true not allowed for this line + , ("n", True, "Hds", 1.0, "%d") + , ("avgseats", True, "Seats", 1.0, "%3.1f") + , ("vpip", True, "VPIP", 1.0, "%3.1f") + , ("pfr", True, "PFR", 1.0, "%3.1f") + , ("pf3", True, "PF3", 1.0, "%3.1f") + , ("steals", True, "Steals", 1.0, "%3.1f") + , ("saw_f", True, "Saw_F", 1.0, "%3.1f") + , ("sawsd", True, "SawSD", 1.0, "%3.1f") + , ("wtsdwsf", True, "WtSDwsF", 1.0, "%3.1f") + , ("wmsd", True, "W$SD", 1.0, "%3.1f") + , ("flafq", True, "FlAFq", 1.0, "%3.1f") + , ("tuafq", True, "TuAFq", 1.0, "%3.1f") + , ("rvafq", True, "RvAFq", 1.0, "%3.1f") + , ("pofafq", False, "PoFAFq", 1.0, "%3.1f") + , ("net", True, "Net($)", 1.0, "%6.2f") + , ("bbper100", True, "BB/100", 1.0, "%4.2f") + , ("rake", True, "Rake($)", 1.0, "%6.2f") + , ("variance", True, "Variance", 1.0, "%5.2f") + ] + + # Detail filters: This holds the data used in the popup window, extra values are + # added at the end of these lists during processing + # sql test, screen description, min, max + self.handtests = [ # already in filter class : ['h.seats', 'Number of Players', 2, 10] + ['h.maxSeats', 'Size of Table', 2, 10] + ,['h.playersVpi', 'Players who VPI', 0, 10] + ,['h.playersAtStreet1', 'Players at Flop', 0, 10] + ,['h.playersAtStreet2', 'Players at Turn', 0, 10] + ,['h.playersAtStreet3', 'Players at River', 0, 10] + ,['h.playersAtStreet4', 'Players at Street7', 0, 10] + ,['h.playersAtShowdown', 'Players at Showdown', 0, 10] + ,['h.street0Raises', 'Bets to See Flop', 0, 5] + ,['h.street1Raises', 'Bets to See Turn', 0, 5] + ,['h.street2Raises', 'Bets to See River', 0, 5] + ,['h.street3Raises', 'Bets to See Street7', 0, 5] + ,['h.street4Raises', 'Bets to See Showdown', 0, 5] + ] - self.heroes = {} - self.stat_table = None self.stats_frame = None + 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() - playerFrame = gtk.Frame("Hero:") - playerFrame.set_label_align(0.0, 0.0) - playerFrame.show() - vbox = gtk.VBox(False, 0) - vbox.show() - - self.fillPlayerFrame(vbox) - playerFrame.add(vbox) - - statsFrame = gtk.Frame("Stats:") - statsFrame.set_label_align(0.0, 0.0) - statsFrame.show() - self.stats_frame = gtk.VBox(False, 0) + self.stats_frame = gtk.Frame() self.stats_frame.show() - self.fillStatsFrame(self.stats_frame) - statsFrame.add(self.stats_frame) + self.stats_vbox = gtk.VBox(False, 0) + self.stats_vbox.show() + 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) + + # make sure Hand column is not displayed + [x for x in self.columns if x[0] == 'hand'][0][1] == False + + def get_vbox(self): + """returns the vbox of this thread""" + return self.main_hbox + + def refreshStats(self, widget, data): + try: self.stats_vbox.destroy() + except AttributeError: pass + self.stats_vbox = gtk.VBox(False, 0) + self.stats_vbox.show() + self.stats_frame.add(self.stats_vbox) + self.fillStatsFrame(self.stats_vbox) + + def fillStatsFrame(self, vbox): + sites = self.filters.getSites() + heroes = self.filters.getHeroes() + siteids = self.filters.getSiteIds() + limits = self.filters.getLimits() + seats = self.filters.getSeats() + sitenos = [] + playerids = [] + + # Which sites are selected? + for site in sites: + if sites[site] == True: + sitenos.append(siteids[site]) + self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) + result = self.db.cursor.fetchall() + if len(result) == 1: + playerids.append(result[0][0]) + + if not sitenos: + #Should probably pop up here. + print "No sites selected - defaulting to PokerStars" + sitenos = [2] + if not playerids: + print "No player ids found" + return + if not limits: + print "No limits found" + return + + self.createStatsTable(vbox, playerids, sitenos, limits, seats) + + def createStatsTable(self, vbox, playerids, sitenos, limits, seats): + starttime = time() + + # 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) + + # Separator + sep = gtk.HSeparator() + vbox.pack_start(sep, expand=False, padding=3) + sep.show_now() + vbox.show_now() + heading = gtk.Label(self.filterText['handhead']) + heading.show() + vbox.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) + + # Detailed table + flags = [True] + self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats) + + self.db.db.commit() + 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): + row = 0 + sqlrow = 0 + colalias,colshow,colheading,colxalign,colformat = 0,1,2,3,4 + if not flags: holecards = False + else: holecards = flags[0] + + + self.stats_table = gtk.Table(1, 1, False) + self.stats_table.set_col_spacings(4) + self.stats_table.show() + + tmp = self.sql.query[query] + tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, seats) + self.cursor.execute(tmp) + result = self.cursor.fetchall() + colnames = [desc[0].lower() for desc in self.cursor.description] + + # pre-fetch some constant values: + cols_to_show = [x for x in self.columns if x[colshow]] + hgametypeid_idx = colnames.index('hgametypeid') + + 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) + textcell = gtk.CellRendererText() + numcell = gtk.CellRendererText() + numcell.set_property('xalign', 1.0) + listcols = [] + + # Create header row eg column: ("game", True, "Game", 0.0, "%s") + for col, column in enumerate(cols_to_show): + if column[colalias] == 'game' and holecards: + s = [x for x in self.columns if x[colalias] == 'hand'][0][colheading] + else: + s = column[colheading] + listcols.append(gtk.TreeViewColumn(s)) + view.append_column(listcols[col]) + if column[colformat] == '%s': + if col == 1 and holecards: + listcols[col].pack_start(textcell, expand=True) + else: + listcols[col].pack_start(textcell, expand=True) + listcols[col].add_attribute(textcell, 'text', col) + listcols[col].set_expand(True) + else: + listcols[col].pack_start(numcell, expand=True) + listcols[col].add_attribute(numcell, 'text', col) + listcols[col].set_alignment(1.0) + listcols[col].set_expand(True) + + rows = len(result) # +1 for title row + + while sqlrow < rows: + treerow = [] + if(row%2 == 0): + bgcolor = "white" + else: + bgcolor = "lightgrey" + for col,column in enumerate(cols_to_show): + if column[colalias] in colnames: + value = result[sqlrow][colnames.index(column[colalias])] + else: + if column[colalias] == 'game': + if holecards: + value = Card.twoStartCardString( result[sqlrow][hgametypeid_idx] ) + else: + minbb = result[sqlrow][colnames.index('minbigblind')] + maxbb = result[sqlrow][colnames.index('maxbigblind')] + value = result[sqlrow][colnames.index('limittype')] + ' ' \ + + result[sqlrow][colnames.index('category')].title() + ' ' \ + + result[sqlrow][colnames.index('name')] + ' $' + if 100 * int(minbb/100.0) != minbb: + value += '%.2f' % (minbb/100.0) + else: + value += '%.0f' % (minbb/100.0) + if minbb != maxbb: + if 100 * int(maxbb/100.0) != maxbb: + value += ' - $' + '%.2f' % (maxbb/100.0) + else: + value += ' - $' + '%.0f' % (maxbb/100.0) + else: + continue + if value and value != -999: + treerow.append(column[colformat] % value) + else: + treerow.append(' ') + iter = liststore.append(treerow) + sqlrow += 1 + row += 1 + vbox.show_all() + + #end def addTable(self, query, vars, playerids, sitenos, limits, seats): + + def refineQuery(self, query, flags, playerids, sitenos, limits, seats): + 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) + else: + query = query.replace("", "1 = 2") + + if seats: + query = query.replace('', 'between ' + str(seats['from']) + ' and ' + str(seats['to'])) + if 'show' in seats and seats['show']: + query = query.replace('', ',h.seats') + query = query.replace('', ',h.seats') + else: + query = query.replace('', '') + query = query.replace('', '') + else: + query = query.replace('', 'between 0 and 100') + 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()])) + blindtest = blindtest.replace("L", "") + blindtest = blindtest.replace(",)",")") + query = query.replace("", " and gt.bigBlind in " + blindtest + " ") + else: + query = query.replace("", "") + + if holecards: # pinch level variables for hole card query + query = query.replace("", "hp.startcards") + query = query.replace("", ",hgameTypeId desc") + else: + query = query.replace("", "") + groupLevels = "show" not in str(limits) + if groupLevels: + query = query.replace("", "-1") + else: + query = query.replace("", "h.gameTypeId") + + # process self.detailFilters (a list of tuples) + flagtest = '' + #self.detailFilters = [('h.seats', 5, 6)] # for debug + if self.detailFilters: + for f in self.detailFilters: + if len(f) == 3: + # X between Y and Z + flagtest += ' and %s between %s and %s ' % (f[0], str(f[1]), str(f[2])) + query = query.replace("", flagtest) + + # allow for differences in sql cast() function: + if self.db.backend == self.MYSQL_INNODB: + query = query.replace("", 'signed ') + else: + query = query.replace("", '') + + #print "query =\n", query + return(query) + #end def refineQuery(self, query, playerids, sitenos, limits): + + def showDetailFilter(self, widget, data): + detailDialog = gtk.Dialog(title="Detailed Filters", parent=self.main_window + ,flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT + ,buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) + + handbox = gtk.VBox(True, 0) + detailDialog.vbox.pack_start(handbox, False, False, 0) + handbox.show() + + label = gtk.Label("Hand Filters:") + handbox.add(label) + label.show() + + betweenFilters = [] + for htest in self.handtests: + hbox = gtk.HBox(False, 0) + handbox.pack_start(hbox, False, False, 0) + hbox.show() + + cb = gtk.CheckButton() + lbl_from = gtk.Label(htest[1]) + lbl_from.set_alignment(xalign=0.0, yalign=0.5) + lbl_tween = gtk.Label('between') + lbl_to = gtk.Label('and') + adj1 = gtk.Adjustment(value=htest[2], lower=0, upper=10, step_incr=1, page_incr=1, page_size=0) + sb1 = gtk.SpinButton(adjustment=adj1, climb_rate=0.0, digits=0) + adj2 = gtk.Adjustment(value=htest[3], lower=2, upper=10, step_incr=1, page_incr=1, page_size=0) + sb2 = gtk.SpinButton(adjustment=adj2, climb_rate=0.0, digits=0) + + for df in [x for x in self.detailFilters if x[0] == htest[0]]: + cb.set_active(True) + + hbox.pack_start(cb, expand=False, padding=3) + hbox.pack_start(lbl_from, expand=True, padding=3) + hbox.pack_start(lbl_tween, expand=False, padding=3) + hbox.pack_start(sb1, False, False, 0) + hbox.pack_start(lbl_to, expand=False, padding=3) + hbox.pack_start(sb2, False, False, 0) + + cb.show() + lbl_from.show() + lbl_tween.show() + sb1.show() + lbl_to.show() + sb2.show() + + htest[4:7] = [cb,sb1,sb2] + + response = detailDialog.run() + + if response == gtk.RESPONSE_ACCEPT: + self.detailFilters = [] + for ht in self.handtests: + if ht[4].get_active(): + self.detailFilters.append( (ht[0], ht[5].get_value_as_int(), ht[6].get_value_as_int()) ) + ht[2],ht[3] = ht[5].get_value_as_int(), ht[6].get_value_as_int() + print "detailFilters =", self.detailFilters + self.refreshStats(None, None) + + detailDialog.destroy() - self.main_hbox.pack_start(playerFrame) - self.main_hbox.pack_start(statsFrame) diff --git a/pyfpdb/GuiPositionalStats.py b/pyfpdb/GuiPositionalStats.py index 64828573..042f7779 100644 --- a/pyfpdb/GuiPositionalStats.py +++ b/pyfpdb/GuiPositionalStats.py @@ -23,9 +23,80 @@ import os import fpdb_import import fpdb_db +import Filters import FpdbSQLQueries class GuiPositionalStats (threading.Thread): + def __init__(self, config, querylist, debug=True): + self.debug=debug + self.conf=config + self.MYSQL_INNODB = 2 + self.PGSQL = 3 + self.SQLITE = 4 + + # create new db connection to avoid conflicts with other threads + self.db = fpdb_db.fpdb_db() + self.db.do_connect(self.conf) + self.cursor=self.db.cursor + self.sql = querylist + + settings = {} + settings.update(config.get_db_parameters()) + settings.update(config.get_tv_parameters()) + settings.update(config.get_import_parameters()) + settings.update(config.get_default_paths()) + + filters_display = { "Heroes" : True, + "Sites" : True, + "Games" : False, + "Limits" : True, + "LimitSep" : True, + "Seats" : True, + "SeatSep" : True, + "Dates" : True, + "Button1" : True, + "Button2" : False + } + + self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display) + self.filters.registerButton1Name("Refresh") + self.filters.registerButton1Callback(self.refreshStats) + + self.stat_table = None + self.stats_frame = None + + self.main_hbox = gtk.HBox(False, 0) + self.main_hbox.show() + + statsFrame = gtk.Frame("Stats:") + statsFrame.set_label_align(0.0, 0.0) + statsFrame.show() + self.stats_frame = gtk.VBox(False, 0) + self.stats_frame.show() + + # This could be stored in config eventually, or maybe configured in this window somehow. + # Each posncols element is the name of a column returned by the sql + # query (in lower case) and each posnheads element is the text to use as + # the heading in the GUI. Both sequences should be the same length. + # To miss columns out remove them from both tuples (the 1st 2 elements should always be included). + # To change the heading just edit the second list element as required + # If the first list element does not match a query column that pair is ignored + self.posncols = ( "game", "avgseats", "plposition", "vpip", "pfr", "pf3", "steals" + , "saw_f", "sawsd", "wtsdwsf", "wmsd", "flafq", "tuafq", "rvafq" + , "pofafq", "net", "bbper100", "profitperhand", "variance", "n" + ) + self.posnheads = ( "Game", "Seats", "Posn", "VPIP", "PFR", "PF3", "Steals" + , "Saw_F", "SawSD", "WtSDwsF", "W$SD", "FlAFq", "TuAFq", "RvAFq" + , "PoFAFq", "Net($)", "BB/100", "$/hand", "Variance", "Hds" + ) + + self.fillStatsFrame(self.stats_frame) + statsFrame.add(self.stats_frame) + + self.main_hbox.pack_start(self.filters.get_vbox()) + self.main_hbox.pack_start(statsFrame) + + def get_vbox(self): """returns the vbox of this thread""" return self.main_hbox @@ -35,177 +106,255 @@ class GuiPositionalStats (threading.Thread): self.activesite = data print "DEBUG: activesite set to %s" %(self.activesite) - def cardCallback(self, widget, data=None): - print "DEBUG: %s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()]) - def refreshStats(self, widget, data): try: self.stats_table.destroy() except AttributeError: pass self.fillStatsFrame(self.stats_frame) def fillStatsFrame(self, vbox): - # Get currently active site and grab playerid - print "DEBUG: attempting to fill stats frame" + sites = self.filters.getSites() + heroes = self.filters.getHeroes() + siteids = self.filters.getSiteIds() + limits = self.filters.getLimits() + seats = self.filters.getSeats() + dates = self.filters.getDates() + sitenos = [] + playerids = [] + + # Which sites are selected? + for site in sites: + if sites[site] == True: + sitenos.append(siteids[site]) + self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) + result = self.db.cursor.fetchall() + if len(result) == 1: + playerids.append(result[0][0]) + + if not sitenos: + #Should probably pop up here. + print "No sites selected - defaulting to PokerStars" + sitenos = [2] + if not playerids: + print "No player ids found" + return + if not limits: + print "No limits found" + return + + self.createStatsTable(vbox, playerids, sitenos, limits, seats, dates) + + def createStatsTable(self, vbox, playerids, sitenos, limits, seats, dates): + self.stats_table = gtk.Table(1, 1, False) # gtk table expands as required + self.stats_table.set_col_spacings(4) + self.stats_table.show() + vbox.add(self.stats_table) + + row = 0 + col = 0 + for t in self.posnheads: + l = gtk.Label(self.posnheads[col]) + l.show() + self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK) + col +=1 + tmp = self.sql.query['playerStatsByPosition'] - - result = self.cursor.execute(self.sql.query['getPlayerId'], (self.heroes[self.activesite],)) + tmp = self.refineQuery(tmp, playerids, sitenos, limits, seats, dates) + self.cursor.execute(tmp) result = self.cursor.fetchall() - if not result == (): - pid = result[0][0] - pid = result[0][0] - tmp = tmp.replace("", "(" + str(pid) + ")") - self.cursor.execute(tmp) - result = self.cursor.fetchall() - cols = 16 - rows = len(result)+1 # +1 for title row - self.stats_table = gtk.Table(rows, cols, False) - self.stats_table.set_col_spacings(4) - self.stats_table.show() - vbox.add(self.stats_table) - # Create header row - titles = ("Game", "Position", "#", "VPIP", "PFR", "Saw_F", "SawSD", "WtSDwsF", "W$SD", "FlAFq", "TuAFq", "RvAFq", "PoFAFq", "Net($)", "BB/100", "$/hand", "Variance") + rows = len(result) + colnames = [desc[0].lower() for desc in self.cursor.description] - col = 0 - row = 0 - for t in titles: - l = gtk.Label(titles[col]) - l.show() - self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK) - col +=1 - - for row in range(rows-1): - if(row%2 == 0): - bgcolor = "white" + last_game,last_seats,sqlrow = "","",0 + while sqlrow < rows: + if(row%2 == 0): + bgcolor = "white" + else: + bgcolor = "lightgrey" + rowprinted=0 + avgcol = colnames.index('avgseats') + for col,colname in enumerate(self.posncols): + if colname in colnames: + sqlcol = colnames.index(colname) + else: + continue + eb = gtk.EventBox() + eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor)) + # print blank row between levels: + if result[sqlrow][sqlcol]: + if sqlrow == 0: + l = gtk.Label(result[sqlrow][sqlcol]) + rowprinted=1 + elif result[sqlrow][0] != last_game: + l = gtk.Label(' ') + elif 'show' in seats and seats['show'] and result[sqlrow][avgcol] != last_seats: + l = gtk.Label(' ') else: - bgcolor = "lightgrey" - for col in range(cols): - eb = gtk.EventBox() - eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor)) - if result[row][col]: - l = gtk.Label(result[row][col]) - else: - l = gtk.Label(' ') - if col == 0: - l.set_alignment(xalign=0.0, yalign=0.5) - else: - l.set_alignment(xalign=1.0, yalign=0.5) - eb.add(l) - self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK) - l.show() - eb.show() - self.fdb.db.commit() + l = gtk.Label(result[sqlrow][sqlcol]) + rowprinted=1 + else: + l = gtk.Label(' ') + if col == 0: + l.set_alignment(xalign=0.0, yalign=0.5) + elif col == 1: + l.set_alignment(xalign=0.5, yalign=0.5) + else: + l.set_alignment(xalign=1.0, yalign=0.5) + eb.add(l) + self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK) + l.show() + eb.show() + last_game = result[sqlrow][0] + last_seats = result[sqlrow][avgcol] + if rowprinted: + sqlrow = sqlrow+1 + row = row + 1 + + # show totals at bottom + tmp = self.sql.query['playerStats'] + tmp = self.refineQuery(tmp, playerids, sitenos, limits, seats, dates) + self.cursor.execute(tmp) + result = self.cursor.fetchall() + rows = len(result) + colnames = [desc[0].lower() for desc in self.cursor.description] + + # blank row between main stats and totals: + col = 0 + if(row%2 == 0): + bgcolor = "white" + else: + bgcolor = "lightgrey" + eb = gtk.EventBox() + eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor)) + l = gtk.Label(' ') + eb.add(l) + self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK) + l.show() + eb.show() + row = row + 1 + + for sqlrow in range(rows): + if(row%2 == 0): + bgcolor = "white" + else: + bgcolor = "lightgrey" + for col,colname in enumerate(self.posncols): + if colname in colnames: + sqlcol = colnames.index(colname) + elif colname != "plposition": + continue + eb = gtk.EventBox() + eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor)) + if colname == 'plposition': + l = gtk.Label('Totals') + elif result[sqlrow][sqlcol]: + l = gtk.Label(result[sqlrow][sqlcol]) + else: + l = gtk.Label(' ') + if col == 0: + l.set_alignment(xalign=0.0, yalign=0.5) + elif col == 1: + l.set_alignment(xalign=0.5, yalign=0.5) + else: + l.set_alignment(xalign=1.0, yalign=0.5) + eb.add(l) + self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK) + l.show() + eb.show() + row = row + 1 + + self.db.db.rollback() #end def fillStatsFrame(self, vbox): - def fillPlayerFrame(self, vbox): - for site in self.conf.supported_sites.keys(): - hbox = gtk.HBox(False, 0) - vbox.pack_start(hbox, False, True, 0) - hbox.show() - - player = self.conf.supported_sites[site].screen_name - self.createPlayerLine(hbox, site, player) - hbox = gtk.HBox(False, 0) - button = gtk.Button("Refresh") - button.connect("clicked", self.refreshStats, False) - button.show() - hbox.add(button) - vbox.pack_start(hbox, False, True, 0) - hbox.show() - - def fillCardsFrame(self, vbox): - hbox1 = gtk.HBox(True,0) - hbox1.show() - vbox.pack_start(hbox1, True, True, 0) - - cards = [ "A", "K","Q","J","T","9","8","7","6","5","4","3","2" ] - - for j in range(0, len(cards)): - hbox1 = gtk.HBox(True,0) - hbox1.show() - vbox.pack_start(hbox1, True, True, 0) - for i in range(0, len(cards)): - if i < (j + 1): - suit = "o" - else: - suit = "s" - button = gtk.ToggleButton("%s%s%s" %(cards[i], cards[j], suit)) - button.connect("toggled", self.cardCallback, "%s%s%s" %(cards[i], cards[j], suit)) - hbox1.pack_start(button, True, True, 0) - button.show() - - def createPlayerLine(self, hbox, site, player): - if(self.buttongroup == None): - button = gtk.RadioButton(None, site + " id:") - button.set_active(True) - self.buttongroup = button - self.activesite = site + def refineQuery(self, query, playerids, sitenos, limits, seats, dates): + if playerids: + nametest = str(tuple(playerids)) + nametest = nametest.replace("L", "") + nametest = nametest.replace(",)",")") + query = query.replace("", nametest) else: - button = gtk.RadioButton(self.buttongroup, site + " id:") - hbox.pack_start(button, True, True, 0) - button.connect("toggled", self.toggleCallback, site) - button.show() + query = query.replace("", "1 = 2") - pname = gtk.Entry() - pname.set_text(player) - 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 - pname.show() - self.__set_hero_name(pname, site) + if seats: + query = query.replace('', 'between ' + str(seats['from']) + ' and ' + str(seats['to'])) + if 'show' in seats and seats['show']: + query = query.replace('', ',hc.activeSeats') + query = query.replace('', ',stats.AvgSeats') + else: + query = query.replace('', '') + query = query.replace('', '') + else: + query = query.replace('', 'between 0 and 100') + query = query.replace('', '') + query = query.replace('', '') - def __set_hero_name(self, w, site): - self.heroes[site] = w.get_text() - - def __init__(self, db, config, querylist, debug=True): - self.debug=debug - self.conf=config - - # create new db connection to avoid conflicts with other threads - self.fdb = fpdb_db.fpdb_db() - self.fdb.do_connect(self.conf) - self.cursor=self.fdb.cursor + if [x for x in limits if str(x).isdigit()]: + blindtest = str(tuple([x for x in limits if str(x).isdigit()])) + blindtest = blindtest.replace("L", "") + blindtest = blindtest.replace(",)",")") + query = query.replace("", "gt.bigBlind in " + blindtest) + else: + query = query.replace("", "gt.bigBlind = -1 ") - self.sql = querylist + groupLevels = "show" not in str(limits) + if groupLevels: + if self.db.backend == self.MYSQL_INNODB: + bigblindselect = """concat('$' + ,trim(leading ' ' from + case when min(gt.bigBlind) < 100 + then format(min(gt.bigBlind)/100.0, 2) + else format(min(gt.bigBlind)/100.0, 0) + end) + ,' - $' + ,trim(leading ' ' from + case when max(gt.bigBlind) < 100 + then format(max(gt.bigBlind)/100.0, 2) + else format(max(gt.bigBlind)/100.0, 0) + end) + ) """ + else: + bigblindselect = """'$' || + trim(leading ' ' from + case when min(gt.bigBlind) < 100 + then to_char(min(gt.bigBlind)/100.0,'90D00') + else to_char(min(gt.bigBlind)/100.0,'999990') + end) + || ' - $' || + trim(leading ' ' from + case when max(gt.bigBlind) < 100 + then to_char(max(gt.bigBlind)/100.0,'90D00') + else to_char(max(gt.bigBlind)/100.0,'999990') + end) """ + bigblindselect = "cast('' as char)" # avoid odd effects when some posns and/or seats + # are missing from some limits (dunno why cast is + # needed but it says "unknown type" otherwise?! + query = query.replace("", bigblindselect) + query = query.replace("", "") + query = query.replace("", "-1") + query = query.replace("", "-1") + else: + if self.db.backend == self.MYSQL_INNODB: + bigblindselect = """concat('$', trim(leading ' ' from + case when gt.bigBlind < 100 + then format(gt.bigBlind/100.0, 2) + else format(gt.bigBlind/100.0, 0) + end + ) )""" + else: + bigblindselect = """'$' || trim(leading ' ' from + case when gt.bigBlind < 100 + then to_char(gt.bigBlind/100.0,'90D00') + else to_char(gt.bigBlind/100.0,'999990') + end + ) """ + query = query.replace("", bigblindselect) + query = query.replace("", ",gt.bigBlind") + query = query.replace("", "hc.gametypeId") + query = query.replace("", "h.gameTypeId") - self.activesite = None - self.buttongroup = None - - self.heroes = {} - self.stat_table = None - self.stats_frame = None - - self.main_hbox = gtk.HBox(False, 0) - self.main_hbox.show() - - playerFrame = gtk.Frame("Hero:") - playerFrame.set_label_align(0.0, 0.0) - playerFrame.show() - vbox = gtk.VBox(False, 0) - vbox.show() - - self.fillPlayerFrame(vbox) - playerFrame.add(vbox) - - cardsFrame = gtk.Frame("Cards:") - cardsFrame.set_label_align(0.0, 0.0) - cardsFrame.show() - vbox = gtk.VBox(False, 0) - vbox.show() - - self.fillCardsFrame(vbox) - cardsFrame.add(vbox) - - statsFrame = gtk.Frame("Stats:") - statsFrame.set_label_align(0.0, 0.0) - statsFrame.show() - self.stats_frame = gtk.VBox(False, 0) - self.stats_frame.show() - - self.fillStatsFrame(self.stats_frame) - statsFrame.add(self.stats_frame) - - self.main_hbox.pack_start(playerFrame) - self.main_hbox.pack_start(statsFrame) + # Filter on dates + query = query.replace("", " between '" + dates[0] + "' and '" + dates[1] + "'") + #print "query =\n", query + return(query) + #end def refineQuery(self, query, playerids, sitenos, limits): diff --git a/pyfpdb/GuiSessionViewer.py b/pyfpdb/GuiSessionViewer.py new file mode 100644 index 00000000..51398b0f --- /dev/null +++ b/pyfpdb/GuiSessionViewer.py @@ -0,0 +1,310 @@ +#!/usr/bin/python + +#Copyright 2008 Steffen Jobbagy-Felso +#This program is free software: you can redistribute it and/or modify +#it under the terms of the GNU Affero General Public License as published by +#the Free Software Foundation, version 3 of the License. +# +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +# +#You should have received a copy of the GNU Affero General Public License +#along with this program. If not, see . +#In the "official" distribution you can find the license in +#agpl-3.0.txt in the docs folder of the package. + +import threading +import pygtk +pygtk.require('2.0') +import gtk +import os +from time import time, strftime, localtime +from numpy import diff, nonzero + +import Card +import fpdb_import +import fpdb_db +import Filters +import FpdbSQLQueries + +class GuiSessionViewer (threading.Thread): + def __init__(self, config, querylist, debug=True): + self.debug=debug + self.conf=config + self.MYSQL_INNODB = 2 + self.PGSQL = 3 + self.SQLITE = 4 + + # create new db connection to avoid conflicts with other threads + self.db = fpdb_db.fpdb_db() + self.db.do_connect(self.conf) + self.cursor=self.db.cursor + self.sql = querylist + + settings = {} + settings.update(config.get_db_parameters()) + settings.update(config.get_tv_parameters()) + settings.update(config.get_import_parameters()) + settings.update(config.get_default_paths()) + + # text used on screen stored here so that it can be configured + 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" : False, + "Groups" : True, + "Button1" : True, + "Button2" : True + } + + self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display) + self.filters.registerButton2Name("_Refresh") + self.filters.registerButton2Callback(self.refreshStats) + + # ToDo: store in config + # ToDo: create popup to adjust column config + # columns to display, keys match column name returned by sql, values in tuple are: + # is column displayed, column heading, xalignment, formatting + self.columns = [ ("game", True, "Game", 0.0, "%s") + , ("hand", False, "Hand", 0.0, "%s") # true not allowed for this line + , ("n", True, "Hds", 1.0, "%d") + , ("avgseats", True, "Seats", 1.0, "%3.1f") + , ("vpip", True, "VPIP", 1.0, "%3.1f") + , ("pfr", True, "PFR", 1.0, "%3.1f") + , ("pf3", True, "PF3", 1.0, "%3.1f") + , ("steals", True, "Steals", 1.0, "%3.1f") + , ("saw_f", True, "Saw_F", 1.0, "%3.1f") + , ("sawsd", True, "SawSD", 1.0, "%3.1f") + , ("wtsdwsf", True, "WtSDwsF", 1.0, "%3.1f") + , ("wmsd", True, "W$SD", 1.0, "%3.1f") + , ("flafq", True, "FlAFq", 1.0, "%3.1f") + , ("tuafq", True, "TuAFq", 1.0, "%3.1f") + , ("rvafq", True, "RvAFq", 1.0, "%3.1f") + , ("pofafq", False, "PoFAFq", 1.0, "%3.1f") + , ("net", True, "Net($)", 1.0, "%6.2f") + , ("bbper100", True, "BB/100", 1.0, "%4.2f") + , ("rake", True, "Rake($)", 1.0, "%6.2f") + , ("variance", True, "Variance", 1.0, "%5.2f") + ] + + self.stats_frame = None + 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.stats_frame = gtk.Frame() + self.stats_frame.show() + + self.stats_vbox = gtk.VBox(False, 0) + self.stats_vbox.show() + 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) + +################################ + + + # make sure Hand column is not displayed + [x for x in self.columns if x[0] == 'hand'][0][1] == False + + def get_vbox(self): + """returns the vbox of this thread""" + return self.main_hbox + + def refreshStats(self, widget, data): + try: self.stats_vbox.destroy() + except AttributeError: pass + self.stats_vbox = gtk.VBox(False, 0) + self.stats_vbox.show() + self.stats_frame.add(self.stats_vbox) + self.fillStatsFrame(self.stats_vbox) + + def fillStatsFrame(self, vbox): + sites = self.filters.getSites() + heroes = self.filters.getHeroes() + siteids = self.filters.getSiteIds() + limits = self.filters.getLimits() + seats = self.filters.getSeats() + sitenos = [] + playerids = [] + + # Which sites are selected? + for site in sites: + if sites[site] == True: + sitenos.append(siteids[site]) + self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) + result = self.db.cursor.fetchall() + if len(result) == 1: + playerids.append(result[0][0]) + + if not sitenos: + #Should probably pop up here. + print "No sites selected - defaulting to PokerStars" + sitenos = [2] + if not playerids: + print "No player ids found" + return + if not limits: + print "No limits found" + return + + self.createStatsTable(vbox, playerids, sitenos, limits, seats) + + def createStatsTable(self, vbox, playerids, sitenos, limits, seats): + starttime = time() + + # 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) + + # Separator + sep = gtk.HSeparator() + vbox.pack_start(sep, expand=False, padding=3) + sep.show_now() + vbox.show_now() + heading = gtk.Label(self.filterText['handhead']) + heading.show() + vbox.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) + + # Detailed table + flags = [True] + self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats) + + self.db.db.commit() + 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): + row = 0 + sqlrow = 0 + colalias,colshow,colheading,colxalign,colformat = 0,1,2,3,4 + if not flags: holecards = False + else: holecards = flags[0] + + + self.stats_table = gtk.Table(1, 1, False) + self.stats_table.set_col_spacings(4) + self.stats_table.show() + + self.db.cursor.execute("""select UNIX_TIMESTAMP(handStart) as time, id from Hands ORDER BY time""") + THRESHOLD = 1800 + hands = self.db.cursor.fetchall() + + times = map(lambda x:long(x[0]), hands) + handids = map(lambda x:int(x[1]), hands) + print "DEBUG: len(times) %s" %(len(times)) + diffs = diff(times) + print "DEBUG: len(diffs) %s" %(len(diffs)) + index = nonzero(diff(times) > THRESHOLD) + print "DEBUG: len(index[0]) %s" %(len(index[0])) + print "DEBUG: index %s" %(index) + print "DEBUG: index[0][0] %s" %(index[0][0]) + + total = 0 + + last_idx = 0 + for i in range(len(index[0])): + print "Hands in session %4s: %4s Start: %s End: %s Total: %s" %(i, index[0][i] - last_idx, strftime("%d/%m/%Y %H:%M", localtime(times[last_idx])), strftime("%d/%m/%Y %H:%M", localtime(times[index[0][i]])), times[index[0][i]] - times[last_idx]) + total = total + (index[0][i] - last_idx) + last_idx = index[0][i] + 1 + + print "Total: ", total +# +# colnames = [desc[0].lower() for desc in self.cursor.description] +# +# # pre-fetch some constant values: +# cols_to_show = [x for x in self.columns if x[colshow]] +# hgametypeid_idx = colnames.index('hgametypeid') +# +# 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) +# textcell = gtk.CellRendererText() +# numcell = gtk.CellRendererText() +# numcell.set_property('xalign', 1.0) +# listcols = [] +# +# # Create header row eg column: ("game", True, "Game", 0.0, "%s") +# for col, column in enumerate(cols_to_show): +# if column[colalias] == 'game' and holecards: +# s = [x for x in self.columns if x[colalias] == 'hand'][0][colheading] +# else: +# s = column[colheading] +# listcols.append(gtk.TreeViewColumn(s)) +# view.append_column(listcols[col]) +# if column[colformat] == '%s': +# if col == 1 and holecards: +# listcols[col].pack_start(textcell, expand=True) +# else: +# listcols[col].pack_start(textcell, expand=False) +# listcols[col].add_attribute(textcell, 'text', col) +# else: +# listcols[col].pack_start(numcell, expand=False) +# listcols[col].add_attribute(numcell, 'text', col) +# +# rows = len(result) # +1 for title row +# +# while sqlrow < rows: +# treerow = [] +# if(row%2 == 0): +# bgcolor = "white" +# else: +# bgcolor = "lightgrey" +# for col,column in enumerate(cols_to_show): +# if column[colalias] in colnames: +# value = result[sqlrow][colnames.index(column[colalias])] +# else: +# if column[colalias] == 'game': +# if holecards: +# value = Card.twoStartCardString( result[sqlrow][hgametypeid_idx] ) +# else: +# minbb = result[sqlrow][colnames.index('minbigblind')] +# maxbb = result[sqlrow][colnames.index('maxbigblind')] +# value = result[sqlrow][colnames.index('limittype')] + ' ' \ +# + result[sqlrow][colnames.index('category')].title() + ' ' \ +# + result[sqlrow][colnames.index('name')] + ' $' +# if 100 * int(minbb/100.0) != minbb: +# value += '%.2f' % (minbb/100.0) +# else: +# value += '%.0f' % (minbb/100.0) +# if minbb != maxbb: +# if 100 * int(maxbb/100.0) != maxbb: +# value += ' - $' + '%.2f' % (maxbb/100.0) +# else: +# value += ' - $' + '%.0f' % (maxbb/100.0) +# else: +# continue +# if value and value != -999: +# treerow.append(column[colformat] % value) +# else: +# treerow.append(' ') +# iter = liststore.append(treerow) +# sqlrow += 1 +# row += 1 + vbox.show_all() diff --git a/pyfpdb/GuiTableViewer.py b/pyfpdb/GuiTableViewer.py index f024a193..35dbb797 100644 --- a/pyfpdb/GuiTableViewer.py +++ b/pyfpdb/GuiTableViewer.py @@ -76,7 +76,7 @@ class GuiTableViewer (threading.Thread): arr=[] #first prepare the header row if (self.category=="holdem" or self.category=="omahahi" or self.category=="omahahilo"): - tmp=("Name", "HDs", "VPIP", "PFR", "PF3B4B", "ST") + tmp=("Name", "HDs", "VPIP", "PFR", "PF3B", "ST") tmp+=("FS", "FB") @@ -131,7 +131,7 @@ class GuiTableViewer (threading.Thread): tmp.append(str(row[6]))#Hands tmp.append(self.hudDivide(row[7],row[6])) #VPIP tmp.append(self.hudDivide(row[8],row[6])) #PFR - tmp.append(self.hudDivide(row[10],row[9])+" ("+str(row[9])+")") #PF3B4B + tmp.append(self.hudDivide(row[10],row[9])+" ("+str(row[9])+")") #PF3B tmp.append(self.hudDivide(row[31],row[30])+" ("+str(row[30])+")") #ST diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index e300e67b..ef30fb9b 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -1,8 +1,25 @@ + + + - + + @@ -49,7 +66,21 @@ - + + @@ -84,7 +115,16 @@ - + + @@ -120,8 +160,10 @@ + - + + @@ -129,7 +171,8 @@ - + + @@ -137,7 +180,8 @@ - + + @@ -145,7 +189,8 @@ - + + @@ -153,7 +198,8 @@ - + + @@ -161,7 +207,8 @@ - + + @@ -170,6 +217,7 @@ + @@ -196,15 +244,60 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 332e33c8..5d34e409 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -51,6 +51,8 @@ import Database import Tables import Hud +aggregate_stats = {"ring": False, "tour": False} # config file! + class HUD_main(object): """A main() object to own both the read_stdin thread and the gui.""" # This class mainly provides state for controlling the multiple HUDs. @@ -79,13 +81,14 @@ class HUD_main(object): def kill_hud(self, event, table): # called by an event in the HUD, to kill this specific HUD - self.hud_dict[table].kill() - self.hud_dict[table].main_window.destroy() - self.vb.remove(self.hud_dict[table].tablehudlabel) - del(self.hud_dict[table]) + if table in self.hud_dict: + self.hud_dict[table].kill() + self.hud_dict[table].main_window.destroy() + self.vb.remove(self.hud_dict[table].tablehudlabel) + del(self.hud_dict[table]) self.main_window.resize(1,1) - def create_HUD(self, new_hand_id, table, table_name, max, poker_game, is_tournament, stat_dict, cards): + def create_HUD(self, new_hand_id, table, table_name, max, poker_game, stat_dict, cards): def idle_func(): @@ -108,9 +111,9 @@ class HUD_main(object): gtk.gdk.threads_leave() self.hud_dict[table_name] = Hud.Hud(self, table, max, poker_game, self.config, self.db_connection) + self.hud_dict[table_name].table_name = table_name self.hud_dict[table_name].stat_dict = stat_dict self.hud_dict[table_name].cards = cards - [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[table_name].aux_windows] gobject.idle_add(idle_func) @@ -149,8 +152,8 @@ class HUD_main(object): # get basic info about the new hand from the db # if there is a db error, complain, skip hand, and proceed try: - (table_name, max, poker_game) = self.db_connection.get_table_name(new_hand_id) - stat_dict = self.db_connection.get_stats_from_hand(new_hand_id) + (table_name, max, poker_game, type) = self.db_connection.get_table_name(new_hand_id) + stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, aggregate = aggregate_stats[type]) cards = self.db_connection.get_cards(new_hand_id) comm_cards = self.db_connection.get_common_cards(new_hand_id) if comm_cards != {}: # stud! @@ -160,15 +163,17 @@ class HUD_main(object): sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) continue -# find out if this hand is from a tournament - mat_obj = tourny_finder.search(table_name) - if mat_obj: - is_tournament = True - (tour_number, tab_number) = mat_obj.group(1, 2) - temp_key = tour_number + if type == "tour": # hand is from a tournament + mat_obj = tourny_finder.search(table_name) + if mat_obj: + (tour_number, tab_number) = mat_obj.group(1, 2) + temp_key = tour_number + else: # tourney, but can't get number and table + print "could not find tournament: skipping " + sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id))) + continue + else: - is_tournament = False - (tour_number, tab_number) = (0, 0) temp_key = table_name # Update an existing HUD @@ -180,18 +185,18 @@ class HUD_main(object): # Or create a new HUD else: - if is_tournament: + if type == "tour": tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number) else: tablewindow = Tables.discover_table_by_name(self.config, table_name) - if tablewindow == None: # If no client window is found on the screen, complain and continue - if is_tournament: + if type == "tour": table_name = "%s %s" % (tour_number, tab_number) sys.stderr.write("table name "+table_name+" not found, skipping.\n") else: - self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, is_tournament, stat_dict, cards) + self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, stat_dict, cards) + self.db_connection.connection.rollback() if __name__== "__main__": sys.stderr.write("HUD_main starting\n") diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 8360dc20..5ff2c9d7 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -125,7 +125,7 @@ class Hud: self.menu = gtk.Menu() self.item1 = gtk.MenuItem('Kill this HUD') self.menu.append(self.item1) - self.item1.connect("activate", self.parent.kill_hud, self.table.name) + self.item1.connect("activate", self.parent.kill_hud, self.table_name) self.item1.show() self.item2 = gtk.MenuItem('Save Layout') @@ -204,14 +204,14 @@ class Hud: def reposition_windows(self, *args): for w in self.stat_windows.itervalues(): if type(w) == int: - print "in reposition, w =", w +# print "in reposition, w =", w continue - print "in reposition, w =", w, w.x, w.y +# print "in reposition, w =", w, w.x, w.y w.window.move(w.x, w.y) return True def debug_stat_windows(self, *args): - print self.table, "\n", self.main_window.window.get_transient_for() +# print self.table, "\n", self.main_window.window.get_transient_for() for w in self.stat_windows: print self.stat_windows[w].window.window.get_transient_for() diff --git a/pyfpdb/Mucked.py b/pyfpdb/Mucked.py index 9d70f8e3..93f6d102 100755 --- a/pyfpdb/Mucked.py +++ b/pyfpdb/Mucked.py @@ -451,7 +451,7 @@ class Flop_Mucked(Aux_Window): def save_layout(self, *args): """Save new layout back to the aux element in the config file.""" new_locs = {} - print "adj =", self.adj +# print "adj =", self.adj for (i, pos) in self.positions.iteritems(): if i != 'common': new_locs[self.adj[int(i)]] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index f81d4dc7..300c6071 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -73,7 +73,7 @@ follow : whether to tail -f the input""" ["ring", "hold", "pl"], ["ring", "hold", "fl"], ["ring", "stud", "fl"], - ["ring", "draw", "fl"], + #["ring", "draw", "fl"], ["ring", "omaha", "pl"] ] diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 2c67cb0a..18d7d116 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -29,7 +29,7 @@ Set up all of the SQL statements for a given game and database type. class Sql: - def __init__(self, game = 'holdem', type = 'PT3'): + def __init__(self, game = 'holdem', type = 'PT3', db_server = 'mysql'): self.query = {} ############################################################################ @@ -172,148 +172,328 @@ class Sql: """ self.query['get_stats_from_hand'] = """ - SELECT HudCache.playerId AS player_id, - seatNo AS seat, - name AS screen_name, - sum(HDs) AS n, - sum(street0VPI) AS vpip, - sum(street0Aggr) AS pfr, - sum(street0_3B4BChance) AS TB_opp_0, - sum(street0_3B4BDone) AS TB_0, - sum(street1Seen) AS saw_f, - sum(street1Seen) AS saw_1, - sum(street2Seen) AS saw_2, - sum(street3Seen) AS saw_3, - sum(street4Seen) AS saw_4, - sum(sawShowdown) AS sd, - sum(street1Aggr) AS aggr_1, - sum(street2Aggr) AS aggr_2, - sum(street3Aggr) AS aggr_3, - sum(street4Aggr) AS aggr_4, - sum(otherRaisedStreet1) AS was_raised_1, - sum(otherRaisedStreet2) AS was_raised_2, - sum(otherRaisedStreet3) AS was_raised_3, - sum(otherRaisedStreet4) AS was_raised_4, - sum(foldToOtherRaisedStreet1) AS f_freq_1, - sum(foldToOtherRaisedStreet2) AS f_freq_2, - sum(foldToOtherRaisedStreet3) AS f_freq_3, - sum(foldToOtherRaisedStreet4) AS f_freq_4, - sum(wonWhenSeenStreet1) AS w_w_s_1, - sum(wonAtSD) AS wmsd, - sum(stealAttemptChance) AS steal_opp, - sum(stealAttempted) AS steal, - sum(foldSbToStealChance) AS SBstolen, - sum(foldedSbToSteal) AS SBnotDef, - sum(foldBbToStealChance) AS BBstolen, - sum(foldedBbToSteal) AS BBnotDef, - sum(street1CBChance) AS CB_opp_1, - sum(street1CBDone) AS CB_1, - sum(street2CBChance) AS CB_opp_2, - sum(street2CBDone) AS CB_2, - sum(street3CBChance) AS CB_opp_3, - sum(street3CBDone) AS CB_3, - sum(street4CBChance) AS CB_opp_4, - sum(street4CBDone) AS CB_4, - sum(foldToStreet1CBChance) AS f_cb_opp_1, - sum(foldToStreet1CBDone) AS f_cb_1, - sum(foldToStreet2CBChance) AS f_cb_opp_2, - sum(foldToStreet2CBDone) AS f_cb_2, - sum(foldToStreet3CBChance) AS f_cb_opp_3, - sum(foldToStreet3CBDone) AS f_cb_3, - sum(foldToStreet4CBChance) AS f_cb_opp_4, - sum(foldToStreet4CBDone) AS f_cb_4, - sum(totalProfit) AS net, - sum(street1CheckCallRaiseChance) AS ccr_opp_1, - sum(street1CheckCallRaiseDone) AS ccr_1, - sum(street2CheckCallRaiseChance) AS ccr_opp_2, - sum(street2CheckCallRaiseDone) AS ccr_2, - sum(street3CheckCallRaiseChance) AS ccr_opp_3, - sum(street3CheckCallRaiseDone) AS ccr_3, - sum(street4CheckCallRaiseChance) AS ccr_opp_4, - sum(street4CheckCallRaiseDone) AS ccr_4 - FROM Hands - INNER JOIN HandsPlayers ON (HandsPlayers.handId = %s) - INNER JOIN HudCache ON ( HudCache.PlayerId = HandsPlayers.PlayerId+0 - AND HudCache.gametypeId+0 = Hands.gametypeId+0) - INNER JOIN Players ON (Players.id = HandsPlayers.PlayerId+0) - WHERE Hands.id = %s - GROUP BY HudCache.PlayerId + SELECT hc.playerId AS player_id, + hp.seatNo AS seat, + p.name AS screen_name, + sum(hc.HDs) AS n, + sum(hc.street0VPI) AS vpip, + sum(hc.street0Aggr) AS pfr, + sum(hc.street0_3BChance) AS TB_opp_0, + sum(hc.street0_3BDone) AS TB_0, + sum(hc.street1Seen) AS saw_f, + sum(hc.street1Seen) AS saw_1, + sum(hc.street2Seen) AS saw_2, + sum(hc.street3Seen) AS saw_3, + sum(hc.street4Seen) AS saw_4, + sum(hc.sawShowdown) AS sd, + sum(hc.street1Aggr) AS aggr_1, + sum(hc.street2Aggr) AS aggr_2, + sum(hc.street3Aggr) AS aggr_3, + sum(hc.street4Aggr) AS aggr_4, + sum(hc.otherRaisedStreet1) AS was_raised_1, + sum(hc.otherRaisedStreet2) AS was_raised_2, + sum(hc.otherRaisedStreet3) AS was_raised_3, + sum(hc.otherRaisedStreet4) AS was_raised_4, + sum(hc.foldToOtherRaisedStreet1) AS f_freq_1, + sum(hc.foldToOtherRaisedStreet2) AS f_freq_2, + sum(hc.foldToOtherRaisedStreet3) AS f_freq_3, + sum(hc.foldToOtherRaisedStreet4) AS f_freq_4, + sum(hc.wonWhenSeenStreet1) AS w_w_s_1, + sum(hc.wonAtSD) AS wmsd, + sum(hc.stealAttemptChance) AS steal_opp, + sum(hc.stealAttempted) AS steal, + sum(hc.foldSbToStealChance) AS SBstolen, + sum(hc.foldedSbToSteal) AS SBnotDef, + sum(hc.foldBbToStealChance) AS BBstolen, + sum(hc.foldedBbToSteal) AS BBnotDef, + sum(hc.street1CBChance) AS CB_opp_1, + sum(hc.street1CBDone) AS CB_1, + sum(hc.street2CBChance) AS CB_opp_2, + sum(hc.street2CBDone) AS CB_2, + sum(hc.street3CBChance) AS CB_opp_3, + sum(hc.street3CBDone) AS CB_3, + sum(hc.street4CBChance) AS CB_opp_4, + sum(hc.street4CBDone) AS CB_4, + sum(hc.foldToStreet1CBChance) AS f_cb_opp_1, + sum(hc.foldToStreet1CBDone) AS f_cb_1, + sum(hc.foldToStreet2CBChance) AS f_cb_opp_2, + sum(hc.foldToStreet2CBDone) AS f_cb_2, + sum(hc.foldToStreet3CBChance) AS f_cb_opp_3, + sum(hc.foldToStreet3CBDone) AS f_cb_3, + sum(hc.foldToStreet4CBChance) AS f_cb_opp_4, + sum(hc.foldToStreet4CBDone) AS f_cb_4, + sum(hc.totalProfit) AS net, + sum(hc.street1CheckCallRaiseChance) AS ccr_opp_1, + sum(hc.street1CheckCallRaiseDone) AS ccr_1, + sum(hc.street2CheckCallRaiseChance) AS ccr_opp_2, + sum(hc.street2CheckCallRaiseDone) AS ccr_2, + sum(hc.street3CheckCallRaiseChance) AS ccr_opp_3, + sum(hc.street3CheckCallRaiseDone) AS ccr_3, + sum(hc.street4CheckCallRaiseChance) AS ccr_opp_4, + sum(hc.street4CheckCallRaiseDone) AS ccr_4 + FROM Hands h + INNER JOIN HandsPlayers hp ON (hp.handId = %s) + INNER JOIN HudCache hc ON ( hc.PlayerId = hp.PlayerId+0 + AND hc.gametypeId+0 = h.gametypeId+0) + INNER JOIN Players p ON (p.id = hp.PlayerId+0) + WHERE h.id = %s + AND hc.styleKey > %s + /* styleKey is currently 'd' (for date) followed by a yyyymmdd + date key. Set it to 0000000 or similar to get all records */ + /* also check activeseats here? even if only 3 groups eg 2-3/4-6/7+ ?? + e.g. could use a multiplier: + AND h.seats > X / 1.25 and hp.seats < X * 1.25 + where X is the number of active players at the current table (and + 1.25 would be a config value so user could change it) + */ + GROUP BY hc.PlayerId, hp.seatNo, p.name """ # same as above except stats are aggregated for all blind/limit levels self.query['get_stats_from_hand_aggregated'] = """ - SELECT HudCache.playerId AS player_id, - sum(HDs) AS n, - sum(street0VPI) AS vpip, - sum(street0Aggr) AS pfr, - sum(street0_3B4BChance) AS TB_opp_0, - sum(street0_3B4BDone) AS TB_0, - sum(street1Seen) AS saw_f, - sum(street1Seen) AS saw_1, - sum(street2Seen) AS saw_2, - sum(street3Seen) AS saw_3, - sum(street4Seen) AS saw_4, - sum(sawShowdown) AS sd, - sum(street1Aggr) AS aggr_1, - sum(street2Aggr) AS aggr_2, - sum(street3Aggr) AS aggr_3, - sum(street4Aggr) AS aggr_4, - sum(otherRaisedStreet1) AS was_raised_1, - sum(otherRaisedStreet2) AS was_raised_2, - sum(otherRaisedStreet3) AS was_raised_3, - sum(otherRaisedStreet4) AS was_raised_4, - sum(foldToOtherRaisedStreet1) AS f_freq_1, - sum(foldToOtherRaisedStreet2) AS f_freq_2, - sum(foldToOtherRaisedStreet3) AS f_freq_3, - sum(foldToOtherRaisedStreet4) AS f_freq_4, - sum(wonWhenSeenStreet1) AS w_w_s_1, - sum(wonAtSD) AS wmsd, - sum(stealAttemptChance) AS steal_opp, - sum(stealAttempted) AS steal, - sum(foldSbToStealChance) AS SBstolen, - sum(foldedSbToSteal) AS SBnotDef, - sum(foldBbToStealChance) AS BBstolen, - sum(foldedBbToSteal) AS BBnotDef, - sum(street1CBChance) AS CB_opp_1, - sum(street1CBDone) AS CB_1, - sum(street2CBChance) AS CB_opp_2, - sum(street2CBDone) AS CB_2, - sum(street3CBChance) AS CB_opp_3, - sum(street3CBDone) AS CB_3, - sum(street4CBChance) AS CB_opp_4, - sum(street4CBDone) AS CB_4, - sum(foldToStreet1CBChance) AS f_cb_opp_1, - sum(foldToStreet1CBDone) AS f_cb_1, - sum(foldToStreet2CBChance) AS f_cb_opp_2, - sum(foldToStreet2CBDone) AS f_cb_2, - sum(foldToStreet3CBChance) AS f_cb_opp_3, - sum(foldToStreet3CBDone) AS f_cb_3, - sum(foldToStreet4CBChance) AS f_cb_opp_4, - sum(foldToStreet4CBDone) AS f_cb_4, - sum(totalProfit) AS net, - sum(street1CheckCallRaiseChance) AS ccr_opp_1, - sum(street1CheckCallRaiseDone) AS ccr_1, - sum(street2CheckCallRaiseChance) AS ccr_opp_2, - sum(street2CheckCallRaiseDone) AS ccr_2, - sum(street3CheckCallRaiseChance) AS ccr_opp_3, - sum(street3CheckCallRaiseDone) AS ccr_3, - sum(street4CheckCallRaiseChance) AS ccr_opp_4, - sum(street4CheckCallRaiseDone) AS ccr_4 - FROM HudCache, Hands - WHERE HudCache.PlayerId in - (SELECT PlayerId FROM HandsPlayers - WHERE handId = %s) - AND Hands.id = %s - AND HudCache.gametypeId in - (SELECT gt1.id from Gametypes gt1, Gametypes gt2, Hands - WHERE gt1.siteid = gt2.siteid - AND gt1.type = gt2.type - AND gt1.category = gt2.category - AND gt1.limittype = gt2.limittype - AND gt2.id = Hands.gametypeId - AND Hands.id = %s) - GROUP BY HudCache.PlayerId + SELECT hc.playerId AS player_id, + max(case when hc.gametypeId = h.gametypeId + then hp.seatNo + else -1 + end) AS seat, + p.name AS screen_name, + sum(hc.HDs) AS n, + sum(hc.street0VPI) AS vpip, + sum(hc.street0Aggr) AS pfr, + sum(hc.street0_3BChance) AS TB_opp_0, + sum(hc.street0_3BDone) AS TB_0, + sum(hc.street1Seen) AS saw_f, + sum(hc.street1Seen) AS saw_1, + sum(hc.street2Seen) AS saw_2, + sum(hc.street3Seen) AS saw_3, + sum(hc.street4Seen) AS saw_4, + sum(hc.sawShowdown) AS sd, + sum(hc.street1Aggr) AS aggr_1, + sum(hc.street2Aggr) AS aggr_2, + sum(hc.street3Aggr) AS aggr_3, + sum(hc.street4Aggr) AS aggr_4, + sum(hc.otherRaisedStreet1) AS was_raised_1, + sum(hc.otherRaisedStreet2) AS was_raised_2, + sum(hc.otherRaisedStreet3) AS was_raised_3, + sum(hc.otherRaisedStreet4) AS was_raised_4, + sum(hc.foldToOtherRaisedStreet1) AS f_freq_1, + sum(hc.foldToOtherRaisedStreet2) AS f_freq_2, + sum(hc.foldToOtherRaisedStreet3) AS f_freq_3, + sum(hc.foldToOtherRaisedStreet4) AS f_freq_4, + sum(hc.wonWhenSeenStreet1) AS w_w_s_1, + sum(hc.wonAtSD) AS wmsd, + sum(hc.stealAttemptChance) AS steal_opp, + sum(hc.stealAttempted) AS steal, + sum(hc.foldSbToStealChance) AS SBstolen, + sum(hc.foldedSbToSteal) AS SBnotDef, + sum(hc.foldBbToStealChance) AS BBstolen, + sum(hc.foldedBbToSteal) AS BBnotDef, + sum(hc.street1CBChance) AS CB_opp_1, + sum(hc.street1CBDone) AS CB_1, + sum(hc.street2CBChance) AS CB_opp_2, + sum(hc.street2CBDone) AS CB_2, + sum(hc.street3CBChance) AS CB_opp_3, + sum(hc.street3CBDone) AS CB_3, + sum(hc.street4CBChance) AS CB_opp_4, + sum(hc.street4CBDone) AS CB_4, + sum(hc.foldToStreet1CBChance) AS f_cb_opp_1, + sum(hc.foldToStreet1CBDone) AS f_cb_1, + sum(hc.foldToStreet2CBChance) AS f_cb_opp_2, + sum(hc.foldToStreet2CBDone) AS f_cb_2, + sum(hc.foldToStreet3CBChance) AS f_cb_opp_3, + sum(hc.foldToStreet3CBDone) AS f_cb_3, + sum(hc.foldToStreet4CBChance) AS f_cb_opp_4, + sum(hc.foldToStreet4CBDone) AS f_cb_4, + sum(hc.totalProfit) AS net, + sum(hc.street1CheckCallRaiseChance) AS ccr_opp_1, + sum(hc.street1CheckCallRaiseDone) AS ccr_1, + sum(hc.street2CheckCallRaiseChance) AS ccr_opp_2, + sum(hc.street2CheckCallRaiseDone) AS ccr_2, + sum(hc.street3CheckCallRaiseChance) AS ccr_opp_3, + sum(hc.street3CheckCallRaiseDone) AS ccr_3, + sum(hc.street4CheckCallRaiseChance) AS ccr_opp_4, + sum(hc.street4CheckCallRaiseDone) AS ccr_4 + FROM Hands h + INNER JOIN HandsPlayers hp ON (hp.handId = %s) + INNER JOIN HudCache hc ON (hc.playerId = hp.playerId) + INNER JOIN Players p ON (p.id = hc.playerId) + WHERE h.id = %s + AND hc.styleKey > %s + /* styleKey is currently 'd' (for date) followed by a yyyymmdd + date key. Set it to 0000000 or similar to get all records */ + /* also check activeseats here? even if only 3 groups eg 2-3/4-6/7+ ?? + e.g. could use a multiplier: + AND h.seats > %s / 1.25 and hp.seats < %s * 1.25 + where %s is the number of active players at the current table (and + 1.25 would be a config value so user could change it) + */ + AND hc.gametypeId+0 in + (SELECT gt1.id from Gametypes gt1, Gametypes gt2 + WHERE gt1.siteid = gt2.siteid + AND gt1.type = gt2.type + AND gt1.category = gt2.category + AND gt1.limittype = gt2.limittype + AND gt2.id = h.gametypeId) + GROUP BY hc.PlayerId, p.name, hc.styleKey """ + + if db_server == 'mysql': + self.query['get_stats_from_hand_session'] = """ + SELECT hp.playerId AS player_id, + hp.handId AS hand_id, + hp.seatNo AS seat, + p.name AS screen_name, + h.seats AS seats, + 1 AS n, + cast(hp2.street0VPI as integer) AS vpip, + cast(hp2.street0Aggr as integer) AS pfr, + cast(hp2.street0_3BChance as integer) AS TB_opp_0, + cast(hp2.street0_3BDone as integer) AS TB_0, + cast(hp2.street1Seen as integer) AS saw_f, + cast(hp2.street1Seen as integer) AS saw_1, + cast(hp2.street2Seen as integer) AS saw_2, + cast(hp2.street3Seen as integer) AS saw_3, + cast(hp2.street4Seen as integer) AS saw_4, + cast(hp2.sawShowdown as integer) AS sd, + cast(hp2.street1Aggr as integer) AS aggr_1, + cast(hp2.street2Aggr as integer) AS aggr_2, + cast(hp2.street3Aggr as integer) AS aggr_3, + cast(hp2.street4Aggr as integer) AS aggr_4, + cast(hp2.otherRaisedStreet1 as integer) AS was_raised_1, + cast(hp2.otherRaisedStreet2 as integer) AS was_raised_2, + cast(hp2.otherRaisedStreet3 as integer) AS was_raised_3, + cast(hp2.otherRaisedStreet4 as integer) AS was_raised_4, + cast(hp2.foldToOtherRaisedStreet1 as integer) AS f_freq_1, + cast(hp2.foldToOtherRaisedStreet2 as integer) AS f_freq_2, + cast(hp2.foldToOtherRaisedStreet3 as integer) AS f_freq_3, + cast(hp2.foldToOtherRaisedStreet4 as integer) AS f_freq_4, + cast(hp2.wonWhenSeenStreet1 as integer) AS w_w_s_1, + cast(hp2.wonAtSD as integer) AS wmsd, + cast(hp2.stealAttemptChance as integer) AS steal_opp, + cast(hp2.stealAttempted as integer) AS steal, + cast(hp2.foldSbToStealChance as integer) AS SBstolen, + cast(hp2.foldedSbToSteal as integer) AS SBnotDef, + cast(hp2.foldBbToStealChance as integer) AS BBstolen, + cast(hp2.foldedBbToSteal as integer) AS BBnotDef, + cast(hp2.street1CBChance as integer) AS CB_opp_1, + cast(hp2.street1CBDone as integer) AS CB_1, + cast(hp2.street2CBChance as integer) AS CB_opp_2, + cast(hp2.street2CBDone as integer) AS CB_2, + cast(hp2.street3CBChance as integer) AS CB_opp_3, + cast(hp2.street3CBDone as integer) AS CB_3, + cast(hp2.street4CBChance as integer) AS CB_opp_4, + cast(hp2.street4CBDone as integer) AS CB_4, + cast(hp2.foldToStreet1CBChance as integer) AS f_cb_opp_1, + cast(hp2.foldToStreet1CBDone as integer) AS f_cb_1, + cast(hp2.foldToStreet2CBChance as integer) AS f_cb_opp_2, + cast(hp2.foldToStreet2CBDone as integer) AS f_cb_2, + cast(hp2.foldToStreet3CBChance as integer) AS f_cb_opp_3, + cast(hp2.foldToStreet3CBDone as integer) AS f_cb_3, + cast(hp2.foldToStreet4CBChance as integer) AS f_cb_opp_4, + cast(hp2.foldToStreet4CBDone as integer) AS f_cb_4, + cast(hp2.totalProfit as integer) AS net, + cast(hp2.street1CheckCallRaiseChance as integer) AS ccr_opp_1, + cast(hp2.street1CheckCallRaiseDone as integer) AS ccr_1, + cast(hp2.street2CheckCallRaiseChance as integer) AS ccr_opp_2, + cast(hp2.street2CheckCallRaiseDone as integer) AS ccr_2, + cast(hp2.street3CheckCallRaiseChance as integer) AS ccr_opp_3, + cast(hp2.street3CheckCallRaiseDone as integer) AS ccr_3, + cast(hp2.street4CheckCallRaiseChance as integer) AS ccr_opp_4, + cast(hp2.street4CheckCallRaiseDone as integer) AS ccr_4 + FROM + Hands h /* players in this hand */ + INNER JOIN Hands h2 ON (h2.id > %s AND h2.tableName = h.tableName) + INNER JOIN HandsPlayers hp ON (h.id = hp.handId) + INNER JOIN HandsPlayers hp2 ON (hp2.playerId+0 = hp.playerId+0 AND (hp2.handId = h2.id+0)) /* other hands by these players */ + INNER JOIN Players p ON (p.id = hp2.PlayerId+0) + WHERE hp.handId = %s + /* check activeseats once this data returned? (don't want to do that here as it might + assume a session ended just because the number of seats dipped for a few hands) + */ + ORDER BY h.handStart desc, hp2.PlayerId + /* order rows by handstart descending so that we can stop reading rows when + there's a gap over X minutes between hands (ie. when we get back to start of + the session */ + """ + else: # assume postgresql + self.query['get_stats_from_hand_session'] = """ + SELECT hp.playerId AS player_id, + hp.handId AS hand_id, + hp.seatNo AS seat, + p.name AS screen_name, + h.seats AS seats, + 1 AS n, + cast(hp2.street0VPI as integer) AS vpip, + cast(hp2.street0Aggr as integer) AS pfr, + cast(hp2.street0_3BChance as integer) AS TB_opp_0, + cast(hp2.street0_3BDone as integer) AS TB_0, + cast(hp2.street1Seen as integer) AS saw_f, + cast(hp2.street1Seen as integer) AS saw_1, + cast(hp2.street2Seen as integer) AS saw_2, + cast(hp2.street3Seen as integer) AS saw_3, + cast(hp2.street4Seen as integer) AS saw_4, + cast(hp2.sawShowdown as integer) AS sd, + cast(hp2.street1Aggr as integer) AS aggr_1, + cast(hp2.street2Aggr as integer) AS aggr_2, + cast(hp2.street3Aggr as integer) AS aggr_3, + cast(hp2.street4Aggr as integer) AS aggr_4, + cast(hp2.otherRaisedStreet1 as integer) AS was_raised_1, + cast(hp2.otherRaisedStreet2 as integer) AS was_raised_2, + cast(hp2.otherRaisedStreet3 as integer) AS was_raised_3, + cast(hp2.otherRaisedStreet4 as integer) AS was_raised_4, + cast(hp2.foldToOtherRaisedStreet1 as integer) AS f_freq_1, + cast(hp2.foldToOtherRaisedStreet2 as integer) AS f_freq_2, + cast(hp2.foldToOtherRaisedStreet3 as integer) AS f_freq_3, + cast(hp2.foldToOtherRaisedStreet4 as integer) AS f_freq_4, + cast(hp2.wonWhenSeenStreet1 as integer) AS w_w_s_1, + cast(hp2.wonAtSD as integer) AS wmsd, + cast(hp2.stealAttemptChance as integer) AS steal_opp, + cast(hp2.stealAttempted as integer) AS steal, + cast(hp2.foldSbToStealChance as integer) AS SBstolen, + cast(hp2.foldedSbToSteal as integer) AS SBnotDef, + cast(hp2.foldBbToStealChance as integer) AS BBstolen, + cast(hp2.foldedBbToSteal as integer) AS BBnotDef, + cast(hp2.street1CBChance as integer) AS CB_opp_1, + cast(hp2.street1CBDone as integer) AS CB_1, + cast(hp2.street2CBChance as integer) AS CB_opp_2, + cast(hp2.street2CBDone as integer) AS CB_2, + cast(hp2.street3CBChance as integer) AS CB_opp_3, + cast(hp2.street3CBDone as integer) AS CB_3, + cast(hp2.street4CBChance as integer) AS CB_opp_4, + cast(hp2.street4CBDone as integer) AS CB_4, + cast(hp2.foldToStreet1CBChance as integer) AS f_cb_opp_1, + cast(hp2.foldToStreet1CBDone as integer) AS f_cb_1, + cast(hp2.foldToStreet2CBChance as integer) AS f_cb_opp_2, + cast(hp2.foldToStreet2CBDone as integer) AS f_cb_2, + cast(hp2.foldToStreet3CBChance as integer) AS f_cb_opp_3, + cast(hp2.foldToStreet3CBDone as integer) AS f_cb_3, + cast(hp2.foldToStreet4CBChance as integer) AS f_cb_opp_4, + cast(hp2.foldToStreet4CBDone as integer) AS f_cb_4, + cast(hp2.totalProfit as integer) AS net, + cast(hp2.street1CheckCallRaiseChance as integer) AS ccr_opp_1, + cast(hp2.street1CheckCallRaiseDone as integer) AS ccr_1, + cast(hp2.street2CheckCallRaiseChance as integer) AS ccr_opp_2, + cast(hp2.street2CheckCallRaiseDone as integer) AS ccr_2, + cast(hp2.street3CheckCallRaiseChance as integer) AS ccr_opp_3, + cast(hp2.street3CheckCallRaiseDone as integer) AS ccr_3, + cast(hp2.street4CheckCallRaiseChance as integer) AS ccr_opp_4, + cast(hp2.street4CheckCallRaiseDone as integer) AS ccr_4 + FROM Hands h /* this hand */ + INNER JOIN Hands h2 ON ( h2.id > %s /* other hands */ + AND h2.tableName = h.tableName) + INNER JOIN HandsPlayers hp ON (h.id = hp.handId) /* players in this hand */ + INNER JOIN HandsPlayers hp2 ON ( hp2.playerId+0 = hp.playerId+0 + AND hp2.handId = h2.id) /* other hands by these players */ + INNER JOIN Players p ON (p.id = hp2.PlayerId+0) + WHERE h.id = %s + /* check activeseats once this data returned? (don't want to do that here as it might + assume a session ended just because the number of seats dipped for a few hands) + */ + ORDER BY h.handStart desc, hp2.PlayerId + /* order rows by handstart descending so that we can stop reading rows when + there's a gap over X minutes between hands (ie. when we get back to start of + the session */ + """ self.query['get_players_from_hand'] = """ SELECT HandsPlayers.playerId, seatNo, name @@ -331,7 +511,7 @@ class Sql: """ self.query['get_table_name'] = """ - select tableName, maxSeats, category + select tableName, maxSeats, category, type from Hands,Gametypes where Hands.id = %s and Gametypes.id = Hands.gametypeId @@ -349,13 +529,13 @@ class Sql: select seatNo AS seat_number, name AS screen_name, - card1Value, card1Suit, - card2Value, card2Suit, - card3Value, card3Suit, - card4Value, card4Suit, - card5Value, card5Suit, - card6Value, card6Suit, - card7Value, card7Suit + card1, /*card1Value, card1Suit, */ + card2, /*card2Value, card2Suit, */ + card3, /*card3Value, card3Suit, */ + card4, /*card4Value, card4Suit, */ + card5, /*card5Value, card5Suit, */ + card6, /*card6Value, card6Suit, */ + card7 /*card7Value, card7Suit */ from HandsPlayers, Players where handID = %s and HandsPlayers.playerId = Players.id order by seatNo @@ -377,9 +557,21 @@ class Sql: FROM Players, HandsActions, HandsPlayers WHERE HandsPlayers.handid = %s AND HandsPlayers.playerid = Players.id - AND HandsActions.handPlayerId = HandsPlayers.id + AND HandsActions.handsPlayerId = HandsPlayers.id ORDER BY street, actionno """ + + if db_server == 'mysql': + self.query['get_hand_1day_ago'] = """ + select coalesce(max(id),0) + from hands + where handstart < date_sub(utc_timestamp(), interval '1' day)""" + else: # assume postgresql + self.query['get_hand_1day_ago'] = """ + select coalesce(max(id),0) + from hands + where handstart < now() at time zone 'UTC' - interval '1 day'""" + if __name__== "__main__": # just print the default queries and exit s = Sql(game = 'razz', type = 'ptracks') diff --git a/pyfpdb/Stats.py b/pyfpdb/Stats.py index 8c33f3a1..eddb0e25 100644 --- a/pyfpdb/Stats.py +++ b/pyfpdb/Stats.py @@ -32,6 +32,8 @@ # float(stat_dict[player]['vpip'])/float(stat_dict[player]['n']). You can see how the # keys of stat_dict relate to the column names in HudCache by inspecting # the proper section of the SQL.py module. +# The stat_dict keys should be in lower case, i.e. vpip not VPIP, since +# postgres returns the column names in lower case. # 3 You have to write a small function for each stat you want to add. See # the vpip() function for example. This function has to be protected from # exceptions, using something like the try:/except: paragraphs in vpip. @@ -189,6 +191,27 @@ def wtsd(stat_dict, player): '% went to showdown' ) +def wtsd_0(stat_dict, player): + """ Went to SD when saw flop/4th.""" + stat = 0.0 + try: + stat = float(stat_dict[player]['sd'])/float(stat_dict[player]['saw_f']) + return (stat, + '%2.0f' % (100*stat) + '%', + 'w=%2.0f' % (100*stat) + '%', + 'wtsd=%2.0f' % (100*stat) + '%', + '(%d/%d)' % (stat_dict[player]['sd'], stat_dict[player]['saw_f']), + '% went to showdown' + ) + except: + return (stat, + '%2.0f' % (0) + '%', + 'w=%2.0f' % (0) + '%', + 'wtsd=%2.0f' % (0) + '%', + '(%d/%d)' % (0, 0), + '% went to showdown' + ) + def wmsd(stat_dict, player): """ Won $ at showdown.""" stat = 0.0 @@ -210,6 +233,27 @@ def wmsd(stat_dict, player): '% won money at showdown' ) +def wmsd_0(stat_dict, player): + """ Won $ at showdown.""" + stat = 0.0 + try: + stat = float(stat_dict[player]['wmsd'])/float(stat_dict[player]['sd']) + return (stat, + '%2.0f' % (100*stat) + '%', + 'w=%2.0f' % (100*stat) + '%', + 'wmsd=%2.0f' % (100*stat) + '%', + '(%5.1f/%d)' % (float(stat_dict[player]['wmsd']), stat_dict[player]['sd']), + '% won money at showdown' + ) + except: + return (stat, + '%2.0f' % (0) + '%', + 'w=%2.0f' % (0) + '%', + 'wmsd=%2.0f' % (0) + '%', + '(%d/%d)' % (0, 0), + '% won money at showdown' + ) + def profit100_0(stat_dict, player): """ Profit won per 100 hands (no decimal places).""" stat = 0.0 @@ -311,17 +355,38 @@ def steal(stat_dict, player): ) except: return (stat, 'NA', 'st=NA', 'steal=NA', '(0/0)', '% steal attempted') + +def steal_0(stat_dict, player): + """ Steal %.""" + stat = 0.0 + try: + stat = float(stat_dict[player]['steal'])/float(stat_dict[player]['steal_opp']) + return (stat, + '%2.0f' % (100*stat) + '%', + 'st=%2.0f' % (100*stat) + '%', + 'steal=%2.0f' % (100*stat) + '%', + '(%d/%d)' % (stat_dict[player]['steal'], stat_dict[player]['steal_opp']), + '% steal attempted' + ) + except: + return (stat, + '%2.0f' % (0) + '%', + 'st=%2.0f' % (0) + '%', + 'steal=%2.0f' % (0) + '%', + '(%d/%d)' % (0, 0), + '% steal attempted' + ) def f_SB_steal(stat_dict, player): """ Folded SB to steal.""" stat = 0.0 try: - stat = float(stat_dict[player]['SBnotDef'])/float(stat_dict[player]['SBstolen']) + stat = float(stat_dict[player]['sbnotdef'])/float(stat_dict[player]['sbstolen']) return (stat, '%3.1f' % (100*stat) + '%', 'fSB=%3.1f' % (100*stat) + '%', 'fSB_s=%3.1f' % (100*stat) + '%', - '(%d/%d)' % (stat_dict[player]['SBnotDef'], stat_dict[player]['SBstolen']), + '(%d/%d)' % (stat_dict[player]['sbnotdef'], stat_dict[player]['sbstolen']), '% folded SB to steal' ) except: @@ -336,12 +401,32 @@ def f_BB_steal(stat_dict, player): """ Folded BB to steal.""" stat = 0.0 try: - stat = float(stat_dict[player]['BBnotDef'])/float(stat_dict[player]['BBstolen']) + stat = float(stat_dict[player]['bbnotdef'])/float(stat_dict[player]['bbstolen']) return (stat, '%3.1f' % (100*stat) + '%', 'fBB=%3.1f' % (100*stat) + '%', 'fBB_s=%3.1f' % (100*stat) + '%', - '(%d/%d)' % (stat_dict[player]['BBnotDef'], stat_dict[player]['BBstolen']), + '(%d/%d)' % (stat_dict[player]['bbnotdef'], stat_dict[player]['bbstolen']), + '% folded BB to steal' + ) + except: + return (stat, + 'NA', + 'fBB=NA', + 'fBB_s=NA', + '(0/0)', + '% folded BB to steal') + +def f_BB_steal_0(stat_dict, player): + """ Folded BB to steal.""" + stat = 0.0 + try: + stat = float(stat_dict[player]['bbnotdef'])/float(stat_dict[player]['bbstolen']) + return (stat, + '%2.0f' % (100*stat) + '%', + 'fBB=%2.0f' % (100*stat) + '%', + 'fBB_s=%2.0f' % (100*stat) + '%', + '(%d/%d)' % (stat_dict[player]['bbnotdef'], stat_dict[player]['bbstolen']), '% folded BB to steal' ) except: @@ -356,12 +441,12 @@ def three_B_0(stat_dict, player): """ Three bet preflop/3rd.""" stat = 0.0 try: - stat = float(stat_dict[player]['TB_0'])/float(stat_dict[player]['TB_opp_0']) + stat = float(stat_dict[player]['tb_0'])/float(stat_dict[player]['tb_opp_0']) return (stat, '%3.1f' % (100*stat) + '%', '3B=%3.1f' % (100*stat) + '%', '3B_pf=%3.1f' % (100*stat) + '%', - '(%d/%d)' % (stat_dict[player]['TB_0'], stat_dict[player]['TB_opp_0']), + '(%d/%d)' % (stat_dict[player]['tb_0'], stat_dict[player]['tb_opp_0']), '% 3/4 Bet preflop/3rd' ) except: @@ -537,12 +622,12 @@ def cb_1(stat_dict, player): """ Flop continuation bet.""" stat = 0.0 try: - stat = float(stat_dict[player]['CB_1'])/float(stat_dict[player]['CB_opp_1']) + stat = float(stat_dict[player]['cb_1'])/float(stat_dict[player]['cb_opp_1']) return (stat, '%3.1f' % (100*stat) + '%', 'cb1=%3.1f' % (100*stat) + '%', 'cb_1=%3.1f' % (100*stat) + '%', - '(%d/%d)' % (stat_dict[player]['CB_1'], stat_dict[player]['CB_opp_1']), + '(%d/%d)' % (stat_dict[player]['cb_1'], stat_dict[player]['cb_opp_1']), '% continuation bet flop/4th' ) except: @@ -558,12 +643,12 @@ def cb_2(stat_dict, player): """ Turn continuation bet.""" stat = 0.0 try: - stat = float(stat_dict[player]['CB_2'])/float(stat_dict[player]['CB_opp_2']) + stat = float(stat_dict[player]['cb_2'])/float(stat_dict[player]['cb_opp_2']) return (stat, '%3.1f' % (100*stat) + '%', 'cb2=%3.1f' % (100*stat) + '%', 'cb_2=%3.1f' % (100*stat) + '%', - '(%d/%d)' % (stat_dict[player]['CB_2'], stat_dict[player]['CB_opp_2']), + '(%d/%d)' % (stat_dict[player]['cb_2'], stat_dict[player]['cb_opp_2']), '% continuation bet turn/5th' ) except: @@ -579,12 +664,12 @@ def cb_3(stat_dict, player): """ River continuation bet.""" stat = 0.0 try: - stat = float(stat_dict[player]['CB_3'])/float(stat_dict[player]['CB_opp_3']) + stat = float(stat_dict[player]['cb_3'])/float(stat_dict[player]['cb_opp_3']) return (stat, '%3.1f' % (100*stat) + '%', 'cb3=%3.1f' % (100*stat) + '%', 'cb_3=%3.1f' % (100*stat) + '%', - '(%d/%d)' % (stat_dict[player]['CB_3'], stat_dict[player]['CB_opp_3']), + '(%d/%d)' % (stat_dict[player]['cb_3'], stat_dict[player]['cb_opp_3']), '% continuation bet river/6th' ) except: @@ -600,12 +685,12 @@ def cb_4(stat_dict, player): """ 7th street continuation bet.""" stat = 0.0 try: - stat = float(stat_dict[player]['CB_4'])/float(stat_dict[player]['CB_opp_4']) + stat = float(stat_dict[player]['cb_4'])/float(stat_dict[player]['cb_opp_4']) return (stat, '%3.1f' % (100*stat) + '%', 'cb4=%3.1f' % (100*stat) + '%', 'cb_4=%3.1f' % (100*stat) + '%', - '(%d/%d)' % (stat_dict[player]['CB_4'], stat_dict[player]['CB_opp_4']), + '(%d/%d)' % (stat_dict[player]['cb_4'], stat_dict[player]['cb_opp_4']), '% continuation bet 7th' ) except: @@ -719,10 +804,10 @@ if __name__== "__main__": print "player = ", player, do_stat(stat_dict, player = player, stat = 'fold_f') print "player = ", player, do_stat(stat_dict, player = player, stat = 'wmsd') print "player = ", player, do_stat(stat_dict, player = player, stat = 'steal') - print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_SB_steal') - print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_BB_steal') - print "player = ", player, do_stat(stat_dict, player = player, stat = 'three_B_0') - print "player = ", player, do_stat(stat_dict, player = player, stat = 'WMsF') + print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_sb_steal') + print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_bb_steal') + print "player = ", player, do_stat(stat_dict, player = player, stat = 'three_b_0') + print "player = ", player, do_stat(stat_dict, player = player, stat = 'wmsf') print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_1') print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_2') print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_3') diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py index 7bc22710..46270dea 100755 --- a/pyfpdb/Tables.py +++ b/pyfpdb/Tables.py @@ -135,7 +135,7 @@ def discover_posix(c): if re.search(params['table_finder'], listing): if 'Lobby' in listing: continue if 'Instant Hand History' in listing: continue - if '\"Full Tilt Poker\"' in listing: continue +# if '\"Full Tilt Poker\"' in listing: continue if 'History for table:' in listing: continue if 'has no name' in listing: continue info = decode_xwininfo(c, listing) @@ -391,7 +391,7 @@ def discover_mac_by_name(c, tablename): if __name__=="__main__": c = Configuration.Config() - print discover_table_by_name(c, "Ringe") + print discover_table_by_name(c, "Torino") # print discover_tournament_table(c, "118942908", "3") tables = discover(c) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 0f0f3bf3..2c54552b 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -44,10 +44,11 @@ import GuiPositionalStats import GuiTableViewer import GuiAutoImport import GuiGraphViewer +import GuiSessionViewer import FpdbSQLQueries import Configuration -VERSION = "0.10" +VERSION = "0.11" class fpdb: def tab_clicked(self, widget, tab_name): @@ -105,30 +106,36 @@ class fpdb: #end def delete_event def destroy(self, widget, data=None): - self.quit(widget, data) + self.quit(widget) #end def destroy - def dia_about(self, widget, data): + def dia_about(self, widget, data=None): print "todo: implement dia_about", print " version = %s, requires database version %s" % (VERSION, "118") #end def dia_about - def dia_create_del_database(self, widget, data): + def dia_create_del_database(self, widget, data=None): print "todo: implement dia_create_del_database" self.obtain_global_lock() #end def dia_create_del_database - def dia_create_del_user(self, widget, data): + def dia_create_del_user(self, widget, data=None): print "todo: implement dia_create_del_user" self.obtain_global_lock() #end def dia_create_del_user - def dia_database_stats(self, widget, data): + def dia_database_stats(self, widget, data=None): print "todo: implement dia_database_stats" #string=fpdb_db.getDbStats(db, cursor) #end def dia_database_stats - def dia_delete_db_parts(self, widget, data): + def dia_database_sessions(self, widget, data=None): + new_sessions_thread=GuiSessionViewer.GuiSessionViewer(self.config, self.querydict) + self.threads.append(new_sessions_thread) + sessions_tab=new_sessions_thread.get_vbox() + self.add_and_display_tab(sessions_tab, "Sessions") + + def dia_delete_db_parts(self, widget, data=None): print "todo: implement dia_delete_db_parts" self.obtain_global_lock() #end def dia_delete_db_parts @@ -138,7 +145,7 @@ class fpdb: self.obtain_global_lock() #end def dia_edit_profile - def dia_export_db(self, widget, data): + def dia_export_db(self, widget, data=None): print "todo: implement dia_export_db" self.obtain_global_lock() #end def dia_export_db @@ -163,16 +170,16 @@ class fpdb: # return (user, pw, response) #end def dia_get_db_root_credentials - def dia_import_db(self, widget, data): + def dia_import_db(self, widget, data=None): print "todo: implement dia_import_db" self.obtain_global_lock() #end def dia_import_db - def dia_licensing(self, widget, data): + def dia_licensing(self, widget, data=None): print "todo: implement dia_licensing" #end def dia_licensing - def dia_load_profile(self, widget, data): + def dia_load_profile(self, widget, data=None): """Dialogue to select a file to load a profile from""" self.obtain_global_lock() chooser = gtk.FileChooserDialog(title="Please select a profile file to load", @@ -188,7 +195,7 @@ class fpdb: print 'User cancelled loading profile' #end def dia_load_profile - def dia_recreate_tables(self, widget, data): + def dia_recreate_tables(self, widget, data=None): """Dialogue that asks user to confirm that he wants to delete and recreate the tables""" self.obtain_global_lock() @@ -205,12 +212,12 @@ class fpdb: print 'User cancelled recreating tables' #end def dia_recreate_tables - def dia_regression_test(self, widget, data): + def dia_regression_test(self, widget, data=None): print "todo: implement dia_regression_test" self.obtain_global_lock() #end def dia_regression_test - def dia_save_profile(self, widget, data): + def dia_save_profile(self, widget, data=None): print "todo: implement dia_save_profile" #end def dia_save_profile @@ -237,11 +244,89 @@ class fpdb: def get_menu(self, window): """returns the menu for this program""" - accel_group = gtk.AccelGroup() - self.item_factory = gtk.ItemFactory(gtk.MenuBar, "
", accel_group) - self.item_factory.create_items(self.menu_items) + fpdbmenu = """ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + uimanager = gtk.UIManager() + accel_group = uimanager.get_accel_group() + actiongroup = gtk.ActionGroup('UIManagerExample') + + # Create actions + actiongroup.add_actions([('main', None, '_Main'), + ('Quit', gtk.STOCK_QUIT, '_Quit me!', None, 'Quit the Program', self.quit), + ('LoadProf', None, '_Load Profile (broken)', 'L', 'Load your profile', self.dia_load_profile), + ('EditProf', None, '_Edit Profile (todo)', 'E', 'Edit your profile', self.dia_edit_profile), + ('SaveProf', None, '_Save Profile (todo)', 'S', 'Save your profile', self.dia_save_profile), + ('import', None, '_Import'), + ('bulkimp', None, '_Bulk Import', 'B', 'Bulk Import', self.tab_bulk_import), + ('autorate', None, 'Auto _Rating (todo)', 'R', 'Auto Rating (todo)', self.not_implemented), + ('viewers', None, '_Viewers'), + ('autoimp', None, '_Auto Import and HUD', 'A', 'Auto Import and HUD', self.tab_auto_import), + ('graphs', None, '_Graphs', 'G', 'Graphs', self.tabGraphViewer), + ('handreplay', None, 'Hand _Replayer (todo)', None, 'Hand Replayer (todo)', self.not_implemented), + ('playerdetails', None, 'Player _Details (todo)', None, 'Player Details (todo)', self.not_implemented), + ('playerstats', None, '_Player Stats (tabulated view)', 'P', 'Player Stats (tabulated view)', self.tab_player_stats), + ('posnstats', None, 'P_ositional Stats (tabulated view)', 'O', 'Positional Stats (tabulated view)', self.tab_positional_stats), + ('sessionreplay', None, '_Session Replayer (todo)', None, 'Session Replayer (todo)', self.not_implemented), + ('tableviewer', None, 'Poker_table Viewer (mostly obselete)', None, 'Poker_table Viewer (mostly obselete)', self.tab_table_viewer), + ('database', None, '_Database'), + ('createdb', None, 'Create or Delete _Database (todo)', None, 'Create or Delete Database', self.dia_create_del_database), + ('createuser', None, 'Create or Delete _User (todo)', None, 'Create or Delete User', self.dia_create_del_user), + ('createtabs', None, 'Create or Recreate _Tables', None, 'Create or Recreate Tables ', self.dia_recreate_tables), + ('stats', None, '_Statistics (todo)', None, 'View Database Statistics', self.dia_database_stats), + ('sessions', None, 'Sessions', None, 'View Sessions', self.dia_database_sessions), + ('help', None, '_Help'), + ('Abbrev', None, '_Abbrevations (todo)', None, 'List of Abbrevations', self.tab_abbreviations), + ('About', None, 'A_bout', None, 'About the program', self.dia_about), + ('License', None, '_License and Copying (todo)', None, 'License and Copying', self.dia_licensing), + ]) + actiongroup.get_action('Quit').set_property('short-label', '_Quit') + + uimanager.insert_action_group(actiongroup, 0) + merge_id = uimanager.add_ui_from_string(fpdbmenu) + + # Create a MenuBar + menubar = uimanager.get_widget('/MenuBar') window.add_accel_group(accel_group) - return self.item_factory.get_widget("
") + return menubar #end def get_menu def load_profile(self): @@ -287,9 +372,10 @@ class fpdb: # Database connected to successfully, load queries to pass on to other classes self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name()) + self.db.db.rollback() #end def load_profile - def not_implemented(self): + def not_implemented(self, widget, data=None): print "todo: called unimplemented menu entry (users: pls ignore this)"#remove this once more entries are implemented #end def not_implemented @@ -297,7 +383,7 @@ class fpdb: print "todo: implement obtain_global_lock (users: pls ignore this)" #end def obtain_global_lock - def quit(self, widget, data): + def quit(self, widget): print "Quitting normally" #check if current settings differ from profile, if so offer to save or abort self.db.disconnect() @@ -308,11 +394,11 @@ class fpdb: print "todo: implement release_global_lock" #end def release_global_lock - def tab_abbreviations(self, widget, data): + def tab_abbreviations(self, widget, data=None): print "todo: implement tab_abbreviations" #end def tab_abbreviations - def tab_auto_import(self, widget, data): + def tab_auto_import(self, widget, data=None): """opens the auto import tab""" new_aimp_thread=GuiAutoImport.GuiAutoImport(self.settings, self.config) self.threads.append(new_aimp_thread) @@ -320,29 +406,29 @@ class fpdb: self.add_and_display_tab(aimp_tab, "Auto Import") #end def tab_auto_import - def tab_bulk_import(self, widget, data): + def tab_bulk_import(self, widget, data=None): """opens a tab for bulk importing""" #print "start of tab_bulk_import" - new_import_thread=GuiBulkImport.GuiBulkImport(self.db, self.settings, self.config) + new_import_thread=GuiBulkImport.GuiBulkImport(self.settings, self.config) self.threads.append(new_import_thread) bulk_tab=new_import_thread.get_vbox() self.add_and_display_tab(bulk_tab, "Bulk Import") #end def tab_bulk_import - def tab_player_stats(self, widget, data): - new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.db, self.config, self.querydict) + def tab_player_stats(self, widget, data=None): + new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.config, self.querydict, self.window) self.threads.append(new_ps_thread) ps_tab=new_ps_thread.get_vbox() self.add_and_display_tab(ps_tab, "Player Stats") - def tab_positional_stats(self, widget, data): - new_ps_thread=GuiPositionalStats.GuiPositionalStats(self.db, self.config, self.querydict) + def tab_positional_stats(self, widget, data=None): + new_ps_thread=GuiPositionalStats.GuiPositionalStats(self.config, self.querydict) self.threads.append(new_ps_thread) ps_tab=new_ps_thread.get_vbox() self.add_and_display_tab(ps_tab, "Positional Stats") - def tab_main_help(self, widget, data): + def tab_main_help(self, widget, data=None): """Displays a tab with the main fpdb help screen""" #print "start of tab_main_help" mh_tab=gtk.Label("""Welcome to Fpdb! @@ -352,7 +438,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") self.add_and_display_tab(mh_tab, "Help") #end def tab_main_help - def tab_table_viewer(self, widget, data): + def tab_table_viewer(self, widget, data=None): """opens a table viewer tab""" #print "start of tab_table_viewer" new_tv_thread=GuiTableViewer.GuiTableViewer(self.db, self.settings) @@ -361,7 +447,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") self.add_and_display_tab(tv_tab, "Table Viewer") #end def tab_table_viewer - def tabGraphViewer(self, widget, data): + def tabGraphViewer(self, widget, data=None): """opens a graph viewer tab""" #print "start of tabGraphViewer" new_gv_thread=GuiGraphViewer.GuiGraphViewer(self.db, self.settings, self.querydict, self.config) @@ -381,49 +467,9 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") self.window.connect("destroy", self.destroy) self.window.set_title("Free Poker DB - v%s or higher" % (VERSION, )) self.window.set_border_width(1) - self.window.set_size_request(1020,400) + self.window.set_default_size(900,720) self.window.set_resizable(True) - self.menu_items = ( - ( "/_Main", None, None, 0, "" ), - ( "/Main/_Load Profile (broken)", "L", self.dia_load_profile, 0, None ), - ( "/Main/_Edit Profile (todo)", "E", self.dia_edit_profile, 0, None ), - ( "/Main/_Save Profile (todo)", None, self.dia_save_profile, 0, None ), - ("/Main/sep1", None, None, 0, "" ), - ("/Main/_Quit", "Q", self.quit, 0, None ), - ("/_Import", None, None, 0, "" ), - ("/Import/_Bulk Import", "B", self.tab_bulk_import, 0, None ), - ("/Import/_Auto Import and HUD", "A", self.tab_auto_import, 0, None ), - ("/Import/Auto _Rating (todo)", "R", self.not_implemented, 0, None ), - ("/_Viewers", None, None, 0, "" ), - ("/_Viewers/_Auto Import and HUD", "A", self.tab_auto_import, 0, None ), - ("/Viewers/_Graphs", "G", self.tabGraphViewer, 0, None ), - ("/Viewers/Hand _Replayer (todo)", None, self.not_implemented, 0, None ), - ("/Viewers/Player _Details (todo)", None, self.not_implemented, 0, None ), - ("/Viewers/_Player Stats (tabulated view)", None, self.tab_player_stats, 0, None ), - ("/Viewers/Positional Stats (tabulated view)", None, self.tab_positional_stats, 0, None ), - ("/Viewers/Starting _Hands (todo)", None, self.not_implemented, 0, None ), - ("/Viewers/_Session Replayer (todo)", None, self.not_implemented, 0, None ), - ("/Viewers/Poker_table Viewer (mostly obselete)", "T", self.tab_table_viewer, 0, None ), - #( "/Viewers/Tourney Replayer - ( "/_Database", None, None, 0, "" ), - ( "/Database/Create or Delete _Database (todo)", None, self.dia_create_del_database, 0, None ), - ( "/Database/Create or Delete _User (todo)", None, self.dia_create_del_user, 0, None ), - ( "/Database/Create or Recreate _Tables", None, self.dia_recreate_tables, 0, None ), - ( "/Database/_Statistics (todo)", None, self.dia_database_stats, 0, None ), - ( "/D_ebugging", None, None, 0, "" ), - ( "/Debugging/_Delete Parts of Database (todo)", None, self.dia_delete_db_parts, 0, None ), - ( "/Debugging/_Export DB (todo)", None, self.dia_export_db, 0, None ), - ( "/Debugging/_Import DB (todo)", None, self.dia_import_db, 0, None ), - ( "/Debugging/_Regression test (todo)", None, self.dia_regression_test, 0, None ), - ( "/_Help", None, None, 0, "" ), - ( "/Help/_Main Help", "H", self.tab_main_help, 0, None ), - ( "/Help/_Abbrevations (todo)", None, self.tab_abbreviations, 0, None ), - ( "/Help/sep1", None, None, 0, "" ), - ( "/Help/A_bout (todo)", None, self.dia_about, 0, None ), - ( "/Help/_License and Copying (todo)", None, self.dia_licensing, 0, None ) - ) - self.main_vbox = gtk.VBox(False, 1) self.main_vbox.set_border_width(1) self.window.add(self.main_vbox) @@ -437,7 +483,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") self.tabs=[] self.tab_names=[] self.tab_buttons=[] - self.tab_box = gtk.HBox(False,1) + self.tab_box = gtk.HBox(True,1) self.main_vbox.pack_start(self.tab_box, False, True, 0) self.tab_box.show() #done tab bar @@ -449,11 +495,12 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") self.tab_main_help(None, None) - self.status_bar = gtk.Label("Status: Connected to "+self.db.get_backend_name()+" database named "+self.db.database+" on host "+self.db.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() self.window.show() + sys.stderr.write("fpdb starting ...") #end def __init__ def main(self): diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index eba87f52..6e48fcf4 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -59,22 +59,33 @@ class fpdb_db: self.database=database if backend==self.MYSQL_INNODB: import MySQLdb - self.db=MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) + try: + self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) + except: + raise fpdb_simple.FpdbError("MySQL connection failed") elif backend==self.PGSQL: import psycopg2 + import psycopg2.extensions + psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) # If DB connection is made over TCP, then the variables # host, user and password are required print "host=%s user=%s pass=%s." % (host, user, password) if self.host and self.user and self.password: - self.db = psycopg2.connect(host = host, - user = user, - password = password, - database = database) + try: + self.db = psycopg2.connect(host = host, + user = user, + password = password, + database = database) + except: + raise fpdb_simple.FpdbError("PostgreSQL connection failed") # For local domain-socket connections, only DB name is # needed, and everything else is in fact undefined and/or # flat out wrong else: - self.db = psycopg2.connect(database = database) + try: + self.db = psycopg2.connect(database = database) + except: + raise fpdb_simple.FpdbError("PostgreSQL connection failed") else: raise fpdb_simple.FpdbError("unrecognised database backend:"+backend) self.cursor=self.db.cursor() @@ -136,7 +147,7 @@ class fpdb_db: if(self.get_backend_name() == 'MySQL InnoDB'): #Databases with FOREIGN KEY support need this switched of before you can drop tables - self.drop_referencial_integrity() + self.drop_referential_integrity() # Query the DB to see what tables exist self.cursor.execute(self.sql.query['list_tables']) @@ -155,7 +166,7 @@ class fpdb_db: self.db.commit() #end def drop_tables - def drop_referencial_integrity(self): + def drop_referential_integrity(self): """Update all tables to remove foreign keys""" self.cursor.execute(self.sql.query['list_tables']) @@ -173,7 +184,7 @@ class fpdb_db: key = "`" + inner[j][0] + "_" + m.group() + "`" self.cursor.execute("ALTER TABLE " + inner[j][0] + " DROP FOREIGN KEY " + key) self.db.commit() - #end drop_referencial_inegrity + #end drop_referential_inegrity def get_backend_name(self): """Returns the name of the currently used backend""" diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 6c0af7f5..2dbb4807 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -58,13 +58,14 @@ class Importer: self.cursor = None self.filelist = {} self.dirlist = {} + self.siteIds = {} self.addToDirList = {} self.removeFromFileList = {} # to remove deleted files self.monitor = False - self.updated = {} #Time last import was run {file:mtime} + self.updated = {} #Time last import was run {file:mtime} self.lines = None - self.faobs = None #File as one big string - self.pos_in_file = {} # dict to remember how far we have read in the file + self.faobs = None # File as one big string + self.pos_in_file = {} # dict to remember how far we have read in the file #Set defaults self.callHud = self.config.get_import_parameters().get("callFpdbHud") @@ -73,6 +74,7 @@ class Importer: self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.fdb.do_connect(self.config) + self.fdb.db.rollback() #Set functions def setCallHud(self, value): @@ -109,20 +111,32 @@ class Importer: def addImportFile(self, filename, site = "default", filter = "passthrough"): #TODO: test it is a valid file -> put that in config!! self.filelist[filename] = [site] + [filter] + if site not in self.siteIds: + # Get id from Sites table in DB + self.fdb.cursor.execute(self.fdb.sql.query['getSiteId'], (site,)) + result = self.fdb.cursor.fetchall() + if len(result) == 1: + self.siteIds[site] = result[0][0] + else: + if len(result) == 0: + print "[ERROR] Database ID for %s not found" % site + else: + print "[ERROR] More than 1 Database ID found for %s - Multiple currencies not implemented yet" % site + # Called from GuiBulkImport to add a file or directory. - def addBulkImportImportFileOrDir(self, inputPath,filter = "passthrough"): + def addBulkImportImportFileOrDir(self, inputPath, site = "PokerStars"): """Add a file or directory for bulk import""" - + filter = self.config.hhcs[site].converter # Bulk import never monitors # if directory, add all files in it. Otherwise add single file. # TODO: only add sane files? if os.path.isdir(inputPath): for subdir in os.walk(inputPath): for file in subdir[2]: - self.addImportFile(os.path.join(inputPath, subdir[0], file), site="default", filter=filter) + self.addImportFile(os.path.join(inputPath, subdir[0], file), site=site, filter=filter) else: - self.addImportFile(inputPath, site="default", filter=filter) + self.addImportFile(inputPath, site=site, filter=filter) #Add a directory of files to filelist #Only one import directory per site supported. #dirlist is a hash of lists: @@ -193,7 +207,7 @@ class Importer: self.addImportDirectory(self.dirlist[site][0], False, site, self.dirlist[site][1]) for file in self.filelist: - if os.path.exists(file): + if os.path.exists(file): stat_info = os.stat(file) try: lastupdate = self.updated[file] @@ -212,15 +226,17 @@ class Importer: #if os.path.isdir(file): #self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) else: - removeFromFileList[file] = True - self.addToDirList = filter(lambda x: self.addImportDirectory(x, True, self.addToDirList[x][0], self.addToDirList[x][1]), self.addToDirList) - + self.removeFromFileList[file] = True + self.addToDirList = filter(lambda x: self.addImportDirectory(x, True, self.addToDirList[x][0], self.addToDirList[x][1]), self.addToDirList) + for file in self.removeFromFileList: if file in self.filelist: del self.filelist[file] self.addToDirList = {} self.removeFromFileList = {} + self.fdb.db.rollback() + # This is now an internal function that should not be called directly. def import_file_dict(self, file, site, filter): @@ -294,10 +310,9 @@ class Importer: print "TODO: implement importing tournament summaries" #self.faobs = readfile(inputFile) #self.parseTourneyHistory() - return 0 - - site = fpdb_simple.recogniseSite(firstline) - category = fpdb_simple.recogniseCategory(firstline) + return (0,0,0,1,0) + + category=fpdb_simple.recogniseCategory(firstline) startpos = 0 stored = 0 #counter @@ -305,61 +320,30 @@ class Importer: partial = 0 #counter errors = 0 #counter - for i in xrange (len(self.lines)): #main loop, iterates through the lines of a file and calls the appropriate parser method - if len(self.lines[i]) < 2: - endpos = i - hand = self.lines[startpos:endpos] + for i in xrange (len(self.lines)): + if (len(self.lines[i])<2): #Wierd way to detect for '\r\n' or '\n' + endpos=i + hand=self.lines[startpos:endpos] - if len(hand[0]) < 2: - hand = hand[1:] - - cancelled=False - damaged=False - if (site=="ftp"): - for i in range (len(hand)): - if hand[i].endswith(" has been canceled"): #this is their typo. this is a typo, right? - cancelled = True + if (len(hand[0])<2): + hand=hand[1:] - #FTP generates lines looking like: - #Seat 1: IOS Seat 2: kashman59 (big blind) showed [8c 9d] and won ($3.25) with a pair of Eights - #ie. Seat X multiple times on the same line in the summary section, when a new player sits down in the - #middle of the hand. - #TODO: Deal with this properly, either fix the file or make the parsing code work with this line. - if "Seat" in hand[i]: - mo = re.search(" Seat [0-9]+: ", hand[i]) - if mo: - print "mo=", mo, "\nmo.start=", mo.start(),"\nhand[i]=",hand[i] - hand.insert(i+1, hand[i][mo.start()+1:]) - hand[i] = hand[i][0:mo.start()] - - if len(hand) < 3: + + if (len(hand)<3): pass - #todo: the above 2 lines are kind of a dirty hack, the mentioned circumstances should be handled elsewhere but that doesnt work with DOS/Win EOL. actually this doesnt work. - elif hand[0].endswith(" (partial)"): #partial hand - do nothing - partial += 1 - elif "Seat" not in hand[1] and "Seat" not in hand[2] and "Seat" not in hand[3]: - partial += 1 - elif cancelled or damaged: - partial += 1 - if damaged: - print """ - DEBUG: Partial hand triggered by a line containing 'Seat X:' twice. This is a - bug in the FTP software when a player sits down in the middle of a hand. - Adding a newline after the player name will fix the issue - """ - print "File: %s" %(file) - print "Line: %s" %(startpos) - else: #normal processing - isTourney = fpdb_simple.isTourney(hand[0]) + #TODO: This is ugly - we didn't actually find the start of the + # hand with the outer loop so we test again... + else: + isTourney=fpdb_simple.isTourney(hand[0]) if not isTourney: - hand = fpdb_simple.filterAnteBlindFold(site,hand) + hand = fpdb_simple.filterAnteBlindFold(hand) self.hand=hand - + try: handsId = fpdb_parse_logic.mainParser(self.settings['db-backend'], self.fdb.db - ,self.fdb.cursor, site, category, hand, self.config) + ,self.fdb.cursor, self.siteIds[site], category, hand, self.config) self.fdb.db.commit() - + stored += 1 if self.callHud: #print "call to HUD here. handsId:",handsId @@ -367,37 +351,39 @@ class Importer: self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) except fpdb_simple.DuplicateError: duplicates += 1 + self.fdb.db.rollback() except (ValueError), fe: errors += 1 self.printEmailErrorMessage(errors, file, hand) - + if (self.settings['failOnError']): self.fdb.db.commit() #dont remove this, in case hand processing was cancelled. raise + else: + self.fdb.db.rollback() except (fpdb_simple.FpdbError), fe: errors += 1 self.printEmailErrorMessage(errors, file, hand) - #fe.printStackTrace() #todo: get stacktrace self.fdb.db.rollback() - + if self.settings['failOnError']: self.fdb.db.commit() #dont remove this, in case hand processing was cancelled. raise - + if self.settings['minPrint']: - if not ((stored+duplicates+partial+errors) % self.settings['minPrint']): - print "stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors + if not ((stored+duplicates+errors) % self.settings['minPrint']): + print "stored:", stored, "duplicates:", duplicates, "errors:", errors if self.settings['handCount']: - if ((stored+duplicates+partial+errors) >= self.settings['handCount']): + if ((stored+duplicates+errors) >= self.settings['handCount']): if not self.settings['quiet']: print "quitting due to reaching the amount of hands to be imported" - print "Total stored:", stored, "duplicates:", duplicates, "partial/damaged:", partial, "errors:", errors, " time:", (time() - starttime) + print "Total stored:", stored, "duplicates:", duplicates, "errors:", errors, " time:", (time() - starttime) sys.exit(0) startpos = endpos ttime = time() - starttime - print "\rTotal stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors, " time:", ttime + print "\rTotal stored:", stored, "duplicates:", duplicates, "errors:", errors, " time:", ttime if not stored: if duplicates: @@ -408,16 +394,11 @@ class Importer: else: print "failed to read a single hand from file:", inputFile handsId=0 - #todo: this will cause return of an unstored hand number if the last hand was error or partial + #todo: this will cause return of an unstored hand number if the last hand was error self.fdb.db.commit() self.handsId=handsId return (stored, duplicates, partial, errors, ttime) - def parseTourneyHistory(self): - print "Tourney history parser stub" - #Find tournament boundaries. - #print self.foabs - def printEmailErrorMessage(self, errors, filename, line): traceback.print_exc(file=sys.stderr) print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it." diff --git a/pyfpdb/fpdb_parse_logic.py b/pyfpdb/fpdb_parse_logic.py index fb352064..150707c1 100644 --- a/pyfpdb/fpdb_parse_logic.py +++ b/pyfpdb/fpdb_parse_logic.py @@ -21,11 +21,11 @@ import fpdb_simple import fpdb_save_to_db #parses a holdem hand -def mainParser(backend, db, cursor, site, category, hand, config): +def mainParser(backend, db, cursor, siteID, category, hand, config): category = fpdb_simple.recogniseCategory(hand[0]) - + base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud" - + #part 0: create the empty arrays lineTypes = [] #char, valid values: header, name, cards, action, win, rake, ignore lineStreets = [] #char, valid values: (predeal, preflop, flop, turn, river) @@ -34,9 +34,7 @@ def mainParser(backend, db, cursor, site, category, hand, config): #part 1: read hand no and check for duplicate siteHandNo = fpdb_simple.parseSiteHandNo(hand[0]) - handStartTime = fpdb_simple.parseHandStartTime(hand[0], site) - siteID = fpdb_simple.recogniseSiteID(cursor, site) - #print "parse logic, siteID:",siteID,"site:",site + handStartTime = fpdb_simple.parseHandStartTime(hand[0]) isTourney = fpdb_simple.isTourney(hand[0]) smallBlindLine = 0 @@ -46,11 +44,9 @@ def mainParser(backend, db, cursor, site, category, hand, config): smallBlindLine = i break #print "small blind line:",smallBlindLine - + gametypeID = fpdb_simple.recogniseGametypeID(backend, db, cursor, hand[0], hand[smallBlindLine], siteID, category, isTourney) if isTourney: - if site != "ps": - raise fpdb_simple.FpdbError("tourneys are only supported on PS right now") siteTourneyNo = fpdb_simple.parseTourneyNo(hand[0]) buyin = fpdb_simple.parseBuyin(hand[0]) fee = fpdb_simple.parseFee(hand[0]) @@ -61,10 +57,10 @@ def mainParser(backend, db, cursor, site, category, hand, config): rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0]) tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(cursor, siteID, buyin, fee, knockout, rebuyOrAddon) - + fpdb_simple.isAlreadyInDB(cursor, gametypeID, siteHandNo) - hand = fpdb_simple.filterCrap(site, hand, isTourney) + hand = fpdb_simple.filterCrap(hand, isTourney) #part 2: classify lines by type (e.g. cards, action, win, sectionchange) and street fpdb_simple.classifyLines(hand, category, lineTypes, lineStreets) @@ -74,10 +70,10 @@ def mainParser(backend, db, cursor, site, category, hand, config): for i, line in enumerate(hand): if lineTypes[i] == "name": seatLines.append(line) - + names = fpdb_simple.parseNames(seatLines) playerIDs = fpdb_simple.recognisePlayerIDs(cursor, names, siteID) - tmp = fpdb_simple.parseCashesAndSeatNos(seatLines, site) + tmp = fpdb_simple.parseCashesAndSeatNos(seatLines) startCashes = tmp['startCashes'] seatNos = tmp['seatNos'] @@ -90,30 +86,27 @@ def mainParser(backend, db, cursor, site, category, hand, config): #part 4: take appropriate action for each line based on linetype for i, line in enumerate(hand): if lineTypes[i] == "cards": - fpdb_simple.parseCardLine(site, category, lineStreets[i], line, names, cardValues, cardSuits, boardValues, boardSuits) + fpdb_simple.parseCardLine(category, lineStreets[i], line, names, cardValues, cardSuits, boardValues, boardSuits) #if category=="studhilo": # print "hand[i]:", hand[i] # print "cardValues:", cardValues # print "cardSuits:", cardSuits elif lineTypes[i] == "action": - fpdb_simple.parseActionLine(site, base, isTourney, line, lineStreets[i], playerIDs, names, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo) + fpdb_simple.parseActionLine(base, isTourney, line, lineStreets[i], playerIDs, names, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo) elif lineTypes[i] == "win": - fpdb_simple.parseWinLine(line, site, names, winnings, isTourney) + fpdb_simple.parseWinLine(line, names, winnings, isTourney) elif lineTypes[i] == "rake": totalRake = 0 if isTourney else fpdb_simple.parseRake(line) fpdb_simple.splitRake(winnings, rakes, totalRake) elif lineTypes[i]=="header" or lineTypes[i]=="rake" or lineTypes[i]=="name" or lineTypes[i]=="ignore": pass elif lineTypes[i]=="ante": - fpdb_simple.parseAnteLine(line, site, isTourney, names, antes) + fpdb_simple.parseAnteLine(line, isTourney, names, antes) elif lineTypes[i]=="table": - tableResult=fpdb_simple.parseTableLine(site, base, line) + tableResult=fpdb_simple.parseTableLine(base, line) else: raise fpdb_simple.FpdbError("unrecognised lineType:"+lineTypes[i]) - - if site == "ftp": - tableResult = fpdb_simple.parseTableLine(site, base, hand[0]) - + maxSeats = tableResult['maxSeats'] tableName = tableResult['tableName'] #print "before part5, antes:", antes @@ -128,7 +121,7 @@ def mainParser(backend, db, cursor, site, category, hand, config): cursor.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, )) limit_type = cursor.fetchone()[0] - fpdb_simple.convert3B4B(site, category, limit_type, actionTypes, actionAmounts) + fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts) totalWinnings = sum(winnings) @@ -141,7 +134,7 @@ def mainParser(backend, db, cursor, site, category, hand, config): hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes , allIns, actionTypeByNo, winnings, totalWinnings, None , actionTypes, actionAmounts, antes) - + if isTourney: ranks = map(lambda x: 0, names) # create an array of 0's equal to the length of names payin_amounts = fpdb_simple.calcPayin(len(names), buyin, fee) @@ -165,7 +158,7 @@ def mainParser(backend, db, cursor, site, category, hand, config): , allIns, actionAmounts, actionNos, hudImportData, maxSeats , tableName, seatNos) else: - raise fpdb_simple.FpdbError("unrecognised category") # it's impossible to get here, but w/e + raise fpdb_simple.FpdbError("unrecognised category") else: if base == "hold": result = fpdb_save_to_db.ring_holdem_omaha( @@ -183,7 +176,7 @@ def mainParser(backend, db, cursor, site, category, hand, config): , actionAmounts, actionNos, hudImportData, maxSeats, tableName , seatNos) else: - raise fpdb_simple.FpdbError ("unrecognised category") # also impossible to get here + raise fpdb_simple.FpdbError ("unrecognised category") db.commit() return result #end def mainParser diff --git a/pyfpdb/fpdb_save_to_db.py b/pyfpdb/fpdb_save_to_db.py index b99975f9..0dbcbf61 100644 --- a/pyfpdb/fpdb_save_to_db.py +++ b/pyfpdb/fpdb_save_to_db.py @@ -32,8 +32,7 @@ saveActions = True # set this to False to avoid storing action data # Pros: speeds up imports # Cons: no action data is saved, so you need to keep the hand histories # variance not available on stats page - # no graphs - + # : No graphs #stores a stud/razz hand into the database def ring_stud(config, backend, db, cursor, base, category, site_hand_no, gametype_id, hand_start_time ,names, player_ids, start_cashes, antes, card_values, card_suits, winnings, rakes @@ -55,7 +54,7 @@ def ring_stud(config, backend, db, cursor, base, category, site_hand_no, gametyp ,start_cashes, antes, card_values ,card_suits, winnings, rakes, seatNos) - fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData) + fpdb_simple.storeHudCache(backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) if saveActions: fpdb_simple.storeActions(cursor, hands_players_ids, action_types @@ -83,17 +82,17 @@ def ring_holdem_omaha(config, backend, db, cursor, base, category, site_hand_no, t2 = time() hands_id = fpdb_simple.storeHands(backend, db, cursor, site_hand_no, gametype_id - ,hand_start_time, names, tableName, maxSeats) + ,hand_start_time, names, tableName, maxSeats, hudImportData) t3 = time() hands_players_ids = fpdb_simple.store_hands_players_holdem_omaha( backend, db, cursor, category, hands_id, player_ids, start_cashes - , positions, card_values, card_suits, winnings, rakes, seatNos) + , positions, card_values, card_suits, winnings, rakes, seatNos, hudImportData) t4 = time() #print "ring holdem, backend=%d" % backend if fastStoreHudCache: - fpdb_simple.storeHudCache2(backend, cursor, base, category, gametype_id, player_ids, hudImportData) + fpdb_simple.storeHudCache2(backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) else: - fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData) + fpdb_simple.storeHudCache(backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) t5 = time() fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits) t6 = time() @@ -132,9 +131,9 @@ def tourney_holdem_omaha(config, backend, db, cursor, base, category, siteTourne #print "tourney holdem, backend=%d" % backend if fastStoreHudCache: - fpdb_simple.storeHudCache2(backend, cursor, base, category, gametype_id, player_ids, hudImportData) + fpdb_simple.storeHudCache2(backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) else: - fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData) + fpdb_simple.storeHudCache(backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits) @@ -166,7 +165,7 @@ def tourney_stud(config, backend, db, cursor, base, category, siteTourneyNo, buy , playerIds, startCashes, antes, cardValues, cardSuits , winnings, rakes, seatNos, tourneys_players_ids) - fpdb_simple.storeHudCache(cursor, base, category, gametypeId, playerIds, hudImportData) + fpdb_simple.storeHudCache(backend, cursor, base, category, gametypeId, hand_start_time, playerIds, hudImportData) if saveActions: fpdb_simple.storeActions(cursor, hands_players_ids, actionTypes, allIns, actionAmounts, actionNos) diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 1435d2ae..e4471e24 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -20,6 +20,8 @@ import datetime import time import re + +import Card PS = 1 FTP = 2 @@ -29,6 +31,8 @@ MYSQL_INNODB = 2 PGSQL = 3 SQLITE = 4 +# config while trying out new hudcache mechanism +use_date_in_hudcache = True # Data Structures for index and foreign key creation # drop_code is an int with possible values: 0 - don't drop for bulk import @@ -54,7 +58,7 @@ indexes = [ , {'tab':'Gametypes', 'col':'siteId', 'drop':0} , {'tab':'Hands', 'col':'gametypeId', 'drop':0} # mct 22/3/09 , {'tab':'Hands', 'col':'siteHandNo', 'drop':0} - , {'tab':'HandsActions', 'col':'handplayerId', 'drop':0} + , {'tab':'HandsActions', 'col':'handsPlayerId', 'drop':0} , {'tab':'HandsPlayers', 'col':'handId', 'drop':1} , {'tab':'HandsPlayers', 'col':'playerId', 'drop':1} , {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0} @@ -78,7 +82,7 @@ foreignKeys = [ {'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1} , {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1} , {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1} - , {'fktab':'HandsActions', 'fkcol':'handPlayerId', 'rtab':'HandsPlayers', 'rcol':'id', 'drop':1} + , {'fktab':'HandsActions', 'fkcol':'handsPlayerId', 'rtab':'HandsPlayers', 'rcol':'id', 'drop':1} , {'fktab':'HudCache', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1} , {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0} , {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1} @@ -87,7 +91,7 @@ foreignKeys = [ {'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1} , {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1} , {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1} - , {'fktab':'HandsActions', 'fkcol':'handPlayerId', 'rtab':'HandsPlayers', 'rcol':'id', 'drop':1} + , {'fktab':'HandsActions', 'fkcol':'handsPlayerId', 'rtab':'HandsPlayers', 'rcol':'id', 'drop':1} , {'fktab':'HudCache', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1} , {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0} , {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1} @@ -337,6 +341,7 @@ def analyzeDB(fdb): except: print "Error during vacuum" fdb.db.set_isolation_level(1) # go back to normal isolation level + fdb.db.commit() #end def analyzeDB class DuplicateError(Exception): @@ -391,10 +396,6 @@ def checkPositions(positions): """ verify positions are valid """ if any(not (p == "B" or p == "S" or (p >= 0 and p <= 9)) for p in positions): raise FpdbError("invalid position '"+p+"' found in checkPositions") -# for p in positions: -# if not (p == "B" or p == "S" or (p >= 0 and p <= 9)): -# raise FpdbError("invalid position '" + p + "' found in checkPositions") - ### RHH modified to allow for "position 9" here (pos==9 is when you're a dead hand before the BB ### eric - position 8 could be valid - if only one blind is posted, but there's still 10 people, ie a sitout is present, and the small is dead... @@ -445,7 +446,7 @@ def classifyLines(hand, category, lineTypes, lineStreets): currentStreet=3 elif line.startswith("*** 7") or line == "*** RIVER ***": lineTypes.append("ignore") - currentStreet=4 + currentStreet=4 elif isWinLine(line): lineTypes.append("win") elif line.startswith("Total pot ") and "Rake" in line: @@ -461,7 +462,7 @@ def classifyLines(hand, category, lineTypes, lineStreets): lineStreets.append(currentStreet) #end def classifyLines -def convert3B4B(site, category, limit_type, actionTypes, actionAmounts): +def convert3B4B(category, limit_type, actionTypes, actionAmounts): """calculates the actual bet amounts in the given amount array and changes it accordingly.""" for i in xrange(len(actionTypes)): for j in xrange(len(actionTypes[i])): @@ -571,7 +572,7 @@ def fillCardArrays(player_count, base, category, card_values, card_suits): #filters out a player that folded before paying ante or blinds. This should be called #before calling the actual hand parser. manipulates hand, no return. -def filterAnteBlindFold(site,hand): +def filterAnteBlindFold(hand): #todo: this'll only get rid of one ante folder, not multiple ones #todo: in tourneys this should not be removed but #print "start of filterAnteBlindFold" @@ -609,7 +610,7 @@ def stripEOLspaces(str): return str.rstrip() #removes useless lines as well as trailing spaces -def filterCrap(site, hand, isTourney): +def filterCrap(hand, isTourney): #remove two trailing spaces at end of line hand = [line.rstrip() for line in hand] @@ -642,18 +643,8 @@ def filterCrap(site, hand, isTourney): hand[i] = False elif hand[i].endswith("is disconnected"): hand[i] = False - elif hand[i].endswith(" is feeling angry"): + elif hand[i].find(" is low with [")!=-1: hand[i] = False - elif hand[i].endswith(" is feeling confused"): - hand[i] = False - elif hand[i].endswith(" is feeling happy"): - hand[i] = False - elif hand[i].endswith(" is feeling normal"): - hand[i] = False - elif " is low with [" in hand[i]: - hand[i] = False - #elif (hand[i].find("-max Seat #")!=-1 and hand[i].find(" is the button")!=-1): - # toRemove.append(hand[i]) elif hand[i].endswith(" mucks"): hand[i] = False elif hand[i].endswith(": mucks hand"): @@ -679,13 +670,9 @@ def filterCrap(site, hand, isTourney): hand[i] = False elif "joins the table at seat " in hand[i]: hand[i] = False - elif (hand[i].endswith(" sits down")): - hand[i] = False elif (hand[i].endswith("leaves the table")): hand[i] = False - elif (hand[i].endswith(" stands up")): - hand[i] = False - elif "is high with" in hand[i]: + elif "is high with " in hand[i]: hand[i] = False elif hand[i].endswith("doesn't show hand"): hand[i] = False @@ -695,11 +682,9 @@ def filterCrap(site, hand, isTourney): hand[i] = False elif hand[i] == "Betting is capped": hand[i] = False - #site specific variable position filter - elif 'said, "' in hand[i]: - hand[i] = False - elif site == "ftp" and ":" in hand[i] and "Seat " not in hand[i] and ": Table" not in hand[i]: # FTP chat + elif (hand[i].find(" said, \"")!=-1): hand[i] = False + if isTourney and not hand[i] == False: if (hand[i].endswith(" is sitting out") and (not hand[i].startswith("Seat "))): hand[i] = False @@ -780,7 +765,7 @@ def isWinLine(line): #end def isWinLine #returns the amount of cash/chips put into the put in the given action line -def parseActionAmount(line, atype, site, isTourney): +def parseActionAmount(line, atype, isTourney): #if (line.endswith(" and is all-in")): # line=line[:-14] #elif (line.endswith(", and is all in")): @@ -794,19 +779,14 @@ def parseActionAmount(line, atype, site, isTourney): if atype == "fold" or atype == "check": amount = 0 elif atype == "unbet": - if site == "ftp": - pos1 = line.find("$") + 1 - pos2 = line.find(" returned to") - amount = float2int(line[pos1:pos2]) - elif site == "ps": - pos1 = line.find("$") + 1 - if pos1 == 0: - pos1 = line.find("(") + 1 - pos2 = line.find(")") - amount = float2int(line[pos1:pos2]) - elif atype == "bet" and site == "ps" and line.find(": raises $")!=-1 and line.find("to $")!=-1: - pos = line.find("to $")+4 - amount = float2int(line[pos:]) + pos1 = line.find("$") + 1 + if pos1 == 0: + pos1 = line.find("(") + 1 + pos2 = line.find(")") + amount = float2int(line[pos1:pos2]) + elif atype == "bet" and line.find(": raises $")!=-1 and line.find("to $")!=-1: + pos=line.find("to $")+4 + amount=float2int(line[pos:]) else: if not isTourney: pos = line.rfind("$")+1 @@ -827,7 +807,7 @@ def parseActionAmount(line, atype, site, isTourney): #doesnt return anything, simply changes the passed arrays action_types and # action_amounts. For stud this expects numeric streets (3-7), for # holdem/omaha it expects predeal, preflop, flop, turn or river -def parseActionLine(site, base, isTourney, line, street, playerIDs, names, action_types, allIns, action_amounts, actionNos, actionTypeByNo): +def parseActionLine(base, isTourney, line, street, playerIDs, names, action_types, allIns, action_amounts, actionNos, actionTypeByNo): if street == "predeal" or street == "preflop": street = 0 elif street == "flop": @@ -846,7 +826,7 @@ def parseActionLine(site, base, isTourney, line, street, playerIDs, names, actio (line, allIn) = goesAllInOnThisLine(line) atype = parseActionType(line) playerno = recognisePlayerNo(line, names, atype) - amount = parseActionAmount(line, atype, site, isTourney) + amount = parseActionAmount(line, atype, isTourney) action_types[street][playerno].append(atype) allIns[street][playerno].append(allIn) @@ -869,11 +849,19 @@ def goesAllInOnThisLine(line): #end def goesAllInOnThisLine #returns the action type code (see table design) of the given action line -ActionTypes = { 'calls':"call", 'brings in for':"blind", 'completes it to':"bet", ' posts $':"blind", - ' posts a dead ' : "blind", ' posts the small blind of $':"blind", ': posts big blind ':"blind", - ' posts the big blind of $':"blind", ': posts small & big blinds $':"blind", - ': posts small blind $':"blind", ': posts small blind ':"blind", - ' bets' : "bet", ' raises' : "bet" +ActionTypes = { 'brings in for' :"blind", + ' posts $' :"blind", + ' posts a dead ' :"blind", + ' posts the small blind of $' :"blind", + ': posts big blind ' :"blind", + ': posts small blind ' :"blind", + ' posts the big blind of $' :"blind", + ': posts small & big blinds $' :"blind", + ': posts small blind $' :"blind", + 'calls' :"call", + 'completes it to' :"bet", + ' bets' :"bet", + ' raises' :"bet" } def parseActionType(line): if (line.startswith("Uncalled bet")): @@ -890,7 +878,7 @@ def parseActionType(line): #end def parseActionType #parses the ante out of the given line and checks which player paid it, updates antes accordingly. -def parseAnteLine(line, site, isTourney, names, antes): +def parseAnteLine(line, isTourney, names, antes): for i, name in enumerate(names): if line.startswith(name.encode("latin-1")): pos = line.rfind("$") + 1 @@ -916,7 +904,7 @@ def parseBuyin(topline): #parses a card line and changes the passed arrays accordingly #todo: reorganise this messy method -def parseCardLine(site, category, street, line, names, cardValues, cardSuits, boardValues, boardSuits): +def parseCardLine(category, street, line, names, cardValues, cardSuits, boardValues, boardSuits): if line.startswith("Dealt to") or " shows [" in line or "mucked [" in line: playerNo = recognisePlayerNo(line, names, "card") #anything but unbet will be ok for that string @@ -990,7 +978,7 @@ def parseCardLine(site, category, street, line, names, cardValues, cardSuits, bo raise FpdbError ("unrecognised line:"+line) #end def parseCardLine -def parseCashesAndSeatNos(lines, site): +def parseCashesAndSeatNos(lines): """parses the startCashes and seatNos of each player out of the given lines and returns them as a dictionary of two arrays""" cashes = [] seatNos = [] @@ -1001,10 +989,7 @@ def parseCashesAndSeatNos(lines, site): pos1=lines[i].rfind("($")+2 if pos1==1: #for tourneys - it's 1 instead of -1 due to adding 2 above pos1=lines[i].rfind("(")+1 - if (site=="ftp"): - pos2=lines[i].rfind(")") - elif (site=="ps"): - pos2=lines[i].find(" in chips") + pos2=lines[i].find(" in chips") cashes.append(float2int(lines[i][pos1:pos2])) return {'startCashes':cashes, 'seatNos':seatNos} #end def parseCashesAndSeatNos @@ -1018,7 +1003,7 @@ def parseFee(topline): #end def parsefee #returns a datetime object with the starttime indicated in the given topline -def parseHandStartTime(topline, site): +def parseHandStartTime(topline): #convert x:13:35 to 0x:13:35 counter=0 while counter < 10: @@ -1029,41 +1014,25 @@ def parseHandStartTime(topline, site): counter += 1 isUTC=False - if site=="ftp": - # Full Tilt Sit'n'Go - # Full Tilt Poker Game #10311865543: $1 + $0.25 Sit & Go (78057629), Table 1 - 25/50 - No Limit Hold'em - 0:07:45 ET - 2009/01/29 - # Cash Game: - # Full Tilt Poker Game #9403951181: Table CR - tay - $0.05/$0.10 - No Limit Hold'em - 9:40:20 ET - 2008/12/09 - # Full Tilt Poker Game #9468383505: Table Bike (deep 6) - $0.05/$0.10 - No Limit Hold'em - 5:09:36 ET - 2008/12/13 - pos = topline.find(" ", len(topline)-26)+1 - tmp = topline[pos:] - - rexx = '(?P
[0-9]+):(?P[0-9]+):(?P[0-9]+) ET [\- ]+(?P[0-9]{4})\/(?P[0-9]{2})\/(?P[0-9]{2})' - m = re.search(rexx,tmp) - result = datetime.datetime(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC'))) - elif site=="ps": - if topline.find("UTC")!=-1: - pos1 = topline.find("-")+2 - pos2 = topline.find("UTC") - tmp=topline[pos1:pos2] - isUTC=True - else: - tmp=topline - #print "parsehandStartTime, tmp:", tmp - pos = tmp.find("-")+2 - tmp = tmp[pos:] - #Need to match either - # 2008/09/07 06:23:14 ET or - # 2008/08/17 - 01:14:43 (ET) or - # 2008/11/12 9:33:31 CET [2008/11/12 3:33:31 ET] - rexx = '(?P[0-9]{4})\/(?P[0-9]{2})\/(?P[0-9]{2})[\- ]+(?P
[0-9]+):(?P[0-9]+):(?P[0-9]+)' - m = re.search(rexx,tmp) - #print "year:", int(m.group('YEAR')), "month", int(m.group('MON')), "day", int(m.group('DAY')), "hour", int(m.group('HR')), "minute", int(m.group('MIN')), "second", int(m.group('SEC')) - result = datetime.datetime(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC'))) + if topline.find("UTC")!=-1: + pos1 = topline.find("-")+2 + pos2 = topline.find("UTC") + tmp=topline[pos1:pos2] + isUTC=True else: - raise FpdbError("invalid site in parseHandStartTime") + tmp=topline + #print "parsehandStartTime, tmp:", tmp + pos = tmp.find("-")+2 + tmp = tmp[pos:] + #Need to match either + # 2008/09/07 06:23:14 ET or + # 2008/08/17 - 01:14:43 (ET) or + # 2008/11/12 9:33:31 CET [2008/11/12 3:33:31 ET] + rexx = '(?P[0-9]{4})\/(?P[0-9]{2})\/(?P[0-9]{2})[\- ]+(?P
[0-9]+):(?P[0-9]+):(?P[0-9]+)' + m = re.search(rexx,tmp) + result = datetime.datetime(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC'))) - if (site=="ftp" or site=="ps") and not isUTC: #these use US ET + if not isUTC: #these use US ET result+=datetime.timedelta(hours=5) return result @@ -1167,42 +1136,15 @@ def parseSiteHandNo(topline): return topline[pos1:pos2] #end def parseSiteHandNo -def parseTableLine(site, base, line): +def parseTableLine(base, line): """returns a dictionary with maxSeats and tableName""" - if site=="ps": - pos1=line.find('\'')+1 - pos2=line.find('\'', pos1) - #print "table:",line[pos1:pos2] - pos3=pos2+2 - pos4=line.find("-max") - #print "seats:",line[pos3:pos4] - return {'maxSeats':int(line[pos3:pos4]), 'tableName':line[pos1:pos2]} - elif site=="ftp": - pos1=line.find("Table ")+6 - pos2=line.find("-")-1 - if base=="hold": - maxSeats=9 - elif base=="stud": - maxSeats=8 - - if line.find("6 max")!=-1: - maxSeats=6 - elif line.find("4 max")!=-1: - maxSeats=4 - elif line.find("heads up")!=-1: - maxSeats=2 - - tableName = line[pos1:pos2] - for pattern in [' \(6 max\)', ' \(heads up\)', ' \(deep\)', - ' \(deep hu\)', ' \(deep 6\)', ' \(2\)', - ' \(edu\)', ' \(edu, 6 max\)', ' \(6\)', - ' \(speed\)', - ' no all-in', ' fast', ',', ' 50BB min', '\s+$']: - tableName = re.sub(pattern, '', tableName) - tableName = tableName.rstrip() - return {'maxSeats':maxSeats, 'tableName':tableName} - else: - raise FpdbError("invalid site ID") + pos1=line.find('\'')+1 + pos2=line.find('\'', pos1) + #print "table:",line[pos1:pos2] + pos3=pos2+2 + pos4=line.find("-max") + #print "seats:",line[pos3:pos4] + return {'maxSeats':int(line[pos3:pos4]), 'tableName':line[pos1:pos2]} #end def parseTableLine #returns the hand no assigned by the poker site @@ -1214,24 +1156,18 @@ def parseTourneyNo(topline): #end def parseTourneyNo #parses a win/collect line. manipulates the passed array winnings, no explicit return -def parseWinLine(line, site, names, winnings, isTourney): +def parseWinLine(line, names, winnings, isTourney): #print "parseWinLine: line:",line for i,n in enumerate(names): n = n.encode("latin-1") if line.startswith(n): if isTourney: pos1 = line.rfind("collected ") + 10 - if site == "ftp": - pos2 = line.find(")", pos1) - elif site == "ps": - pos2 = line.find(" ", pos1) - winnings[i] += int(line[pos1:pos2]) + pos2 = line.find(" ", pos1) + winnings[i]+=int(line[pos1:pos2]) else: pos1 = line.rfind("$") + 1 - if site == "ftp": - pos2 = line.find(")", pos1) - elif site == "ps": - pos2 = line.find(" ", pos1) + pos2 = line.find(" ", pos1) winnings[i] += float2int(line[pos1:pos2]) #end def parseWinLine @@ -1277,10 +1213,7 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c pos1=pos2+2 if isTourney: pos1-=1 - if (site_id==1): #ftp - pos2=topline.find(" ", pos1) - elif (site_id==2): #ps - pos2=topline.find(")") + pos2=topline.find(")") if pos2<=pos1: pos2=topline.find(")", pos1) @@ -1402,12 +1335,12 @@ def recognisePlayerIDs(cursor, names, site_id): if len(ids) != len(names): notfound = [n for n in names if n not in ids] # make list of names not in database if notfound: # insert them into database - cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", (notfound)) + cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", [(n,) for n in notfound]) q2 = "SELECT name,id FROM Players WHERE name=%s" % " OR name=".join(["%s" for n in notfound]) cursor.execute(q2, notfound) # get their new ids - tmp = dict(cursor.fetchall()) - for n in tmp: # put them all into the same dict - ids[n] = tmp[n] + tmp = cursor.fetchall() + for n,id in tmp: # put them all into the same dict + ids[n] = id # return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB return [ids[n] for n in names] #end def recognisePlayerIDs @@ -1463,28 +1396,6 @@ def recognisePlayerNo(line, names, atype): raise FpdbError ("failed to recognise player in: "+line+" atype:"+atype) #end def recognisePlayerNo -#returns the site abbreviation for the given site -def recogniseSite(line): - if (line.startswith("Full Tilt Poker") or line.startswith("FullTiltPoker")): - return "ftp" - elif (line.startswith("PokerStars")): - return "ps" - else: - raise FpdbError("failed to recognise site, line:"+line) -#end def recogniseSite - -#returns the ID of the given site -def recogniseSiteID(cursor, site): - if (site=="ftp"): - return 1 - #cursor.execute("SELECT id FROM Sites WHERE name = ('Full Tilt Poker')") - elif (site=="ps"): - return 2 - #cursor.execute("SELECT id FROM Sites WHERE name = ('PokerStars')") - else: - raise FpdbError("invalid site in recogniseSiteID: "+site) - return cursor.fetchall()[0][0] -#end def recogniseSiteID #removes trailing \n from the given array def removeTrailingEOL(arr): @@ -1526,11 +1437,12 @@ def storeActions(cursor, handsPlayersIds, actionTypes, allIns, actionAmounts, ac # Add inserts into a list and let inserts = inserts + [(handsPlayersIds[j], i, actionNos[i][j][k], actionTypes[i][j][k], allIns[i][j][k], actionAmounts[i][j][k])] - cursor.executemany("INSERT INTO HandsActions (handPlayerId, street, actionNo, action, allIn, amount) VALUES (%s, %s, %s, %s, %s, %s)", inserts) + cursor.executemany("INSERT INTO HandsActions (handsPlayerId, street, actionNo, action, allIn, amount) VALUES (%s, %s, %s, %s, %s, %s)", inserts) #end def storeActions def store_board_cards(cursor, hands_id, board_values, board_suits): #stores into table board_cards + return cursor.execute ("""INSERT INTO BoardCards (handId, card1Value, card1Suit, card2Value, card2Suit, card3Value, card3Suit, card4Value, card4Suit, card5Value, card5Suit) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", @@ -1540,46 +1452,166 @@ card5Value, card5Suit) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", #end def store_board_cards def storeHands(backend, conn, cursor, site_hand_no, gametype_id - ,hand_start_time, names, tableName, maxSeats): -#stores into table hands - cursor.execute ("INSERT INTO Hands (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats) VALUES (%s, %s, %s, %s, %s, %s, %s)", (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.datetime.today(), maxSeats)) - #todo: find a better way of doing this... - #cursor.execute("SELECT id FROM Hands WHERE siteHandNo=%s AND gametypeId=%s", (site_hand_no, gametype_id)) - #return cursor.fetchall()[0][0] + ,hand_start_time, names, tableName, maxSeats, hudCache): +#stores into table hands: + cursor.execute ("""INSERT INTO Hands + (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats + ,playersVpi, 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) + """ + , (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.datetime.today(), maxSeats + ,hudCache['playersVpi'], hudCache['playersAtStreet1'], hudCache['playersAtStreet2'] + ,hudCache['playersAtStreet3'], hudCache['playersAtStreet4'], hudCache['playersAtShowdown'] + ,hudCache['street0Raises'], hudCache['street1Raises'], hudCache['street2Raises'] + ,hudCache['street3Raises'], hudCache['street4Raises'], hudCache['street1Pot'] + ,hudCache['street2Pot'], hudCache['street3Pot'], hudCache['street4Pot'] + ,hudCache['showdownPot'] + )) return getLastInsertId(backend, conn, cursor) - #return db.insert_id() # mysql only #end def storeHands def store_hands_players_holdem_omaha(backend, conn, cursor, category, hands_id, player_ids, start_cashes - ,positions, card_values, card_suits, winnings, rakes, seatNos): + ,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) + if (category=="holdem"): for i in xrange(len(player_ids)): + startCards = Card.twoStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1]) + card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0]) + card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1]) cursor.execute (""" INSERT INTO HandsPlayers -(handId, playerId, startCash, position, -card1Value, card1Suit, card2Value, card2Suit, winnings, rake, seatNo) -VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", - (hands_id, player_ids[i], start_cashes[i], positions[i], - card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1], - winnings[i], rakes[i], seatNos[i])) +(handId, playerId, startCash, position, tourneyTypeId, + card1, card2, 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)""", + (hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid + card1, card2, 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] + ) ) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId=%s", (hands_id, player_ids[i])) #result.append(cursor.fetchall()[0][0]) - result.append( getLastInsertId(backend, conn, cursor) ) # mysql only + result.append( getLastInsertId(backend, conn, cursor) ) elif (category=="omahahi" or category=="omahahilo"): for i in xrange(len(player_ids)): + 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]) + card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0]) + card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1]) + card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2]) + card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3]) cursor.execute ("""INSERT INTO HandsPlayers -(handId, playerId, startCash, position, -card1Value, card1Suit, card2Value, card2Suit, -card3Value, card3Suit, card4Value, card4Suit, winnings, rake, seatNo) -VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", - (hands_id, player_ids[i], start_cashes[i], positions[i], - 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], - winnings[i], rakes[i], seatNos[i])) +(handId, playerId, startCash, position, tourneyTypeId, + card1, card2, card3, card4, 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)""", + (hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid + card1, card2, card3, card4, + 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] + ) ) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) #result.append(cursor.fetchall()[0][0]) - result.append( getLastInsertId(backend, conn, cursor) ) # mysql only + result.append( getLastInsertId(backend, conn, cursor) ) else: raise FpdbError("invalid category") return result @@ -1606,7 +1638,7 @@ VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, card_values[i][6], card_suits[i][6], winnings[i], rakes[i], seatNos[i])) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) #result.append(cursor.fetchall()[0][0]) - result.append( getLastInsertId(backend, conn, cursor) ) # mysql only + result.append( getLastInsertId(backend, conn, cursor) ) return result #end def store_hands_players_stud @@ -1640,7 +1672,7 @@ VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", raise FpdbError ("invalid card_values length:"+str(len(card_values[0]))) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) #result.append(cursor.fetchall()[0][0]) - result.append( getLastInsertId(backend, conn, cursor) ) # mysql only + result.append( getLastInsertId(backend, conn, cursor) ) return result #end def store_hands_players_holdem_omaha_tourney @@ -1665,7 +1697,7 @@ VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, card_values[i][6], card_suits[i][6], winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i])) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) #result.append(cursor.fetchall()[0][0]) - result.append( getLastInsertId(backend, conn, cursor) ) # mysql only + result.append( getLastInsertId(backend, conn, cursor) ) return result #end def store_hands_players_stud_tourney @@ -1678,8 +1710,8 @@ sure to also change the following storage method and table_viewer.prepare_data i #setup subarrays of the result dictionary. street0VPI=[] street0Aggr=[] - street0_3B4BChance=[] - street0_3B4BDone=[] + street0_3BChance=[] + street0_3BDone=[] street1Seen=[] street2Seen=[] street3Seen=[] @@ -1704,6 +1736,41 @@ sure to also change the following storage method and table_viewer.prepare_data i 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 @@ -1724,6 +1791,11 @@ sure to also change the following storage method and table_viewer.prepare_data i firstPfCallByNo = i firstPfCallerId = action[0] break + firstPlayId = firstPfCallerId + if firstPfRaiseByNo <> -1: + if firstPfRaiseByNo < firstPfCallByNo or firstPfCallByNo == -1: + firstPlayId = firstPfRaiserId + cutoffId=-1 buttonId=-1 @@ -1747,8 +1819,8 @@ sure to also change the following storage method and table_viewer.prepare_data i #set default values myStreet0VPI=False myStreet0Aggr=False - myStreet0_3B4BChance=False - myStreet0_3B4BDone=False + myStreet0_3BChance=False + myStreet0_3BDone=False myStreet1Seen=False myStreet2Seen=False myStreet3Seen=False @@ -1770,6 +1842,21 @@ sure to also change the following storage method and table_viewer.prepare_data i 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 @@ -1779,8 +1866,15 @@ sure to also change the following storage method and table_viewer.prepare_data i 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 - #PF3B4BChance and PF3B4B + #PF3BChance and PF3B pfFold=-1 pfRaise=-1 if firstPfRaiseByNo != -1: @@ -1791,30 +1885,33 @@ sure to also change the following storage method and table_viewer.prepare_data i if actionType[1] == "fold" and pfFold == -1: pfFold = i if pfFold == -1 or pfFold > firstPfRaiseByNo: - myStreet0_3B4BChance = True + myStreet0_3BChance = True if pfRaise > firstPfRaiseByNo: - myStreet0_3B4BDone = True + myStreet0_3BDone = True #steal calculations - if base == "hold": - if len(player_ids)>=5: #no point otherwise + 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]: - myStealAttemptChance=True + if firstPfRaiserId==player_ids[player] \ + and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo): myStealAttempted=True - elif firstPfRaiserId==buttonId or firstPfRaiserId==sbId or firstPfRaiserId==bbId or firstPfRaiserId==-1: + 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]: - myStealAttemptChance=True + if firstPfRaiserId==player_ids[player] \ + and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo): myStealAttempted=True - elif firstPfRaiserId==sbId or firstPfRaiserId==bbId or firstPfRaiserId==-1: + 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]: - myStealAttemptChance=True + if firstPfRaiserId==player_ids[player] \ + and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo): myStealAttempted=True - elif firstPfRaiserId==bbId or firstPfRaiserId==-1: + myStealAttemptChance=True + if firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1: myStealAttemptChance=True if positions[player]=='B': pass @@ -1856,7 +1953,17 @@ sure to also change the following storage method and table_viewer.prepare_data i 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 @@ -1864,6 +1971,11 @@ sure to also change the following storage method and table_viewer.prepare_data i 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 @@ -1881,6 +1993,11 @@ sure to also change the following storage method and table_viewer.prepare_data i 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 @@ -1898,6 +2015,11 @@ sure to also change the following storage method and table_viewer.prepare_data i 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 @@ -1915,6 +2037,11 @@ sure to also change the following storage method and table_viewer.prepare_data i 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 @@ -1935,8 +2062,8 @@ sure to also change the following storage method and table_viewer.prepare_data i #add each value to the appropriate array street0VPI.append(myStreet0VPI) street0Aggr.append(myStreet0Aggr) - street0_3B4BChance.append(myStreet0_3B4BChance) - street0_3B4BDone.append(myStreet0_3B4BDone) + street0_3BChance.append(myStreet0_3BChance) + street0_3BDone.append(myStreet0_3BDone) street1Seen.append(myStreet1Seen) street2Seen.append(myStreet2Seen) street3Seen.append(myStreet3Seen) @@ -1980,12 +2107,28 @@ sure to also change the following storage method and table_viewer.prepare_data i 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['street0VPI']=street0VPI result['street0Aggr']=street0Aggr - result['street0_3B4BChance']=street0_3B4BChance - result['street0_3B4BDone']=street0_3B4BDone + result['street0_3BChance']=street0_3BChance + result['street0_3BDone']=street0_3BDone result['street1Seen']=street1Seen result['street2Seen']=street2Seen result['street3Seen']=street3Seen @@ -2008,6 +2151,21 @@ sure to also change the following storage method and table_viewer.prepare_data i 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=[] @@ -2251,168 +2409,15 @@ def generateFoldToCB(street, playerIDs, didStreetCB, streetCBDone, foldToStreetC foldToStreetCBDone[player]=True #end def generateFoldToCB -def storeHudCache(cursor, base, category, gametypeId, playerIds, hudImportData): -# if (category=="holdem" or category=="omahahi" or category=="omahahilo"): - - #print "storeHudCache, len(playerIds)=", len(playerIds), " len(vpip)=" \ - #, len(hudImportData['street0VPI']), " len(totprof)=", len(hudImportData['totalProfit']) - for player in xrange(len(playerIds)): - if base=="hold": - cursor.execute("SELECT * FROM HudCache WHERE gametypeId+0=%s AND playerId=%s AND activeSeats=%s AND position=%s", (gametypeId, playerIds[player], len(playerIds), hudImportData['position'][player])) - else: - cursor.execute("SELECT * FROM HudCache WHERE gametypeId+0=%s AND playerId=%s AND activeSeats=%s", (gametypeId, playerIds[player], len(playerIds))) - row=cursor.fetchone() - #print "gametypeId:", gametypeId, "playerIds[player]",playerIds[player], "len(playerIds):",len(playerIds), "row:",row - - try: len(row) - except TypeError: - row=[] - - if not row: - #print "new huddata row" - doInsert=True - row=[] - row.append(0)#blank for id - row.append(gametypeId) - row.append(playerIds[player]) - row.append(len(playerIds))#seats - for i in xrange(len(hudImportData)+2): - row.append(0) - - else: - doInsert=False - # This is making a copy of the original list, although i really don't see any reason it's being done? - newrow=[] - newrow.extend(row) -# for i in xrange(len(row)): -# newrow.append(row[i]) - row=newrow - - if base=="hold": - row[4]=hudImportData['position'][player] - else: - row[4]=0 - row[5]=1 #tourneysGametypeId - row[6]+=1 #HDs - if hudImportData['street0VPI'][player]: row[7]+=1 - if hudImportData['street0Aggr'][player]: row[8]+=1 - if hudImportData['street0_3B4BChance'][player]: row[9]+=1 - if hudImportData['street0_3B4BDone'][player]: row[10]+=1 - if hudImportData['street1Seen'][player]: row[11]+=1 - if hudImportData['street2Seen'][player]: row[12]+=1 - if hudImportData['street3Seen'][player]: row[13]+=1 - if hudImportData['street4Seen'][player]: row[14]+=1 - if hudImportData['sawShowdown'][player]: row[15]+=1 - if hudImportData['street1Aggr'][player]: row[16]+=1 - if hudImportData['street2Aggr'][player]: row[17]+=1 - if hudImportData['street3Aggr'][player]: row[18]+=1 - if hudImportData['street4Aggr'][player]: row[19]+=1 - if hudImportData['otherRaisedStreet1'][player]: row[20]+=1 - if hudImportData['otherRaisedStreet2'][player]: row[21]+=1 - if hudImportData['otherRaisedStreet3'][player]: row[22]+=1 - if hudImportData['otherRaisedStreet4'][player]: row[23]+=1 - if hudImportData['foldToOtherRaisedStreet1'][player]: row[24]+=1 - if hudImportData['foldToOtherRaisedStreet2'][player]: row[25]+=1 - if hudImportData['foldToOtherRaisedStreet3'][player]: row[26]+=1 - if hudImportData['foldToOtherRaisedStreet4'][player]: row[27]+=1 - if hudImportData['wonWhenSeenStreet1'][player]!=0.0: row[28]+=hudImportData['wonWhenSeenStreet1'][player] - if hudImportData['wonAtSD'][player]!=0.0: row[29]+=hudImportData['wonAtSD'][player] - if hudImportData['stealAttemptChance'][player]: row[30]+=1 - if hudImportData['stealAttempted'][player]: row[31]+=1 - if hudImportData['foldBbToStealChance'][player]: row[32]+=1 - if hudImportData['foldedBbToSteal'][player]: row[33]+=1 - if hudImportData['foldSbToStealChance'][player]: row[34]+=1 - if hudImportData['foldedSbToSteal'][player]: row[35]+=1 - - if hudImportData['street1CBChance'][player]: row[36]+=1 - if hudImportData['street1CBDone'][player]: row[37]+=1 - if hudImportData['street2CBChance'][player]: row[38]+=1 - if hudImportData['street2CBDone'][player]: row[39]+=1 - if hudImportData['street3CBChance'][player]: row[40]+=1 - if hudImportData['street3CBDone'][player]: row[41]+=1 - if hudImportData['street4CBChance'][player]: row[42]+=1 - if hudImportData['street4CBDone'][player]: row[43]+=1 - - if hudImportData['foldToStreet1CBChance'][player]: row[44]+=1 - if hudImportData['foldToStreet1CBDone'][player]: row[45]+=1 - if hudImportData['foldToStreet2CBChance'][player]: row[46]+=1 - if hudImportData['foldToStreet2CBDone'][player]: row[47]+=1 - if hudImportData['foldToStreet3CBChance'][player]: row[48]+=1 - if hudImportData['foldToStreet3CBDone'][player]: row[49]+=1 - if hudImportData['foldToStreet4CBChance'][player]: row[50]+=1 - if hudImportData['foldToStreet4CBDone'][player]: row[51]+=1 - - #print "player=", player - #print "len(totalProfit)=", len(hudImportData['totalProfit']) - if hudImportData['totalProfit'][player]: - row[52]+=hudImportData['totalProfit'][player] - - if hudImportData['street1CheckCallRaiseChance'][player]: row[53]+=1 - if hudImportData['street1CheckCallRaiseDone'][player]: row[54]+=1 - if hudImportData['street2CheckCallRaiseChance'][player]: row[55]+=1 - if hudImportData['street2CheckCallRaiseDone'][player]: row[56]+=1 - if hudImportData['street3CheckCallRaiseChance'][player]: row[57]+=1 - if hudImportData['street3CheckCallRaiseDone'][player]: row[58]+=1 - if hudImportData['street4CheckCallRaiseChance'][player]: row[59]+=1 - if hudImportData['street4CheckCallRaiseDone'][player]: row[60]+=1 - - if doInsert: - #print "playerid before insert:",row[2] - cursor.execute("""INSERT INTO HudCache -(gametypeId, playerId, activeSeats, position, tourneyTypeId, -HDs, street0VPI, street0Aggr, street0_3B4BChance, street0_3B4BDone, -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) -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)""", (row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11], row[12], row[13], row[14], row[15], row[16], row[17], row[18], row[19], row[20], row[21], row[22], row[23], row[24], row[25], row[26], row[27], row[28], row[29], row[30], row[31], row[32], row[33], row[34], row[35], row[36], row[37], row[38], row[39], row[40], row[41], row[42], row[43], row[44], row[45], row[46], row[47], row[48], row[49], row[50], row[51], row[52], row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60])) - else: - #print "storing updated hud data line" - cursor.execute("""UPDATE HudCache -SET HDs=%s, street0VPI=%s, street0Aggr=%s, street0_3B4BChance=%s, street0_3B4BDone=%s, -street1Seen=%s, street2Seen=%s, street3Seen=%s, street4Seen=%s, sawShowdown=%s, -street1Aggr=%s, street2Aggr=%s, street3Aggr=%s, street4Aggr=%s, otherRaisedStreet1=%s, -otherRaisedStreet2=%s, otherRaisedStreet3=%s, otherRaisedStreet4=%s, foldToOtherRaisedStreet1=%s, foldToOtherRaisedStreet2=%s, -foldToOtherRaisedStreet3=%s, foldToOtherRaisedStreet4=%s, wonWhenSeenStreet1=%s, wonAtSD=%s, stealAttemptChance=%s, -stealAttempted=%s, foldBbToStealChance=%s, foldedBbToSteal=%s, foldSbToStealChance=%s, foldedSbToSteal=%s, -street1CBChance=%s, street1CBDone=%s, street2CBChance=%s, street2CBDone=%s, street3CBChance=%s, -street3CBDone=%s, street4CBChance=%s, street4CBDone=%s, foldToStreet1CBChance=%s, foldToStreet1CBDone=%s, -foldToStreet2CBChance=%s, foldToStreet2CBDone=%s, foldToStreet3CBChance=%s, foldToStreet3CBDone=%s, foldToStreet4CBChance=%s, -foldToStreet4CBDone=%s, totalProfit=%s, street1CheckCallRaiseChance=%s, street1CheckCallRaiseDone=%s, street2CheckCallRaiseChance=%s, -street2CheckCallRaiseDone=%s, street3CheckCallRaiseChance=%s, street3CheckCallRaiseDone=%s, street4CheckCallRaiseChance=%s, street4CheckCallRaiseDone=%s -WHERE gametypeId=%s AND playerId=%s AND activeSeats=%s AND position=%s AND tourneyTypeId=%s""", (row[6], row[7], row[8], row[9], row[10], - row[11], row[12], row[13], row[14], row[15], - row[16], row[17], row[18], row[19], row[20], - row[21], row[22], row[23], row[24], row[25], - row[26], row[27], row[28], row[29], row[30], - row[31], row[32], row[33], row[34], row[35], row[36], row[37], row[38], row[39], row[40], - row[41], row[42], row[43], row[44], row[45], row[46], row[47], row[48], row[49], row[50], - row[51], row[52], row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60], - row[1], row[2], row[3], str(row[4]), row[5])) -# else: -# print "todo: implement storeHudCache for stud base" -#end def storeHudCache - -def storeHudCache2(backend, cursor, base, category, gametypeId, playerIds, hudImportData): +def storeHudCache(backend, cursor, base, category, gametypeId, hand_start_time, playerIds, hudImportData): """Modified version aiming for more speed ...""" # if (category=="holdem" or category=="omahahi" or category=="omahahilo"): + if use_date_in_hudcache: + #print "key =", "d%02d%02d%02d " % (hand_start_time.year-2000, hand_start_time.month, hand_start_time.day) + styleKey = "d%02d%02d%02d" % (hand_start_time.year-2000, hand_start_time.month, hand_start_time.day) + else: + # hard-code styleKey as 'A000000' (all-time cache, no key) for now + styleKey = 'A000000' #print "storeHudCache, len(playerIds)=", len(playerIds), " len(vpip)=" \ #, len(hudImportData['street0VPI']), " len(totprof)=", len(hudImportData['totalProfit']) @@ -2435,8 +2440,8 @@ def storeHudCache2(backend, cursor, base, category, gametypeId, playerIds, hudIm row[6]+=1 #HDs if hudImportData['street0VPI'][player]: row[7]+=1 if hudImportData['street0Aggr'][player]: row[8]+=1 - if hudImportData['street0_3B4BChance'][player]: row[9]+=1 - if hudImportData['street0_3B4BDone'][player]: row[10]+=1 + if hudImportData['street0_3BChance'][player]: row[9]+=1 + if hudImportData['street0_3BDone'][player]: row[10]+=1 if hudImportData['street1Seen'][player]: row[11]+=1 if hudImportData['street2Seen'][player]: row[12]+=1 if hudImportData['street3Seen'][player]: row[13]+=1 @@ -2498,7 +2503,7 @@ def storeHudCache2(backend, cursor, base, category, gametypeId, playerIds, hudIm # Try to do the update first: num = cursor.execute("""UPDATE HudCache SET HDs=HDs+%s, street0VPI=street0VPI+%s, street0Aggr=street0Aggr+%s, - street0_3B4BChance=%s, street0_3B4BDone=%s, + street0_3BChance=street0_3BChance+%s, street0_3BDone=street0_3BDone+%s, street1Seen=street1Seen+%s, street2Seen=street2Seen+%s, street3Seen=street3Seen+%s, street4Seen=street4Seen+%s, sawShowdown=sawShowdown+%s, street1Aggr=street1Aggr+%s, street2Aggr=street2Aggr+%s, street3Aggr=street3Aggr+%s, @@ -2528,7 +2533,9 @@ WHERE gametypeId+0=%s AND playerId=%s AND activeSeats=%s AND position=%s -AND tourneyTypeId+0=%s""", (row[6], row[7], row[8], row[9], row[10], +AND tourneyTypeId+0=%s +AND styleKey=%s + """, (row[6], row[7], row[8], row[9], row[10], row[11], row[12], row[13], row[14], row[15], row[16], row[17], row[18], row[19], row[20], row[21], row[22], row[23], row[24], row[25], @@ -2539,15 +2546,15 @@ AND tourneyTypeId+0=%s""", (row[6], row[7], row[8], row[9], row[10], row[46], row[47], row[48], row[49], row[50], row[51], row[52], row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60], - row[1], row[2], row[3], str(row[4]), row[5])) + row[1], row[2], row[3], str(row[4]), row[5], styleKey)) # Test statusmessage to see if update worked, do insert if not #print "storehud2, upd num =", num if ( (backend == PGSQL and cursor.statusmessage != "UPDATE 1") or (backend == MYSQL_INNODB and num == 0) ): #print "playerid before insert:",row[2]," num = ", num cursor.execute("""INSERT INTO HudCache -(gametypeId, playerId, activeSeats, position, tourneyTypeId, -HDs, street0VPI, street0Aggr, street0_3B4BChance, street0_3B4BDone, +(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, @@ -2558,7 +2565,7 @@ street3CBDone, street4CBChance, street4CBDone, foldToStreet1CBChance, foldToStre foldToStreet2CBChance, foldToStreet2CBDone, foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone, totalProfit, street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone, street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone) -VALUES (%s, %s, %s, %s, %s, +VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, @@ -2569,7 +2576,196 @@ 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)""", (row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11], row[12], row[13], row[14], row[15], row[16], row[17], row[18], row[19], row[20], row[21], row[22], row[23], row[24], row[25], row[26], row[27], row[28], row[29], row[30], row[31], row[32], row[33], row[34], row[35], row[36], row[37], row[38], row[39], row[40], row[41], row[42], row[43], row[44], row[45], row[46], row[47], row[48], row[49], row[50], row[51], row[52], row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60])) +%s, %s, %s, %s, %s)""" + , (row[1], row[2], row[3], row[4], row[5], styleKey, row[6], row[7], row[8], row[9], row[10] + ,row[11], row[12], row[13], row[14], row[15], row[16], row[17], row[18], row[19], row[20] + ,row[21], row[22], row[23], row[24], row[25], row[26], row[27], row[28], row[29], row[30] + ,row[31], row[32], row[33], row[34], row[35], row[36], row[37], row[38], row[39], row[40] + ,row[41], row[42], row[43], row[44], row[45], row[46], row[47], row[48], row[49], row[50] + ,row[51], row[52], row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60]) ) + #print "hopefully inserted hud data line: ", cursor.statusmessage + # message seems to be "INSERT 0 1" + else: + #print "updated(2) hud data line" + pass +# else: +# print "todo: implement storeHudCache for stud base" +#end def storeHudCache + +def storeHudCache2(backend, cursor, base, category, gametypeId, hand_start_time, playerIds, hudImportData): + """Modified version aiming for more speed ...""" +# if (category=="holdem" or category=="omahahi" or category=="omahahilo"): + if use_date_in_hudcache: + #print "key =", "d%02d%02d%02d " % (hand_start_time.year-2000, hand_start_time.month, hand_start_time.day) + styleKey = "d%02d%02d%02d" % (hand_start_time.year-2000, hand_start_time.month, hand_start_time.day) + else: + # hard-code styleKey as 'A000000' (all-time cache, no key) for now + styleKey = 'A000000' + + #print "storeHudCache2, len(playerIds)=", len(playerIds), " len(vpip)=" \ + #, len(hudImportData['street0VPI']), " len(totprof)=", len(hudImportData['totalProfit']) + for player in xrange(len(playerIds)): + + # Set up a clean row + row=[] + row.append(0)#blank for id + row.append(gametypeId) + row.append(playerIds[player]) + row.append(len(playerIds))#seats + for i in xrange(len(hudImportData)+2): + row.append(0) + + if base=="hold": + row[4]=hudImportData['position'][player] + else: + row[4]=0 + row[5]=1 #tourneysGametypeId + row[6]+=1 #HDs + if hudImportData['street0VPI'][player]: row[7]+=1 + if hudImportData['street0Aggr'][player]: row[8]+=1 + if hudImportData['street0_3BChance'][player]: row[9]+=1 + if hudImportData['street0_3BDone'][player]: row[10]+=1 + if hudImportData['street1Seen'][player]: row[11]+=1 + if hudImportData['street2Seen'][player]: row[12]+=1 + if hudImportData['street3Seen'][player]: row[13]+=1 + if hudImportData['street4Seen'][player]: row[14]+=1 + if hudImportData['sawShowdown'][player]: row[15]+=1 + if hudImportData['street1Aggr'][player]: row[16]+=1 + if hudImportData['street2Aggr'][player]: row[17]+=1 + if hudImportData['street3Aggr'][player]: row[18]+=1 + if hudImportData['street4Aggr'][player]: row[19]+=1 + if hudImportData['otherRaisedStreet1'][player]: row[20]+=1 + if hudImportData['otherRaisedStreet2'][player]: row[21]+=1 + if hudImportData['otherRaisedStreet3'][player]: row[22]+=1 + if hudImportData['otherRaisedStreet4'][player]: row[23]+=1 + if hudImportData['foldToOtherRaisedStreet1'][player]: row[24]+=1 + if hudImportData['foldToOtherRaisedStreet2'][player]: row[25]+=1 + if hudImportData['foldToOtherRaisedStreet3'][player]: row[26]+=1 + if hudImportData['foldToOtherRaisedStreet4'][player]: row[27]+=1 + if hudImportData['wonWhenSeenStreet1'][player]!=0.0: row[28]+=hudImportData['wonWhenSeenStreet1'][player] + if hudImportData['wonAtSD'][player]!=0.0: row[29]+=hudImportData['wonAtSD'][player] + if hudImportData['stealAttemptChance'][player]: row[30]+=1 + if hudImportData['stealAttempted'][player]: row[31]+=1 + if hudImportData['foldBbToStealChance'][player]: row[32]+=1 + if hudImportData['foldedBbToSteal'][player]: row[33]+=1 + if hudImportData['foldSbToStealChance'][player]: row[34]+=1 + if hudImportData['foldedSbToSteal'][player]: row[35]+=1 + + if hudImportData['street1CBChance'][player]: row[36]+=1 + if hudImportData['street1CBDone'][player]: row[37]+=1 + if hudImportData['street2CBChance'][player]: row[38]+=1 + if hudImportData['street2CBDone'][player]: row[39]+=1 + if hudImportData['street3CBChance'][player]: row[40]+=1 + if hudImportData['street3CBDone'][player]: row[41]+=1 + if hudImportData['street4CBChance'][player]: row[42]+=1 + if hudImportData['street4CBDone'][player]: row[43]+=1 + + if hudImportData['foldToStreet1CBChance'][player]: row[44]+=1 + if hudImportData['foldToStreet1CBDone'][player]: row[45]+=1 + if hudImportData['foldToStreet2CBChance'][player]: row[46]+=1 + if hudImportData['foldToStreet2CBDone'][player]: row[47]+=1 + if hudImportData['foldToStreet3CBChance'][player]: row[48]+=1 + if hudImportData['foldToStreet3CBDone'][player]: row[49]+=1 + if hudImportData['foldToStreet4CBChance'][player]: row[50]+=1 + if hudImportData['foldToStreet4CBDone'][player]: row[51]+=1 + + #print "player=", player + #print "len(totalProfit)=", len(hudImportData['totalProfit']) + if hudImportData['totalProfit'][player]: + row[52]+=hudImportData['totalProfit'][player] + + if hudImportData['street1CheckCallRaiseChance'][player]: row[53]+=1 + if hudImportData['street1CheckCallRaiseDone'][player]: row[54]+=1 + if hudImportData['street2CheckCallRaiseChance'][player]: row[55]+=1 + if hudImportData['street2CheckCallRaiseDone'][player]: row[56]+=1 + if hudImportData['street3CheckCallRaiseChance'][player]: row[57]+=1 + if hudImportData['street3CheckCallRaiseDone'][player]: row[58]+=1 + if hudImportData['street4CheckCallRaiseChance'][player]: row[59]+=1 + if hudImportData['street4CheckCallRaiseDone'][player]: row[60]+=1 + + # Try to do the update first: + num = cursor.execute("""UPDATE HudCache +SET HDs=HDs+%s, street0VPI=street0VPI+%s, street0Aggr=street0Aggr+%s, + street0_3BChance=street0_3BChance+%s, street0_3BDone=street0_3BDone+%s, + street1Seen=street1Seen+%s, street2Seen=street2Seen+%s, street3Seen=street3Seen+%s, + street4Seen=street4Seen+%s, sawShowdown=sawShowdown+%s, + street1Aggr=street1Aggr+%s, street2Aggr=street2Aggr+%s, street3Aggr=street3Aggr+%s, + street4Aggr=street4Aggr+%s, otherRaisedStreet1=otherRaisedStreet1+%s, + otherRaisedStreet2=otherRaisedStreet2+%s, otherRaisedStreet3=otherRaisedStreet3+%s, + otherRaisedStreet4=otherRaisedStreet4+%s, + foldToOtherRaisedStreet1=foldToOtherRaisedStreet1+%s, foldToOtherRaisedStreet2=foldToOtherRaisedStreet2+%s, + foldToOtherRaisedStreet3=foldToOtherRaisedStreet3+%s, foldToOtherRaisedStreet4=foldToOtherRaisedStreet4+%s, + wonWhenSeenStreet1=wonWhenSeenStreet1+%s, wonAtSD=wonAtSD+%s, stealAttemptChance=stealAttemptChance+%s, + stealAttempted=stealAttempted+%s, foldBbToStealChance=foldBbToStealChance+%s, + foldedBbToSteal=foldedBbToSteal+%s, + foldSbToStealChance=foldSbToStealChance+%s, foldedSbToSteal=foldedSbToSteal+%s, + street1CBChance=street1CBChance+%s, street1CBDone=street1CBDone+%s, street2CBChance=street2CBChance+%s, + street2CBDone=street2CBDone+%s, street3CBChance=street3CBChance+%s, + street3CBDone=street3CBDone+%s, street4CBChance=street4CBChance+%s, street4CBDone=street4CBDone+%s, + foldToStreet1CBChance=foldToStreet1CBChance+%s, foldToStreet1CBDone=foldToStreet1CBDone+%s, + foldToStreet2CBChance=foldToStreet2CBChance+%s, foldToStreet2CBDone=foldToStreet2CBDone+%s, + foldToStreet3CBChance=foldToStreet3CBChance+%s, + foldToStreet3CBDone=foldToStreet3CBDone+%s, foldToStreet4CBChance=foldToStreet4CBChance+%s, + foldToStreet4CBDone=foldToStreet4CBDone+%s, totalProfit=totalProfit+%s, + street1CheckCallRaiseChance=street1CheckCallRaiseChance+%s, + street1CheckCallRaiseDone=street1CheckCallRaiseDone+%s, street2CheckCallRaiseChance=street2CheckCallRaiseChance+%s, + street2CheckCallRaiseDone=street2CheckCallRaiseDone+%s, street3CheckCallRaiseChance=street3CheckCallRaiseChance+%s, + street3CheckCallRaiseDone=street3CheckCallRaiseDone+%s, street4CheckCallRaiseChance=street4CheckCallRaiseChance+%s, + street4CheckCallRaiseDone=street4CheckCallRaiseDone+%s +WHERE gametypeId+0=%s +AND playerId=%s +AND activeSeats=%s +AND position=%s +AND tourneyTypeId+0=%s +AND styleKey=%s + """, (row[6], row[7], row[8], row[9], row[10], + row[11], row[12], row[13], row[14], row[15], + row[16], row[17], row[18], row[19], row[20], + row[21], row[22], row[23], row[24], row[25], + row[26], row[27], row[28], row[29], row[30], + row[31], row[32], row[33], row[34], row[35], + row[36], row[37], row[38], row[39], row[40], + row[41], row[42], row[43], row[44], row[45], + row[46], row[47], row[48], row[49], row[50], + row[51], row[52], row[53], row[54], row[55], + row[56], row[57], row[58], row[59], row[60], + row[1], row[2], row[3], str(row[4]), row[5], styleKey)) + # Test statusmessage to see if update worked, do insert if not + #print "storehud2, upd num =", num + if ( (backend == PGSQL and cursor.statusmessage != "UPDATE 1") + or (backend == MYSQL_INNODB and num == 0) ): + #print "playerid before insert:",row[2]," num = ", num + cursor.execute("""INSERT INTO HudCache +(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) +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)""" + , (row[1], row[2], row[3], row[4], row[5], styleKey, row[6], row[7], row[8], row[9], row[10] + ,row[11], row[12], row[13], row[14], row[15], row[16], row[17], row[18], row[19], row[20] + ,row[21], row[22], row[23], row[24], row[25], row[26], row[27], row[28], row[29], row[30] + ,row[31], row[32], row[33], row[34], row[35], row[36], row[37], row[38], row[39], row[40] + ,row[41], row[42], row[43], row[44], row[45], row[46], row[47], row[48], row[49], row[50] + ,row[51], row[52], row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60]) ) #print "hopefully inserted hud data line: ", cursor.statusmessage # message seems to be "INSERT 0 1" else: