Merge branch 'master' into good

Conflicts:
	pyfpdb/Configuration.py
	pyfpdb/HUD_config.xml.example
This commit is contained in:
Mika Bostrom 2009-10-15 09:06:31 +03:00
commit 019440a71b
22 changed files with 2587 additions and 692 deletions

View File

@ -6,7 +6,7 @@ Build-Depends: debhelper, python-support
Standards-Version: 3.8.0 Standards-Version: 3.8.0
Package: python-fpdb Package: python-fpdb
Architecture: any Architecture: all
Section: games Section: games
Priority: extra Priority: extra
Depends: ${python:Depends}, python-gtk2, python-matplotlib, Depends: ${python:Depends}, python-gtk2, python-matplotlib,

View File

@ -26,17 +26,17 @@ def twoStartCards(value1, suit1, value2, suit2):
if value1 < 2 or value2 < 2: if value1 < 2 or value2 < 2:
ret = 0 ret = 0
if value1 == value2: # pairs if value1 == value2: # pairs
ret = (13 * (value2-2) + (value2-1) ) ret = (13 * (value2-2) + (value2-2) )
elif suit1 == suit2: elif suit1 == suit2:
if value1 > value2: if value1 > value2:
ret = 13 * (value1-2) + (value2-1) ret = 13 * (value1-2) + (value2-2)
else: else:
ret = 13 * (value2-2) + (value1-1) ret = 13 * (value2-2) + (value1-2)
else: else:
if value1 > value2: if value1 > value2:
ret = 13 * (value2-2) + (value2-1) ret = 13 * (value2-2) + (value1-2)
else: else:
ret = 13 * (value1-2) + (value2-1) ret = 13 * (value1-2) + (value2-2)
# print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret # print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret
return ret return ret
@ -46,7 +46,6 @@ def twoStartCardString(card):
into a string like AQo """ into a string like AQo """
ret = 'xx' ret = 'xx'
if card > 0: if card > 0:
card -= 1
s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A') s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
x = card / 13 x = card / 13
y = card - 13 * x y = card - 13 * x

View File

@ -282,6 +282,19 @@ class HudUI:
def __init__(self, node): def __init__(self, node):
self.node = node self.node = node
self.label = node.getAttribute('label') self.label = node.getAttribute('label')
#
self.aggregate_ring = fix_tf(node.getAttribute('aggregate_ring_game_stats'))
self.aggregate_tour = fix_tf(node.getAttribute('aggregate_tourney_stats'))
self.hud_style = node.getAttribute('stat_aggregation_range')
self.hud_days = node.getAttribute('aggregation_days')
self.agg_bb_mult = node.getAttribute('aggregation_level_multiplier')
#
self.h_aggregate_ring = fix_tf(node.getAttribute('aggregate_hero_ring_game_stats'))
self.h_aggregate_tour = fix_tf(node.getAttribute('aggregate_hero_tourney_stats'))
self.h_hud_style = node.getAttribute('hero_stat_aggregation_range')
self.h_hud_days = node.getAttribute('hero_aggregation_days')
self.h_agg_bb_mult = node.getAttribute('hero_aggregation_level_multiplier')
def __str__(self): def __str__(self):
return " label = %s\n" % self.label return " label = %s\n" % self.label
@ -320,13 +333,21 @@ class Config:
pass pass
if file == None: # that didn't work either, just die if file == None: # that didn't work either, just die
print "No HUD_config_xml found. Exiting" print "No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting"
sys.stderr.write("No HUD_config_xml found. Exiting") sys.stderr.write("No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting")
print "press enter to continue"
sys.stdin.readline()
sys.exit() sys.exit()
# Parse even if there was no real config file found and we are using the example # Parse even if there was no real config file found and we are using the example
# If using the example, we'll edit it later # If using the example, we'll edit it later
# sc 2009/10/04 Example already copied to main filename, is this ok?
log.info("Reading configuration file %s" % file) log.info("Reading configuration file %s" % file)
if os.sep in file:
print "\nReading configuration file %s\n" % file
else:
print "\nReading configuration file %s" % file
print "in %s\n" % os.getcwd()
try: try:
doc = xml.dom.minidom.parse(file) doc = xml.dom.minidom.parse(file)
except: except:
@ -418,6 +439,8 @@ class Config:
db_pass = df_parms['db-password']) db_pass = df_parms['db-password'])
self.save(file=os.path.join(self.default_config_path, "HUD_config.xml")) self.save(file=os.path.join(self.default_config_path, "HUD_config.xml"))
print ""
def set_hhArchiveBase(self, path): def set_hhArchiveBase(self, path):
self.imp.node.setAttribute("hhArchiveBase", path) self.imp.node.setAttribute("hhArchiveBase", path)
@ -467,11 +490,15 @@ class Config:
def find_example_config(self): def find_example_config(self):
if os.path.exists('HUD_config.xml.example'): # there is a HUD_config in the cwd if os.path.exists('HUD_config.xml.example'): # there is a HUD_config in the cwd
file = 'HUD_config.xml.example' # so we use it file = 'HUD_config.xml' # so we use it
try:
shutil.copyfile(file+'.example', file)
except:
file = ''
print "No HUD_config.xml found, using HUD_config.xml.example.\n", \ print "No HUD_config.xml found, using HUD_config.xml.example.\n", \
"A HUD_config.xml will be written. You will probably have to edit it." "A HUD_config.xml has been created. You will probably have to edit it."
sys.stderr.write("No HUD_config.xml found, using HUD_config.xml.example.\n" + \ sys.stderr.write("No HUD_config.xml found, using HUD_config.xml.example.\n" + \
"A HUD_config.xml will be written. You will probably have to edit it.") "A HUD_config.xml has been created. You will probably have to edit it.")
else: else:
file = None file = None
return file return file
@ -615,6 +642,7 @@ class Config:
# Allow to change the menu appearance # Allow to change the menu appearance
def get_hud_ui_parameters(self): def get_hud_ui_parameters(self):
hui = {} hui = {}
default_text = 'FPDB Menu - Right click\nLeft-Drag to Move' default_text = 'FPDB Menu - Right click\nLeft-Drag to Move'
try: try:
hui['label'] = self.ui.label hui['label'] = self.ui.label
@ -622,6 +650,39 @@ class Config:
hui['label'] = default_text hui['label'] = default_text
except: except:
hui['label'] = default_text hui['label'] = default_text
try: hui['aggregate_ring'] = self.ui.aggregate_ring
except: hui['aggregate_ring'] = False
try: hui['aggregate_tour'] = self.ui.aggregate_tour
except: hui['aggregate_tour'] = True
try: hui['hud_style'] = self.ui.hud_style
except: hui['hud_style'] = 'A'
try: hui['hud_days'] = int(self.ui.hud_days)
except: hui['hud_days'] = 90
try: hui['agg_bb_mult'] = self.ui.agg_bb_mult
except: hui['agg_bb_mult'] = 1
# Hero specific
try: hui['h_aggregate_ring'] = self.ui.h_aggregate_ring
except: hui['h_aggregate_ring'] = False
try: hui['h_aggregate_tour'] = self.ui.h_aggregate_tour
except: hui['h_aggregate_tour'] = True
try: hui['h_hud_style'] = self.ui.h_hud_style
except: hui['h_hud_style'] = 'S'
try: hui['h_hud_days'] = int(self.ui.h_hud_days)
except: hui['h_hud_days'] = 30
try: hui['h_agg_bb_mult'] = self.ui.h_agg_bb_mult
except: hui['h_agg_bb_mult'] = 1
return hui return hui

File diff suppressed because it is too large Load Diff

View File

