From cf8b6c7e923ef4e97eab0866817924e5e15c0c9e Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Thu, 21 May 2009 04:26:00 +0100 Subject: [PATCH] several db changes and a fancy playerstats window, now to tidy the code up a bit .... --- pyfpdb/Card.py | 68 +++++++ pyfpdb/Database.py | 16 +- pyfpdb/Filters.py | 111 ++++++++---- pyfpdb/FpdbSQLQueries.py | 204 +++++++++++++++------ pyfpdb/GuiPlayerStats.py | 368 ++++++++++++++++++++++++++++---------- pyfpdb/SQL.py | 14 +- pyfpdb/fpdb_save_to_db.py | 4 +- pyfpdb/fpdb_simple.py | 200 ++++++++++++++++++--- 8 files changed, 758 insertions(+), 227 deletions(-) create mode 100755 pyfpdb/Card.py diff --git a/pyfpdb/Card.py b/pyfpdb/Card.py new file mode 100755 index 00000000..4ecd69b0 --- /dev/null +++ b/pyfpdb/Card.py @@ -0,0 +1,68 @@ +#!/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 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/Database.py b/pyfpdb/Database.py index 0e5c1547..0483da96 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -32,6 +32,7 @@ import traceback # FreePokerTools modules import Configuration import SQL +import Card class Database: def __init__(self, c, db_name, game): @@ -78,6 +79,7 @@ class Database: self.type = c.supported_databases[db_name].db_type self.sql = SQL.Sql(game = game, type = self.type) + self.connection.rollback() def close_connection(self): self.connection.close() @@ -122,11 +124,17 @@ class Database: c = self.connection.cursor() c.execute(self.sql.query['get_cards'], [hand]) colnames = [desc[0] for desc in c.description] + cardnames = ['card1', 'card2', 'card3', 'card4', 'card5', 'card6', 'card7'] for row in c.fetchall(): - 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): diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py index d35d0817..3a5f0365 100644 --- a/pyfpdb/Filters.py +++ b/pyfpdb/Filters.py @@ -38,6 +38,7 @@ class Filters(threading.Thread): self.settings=settings self.sql=qdict self.conf = config + self.display = display self.sites = {} self.games = {} @@ -45,10 +46,12 @@ class Filters(threading.Thread): 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 Seats' + 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. @@ -66,6 +69,7 @@ class Filters(threading.Thread): self.fillPlayerFrame(vbox) playerFrame.add(vbox) + self.boxes['player'] = vbox sitesFrame = gtk.Frame("Sites:") sitesFrame.set_label_align(0.0, 0.0) @@ -73,6 +77,7 @@ class Filters(threading.Thread): self.fillSitesFrame(vbox) sitesFrame.add(vbox) + self.boxes['sites'] = vbox # Game types gamesFrame = gtk.Frame("Games:") @@ -82,29 +87,29 @@ class Filters(threading.Thread): self.fillGamesFrame(vbox) gamesFrame.add(vbox) + self.boxes['games'] = vbox # Limits - limitsFrame = gtk.Frame("Limits:") - limitsFrame.set_label_align(0.0, 0.0) + limitsFrame = gtk.Frame() limitsFrame.show() vbox = gtk.VBox(False, 0) self.cbLimits = {} self.cbNoLimits = None self.cbAllLimits = None - self.fillLimitsFrame(vbox, display) + self.fillLimitsFrame(vbox, self.display) limitsFrame.add(vbox) # Seats - seatsFrame = gtk.Frame("Seats:") - seatsFrame.set_label_align(0.0, 0.0) + seatsFrame = gtk.Frame() seatsFrame.show() vbox = gtk.VBox(False, 0) self.sbSeats = {} - self.fillSeatsFrame(vbox, display) + self.fillSeatsFrame(vbox, self.display) seatsFrame.add(vbox) + # Date dateFrame = gtk.Frame("Date:") dateFrame.set_label_align(0.0, 0.0) dateFrame.show() @@ -112,11 +117,13 @@ class Filters(threading.Thread): 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.exportButton.connect("clicked", self.exportGraph, "show clicked") self.Button2.set_sensitive(False) self.mainVBox.add(playerFrame) @@ -131,21 +138,21 @@ class Filters(threading.Thread): self.mainVBox.show_all() # Should do this cleaner - if "Heroes" not in display or display["Heroes"] == False: + if "Heroes" not in self.display or self.display["Heroes"] == False: playerFrame.hide() - if "Sites" not in display or display["Sites"] == False: + if "Sites" not in self.display or self.display["Sites"] == False: sitesFrame.hide() - if "Games" not in display or display["Games"] == False: + if "Games" not in self.display or self.display["Games"] == False: gamesFrame.hide() - if "Limits" not in display or display["Limits"] == False: + if "Limits" not in self.display or self.display["Limits"] == False: limitsFrame.hide() - if "Seats" not in display or display["Seats"] == False: + if "Seats" not in self.display or self.display["Seats"] == False: seatsFrame.hide() - if "Dates" not in display or display["Dates"] == False: + if "Dates" not in self.display or self.display["Dates"] == False: dateFrame.hide() - if "Button1" not in display or display["Button1"] == False: + if "Button1" not in self.display or self.display["Button1"] == False: self.Button1.hide() - if "Button2" not in display or display["Button2"] == False: + if "Button2" not in self.display or self.display["Button2"] == False: self.Button2.hide() def get_vbox(self): @@ -184,12 +191,14 @@ class Filters(threading.Thread): 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()]) @@ -226,7 +235,7 @@ class Filters(threading.Thread): cb = gtk.CheckButton(str(ltext)) cb.connect('clicked', self.__set_limit_select, limit) hbox.pack_start(cb, False, False, 0) - if limit != "None": + if limit != "none": cb.set_active(True) return(cb) @@ -251,11 +260,11 @@ class Filters(threading.Thread): else: if self.cbAllLimits != None: self.cbAllLimits.set_active(False) - elif limit == "All": + elif limit == "all": if self.limits[limit]: for cb in self.cbLimits.values(): cb.set_active(True) - elif limit == "None": + elif limit == "none": if self.limits[limit]: for cb in self.cbLimits.values(): cb.set_active(False) @@ -298,38 +307,66 @@ class Filters(threading.Thread): print "INFO: No games returned from database" def fillLimitsFrame(self, vbox, display): + hbox = gtk.HBox(False, 0) + vbox.pack_start(hbox, False, False, 0) + 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) - vbox.pack_start(hbox, False, False, 0) - vbox1 = gtk.VBox(False, 0) - hbox.pack_start(vbox1, False, False, 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: - vbox1.pack_start(hbox, False, False, 0) - else: 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) - vbox.pack_start(hbox, False, True, 0) + vbox1.pack_start(hbox, False, True, 0) self.cbAllLimits = self.createLimitLine(hbox, 'all', self.filterText['limitsall']) hbox = gtk.HBox(False, 0) - vbox.pack_start(hbox, False, True, 0) + vbox1.pack_start(hbox, False, True, 0) self.cbNoLimits = self.createLimitLine(hbox, 'none', self.filterText['limitsnone']) hbox = gtk.HBox(False, 0) - vbox.pack_start(hbox, False, True, 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, True, 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']) @@ -338,8 +375,6 @@ class Filters(threading.Thread): 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) @@ -347,7 +382,7 @@ class Filters(threading.Thread): if "SeatSep" in display and display["SeatSep"] == True: hbox = gtk.HBox(False, 0) - vbox.pack_start(hbox, False, True, 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) @@ -358,8 +393,6 @@ class Filters(threading.Thread): self.sbSeats['from'] = sb1 self.sbSeats['to'] = sb2 - - def fillCardsFrame(self, vbox): hbox1 = gtk.HBox(True,0) hbox1.show() @@ -414,6 +447,16 @@ class Filters(threading.Thread): 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') diff --git a/pyfpdb/FpdbSQLQueries.py b/pyfpdb/FpdbSQLQueries.py index dd770106..422da934 100644 --- a/pyfpdb/FpdbSQLQueries.py +++ b/pyfpdb/FpdbSQLQueries.py @@ -183,37 +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, - vpi SMALLINT, - street0Seen SMALLINT, - street1Seen SMALLINT, - street2Seen SMALLINT, - street3Seen SMALLINT, - street4Seen SMALLINT, - sdSeen SMALLINT, + 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, - vpi SMALLINT, - street0Seen SMALLINT, - street1Seen SMALLINT, - street2Seen SMALLINT, - street3Seen SMALLINT, - street4Seen SMALLINT, - sdSeen 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'] = """ """ @@ -321,20 +351,13 @@ class FpdbSQLQueries: position CHAR(1), seatNo SMALLINT NOT NULL, - 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), + 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, @@ -416,7 +439,25 @@ class FpdbSQLQueries: 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'): @@ -428,20 +469,13 @@ class FpdbSQLQueries: position CHAR(1), seatNo SMALLINT NOT NULL, - 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), + 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, @@ -524,6 +558,24 @@ class FpdbSQLQueries: 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'] = """ """ @@ -674,7 +726,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 ( @@ -756,7 +825,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'] = """ """ @@ -867,6 +953,8 @@ class FpdbSQLQueries: where hp.playerId in and hp.tourneysPlayersId IS NULL and h.seats + + group by hgameTypeId ,hp.playerId ,gt.base @@ -878,6 +966,8 @@ class FpdbSQLQueries: ,gt.base ,gt.category + + ,maxbigblind desc ,upper(gt.limitType) ,s.name """ diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index 73cb981f..a7f3abf1 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -20,7 +20,9 @@ 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 @@ -47,6 +49,10 @@ class GuiPlayerStats (threading.Thread): 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, @@ -55,65 +61,93 @@ class GuiPlayerStats (threading.Thread): "Seats" : True, "SeatSep" : True, "Dates" : False, + "Groups" : True, "Button1" : True, - "Button2" : False + "Button2" : True } self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display) - self.filters.registerButton1Name("Refresh") - self.filters.registerButton1Callback(self.refreshStats) + self.filters.registerButton1Name("_Filters") + self.filters.registerButton1Callback(self.showDetailFilter) + self.filters.registerButton2Name("_Refresh") + self.filters.registerButton2Callback(self.refreshStats) - # TODO: these probably be a dict keyed on colAlias and the headings loop should use colAlias ... - # This could be stored in config eventually, or maybe configured in this window somehow. - # Each colAlias element is the name of a column returned by the sql - # query (in lower case) and each colHeads 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.colAlias = ( "game", "n", "avgseats", "vpip", "pfr", "pf3", "steals" - , "saw_f", "sawsd", "wtsdwsf", "wmsd", "flafq", "tuafq", "rvafq" - , "pofafq", "net", "bbper100", "rake", "variance" - ) - self.colHeads = ( "Game", "Hds", "Seats", "VPIP", "PFR", "PF3", "Steals" - , "Saw_F", "SawSD", "WtSDwsF", "W$SD", "FlAFq", "TuAFq", "RvAFq" - , "PoFAFq", "Net($)", "BB/100", "Rake($)", "Variance" - ) - self.colXAligns = ( 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 - , 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 - , 1.0, 1.0, 1.0, 1.0, 1.0 - ) - self.colFormats = ( "%s", "%d", "%3.1f", "%3.1f", "%3.1f", "%3.1f", "%3.1f" - , "%3.1f", "%3.1f", "%3.1f", "%3.1f", "%3.1f", "%3.1f", "%3.1f" - , "%3.1f", "%6.2f", "%4.2f", "%6.2f", "%5.2f" - ) + # 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.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() - 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(statsFrame) + 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_table.destroy() + try: self.stats_vbox.destroy() except AttributeError: pass - self.fillStatsFrame(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) def fillStatsFrame(self, vbox): sites = self.filters.getSites() @@ -147,72 +181,137 @@ class GuiPlayerStats (threading.Thread): 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() - vbox.add(self.stats_table) - - # Create header row - row = 0 - col = 0 - for t in self.colHeads: - l = gtk.Label(self.colHeads[col]) - l.set_alignment(xalign=self.colXAligns[col], yalign=0.5) - l.show() - self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK) - col +=1 - - tmp = self.sql.query['playerDetailedStats'] - tmp = self.refineQuery(tmp, playerids, sitenos, limits, seats) + + tmp = self.sql.query[query] + tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, seats) self.cursor.execute(tmp) result = self.cursor.fetchall() - - #cols = 19 - rows = len(result) # +1 for title row colnames = [desc[0].lower() for desc in self.cursor.description] - col = 0 - for row in range(rows): + # 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,colname in enumerate(self.colAlias): - if colname in colnames: - value = result[row][colnames.index(colname)] + for col,column in enumerate(cols_to_show): + if column[colalias] in colnames: + value = result[sqlrow][colnames.index(column[colalias])] else: - if colname == 'game': - minbb = result[row][colnames.index('minbigblind')] - maxbb = result[row][colnames.index('maxbigblind')] - value = result[row][colnames.index('limittype')] + ' ' \ - + result[row][colnames.index('category')].title() + ' ' \ - + result[row][colnames.index('name')] + ' $' - if 100 * int(minbb/100.0) != minbb: - value += '%.2f' % (minbb/100.0) + if column[colalias] == 'game': + if holecards: + value = Card.twoStartCardString( result[sqlrow][hgametypeid_idx] ) else: - value += '%.0f' % (minbb/100.0) - if minbb != maxbb: - if 100 * int(maxbb/100.0) != maxbb: - value += ' - $' + '%.2f' % (maxbb/100.0) + 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' % (maxbb/100.0) + 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 - eb = gtk.EventBox() - eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor)) if value and value != -999: - l = gtk.Label(self.colFormats[col] % value) + treerow.append(column[colformat] % value) else: - l = gtk.Label(' ') - l.set_alignment(xalign=self.colXAligns[col], 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.db.db.commit() - #end def fillStatsFrame(self, vbox): + 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] - def refineQuery(self, query, playerids, sitenos, limits, seats): if playerids: nametest = str(tuple(playerids)) nametest = nametest.replace("L", "") @@ -238,20 +337,32 @@ class GuiPlayerStats (threading.Thread): 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) + query = query.replace("", " and gt.bigBlind in " + blindtest + " ") else: - query = query.replace("", "gt.bigBlind = -1 ") + query = query.replace("", "") - groupLevels = "show" not in str(limits) - if groupLevels: - query = query.replace("", "") - query = query.replace("", "-1") - query = query.replace("", "-1") + if holecards: # pinch level variables for hole card query + query = query.replace("", "hp.startcards") + query = query.replace("", ",hgameTypeId desc") else: - query = query.replace("", ",gt.bigBlind") - query = query.replace("", "hc.gametypeId") - query = query.replace("", "h.gameTypeId") + 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: @@ -260,3 +371,70 @@ class GuiPlayerStats (threading.Thread): #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() + + + + + diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 9eb42d0f..6d4c3241 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -349,13 +349,13 @@ class Sql: select seatNo AS seat_number, name AS screen_name, - card1Value, card1Suit, - card2Value, card2Suit, - card3Value, card3Suit, - card4Value, card4Suit, - card5Value, card5Suit, - card6Value, card6Suit, - card7Value, card7Suit + card1, /*card1Value, card1Suit, */ + card2, /*card2Value, card2Suit, */ + card3, /*card3Value, card3Suit, */ + card4, /*card4Value, card4Suit, */ + card5, /*card5Value, card5Suit, */ + card6, /*card6Value, card6Suit, */ + card7 /*card7Value, card7Suit */ from HandsPlayers, Players where handID = %s and HandsPlayers.playerId = Players.id order by seatNo diff --git a/pyfpdb/fpdb_save_to_db.py b/pyfpdb/fpdb_save_to_db.py index f983b910..18344030 100644 --- a/pyfpdb/fpdb_save_to_db.py +++ b/pyfpdb/fpdb_save_to_db.py @@ -82,11 +82,11 @@ def ring_holdem_omaha(config, backend, db, cursor, base, category, site_hand_no, t2 = time() hands_id = fpdb_simple.storeHands(backend, db, cursor, site_hand_no, gametype_id - ,hand_start_time, names, tableName, maxSeats) + ,hand_start_time, names, tableName, maxSeats, hudImportData) t3 = time() hands_players_ids = fpdb_simple.store_hands_players_holdem_omaha( backend, db, cursor, category, hands_id, player_ids, start_cashes - , positions, card_values, card_suits, winnings, rakes, seatNos) + , positions, card_values, card_suits, winnings, rakes, seatNos, hudImportData) t4 = time() #print "ring holdem, backend=%d" % backend if fastStoreHudCache: diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index cd8a9e76..2b36cf01 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -20,6 +20,8 @@ import datetime import time import re + +import Card PS = 1 FTP = 2 @@ -1448,14 +1450,29 @@ card5Value, card5Suit) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", #end def store_board_cards def storeHands(backend, conn, cursor, site_hand_no, gametype_id - ,hand_start_time, names, tableName, maxSeats): -#stores into table hands - cursor.execute ("INSERT INTO Hands (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats) VALUES (%s, %s, %s, %s, %s, %s, %s)", (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.datetime.today(), maxSeats)) - #todo: find a better way of doing this... - #cursor.execute("SELECT id FROM Hands WHERE siteHandNo=%s AND gametypeId=%s", (site_hand_no, gametype_id)) - #return cursor.fetchall()[0][0] + ,hand_start_time, names, tableName, maxSeats, hudCache): +#stores into table hands: + cursor.execute ("""INSERT INTO Hands + (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats + ,playersVpi, playersAtStreet1, playersAtStreet2 + ,playersAtStreet3, playersAtStreet4, playersAtShowdown + ,street0Raises, street1Raises, street2Raises + ,street3Raises, street4Raises, street1Pot + ,street2Pot, street3Pot, street4Pot + ,showdownPot + ) + VALUES + (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + """ + , (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.datetime.today(), maxSeats + ,hudCache['playersVpi'], hudCache['playersAtStreet1'], hudCache['playersAtStreet2'] + ,hudCache['playersAtStreet3'], hudCache['playersAtStreet4'], hudCache['playersAtShowdown'] + ,hudCache['street0Raises'], hudCache['street1Raises'], hudCache['street2Raises'] + ,hudCache['street3Raises'], hudCache['street4Raises'], hudCache['street1Pot'] + ,hudCache['street2Pot'], hudCache['street3Pot'], hudCache['street4Pot'] + ,hudCache['showdownPot'] + )) return getLastInsertId(backend, conn, cursor) - #return db.insert_id() # mysql only #end def storeHands def store_hands_players_holdem_omaha(backend, conn, cursor, category, hands_id, player_ids, start_cashes @@ -1474,14 +1491,13 @@ def store_hands_players_holdem_omaha(backend, conn, cursor, category, hands_id, if (category=="holdem"): for i in xrange(len(player_ids)): - x,y = card_values[i][0],card_values[i][1] - if (card_suits[i][0] == card_suits[i][1] and x < y) or (card_suits[i][0] != card_suits[i][1] and x > y): - x,y = y,x - startCards = 13 * (x-2) + (y-2) + startCards = Card.twoStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1]) + card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0]) + card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1]) cursor.execute (""" INSERT INTO HandsPlayers -(handId, playerId, startCash, position, activeSeats, tourneyTypeId, - card1Value, card1Suit, card2Value, card2Suit, winnings, rake, seatNo, totalProfit, +(handId, playerId, startCash, position, tourneyTypeId, + card1, card2, startCards, winnings, rake, seatNo, totalProfit, street0VPI, street0Aggr, street0_3BChance, street0_3BDone, street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, street1Aggr, street2Aggr, street3Aggr, street4Aggr, @@ -1494,13 +1510,16 @@ INSERT INTO HandsPlayers foldToStreet1CBChance, foldToStreet1CBDone, foldToStreet2CBChance, foldToStreet2CBDone, foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone, street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone, - street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone + street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone, + street0Calls, street1Calls, street2Calls, street3Calls, street4Calls, + street0Bets, street1Bets, street2Bets, street3Bets, street4Bets ) -VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, +VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", - (hands_id, player_ids[i], start_cashes[i], positions[i], len(player_ids), 1, # tourneytypeid - card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1], + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s)""", + (hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid + card1, card2, startCards, winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i], hudCache['street0VPI'][i], hudCache['street0Aggr'][i], hudCache['street0_3BChance'][i], hudCache['street0_3BDone'][i], @@ -1523,7 +1542,9 @@ VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i], hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i], - hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i] + hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i], + hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i], + hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i] ) ) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId=%s", (hands_id, player_ids[i])) #result.append(cursor.fetchall()[0][0]) @@ -1531,8 +1552,8 @@ VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, elif (category=="omahahi" or category=="omahahilo"): for i in xrange(len(player_ids)): cursor.execute ("""INSERT INTO HandsPlayers -(handId, playerId, startCash, position, activeSeats, tourneyTypeId, - card1Value, card1Suit, card2Value, card2Suit, +(handId, playerId, startCash, position, tourneyTypeId, + card1Value, card1Suit, card2Value, card2Suit, card3Value, card3Suit, card4Value, card4Suit, winnings, rake, seatNo, totalProfit, street0VPI, street0Aggr, street0_3BChance, street0_3BDone, street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, @@ -1546,12 +1567,15 @@ VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, foldToStreet1CBChance, foldToStreet1CBDone, foldToStreet2CBChance, foldToStreet2CBDone, foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone, street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone, - street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone + street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone, + street0Calls, street1Calls, street2Calls, street3Calls, street4Calls, + street0Bets, street1Bets, street2Bets, street3Bets, street4Bets ) -VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, +VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", - (hands_id, player_ids[i], start_cashes[i], positions[i], len(player_ids), 1, # tourneytypeid + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s)""", + (hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1], card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3], winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i], @@ -1576,7 +1600,9 @@ VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i], hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i], - hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i] + hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i], + hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i], + hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i] ) ) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) #result.append(cursor.fetchall()[0][0]) @@ -1705,6 +1731,41 @@ sure to also change the following storage method and table_viewer.prepare_data i stealAttempted=[] hudDataPositions=[] + street0Calls=[] + street1Calls=[] + street2Calls=[] + street3Calls=[] + street4Calls=[] + street0Bets=[] + street1Bets=[] + street2Bets=[] + street3Bets=[] + street4Bets=[] + #street0Raises=[] + #street1Raises=[] + #street2Raises=[] + #street3Raises=[] + #street4Raises=[] + + # Summary figures for hand table: + result={} + result['playersVpi']=0 + result['playersAtStreet1']=0 + result['playersAtStreet2']=0 + result['playersAtStreet3']=0 + result['playersAtStreet4']=0 + result['playersAtShowdown']=0 + result['street0Raises']=0 + result['street1Raises']=0 + result['street2Raises']=0 + result['street3Raises']=0 + result['street4Raises']=0 + result['street1Pot']=0 + result['street2Pot']=0 + result['street3Pot']=0 + result['street4Pot']=0 + result['showdownPot']=0 + firstPfRaiseByNo=-1 firstPfRaiserId=-1 firstPfRaiserNo=-1 @@ -1776,6 +1837,21 @@ sure to also change the following storage method and table_viewer.prepare_data i myWonAtSD=0.0 myStealAttemptChance=False myStealAttempted=False + myStreet0Calls=0 + myStreet1Calls=0 + myStreet2Calls=0 + myStreet3Calls=0 + myStreet4Calls=0 + myStreet0Bets=0 + myStreet1Bets=0 + myStreet2Bets=0 + myStreet3Bets=0 + myStreet4Bets=0 + #myStreet0Raises=0 + #myStreet1Raises=0 + #myStreet2Raises=0 + #myStreet3Raises=0 + #myStreet4Raises=0 #calculate VPIP and PFR street=0 @@ -1785,6 +1861,13 @@ sure to also change the following storage method and table_viewer.prepare_data i myStreet0Aggr = True if currentAction == "bet" or currentAction == "call": myStreet0VPI = True + + if myStreet0VPI: + result['playersVpi'] += 1 + myStreet0Calls = action_types[street][player].count('call') + myStreet0Bets = action_types[street][player].count('bet') + # street0Raises = action_types[street][player].count('raise') bet count includes raises for now + result['street0Raises'] += myStreet0Bets #PF3BChance and PF3B pfFold=-1 @@ -1865,7 +1948,17 @@ sure to also change the following storage method and table_viewer.prepare_data i mySawShowdown = True if any(actiontype == "fold" for actiontype in action_types[4][player]): mySawShowdown = False - + + if myStreet1Seen: + result['playersAtStreet1'] += 1 + if myStreet2Seen: + result['playersAtStreet2'] += 1 + if myStreet3Seen: + result['playersAtStreet3'] += 1 + if myStreet4Seen: + result['playersAtStreet4'] += 1 + if mySawShowdown: + result['playersAtShowdown'] += 1 #flop stuff street=1 @@ -1873,6 +1966,11 @@ sure to also change the following storage method and table_viewer.prepare_data i if any(actiontype == "bet" for actiontype in action_types[street][player]): myStreet1Aggr = True + myStreet1Calls = action_types[street][player].count('call') + myStreet1Bets = action_types[street][player].count('bet') + # street1Raises = action_types[street][player].count('raise') bet count includes raises for now + result['street1Raises'] += myStreet1Bets + for otherPlayer in xrange(len(player_ids)): if player==otherPlayer: pass @@ -1890,6 +1988,11 @@ sure to also change the following storage method and table_viewer.prepare_data i if any(actiontype == "bet" for actiontype in action_types[street][player]): myStreet2Aggr = True + myStreet2Calls = action_types[street][player].count('call') + myStreet2Bets = action_types[street][player].count('bet') + # street2Raises = action_types[street][player].count('raise') bet count includes raises for now + result['street2Raises'] += myStreet2Bets + for otherPlayer in xrange(len(player_ids)): if player==otherPlayer: pass @@ -1907,6 +2010,11 @@ sure to also change the following storage method and table_viewer.prepare_data i if any(actiontype == "bet" for actiontype in action_types[street][player]): myStreet3Aggr = True + myStreet3Calls = action_types[street][player].count('call') + myStreet3Bets = action_types[street][player].count('bet') + # street3Raises = action_types[street][player].count('raise') bet count includes raises for now + result['street3Raises'] += myStreet3Bets + for otherPlayer in xrange(len(player_ids)): if player==otherPlayer: pass @@ -1924,6 +2032,11 @@ sure to also change the following storage method and table_viewer.prepare_data i if any(actiontype == "bet" for actiontype in action_types[street][player]): myStreet4Aggr=True + myStreet4Calls = action_types[street][player].count('call') + myStreet4Bets = action_types[street][player].count('bet') + # street4Raises = action_types[street][player].count('raise') bet count includes raises for now + result['street4Raises'] += myStreet4Bets + for otherPlayer in xrange(len(player_ids)): if player==otherPlayer: pass @@ -1989,9 +2102,25 @@ sure to also change the following storage method and table_viewer.prepare_data i elif base=="stud": #todo: stud positions and steals pass + + street0Calls.append(myStreet0Calls) + street1Calls.append(myStreet1Calls) + street2Calls.append(myStreet2Calls) + street3Calls.append(myStreet3Calls) + street4Calls.append(myStreet4Calls) + street0Bets.append(myStreet0Bets) + street1Bets.append(myStreet1Bets) + street2Bets.append(myStreet2Bets) + street3Bets.append(myStreet3Bets) + street4Bets.append(myStreet4Bets) + #street0Raises.append(myStreet0Raises) + #street1Raises.append(myStreet1Raises) + #street2Raises.append(myStreet2Raises) + #street3Raises.append(myStreet3Raises) + #street4Raises.append(myStreet4Raises) #add each array to the to-be-returned dictionary - result={'street0VPI':street0VPI} + result['street0VPI']=street0VPI result['street0Aggr']=street0Aggr result['street0_3BChance']=street0_3BChance result['street0_3BDone']=street0_3BDone @@ -2017,6 +2146,21 @@ sure to also change the following storage method and table_viewer.prepare_data i result['wonAtSD']=wonAtSD result['stealAttemptChance']=stealAttemptChance result['stealAttempted']=stealAttempted + result['street0Calls']=street0Calls + result['street1Calls']=street1Calls + result['street2Calls']=street2Calls + result['street3Calls']=street3Calls + result['street4Calls']=street4Calls + result['street0Bets']=street0Bets + result['street1Bets']=street1Bets + result['street2Bets']=street2Bets + result['street3Bets']=street3Bets + result['street4Bets']=street4Bets + #result['street0Raises']=street0Raises + #result['street1Raises']=street1Raises + #result['street2Raises']=street2Raises + #result['street3Raises']=street3Raises + #result['street4Raises']=street4Raises #now the various steal values foldBbToStealChance=[]