From ef9abd29480ccb32ca70410d410e477d373e3aac Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 24 Nov 2009 11:21:55 +0800 Subject: [PATCH 01/15] Force all output from HHCs to by utf8 --- pyfpdb/HandHistoryConverter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index a662ca79..804b3534 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -94,7 +94,7 @@ follow : whether to tail -f the input""" else: log.info("Created directory '%s'" % out_dir) try: - self.out_fh = codecs.open(self.out_path, 'w', 'cp1252') + self.out_fh = codecs.open(self.out_path, 'w', 'utf8') except: log.error("out_path %s couldn't be opened" % (self.out_path)) else: From d617f1c4e005ce2dde00fd0c2796a642d7746537 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 24 Nov 2009 16:39:59 +0800 Subject: [PATCH 02/15] [NEWIMPORT] Update Database.storeHandsPlayers --- pyfpdb/Database.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index dbd7afe1..1dddafb2 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1343,7 +1343,9 @@ class Database: q = q.replace('%s', self.sql.query['placeholder']) - self.cursor.execute(q, ( + c = self.connection.cursor() + + c.execute(q, ( p['tableName'], p['gameTypeId'], p['siteHandNo'], @@ -1374,7 +1376,7 @@ class Database: p['street4Pot'], p['showdownPot'] )) - return self.get_last_insert_id(self.cursor) + return self.get_last_insert_id(c) # def storeHand def storeHandsPlayers(self, hid, pids, pdata): @@ -1393,6 +1395,7 @@ class Database: pdata[p]['card6'], pdata[p]['card7'], pdata[p]['winnings'], + pdata[p]['rake'], pdata[p]['street0VPI'], pdata[p]['street1Seen'], pdata[p]['street2Seen'], @@ -1418,6 +1421,7 @@ class Database: card6, card7, winnings, + rake, street0VPI, street1Seen, street2Seen, @@ -1430,7 +1434,7 @@ class Database: street4Aggr ) VALUES ( - %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, @@ -1440,11 +1444,11 @@ class Database: # position, # tourneyTypeId, # startCards, -# rake, # totalProfit, # street0_3BChance, # street0_3BDone, # sawShowdown, +# wonAtSD, # otherRaisedStreet1, # otherRaisedStreet2, # otherRaisedStreet3, @@ -1454,7 +1458,6 @@ class Database: # foldToOtherRaisedStreet3, # foldToOtherRaisedStreet4, # wonWhenSeenStreet1, -# wonAtSD, # stealAttemptChance, # stealAttempted, # foldBbToStealChance, @@ -1499,7 +1502,9 @@ class Database: q = q.replace('%s', self.sql.query['placeholder']) #print "DEBUG: inserts: %s" %inserts - self.cursor.executemany(q, inserts) + #print "DEBUG: q: %s" % q + c = self.connection.cursor() + c.executemany(q, inserts) def storeHudCacheNew(self, gid, pid, hc): q = """INSERT INTO HudCache ( From d65ee55b64f23e03aabe124208d6d12c08ad719c Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 24 Nov 2009 16:44:46 +0800 Subject: [PATCH 03/15] [NEWIMPORT] Calculate rake, make card calculation holdem only Stud card fetching still terminally broken --- pyfpdb/DerivedStats.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index e4d59336..2d9869ea 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -39,6 +39,7 @@ class DerivedStats(): #Init vars that may not be used, but still need to be inserted. # All stud street4 need this when importing holdem self.handsplayers[player[1]]['winnings'] = 0 + self.handsplayers[player[1]]['rake'] = 0 self.handsplayers[player[1]]['street4Seen'] = False self.handsplayers[player[1]]['street4Aggr'] = False @@ -109,6 +110,11 @@ class DerivedStats(): # rake taken out. hand.collectees is Decimal, database requires cents for player in hand.collectees: self.handsplayers[player]['winnings'] = int(100 * hand.collectees[player]) + #FIXME: This is pretty dodgy, rake = hand.rake/#collectees + # You can really only pay rake when you collect money, but + # different sites calculate rake differently. + # Should be fine for split-pots, but won't be accurate for multi-way pots + self.handsplayers[player]['rake'] = int(100* hand.rake)/len(hand.collectees) for i, street in enumerate(hand.actionStreets[2:]): self.seen(self.hand, i+1) @@ -116,12 +122,20 @@ class DerivedStats(): for i, street in enumerate(hand.actionStreets[1:]): self.aggr(self.hand, i) - default_holecards = ["Xx", "Xx", "Xx", "Xx"] + #default_holecards = ["Xx", "Xx", "Xx", "Xx"] + #if hand.gametype['base'] == "hold": + # pass + #elif hand.gametype['base'] == "stud": + # pass + #else: + # # Flop hopefully... + # pass for street in hand.holeStreets: for player in hand.players: for i in range(1,8): self.handsplayers[player[1]]['card%d' % i] = 0 - if player[1] in hand.holecards[street].keys(): + #print "DEBUG: hand.holecards[%s]: %s" % (street, hand.holecards[street]) + if player[1] in hand.holecards[street].keys() and hand.gametype['base'] == "hold": self.handsplayers[player[1]]['card1'] = Card.encodeCard(hand.holecards[street][player[1]][1][0]) self.handsplayers[player[1]]['card2'] = Card.encodeCard(hand.holecards[street][player[1]][1][1]) try: From 48c395565ece9f8151c5f6c5621d6608c9386780 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 24 Nov 2009 17:29:54 +0800 Subject: [PATCH 04/15] [NEWIMPORT] Add HandsPlayers.totalProfit Grapher now works after import yay --- pyfpdb/Database.py | 5 +++-- pyfpdb/DerivedStats.py | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 1dddafb2..9134fc6a 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1396,6 +1396,7 @@ class Database: pdata[p]['card7'], pdata[p]['winnings'], pdata[p]['rake'], + pdata[p]['totalProfit'], pdata[p]['street0VPI'], pdata[p]['street1Seen'], pdata[p]['street2Seen'], @@ -1422,6 +1423,7 @@ class Database: card7, winnings, rake, + totalProfit, street0VPI, street1Seen, street2Seen, @@ -1434,7 +1436,7 @@ class Database: street4Aggr ) VALUES ( - %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, @@ -1444,7 +1446,6 @@ class Database: # position, # tourneyTypeId, # startCards, -# totalProfit, # street0_3BChance, # street0_3BDone, # sawShowdown, diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 2d9869ea..1cb39a07 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -40,6 +40,7 @@ class DerivedStats(): # All stud street4 need this when importing holdem self.handsplayers[player[1]]['winnings'] = 0 self.handsplayers[player[1]]['rake'] = 0 + self.handsplayers[player[1]]['totalProfit'] = 0 self.handsplayers[player[1]]['street4Seen'] = False self.handsplayers[player[1]]['street4Aggr'] = False @@ -96,9 +97,6 @@ class DerivedStats(): #print "DEBUG: playersAtStreet 1:'%s' 2:'%s' 3:'%s' 4:'%s'" %(self.hands['playersAtStreet1'],self.hands['playersAtStreet2'],self.hands['playersAtStreet3'],self.hands['playersAtStreet4']) self.streetXRaises(hand) # Empty function currently - # comment TEXT, - # commentTs DATETIME - def assembleHandsPlayers(self, hand): #street0VPI/vpip already called in Hand #hand.players = [[seat, name, chips],[seat, name, chips]] @@ -116,6 +114,9 @@ class DerivedStats(): # Should be fine for split-pots, but won't be accurate for multi-way pots self.handsplayers[player]['rake'] = int(100* hand.rake)/len(hand.collectees) + for player in hand.pot.committed: + self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player])) + for i, street in enumerate(hand.actionStreets[2:]): self.seen(self.hand, i+1) From e9a858e4cdc04bc2469c2e688a367d1de8f50c5a Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 24 Nov 2009 17:55:00 +0800 Subject: [PATCH 05/15] Make DEBUG = False in DerivedStats --- pyfpdb/DerivedStats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 1cb39a07..4366d067 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -18,7 +18,7 @@ #fpdb modules import Card -DEBUG = True +DEBUG = False if DEBUG: import pprint From dc1b0d2e38df78a5e5ee0ddae8c4863525ab3ddc Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 24 Nov 2009 21:58:27 +0800 Subject: [PATCH 06/15] [NEWIMPORT] Calculate wonWhenSeenStreet1 Won is defined as 'collected money from the pot' Seen street 1 does not require vpip on street 0 --- pyfpdb/Database.py | 9 +++++---- pyfpdb/DerivedStats.py | 14 +++++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 9134fc6a..ed987d81 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1406,7 +1406,8 @@ class Database: pdata[p]['street1Aggr'], pdata[p]['street2Aggr'], pdata[p]['street3Aggr'], - pdata[p]['street4Aggr'] + pdata[p]['street4Aggr'], + pdata[p]['wonWhenSeenStreet1'] ) ) q = """INSERT INTO HandsPlayers ( @@ -1433,10 +1434,11 @@ class Database: street1Aggr, street2Aggr, street3Aggr, - street4Aggr + street4Aggr, + wonWhenSeenStreet1 ) 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, @@ -1458,7 +1460,6 @@ class Database: # foldToOtherRaisedStreet2, # foldToOtherRaisedStreet3, # foldToOtherRaisedStreet4, -# wonWhenSeenStreet1, # stealAttemptChance, # stealAttempted, # foldBbToStealChance, diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 4366d067..c6b3fc64 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -43,6 +43,7 @@ class DerivedStats(): self.handsplayers[player[1]]['totalProfit'] = 0 self.handsplayers[player[1]]['street4Seen'] = False self.handsplayers[player[1]]['street4Aggr'] = False + self.handsplayers[player[1]]['wonWhenSeenStreet1'] = False self.assembleHands(self.hand) self.assembleHandsPlayers(self.hand) @@ -104,6 +105,12 @@ class DerivedStats(): self.handsplayers[player[1]]['seatNo'] = player[0] self.handsplayers[player[1]]['startCash'] = player[2] + for i, street in enumerate(hand.actionStreets[2:]): + self.seen(self.hand, i+1) + + for i, street in enumerate(hand.actionStreets[1:]): + self.aggr(self.hand, i) + # Winnings is a non-negative value of money collected from the pot, which already includes the # rake taken out. hand.collectees is Decimal, database requires cents for player in hand.collectees: @@ -113,15 +120,12 @@ class DerivedStats(): # different sites calculate rake differently. # Should be fine for split-pots, but won't be accurate for multi-way pots self.handsplayers[player]['rake'] = int(100* hand.rake)/len(hand.collectees) + if self.handsplayers[player]['street1Seen'] == True: + self.handsplayers[player]['wonWhenSeenStreet1'] = True for player in hand.pot.committed: self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player])) - for i, street in enumerate(hand.actionStreets[2:]): - self.seen(self.hand, i+1) - - for i, street in enumerate(hand.actionStreets[1:]): - self.aggr(self.hand, i) #default_holecards = ["Xx", "Xx", "Xx", "Xx"] #if hand.gametype['base'] == "hold": From 9203e0b0d8418cd33000662c2beab9520d754cce Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 24 Nov 2009 23:14:43 +0800 Subject: [PATCH 07/15] [NEWIMPORT] HandsPlayers.sawShowdown added --- pyfpdb/Database.py | 4 +++- pyfpdb/DerivedStats.py | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index ed987d81..42fee82b 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1402,6 +1402,7 @@ class Database: pdata[p]['street2Seen'], pdata[p]['street3Seen'], pdata[p]['street4Seen'], + pdata[p]['sawShowdown'], pdata[p]['street0Aggr'], pdata[p]['street1Aggr'], pdata[p]['street2Aggr'], @@ -1430,6 +1431,7 @@ class Database: street2Seen, street3Seen, street4Seen, + sawShowdown, street0Aggr, street1Aggr, street2Aggr, @@ -1438,6 +1440,7 @@ class Database: wonWhenSeenStreet1 ) VALUES ( + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, @@ -1450,7 +1453,6 @@ class Database: # startCards, # street0_3BChance, # street0_3BDone, -# sawShowdown, # wonAtSD, # otherRaisedStreet1, # otherRaisedStreet2, diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index c6b3fc64..3214cbbb 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -44,6 +44,7 @@ class DerivedStats(): self.handsplayers[player[1]]['street4Seen'] = False self.handsplayers[player[1]]['street4Aggr'] = False self.handsplayers[player[1]]['wonWhenSeenStreet1'] = False + self.handsplayers[player[1]]['sawShowdown'] = False self.assembleHands(self.hand) self.assembleHandsPlayers(self.hand) @@ -100,6 +101,8 @@ class DerivedStats(): def assembleHandsPlayers(self, hand): #street0VPI/vpip already called in Hand + # sawShowdown is calculated in playersAtStreetX, as that calculation gives us a convenient list of names + #hand.players = [[seat, name, chips],[seat, name, chips]] for player in hand.players: self.handsplayers[player[1]]['seatNo'] = player[0] @@ -193,7 +196,11 @@ class DerivedStats(): self.hands['playersAtStreet%d' % (i+1)] = len(set.union(alliners, actors)) actions = hand.actions[hand.actionStreets[-1]] - self.hands['playersAtShowdown'] = len(set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners)) + pas = set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners) + self.hands['playersAtShowdown'] = len(pas) + + for player in pas: + self.handsplayers[player]['sawShowdown'] = True def streetXRaises(self, hand): # self.actions[street] is a list of all actions in a tuple, contining the action as the second element From 3bb1656603759513185e9e8f7e4d49fb842a7c65 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 24 Nov 2009 23:23:21 +0800 Subject: [PATCH 08/15] [NEWIMPORT] Add HandsPlayers.wonAtSD --- pyfpdb/Database.py | 5 +++-- pyfpdb/DerivedStats.py | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 42fee82b..9bfe9dd6 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1403,6 +1403,7 @@ class Database: pdata[p]['street3Seen'], pdata[p]['street4Seen'], pdata[p]['sawShowdown'], + pdata[p]['wonAtSD'], pdata[p]['street0Aggr'], pdata[p]['street1Aggr'], pdata[p]['street2Aggr'], @@ -1432,6 +1433,7 @@ class Database: street3Seen, street4Seen, sawShowdown, + wonAtSD, street0Aggr, street1Aggr, street2Aggr, @@ -1440,7 +1442,7 @@ class Database: wonWhenSeenStreet1 ) VALUES ( - %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, @@ -1453,7 +1455,6 @@ class Database: # startCards, # street0_3BChance, # street0_3BDone, -# wonAtSD, # otherRaisedStreet1, # otherRaisedStreet2, # otherRaisedStreet3, diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 3214cbbb..fabadb3b 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -45,6 +45,7 @@ class DerivedStats(): self.handsplayers[player[1]]['street4Aggr'] = False self.handsplayers[player[1]]['wonWhenSeenStreet1'] = False self.handsplayers[player[1]]['sawShowdown'] = False + self.handsplayers[player[1]]['wonAtSD'] = False self.assembleHands(self.hand) self.assembleHandsPlayers(self.hand) @@ -125,6 +126,8 @@ class DerivedStats(): self.handsplayers[player]['rake'] = int(100* hand.rake)/len(hand.collectees) if self.handsplayers[player]['street1Seen'] == True: self.handsplayers[player]['wonWhenSeenStreet1'] = True + if self.handsplayers[player]['sawShowdown'] == True: + self.handsplayers[player]['wonAtSD'] = True for player in hand.pot.committed: self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player])) From a87a145c28031d517b74b98162129619dffe1432 Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 25 Nov 2009 00:57:14 +0800 Subject: [PATCH 09/15] [NEWIMPORT] HandsPlayers.streetXCalls and streetXBets Pretty sure the bets stat is wrong --- pyfpdb/Database.py | 36 ++++++++++++++++++++++++------------ pyfpdb/DerivedStats.py | 20 +++++++++++++++++++- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 9bfe9dd6..9f214aeb 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1409,7 +1409,17 @@ class Database: pdata[p]['street2Aggr'], pdata[p]['street3Aggr'], pdata[p]['street4Aggr'], - pdata[p]['wonWhenSeenStreet1'] + pdata[p]['wonWhenSeenStreet1'], + pdata[p]['street0Calls'], + pdata[p]['street1Calls'], + pdata[p]['street2Calls'], + pdata[p]['street3Calls'], + pdata[p]['street4Calls'], + pdata[p]['street0Bets'], + pdata[p]['street1Bets'], + pdata[p]['street2Bets'], + pdata[p]['street3Bets'], + pdata[p]['street4Bets'], ) ) q = """INSERT INTO HandsPlayers ( @@ -1439,7 +1449,17 @@ class Database: street2Aggr, street3Aggr, street4Aggr, - wonWhenSeenStreet1 + wonWhenSeenStreet1, + street0Calls, + street1Calls, + street2Calls, + street3Calls, + street4Calls, + street0Bets, + street1Bets, + street2Bets, + street3Bets, + street4Bets ) VALUES ( %s, %s, @@ -1447,6 +1467,8 @@ class Database: %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )""" @@ -1493,16 +1515,6 @@ class Database: # street3CheckCallRaiseDone, # street4CheckCallRaiseChance, # street4CheckCallRaiseDone, -# street0Calls, -# street1Calls, -# street2Calls, -# street3Calls, -# street4Calls, -# street0Bets, -# street1Bets, -# street2Bets, -# street3Bets, -# street4Bets q = q.replace('%s', self.sql.query['placeholder']) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index fabadb3b..3da670cc 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -46,6 +46,9 @@ class DerivedStats(): self.handsplayers[player[1]]['wonWhenSeenStreet1'] = False self.handsplayers[player[1]]['sawShowdown'] = False self.handsplayers[player[1]]['wonAtSD'] = False + for i in range(5): + self.handsplayers[player[1]]['street%dCalls' % i] = 0 + self.handsplayers[player[1]]['street%dBets' % i] = 0 self.assembleHands(self.hand) self.assembleHandsPlayers(self.hand) @@ -114,6 +117,8 @@ class DerivedStats(): for i, street in enumerate(hand.actionStreets[1:]): self.aggr(self.hand, i) + self.calls(self.hand, i) + self.bets(self.hand, i) # Winnings is a non-negative value of money collected from the pot, which already includes the # rake taken out. hand.collectees is Decimal, database requires cents @@ -132,7 +137,6 @@ class DerivedStats(): for player in hand.pot.committed: self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player])) - #default_holecards = ["Xx", "Xx", "Xx", "Xx"] #if hand.gametype['base'] == "hold": # pass @@ -240,6 +244,20 @@ class DerivedStats(): else: self.handsplayers[player[1]]['street%sAggr' % i] = False + def calls(self, hand, i): + callers = [] + for act in hand.actions[hand.actionStreets[i+1]]: + if act[1] in ('calls'): + self.handsplayers[act[0]]['street%sCalls' % i] = 1 + self.handsplayers[act[0]]['street%sCalls' % i] + + # CG - I'm sure this stat is wrong + # Best guess is that raise = 2 bets + def bets(self, hand, i): + betters = [] + for act in hand.actions[hand.actionStreets[i+1]]: + if act[1] in ('bets'): + self.handsplayers[act[0]]['street%sBets' % i] = 1 + self.handsplayers[act[0]]['street%sBets' % i] + def countPlayers(self, hand): pass From c856824145c4b7d0806490299312687dc0fc3146 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 24 Nov 2009 19:46:57 +0000 Subject: [PATCH 10/15] fix bug in save() and simplify it. Add get_doc() method --- pyfpdb/Configuration.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 3fa5cc1d..d2894f6e 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -516,6 +516,9 @@ class Config: file = None return file + def get_doc(self): + return self.doc + def get_site_node(self, site): for site_node in self.doc.getElementsByTagName("site"): if site_node.getAttribute("site_name") == site: @@ -550,11 +553,9 @@ class Config: return location_node def save(self, file = None): - if file is not None: - with open(file, 'w') as f: - self.doc.writexml(f) - else: - shutil.move(self.file, self.file+".backup") + if file is None: + file = self.file + shutil.move(file, file+".backup") with open(file, 'w') as f: self.doc.writexml(f) From 02fd6d6bd0f05718dd02d55da450e7abafd7b4de Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 24 Nov 2009 19:50:48 +0000 Subject: [PATCH 11/15] add Preferences option on File menu --- pyfpdb/GuiPrefs.py | 169 +++++++++++++++++++++++++++++++++++++++++++++ pyfpdb/fpdb.py | 17 +++++ 2 files changed, 186 insertions(+) create mode 100755 pyfpdb/GuiPrefs.py diff --git a/pyfpdb/GuiPrefs.py b/pyfpdb/GuiPrefs.py new file mode 100755 index 00000000..18ffaeef --- /dev/null +++ b/pyfpdb/GuiPrefs.py @@ -0,0 +1,169 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +#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. + + +import xml.dom.minidom +from xml.dom.minidom import Node + +import pygtk +pygtk.require('2.0') +import gtk +import gobject + +import Configuration + + +class GuiPrefs: + + def __init__(self, config, mainwin, dia): + self.config = config + self.main_window = mainwin + self.dialog = dia + + self.tree_box = gtk.ScrolledWindow() + self.tree_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + + self.dialog.add(self.tree_box) + self.dialog.show() + + self.doc = None + self.configStore = None + self.configView = None + + self.fillFrames() + + def fillFrames(self): + self.doc = self.config.get_doc() + + self.configStore = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING) + self.configView = gtk.TreeView(self.configStore) + self.configView.set_enable_tree_lines(True) + + configColumn = gtk.TreeViewColumn("Setting") + self.configView.append_column(configColumn) + cRender = gtk.CellRendererText() + configColumn.pack_start(cRender, True) + configColumn.add_attribute(cRender, 'text', 1) + + configColumn = gtk.TreeViewColumn("Value") + self.configView.append_column(configColumn) + cRender = gtk.CellRendererText() + configColumn.pack_start(cRender, True) + configColumn.add_attribute(cRender, 'text', 2) + + if self.doc.documentElement.tagName == 'FreePokerToolsConfig': + self.configStore.clear() + self.root = self.configStore.append( None, [self.doc.documentElement, "fpdb", None] ) + for elem in self.doc.documentElement.childNodes: + iter = self.addTreeRows(self.root, elem) + if self.root != None: + self.configView.expand_row(self.configStore.get_path(self.root), False) + self.configView.connect("row-activated", self.rowChosen) + self.configView.show() + self.tree_box.add(self.configView) + self.tree_box.show() + self.dialog.show() + + def addTreeRows(self, parent, node): + if (node.nodeType == node.ELEMENT_NODE): + (setting, value) = (node.nodeName, None) + elif (node.nodeType == node.TEXT_NODE): + # text nodes hold the whitespace (or whatever) between the xml elements, not used here + (setting, value) = ("TEXT: ["+node.nodeValue+"|"+node.nodeValue+"]", node.data) + else: + (setting, value) = ("?? "+node.nodeValue, "type="+str(node.nodeType)) + + #iter = self.configStore.append( parent, [node.nodeValue, None] ) + iter = None + if node.nodeType != node.TEXT_NODE: + iter = self.configStore.append( parent, [node, setting, value] ) + if node.hasAttributes(): + for i in xrange(node.attributes.length): + self.configStore.append( iter, [node, node.attributes.item(i).localName, node.attributes.item(i).value] ) + if node.hasChildNodes(): + for elem in node.childNodes: + self.addTreeRows(iter, elem) + return iter + + def rowChosen(self, tview, path, something2, data=None): + # tview should= self.configStore + tmodel = tview.get_model() + iter = tmodel.get_iter(path) + if tmodel.iter_has_child(iter): + # toggle children display + if tview.row_expanded(path): + tview.collapse_row(tmodel.get_path(iter)) + else: + tview.expand_row(tmodel.get_path(iter), False) + else: + # display value and allow edit + name = tmodel.get_value( iter, 1 ) + val = tmodel.get_value( iter, 2 ) + dia_edit = gtk.Dialog(name, + self.main_window, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) + #dia_edit.set_default_size(350, 100) + entry = gtk.Entry() + if val: + entry.set_text(val) + entry.set_width_chars(40) + dia_edit.vbox.pack_start(entry, False, False, 0) + entry.show() + entry.connect("activate", self.__set_entry, dia_edit) + response = dia_edit.run() + if response == gtk.RESPONSE_ACCEPT: + # update configStore + new_val = entry.get_text() + tmodel.set_value(iter, 2, new_val) + tmodel.get_value(iter, 0).setAttribute(name, new_val) + dia_edit.destroy() + + def __set_entry(self, w, dia=None): + if dia is not None: + dia.response(gtk.RESPONSE_ACCEPT) + + + +if __name__=="__main__": + + config = Configuration.Config() + + win = gtk.Window(gtk.WINDOW_TOPLEVEL) + win.set_title("Test Preferences Dialog") + win.set_border_width(1) + win.set_default_size(600, 500) + win.set_resizable(True) + + dia = gtk.Dialog("Preferences", + win, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) + dia.set_default_size(500, 500) + prefs = GuiPrefs(config, win, dia.vbox) + response = dia.run() + if response == gtk.RESPONSE_ACCEPT: + # save updated config + config.save() + dia.destroy() + + + + diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 97cf8cf5..ff754520 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -69,6 +69,7 @@ import gtk import interlocks +import GuiPrefs import GuiBulkImport import GuiPlayerStats import GuiPositionalStats @@ -146,6 +147,20 @@ class fpdb: dia.run() dia.destroy() + def dia_preferences(self, widget, data=None): + dia = gtk.Dialog("Preferences", + self.window, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) + dia.set_default_size(500, 500) + prefs = GuiPrefs.GuiPrefs(self.config, self.window, dia.vbox) + response = dia.run() + if response == gtk.RESPONSE_ACCEPT: + # save updated config + self.config.save() + dia.destroy() + def dia_create_del_database(self, widget, data=None): self.warning_box("Unimplemented: Create/Delete Database") self.obtain_global_lock() @@ -350,6 +365,7 @@ class fpdb: + @@ -396,6 +412,7 @@ class fpdb: ('LoadProf', None, '_Load Profile (broken)', 'L', 'Load your profile', self.dia_load_profile), ('EditProf', None, '_Edit Profile (todo)', 'E', 'Edit your profile', self.dia_edit_profile), ('SaveProf', None, '_Save Profile (todo)', 'S', 'Save your profile', self.dia_save_profile), + ('Preferences', None, '_Preferences', None, 'Edit your preferences', self.dia_preferences), ('import', None, '_Import'), ('sethharchive', None, '_Set HandHistory Archive Directory', None, 'Set HandHistory Archive Directory', self.select_hhArchiveBase), ('bulkimp', None, '_Bulk Import', 'B', 'Bulk Import', self.tab_bulk_import), From 1b2a45b77e28db655fbacef491f4b361c3c516a1 Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 25 Nov 2009 09:06:01 +0800 Subject: [PATCH 12/15] Prefs: Fix display when a comment node exists in config --- pyfpdb/GuiPrefs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/GuiPrefs.py b/pyfpdb/GuiPrefs.py index 18ffaeef..ada9cb51 100755 --- a/pyfpdb/GuiPrefs.py +++ b/pyfpdb/GuiPrefs.py @@ -90,7 +90,7 @@ class GuiPrefs: #iter = self.configStore.append( parent, [node.nodeValue, None] ) iter = None - if node.nodeType != node.TEXT_NODE: + if node.nodeType != node.TEXT_NODE and node.nodeType != node.COMMENT_NODE: iter = self.configStore.append( parent, [node, setting, value] ) if node.hasAttributes(): for i in xrange(node.attributes.length): From 30332d213265602db8004016c17eb3b0d193aec4 Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 25 Nov 2009 10:27:54 +0800 Subject: [PATCH 13/15] Remove forced assert --- pyfpdb/test_Database.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyfpdb/test_Database.py b/pyfpdb/test_Database.py index b348f741..25bd6dbc 100644 --- a/pyfpdb/test_Database.py +++ b/pyfpdb/test_Database.py @@ -64,5 +64,4 @@ def testSQLiteModFunction(): assert vars[idx]%13 == int(i[0]) idx = idx+1 - assert 0 == 1 cur.execute("DROP TABLE test") From 83f06c35cc5005c3fd2fefb601ab7abb66789044 Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 25 Nov 2009 14:59:29 +0800 Subject: [PATCH 14/15] [NEWIMPORT] HandsPlayers.CBet stats --- pyfpdb/Database.py | 27 ++++++++++++++-------- pyfpdb/DerivedStats.py | 52 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 9f214aeb..fde03b71 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1409,6 +1409,14 @@ class Database: pdata[p]['street2Aggr'], pdata[p]['street3Aggr'], pdata[p]['street4Aggr'], + pdata[p]['street1CBChance'], + pdata[p]['street2CBChance'], + pdata[p]['street3CBChance'], + pdata[p]['street4CBChance'], + pdata[p]['street1CBDone'], + pdata[p]['street2CBDone'], + pdata[p]['street3CBDone'], + pdata[p]['street4CBDone'], pdata[p]['wonWhenSeenStreet1'], pdata[p]['street0Calls'], pdata[p]['street1Calls'], @@ -1449,6 +1457,14 @@ class Database: street2Aggr, street3Aggr, street4Aggr, + street1CBChance, + street2CBChance, + street3CBChance, + street4CBChance, + street1CBDone, + street2CBDone, + street3CBDone, + street4CBDone, wonWhenSeenStreet1, street0Calls, street1Calls, @@ -1462,7 +1478,8 @@ class Database: street4Bets ) VALUES ( - %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, @@ -1491,14 +1508,6 @@ class Database: # foldedBbToSteal, # foldSbToStealChance, # foldedSbToSteal, -# street1CBChance, -# street1CBDone, -# street2CBChance, -# street2CBDone, -# street3CBChance, -# street3CBDone, -# street4CBChance, -# street4CBDone, # foldToStreet1CBChance, # foldToStreet1CBDone, # foldToStreet2CBChance, diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 3da670cc..c5575ddc 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -49,10 +49,14 @@ class DerivedStats(): for i in range(5): self.handsplayers[player[1]]['street%dCalls' % i] = 0 self.handsplayers[player[1]]['street%dBets' % i] = 0 + for i in range(1,5): + self.handsplayers[player[1]]['street%dCBChance' %i] = False + self.handsplayers[player[1]]['street%dCBDone' %i] = False self.assembleHands(self.hand) self.assembleHandsPlayers(self.hand) + if DEBUG: print "Hands:" pp.pprint(self.hands) @@ -137,6 +141,8 @@ class DerivedStats(): for player in hand.pot.committed: self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player])) + self.calcCBets(hand) + #default_holecards = ["Xx", "Xx", "Xx", "Xx"] #if hand.gametype['base'] == "hold": # pass @@ -221,6 +227,20 @@ class DerivedStats(): for (i, street) in enumerate(hand.actionStreets[1:]): self.hands['street%dRaises' % i] = len(filter( lambda action: action[1] in ('raises','bets'), hand.actions[street])) + def calcCBets(self, hand): + # Continuation Bet chance, action: + # Had the last bet (initiative) on previous street, got called, close street action + # Then no bets before the player with initiatives first action on current street + # ie. if player on street-1 had initiative + # and no donkbets occurred + for i, street in enumerate(hand.actionStreets[2:], start=1): + name = self.lastBetOrRaiser(hand.actionStreets[i]) + if name: + chance = self.noBetsBefore(hand.actionStreets[i+1], name) + self.handsplayers[name]['street%dCBChance' %i] = True + if chance == True: + self.handsplayers[name]['street%dCBDone' %i] = self.betStreet(hand.actionStreets[i+1], name) + def seen(self, hand, i): pas = set() for act in hand.actions[hand.actionStreets[i+1]]: @@ -273,3 +293,35 @@ class DerivedStats(): if f is not None and action[1] in f: continue players.add(action[0]) return players + + def noBetsBefore(self, street, player): + """Returns true if there were no bets before the specified players turn, false otherwise""" + betOrRaise = False + for act in self.hand.actions[street]: + #Must test for player first in case UTG + if act[0] == player: + betOrRaise = True + break + if act[1] in ('bets', 'raises'): + break + return betOrRaise + + def betStreet(self, street, player): + """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: + break + return betOrRaise + + + def lastBetOrRaiser(self, street): + """Returns player name that placed the last bet or raise for that street. + None if there were no bets or raises on that street""" + lastbet = None + for act in self.hand.actions[street]: + if act[1] in ('bets', 'raises'): + lastbet = act[0] + return lastbet From aee9a7339c60d023d7f335fe935f021ca29da838 Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 25 Nov 2009 16:29:30 +0800 Subject: [PATCH 15/15] [NEWIMPORT] Stop duplicate hands from crashing import --- pyfpdb/Database.py | 16 ++++++++++++++++ pyfpdb/Hand.py | 30 +++++++++++++++--------------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index fde03b71..42cd986c 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1672,6 +1672,15 @@ class Database: # street4CheckCallRaiseChance, # street4CheckCallRaiseDone) + def isDuplicate(self, gametypeID, siteHandNo): + dup = False + c = self.get_cursor() + c.execute(self.sql.query['isAlreadyInDB'], (gametypeID, siteHandNo)) + result = c.fetchall() + if len(result) > 0: + dup = True + return dup + def getGameTypeId(self, siteid, game): c = self.get_cursor() #FIXME: Fixed for NL at the moment @@ -1711,6 +1720,13 @@ class Database: q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s" q = q.replace('%s', self.sql.query['placeholder']) + #NOTE/FIXME?: MySQL has ON DUPLICATE KEY UPDATE + #Usage: + # INSERT INTO `tags` (`tag`, `count`) + # VALUES ($tag, 1) + # ON DUPLICATE KEY UPDATE `count`=`count`+1; + + #print "DEBUG: name: %s site: %s" %(name, site_id) c.execute (q, (site_id, name)) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index a5ea87ec..f6fa478e 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -210,24 +210,24 @@ db: a connected fpdb_db object""" ##### # End prep functions ##### - - # HandsActions - all actions for all players for all streets - self.actions - # HudCache data can be generated from HandsActions (HandsPlayers?) - - # Hands - Summary information of hand indexed by handId - gameinfo hh = self.stats.getHands() - hh['gameTypeId'] = gtid - # seats TINYINT NOT NULL, - hh['seats'] = len(sqlids) - #print hh - handid = db.storeHand(hh) - # HandsPlayers - ? ... Do we fix winnings? - db.storeHandsPlayers(handid, sqlids, self.stats.getHandsPlayers()) - # Tourneys ? - # TourneysPlayers + if not db.isDuplicate(gtid, hh['siteHandNo']): + # Hands - Summary information of hand indexed by handId - gameinfo + hh['gameTypeId'] = gtid + # seats TINYINT NOT NULL, + hh['seats'] = len(sqlids) - pass + handid = db.storeHand(hh) + db.storeHandsPlayers(handid, sqlids, self.stats.getHandsPlayers()) + # HandsActions - all actions for all players for all streets - self.actions + # HudCache data can be generated from HandsActions (HandsPlayers?) + # Tourneys ? + # TourneysPlayers + else: + log.info("Hand.insert(): hid #: %s is a duplicate" % hh['siteHandNo']) + #Raise Duplicate exception? + pass def select(self, handId): """ Function to create Hand object from database """