@ -22,76 +22,6 @@ class DerivedStats():
def __init__(self, hand): def __init__(self, hand):
self.hand = hand self.hand = hand
self.activeSeats = 0
self.position = 0
self.tourneyTypeId = 0
self.HDs = 0
self.street0VPI = 0
self.street0Aggr = 0
self.street0_3BChance = 0
self.street0_3BDone = 0
self.street0_4BChance = 0
self.street0_4BDone = 0
self.street1Seen = 0
self.street2Seen = 0
self.street3Seen = 0
self.street4Seen = 0
self.sawShowdown = 0
self.street1Aggr = 0
self.street2Aggr = 0
self.street3Aggr = 0
self.street4Aggr = 0
self.otherRaisedStreet1 = 0
self.otherRaisedStreet2 = 0
self.otherRaisedStreet3 = 0
self.otherRaisedStreet4 = 0
self.foldToOtherRaisedStreet1 = 0
self.foldToOtherRaisedStreet2 = 0
self.foldToOtherRaisedStreet3 = 0
self.foldToOtherRaisedStreet4 = 0
self.wonWhenSeenStreet1 = 0
self.wonAtSD = 0
self.stealAttemptChance = 0
self.stealAttempted = 0
self.foldBbToStealChance = 0
self.foldedBbToSteal = 0
self.foldSbToStealChance = 0
self.foldedSbToSteal = 0
self.street1CBChance = 0
self.street1CBDone = 0
self.street2CBChance = 0
self.street2CBDone = 0
self.street3CBChance = 0
self.street3CBDone = 0
self.street4CBChance = 0
self.street4CBDone = 0
self.foldToStreet1CBChance = 0
self.foldToStreet1CBDone = 0
self.foldToStreet2CBChance = 0
self.foldToStreet2CBDone = 0
self.foldToStreet3CBChance = 0
self.foldToStreet3CBDone = 0
self.foldToStreet4CBChance = 0
self.foldToStreet4CBDone = 0
self.totalProfit = 0
self.street1CheckCallRaiseChance = 0
self.street1CheckCallRaiseDone = 0
self.street2CheckCallRaiseChance = 0
self.street2CheckCallRaiseDone = 0
self.street3CheckCallRaiseChance = 0
self.street3CheckCallRaiseDone = 0
self.street4CheckCallRaiseChance = 0
self.street4CheckCallRaiseDone = 0
self.hands = {} self.hands = {}
self.handsplayers = {} self.handsplayers = {}
@ -106,6 +36,9 @@ class DerivedStats():
print "hands =", self.hands print "hands =", self.hands
print "handsplayers =", self.handsplayers print "handsplayers =", self.handsplayers
def getHands(self):
return self.hands
def assembleHands(self, hand): def assembleHands(self, hand):
self.hands['tableName'] = hand.tablename self.hands['tableName'] = hand.tablename
self.hands['siteHandNo'] = hand.handid self.hands['siteHandNo'] = hand.handid
@ -114,36 +47,790 @@ class DerivedStats():
self.hands['importTime'] = None self.hands['importTime'] = None
self.hands['seats'] = self.countPlayers(hand) self.hands['seats'] = self.countPlayers(hand)
self.hands['maxSeats'] = hand.maxseats self.hands['maxSeats'] = hand.maxseats
self.hands['boardcard1'] = None self.hands['texture'] = None # No calculation done for this yet.
self.hands['boardcard2'] = None
self.hands['boardcard3'] = None
self.hands['boardcard4'] = None
self.hands['boardcard5'] = None
boardCard = 1 # This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and
for street in hand.communityStreets: # those values remain default in stud.
for card in hand.board[street]: boardcards = hand.board['FLOP'] + hand.board['TURN'] + hand.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x']
self.hands['boardcard%s' % str(boardCard)] = Card.encodeCard(card) cards = [Card.encodeCard(c) for c in boardcards[0:5]]
boardCard += 1 self.hands['boardcard1'] = cards[0]
self.hands['boardcard2'] = cards[1]
self.hands['boardcard3'] = cards[2]
self.hands['boardcard4'] = cards[3]
self.hands['boardcard5'] = cards[4]
#print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % hand.getStreetTotals()
#FIXME: Pot size still in decimal, needs to be converted to cents
(self.hands['street1Pot'],
self.hands['street2Pot'],
self.hands['street3Pot'],
self.hands['street4Pot'],
self.hands['showdownPot']) = hand.getStreetTotals()
self.vpip(hand) # Gives playersVpi (num of players vpip)
#print "DEBUG: vpip: %s" %(self.hands['playersVpi'])
self.playersAtStreetX(hand) # Gives playersAtStreet1..4 and Showdown
#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): def assembleHandsPlayers(self, hand):
self.vpip(self.hand) self.vpip(self.hand)
for i, street in enumerate(hand.actionStreets[1:]): for i, street in enumerate(hand.actionStreets[1:]):
self.aggr(self.hand, i) self.aggr(self.hand, i)
def assembleHudCache(self, hand):
# # def generateHudCacheData(player_ids, base, category, action_types, allIns, actionTypeByNo
# # ,winnings, totalWinnings, positions, actionTypes, actionAmounts, antes):
# #"""calculates data for the HUD during import. IMPORTANT: if you change this method make
# # sure to also change the following storage method and table_viewer.prepare_data if necessary
# #"""
# #print "generateHudCacheData, len(player_ids)=", len(player_ids)
# #setup subarrays of the result dictionary.
# street0VPI=[]
# street0Aggr=[]
# street0_3BChance=[]
# street0_3BDone=[]
# street1Seen=[]
# street2Seen=[]
# street3Seen=[]
# street4Seen=[]
# sawShowdown=[]
# street1Aggr=[]
# street2Aggr=[]
# street3Aggr=[]
# street4Aggr=[]
# otherRaisedStreet1=[]
# otherRaisedStreet2=[]
# otherRaisedStreet3=[]
# otherRaisedStreet4=[]
# foldToOtherRaisedStreet1=[]
# foldToOtherRaisedStreet2=[]
# foldToOtherRaisedStreet3=[]
# foldToOtherRaisedStreet4=[]
# wonWhenSeenStreet1=[]
#
# wonAtSD=[]
# stealAttemptChance=[]
# stealAttempted=[]
# 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
# firstPfCallByNo=-1
# firstPfCallerId=-1
#
# for i, action in enumerate(actionTypeByNo[0]):
# if action[1] == "bet":
# firstPfRaiseByNo = i
# firstPfRaiserId = action[0]
# for j, pid in enumerate(player_ids):
# if pid == firstPfRaiserId:
# firstPfRaiserNo = j
# break
# break
# for i, action in enumerate(actionTypeByNo[0]):
# if action[1] == "call":
# firstPfCallByNo = i
# firstPfCallerId = action[0]
# break
# firstPlayId = firstPfCallerId
# if firstPfRaiseByNo <> -1:
# if firstPfRaiseByNo < firstPfCallByNo or firstPfCallByNo == -1:
# firstPlayId = firstPfRaiserId
#
#
# cutoffId=-1
# buttonId=-1
# sbId=-1
# bbId=-1
# if base=="hold":
# for player, pos in enumerate(positions):
# if pos == 1:
# cutoffId = player_ids[player]
# if pos == 0:
# buttonId = player_ids[player]
# if pos == 'S':
# sbId = player_ids[player]
# if pos == 'B':
# bbId = player_ids[player]
#
# someoneStole=False
#
# #run a loop for each player preparing the actual values that will be commited to SQL
# for player in xrange(len(player_ids)):
# #set default values
# myStreet0VPI=False
# myStreet0Aggr=False
# myStreet0_3BChance=False
# myStreet0_3BDone=False
# myStreet1Seen=False
# myStreet2Seen=False
# myStreet3Seen=False
# myStreet4Seen=False
# mySawShowdown=False
# myStreet1Aggr=False
# myStreet2Aggr=False
# myStreet3Aggr=False
# myStreet4Aggr=False
# myOtherRaisedStreet1=False
# myOtherRaisedStreet2=False
# myOtherRaisedStreet3=False
# myOtherRaisedStreet4=False
# myFoldToOtherRaisedStreet1=False
# myFoldToOtherRaisedStreet2=False
# myFoldToOtherRaisedStreet3=False
# myFoldToOtherRaisedStreet4=False
# myWonWhenSeenStreet1=0.0
# 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
# heroPfRaiseCount=0
# for currentAction in action_types[street][player]: # finally individual actions
# if currentAction == "bet":
# 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
# pfRaise=-1
# if firstPfRaiseByNo != -1:
# for i, actionType in enumerate(actionTypeByNo[0]):
# if actionType[0] == player_ids[player]:
# if actionType[1] == "bet" and pfRaise == -1 and i > firstPfRaiseByNo:
# pfRaise = i
# if actionType[1] == "fold" and pfFold == -1:
# pfFold = i
# if pfFold == -1 or pfFold > firstPfRaiseByNo:
# myStreet0_3BChance = True
# if pfRaise > firstPfRaiseByNo:
# myStreet0_3BDone = True
#
# #steal calculations
# if base=="hold":
# if len(player_ids)>=3: # no point otherwise # was 5, use 3 to match pokertracker definition
# if positions[player]==1:
# if firstPfRaiserId==player_ids[player] \
# and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo):
# myStealAttempted=True
# myStealAttemptChance=True
# if firstPlayId==cutoffId or firstPlayId==buttonId or firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1:
# myStealAttemptChance=True
# if positions[player]==0:
# if firstPfRaiserId==player_ids[player] \
# and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo):
# myStealAttempted=True
# myStealAttemptChance=True
# if firstPlayId==buttonId or firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1:
# myStealAttemptChance=True
# if positions[player]=='S':
# if firstPfRaiserId==player_ids[player] \
# and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo):
# myStealAttempted=True
# myStealAttemptChance=True
# if firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1:
# myStealAttemptChance=True
# if positions[player]=='B':
# pass
#
# if myStealAttempted:
# someoneStole=True
#
#
# #calculate saw* values
# isAllIn = False
# if any(i for i in allIns[0][player]):
# isAllIn = True
# if (len(action_types[1][player])>0 or isAllIn):
# myStreet1Seen = True
#
# if any(i for i in allIns[1][player]):
# isAllIn = True
# if (len(action_types[2][player])>0 or isAllIn):
# myStreet2Seen = True
#
# if any(i for i in allIns[2][player]):
# isAllIn = True
# if (len(action_types[3][player])>0 or isAllIn):
# myStreet3Seen = True
#
# #print "base:", base
# if base=="hold":
# mySawShowdown = True
# if any(actiontype == "fold" for actiontype in action_types[3][player]):
# mySawShowdown = False
# else:
# #print "in else"
# if any(i for i in allIns[3][player]):
# isAllIn = True
# if (len(action_types[4][player])>0 or isAllIn):
# #print "in if"
# myStreet4Seen = True
#
# 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
# if myStreet1Seen:
# 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
# else:
# for countOther in xrange(len(action_types[street][otherPlayer])):
# if action_types[street][otherPlayer][countOther]=="bet":
# myOtherRaisedStreet1=True
# for countOtherFold in xrange(len(action_types[street][player])):
# if action_types[street][player][countOtherFold]=="fold":
# myFoldToOtherRaisedStreet1=True
#
# #turn stuff - copy of flop with different vars
# street=2
# if myStreet2Seen:
# 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
# else:
# for countOther in xrange(len(action_types[street][otherPlayer])):
# if action_types[street][otherPlayer][countOther]=="bet":
# myOtherRaisedStreet2=True
# for countOtherFold in xrange(len(action_types[street][player])):
# if action_types[street][player][countOtherFold]=="fold":
# myFoldToOtherRaisedStreet2=True
#
# #river stuff - copy of flop with different vars
# street=3
# if myStreet3Seen:
# 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
# else:
# for countOther in xrange(len(action_types[street][otherPlayer])):
# if action_types[street][otherPlayer][countOther]=="bet":
# myOtherRaisedStreet3=True
# for countOtherFold in xrange(len(action_types[street][player])):
# if action_types[street][player][countOtherFold]=="fold":
# myFoldToOtherRaisedStreet3=True
#
# #stud river stuff - copy of flop with different vars
# street=4
# if myStreet4Seen:
# 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
# else:
# for countOther in xrange(len(action_types[street][otherPlayer])):
# if action_types[street][otherPlayer][countOther]=="bet":
# myOtherRaisedStreet4=True
# for countOtherFold in xrange(len(action_types[street][player])):
# if action_types[street][player][countOtherFold]=="fold":
# myFoldToOtherRaisedStreet4=True
#
# if winnings[player] != 0:
# if myStreet1Seen:
# myWonWhenSeenStreet1 = winnings[player] / float(totalWinnings)
# if mySawShowdown:
# myWonAtSD=myWonWhenSeenStreet1
#
# #add each value to the appropriate array
# street0VPI.append(myStreet0VPI)
# street0Aggr.append(myStreet0Aggr)
# street0_3BChance.append(myStreet0_3BChance)
# street0_3BDone.append(myStreet0_3BDone)
# street1Seen.append(myStreet1Seen)
# street2Seen.append(myStreet2Seen)
# street3Seen.append(myStreet3Seen)
# street4Seen.append(myStreet4Seen)
# sawShowdown.append(mySawShowdown)
# street1Aggr.append(myStreet1Aggr)
# street2Aggr.append(myStreet2Aggr)
# street3Aggr.append(myStreet3Aggr)
# street4Aggr.append(myStreet4Aggr)
# otherRaisedStreet1.append(myOtherRaisedStreet1)
# otherRaisedStreet2.append(myOtherRaisedStreet2)
# otherRaisedStreet3.append(myOtherRaisedStreet3)
# otherRaisedStreet4.append(myOtherRaisedStreet4)
# foldToOtherRaisedStreet1.append(myFoldToOtherRaisedStreet1)
# foldToOtherRaisedStreet2.append(myFoldToOtherRaisedStreet2)
# foldToOtherRaisedStreet3.append(myFoldToOtherRaisedStreet3)
# foldToOtherRaisedStreet4.append(myFoldToOtherRaisedStreet4)
# wonWhenSeenStreet1.append(myWonWhenSeenStreet1)
# wonAtSD.append(myWonAtSD)
# stealAttemptChance.append(myStealAttemptChance)
# stealAttempted.append(myStealAttempted)
# if base=="hold":
# pos=positions[player]
# if pos=='B':
# hudDataPositions.append('B')
# elif pos=='S':
# hudDataPositions.append('S')
# elif pos==0:
# hudDataPositions.append('D')
# elif pos==1:
# hudDataPositions.append('C')
# elif pos>=2 and pos<=4:
# hudDataPositions.append('M')
# elif pos>=5 and pos<=8:
# hudDataPositions.append('E')
# ### RHH Added this elif to handle being a dead hand before the BB (pos==9)
# elif pos==9:
# hudDataPositions.append('X')
# else:
# raise FpdbError("invalid position")
# 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['street0Aggr']=street0Aggr
# result['street0_3BChance']=street0_3BChance
# result['street0_3BDone']=street0_3BDone
# result['street1Seen']=street1Seen
# result['street2Seen']=street2Seen
# result['street3Seen']=street3Seen
# result['street4Seen']=street4Seen
# result['sawShowdown']=sawShowdown
#
# result['street1Aggr']=street1Aggr
# result['otherRaisedStreet1']=otherRaisedStreet1
# result['foldToOtherRaisedStreet1']=foldToOtherRaisedStreet1
# result['street2Aggr']=street2Aggr
# result['otherRaisedStreet2']=otherRaisedStreet2
# result['foldToOtherRaisedStreet2']=foldToOtherRaisedStreet2
# result['street3Aggr']=street3Aggr
# result['otherRaisedStreet3']=otherRaisedStreet3
# result['foldToOtherRaisedStreet3']=foldToOtherRaisedStreet3
# result['street4Aggr']=street4Aggr
# result['otherRaisedStreet4']=otherRaisedStreet4
# result['foldToOtherRaisedStreet4']=foldToOtherRaisedStreet4
# result['wonWhenSeenStreet1']=wonWhenSeenStreet1
# 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=[]
# foldedBbToSteal=[]
# foldSbToStealChance=[]
# foldedSbToSteal=[]
# for player in xrange(len(player_ids)):
# myFoldBbToStealChance=False
# myFoldedBbToSteal=False
# myFoldSbToStealChance=False
# myFoldedSbToSteal=False
#
# if base=="hold":
# if someoneStole and (positions[player]=='B' or positions[player]=='S') and firstPfRaiserId!=player_ids[player]:
# street=0
# for count in xrange(len(action_types[street][player])):#individual actions
# if positions[player]=='B':
# myFoldBbToStealChance=True
# if action_types[street][player][count]=="fold":
# myFoldedBbToSteal=True
# if positions[player]=='S':
# myFoldSbToStealChance=True
# if action_types[street][player][count]=="fold":
# myFoldedSbToSteal=True
#
#
# foldBbToStealChance.append(myFoldBbToStealChance)
# foldedBbToSteal.append(myFoldedBbToSteal)
# foldSbToStealChance.append(myFoldSbToStealChance)
# foldedSbToSteal.append(myFoldedSbToSteal)
# result['foldBbToStealChance']=foldBbToStealChance
# result['foldedBbToSteal']=foldedBbToSteal
# result['foldSbToStealChance']=foldSbToStealChance
# result['foldedSbToSteal']=foldedSbToSteal
#
# #now CB
# street1CBChance=[]
# street1CBDone=[]
# didStreet1CB=[]
# for player in xrange(len(player_ids)):
# myStreet1CBChance=False
# myStreet1CBDone=False
#
# if street0VPI[player]:
# myStreet1CBChance=True
# if street1Aggr[player]:
# myStreet1CBDone=True
# didStreet1CB.append(player_ids[player])
#
# street1CBChance.append(myStreet1CBChance)
# street1CBDone.append(myStreet1CBDone)
# result['street1CBChance']=street1CBChance
# result['street1CBDone']=street1CBDone
#
# #now 2B
# street2CBChance=[]
# street2CBDone=[]
# didStreet2CB=[]
# for player in xrange(len(player_ids)):
# myStreet2CBChance=False
# myStreet2CBDone=False
#
# if street1CBDone[player]:
# myStreet2CBChance=True
# if street2Aggr[player]:
# myStreet2CBDone=True
# didStreet2CB.append(player_ids[player])
#
# street2CBChance.append(myStreet2CBChance)
# street2CBDone.append(myStreet2CBDone)
# result['street2CBChance']=street2CBChance
# result['street2CBDone']=street2CBDone
#
# #now 3B
# street3CBChance=[]
# street3CBDone=[]
# didStreet3CB=[]
# for player in xrange(len(player_ids)):
# myStreet3CBChance=False
# myStreet3CBDone=False
#
# if street2CBDone[player]:
# myStreet3CBChance=True
# if street3Aggr[player]:
# myStreet3CBDone=True
# didStreet3CB.append(player_ids[player])
#
# street3CBChance.append(myStreet3CBChance)
# street3CBDone.append(myStreet3CBDone)
# result['street3CBChance']=street3CBChance
# result['street3CBDone']=street3CBDone
#
# #and 4B
# street4CBChance=[]
# street4CBDone=[]
# didStreet4CB=[]
# for player in xrange(len(player_ids)):
# myStreet4CBChance=False
# myStreet4CBDone=False
#
# if street3CBDone[player]:
# myStreet4CBChance=True
# if street4Aggr[player]:
# myStreet4CBDone=True
# didStreet4CB.append(player_ids[player])
#
# street4CBChance.append(myStreet4CBChance)
# street4CBDone.append(myStreet4CBDone)
# result['street4CBChance']=street4CBChance
# result['street4CBDone']=street4CBDone
#
#
# result['position']=hudDataPositions
#
# foldToStreet1CBChance=[]
# foldToStreet1CBDone=[]
# foldToStreet2CBChance=[]
# foldToStreet2CBDone=[]
# foldToStreet3CBChance=[]
# foldToStreet3CBDone=[]
# foldToStreet4CBChance=[]
# foldToStreet4CBDone=[]
#
# for player in xrange(len(player_ids)):
# myFoldToStreet1CBChance=False
# myFoldToStreet1CBDone=False
# foldToStreet1CBChance.append(myFoldToStreet1CBChance)
# foldToStreet1CBDone.append(myFoldToStreet1CBDone)
#
# myFoldToStreet2CBChance=False
# myFoldToStreet2CBDone=False
# foldToStreet2CBChance.append(myFoldToStreet2CBChance)
# foldToStreet2CBDone.append(myFoldToStreet2CBDone)
#
# myFoldToStreet3CBChance=False
# myFoldToStreet3CBDone=False
# foldToStreet3CBChance.append(myFoldToStreet3CBChance)
# foldToStreet3CBDone.append(myFoldToStreet3CBDone)
#
# myFoldToStreet4CBChance=False
# myFoldToStreet4CBDone=False
# foldToStreet4CBChance.append(myFoldToStreet4CBChance)
# foldToStreet4CBDone.append(myFoldToStreet4CBDone)
#
# if len(didStreet1CB)>=1:
# generateFoldToCB(1, player_ids, didStreet1CB, street1CBDone, foldToStreet1CBChance, foldToStreet1CBDone, actionTypeByNo)
#
# if len(didStreet2CB)>=1:
# generateFoldToCB(2, player_ids, didStreet2CB, street2CBDone, foldToStreet2CBChance, foldToStreet2CBDone, actionTypeByNo)
#
# if len(didStreet3CB)>=1:
# generateFoldToCB(3, player_ids, didStreet3CB, street3CBDone, foldToStreet3CBChance, foldToStreet3CBDone, actionTypeByNo)
#
# if len(didStreet4CB)>=1:
# generateFoldToCB(4, player_ids, didStreet4CB, street4CBDone, foldToStreet4CBChance, foldToStreet4CBDone, actionTypeByNo)
#
# result['foldToStreet1CBChance']=foldToStreet1CBChance
# result['foldToStreet1CBDone']=foldToStreet1CBDone
# result['foldToStreet2CBChance']=foldToStreet2CBChance
# result['foldToStreet2CBDone']=foldToStreet2CBDone
# result['foldToStreet3CBChance']=foldToStreet3CBChance
# result['foldToStreet3CBDone']=foldToStreet3CBDone
# result['foldToStreet4CBChance']=foldToStreet4CBChance
# result['foldToStreet4CBDone']=foldToStreet4CBDone
#
#
# totalProfit=[]
#
# street1CheckCallRaiseChance=[]
# street1CheckCallRaiseDone=[]
# street2CheckCallRaiseChance=[]
# street2CheckCallRaiseDone=[]
# street3CheckCallRaiseChance=[]
# street3CheckCallRaiseDone=[]
# street4CheckCallRaiseChance=[]
# street4CheckCallRaiseDone=[]
# #print "b4 totprof calc, len(playerIds)=", len(player_ids)
# for pl in xrange(len(player_ids)):
# #print "pl=", pl
# myTotalProfit=winnings[pl] # still need to deduct other costs
# if antes:
# myTotalProfit=winnings[pl] - antes[pl]
# for i in xrange(len(actionTypes)): #iterate through streets
# #for j in xrange(len(actionTypes[i])): #iterate through names (using pl loop above)
# for k in xrange(len(actionTypes[i][pl])): #iterate through individual actions of that player on that street
# myTotalProfit -= actionAmounts[i][pl][k]
#
# myStreet1CheckCallRaiseChance=False
# myStreet1CheckCallRaiseDone=False
# myStreet2CheckCallRaiseChance=False
# myStreet2CheckCallRaiseDone=False
# myStreet3CheckCallRaiseChance=False
# myStreet3CheckCallRaiseDone=False
# myStreet4CheckCallRaiseChance=False
# myStreet4CheckCallRaiseDone=False
#
# #print "myTotalProfit=", myTotalProfit
# totalProfit.append(myTotalProfit)
# #print "totalProfit[]=", totalProfit
#
# street1CheckCallRaiseChance.append(myStreet1CheckCallRaiseChance)
# street1CheckCallRaiseDone.append(myStreet1CheckCallRaiseDone)
# street2CheckCallRaiseChance.append(myStreet2CheckCallRaiseChance)
# street2CheckCallRaiseDone.append(myStreet2CheckCallRaiseDone)
# street3CheckCallRaiseChance.append(myStreet3CheckCallRaiseChance)
# street3CheckCallRaiseDone.append(myStreet3CheckCallRaiseDone)
# street4CheckCallRaiseChance.append(myStreet4CheckCallRaiseChance)
# street4CheckCallRaiseDone.append(myStreet4CheckCallRaiseDone)
#
# result['totalProfit']=totalProfit
# #print "res[totalProfit]=", result['totalProfit']
#
# result['street1CheckCallRaiseChance']=street1CheckCallRaiseChance
# result['street1CheckCallRaiseDone']=street1CheckCallRaiseDone
# result['street2CheckCallRaiseChance']=street2CheckCallRaiseChance
# result['street2CheckCallRaiseDone']=street2CheckCallRaiseDone
# result['street3CheckCallRaiseChance']=street3CheckCallRaiseChance
# result['street3CheckCallRaiseDone']=street3CheckCallRaiseDone
# result['street4CheckCallRaiseChance']=street4CheckCallRaiseChance
# result['street4CheckCallRaiseDone']=street4CheckCallRaiseDone
# return result
# #end def generateHudCacheData
pass
def vpip(self, hand): def vpip(self, hand):
vpipers = set() vpipers = set()
for act in hand.actions[hand.actionStreets[1]]: for act in hand.actions[hand.actionStreets[1]]:
if act[1] in ('calls','bets', 'raises'): if act[1] in ('calls','bets', 'raises'):
vpipers.add(act[0]) vpipers.add(act[0])
for player in hand.players: #for player in hand.players:
if player[1] in vpipers: # print "DEBUG: '%s' '%s' '%s'" %(player, player[1], vpipers)
self.handsplayers[player[1]]['vpip'] = True # if player[1] in vpipers:
else: # self.handsplayers[player[1]]['vpip'] = True
self.handsplayers[player[1]]['vpip'] = False # else:
# self.handsplayers[player[1]]['vpip'] = False
self.hands['playersVpi'] = len(vpipers) self.hands['playersVpi'] = len(vpipers)
def playersAtStreetX(self, hand):
""" playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4/draw1 */"""
# self.actions[street] is a list of all actions in a tuple, contining the player name first
# [ (player, action, ....), (player2, action, ...) ]
# The number of unique players in the list per street gives the value for playersAtStreetXXX
self.hands['playersAtStreet1'] = 0
self.hands['playersAtStreet2'] = 0
self.hands['playersAtStreet3'] = 0
self.hands['playersAtStreet4'] = 0
self.hands['playersAtShowdown'] = 0
for street in hand.actionStreets:
actors = {}
for act in hand.actions[street]:
actors[act[0]] = 1
#print "len(actors.keys(%s)): %s" % ( street, len(actors.keys()))
if hand.gametype['base'] in ("hold"):
if street in "FLOP": self.hands['playersAtStreet1'] = len(actors.keys())
elif street in "TURN": self.hands['playersAtStreet2'] = len(actors.keys())
elif street in "RIVER": self.hands['playersAtStreet3'] = len(actors.keys())
elif hand.gametype['base'] in ("stud"):
if street in "FOURTH": self.hands['playersAtStreet1'] = len(actors.keys())
elif street in "FIFTH": self.hands['playersAtStreet2'] = len(actors.keys())
elif street in "SIXTH": self.hands['playersAtStreet3'] = len(actors.keys())
elif street in "SEVENTH": self.hands['playersAtStreet4'] = len(actors.keys())
elif hand.gametype['base'] in ("draw"):
if street in "DRAWONE": self.hands['playersAtStreet1'] = len(actors.keys())
elif street in "DRAWTWO": self.hands['playersAtStreet2'] = len(actors.keys())
elif street in "DRAWTHREE": self.hands['playersAtStreet3'] = len(actors.keys())
#Need playersAtShowdown
def streetXRaises(self, hand):
# self.actions[street] is a list of all actions in a tuple, contining the action as the second element
# [ (player, action, ....), (player2, action, ...) ]
# No idea what this value is actually supposed to be
# In theory its "num small bets paid to see flop/street4, including blind" which makes sense for limit. Not so useful for nl
# Leaving empty for the moment,
self.hands['street0Raises'] = 0 # /* num small bets paid to see flop/street4, including blind */
self.hands['street1Raises'] = 0 # /* num small bets paid to see turn/street5 */
self.hands['street2Raises'] = 0 # /* num big bets paid to see river/street6 */
self.hands['street3Raises'] = 0 # /* num big bets paid to see sd/street7 */
self.hands['street4Raises'] = 0 # /* num big bets paid to see showdown */
def aggr(self, hand, i): def aggr(self, hand, i):
aggrers = set() aggrers = set()
for act in hand.actions[hand.actionStreets[i]]: for act in hand.actions[hand.actionStreets[i]]:

