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