From 014ddedc013dcb449596c2475b5744f664013291 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 7 Mar 2010 10:30:56 +0000 Subject: [PATCH 01/16] create db automatically if using sqlite --- pyfpdb/Database.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index f51ce5f5..8939d4b3 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -382,6 +382,7 @@ class Database: print msg raise FpdbError(msg) elif backend == Database.SQLITE: + create = True import sqlite3 if use_pool: sqlite3 = pool.manage(sqlite3, pool_size=1) From 2e83e91ba53802c2a59a93c162d159df51778212 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 8 Mar 2010 22:31:07 +0000 Subject: [PATCH 02/16] add having clause to sqlite version of guistats query --- pyfpdb/SQL.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 51863698..b6eb8ee0 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2099,6 +2099,7 @@ class Sql: ,plposition ,upper(gt.limitType) ,s.name + having 1 = 1 order by hp.playerId ,gt.base ,gt.category From 04acf25416e4f87e680eb38dce9efeba2fe8974d Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 8 Mar 2010 22:32:09 +0000 Subject: [PATCH 03/16] don't display headings for bottom table when it can't be calculated --- pyfpdb/GuiPlayerStats.py | 41 +++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index 3c3f46e3..a4bbdef1 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -208,6 +208,7 @@ class GuiPlayerStats (threading.Thread): def createStatsTable(self, vbox, playerids, sitenos, limits, type, seats, groups, dates, games): starttime = time() + show_detail = True # Scrolled window for summary table swin = gtk.ScrolledWindow(hadjustment=None, vadjustment=None) @@ -224,25 +225,30 @@ class GuiPlayerStats (threading.Thread): self.addGrid(swin, 'playerDetailedStats', flags, playerids ,sitenos, limits, type, seats, groups, dates, games) - # Separator - vbox2 = gtk.VBox(False, 0) - heading = gtk.Label(self.filterText['handhead']) - heading.show() - vbox2.pack_start(heading, expand=False, padding=3) + if 'allplayers' in groups and groups['allplayers']: + # can't currently do this combination so skip detailed table + show_detail = False - # 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() - vbox2.pack_start(swin, expand=True, padding=3) - vbox.pack2(vbox2) - vbox2.show() + if show_detail: + # Separator + vbox2 = gtk.VBox(False, 0) + heading = gtk.Label(self.filterText['handhead']) + heading.show() + vbox2.pack_start(heading, expand=False, padding=3) - # Detailed table - flags[0] = True - flags[2] = 1 - self.addGrid(swin, 'playerDetailedStats', flags, playerids - ,sitenos, limits, type, seats, groups, dates, games) + # 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() + vbox2.pack_start(swin, expand=True, padding=3) + vbox.pack2(vbox2) + vbox2.show() + + # Detailed table + flags[0] = True + flags[2] = 1 + self.addGrid(swin, 'playerDetailedStats', flags, playerids + ,sitenos, limits, type, seats, groups, dates, games) self.db.rollback() print "Stats page displayed in %4.2f seconds" % (time() - starttime) @@ -421,6 +427,7 @@ class GuiPlayerStats (threading.Thread): else: treerow.append(' ') iter = self.liststore[grid].append(treerow) + #print treerow sqlrow += 1 row += 1 vbox.show_all() From 6117eb64c8f30883bb0ca6d192b539157a497429 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 8 Mar 2010 22:47:44 +0000 Subject: [PATCH 04/16] remember separator position when refresh is clicked --- pyfpdb/GuiPlayerStats.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index a4bbdef1..30bef936 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -142,7 +142,7 @@ class GuiPlayerStats (threading.Thread): self.stats_frame = gtk.Frame() self.stats_frame.show() - self.stats_vbox = gtk.VBox(False, 0) + self.stats_vbox = gtk.VPaned() self.stats_vbox.show() self.stats_frame.add(self.stats_vbox) # self.fillStatsFrame(self.stats_vbox) @@ -155,12 +155,15 @@ class GuiPlayerStats (threading.Thread): # make sure Hand column is not displayed [x for x in self.columns if x[0] == 'hand'][0][1] = False + self.last_pos = -1 + def get_vbox(self): """returns the vbox of this thread""" return self.main_hbox def refreshStats(self, widget, data): + self.last_pos = self.stats_vbox.get_position() try: self.stats_vbox.destroy() except AttributeError: pass self.liststore = [] @@ -170,6 +173,8 @@ class GuiPlayerStats (threading.Thread): self.stats_vbox.show() self.stats_frame.add(self.stats_vbox) self.fillStatsFrame(self.stats_vbox) + if self.last_pos > 0: + self.stats_vbox.set_position(self.last_pos) def fillStatsFrame(self, vbox): sites = self.filters.getSites() From a10f7c144ea8aa302cc73437b5126f3dce7220ef Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 9 Mar 2010 22:36:03 +0000 Subject: [PATCH 05/16] allow log viewer to view all 4 log/error files --- pyfpdb/GuiLogView.py | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/pyfpdb/GuiLogView.py b/pyfpdb/GuiLogView.py index 9dcb9588..755e1762 100755 --- a/pyfpdb/GuiLogView.py +++ b/pyfpdb/GuiLogView.py @@ -33,6 +33,11 @@ log = logging.getLogger("logview") MAX_LINES = 100000 # max lines to display in window EST_CHARS_PER_LINE = 150 # used to guesstimate number of lines in log file +LOGFILES = [ [ 'Fpdb Errors', 'fpdb-errors.txt', False ] # label, filename, start value + , [ 'Fpdb Log', 'fpdb-log.txt', True ] + , [ 'HUD Errors', 'HUD-errors.txt', False ] + , [ 'HUD Log', 'HUD-log.txt', False ] + ] class GuiLogView: @@ -41,7 +46,7 @@ class GuiLogView: self.main_window = mainwin self.closeq = closeq - self.logfile = self.config.log_file # name of logfile + self.logfile = os.path.join(self.config.dir_log, LOGFILES[1][1]) self.dia = gtk.Dialog(title="Log Messages" ,parent=None ,flags=gtk.DIALOG_DESTROY_WITH_PARENT @@ -69,10 +74,19 @@ class GuiLogView: scrolledwindow.add(self.listview) self.vbox.pack_start(scrolledwindow, expand=True, fill=True, padding=0) + hb = gtk.HBox(False, 0) + grp = None + for logf in LOGFILES: + rb = gtk.RadioButton(group=grp, label=logf[0], use_underline=True) + if grp is None: grp = rb + rb.set_active(logf[2]) + rb.connect('clicked', self.__set_logfile, logf[0]) + hb.pack_start(rb, False, False, 3) refreshbutton = gtk.Button("Refresh") refreshbutton.connect("clicked", self.refresh, None) - self.vbox.pack_start(refreshbutton, False, False, 3) + hb.pack_start(refreshbutton, False, False, 3) refreshbutton.show() + self.vbox.pack_start(hb, False, False, 0) self.listview.show() scrolledwindow.show() @@ -90,6 +104,14 @@ class GuiLogView: self.dia.connect('response', self.dialog_response_cb) + def __set_logfile(self, w, file): + #print "w is", w, "file is", file, "active is", w.get_active() + if w.get_active(): + for logf in LOGFILES: + if logf[0] == file: + self.logfile = os.path.join(self.config.dir_log, logf[1]) + self.refresh(w, file) # params are not used + def dialog_response_cb(self, dialog, response_id): # this is called whether close button is pressed or window is closed self.closeq.put(self.__class__) @@ -131,11 +153,14 @@ class GuiLogView: l = 0 for line in open(self.logfile): - # eg line: + # example line in logfile format: # 2009-12-02 15:23:21,716 - config DEBUG config logger initialised l = l + 1 - if l > startline and len(line) > 49: - iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) ) + if l > startline: + if len(line) > 49 and line[23:26] == ' - ' and line[34:39] == ' ': + iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) ) + else: + iter = self.liststore.append( ('', '', '', line.strip(), True) ) def sortCols(self, col, n): try: From fb6af1fe75b694995001770eefdaf51412e06d50 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 30 Mar 2010 13:04:39 +0800 Subject: [PATCH 06/16] Fix for PT-Stud exported Stars HH's Exports files as 'RAZZ LIMIT' instead of 'Razz Limit' --- pyfpdb/PokerStarsToFpdb.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index bf0e8427..801f17d6 100644 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -50,8 +50,8 @@ class PokerStars(HandHistoryConverter): (?P([%(LS)s\+\d\.]+\s?(?P%(LEGAL_ISO)s)?)|Freeroll)\s+)? # close paren of tournament info (?PHORSE|8\-Game|HOSE)?\s?\(? - (?PHold\'em|Razz|7\sCard\sStud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi|Triple\sDraw\s2\-7\sLowball|5\sCard\sDraw)\s - (?PNo\sLimit|Limit|Pot\sLimit)\)?,?\s + (?PHold\'em|Razz|RAZZ|7\sCard\sStud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi|Triple\sDraw\s2\-7\sLowball|5\sCard\sDraw)\s + (?PNo\sLimit|Limit|LIMIT|Pot\sLimit)\)?,?\s (-\sLevel\s(?P[IVXLC]+)\s)? \(? # open paren of the stakes (?P%(LS)s|)? @@ -148,12 +148,13 @@ class PokerStars(HandHistoryConverter): '1000.00': ('250.00', '500.00')} - limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' } + limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl', 'LIMIT':'fl' } games = { # base, category "Hold'em" : ('hold','holdem'), 'Omaha' : ('hold','omahahi'), 'Omaha Hi/Lo' : ('hold','omahahilo'), 'Razz' : ('stud','razz'), + 'RAZZ' : ('stud','razz'), '7 Card Stud' : ('stud','studhi'), '7 Card Stud Hi/Lo' : ('stud','studhilo'), 'Badugi' : ('draw','badugi'), From 81c731b42ed54de9a665adfbcedfd979a39d085a Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 15 Apr 2010 14:51:20 +0800 Subject: [PATCH 07/16] Fix for CBet stat Patch from bbtgaf@googlemail.com aka gimick DerivedStats.betStreet() was only functioning if the player was the first person to act on a street. If the player was checked to the function would exit as False before ever finding the player --- pyfpdb/DerivedStats.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 327b8de2..ae581ee1 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -505,9 +505,13 @@ class DerivedStats(): """Returns true if player bet/raised the street as their first action""" betOrRaise = False for act in self.hand.actions[street]: - if act[0] == player and act[1] in ('bets', 'raises'): - betOrRaise = True - else: + if act[0] == player: + if act[1] in ('bets', 'raises'): + betOrRaise = True + else: + # player found but did not bet or raise as their first action break + #else: + # haven't found player's first action yet return betOrRaise From b14bed4e9b5a8cd9e0cb408d4e83d9d2caac2a4c Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 15 Apr 2010 15:48:57 +0800 Subject: [PATCH 08/16] Fix last patch - add pass --- pyfpdb/DerivedStats.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index ae581ee1..4e55cdfc 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -510,6 +510,7 @@ class DerivedStats(): betOrRaise = True else: # player found but did not bet or raise as their first action + pass break #else: # haven't found player's first action yet From 6ba7621f2a4a8eb934f02908c8afeef6d6533a88 Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 23 Apr 2010 00:28:30 +0800 Subject: [PATCH 09/16] Fix 'errors' stat in importer Instead of: GuiBulkImport done: Stored: 32 Duplicates: 0 Partial: 0 Errors: 32 in 0.530081987381 seconds - 0/sec We have: GuiBulkImport done: Stored: 0 Duplicates: 0 Partial: 0 Errors: 32 in 0.530081987381 seconds - 0/sec --- pyfpdb/fpdb_import.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 689858e0..56c59b77 100755 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -468,6 +468,7 @@ class Importer: errors = getattr(hhc, 'numErrors') stored = getattr(hhc, 'numHands') stored -= duplicates + stored -= errors else: # conversion didn't work # TODO: appropriate response? From 3dd5f92a3c115f9761e6c51ae78bcb32dcd6d00b Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 23 Apr 2010 00:33:24 +0800 Subject: [PATCH 10/16] Add logging for two areas, fix RAZZ v Razz issue Add ERROR conditions for determineGameType failing, and raise a FpdbParseError in each case --- pyfpdb/PokerStarsToFpdb.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 801f17d6..24cf3bb7 100644 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -135,8 +135,10 @@ class PokerStars(HandHistoryConverter): info = {} m = self.re_GameInfo.search(handText) if not m: - print "DEBUG: determineGameType(): did not match" - return None + tmp = handText[0:100] + log.error("determineGameType: Unable to recognise gametype from: '%s'" % tmp) + log.error("determineGameType: Raising FpdbParseError") + raise FpdbParseError mg = m.groupdict() # translations from captured groups to fpdb info strings @@ -154,7 +156,7 @@ class PokerStars(HandHistoryConverter): 'Omaha' : ('hold','omahahi'), 'Omaha Hi/Lo' : ('hold','omahahilo'), 'Razz' : ('stud','razz'), - 'RAZZ' : ('stud','razz'), + 'RAZZ' : ('stud','razz'), '7 Card Stud' : ('stud','studhi'), '7 Card Stud Hi/Lo' : ('stud','studhilo'), 'Badugi' : ('draw','badugi'), @@ -183,8 +185,13 @@ class PokerStars(HandHistoryConverter): info['type'] = 'tour' if info['limitType'] == 'fl' and info['bb'] is not None and info['type'] == 'ring' and info['base'] != 'stud': - info['sb'] = Lim_Blinds[mg['BB']][0] - info['bb'] = Lim_Blinds[mg['BB']][1] + try: + info['sb'] = Lim_Blinds[mg['BB']][0] + info['bb'] = Lim_Blinds[mg['BB']][1] + except KeyError: + log.error("determineGameType: Lim_Blinds has no lookup for '%s'" % mg['BB']) + log.error("determineGameType: Raising FpdbParseError") + raise FpdbParseError # NB: SB, BB must be interpreted as blinds or bets depending on limit type. return info From 5aadf643be07b1fc12887181a0128265508e91d9 Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 23 Apr 2010 00:36:12 +0800 Subject: [PATCH 11/16] Add '2' to the Lim_Blinds lookup table Fixes Dogs import issue. --- pyfpdb/PokerStarsToFpdb.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 24cf3bb7..75cf3cbb 100644 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -144,6 +144,7 @@ class PokerStars(HandHistoryConverter): # translations from captured groups to fpdb info strings Lim_Blinds = { '0.04': ('0.01', '0.02'), '0.10': ('0.02', '0.05'), '0.20': ('0.05', '0.10'), '0.50': ('0.10', '0.25'), '1.00': ('0.25', '0.50'), '2.00': ('0.50', '1.00'), + '2': ('0.50', '1.00'), '4.00': ('1.00', '2.00'), '6.00': ('1.00', '3.00'), '10.00': ('2.00', '5.00'), '20.00': ('5.00', '10.00'), '30.00': ('10.00', '15.00'), '60.00': ('15.00', '30.00'), '100.00': ('25.00', '50.00'),'200.00': ('50.00', '100.00'),'400.00': ('100.00', '200.00'), From c0ebc4b7cf4a039418e9eb0f5e6425312d1e3886 Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 22 Apr 2010 23:22:28 +0800 Subject: [PATCH 12/16] Update to Session viewer Fix a couple of crashers - Make sure last session in list is displayed correctly - Actually calculate hands/hour (Thanks Socratic) - Make graph display the correct number of sessions --- pyfpdb/GuiSessionViewer.py | 62 +++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/pyfpdb/GuiSessionViewer.py b/pyfpdb/GuiSessionViewer.py index b5ca0867..d11f83d8 100755 --- a/pyfpdb/GuiSessionViewer.py +++ b/pyfpdb/GuiSessionViewer.py @@ -184,7 +184,7 @@ class GuiSessionViewer (threading.Thread): sitenos.append(siteids[site]) _q = self.sql.query['getPlayerId'] _name = Charset.to_utf8(heroes[site]) - print 'DEBUG(_name) :: %s' % _name + #print 'DEBUG(_name) :: %s' % _name self.cursor.execute(_q, (_name,)) # arg = tuple result = self.db.cursor.fetchall() if len(result) == 1: @@ -262,13 +262,20 @@ class GuiSessionViewer (threading.Thread): times = map(lambda x:long(x[0]), hands) handids = map(lambda x:int(x[1]), hands) winnings = map(lambda x:float(x[4]), hands) - print "DEBUG: len(times) %s" %(len(times)) + #print "DEBUG: len(times) %s" %(len(times)) diffs = diff(times) # This array is the difference in starttime between consecutive hands index = nonzero(diff(times) > THRESHOLD) # This array represents the indexes into 'times' for start/end times of sessions # ie. times[index[0][0]] is the end of the first session #print "DEBUG: len(index[0]) %s" %(len(index[0])) - #print "DEBUG: index %s" %(index) - #print "DEBUG: index[0][0] %s" %(index[0][0]) + if len(index[0]) > 0: + #print "DEBUG: index[0][0] %s" %(index[0][0]) + #print "DEBUG: index %s" %(index) + pass + else: + index = [[0]] + #print "DEBUG: index %s" %(index) + #print "DEBUG: index[0][0] %s" %(index[0][0]) + pass total = 0 last_idx = 0 @@ -281,27 +288,57 @@ class GuiSessionViewer (threading.Thread): results = [] cum_sum = cumsum(winnings) cum_sum = cum_sum/100 + sid = 0 # Take all results and format them into a list for feeding into gui model. for i in range(len(index[0])): - sid = i # Session id hds = index[0][i] - last_idx # Number of hands in session if hds > 0: stime = strftime("%d/%m/%Y %H:%M", localtime(times[last_idx])) # Formatted start time etime = strftime("%d/%m/%Y %H:%M", localtime(times[index[0][i]])) # Formatted end time - hph = (times[index[0][i]] - times[last_idx])/60 # Hands per hour + minutesplayed = (times[index[0][i]] - times[last_idx])/60 + if minutesplayed == 0: + minutesplayed = 1 + hph = hds*60/minutesplayed # Hands per hour won = sum(winnings[last_idx:index[0][i]])/100.0 hwm = max(cum_sum[last_idx:index[0][i]]) lwm = min(cum_sum[last_idx:index[0][i]]) - #print "DEBUG: range: (%s, %s) - (min, max): (%s, %s)" %(last_idx, index[0][i], hwm, lwm) + open = (sum(winnings[:last_idx]))/100 + close = (sum(winnings[:index[0][i]]))/100 + #print "DEBUG: range: (%s, %s) - (min, max): (%s, %s) - (open,close): (%s, %s)" %(last_idx, index[0][i], lwm, hwm, open, close) results.append([sid, hds, stime, etime, hph, won]) - opens.append((sum(winnings[:last_idx]))/100) - closes.append((sum(winnings[:index[0][i]]))/100) + opens.append(open) + closes.append(close) highs.append(hwm) lows.append(lwm) - #print "Hands in session %4s: %4s Start: %s End: %s HPH: %s Profit: %s" %(sid, hds, stime, etime, hph, won) + #print "DEBUG: Hands in session %4s: %4s Start: %s End: %s HPH: %s Profit: %s" %(sid, hds, stime, etime, hph, won) total = total + (index[0][i] - last_idx) last_idx = index[0][i] + 1 + sid = sid+1 + else: + print "hds <= 0" + + #The last session is between times[last_idx:-1] + hds = len(times) - last_idx + stime = strftime("%d/%m/%Y %H:%M", localtime(times[last_idx])) # Formatted start time + etime = strftime("%d/%m/%Y %H:%M", localtime(times[index[0][-1]])) # Formatted end time + minutesplayed = (times[-1] - times[last_idx])/60 + if minutesplayed == 0: + minutesplayed = 1 + hph = hds*60/minutesplayed # Hands per hour + won = sum(winnings[last_idx:-1])/100.0 + hwm = max(cum_sum[last_idx:-1]) + lwm = min(cum_sum[last_idx:-1]) + open = (sum(winnings[:last_idx]))/100 + close = (sum(winnings[:-1]))/100 + #print "DEBUG: range: (%s, %s) - (min, max): (%s, %s) - (open,close): (%s, %s)" %(last_idx, index[0][i], lwm, hwm, open, close) + + results.append([sid, hds, stime, etime, hph, won]) + opens.append(open) + closes.append(close) + highs.append(hwm) + lows.append(lwm) + #print "Hands in session %4s: %4s Start: %s End: %s HPH: %s Profit: %s" %(sid, hds, stime, etime, hph, won) return (results, opens, closes, highs, lows) @@ -330,11 +367,6 @@ class GuiSessionViewer (threading.Thread): def generateGraph(self, opens, closes, highs, lows): self.clearGraphData() - #FIXME: Weird - first data entry is crashing this for me - opens = opens[1:] - closes = closes[1:] - highs = highs[1:] - lows = lows[1:] # print "DEBUG:" # print "highs = %s" % highs # print "lows = %s" % lows From d11623c7364b8b7ed06cfd0e1b790093668ebcc0 Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 23 Apr 2010 11:39:52 +0800 Subject: [PATCH 13/16] Update Session viewer based on Socratic comments --- pyfpdb/GuiSessionViewer.py | 61 ++++++++++++++------------------------ 1 file changed, 22 insertions(+), 39 deletions(-) diff --git a/pyfpdb/GuiSessionViewer.py b/pyfpdb/GuiSessionViewer.py index d11f83d8..b4f14d95 100755 --- a/pyfpdb/GuiSessionViewer.py +++ b/pyfpdb/GuiSessionViewer.py @@ -33,7 +33,7 @@ try: from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar from matplotlib.finance import candlestick2 - from numpy import diff, nonzero, sum, cumsum, max, min + from numpy import diff, nonzero, sum, cumsum, max, min, append # from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \ # DayLocator, MONDAY, timezone @@ -241,6 +241,9 @@ class GuiSessionViewer (threading.Thread): #end def fillStatsFrame(self, vbox): def generateDatasets(self, playerids, sitenos, limits, seats): + THRESHOLD = 1800 # Minimum number of seconds between consecutive hands before being considered a new session + PADDING = 5 # Additional time in minutes to add to a session, session startup, shutdown etc (FiXME: user configurable) + # Get a list of all handids and their timestampts #FIXME: Query still need to filter on blind levels @@ -255,7 +258,6 @@ class GuiSessionViewer (threading.Thread): q = q.replace("", "%s") self.db.cursor.execute(q) - THRESHOLD = 1800 hands = self.db.cursor.fetchall() # Take that list and create an array of the time between hands @@ -263,9 +265,11 @@ class GuiSessionViewer (threading.Thread): handids = map(lambda x:int(x[1]), hands) winnings = map(lambda x:float(x[4]), hands) #print "DEBUG: len(times) %s" %(len(times)) - diffs = diff(times) # This array is the difference in starttime between consecutive hands - index = nonzero(diff(times) > THRESHOLD) # This array represents the indexes into 'times' for start/end times of sessions - # ie. times[index[0][0]] is the end of the first session + diffs = diff(times) # This array is the difference in starttime between consecutive hands + diffs2 = append(diffs,THRESHOLD + 1) # Append an additional session to the end of the diffs, so the next line + # includes an index into the last 'session' + index = nonzero(diffs2 > THRESHOLD) # This array represents the indexes into 'times' for start/end times of sessions + # times[index[0][0]] is the end of the first session, #print "DEBUG: len(index[0]) %s" %(len(index[0])) if len(index[0]) > 0: #print "DEBUG: index[0][0] %s" %(index[0][0]) @@ -278,7 +282,7 @@ class GuiSessionViewer (threading.Thread): pass total = 0 - last_idx = 0 + first_idx = 0 lowidx = 0 uppidx = 0 opens = [] @@ -288,23 +292,24 @@ class GuiSessionViewer (threading.Thread): results = [] cum_sum = cumsum(winnings) cum_sum = cum_sum/100 - sid = 0 + sid = 1 # Take all results and format them into a list for feeding into gui model. for i in range(len(index[0])): - hds = index[0][i] - last_idx # Number of hands in session + hds = index[0][i] - first_idx + 1 # Number of hands in session if hds > 0: - stime = strftime("%d/%m/%Y %H:%M", localtime(times[last_idx])) # Formatted start time + stime = strftime("%d/%m/%Y %H:%M", localtime(times[first_idx])) # Formatted start time etime = strftime("%d/%m/%Y %H:%M", localtime(times[index[0][i]])) # Formatted end time - minutesplayed = (times[index[0][i]] - times[last_idx])/60 + minutesplayed = (times[index[0][i]] - times[first_idx])/60 if minutesplayed == 0: minutesplayed = 1 + minutesplayed = minutesplayed + PADDING hph = hds*60/minutesplayed # Hands per hour - won = sum(winnings[last_idx:index[0][i]])/100.0 - hwm = max(cum_sum[last_idx:index[0][i]]) - lwm = min(cum_sum[last_idx:index[0][i]]) - open = (sum(winnings[:last_idx]))/100 + won = sum(winnings[first_idx:index[0][i]])/100.0 + hwm = max(cum_sum[first_idx:index[0][i]]) + lwm = min(cum_sum[first_idx:index[0][i]]) + open = (sum(winnings[:first_idx]))/100 close = (sum(winnings[:index[0][i]]))/100 - #print "DEBUG: range: (%s, %s) - (min, max): (%s, %s) - (open,close): (%s, %s)" %(last_idx, index[0][i], lwm, hwm, open, close) + #print "DEBUG: range: (%s, %s) - (min, max): (%s, %s) - (open,close): (%s, %s)" %(first_idx, index[0][i], lwm, hwm, open, close) results.append([sid, hds, stime, etime, hph, won]) opens.append(open) @@ -312,34 +317,12 @@ class GuiSessionViewer (threading.Thread): highs.append(hwm) lows.append(lwm) #print "DEBUG: Hands in session %4s: %4s Start: %s End: %s HPH: %s Profit: %s" %(sid, hds, stime, etime, hph, won) - total = total + (index[0][i] - last_idx) - last_idx = index[0][i] + 1 + total = total + (index[0][i] - first_idx) + first_idx = index[0][i] + 1 sid = sid+1 else: print "hds <= 0" - #The last session is between times[last_idx:-1] - hds = len(times) - last_idx - stime = strftime("%d/%m/%Y %H:%M", localtime(times[last_idx])) # Formatted start time - etime = strftime("%d/%m/%Y %H:%M", localtime(times[index[0][-1]])) # Formatted end time - minutesplayed = (times[-1] - times[last_idx])/60 - if minutesplayed == 0: - minutesplayed = 1 - hph = hds*60/minutesplayed # Hands per hour - won = sum(winnings[last_idx:-1])/100.0 - hwm = max(cum_sum[last_idx:-1]) - lwm = min(cum_sum[last_idx:-1]) - open = (sum(winnings[:last_idx]))/100 - close = (sum(winnings[:-1]))/100 - #print "DEBUG: range: (%s, %s) - (min, max): (%s, %s) - (open,close): (%s, %s)" %(last_idx, index[0][i], lwm, hwm, open, close) - - results.append([sid, hds, stime, etime, hph, won]) - opens.append(open) - closes.append(close) - highs.append(hwm) - lows.append(lwm) - #print "Hands in session %4s: %4s Start: %s End: %s HPH: %s Profit: %s" %(sid, hds, stime, etime, hph, won) - return (results, opens, closes, highs, lows) def clearGraphData(self): From c871d7fc2fbe15bb7347be6bf685fab96b54ba46 Mon Sep 17 00:00:00 2001 From: gimick Date: Thu, 15 Apr 2010 23:16:26 +0100 Subject: [PATCH 14/16] gimick - Do not set CBChance if there has been a donkbet --- pyfpdb/DerivedStats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 4e55cdfc..f5278b99 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -368,8 +368,8 @@ class DerivedStats(): name = self.lastBetOrRaiser(hand.actionStreets[i+1]) if name: chance = self.noBetsBefore(hand.actionStreets[i+2], name) - self.handsplayers[name]['street%dCBChance' % (i+1)] = True if chance == True: + self.handsplayers[name]['street%dCBChance' % (i+1)] = True self.handsplayers[name]['street%dCBDone' % (i+1)] = self.betStreet(hand.actionStreets[i+2], name) def calcCheckCallRaise(self, hand): From 6e603149267822b07259d84ffa6c52c0590c8e53 Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 23 Apr 2010 11:49:57 +0800 Subject: [PATCH 15/16] First part of making FTP archive files work --- pyfpdb/HandHistoryConverter.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 2053eba9..5b65b955 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -62,7 +62,7 @@ class HandHistoryConverter(): codepage = "cp1252" - def __init__(self, config, in_path = '-', out_path = '-', follow=False, index=0, autostart=True, starsArchive=False): + def __init__(self, config, in_path = '-', out_path = '-', follow=False, index=0, autostart=True, starsArchive=False, ftpArchive=False): """\ in_path (default '-' = sys.stdin) out_path (default '-' = sys.stdout) @@ -75,6 +75,7 @@ follow : whether to tail -f the input""" self.index = index self.starsArchive = starsArchive + self.ftpArchive = ftpArchive self.in_path = in_path self.out_path = out_path @@ -247,6 +248,11 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py. m = re.compile('^Hand #\d+', re.MULTILINE) self.obs = m.sub('', self.obs) + if self.ftpArchive == True: + log.debug("Converting ftpArchive format to readable") + m = re.compile('^\*\*\*\*\*\*+\s#\s\d+\s\*\*\*\*\*+$', re.MULTILINE) + self.obs = m.sub('', self.obs) + if self.obs is None or self.obs == "": log.info("Read no hands.") return [] From 9ac46c8c92c1c135e9741bc8812d39f0dd51eb52 Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 23 Apr 2010 17:09:08 +0800 Subject: [PATCH 16/16] Add to Stars limit lookup table. --- pyfpdb/PokerStarsToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 75cf3cbb..c964faa5 100644 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -144,7 +144,7 @@ class PokerStars(HandHistoryConverter): # translations from captured groups to fpdb info strings Lim_Blinds = { '0.04': ('0.01', '0.02'), '0.10': ('0.02', '0.05'), '0.20': ('0.05', '0.10'), '0.50': ('0.10', '0.25'), '1.00': ('0.25', '0.50'), '2.00': ('0.50', '1.00'), - '2': ('0.50', '1.00'), + '2': ('0.50', '1.00'), '4': ('1.00', '2.00'), '6': ('1.00', '3.00'), '4.00': ('1.00', '2.00'), '6.00': ('1.00', '3.00'), '10.00': ('2.00', '5.00'), '20.00': ('5.00', '10.00'), '30.00': ('10.00', '15.00'), '60.00': ('15.00', '30.00'), '100.00': ('25.00', '50.00'),'200.00': ('50.00', '100.00'),'400.00': ('100.00', '200.00'),