View File

@ -17,5 +17,8 @@ class FpdbParseError(FpdbError):
class FpdbDatabaseError(FpdbError): class FpdbDatabaseError(FpdbError):
pass pass
class FpdbMySQLFailedError(FpdbDatabaseError):
pass
class DuplicateError(FpdbError): class DuplicateError(FpdbError):
pass pass

View File

@ -23,6 +23,7 @@ import os
import sys import sys
from optparse import OptionParser from optparse import OptionParser
from time import * from time import *
import gobject
#import pokereval #import pokereval
import Configuration import Configuration
@ -31,12 +32,13 @@ import FpdbSQLQueries
class Filters(threading.Thread): class Filters(threading.Thread):
def __init__(self, db, config, qdict, display = {}, debug=True): def __init__(self, db, config, qdict, display = {}, debug=True):
# config and qdict are now redundant
self.debug = debug self.debug = debug
#print "start of GraphViewer constructor" #print "start of GraphViewer constructor"
self.db = db self.db = db
self.cursor = db.cursor self.cursor = db.cursor
self.sql=qdict self.sql = db.sql
self.conf = config self.conf = db.config
self.display = display self.display = display
self.sites = {} self.sites = {}
@ -53,6 +55,7 @@ class Filters(threading.Thread):
,'seatsbetween':'Between:', 'seatsand':'And:', 'seatsshow':'Show Number of _Players' ,'seatsbetween':'Between:', 'seatsand':'And:', 'seatsshow':'Show Number of _Players'
,'limitstitle':'Limits:', 'seatstitle':'Number of Players:' ,'limitstitle':'Limits:', 'seatstitle':'Number of Players:'
,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:' ,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:'
,'limitsFL':'FL', 'limitsNL':'NL', 'ring':'Ring', 'tour':'Tourney'
} }
# For use in date ranges. # For use in date ranges.
@ -97,6 +100,11 @@ class Filters(threading.Thread):
self.cbLimits = {} self.cbLimits = {}
self.cbNoLimits = None self.cbNoLimits = None
self.cbAllLimits = None self.cbAllLimits = None
self.cbFL = None
self.cbNL = None
self.rb = {} # radio buttons for ring/tour
self.type = None # ring/tour
self.types = {} # list of all ring/tour values
self.fillLimitsFrame(vbox, self.display) self.fillLimitsFrame(vbox, self.display)
limitsFrame.add(vbox) limitsFrame.add(vbox)
@ -189,6 +197,9 @@ class Filters(threading.Thread):
ltuple.append(l) ltuple.append(l)
return ltuple return ltuple
def getType(self):
return(self.type)
def getSeats(self): def getSeats(self):
if 'from' in self.sbSeats: if 'from' in self.sbSeats:
self.seats['from'] = self.sbSeats['from'].get_value_as_int() self.seats['from'] = self.sbSeats['from'].get_value_as_int()
@ -228,7 +239,16 @@ class Filters(threading.Thread):
pname.set_width_chars(20) pname.set_width_chars(20)
hbox.pack_start(pname, False, True, 0) hbox.pack_start(pname, False, True, 0)
pname.connect("changed", self.__set_hero_name, site) pname.connect("changed", self.__set_hero_name, site)
#TODO: Look at GtkCompletion - to fill out usernames
# Added EntryCompletion but maybe comboBoxEntry is more flexible? (e.g. multiple choices)
completion = gtk.EntryCompletion()
pname.set_completion(completion)
liststore = gtk.ListStore(gobject.TYPE_STRING)
completion.set_model(liststore)
completion.set_text_column(0)
names = self.db.get_player_names(self.conf) # (config=self.conf, site_id=None, like_player_name="%")
for n in names:
liststore.append(n)
self.__set_hero_name(pname, site) self.__set_hero_name(pname, site)
@ -269,21 +289,99 @@ class Filters(threading.Thread):
#print w.get_active() #print w.get_active()
self.limits[limit] = w.get_active() self.limits[limit] = w.get_active()
print "self.limit[%s] set to %s" %(limit, self.limits[limit]) print "self.limit[%s] set to %s" %(limit, self.limits[limit])
if str(limit).isdigit(): if limit.isdigit() or (len(limit) > 2 and limit[-2:] == 'nl'):
if self.limits[limit]: if self.limits[limit]:
if self.cbNoLimits != None: if self.cbNoLimits != None:
self.cbNoLimits.set_active(False) self.cbNoLimits.set_active(False)
else: else:
if self.cbAllLimits != None: if self.cbAllLimits != None:
self.cbAllLimits.set_active(False) self.cbAllLimits.set_active(False)
if not self.limits[limit]:
if limit.isdigit():
self.cbFL.set_active(False)
else:
self.cbNL.set_active(False)
elif limit == "all": elif limit == "all":
if self.limits[limit]: if self.limits[limit]:
for cb in self.cbLimits.values(): #for cb in self.cbLimits.values():
cb.set_active(True) # cb.set_active(True)
if self.cbFL != None:
self.cbFL.set_active(True)
if self.cbNL != None:
self.cbNL.set_active(True)
elif limit == "none": elif limit == "none":
if self.limits[limit]: if self.limits[limit]:
for cb in self.cbLimits.values(): for cb in self.cbLimits.values():
cb.set_active(False) cb.set_active(False)
self.cbNL.set_active(False)
self.cbFL.set_active(False)
elif limit == "fl":
if not self.limits[limit]:
# only toggle all fl limits off if they are all currently on
# this stops turning one off from cascading into 'fl' box off
# and then all fl limits being turned off
all_fl_on = True
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if t.isdigit():
if not cb.get_active():
all_fl_on = False
found = {'ring':False, 'tour':False}
for cb in self.cbLimits.values():
#print "cb label: ", cb.children()[0].get_text()
t = cb.get_children()[0].get_text()
if t.isdigit():
if self.limits[limit] or all_fl_on:
cb.set_active(self.limits[limit])
found[self.types[t]] = True
if self.limits[limit]:
if not found[self.type]:
if self.type == 'ring':
if 'tour' in self.rb:
self.rb['tour'].set_active(True)
elif self.type == 'tour':
if 'ring' in self.rb:
self.rb['ring'].set_active(True)
elif limit == "nl":
if not self.limits[limit]:
# only toggle all nl limits off if they are all currently on
# this stops turning one off from cascading into 'nl' box off
# and then all nl limits being turned off
all_nl_on = True
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "nl" in t and len(t) > 2:
if not cb.get_active():
all_nl_on = False
found = {'ring':False, 'tour':False}
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "nl" in t and len(t) > 2:
if self.limits[limit] or all_nl_on:
cb.set_active(self.limits[limit])
found[self.types[t]] = True
if self.limits[limit]:
if not found[self.type]:
if self.type == 'ring':
self.rb['tour'].set_active(True)
elif self.type == 'tour':
self.rb['ring'].set_active(True)
elif limit == "ring":
print "set", limit, "to", self.limits[limit]
if self.limits[limit]:
self.type = "ring"
for cb in self.cbLimits.values():
#print "cb label: ", cb.children()[0].get_text()
if self.types[cb.get_children()[0].get_text()] == 'tour':
cb.set_active(False)
elif limit == "tour":
print "set", limit, "to", self.limits[limit]
if self.limits[limit]:
self.type = "tour"
for cb in self.cbLimits.values():
#print "cb label: ", cb.children()[0].get_text()
if self.types[cb.get_children()[0].get_text()] == 'ring':
cb.set_active(False)
def __set_seat_select(self, w, seat): def __set_seat_select(self, w, seat):
#print "__set_seat_select: seat =", seat, "active =", w.get_active() #print "__set_seat_select: seat =", seat, "active =", w.get_active()
@ -328,22 +426,23 @@ class Filters(threading.Thread):
print "INFO: No games returned from database" print "INFO: No games returned from database"
def fillLimitsFrame(self, vbox, display): def fillLimitsFrame(self, vbox, display):
hbox = gtk.HBox(False, 0) top_hbox = gtk.HBox(False, 0)
vbox.pack_start(hbox, False, False, 0) vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['limitstitle']) lbl_title = gtk.Label(self.filterText['limitstitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5) lbl_title.set_alignment(xalign=0.0, yalign=0.5)
hbox.pack_start(lbl_title, expand=True, padding=3) top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True) showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5) showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'limits') showb.connect('clicked', self.__toggle_box, 'limits')
hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0) vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0) vbox.pack_start(vbox1, False, False, 0)
self.boxes['limits'] = vbox1 self.boxes['limits'] = vbox1
self.cursor.execute(self.sql.query['getLimits']) self.cursor.execute(self.sql.query['getLimits2'])
# selects limitType, bigBlind
result = self.db.cursor.fetchall() result = self.db.cursor.fetchall()
fl, nl = False, False
if len(result) >= 1: if len(result) >= 1:
hbox = gtk.HBox(True, 0) hbox = gtk.HBox(True, 0)
vbox1.pack_start(hbox, False, False, 0) vbox1.pack_start(hbox, False, False, 0)
@ -351,26 +450,72 @@ class Filters(threading.Thread):
hbox.pack_start(vbox2, False, False, 0) hbox.pack_start(vbox2, False, False, 0)
vbox3 = gtk.VBox(False, 0) vbox3 = gtk.VBox(False, 0)
hbox.pack_start(vbox3, False, False, 0) hbox.pack_start(vbox3, False, False, 0)
found = {'nl':False, 'fl':False, 'ring':False, 'tour':False}
for i, line in enumerate(result): for i, line in enumerate(result):
if "UseType" in self.display:
if line[0] != self.display["UseType"]:
continue
hbox = gtk.HBox(False, 0) hbox = gtk.HBox(False, 0)
if i <= len(result)/2: if i <= len(result)/2:
vbox2.pack_start(hbox, False, False, 0) vbox2.pack_start(hbox, False, False, 0)
else: else:
vbox3.pack_start(hbox, False, False, 0) vbox3.pack_start(hbox, False, False, 0)
self.cbLimits[line[0]] = self.createLimitLine(hbox, line[0], line[0]) if line[1] == 'fl':
name = str(line[2])
found['fl'] = True
else:
name = str(line[2])+line[1]
found['nl'] = True
self.cbLimits[name] = self.createLimitLine(hbox, name, name)
self.types[name] = line[0]
found[line[0]] = True # type is ring/tour
self.type = line[0] # if only one type, set it now
if "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2: if "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2:
hbox = gtk.HBox(True, 0)
vbox1.pack_start(hbox, False, False, 0)
vbox2 = gtk.VBox(False, 0)
hbox.pack_start(vbox2, False, False, 0)
vbox3 = gtk.VBox(False, 0)
hbox.pack_start(vbox3, False, False, 0)
hbox = gtk.HBox(False, 0) hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0) vbox2.pack_start(hbox, False, False, 0)
self.cbAllLimits = self.createLimitLine(hbox, 'all', self.filterText['limitsall']) self.cbAllLimits = self.createLimitLine(hbox, 'all', self.filterText['limitsall'])
hbox = gtk.HBox(False, 0) hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0) vbox2.pack_start(hbox, False, False, 0)
self.cbNoLimits = self.createLimitLine(hbox, 'none', self.filterText['limitsnone']) self.cbNoLimits = self.createLimitLine(hbox, 'none', self.filterText['limitsnone'])
dest = vbox3 # for ring/tour buttons
if "LimitType" in display and display["LimitType"] == True and found['nl'] and found['fl']:
#if found['fl']:
hbox = gtk.HBox(False, 0) hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0) vbox3.pack_start(hbox, False, False, 0)
cb = self.createLimitLine(hbox, 'show', self.filterText['limitsshow']) self.cbFL = self.createLimitLine(hbox, 'fl', self.filterText['limitsFL'])
#if found['nl']:
hbox = gtk.HBox(False, 0)
vbox3.pack_start(hbox, False, False, 0)
self.cbNL = self.createLimitLine(hbox, 'nl', self.filterText['limitsNL'])
dest = vbox2 # for ring/tour buttons
else: else:
print "INFO: No games returned from database" print "INFO: No games returned from database"
if "Type" in display and display["Type"] == True and found['ring'] and found['tour']:
rb1 = gtk.RadioButton(None, self.filterText['ring'])
rb1.connect('clicked', self.__set_limit_select, 'ring')
rb2 = gtk.RadioButton(rb1, self.filterText['tour'])
rb2.connect('clicked', self.__set_limit_select, 'tour')
top_hbox.pack_start(rb1, False, False, 0) # (child, expand, fill, padding)
top_hbox.pack_start(rb2, True, True, 0) # child uses expand space if fill is true
self.rb['ring'] = rb1
self.rb['tour'] = rb2
#print "about to set ring to true"
rb1.set_active(True)
# set_active doesn't seem to call this for some reason so call manually:
self.__set_limit_select(rb1, 'ring')
self.type = 'ring'
top_hbox.pack_start(showb, expand=False, padding=1)
def fillSeatsFrame(self, vbox, display): def fillSeatsFrame(self, vbox, display):
hbox = gtk.HBox(False, 0) hbox = gtk.HBox(False, 0)
vbox.pack_start(hbox, False, False, 0) vbox.pack_start(hbox, False, False, 0)
@ -401,15 +546,6 @@ class Filters(threading.Thread):
hbox.pack_start(lbl_to, expand=False, padding=3) hbox.pack_start(lbl_to, expand=False, padding=3)
hbox.pack_start(sb2, False, False, 0) hbox.pack_start(sb2, False, False, 0)
if "SeatSep" in display and display["SeatSep"] == True:
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
cb = gtk.CheckButton(self.filterText['seatsshow'])
cb.connect('clicked', self.__set_seat_select, 'show')
hbox.pack_start(cb, False, False, 0)
self.sbSeats['show'] = cb
self.seats['show'] = False
self.sbSeats['from'] = sb1 self.sbSeats['from'] = sb1
self.sbSeats['to'] = sb2 self.sbSeats['to'] = sb2
@ -429,14 +565,26 @@ class Filters(threading.Thread):
self.boxes['groups'] = vbox1 self.boxes['groups'] = vbox1
hbox = gtk.HBox(False, 0) hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0) vbox1.pack_start(hbox, False, False, 0)
cb = self.createLimitLine(hbox, 'show', self.filterText['limitsshow'])
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
cb = gtk.CheckButton(self.filterText['posnshow']) cb = gtk.CheckButton(self.filterText['posnshow'])
cb.connect('clicked', self.__set_group_select, 'posn') cb.connect('clicked', self.__set_group_select, 'posn')
hbox.pack_start(cb, False, False, 0) hbox.pack_start(cb, False, False, 0)
self.sbGroups['posn'] = cb self.sbGroups['posn'] = cb
self.groups['posn'] = False self.groups['posn'] = False
if "SeatSep" in display and display["SeatSep"] == True:
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
cb = gtk.CheckButton(self.filterText['seatsshow'])
cb.connect('clicked', self.__set_seat_select, 'show')
hbox.pack_start(cb, False, False, 0)
self.sbSeats['show'] = cb
self.seats['show'] = False
def fillCardsFrame(self, vbox): def fillCardsFrame(self, vbox):
hbox1 = gtk.HBox(True,0) hbox1 = gtk.HBox(True,0)
hbox1.show() hbox1.show()

6
pyfpdb/FulltiltToFpdb.py Normal file → Executable file
View File

@ -40,6 +40,7 @@ class Fulltilt(HandHistoryConverter):
(?P<SB>[.0-9]+)/ (?P<SB>[.0-9]+)/
\$?(?P<BB>[.0-9]+)\s \$?(?P<BB>[.0-9]+)\s
(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s (Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s
\$?(?P<CAP>[.0-9]+\sCap\s)?
(?P<LIMIT>(No\sLimit|Pot\sLimit|Limit))?\s (?P<LIMIT>(No\sLimit|Pot\sLimit|Limit))?\s
(?P<GAME>(Hold\'em|Omaha\sHi|Omaha\sH/L|7\sCard\sStud|Stud\sH/L|Razz|Stud\sHi)) (?P<GAME>(Hold\'em|Omaha\sHi|Omaha\sH/L|7\sCard\sStud|Stud\sH/L|Razz|Stud\sHi))
''', re.VERBOSE) ''', re.VERBOSE)
@ -52,6 +53,7 @@ class Fulltilt(HandHistoryConverter):
(?P<TABLE>[-\s\da-zA-Z]+)\s (?P<TABLE>[-\s\da-zA-Z]+)\s
(\((?P<TABLEATTRIBUTES>.+)\)\s)?-\s (\((?P<TABLEATTRIBUTES>.+)\)\s)?-\s
\$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\s(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\s(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s
\$?(?P<CAP>[.0-9]+\sCap\s)?
(?P<GAMETYPE>[a-zA-Z\/\'\s]+)\s-\s (?P<GAMETYPE>[a-zA-Z\/\'\s]+)\s-\s
(?P<DATETIME>\d+:\d+:\d+\s\w+\s-\s\d+/\d+/\d+)\s? (?P<DATETIME>\d+:\d+:\d+\s\w+\s-\s\d+/\d+/\d+)\s?
(?P<PARTIAL>\(partial\))?\n (?P<PARTIAL>\(partial\))?\n
@ -143,6 +145,7 @@ class Fulltilt(HandHistoryConverter):
return [["ring", "hold", "nl"], return [["ring", "hold", "nl"],
["ring", "hold", "pl"], ["ring", "hold", "pl"],
["ring", "hold", "fl"], ["ring", "hold", "fl"],
["ring", "hold", "cn"],
["ring", "stud", "fl"], ["ring", "stud", "fl"],
@ -175,6 +178,9 @@ class Fulltilt(HandHistoryConverter):
'Stud H/L' : ('stud','studhilo') 'Stud H/L' : ('stud','studhilo')
} }
currencies = { u'':'EUR', '$':'USD', '':'T$' } currencies = { u'':'EUR', '$':'USD', '':'T$' }
if mg['CAP']:
info['limitType'] = 'cn'
else:
info['limitType'] = limits[mg['LIMIT']] info['limitType'] = limits[mg['LIMIT']]
info['sb'] = mg['SB'] info['sb'] = mg['SB']
info['bb'] = mg['BB'] info['bb'] = mg['BB']

View File

@ -57,16 +57,22 @@ class GuiGraphViewer (threading.Thread):
"Sites" : True, "Sites" : True,
"Games" : True, "Games" : True,
"Limits" : True, "Limits" : True,
"LimitSep" : True,
"LimitType" : True,
"Type" : False,
"UseType" : 'ring',
"Seats" : False, "Seats" : False,
"SeatSep" : False,
"Dates" : True, "Dates" : True,
"Groups" : False,
"Button1" : True, "Button1" : True,
"Button2" : True "Button2" : True
} }
self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display) self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
self.filters.registerButton1Name("Refresh Graph") self.filters.registerButton1Name("Refresh _Graph")
self.filters.registerButton1Callback(self.generateGraph) self.filters.registerButton1Callback(self.generateGraph)
self.filters.registerButton2Name("Export to File") self.filters.registerButton2Name("_Export to File")
self.filters.registerButton2Callback(self.exportGraph) self.filters.registerButton2Callback(self.exportGraph)
self.mainHBox = gtk.HBox(False, 0) self.mainHBox = gtk.HBox(False, 0)
@ -146,10 +152,8 @@ class GuiGraphViewer (threading.Thread):
raise raise
def generateGraph(self, widget, data): def generateGraph(self, widget, data):
print "generateGraph: start"
try: try:
self.clearGraphData() self.clearGraphData()
print "after cleardata"
sitenos = [] sitenos = []
playerids = [] playerids = []
@ -158,15 +162,18 @@ class GuiGraphViewer (threading.Thread):
heroes = self.filters.getHeroes() heroes = self.filters.getHeroes()
siteids = self.filters.getSiteIds() siteids = self.filters.getSiteIds()
limits = self.filters.getLimits() limits = self.filters.getLimits()
print "got filter data" for i in ('show', 'none'):
if i in limits:
limits.remove(i)
# Which sites are selected? # Which sites are selected?
for site in sites: for site in sites:
if sites[site] == True: if sites[site] == True:
sitenos.append(siteids[site]) sitenos.append(siteids[site])
self.db.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) c = self.db.get_cursor()
result = self.db.cursor.fetchall() c.execute(self.sql.query['getPlayerId'], (heroes[site],))
result = c.fetchall()
if len(result) == 1: if len(result) == 1:
playerids.append(result[0][0]) playerids.append( int(result[0][0]) )
if not sitenos: if not sitenos:
#Should probably pop up here. #Should probably pop up here.
@ -182,12 +189,10 @@ class GuiGraphViewer (threading.Thread):
return return
#Set graph properties #Set graph properties
print "add_subplot"
self.ax = self.fig.add_subplot(111) self.ax = self.fig.add_subplot(111)
#Get graph data from DB #Get graph data from DB
starttime = time() starttime = time()
print "get line: playerids =", playerids, "sitenos =", sitenos, "limits =", limits
line = self.getRingProfitGraph(playerids, sitenos, limits) line = self.getRingProfitGraph(playerids, sitenos, limits)
print "Graph generated in: %s" %(time() - starttime) print "Graph generated in: %s" %(time() - starttime)
@ -234,12 +239,31 @@ class GuiGraphViewer (threading.Thread):
# [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829) # [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829)
nametest = str(tuple(names)) nametest = str(tuple(names))
sitetest = str(tuple(sites)) sitetest = str(tuple(sites))
limittest = str(tuple(limits)) #nametest = nametest.replace("L", "")
nametest = nametest.replace("L", "")
nametest = nametest.replace(",)",")") lims = [int(x) for x in limits if x.isdigit()]
sitetest = sitetest.replace(",)",")") nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl']
limittest = limittest.replace("L", "") limittest = "and ( (gt.limitType = 'fl' and gt.bigBlind in "
limittest = limittest.replace(",)",")") # and ( (limit and bb in()) or (nolimit and bb in ()) )
if lims:
blindtest = str(tuple(lims))
blindtest = blindtest.replace("L", "")
blindtest = blindtest.replace(",)",")")
limittest = limittest + blindtest + ' ) '
else:
limittest = limittest + '(-1) ) '
limittest = limittest + " or (gt.limitType = 'nl' and gt.bigBlind in "
if nolims:
blindtest = str(tuple(nolims))
blindtest = blindtest.replace("L", "")
blindtest = blindtest.replace(",)",")")
limittest = limittest + blindtest + ' ) )'
else:
limittest = limittest + '(-1) ) )'
if type == 'ring':
limittest = limittest + " and gt.type = 'ring' "
elif type == 'tour':
limittest = limittest + " and gt.type = 'tour' "
#Must be a nicer way to deal with tuples of size 1 ie. (2,) - which makes sql barf #Must be a nicer way to deal with tuples of size 1 ie. (2,) - which makes sql barf
tmp = tmp.replace("<player_test>", nametest) tmp = tmp.replace("<player_test>", nametest)
@ -247,6 +271,7 @@ class GuiGraphViewer (threading.Thread):
tmp = tmp.replace("<startdate_test>", start_date) tmp = tmp.replace("<startdate_test>", start_date)
tmp = tmp.replace("<enddate_test>", end_date) tmp = tmp.replace("<enddate_test>", end_date)
tmp = tmp.replace("<limit_test>", limittest) tmp = tmp.replace("<limit_test>", limittest)
tmp = tmp.replace(",)", ")")
#print "DEBUG: sql query:" #print "DEBUG: sql query:"
#print tmp #print tmp
@ -255,10 +280,10 @@ class GuiGraphViewer (threading.Thread):
winnings = self.db.cursor.fetchall() winnings = self.db.cursor.fetchall()
self.db.rollback() self.db.rollback()
if(winnings == ()): if winnings == ():
return None return None
y=map(lambda x:float(x[3]), winnings) y = map(lambda x:float(x[1]), winnings)
line = cumsum(y) line = cumsum(y)
return line/100 return line/100
#end of def getRingProfitGraph #end of def getRingProfitGraph

View File

@ -59,6 +59,8 @@ class GuiPlayerStats (threading.Thread):
"Games" : False, "Games" : False,
"Limits" : True, "Limits" : True,
"LimitSep" : True, "LimitSep" : True,
"LimitType" : True,
"Type" : True,
"Seats" : True, "Seats" : True,
"SeatSep" : True, "SeatSep" : True,
"Dates" : True, "Dates" : True,
@ -157,6 +159,7 @@ class GuiPlayerStats (threading.Thread):
heroes = self.filters.getHeroes() heroes = self.filters.getHeroes()
siteids = self.filters.getSiteIds() siteids = self.filters.getSiteIds()
limits = self.filters.getLimits() limits = self.filters.getLimits()
type = self.filters.getType()
seats = self.filters.getSeats() seats = self.filters.getSeats()
groups = self.filters.getGroups() groups = self.filters.getGroups()
dates = self.filters.getDates() dates = self.filters.getDates()
@ -185,16 +188,16 @@ class GuiPlayerStats (threading.Thread):
print "No limits found" print "No limits found"
return return
self.createStatsTable(vbox, playerids, sitenos, limits, seats, groups, dates) self.createStatsTable(vbox, playerids, sitenos, limits, type, seats, groups, dates)
def createStatsTable(self, vbox, playerids, sitenos, limits, seats, groups, dates): def createStatsTable(self, vbox, playerids, sitenos, limits, type, seats, groups, dates):
starttime = time() starttime = time()
# Display summary table at top of page # Display summary table at top of page
# 3rd parameter passes extra flags, currently includes: # 3rd parameter passes extra flags, currently includes:
# holecards - whether to display card breakdown (True/False) # holecards - whether to display card breakdown (True/False)
flags = [False] flags = [False]
self.addTable(vbox, 'playerDetailedStats', flags, playerids, sitenos, limits, seats, groups, dates) self.addTable(vbox, 'playerDetailedStats', flags, playerids, sitenos, limits, type, seats, groups, dates)
# Separator # Separator
sep = gtk.HSeparator() sep = gtk.HSeparator()
@ -217,13 +220,13 @@ class GuiPlayerStats (threading.Thread):
# Detailed table # Detailed table
flags = [True] flags = [True]
self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats, groups, dates) self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, type, seats, groups, dates)
self.db.rollback() self.db.rollback()
print "Stats page displayed in %4.2f seconds" % (time() - starttime) print "Stats page displayed in %4.2f seconds" % (time() - starttime)
#end def fillStatsFrame(self, vbox): #end def fillStatsFrame(self, vbox):
def addTable(self, vbox, query, flags, playerids, sitenos, limits, seats, groups, dates): def addTable(self, vbox, query, flags, playerids, sitenos, limits, type, seats, groups, dates):
row = 0 row = 0
sqlrow = 0 sqlrow = 0
colalias,colshow,colheading,colxalign,colformat = 0,1,2,3,4 colalias,colshow,colheading,colxalign,colformat = 0,1,2,3,4
@ -231,7 +234,7 @@ class GuiPlayerStats (threading.Thread):
else: holecards = flags[0] else: holecards = flags[0]
tmp = self.sql.query[query] tmp = self.sql.query[query]
tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, seats, groups, dates) tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, type, seats, groups, dates)
self.cursor.execute(tmp) self.cursor.execute(tmp)
result = self.cursor.fetchall() result = self.cursor.fetchall()
colnames = [desc[0].lower() for desc in self.cursor.description] colnames = [desc[0].lower() for desc in self.cursor.description]
@ -317,9 +320,9 @@ class GuiPlayerStats (threading.Thread):
row += 1 row += 1
vbox.show_all() vbox.show_all()
#end def addTable(self, query, vars, playerids, sitenos, limits, seats): #end def addTable(self, query, vars, playerids, sitenos, limits, type, seats, groups, dates):
def refineQuery(self, query, flags, playerids, sitenos, limits, seats, groups, dates): def refineQuery(self, query, flags, playerids, sitenos, limits, type, seats, groups, dates):
if not flags: holecards = False if not flags: holecards = False
else: holecards = flags[0] else: holecards = flags[0]
@ -344,13 +347,30 @@ class GuiPlayerStats (threading.Thread):
query = query.replace('<groupbyseats>', '') query = query.replace('<groupbyseats>', '')
query = query.replace('<orderbyseats>', '') query = query.replace('<orderbyseats>', '')
if [x for x in limits if str(x).isdigit()]: lims = [int(x) for x in limits if x.isdigit()]
blindtest = str(tuple([x for x in limits if str(x).isdigit()])) nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl']
bbtest = "and ( (gt.limitType = 'fl' and gt.bigBlind in "
# and ( (limit and bb in()) or (nolimit and bb in ()) )
if lims:
blindtest = str(tuple(lims))
blindtest = blindtest.replace("L", "") blindtest = blindtest.replace("L", "")
blindtest = blindtest.replace(",)",")") blindtest = blindtest.replace(",)",")")
query = query.replace("<gtbigBlind_test>", " and gt.bigBlind in " + blindtest + " ") bbtest = bbtest + blindtest + ' ) '
else: else:
query = query.replace("<gtbigBlind_test>", "") bbtest = bbtest + '(-1) ) '
bbtest = bbtest + " or (gt.limitType = 'nl' and gt.bigBlind in "
if nolims:
blindtest = str(tuple(nolims))
blindtest = blindtest.replace("L", "")
blindtest = blindtest.replace(",)",")")
bbtest = bbtest + blindtest + ' ) )'
else:
bbtest = bbtest + '(-1) ) )'
if type == 'ring':
bbtest = bbtest + " and gt.type = 'ring' "
elif type == 'tour':
bbtest = bbtest + " and gt.type = 'tour' "
query = query.replace("<gtbigBlind_test>", bbtest)
if holecards: # pinch level variables for hole card query if holecards: # pinch level variables for hole card query
query = query.replace("<hgameTypeId>", "hp.startcards") query = query.replace("<hgameTypeId>", "hp.startcards")

View File

@ -4,8 +4,96 @@
<import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import> <import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import>
<hud_ui label="FPDB Menu - Right-click <!-- These values need some explaining
Left-Drag to Move" />
aggregate_ring_game_stats :
- True/False
- if set to True, includes data from other blind levels
- defaults to False
aggregate_tourney_stats :
- True/False
- if set to True, includes data from other blind levels
- defaults to True
stat_aggregation_range :
- A/S/T
- if set to A, includes stats from all time
- if set to S, includes stats from current sessions
- if set to T, includes stats from last N days; set value in hud_days
- defaults to A
aggregation_days :
- a numeric value
- if hud_style is set to 'T', this value tells how many days are
included in the stat calculation
- defaults to 90
- value not used by default, as depends on hud_style setting
aggregation_level_multiplier :
- float value
- defines how many blind levels are used for aggregation
- the logic is weird, at best
- if value is 100, almost all levels are included
- if value is 2.1, levels from half to double the current blind
level are included
- if value it 1, no aggregation is performed
- defaults to 1
The following values define how hero's stats are done
aggregate_hero_ring_game_stats :
- True/False
- if set to True, hero's data is calculated over multiple blind levels
- defaults to False
aggregate_hero_tourney_stats :
- True/False
- if set to True, hero's data is calculated over multiple blind levels
- defaults to False
hero_stat_aggregation_range :
- A/S/T
- if set to A, includes stats from all time
- if set to S, includes stats from current sessions
- if set to T, includes stats from last N days; set value in hud_days
- defaults to S
hero_aggregation_days :
- a numeric value
- if hero_stat_aggregation_range is set to 'T', this value tells
how many days are included in the stat calculation
- defaults to 30
- value not used by default, as depends on hud_style setting
hero_aggregation_level_multiplier :
- float value
- defines how many blind levels are used for aggregation
- the logic is weird, at best
- if value is 100, almost all levels are included
- if value is 2.1, levels from half to double the current blind
level are included
- if value it 1, no aggregation is performed
- defaults to 1
-->
<hud_ui
aggregate_ring_game_stats="False"
aggregate_tourney_stats="False"
stat_aggregation_range="A"
aggregation_days="90"
aggregation_level_multiplier="1"
aggregate_hero_ring_game_stats="False"
aggregate_hero_tourney_stats="True"
hero_stat_aggregation_range="S"
hero_aggregation_days="30"
hero_aggregation_level_multiplier="1"
label="FPDB Menu - Right-click
Left-Drag to Move"
/>
<supported_sites> <supported_sites>

View File

@ -56,23 +56,32 @@ import Database
import Tables import Tables
import Hud import Hud
# To add to config:
aggregate_stats = {"ring": False, "tour": False} # uses agg_bb_mult # HUD params:
hud_style = 'A' # A=All-time # - Set aggregate_ring and/or aggregate_tour to True is you want to include stats from other blind levels in the HUD display
# S=Session # - If aggregation is used, the value of agg_bb_mult determines how what levels are included, e.g.
# T=timed (last n days - set hud_days to required value) # if agg_bb_mult is 100, almost all levels are included in all HUD displays
# Future values may also include: # if agg_bb_mult is 2.1, levels from half to double the current blind level are included in the HUD
# H=Hands (last n hands) # - Set hud_style to A to see stats for all-time
hud_days = 90 # Max number of days from each player to use for hud stats # Set hud_style to S to only see stats for current session (currently this shows stats for the last 24 hours)
agg_bb_mult = 100 # 1 = no aggregation. When aggregating stats across levels larger blinds # Set hud_style to T to only see stats for the last N days (uses value in hud_days)
# must be < (agg_bb_mult * smaller blinds) to be aggregated # - Set hud_days to N to see stats for the last N days in the HUD (only applies if hud_style is T)
# ie. 100 will aggregate almost everything, 2 will probably agg just the def_hud_params = { # Settings for all players apart from program owner ('hero')
# next higher and lower levels into the current one, try 3/10/30/100 'aggregate_ring' : False
hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of session , 'aggregate_tour' : True
# (hands every 2 mins for 1 hour = one session, if followed , 'hud_style' : 'A'
# by a 40 minute gap and then more hands on same table that is , 'hud_days' : 90
# a new session) , 'agg_bb_mult' : 1 # 1 means no aggregation
#hud_hands = 0 # Max number of hands from each player to use for hud stats (not used) # , 'hud_session_gap' : 30 not currently used
# Second set of variables for hero - these settings only apply to the program owner
, 'h_aggregate_ring' : False
, 'h_aggregate_tour' : True
, 'h_hud_style' : 'S' # A(ll) / S(ession) / T(ime in days)
, 'h_hud_days' : 30
, 'h_agg_bb_mult' : 1 # 1 means no aggregation
# , 'h_hud_session_gap' : 30 not currently used
}
class HUD_main(object): class HUD_main(object):
"""A main() object to own both the read_stdin thread and the gui.""" """A main() object to own both the read_stdin thread and the gui."""
@ -82,6 +91,7 @@ class HUD_main(object):
self.db_name = db_name self.db_name = db_name
self.config = Configuration.Config(file=options.config, dbname=options.dbname) self.config = Configuration.Config(file=options.config, dbname=options.dbname)
self.hud_dict = {} self.hud_dict = {}
self.hud_params = self.config.get_hud_ui_parameters()
# a thread to read stdin # a thread to read stdin
gobject.threads_init() # this is required gobject.threads_init() # this is required
@ -104,12 +114,17 @@ class HUD_main(object):
# called by an event in the HUD, to kill this specific HUD # called by an event in the HUD, to kill this specific HUD
if table in self.hud_dict: if table in self.hud_dict:
self.hud_dict[table].kill() self.hud_dict[table].kill()
try:
# throws exception in windows sometimes (when closing using main_window menu?)
self.hud_dict[table].main_window.destroy() self.hud_dict[table].main_window.destroy()
except:
pass
self.vb.remove(self.hud_dict[table].tablehudlabel) self.vb.remove(self.hud_dict[table].tablehudlabel)
del(self.hud_dict[table]) del(self.hud_dict[table])
self.main_window.resize(1,1) self.main_window.resize(1,1)
def create_HUD(self, new_hand_id, table, table_name, max, poker_game, stat_dict, cards): def create_HUD(self, new_hand_id, table, table_name, max, poker_game, type, stat_dict, cards):
"""type is "ring" or "tour" used to set hud_params"""
def idle_func(): def idle_func():
@ -135,6 +150,18 @@ class HUD_main(object):
self.hud_dict[table_name].table_name = table_name self.hud_dict[table_name].table_name = table_name
self.hud_dict[table_name].stat_dict = stat_dict self.hud_dict[table_name].stat_dict = stat_dict
self.hud_dict[table_name].cards = cards self.hud_dict[table_name].cards = cards
if type == "tour" and self.hud_params['aggregate_tour'] == False:
self.hud_dict[table_name].hud_params['agg_bb_mult'] = 1
elif type == "ring" and self.hud_params['aggregate_ring'] == False:
self.hud_dict[table_name].hud_params['agg_bb_mult'] = 1
if type == "tour" and self.hud_params['h_aggregate_tour'] == False:
self.hud_dict[table_name].hud_params['h_agg_bb_mult'] = 1
elif type == "ring" and self.hud_params['h_aggregate_ring'] == False:
self.hud_dict[table_name].hud_params['h_agg_bb_mult'] = 1
self.hud_params['aggregate_ring'] == True
self.hud_params['h_aggregate_ring'] == True
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[table_name].aux_windows] [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[table_name].aux_windows]
gobject.idle_add(idle_func) gobject.idle_add(idle_func)
@ -160,10 +187,19 @@ class HUD_main(object):
# be passed to HUDs for use in the gui thread. HUD objects should not # be passed to HUDs for use in the gui thread. HUD objects should not
# need their own access to the database, but should open their own # need their own access to the database, but should open their own
# if it is required. # if it is required.
try:
self.db_connection = Database.Database(self.config) self.db_connection = Database.Database(self.config)
self.db_connection.init_hud_stat_vars(hud_days)
tourny_finder = re.compile('(\d+) (\d+)') tourny_finder = re.compile('(\d+) (\d+)')
# get hero's screen names and player ids
self.hero, self.hero_ids = {}, {}
for site in self.config.get_supported_sites():
result = self.db_connection.get_site_id(site)
if result:
site_id = result[0][0]
self.hero[site_id] = self.config.supported_sites[site].screen_name
self.hero_ids[site_id] = self.db_connection.get_player_id(self.config, site, self.hero[site_id])
while 1: # wait for a new hand number on stdin while 1: # wait for a new hand number on stdin
new_hand_id = sys.stdin.readline() new_hand_id = sys.stdin.readline()
new_hand_id = string.rstrip(new_hand_id) new_hand_id = string.rstrip(new_hand_id)
@ -173,9 +209,7 @@ class HUD_main(object):
# get basic info about the new hand from the db # get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed # if there is a db error, complain, skip hand, and proceed
try: try:
(table_name, max, poker_game, type) = self.db_connection.get_table_name(new_hand_id) (table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id)
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, aggregate_stats[type]
,hud_style, agg_bb_mult)
cards = self.db_connection.get_cards(new_hand_id) cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id) comm_cards = self.db_connection.get_common_cards(new_hand_id)
@ -203,6 +237,17 @@ class HUD_main(object):
# Update an existing HUD # Update an existing HUD
if temp_key in self.hud_dict: if temp_key in self.hud_dict:
try:
# get stats using hud's specific params
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days']
, self.hud_dict[temp_key].hud_params['h_hud_days'])
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id])
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
self.hud_dict[temp_key].stat_dict = stat_dict self.hud_dict[temp_key].stat_dict = stat_dict
self.hud_dict[temp_key].cards = cards self.hud_dict[temp_key].cards = cards
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows] [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows]
@ -210,6 +255,16 @@ class HUD_main(object):
# Or create a new HUD # Or create a new HUD
else: else:
try:
# get stats using default params
self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] )
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params, self.hero_ids[site_id])
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
if type == "tour": if type == "tour":
tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number) tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number)
else: else:
@ -220,8 +275,11 @@ class HUD_main(object):
table_name = "%s %s" % (tour_number, tab_number) table_name = "%s %s" % (tour_number, tab_number)
sys.stderr.write("table name "+table_name+" not found, skipping.\n") sys.stderr.write("table name "+table_name+" not found, skipping.\n")
else: else:
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, stat_dict, cards) self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards)
self.db_connection.connection.rollback() self.db_connection.connection.rollback()
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if __name__== "__main__": if __name__== "__main__":

View File

@ -194,64 +194,32 @@ dealt whether they were seen in a 'dealt to' line
""" Function to insert Hand into database """ Function to insert Hand into database
Should not commit, and do minimal selects. Callers may want to cache commits Should not commit, and do minimal selects. Callers may want to cache commits
db: a connected fpdb_db object""" db: a connected fpdb_db object"""
# TODO:
#####
# Players, Gametypes, TourneyTypes are all shared functions that are needed for additional tables
# These functions are intended for prep insert eventually
#####
# Players - base playerid and siteid tuple # Players - base playerid and siteid tuple
sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId) sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId)
#Gametypes #Gametypes
gtid = db.getGameTypeId(self.siteId, self.gametype) gtid = db.getGameTypeId(self.siteId, self.gametype)
self.stats.assembleHands(self)
#####
# End prep functions
#####
# HudCache data to come from DerivedStats class # HudCache data to come from DerivedStats class
# HandsActions - all actions for all players for all streets - self.actions # HandsActions - all actions for all players for all streets - self.actions
# Hands - Summary information of hand indexed by handId - gameinfo # Hands - Summary information of hand indexed by handId - gameinfo
#This should be moved to prepInsert hh = self.stats.getHands()
hh = {}
hh['siteHandNo'] = self.handid
hh['handStart'] = self.starttime
hh['gameTypeId'] = gtid hh['gameTypeId'] = gtid
# seats TINYINT NOT NULL, # seats TINYINT NOT NULL,
hh['tableName'] = self.tablename
hh['maxSeats'] = self.maxseats
hh['seats'] = len(sqlids) hh['seats'] = len(sqlids)
# Flop turn and river may all be empty - add (likely) too many elements and trim with range
boardcards = self.board['FLOP'] + self.board['TURN'] + self.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x']
cards = [Card.encodeCard(c) for c in boardcards[0:5]]
hh['boardcard1'] = cards[0]
hh['boardcard2'] = cards[1]
hh['boardcard3'] = cards[2]
hh['boardcard4'] = cards[3]
hh['boardcard5'] = cards[4]
# texture smallint,
# playersVpi SMALLINT NOT NULL, /* num of players vpi */
# Needs to be recorded
# playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */
# Needs to be recorded
# playersAtStreet2 SMALLINT NOT NULL,
# Needs to be recorded
# playersAtStreet3 SMALLINT NOT NULL,
# Needs to be recorded
# playersAtStreet4 SMALLINT NOT NULL,
# Needs to be recorded
# playersAtShowdown SMALLINT NOT NULL,
# Needs to be recorded
# street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */
# Needs to be recorded
# street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */
# Needs to be recorded
# street2Raises TINYINT NOT NULL, /* num big bets paid to see river/street6 */
# Needs to be recorded
# street3Raises TINYINT NOT NULL, /* num big bets paid to see sd/street7 */
# Needs to be recorded
# street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */
# Needs to be recorded
#print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % self.getStreetTotals()
#FIXME: Pot size still in decimal, needs to be converted to cents
(hh['street1Pot'], hh['street2Pot'], hh['street3Pot'], hh['street4Pot'], hh['showdownPot']) = self.getStreetTotals()
# comment TEXT,
# commentTs DATETIME
#print hh #print hh
handid = db.storeHand(hh) handid = db.storeHand(hh)
# HandsPlayers - ? ... Do we fix winnings? # HandsPlayers - ? ... Do we fix winnings?
@ -603,7 +571,11 @@ Map the tuple self.gametype onto the pokerstars string describing it
return gs + timestr return gs + timestr
def writeTableLine(self): def writeTableLine(self):
table_string = "Table \'%s\' %s-max" % (self.tablename, self.maxseats) table_string = "Table "
if self.gametype['type'] == 'tour':
table_string = table_string + "\'%s %s\' %s-max" % (self.tourNo, self.tablename, self.maxseats)
else:
table_string = table_string + "\'%s\' %s-max" % (self.tablename, self.maxseats)
if self.gametype['currency'] == 'play': if self.gametype['currency'] == 'play':
table_string = table_string + " (Play Money)" table_string = table_string + " (Play Money)"
if self.buttonpos != None and self.buttonpos != 0: if self.buttonpos != None and self.buttonpos != 0:
@ -673,7 +645,14 @@ class HoldemOmahaHand(Hand):
if shown: self.shown.add(player) if shown: self.shown.add(player)
if mucked: self.mucked.add(player) if mucked: self.mucked.add(player)
else: else:
if len(cards) in (2, 4): # avoid adding board by mistake (Everleaf problem)
self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt) self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt)
elif len(cards) == 5: # cards holds a winning hand, not hole cards
# filter( lambda x: x not in b, a ) # calcs a - b where a and b are lists
# so diff is set to the winning hand minus the board cards, if we're lucky that leaves the hole cards
diff = filter( lambda x: x not in self.board['FLOP']+self.board['TURN']+self.board['RIVER'], cards )
if len(diff) == 2 and self.gametype['category'] in ('holdem'):
self.addHoleCards('PREFLOP', player, open=[], closed=diff, shown=shown, mucked=mucked, dealt=dealt)
def getStreetTotals(self): def getStreetTotals(self):
# street1Pot INT, /* pot size at flop/street4 */ # street1Pot INT, /* pot size at flop/street4 */

View File

@ -73,6 +73,8 @@ class Hud:
self.stacked = True self.stacked = True
self.site = table.site self.site = table.site
self.mw_created = False self.mw_created = False
self.hud_params = parent.hud_params
self.stat_windows = {} self.stat_windows = {}
self.popup_windows = {} self.popup_windows = {}
@ -145,6 +147,147 @@ class Hud:
menu.append(repositem) menu.append(repositem)
repositem.connect("activate", self.reposition_windows) repositem.connect("activate", self.reposition_windows)
aggitem = gtk.MenuItem('Show Player Stats')
menu.append(aggitem)
self.aggMenu = gtk.Menu()
aggitem.set_submenu(self.aggMenu)
# set agg_bb_mult to 1 to stop aggregation
item = gtk.CheckMenuItem('For This Blind Level Only')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, ('P',1))
setattr(self, 'h_aggBBmultItem1', item)
#
item = gtk.MenuItem('For Multiple Blind Levels:')
self.aggMenu.append(item)
#
item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, ('P',2))
setattr(self, 'h_aggBBmultItem2', item)
#
item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, ('P',3))
setattr(self, 'h_aggBBmultItem3', item)
#
item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, ('P',10))
setattr(self, 'h_aggBBmultItem10', item)
#
item = gtk.CheckMenuItem(' All Levels')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, ('P',10000))
setattr(self, 'h_aggBBmultItem10000', item)
#
item = gtk.MenuItem('Since:')
self.aggMenu.append(item)
#
item = gtk.CheckMenuItem(' All Time')
self.aggMenu.append(item)
item.connect("activate", self.set_hud_style, ('P','A'))
setattr(self, 'h_hudStyleOptionA', item)
#
item = gtk.CheckMenuItem(' Session')
self.aggMenu.append(item)
item.connect("activate", self.set_hud_style, ('P','S'))
setattr(self, 'h_hudStyleOptionS', item)
#
item = gtk.CheckMenuItem(' %s Days' % (self.hud_params['h_hud_days']))
self.aggMenu.append(item)
item.connect("activate", self.set_hud_style, ('P','T'))
setattr(self, 'h_hudStyleOptionT', item)
aggitem = gtk.MenuItem('Show Opponent Stats')
menu.append(aggitem)
self.aggMenu = gtk.Menu()
aggitem.set_submenu(self.aggMenu)
# set agg_bb_mult to 1 to stop aggregation
item = gtk.CheckMenuItem('For This Blind Level Only')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, ('O',1))
setattr(self, 'aggBBmultItem1', item)
#
item = gtk.MenuItem('For Multiple Blind Levels:')
self.aggMenu.append(item)
#
item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, ('O',2))
setattr(self, 'aggBBmultItem2', item)
#
item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, ('O',3))
setattr(self, 'aggBBmultItem3', item)
#
item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, ('O',10))
setattr(self, 'aggBBmultItem10', item)
#
item = gtk.CheckMenuItem(' All Levels')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, ('O',10000))
setattr(self, 'aggBBmultItem10000', item)
#
item = gtk.MenuItem('Since:')
self.aggMenu.append(item)
#
item = gtk.CheckMenuItem(' All Time')
self.aggMenu.append(item)
item.connect("activate", self.set_hud_style, ('O','A'))
setattr(self, 'hudStyleOptionA', item)
#
item = gtk.CheckMenuItem(' Session')
self.aggMenu.append(item)
item.connect("activate", self.set_hud_style, ('O','S'))
setattr(self, 'hudStyleOptionS', item)
#
item = gtk.CheckMenuItem(' %s Days' % (self.hud_params['h_hud_days']))
self.aggMenu.append(item)
item.connect("activate", self.set_hud_style, ('O','T'))
setattr(self, 'hudStyleOptionT', item)
# set active on current options:
if self.hud_params['h_agg_bb_mult'] == 1:
getattr(self, 'h_aggBBmultItem1').set_active(True)
elif self.hud_params['h_agg_bb_mult'] == 2:
getattr(self, 'h_aggBBmultItem2').set_active(True)
elif self.hud_params['h_agg_bb_mult'] == 3:
getattr(self, 'h_aggBBmultItem3').set_active(True)
elif self.hud_params['h_agg_bb_mult'] == 10:
getattr(self, 'h_aggBBmultItem10').set_active(True)
elif self.hud_params['h_agg_bb_mult'] > 9000:
getattr(self, 'h_aggBBmultItem10000').set_active(True)
#
if self.hud_params['agg_bb_mult'] == 1:
getattr(self, 'aggBBmultItem1').set_active(True)
elif self.hud_params['agg_bb_mult'] == 2:
getattr(self, 'aggBBmultItem2').set_active(True)
elif self.hud_params['agg_bb_mult'] == 3:
getattr(self, 'aggBBmultItem3').set_active(True)
elif self.hud_params['agg_bb_mult'] == 10:
getattr(self, 'aggBBmultItem10').set_active(True)
elif self.hud_params['agg_bb_mult'] > 9000:
getattr(self, 'aggBBmultItem10000').set_active(True)
#
if self.hud_params['h_hud_style'] == 'A':
getattr(self, 'h_hudStyleOptionA').set_active(True)
elif self.hud_params['h_hud_style'] == 'S':
getattr(self, 'h_hudStyleOptionS').set_active(True)
elif self.hud_params['h_hud_style'] == 'T':
getattr(self, 'h_hudStyleOptionT').set_active(True)
#
if self.hud_params['hud_style'] == 'A':
getattr(self, 'hudStyleOptionA').set_active(True)
elif self.hud_params['hud_style'] == 'S':
getattr(self, 'hudStyleOptionS').set_active(True)
elif self.hud_params['hud_style'] == 'T':
getattr(self, 'hudStyleOptionT').set_active(True)
eventbox.connect_object("button-press-event", self.on_button_press, menu)
debugitem = gtk.MenuItem('Debug StatWindows') debugitem = gtk.MenuItem('Debug StatWindows')
menu.append(debugitem) menu.append(debugitem)
debugitem.connect("activate", self.debug_stat_windows) debugitem.connect("activate", self.debug_stat_windows)
@ -177,9 +320,58 @@ class Hud:
self.create(*self.creation_attrs) self.create(*self.creation_attrs)
self.update(self.hand, self.config) self.update(self.hand, self.config)
except Exception, e: except Exception, e:
print "Expcetion:",str(e) print "Exception:",str(e)
pass pass
def set_aggregation(self, widget, val):
(player_opp, num) = val
if player_opp == 'P':
# set these true all the time, set the multiplier to 1 to turn agg off:
self.hud_params['h_aggregate_ring'] = True
self.hud_params['h_aggregate_tour'] = True
if self.hud_params['h_agg_bb_mult'] != num \
and getattr(self, 'h_aggBBmultItem'+str(num)).get_active():
print 'set_player_aggregation', num
self.hud_params['h_agg_bb_mult'] = num
for mult in ('1', '2', '3', '10', '10000'):
if mult != str(num):
getattr(self, 'h_aggBBmultItem'+mult).set_active(False)
else:
self.hud_params['aggregate_ring'] = True
self.hud_params['aggregate_tour'] = True
if self.hud_params['agg_bb_mult'] != num \
and getattr(self, 'aggBBmultItem'+str(num)).get_active():
print 'set_opponent_aggregation', num
self.hud_params['agg_bb_mult'] = num
for mult in ('1', '2', '3', '10', '10000'):
if mult != str(num):
getattr(self, 'aggBBmultItem'+mult).set_active(False)
def set_hud_style(self, widget, val):
(player_opp, style) = val
if player_opp == 'P':
param = 'h_hud_style'
prefix = 'h_'
else:
param = 'hud_style'
prefix = ''
if style == 'A' and getattr(self, prefix+'hudStyleOptionA').get_active():
self.hud_params[param] = 'A'
getattr(self, prefix+'hudStyleOptionS').set_active(False)
getattr(self, prefix+'hudStyleOptionT').set_active(False)
elif style == 'S' and getattr(self, prefix+'hudStyleOptionS').get_active():
self.hud_params[param] = 'S'
getattr(self, prefix+'hudStyleOptionA').set_active(False)
getattr(self, prefix+'hudStyleOptionT').set_active(False)
elif style == 'T' and getattr(self, prefix+'hudStyleOptionT').get_active():
self.hud_params[param] = 'T'
getattr(self, prefix+'hudStyleOptionA').set_active(False)
getattr(self, prefix+'hudStyleOptionS').set_active(False)
print "setting self.hud_params[%s] = %s" % (param, style)
def update_table_position(self): def update_table_position(self):
if os.name == 'nt': if os.name == 'nt':
if not win32gui.IsWindow(self.table.number): if not win32gui.IsWindow(self.table.number):
@ -219,7 +411,11 @@ class Hud:
# heap dead, burnt bodies, blood 'n guts, veins between my teeth # heap dead, burnt bodies, blood 'n guts, veins between my teeth
for s in self.stat_windows.itervalues(): for s in self.stat_windows.itervalues():
s.kill_popups() s.kill_popups()
try:
# throws "invalid window handle" in WinXP (sometimes?)
s.window.destroy() s.window.destroy()
except:
pass
self.stat_windows = {} self.stat_windows = {}
# also kill any aux windows # also kill any aux windows
for aux in self.aux_windows: for aux in self.aux_windows:

View File

@ -331,7 +331,8 @@ class Sql:
speed varchar(10), speed varchar(10),
headsUp BOOLEAN NOT NULL DEFAULT False, headsUp BOOLEAN NOT NULL DEFAULT False,
shootout BOOLEAN NOT NULL DEFAULT False, shootout BOOLEAN NOT NULL DEFAULT False,
matrix BOOLEAN NOT NULL DEFAULT False matrix BOOLEAN NOT NULL DEFAULT False,
sng BOOLEAN NOT NULL DEFAULT False
) )
ENGINE=INNODB""" ENGINE=INNODB"""
elif db_server == 'postgresql': elif db_server == 'postgresql':
@ -346,7 +347,8 @@ class Sql:
speed varchar(10), speed varchar(10),
headsUp BOOLEAN NOT NULL DEFAULT False, headsUp BOOLEAN NOT NULL DEFAULT False,
shootout BOOLEAN NOT NULL DEFAULT False, shootout BOOLEAN NOT NULL DEFAULT False,
matrix BOOLEAN NOT NULL DEFAULT False matrix BOOLEAN NOT NULL DEFAULT False,
sng BOOLEAN NOT NULL DEFAULT False
)""" )"""
elif db_server == 'sqlite': elif db_server == 'sqlite':
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes ( self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
@ -360,7 +362,8 @@ class Sql:
speed TEXT, speed TEXT,
headsUp BOOLEAN NOT NULL DEFAULT 0, headsUp BOOLEAN NOT NULL DEFAULT 0,
shootout BOOLEAN NOT NULL DEFAULT 0, shootout BOOLEAN NOT NULL DEFAULT 0,
matrix BOOLEAN NOT NULL DEFAULT 0 matrix BOOLEAN NOT NULL DEFAULT 0,
sng BOOLEAN NOT NULL DEFAULT 0
)""" )"""
################################ ################################
@ -820,7 +823,21 @@ class Sql:
comment TEXT, comment TEXT,
commentTs timestamp without time zone)""" commentTs timestamp without time zone)"""
elif db_server == 'sqlite': elif db_server == 'sqlite':
self.query['createTourneysPlayersTable'] = """ """ self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers (
id INT PRIMARY KEY,
tourneyId INT,
playerId INT,
payinAmount INT,
rank INT,
winnings INT,
nbRebuys INT DEFAULT 0,
nbAddons INT DEFAULT 0,
nbKO INT DEFAULT 0,
comment TEXT,
commentTs timestamp without time zone,
FOREIGN KEY (tourneyId) REFERENCES Tourneys(id),
FOREIGN KEY (playerId) REFERENCES Players(id)
)"""
################################ ################################
@ -851,7 +868,18 @@ class Sql:
comment TEXT, comment TEXT,
commentTs timestamp without time zone)""" commentTs timestamp without time zone)"""
elif db_server == 'sqlite': elif db_server == 'sqlite':
self.query['createHandsActionsTable'] = """ """ self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions (
id INT PRIMARY KEY,
handsPlayerId BIGINT,
street SMALLINT,
actionNo SMALLINT,
action CHAR(5),
allIn INT,
amount INT,
comment TEXT,
commentTs timestamp without time zone,
FOREIGN KEY (handsPlayerId) REFERENCES HandsPlayers(id)
)"""
################################ ################################
@ -1160,26 +1188,42 @@ class Sql:
if db_server == 'mysql': if db_server == 'mysql':
self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)""" self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD UNIQUE INDEX siteTourneyNo(siteTourneyNo, tourneyTypeId)"""
elif db_server == 'postgresql': elif db_server == 'postgresql':
self.query['addTourneyIndex'] = """CREATE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo, tourneyTypeId)"""
elif db_server == 'sqlite': elif db_server == 'sqlite':
self.query['addHandsIndex'] = """ """ self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo, tourneyTypeId)"""
if db_server == 'mysql': if db_server == 'mysql':
self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)""" self.query['addHandsIndex'] = """ALTER TABLE Hands ADD UNIQUE INDEX siteHandNo(siteHandNo, gameTypeId)"""
elif db_server == 'postgresql': elif db_server == 'postgresql':
self.query['addHandsIndex'] = """CREATE INDEX siteHandNo ON Hands (siteHandNo)""" self.query['addHandsIndex'] = """CREATE UNIQUE INDEX siteHandNo ON Hands (siteHandNo, gameTypeId)"""
elif db_server == 'sqlite': elif db_server == 'sqlite':
self.query['addHandsIndex'] = """ """ self.query['addHandsIndex'] = """CREATE UNIQUE INDEX siteHandNo ON Hands (siteHandNo, gameTypeId)"""
if db_server == 'mysql': if db_server == 'mysql':
self.query['addPlayersIndex'] = """ALTER TABLE Players ADD INDEX name(name)""" self.query['addPlayersIndex'] = """ALTER TABLE Players ADD UNIQUE INDEX name(name, siteId)"""
elif db_server == 'postgresql': elif db_server == 'postgresql':
self.query['addPlayersIndex'] = """CREATE INDEX name ON Players (name)""" self.query['addPlayersIndex'] = """CREATE UNIQUE INDEX name ON Players (name, siteId)"""
elif db_server == 'sqlite': elif db_server == 'sqlite':
self.query['addPlayersIndex'] = """ """ self.query['addPlayersIndex'] = """CREATE UNIQUE INDEX name ON Players (name, siteId)"""
if db_server == 'mysql':
self.query['addTPlayersIndex'] = """ALTER TABLE TourneysPlayers ADD UNIQUE INDEX tourneyId(tourneyId, playerId)"""
elif db_server == 'postgresql':
self.query['addTPlayersIndex'] = """CREATE UNIQUE INDEX tourneyId ON TourneysPlayers (tourneyId, playerId)"""
elif db_server == 'sqlite':
self.query['addTPlayersIndex'] = """CREATE UNIQUE INDEX tourneyId ON TourneysPlayers (tourneyId, playerId)"""
if db_server == 'mysql':
self.query['addTTypesIndex'] = """ALTER TABLE TourneyTypes ADD UNIQUE INDEX tourneytypes_all(buyin, fee
, maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)"""
elif db_server == 'postgresql':
self.query['addTTypesIndex'] = """CREATE UNIQUE INDEX tourneyTypes_all ON TourneyTypes (buyin, fee
, maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)"""
elif db_server == 'sqlite':
self.query['addTTypesIndex'] = """CREATE UNIQUE INDEX tourneyTypes_all ON TourneyTypes (buyin, fee
, maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)"""
self.query['get_last_hand'] = "select max(id) from Hands" self.query['get_last_hand'] = "select max(id) from Hands"
@ -1188,7 +1232,14 @@ class Sql:
from Players, Sites from Players, Sites
where Players.name = %s where Players.name = %s
and Sites.name = %s and Sites.name = %s
and Players.SiteId = Sites.id and Players.siteId = Sites.id
"""
self.query['get_player_names'] = """
select p.name
from Players p
where lower(p.name) like lower(%s)
and (p.siteId = %s or %s = -1)
""" """
self.query['getSiteId'] = """SELECT id from Sites where name = %s""" self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
@ -1340,28 +1391,45 @@ class Sql:
INNER JOIN HudCache hc ON (hc.playerId = hp.playerId) INNER JOIN HudCache hc ON (hc.playerId = hp.playerId)
INNER JOIN Players p ON (p.id = hc.playerId) INNER JOIN Players p ON (p.id = hc.playerId)
WHERE h.id = %s WHERE h.id = %s
AND ( /* 2 separate parts for hero and opponents */
( hp.playerId != %s
AND hc.styleKey > %s AND hc.styleKey > %s
/* styleKey is currently 'd' (for date) followed by a yyyymmdd
date key. Set it to 0000000 or similar to get all records */
/* Note: s means the placeholder 'percent's but we can't include that
in comments. (db api thinks they are actual arguments)
Could also check activeseats here even if only 3 groups eg 2-3/4-6/7+
e.g. could use a multiplier:
AND h.seats > s / 1.25 and hp.seats < s * 1.25
where s is the number of active players at the current table (and
1.25 would be a config value so user could change it)
*/
AND hc.gametypeId+0 in AND hc.gametypeId+0 in
(SELECT gt1.id from Gametypes gt1, Gametypes gt2 (SELECT gt1.id from Gametypes gt1, Gametypes gt2
WHERE gt1.siteid = gt2.siteid /* find gametypes where these match: */ WHERE gt1.siteid = gt2.siteid /* find gametypes where these match: */
AND gt1.type = gt2.type /* ring/tourney */ AND gt1.type = gt2.type /* ring/tourney */
AND gt1.category = gt2.category /* holdem/stud*/ AND gt1.category = gt2.category /* holdem/stud*/
AND gt1.limittype = gt2.limittype /* fl/nl */ AND gt1.limittype = gt2.limittype /* fl/nl */
AND gt1.bigblind < gt2.bigblind * %s /* bigblind similar size */ AND gt1.bigblind <= gt2.bigblind * %s /* bigblind similar size */
AND gt1.bigblind > gt2.bigblind / %s AND gt1.bigblind >= gt2.bigblind / %s
AND gt2.id = h.gametypeId) AND gt2.id = h.gametypeId)
)
OR
( hp.playerId = %s
AND hc.styleKey > %s
AND hc.gametypeId+0 in
(SELECT gt1.id from Gametypes gt1, Gametypes gt2
WHERE gt1.siteid = gt2.siteid /* find gametypes where these match: */
AND gt1.type = gt2.type /* ring/tourney */
AND gt1.category = gt2.category /* holdem/stud*/
AND gt1.limittype = gt2.limittype /* fl/nl */
AND gt1.bigblind <= gt2.bigblind * %s /* bigblind similar size */
AND gt1.bigblind >= gt2.bigblind / %s
AND gt2.id = h.gametypeId)
)
)
GROUP BY hc.PlayerId, p.name GROUP BY hc.PlayerId, p.name
""" """
# NOTES on above cursor:
# - Do NOT include %s inside query in a comment - the db api thinks
# they are actual arguments.
# - styleKey is currently 'd' (for date) followed by a yyyymmdd
# date key. Set it to 0000000 or similar to get all records
# Could also check activeseats here even if only 3 groups eg 2-3/4-6/7+
# e.g. could use a multiplier:
# AND h.seats > %s / 1.25 and hp.seats < %s * 1.25
# where %s is the number of active players at the current table (and
# 1.25 would be a config value so user could change it)
if db_server == 'mysql': if db_server == 'mysql':
self.query['get_stats_from_hand_session'] = """ self.query['get_stats_from_hand_session'] = """
@ -1537,10 +1605,11 @@ class Sql:
""" """
self.query['get_table_name'] = """ self.query['get_table_name'] = """
select tableName, maxSeats, category, type select h.tableName, h.maxSeats, gt.category, gt.type, gt.siteId
from Hands,Gametypes from Hands h
where Hands.id = %s ,Gametypes gt
and Gametypes.id = Hands.gametypeId where h.id = %s
and gt.id = h.gametypeId
""" """
self.query['get_actual_seat'] = """ self.query['get_actual_seat'] = """
@ -1651,6 +1720,9 @@ class Sql:
self.query['getSiteId'] = """SELECT id from Sites where name = %s""" self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
self.query['getGames'] = """SELECT DISTINCT category from Gametypes""" self.query['getGames'] = """SELECT DISTINCT category from Gametypes"""
self.query['getLimits'] = """SELECT DISTINCT bigBlind from Gametypes ORDER by bigBlind DESC""" self.query['getLimits'] = """SELECT DISTINCT bigBlind from Gametypes ORDER by bigBlind DESC"""
self.query['getLimits2'] = """SELECT DISTINCT type, limitType, bigBlind
from Gametypes
ORDER by type, limitType DESC, bigBlind DESC"""
if db_server == 'mysql': if db_server == 'mysql':
self.query['playerDetailedStats'] = """ self.query['playerDetailedStats'] = """
@ -1706,7 +1778,7 @@ class Sql:
inner join Gametypes gt on (gt.Id = h.gameTypeId) inner join Gametypes gt on (gt.Id = h.gameTypeId)
inner join Sites s on (s.Id = gt.siteId) inner join Sites s on (s.Id = gt.siteId)
where hp.playerId in <player_test> where hp.playerId in <player_test>
and hp.tourneysPlayersId IS NULL /*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test> and h.seats <seats_test>
<flagtest> <flagtest>
<gtbigBlind_test> <gtbigBlind_test>
@ -1728,11 +1800,11 @@ class Sql:
else concat('Z', <position>) else concat('Z', <position>)
end end
<orderbyhgameTypeId> <orderbyhgameTypeId>
,upper(gt.limitType) desc
,maxbigblind desc ,maxbigblind desc
,upper(gt.limitType)
,s.name ,s.name
""" """
else: # assume postgresql elif db_server == 'postgresql':
self.query['playerDetailedStats'] = """ self.query['playerDetailedStats'] = """
select <hgameTypeId> AS hgametypeid select <hgameTypeId> AS hgametypeid
,gt.base ,gt.base
@ -1786,7 +1858,7 @@ class Sql:
inner join Gametypes gt on (gt.Id = h.gameTypeId) inner join Gametypes gt on (gt.Id = h.gameTypeId)
inner join Sites s on (s.Id = gt.siteId) inner join Sites s on (s.Id = gt.siteId)
where hp.playerId in <player_test> where hp.playerId in <player_test>
and hp.tourneysPlayersId IS NULL /*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test> and h.seats <seats_test>
<flagtest> <flagtest>
<gtbigBlind_test> <gtbigBlind_test>
@ -1809,12 +1881,91 @@ class Sql:
else 'Z'||<position> else 'Z'||<position>
end end
<orderbyhgameTypeId> <orderbyhgameTypeId>
,upper(gt.limitType) desc
,maxbigblind desc
,s.name
"""
elif db_server == 'sqlite':
self.query['playerDetailedStats'] = """
select <hgameTypeId> AS hgametypeid
,gt.base
,gt.category
,upper(gt.limitType) AS limittype
,s.name
,min(gt.bigBlind) AS minbigblind
,max(gt.bigBlind) AS maxbigblind
/*,<hcgametypeId> AS gtid*/
,<position> AS plposition
,count(1) AS n
,100.0*sum(cast(hp.street0VPI as <signed>integer))/count(1) AS vpip
,100.0*sum(cast(hp.street0Aggr as <signed>integer))/count(1) AS pfr
,case when sum(cast(hp.street0_3Bchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street0_3Bdone as <signed>integer))/sum(cast(hp.street0_3Bchance as <signed>integer))
end AS pf3
,case when sum(cast(hp.stealattemptchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.stealattempted as <signed>integer))/sum(cast(hp.stealattemptchance as <signed>integer))
end AS steals
,100.0*sum(cast(hp.street1Seen as <signed>integer))/count(1) AS saw_f
,100.0*sum(cast(hp.sawShowdown as <signed>integer))/count(1) AS sawsd
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.sawShowdown as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
end AS wtsdwsf
,case when sum(cast(hp.sawShowdown as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.wonAtSD as <signed>integer))/sum(cast(hp.sawShowdown as <signed>integer))
end AS wmsd
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street1Aggr as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
end AS flafq
,case when sum(cast(hp.street2Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street2Aggr as <signed>integer))/sum(cast(hp.street2Seen as <signed>integer))
end AS tuafq
,case when sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street3Aggr as <signed>integer))/sum(cast(hp.street3Seen as <signed>integer))
end AS rvafq
,case when sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
else 100.0*(sum(cast(hp.street1Aggr as <signed>integer))+sum(cast(hp.street2Aggr as <signed>integer))+sum(cast(hp.street3Aggr as <signed>integer)))
/(sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)))
end AS pofafq
,sum(hp.totalProfit)/100.0 AS net
,sum(hp.rake)/100.0 AS rake
,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100
,avg(hp.totalProfit)/100.0 AS profitperhand
,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr
,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr
,avg(h.seats+0.0) AS avgseats
,variance(hp.totalProfit/100.0) AS variance
from HandsPlayers hp
inner join Hands h on (h.id = hp.handId)
inner join Gametypes gt on (gt.Id = h.gameTypeId)
inner join Sites s on (s.Id = gt.siteId)
where hp.playerId in <player_test>
/*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test>
<flagtest>
<gtbigBlind_test>
and to_char(h.handStart, 'YYYY-MM-DD') <datestest>
group by hgameTypeId
,hp.playerId
,gt.base
,gt.category
<groupbyseats>
,plposition
,upper(gt.limitType)
,s.name
order by hp.playerId
,gt.base
,gt.category
<orderbyseats>
,case <position> when 'B' then 'B'
when 'S' then 'S'
when '0' then 'Y'
else 'Z'||<position>
end
<orderbyhgameTypeId>
,upper(gt.limitType) desc
,maxbigblind desc ,maxbigblind desc
,upper(gt.limitType)
,s.name ,s.name
""" """
#elif db_server == 'sqlite':
# self.query['playerDetailedStats'] = """ """
if db_server == 'mysql': if db_server == 'mysql':
self.query['playerStats'] = """ self.query['playerStats'] = """
@ -2304,16 +2455,16 @@ class Sql:
# self.query['playerStatsByPosition'] = """ """ # self.query['playerStatsByPosition'] = """ """
self.query['getRingProfitAllHandsPlayerIdSite'] = """ self.query['getRingProfitAllHandsPlayerIdSite'] = """
SELECT hp.handId, hp.totalProfit, hp.totalProfit, hp.totalProfit SELECT hp.handId, hp.totalProfit
FROM HandsPlayers hp FROM HandsPlayers hp
INNER JOIN Players pl ON (hp.playerId = pl.id) INNER JOIN Players pl ON (pl.id = hp.playerId)
INNER JOIN Hands h ON (h.id = hp.handId) INNER JOIN Hands h ON (h.id = hp.handId)
INNER JOIN Gametypes g ON (h.gametypeId = g.id) INNER JOIN Gametypes gt ON (gt.id = h.gametypeId)
where pl.id in <player_test> WHERE pl.id in <player_test>
AND pl.siteId in <site_test> AND pl.siteId in <site_test>
AND h.handStart > '<startdate_test>' AND h.handStart > '<startdate_test>'
AND h.handStart < '<enddate_test>' AND h.handStart < '<enddate_test>'
AND g.bigBlind in <limit_test> <limit_test>
AND hp.tourneysPlayersId IS NULL AND hp.tourneysPlayersId IS NULL
GROUP BY h.handStart, hp.handId, hp.totalProfit GROUP BY h.handStart, hp.handId, hp.totalProfit
ORDER BY h.handStart""" ORDER BY h.handStart"""
@ -2466,6 +2617,7 @@ class Sql:
,sum(street4CheckCallRaiseDone) ,sum(street4CheckCallRaiseDone)
FROM HandsPlayers hp FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId) INNER JOIN Hands h ON (h.id = hp.handId)
<where_clause>
GROUP BY h.gametypeId GROUP BY h.gametypeId
,hp.playerId ,hp.playerId
,h.seats ,h.seats
@ -2614,6 +2766,7 @@ class Sql:
,sum(CAST(street4CheckCallRaiseDone as integer)) ,sum(CAST(street4CheckCallRaiseDone as integer))
FROM HandsPlayers hp FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId) INNER JOIN Hands h ON (h.id = hp.handId)
<where_clause>
GROUP BY h.gametypeId GROUP BY h.gametypeId
,hp.playerId ,hp.playerId
,h.seats ,h.seats
@ -2762,6 +2915,7 @@ class Sql:
,sum(CAST(street4CheckCallRaiseDone as integer)) ,sum(CAST(street4CheckCallRaiseDone as integer))
FROM HandsPlayers hp FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId) INNER JOIN Hands h ON (h.id = hp.handId)
<where_clause>
GROUP BY h.gametypeId GROUP BY h.gametypeId
,hp.playerId ,hp.playerId
,h.seats ,h.seats
@ -2770,9 +2924,14 @@ class Sql:
,'d' || substr(strftime('%Y%m%d', h.handStart),3,7) ,'d' || substr(strftime('%Y%m%d', h.handStart),3,7)
""" """
self.query['get_hero_hudcache_start'] = """select min(hc.styleKey)
from HudCache hc
where hc.playerId in <playerid_list>
and hc.styleKey like 'd%'"""
if db_server == 'mysql': if db_server == 'mysql':
self.query['analyze'] = """ self.query['analyze'] = """
analyze table Autorates, GameTypes, Hands, HandsPlayers, Hudcache, Players analyze table Autorates, GameTypes, Hands, HandsPlayers, HudCache, Players
, Settings, Sites, Tourneys, TourneysPlayers, TourneyTypes , Settings, Sites, Tourneys, TourneysPlayers, TourneyTypes
""" """
else: # assume postgres else: # assume postgres

View File

@ -257,6 +257,10 @@ def discover_nt_tournament(c, tour_number, tab_number):
titles ={} titles ={}
win32gui.EnumWindows(win_enum_handler, titles) win32gui.EnumWindows(win_enum_handler, titles)
for hwnd in titles: for hwnd in titles:
if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows
if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window
if 'HUD:' in titles[hwnd]: continue # FPDB HUD window
if re.search(search_string, titles[hwnd]): if re.search(search_string, titles[hwnd]):
return decode_windows(c, titles[hwnd], hwnd) return decode_windows(c, titles[hwnd], hwnd)
return None return None
@ -376,7 +380,7 @@ def clean_title(name):
"""Clean the little info strings from the table name.""" """Clean the little info strings from the table name."""
# these strings could go in a config file # these strings could go in a config file
for pattern in [' \(6 max\)', ' \(heads up\)', ' \(deep\)', for pattern in [' \(6 max\)', ' \(heads up\)', ' \(deep\)',
' \(deep hu\)', ' \(deep 6\)', ' \(2\)', ' \(deep hu\)', ' \(deep 6\)', '\(6 max, deep\)', ' \(2\)',
' \(edu\)', ' \(edu, 6 max\)', ' \(6\)', ' \(edu\)', ' \(edu, 6 max\)', ' \(6\)',
' \(speed\)', 'special', 'newVPP', ' \(speed\)', 'special', 'newVPP',
' no all-in', ' fast', ',', ' 50BB min', '50bb min', '\s+$']: ' no all-in', ' fast', ',', ' 50BB min', '50bb min', '\s+$']:

View File

@ -248,7 +248,7 @@ class ttracker_main(object):
# get basic info about the new hand from the db # get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed # if there is a db error, complain, skip hand, and proceed
try: try:
(table_name, max, poker_game, type) = self.db_connection.get_table_name(new_hand_id) (table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id)
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, aggregate_stats[type] stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, aggregate_stats[type]
,hud_style, agg_bb_mult) ,hud_style, agg_bb_mult)

View File

@ -44,6 +44,7 @@ else:
print "Python " + sys.version[0:3] + '...\n' print "Python " + sys.version[0:3] + '...\n'
import traceback
import threading import threading
import Options import Options
import string import string
@ -64,7 +65,6 @@ import gtk
import interlocks import interlocks
import fpdb_simple
import GuiBulkImport import GuiBulkImport
import GuiPlayerStats import GuiPlayerStats
import GuiPositionalStats import GuiPositionalStats
@ -234,13 +234,13 @@ class fpdb:
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING,
buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables") buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables")
diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database " \ diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database " \
+self.db.fdb.database+" on "+self.db.fdb.host+" they will be deleted." +self.db.database+" on "+self.db.host+" they will be deleted."
dia_confirm.format_secondary_text(diastring)#todo: make above string with bold for db, host and deleted dia_confirm.format_secondary_text(diastring)#todo: make above string with bold for db, host and deleted
response = dia_confirm.run() response = dia_confirm.run()
dia_confirm.destroy() dia_confirm.destroy()
if response == gtk.RESPONSE_YES: if response == gtk.RESPONSE_YES:
#if self.db.fdb.backend == self.fdb_lock.fdb.MYSQL_INNODB: #if self.db.backend == self.fdb_lock.fdb.MYSQL_INNODB:
# mysql requires locks on all tables or none - easier to release this lock # mysql requires locks on all tables or none - easier to release this lock
# than lock all the other tables # than lock all the other tables
# ToDo: lock all other tables so that lock doesn't have to be released # ToDo: lock all other tables so that lock doesn't have to be released
@ -257,18 +257,66 @@ class fpdb:
def dia_recreate_hudcache(self, widget, data=None): def dia_recreate_hudcache(self, widget, data=None):
if self.obtain_global_lock(): if self.obtain_global_lock():
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache") self.dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache")
diastring = "Please confirm that you want to re-create the HUD cache." diastring = "Please confirm that you want to re-create the HUD cache."
dia_confirm.format_secondary_text(diastring) self.dia_confirm.format_secondary_text(diastring)
response = dia_confirm.run() hb = gtk.HBox(True, 1)
dia_confirm.destroy() self.start_date = gtk.Entry(max=12)
self.start_date.set_text( self.db.get_hero_hudcache_start() )
lbl = gtk.Label(" Hero's cache starts: ")
btn = gtk.Button()
btn.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
btn.connect('clicked', self.__calendar_dialog, self.start_date)
hb.pack_start(lbl, expand=True, padding=3)
hb.pack_start(self.start_date, expand=True, padding=2)
hb.pack_start(btn, expand=False, padding=3)
self.dia_confirm.vbox.add(hb)
hb.show_all()
response = self.dia_confirm.run()
self.dia_confirm.destroy()
if response == gtk.RESPONSE_YES: if response == gtk.RESPONSE_YES:
self.db.rebuild_hudcache() self.db.rebuild_hudcache( self.start_date.get_text() )
elif response == gtk.REPSONSE_NO: elif response == gtk.RESPONSE_NO:
print 'User cancelled rebuilding hud cache' print 'User cancelled rebuilding hud cache'
self.release_global_lock() self.release_global_lock()
def __calendar_dialog(self, widget, entry):
self.dia_confirm.set_modal(False)
d = gtk.Window(gtk.WINDOW_TOPLEVEL)
d.set_title('Pick a date')
vb = gtk.VBox()
cal = gtk.Calendar()
vb.pack_start(cal, expand=False, padding=0)
btn = gtk.Button('Done')
btn.connect('clicked', self.__get_date, cal, entry, d)
vb.pack_start(btn, expand=False, padding=4)
d.add(vb)
d.set_position(gtk.WIN_POS_MOUSE)
d.show_all()
def __get_dates(self):
t1 = self.start_date.get_text()
if t1 == '':
t1 = '1970-01-01'
return (t1)
def __get_date(self, widget, calendar, entry, win):
# year and day are correct, month is 0..11
(year, month, day) = calendar.get_date()
month += 1
ds = '%04d-%02d-%02d' % (year, month, day)
entry.set_text(ds)
win.destroy()
self.dia_confirm.set_modal(True)
def dia_regression_test(self, widget, data=None): def dia_regression_test(self, widget, data=None):
self.warning_box("Unimplemented: Regression Test") self.warning_box("Unimplemented: Regression Test")
self.obtain_global_lock() self.obtain_global_lock()
@ -405,9 +453,25 @@ class fpdb:
self.db.disconnect() self.db.disconnect()
self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server'])
try:
self.db = Database.Database(self.config, sql = self.sql) self.db = Database.Database(self.config, sql = self.sql)
except FpdbMySQLFailedError:
self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR")
exit()
except FpdbError:
#print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])
self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR")
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']))
except:
#print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])
self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR")
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']))
if self.db.fdb.wrongDbVersion: if self.db.wrongDbVersion:
diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK))
label = gtk.Label("An invalid DB version or missing tables have been detected.") label = gtk.Label("An invalid DB version or missing tables have been detected.")
@ -426,14 +490,14 @@ class fpdb:
diaDbVersionWarning.destroy() diaDbVersionWarning.destroy()
if self.status_bar == None: if self.status_bar == None:
self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host)) self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.database, self.db.host))
self.main_vbox.pack_end(self.status_bar, False, True, 0) self.main_vbox.pack_end(self.status_bar, False, True, 0)
self.status_bar.show() self.status_bar.show()
else: else:
self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host)) self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.database, self.db.host))
# Database connected to successfully, load queries to pass on to other classes # Database connected to successfully, load queries to pass on to other classes
self.db.connection.rollback() self.db.rollback()
self.validate_config() self.validate_config()

View File

@ -38,6 +38,8 @@ class fpdb_db:
MYSQL_INNODB = 2 MYSQL_INNODB = 2
PGSQL = 3 PGSQL = 3
SQLITE = 4 SQLITE = 4
sqlite_db_dir = ".." + os.sep + "database"
def __init__(self): def __init__(self):
"""Simple constructor, doesnt really do anything""" """Simple constructor, doesnt really do anything"""
self.db = None self.db = None
@ -78,7 +80,7 @@ class fpdb_db:
try: try:
self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True)
except: except:
raise FpdbError("MySQL connection failed") raise FpdbMySQLFailedError("MySQL connection failed")
elif backend==fpdb_db.PGSQL: elif backend==fpdb_db.PGSQL:
import psycopg2 import psycopg2
import psycopg2.extensions import psycopg2.extensions
@ -109,7 +111,7 @@ class fpdb_db:
password = password, password = password,
database = database) database = database)
except: except:
msg = "PostgreSQL connection to database (%s) user (%s) failed." % (database, user) msg = "PostgreSQL connection to database (%s) user (%s) failed. Are you sure the DB is running?" % (database, user)
print msg print msg
raise FpdbError(msg) raise FpdbError(msg)
elif backend == fpdb_db.SQLITE: elif backend == fpdb_db.SQLITE:
@ -119,7 +121,12 @@ class fpdb_db:
sqlite3 = pool.manage(sqlite3, pool_size=1) sqlite3 = pool.manage(sqlite3, pool_size=1)
else: else:
logging.warning("SQLite won't work well without 'sqlalchemy' installed.") logging.warning("SQLite won't work well without 'sqlalchemy' installed.")
self.db = sqlite3.connect(database,detect_types=sqlite3.PARSE_DECLTYPES)
if not os.path.isdir(self.sqlite_db_dir):
print "Creating directory: '%s'" % (self.sqlite_db_dir)
os.mkdir(self.sqlite_db_dir)
self.db = sqlite3.connect( self.sqlite_db_dir + os.sep + database
, detect_types=sqlite3.PARSE_DECLTYPES )
sqlite3.register_converter("bool", lambda x: bool(int(x))) sqlite3.register_converter("bool", lambda x: bool(int(x)))
sqlite3.register_adapter(bool, lambda x: "1" if x else "0") sqlite3.register_adapter(bool, lambda x: "1" if x else "0")
else: else:

View File

@ -547,7 +547,7 @@ class Importer:
if self.callHud: if self.callHud:
#print "call to HUD here. handsId:",handsId #print "call to HUD here. handsId:",handsId
#pipe the Hands.id out to the HUD #pipe the Hands.id out to the HUD
#print "sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud print "sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
except Exceptions.DuplicateError: except Exceptions.DuplicateError:
duplicates += 1 duplicates += 1

View File

@ -118,7 +118,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
seatLines.append(line) seatLines.append(line)
names = fpdb_simple.parseNames(seatLines) names = fpdb_simple.parseNames(seatLines)
playerIDs = fpdb_simple.recognisePlayerIDs(db, names, siteID) # inserts players as needed playerIDs = db.recognisePlayerIDs(names, siteID) # inserts players as needed
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines) tmp = fpdb_simple.parseCashesAndSeatNos(seatLines)
startCashes = tmp['startCashes'] startCashes = tmp['startCashes']
seatNos = tmp['seatNos'] seatNos = tmp['seatNos']

View File

@ -913,6 +913,7 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c
#end def recogniseGametypeID #end def recogniseGametypeID
def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebuyOrAddon): def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebuyOrAddon):
ret = -1
cursor = db.get_cursor() cursor = db.get_cursor()
# First we try to find the tourney itself (by its tourneySiteId) in case it has already been inserted before (by a summary file for instance) # First we try to find the tourney itself (by its tourneySiteId) in case it has already been inserted before (by a summary file for instance)
# The reason is that some tourneys may not be identified correctly in the HH toplines (especially Buy-In and Fee which are used to search/create the TourneyTypeId) # The reason is that some tourneys may not be identified correctly in the HH toplines (especially Buy-In and Fee which are used to search/create the TourneyTypeId)
@ -922,83 +923,44 @@ def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebu
try: try:
len(result) len(result)
ret = result[0]
except: except:
cursor.execute ("SELECT id FROM TourneyTypes WHERE siteId=%s AND buyin=%s AND fee=%s AND knockout=%s AND rebuyOrAddon=%s", (siteId, buyin, fee, knockout, rebuyOrAddon)) cursor.execute( """SELECT id FROM TourneyTypes
WHERE siteId=%s AND buyin=%s AND fee=%s
AND knockout=%s AND rebuyOrAddon=%s"""
, (siteId, buyin, fee, knockout, rebuyOrAddon) )
result = cursor.fetchone() result = cursor.fetchone()
#print "tried SELECTing gametypes.id, result:",result #print "tried selecting tourneytypes.id, result:", result
try: try:
len(result) len(result)
ret = result[0]
except TypeError:#this means we need to create a new entry except TypeError:#this means we need to create a new entry
cursor.execute("""INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon) VALUES (%s, %s, %s, %s, %s)""", (siteId, buyin, fee, knockout, rebuyOrAddon)) #print "insert new tourneytype record ..."
cursor.execute("SELECT id FROM TourneyTypes WHERE siteId=%s AND buyin=%s AND fee=%s AND knockout=%s AND rebuyOrAddon=%s", (siteId, buyin, fee, knockout, rebuyOrAddon)) try:
cursor.execute( """INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon)
VALUES (%s, %s, %s, %s, %s)"""
, (siteId, buyin, fee, knockout, rebuyOrAddon) )
ret = db.get_last_insert_id(cursor)
except:
#print "maybe tourneytype was created since select, try selecting again ..."
cursor.execute( """SELECT id FROM TourneyTypes
WHERE siteId=%s AND buyin=%s AND fee=%s
AND knockout=%s AND rebuyOrAddon=%s"""
, (siteId, buyin, fee, knockout, rebuyOrAddon) )
result = cursor.fetchone() result = cursor.fetchone()
try:
len(result)
ret = result[0]
except:
print "Failed to find or insert TourneyTypes record"
ret = -1 # failed to find or insert record
#print "tried selecting tourneytypes.id again, result:", result
return result[0] #print "recogniseTourneyTypeId: returning", ret
return ret
#end def recogniseTourneyTypeId #end def recogniseTourneyTypeId
#returns the SQL ids of the names given in an array
# TODO: if someone gets industrious, they should make the parts that use the output of this function deal with a dict
# { playername: id } instead of depending on it's relation to the positions list
# then this can be reduced in complexity a bit
#def recognisePlayerIDs(cursor, names, site_id):
# result = []
# for i in xrange(len(names)):
# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],))
# tmp=cursor.fetchall()
# if (len(tmp)==0): #new player
# cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id))
# #print "Number of players rows inserted: %d" % cursor.rowcount
# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],))
# tmp=cursor.fetchall()
# #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp
# result.append(tmp[0][0])
# return result
def recognisePlayerIDs(db, names, site_id):
c = db.get_cursor()
q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([db.sql.query['placeholder'] for n in names]))
c.execute(q, names) # get all playerids by the names passed in
ids = dict(c.fetchall()) # convert to dict
if len(ids) != len(names):
notfound = [n for n in names if n not in ids] # make list of names not in database
if notfound: # insert them into database
q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")"
q_ins = q_ins.replace('%s', db.sql.query['placeholder'])
c.executemany(q_ins, [(n,) for n in notfound])
q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound]))
q2 = q2.replace('%s', db.sql.query['placeholder'])
c.execute(q2, notfound) # get their new ids
tmp = c.fetchall()
for n,id in tmp: # put them all into the same dict
ids[n] = id
# return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB
return [ids[n] for n in names]
#end def recognisePlayerIDs
# Here's a version that would work if it wasn't for the fact that it needs to have the output in the same order as input
# this version could also be improved upon using list comprehensions, etc
#def recognisePlayerIDs(cursor, names, site_id):
# result = []
# notfound = []
# cursor.execute("SELECT name,id FROM Players WHERE name='%s'" % "' OR name='".join(names))
# tmp = dict(cursor.fetchall())
# for n in names:
# if n not in tmp:
# notfound.append(n)
# else:
# result.append(tmp[n])
# if notfound:
# cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", (notfound))
# cursor.execute("SELECT id FROM Players WHERE name='%s'" % "' OR name='".join(notfound))
# tmp = cursor.fetchall()
# for n in tmp:
# result.append(n[0])
#
# return result
#recognises the name in the given line and returns its array position in the given array #recognises the name in the given line and returns its array position in the given array
def recognisePlayerNo(line, names, atype): def recognisePlayerNo(line, names, atype):