Merge branch 'master' of git://git.assembla.com/fpdboz.git

Conflicts:
	pyfpdb/SQL.py
This commit is contained in:
Eric Blade 2009-11-20 07:49:48 -05:00
commit 3c26971414
19 changed files with 3508 additions and 4025 deletions

View File

@ -37,20 +37,79 @@ from xml.dom.minidom import Node
import logging, logging.config
import ConfigParser
try: # local path
logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf"))
except ConfigParser.NoSectionError: # debian package path
logging.config.fileConfig('/usr/share/python-fpdb/logging.conf')
##############################################################################
# Functions for finding config files and setting up logging
# Also used in other modules that use logging.
def get_default_config_path():
"""Returns the path where the fpdb config file _should_ be stored."""
if os.name == 'posix':
config_path = os.path.join(os.path.expanduser("~"), '.fpdb')
elif os.name == 'nt':
config_path = os.path.join(os.environ["APPDATA"], 'fpdb')
else: config_path = False
return config_path
def get_exec_path():
"""Returns the path to the fpdb.(py|exe) file we are executing"""
if hasattr(sys, "frozen"): # compiled by py2exe
return os.path.dirname(sys.executable)
else:
return os.path.dirname(sys.path[0])
def get_config(file_name, fallback = True):
"""Looks in cwd and in self.default_config_path for a config file."""
config_path = os.path.join(get_exec_path(), file_name)
if os.path.exists(config_path): # there is a file in the cwd
return config_path # so we use it
else: # no file in the cwd, look where it should be in the first place
config_path = os.path.join(get_default_config_path(), file_name)
if os.path.exists(config_path):
return config_path
# No file found
if not fallback:
return False
# OK, fall back to the .example file, should be in the start dir
if os.path.exists(file_name + ".example"):
try:
shutil.copyfile(file_name + ".example", file_name)
print "No %s found, using %s.example.\n" % (file_name, file_name)
print "A %s file has been created. You will probably have to edit it." % file_name
sys.stderr.write("No %s found, using %s.example.\n" % (file_name, file_name) )
except:
print "No %s found, cannot fall back. Exiting.\n" % file_name
sys.stderr.write("No %s found, cannot fall back. Exiting.\n" % file_name)
sys.exit()
return file_name
def get_logger(file_name, config = "config", fallback = False):
conf = get_config(file_name, fallback = fallback)
if conf:
try:
logging.config.fileConfig(conf)
log = logging.getLogger(config)
log.debug("%s logger initialised" % config)
return log
except:
pass
log = logging.basicConfig()
log = logging.getLogger()
log.debug("config logger initialised")
return log
# find a logging.conf file and set up logging
log = get_logger("logging.conf")
log = logging.getLogger("config")
log.debug("config logger initialised")
########################################################################
# application wide consts
APPLICATION_NAME_SHORT = 'fpdb'
APPLICATION_VERSION = 'xx.xx.xx'
DIR_SELF = os.path.dirname(os.path.abspath(__file__))
DIR_SELF = os.path.dirname(get_exec_path())
#TODO: imo no good idea to place 'database' in parent dir
DIR_DATABASES = os.path.join(os.path.dirname(DIR_SELF), 'database')
@ -302,16 +361,16 @@ class HudUI:
self.node = node
self.label = node.getAttribute('label')
#
self.hud_style = node.getAttribute('stat_range')
self.hud_days = node.getAttribute('stat_days')
self.aggregate_ring = string_to_bool(node.getAttribute('aggregate_ring_game_stats'))
self.aggregate_tour = string_to_bool(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 = string_to_bool(node.getAttribute('aggregate_hero_ring_game_stats'))
self.h_aggregate_tour = string_to_bool(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_hud_style = node.getAttribute('hero_stat_range')
self.h_hud_days = node.getAttribute('hero_stat_days')
self.h_aggregate_ring = string_to_bool(node.getAttribute('aggregate_hero_ring_game_stats'))
self.h_aggregate_tour = string_to_bool(node.getAttribute('aggregate_hero_tourney_stats'))
self.h_agg_bb_mult = node.getAttribute('hero_aggregation_level_multiplier')
@ -335,7 +394,7 @@ class Config:
# "file" is a path to an xml file with the fpdb/HUD configuration
# we check the existence of "file" and try to recover if it doesn't exist
self.default_config_path = self.get_default_config_path()
# self.default_config_path = self.get_default_config_path()
if file is not None: # config file path passed in
file = os.path.expanduser(file)
if not os.path.exists(file):
@ -343,28 +402,12 @@ class Config:
sys.stderr.write("Configuration file %s not found. Using defaults." % (file))
file = None
if file is None: # configuration file path not passed or invalid
file = self.find_config() #Look for a config file in the normal places
if file is None: # no config file in the normal places
file = self.find_example_config() #Look for an example file to edit
if file is None: # that didn't work either, just die
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 after looking in current directory and "+self.default_config_path+"\nExiting")
print "press enter to continue"
sys.stdin.readline()
sys.exit()
if file is None: file = get_config("HUD_config.xml")
# 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
# sc 2009/10/04 Example already copied to main filename, is this ok?
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()
print "\nReading configuration file %s\n" % file
try:
doc = xml.dom.minidom.parse(file)
except:
@ -460,28 +503,6 @@ class Config:
def set_hhArchiveBase(self, path):
self.imp.node.setAttribute("hhArchiveBase", path)
def find_config(self):
"""Looks in cwd and in self.default_config_path for a config file."""
if os.path.exists('HUD_config.xml'): # there is a HUD_config in the cwd
file = 'HUD_config.xml' # so we use it
else: # no HUD_config in the cwd, look where it should be in the first place
config_path = os.path.join(self.default_config_path, 'HUD_config.xml')
if os.path.exists(config_path):
file = config_path
else:
file = None
return file
def get_default_config_path(self):
"""Returns the path where the fpdb config file _should_ be stored."""
if os.name == 'posix':
config_path = os.path.join(os.path.expanduser("~"), '.fpdb')
elif os.name == 'nt':
config_path = os.path.join(os.environ["APPDATA"], 'fpdb')
else: config_path = None
return config_path
def find_default_conf(self):
if os.name == 'posix':
config_path = os.path.join(os.path.expanduser("~"), '.fpdb', 'default.conf')
@ -495,30 +516,6 @@ class Config:
file = None
return file
def read_default_conf(self, file):
parms = {}
with open(file, "r") as fh:
for line in fh:
line = string.strip(line)
(key, value) = line.split('=')
parms[key] = value
return parms
def find_example_config(self):
if os.path.exists('HUD_config.xml.example'): # there is a HUD_config in the cwd
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", \
"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" + \
"A HUD_config.xml has been created. You will probably have to edit it.")
else:
file = None
return file
def get_site_node(self, site):
for site_node in self.doc.getElementsByTagName("site"):
if site_node.getAttribute("site_name") == site:
@ -948,3 +945,7 @@ if __name__== "__main__":
print c.get_game_parameters(game)
print "start up path = ", c.execution_path("")
from xml.dom.ext import PrettyPrint
for site_node in c.doc.getElementsByTagName("site"):
PrettyPrint(site_node, stream=sys.stdout, encoding="utf-8")

View File

@ -45,16 +45,7 @@ import Card
import Tourney
from Exceptions import *
import logging, logging.config
import ConfigParser
try: # local path
logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf"))
except ConfigParser.NoSectionError: # debian package path
logging.config.fileConfig('/usr/share/python-fpdb/logging.conf')
log = logging.getLogger('db')
log = Configuration.get_logger("logging.conf")
class Database:
@ -441,16 +432,14 @@ class Database:
print "*** Database Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
def get_stats_from_hand( self, hand, type # type is "ring" or "tour"
, hud_params = {'aggregate_tour':False, 'aggregate_ring':False, 'hud_style':'A', 'hud_days':30, 'agg_bb_mult':100
,'h_aggregate_tour':False, 'h_aggregate_ring':False, 'h_hud_style':'S', 'h_hud_days':30, 'h_agg_bb_mult':100}
, hud_params = {'hud_style':'A', 'agg_bb_mult':1000
,'h_hud_style':'S', 'h_agg_bb_mult':1000}
, hero_id = -1
):
aggregate = hud_params['aggregate_tour'] if type == "tour" else hud_params['aggregate_ring']
hud_style = hud_params['hud_style']
agg_bb_mult = hud_params['agg_bb_mult'] if aggregate else 1
h_aggregate = hud_params['h_aggregate_tour'] if type == "tour" else hud_params['h_aggregate_ring']
agg_bb_mult = hud_params['agg_bb_mult']
h_hud_style = hud_params['h_hud_style']
h_agg_bb_mult = hud_params['h_agg_bb_mult'] if h_aggregate else 1
h_agg_bb_mult = hud_params['h_agg_bb_mult']
stat_dict = {}
if hud_style == 'S' or h_hud_style == 'S':
@ -477,13 +466,8 @@ class Database:
#elif h_hud_style == 'H':
# h_stylekey = date_nhands_ago needs array by player here ...
#if aggregate: always use aggregate query now: use agg_bb_mult of 1 for no aggregation:
query = 'get_stats_from_hand_aggregated'
subs = (hand, hero_id, stylekey, agg_bb_mult, agg_bb_mult, hero_id, h_stylekey, h_agg_bb_mult, h_agg_bb_mult)
#print "agg query subs:", subs
#else:
# query = 'get_stats_from_hand'
# subs = (hand, stylekey)
#print "get stats: hud style =", hud_style, "query =", query, "subs =", subs
c = self.connection.cursor()
@ -1393,6 +1377,12 @@ class Database:
pids[p],
pdata[p]['startCash'],
pdata[p]['seatNo'],
pdata[p]['winnings'],
pdata[p]['street0VPI'],
pdata[p]['street1Seen'],
pdata[p]['street2Seen'],
pdata[p]['street3Seen'],
pdata[p]['street4Seen'],
pdata[p]['street0Aggr'],
pdata[p]['street1Aggr'],
pdata[p]['street2Aggr'],
@ -1405,6 +1395,12 @@ class Database:
playerId,
startCash,
seatNo,
winnings,
street0VPI,
street1Seen,
street2Seen,
street3Seen,
street4Seen,
street0Aggr,
street1Aggr,
street2Aggr,
@ -1413,7 +1409,8 @@ class Database:
)
VALUES (
%s, %s, %s, %s, %s,
%s, %s, %s, %s
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s
)"""
# position,
@ -1423,16 +1420,10 @@ class Database:
# card3,
# card4,
# startCards,
# winnings,
# rake,
# totalProfit,
# street0VPI,
# street0_3BChance,
# street0_3BDone,
# street1Seen,
# street2Seen,
# street3Seen,
# street4Seen,
# sawShowdown,
# otherRaisedStreet1,
# otherRaisedStreet2,
@ -2683,13 +2674,11 @@ class HandToWrite:
if __name__=="__main__":
c = Configuration.Config()
db_connection = Database(c, 'fpdb', 'holdem') # mysql fpdb holdem
db_connection = Database(c) # mysql fpdb holdem
# db_connection = Database(c, 'fpdb-p', 'test') # mysql fpdb holdem
# db_connection = Database(c, 'PTrackSv2', 'razz') # mysql razz
# db_connection = Database(c, 'ptracks', 'razz') # postgres
print "database connection object = ", db_connection.connection
print "database type = ", db_connection.type
db_connection.recreate_tables()
h = db_connection.get_last_hand()
@ -2703,18 +2692,12 @@ if __name__=="__main__":
for p in stat_dict.keys():
print p, " ", stat_dict[p]
#print "nutOmatics stats:"
#stat_dict = db_connection.get_stats_from_hand(h, "ring")
#for p in stat_dict.keys():
# print p, " ", stat_dict[p]
print "cards =", db_connection.get_cards(u'1')
db_connection.close_connection
print "press enter to continue"
sys.stdin.readline()
#Code borrowed from http://push.cx/2008/caching-dictionaries-in-python-vs-ruby
class LambdaDict(dict):
def __init__(self, l):

View File

@ -18,6 +18,13 @@
#fpdb modules
import Card
DEBUG = True
if DEBUG:
import pprint
pp = pprint.PrettyPrinter(indent=4)
class DerivedStats():
def __init__(self, hand):
self.hand = hand
@ -30,13 +37,19 @@ class DerivedStats():
for player in hand.players:
self.handsplayers[player[1]] = {}
#Init vars that may not be used, but still need to be inserted.
# All stud street4 need this when importing holdem
self.handsplayers[player[1]]['winnings'] = 0
self.handsplayers[player[1]]['street4Seen'] = False
self.handsplayers[player[1]]['street4Aggr'] = False
self.assembleHands(self.hand)
self.assembleHandsPlayers(self.hand)
print "hands =", self.hands
print "handsplayers =", self.handsplayers
if DEBUG:
print "Hands:"
pp.pprint(self.hands)
print "HandsPlayers:"
pp.pprint(self.handsplayers)
def getHands(self):
return self.hands
@ -85,703 +98,25 @@ class DerivedStats():
# commentTs DATETIME
def assembleHandsPlayers(self, hand):
#street0VPI/vpip already called in Hand
#hand.players = [[seat, name, chips],[seat, name, chips]]
for player in hand.players:
self.handsplayers[player[1]]['seatNo'] = player[0]
self.handsplayers[player[1]]['startCash'] = player[2]
# Winnings is a non-negative value of money collected from the pot, which already includes the
# rake taken out. hand.collectees is Decimal, database requires cents
for player in hand.collectees:
self.handsplayers[player]['winnings'] = int(100 * hand.collectees[player])
for i, street in enumerate(hand.actionStreets[2:]):
self.seen(self.hand, i+1)
for i, street in enumerate(hand.actionStreets[1:]):
self.aggr(self.hand, i)
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):
@ -794,9 +129,9 @@ class DerivedStats():
for player in hand.players:
if player[1] in vpipers:
self.handsplayers[player[1]]['vpip'] = True
self.handsplayers[player[1]]['street0VPI'] = True
else:
self.handsplayers[player[1]]['vpip'] = False
self.handsplayers[player[1]]['street0VPI'] = False
def playersAtStreetX(self, hand):
""" playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4/draw1 */"""
@ -833,6 +168,17 @@ class DerivedStats():
self.hands['street3Raises'] = 0 # /* num big bets paid to see sd/street7 */
self.hands['street4Raises'] = 0 # /* num big bets paid to see showdown */
def seen(self, hand, i):
pas = set()
for act in hand.actions[hand.actionStreets[i+1]]:
pas.add(act[0])
for player in hand.players:
if player[1] in pas:
self.handsplayers[player[1]]['street%sSeen' % i] = True
else:
self.handsplayers[player[1]]['street%sSeen' % i] = False
def aggr(self, hand, i):
aggrers = set()
for act in hand.actions[hand.actionStreets[i]]:

View File

@ -9,8 +9,8 @@ class FpdbParseError(FpdbError):
self.value = value
self.hid = hid
def __str__(self):
if hid:
return repr("HID:"+hid+", "+self.value)
if self.hid:
return repr("HID:"+self.hid+", "+self.value)
else:
return repr(self.value)

View File

@ -544,7 +544,7 @@ class GuiPlayerStats (threading.Thread):
# set flag in self.columns to show posn column
[x for x in self.columns if x[0] == 'plposition'][0][1] = True
else:
query = query.replace("<position>", "'1'")
query = query.replace("<position>", "gt.base")
# unset flag in self.columns to hide posn column
[x for x in self.columns if x[0] == 'plposition'][0][1] = False

View File

@ -4,91 +4,95 @@
<import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import>
<!-- These values need some explaining
<!-- These values determine what stats are displayed in the HUD
aggregate_ring_game_stats :
The following values define how opponents' stats are done, the first 2 determine
the time period stats are displayed for, the next 3 determine what blind levels
are included (i.e. aggregated):
stat_range :
- A/S/T
- if set to A, includes stats from all time
- if set to S, includes stats from current session
- if set to T, includes stats from last N days; set value in stat_days
- defaults to A
stat_days :
- a numeric value
- only used if stat_range 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 it depends on stat_range setting
aggregate_ring_game_stats :
- True/False
- if set to True, includes data from other blind levels
- if set to True, opponents stats include other blind levels during ring games
- defaults to False
aggregate_tourney_stats :
- True/False
- if set to True, includes data from other blind levels
- if set to True, opponents stats include other blind levels during tourneys
- 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
- defines how many blind levels are included in stats displayed in HUD
- if value is M, stats for blind levels are combined if the higher level
is less than or equal to M times the lower blind level
- defaults to 3, meaning blind levels from 1/3 of the current level to 3
times the current level are included in the stats displayed in the HUD
- e.g. if current big blind is 50, stats for blind levels from big blind
of 16.7 (50 divided by 3) to big blind of 150 (50 times 3) are included
The following values define how hero's stats are done
The following values define how hero's stats are done, the first 2 determine
the time period stats are displayed for, the next 3 determine what blind levels
are included (i.e. aggregated):
hero_stat_range :
- A/S/T
- if set to A, includes stats from all time
- if set to S, includes stats from current session
- if set to T, includes stats from last N days; set value in hero_stat_days
- defaults to S
hero_stat_days :
- a numeric value
- if hero_stat_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 it depends on hero_stat_range setting
aggregate_hero_ring_game_stats :
- True/False
- if set to True, hero's data is calculated over multiple blind levels
- if set to True, hero's stats are 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
- if set to True, hero's stats are 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
- defines how many blind levels are included in stats displayed in HUD
- if value is M, stats for blind levels are combined if the higher level
is less than or equal to M times the lower blind level
- defaults to 1, meaning only stats from current blind level are included
- e.g. if set to 3 and current big blind is 50, stats for blind levels from
16.7 (50 divided by 3) to big blind of 150 (50 times 3) are included
-->
<hud_ui
stat_range="A"
stat_days="90"
aggregate_ring_game_stats="False"
aggregate_tourney_stats="False"
stat_aggregation_range="A"
aggregation_days="90"
aggregation_level_multiplier="1"
aggregate_tourney_stats="True"
aggregation_level_multiplier="3"
hero_stat_range="S"
hero_stat_days="30"
aggregate_hero_ring_game_stats="False"
aggregate_hero_tourney_stats="True"
hero_stat_aggregation_range="S"
hero_aggregation_days="30"
aggregate_hero_tourney_stats="False"
hero_aggregation_level_multiplier="1"
label="FPDB Menu - Right-click

View File

@ -53,6 +53,7 @@ import gobject
# FreePokerTools modules
import Configuration
import Database
from HandHistoryConverter import getTableTitleRe
# get the correct module for the current os
if os.name == 'posix':
import XTables as Tables
@ -62,34 +63,6 @@ elif os.name == 'nt':
import Hud
# HUD params:
# - Set aggregate_ring and/or aggregate_tour to True is you want to include stats from other blind levels in the HUD display
# - If aggregation is used, the value of agg_bb_mult determines what levels are included. If
# agg_bb_mult is M and current blind level is L, blinds between L/M and L*M are included. e.g.
# if agg_bb_mult is 100, almost all levels are included in all HUD displays
# if agg_bb_mult is 2, levels from half to double the current blind level are included in the HUD
# if agg_bb_mult is 1 only the current level is included
# - Set hud_style to A to see stats for all-time
# Set hud_style to S to only see stats for current session (currently this shows stats for the last 24 hours)
# Set hud_style to T to only see stats for the last N days (uses value in hud_days)
# - Set hud_days to N to see stats for the last N days in the HUD (only applies if hud_style is T)
def_hud_params = { # Settings for all players apart from program owner ('hero')
'aggregate_ring' : False
, 'aggregate_tour' : True
, 'hud_style' : 'A'
, 'hud_days' : 90
, 'agg_bb_mult' : 10000 # 1 means no aggregation
# , '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' : 60
, 'h_agg_bb_mult' : 10000 # 1 means no aggregation
# , 'h_hud_session_gap' : 30 not currently used
}
class HUD_main(object):
"""A main() object to own both the read_stdin thread and the gui."""
# This class mainly provides state for controlling the multiple HUDs.
@ -158,6 +131,8 @@ class HUD_main(object):
self.hud_dict[table_name].stat_dict = stat_dict
self.hud_dict[table_name].cards = cards
# set agg_bb_mult so that aggregate_tour and aggregate_ring can be ignored,
# agg_bb_mult == 1 means no aggregation after these if statements:
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:
@ -166,8 +141,13 @@ class HUD_main(object):
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
# sqlcoder: I forget why these are set to true (aren't they ignored from now on?)
# but I think it's needed:
self.hud_params['aggregate_ring'] == True
self.hud_params['h_aggregate_ring'] == True
# so maybe the tour ones should be set as well? does this fix the bug I see mentioned?
self.hud_params['aggregate_tour'] = True
self.hud_params['h_aggregate_tour'] == True
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[table_name].aux_windows]
gobject.idle_add(idle_func)
@ -253,10 +233,10 @@ class HUD_main(object):
if comm_cards != {}: # stud!
cards['common'] = comm_cards['common']
if type == "tour":
tablewindow = Tables.Table(tournament = tour_number, table_number = tab_number)
else:
tablewindow = Tables.Table(table_name = table_name)
table_kwargs = dict(table_name = table_name, tournament = tour_number, table_number = tab_number)
search_string = getTableTitleRe(self.config, site, type, **table_kwargs)
tablewindow = Tables.Table(search_string, **table_kwargs)
if tablewindow is None:
# If no client window is found on the screen, complain and continue
if type == "tour":

View File

@ -32,19 +32,12 @@ from xml.dom.minidom import Node
import time
import datetime
from Exceptions import FpdbParseError
import Configuration
import gettext
gettext.install('fpdb')
import logging, logging.config
import ConfigParser
try:
logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf"))
except ConfigParser.NoSectionError: # debian package path
logging.config.fileConfig('/usr/share/python-fpdb/logging.conf')
log = logging.getLogger("parser")
log = Configuration.get_logger("logging.conf")
import pygtk
import gtk
@ -154,6 +147,7 @@ Otherwise, finish at EOF.
except FpdbParseError, e:
numErrors += 1
log.warning("Failed to convert hand %s" % e.hid)
log.warning("Exception msg: '%s'" % str(e))
log.debug(handText)
else:
handsList = self.allHandsAsList()
@ -168,6 +162,7 @@ Otherwise, finish at EOF.
except FpdbParseError, e:
numErrors += 1
log.warning("Failed to convert hand %s" % e.hid)
log.warning("Exception msg: '%s'" % str(e))
log.debug(handText)
numHands = len(handsList)
endtime = time.time()
@ -506,3 +501,26 @@ or None if we fail to get the info """
def getTourney(self):
return self.tourney
@staticmethod
def getTableTitleRe(type, table_name=None, tournament = None, table_number=None):
"Returns string to search in windows titles"
if type=="tour":
return "%s.+Table\s%s" % (tournament, table_number)
else:
return table_name
def getTableTitleRe(config, sitename, *args, **kwargs):
"Returns string to search in windows titles for current site"
return getSiteHhc(config, sitename).getTableTitleRe(*args, **kwargs)
def getSiteHhc(config, sitename):
"Returns HHC class for current site"
hhcName = config.supported_sites[sitename].converter
hhcModule = __import__(hhcName)
return getattr(hhcModule, hhcName[:-6])

View File

@ -386,9 +386,9 @@ class Hud:
(x, y) = loc[adj[i+1]]
w.relocate(x, y)
# While we're at it, fix the positions of mucked cards too
for aux in self.aux_windows:
aux.update_card_positions()
# While we're at it, fix the positions of mucked cards too
for aux in self.aux_windows:
aux.update_card_positions()
return True
@ -440,7 +440,7 @@ class Hud:
new_layout[self.stat_windows[sw].adj - 1] = new_loc
self.config.edit_layout(self.table.site, self.max, locations = new_layout)
# ask each aux to save its layout back to the config object
(aux.save_layout() for aux in self.aux_windows)
[aux.save_layout() for aux in self.aux_windows]
# save the config object back to the file
print "saving new xml file"
self.config.save()

View File

@ -92,7 +92,7 @@ class PokerStars(HandHistoryConverter):
self.compiledPlayers = players
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
subst = {'PLYR': player_re, 'CUR': self.sym[hand.gametype['currency']]}
logging.debug("player_re: " + player_re)
log.debug("player_re: " + player_re)
self.re_PostSB = re.compile(r"^%(PLYR)s: posts small blind %(CUR)s(?P<SB>[.0-9]+)" % subst, re.MULTILINE)
self.re_PostBB = re.compile(r"^%(PLYR)s: posts big blind %(CUR)s(?P<BB>[.0-9]+)" % subst, re.MULTILINE)
self.re_Antes = re.compile(r"^%(PLYR)s: posts the ante %(CUR)s(?P<ANTE>[.0-9]+)" % subst, re.MULTILINE)
@ -186,7 +186,7 @@ class PokerStars(HandHistoryConverter):
# m = self.re_Button.search(hand.handText)
# if m: info.update(m.groupdict())
# TODO : I rather like the idea of just having this dict as hand.info
logging.debug("readHandInfo: %s" % info)
log.debug("readHandInfo: %s" % info)
for key in info:
if key == 'DATETIME':
#2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET]
@ -226,10 +226,10 @@ class PokerStars(HandHistoryConverter):
if m:
hand.buttonpos = int(m.group('BUTTON'))
else:
logging.info('readButton: not found')
log.info('readButton: not found')
def readPlayerStacks(self, hand):
logging.debug("readPlayerStacks")
log.debug("readPlayerStacks")
m = self.re_PlayerInfo.finditer(hand.handText)
players = []
for a in m:
@ -265,7 +265,7 @@ class PokerStars(HandHistoryConverter):
hand.setCommunityCards(street, m.group('CARDS').split(' '))
def readAntes(self, hand):
logging.debug("reading antes")
log.debug("reading antes")
m = self.re_Antes.finditer(hand.handText)
for player in m:
#~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))

File diff suppressed because it is too large Load Diff

View File

@ -93,19 +93,17 @@ gobject.signal_new("client_destroyed", gtk.Window,
# screen location of (0, 0) in the working window.
class Table_Window(object):
def __init__(self, table_name = None, tournament = None, table_number = None):
def __init__(self, search_string, table_name = None, tournament = None, table_number = None):
if table_name is not None:
search_string = table_name
self.name = table_name
self.tournament = None
self.table = None
elif tournament is not None and table_number is not None:
if tournament is not None and table_number is not None:
print "tournament %s, table %s" % (tournament, table_number)
self.tournament = int(tournament)
self.table = int(table_number)
self.name = "%s - %s" % (self.tournament, self.table)
search_string = "%s.+Table\s%s" % (tournament, table_number)
elif table_name is not None:
search_string = table_name
self.name = table_name
self.tournament = None
else:
return None

View File

@ -82,18 +82,19 @@ if __name__=="__main__":
(tour_no, tab_no) = table_name.split(",", 1)
tour_no = tour_no.rstrip()
tab_no = tab_no.rstrip()
table = Tables.Table(tournament = tour_no, table_number = tab_no)
table = Tables.Table(None, tournament = tour_no, table_number = tab_no)
else: # not a tournament
print "cash game"
table_name = table_name.rstrip()
table = Tables.Table(table_name = table_name)
table = Tables.Table(None, table_name = table_name)
table.gdk_handle = gtk.gdk.window_foreign_new(table.number)
print "table =", table
print "game =", table.get_game()
# print "game =", table.get_game()
fake = fake_hud(table)
print "fake =", fake
gobject.timeout_add(100, check_on_table, table, fake)
# gobject.timeout_add(100, check_on_table, table, fake)
print "calling main"
gtk.main()

View File

@ -25,6 +25,7 @@ of Table_Window objects representing the windows found.
# Standard Library modules
import re
import os
# pyGTK modules
import pygtk
@ -40,39 +41,70 @@ from TableWindow import Table_Window
# We might as well do this once and make them globals
disp = Xlib.display.Display()
root = disp.screen().root
name_atom = disp.get_atom("WM_NAME", 1)
class Table(Table_Window):
def find_table_parameters(self, search_string):
self.window = None
done_looping = False
for outside in root.query_tree().children:
for inside in outside.query_tree().children:
if done_looping: break
if inside.get_wm_name() and re.search(search_string, inside.get_wm_name()):
if self.check_bad_words(inside.get_wm_name()): continue
self.window = inside
self.parent = outside
done_looping = True
break
# self.window = None
# done_looping = False
# for outside in root.query_tree().children:
# for inside in outside.query_tree().children:
# if done_looping: break
# prop = inside.get_property(name_atom, Xlib.Xatom.STRING, 0, 1000)
# print prop
# if prop is None: continue
# if prop.value and re.search(search_string, prop.value):
# if self.check_bad_words(prop.value): continue
## if inside.get_wm_name() and re.search(search_string, inside.get_wm_name()):
## if self.check_bad_words(inside.get_wm_name()):
## print "bad word =", inside.get_wm_name()
## continue
# self.window = inside
# self.parent = outside
# done_looping = True
# break
if self.window == None or self.parent == None:
window_number = None
for listing in os.popen('xwininfo -root -tree').readlines():
if re.search(search_string, listing):
print listing
mo = re.match('\s+([\dxabcdef]+) (.+):\s\(\"([a-zA-Z.]+)\".+ (\d+)x(\d+)\+\d+\+\d+ \+(\d+)\+(\d+)', listing)
self.number = int( mo.group(1), 0)
self.width = int( mo.group(4) )
self.height = int( mo.group(5) )
self.x = int( mo.group(6) )
self.y = int( mo.group(7) )
self.title = re.sub('\"', '', mo.group(2))
self.exe = "" # not used?
self.hud = None
# done_looping = False
# for outside in root.query_tree().children:
# for inside in outside.query_tree().children:
# if done_looping: break
# if inside.id == window_number:
# self.window = inside
# self.parent = outside
# done_looping = True
# break
if window_number is None:
print "Window %s not found. Skipping." % search_string
return None
my_geo = self.window.get_geometry()
pa_geo = self.parent.get_geometry()
# my_geo = self.window.get_geometry()
# pa_geo = self.parent.get_geometry()
#
# self.x = pa_geo.x + my_geo.x
# self.y = pa_geo.y + my_geo.y
# self.width = my_geo.width
# self.height = my_geo.height
# self.exe = self.window.get_wm_class()[0]
# self.title = self.window.get_wm_name()
# self.site = ""
# self.hud = None
self.x = pa_geo.x + my_geo.x
self.y = pa_geo.y + my_geo.y
self.width = my_geo.width
self.height = my_geo.height
self.exe = self.window.get_wm_class()[0]
self.title = self.window.get_wm_name()
self.site = ""
self.hud = None
window_string = str(self.window)
# window_string = str(self.window)
mo = re.match('Xlib\.display\.Window\(([\dxabcdef]+)', window_string)
if not mo:
print "Not matched"

View File

@ -20,6 +20,7 @@ import os
import re
import sys
import logging
import math
from time import time, strftime
from Exceptions import *
@ -30,11 +31,33 @@ except ImportError:
logging.info("Not using sqlalchemy connection pool.")
use_pool = False
try:
from numpy import var
use_numpy = True
except ImportError:
logging.info("Not using numpy to define variance in sqlite.")
use_numpy = False
import fpdb_simple
import FpdbSQLQueries
import Configuration
# Variance created as sqlite has a bunch of undefined aggregate functions.
class VARIANCE:
def __init__(self):
self.store = []
def step(self, value):
self.store.append(value)
def finalize(self):
return float(var(self.store))
class sqlitemath:
def mod(self, a, b):
return a%b
class fpdb_db:
MYSQL_INNODB = 2
PGSQL = 3
@ -130,6 +153,13 @@ class fpdb_db:
, detect_types=sqlite3.PARSE_DECLTYPES )
sqlite3.register_converter("bool", lambda x: bool(int(x)))
sqlite3.register_adapter(bool, lambda x: "1" if x else "0")
self.db.create_function("floor", 1, math.floor)
tmp = sqlitemath()
self.db.create_function("mod", 2, tmp.mod)
if use_numpy:
self.db.create_aggregate("variance", 1, VARIANCE)
else:
logging.warning("Some database functions will not work without NumPy support")
else:
raise FpdbError("unrecognised database backend:"+backend)
self.cursor = self.db.cursor()

View File

@ -42,15 +42,7 @@ import fpdb_parse_logic
import Configuration
import Exceptions
import logging, logging.config
import ConfigParser
try:
logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf"))
except ConfigParser.NoSectionError: # debian package path
logging.config.fileConfig('/usr/share/python-fpdb/logging.conf')
log = logging.getLogger('importer')
log = Configuration.get_logger("logging.conf", "importer")
# database interface modules
try:

View File

@ -927,7 +927,7 @@ def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebu
except:
cursor.execute( """SELECT id FROM TourneyTypes
WHERE siteId=%s AND buyin=%s AND fee=%s
AND knockout=%s AND rebuyOrAddon=%s"""
AND knockout=%s AND rebuyOrAddon=%s""".replace('%s', db.sql.query['placeholder'])
, (siteId, buyin, fee, knockout, rebuyOrAddon) )
result = cursor.fetchone()
#print "tried selecting tourneytypes.id, result:", result
@ -939,14 +939,14 @@ def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebu
#print "insert new tourneytype record ..."
try:
cursor.execute( """INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon)
VALUES (%s, %s, %s, %s, %s)"""
VALUES (%s, %s, %s, %s, %s)""".replace('%s', db.sql.query['placeholder'])
, (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"""
AND knockout=%s AND rebuyOrAddon=%s""".replace('%s', db.sql.query['placeholder'])
, (siteId, buyin, fee, knockout, rebuyOrAddon) )
result = cursor.fetchone()
try:

View File

@ -27,6 +27,22 @@ Py2exe script for fpdb.
# get rid of all the uneeded libraries (e.g., pyQT)
# think about an installer
#HOW TO USE this script:
#
# cd to the folder where this script is stored, usually .../pyfpdb.
# If there are build and dist subfolders present , delete them to get
# rid of earlier builds.
# Run the script with "py2exe_setup.py py2exe"
# You will frequently get messages about missing .dll files. E. g.,
# MSVCP90.dll. These are somewhere in your windows install, so you
# can just copy them to your working folder.
# If it works, you'll have 2 new folders, build and dist. Build is
# working space and should be deleted. Dist contains the files to be
# distributed. Last, you must copy the etc/, lib/ and share/ folders
# from your gtk/bin/ folder to the dist folder. (the whole folders, not
# just the contents) You can (should) then prune the etc/, lib/ and
# share/ folders to remove components we don't need.
from distutils.core import setup
import py2exe
@ -36,7 +52,8 @@ setup(
version = '0.12',
console = [ {'script': 'fpdb.py', },
{'script': 'HUD_main.py', }
{'script': 'HUD_main.py', },
{'script': 'Configuration.py', }
],
options = {'py2exe': {
@ -47,8 +64,10 @@ setup(
}
},
data_files = ['HUD_config.xml',
'Cards01.png'
data_files = ['HUD_config.xml.example',
'Cards01.png',
'logging.conf',
(r'matplotlibdata', glob.glob(r'c:\python26\Lib\site-packages\matplotlib\mpl-data\*'))
]
)

68
pyfpdb/test_Database.py Normal file
View File

@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
import sqlite3
import fpdb_db
import math
# Should probably use our wrapper classes - creating sqlite db in memory
sqlite3.register_converter("bool", lambda x: bool(int(x)))
sqlite3.register_adapter(bool, lambda x: "1" if x else "0")
con = sqlite3.connect(":memory:")
con.isolation_level = None
#Floor function
con.create_function("floor", 1, math.floor)
#Mod function
tmp = fpdb_db.sqlitemath()
con.create_function("mod", 2, tmp.mod)
# Aggregate function VARIANCE()
con.create_aggregate("variance", 1, fpdb_db.VARIANCE)
cur = con.cursor()
def testSQLiteVarianceFunction():
cur.execute("CREATE TABLE test(i)")
cur.execute("INSERT INTO test(i) values (1)")
cur.execute("INSERT INTO test(i) values (2)")
cur.execute("INSERT INTO test(i) values (3)")
cur.execute("SELECT variance(i) from test")
result = cur.fetchone()[0]
print "DEBUG: Testing variance function"
print "DEBUG: result: %s expecting: 0.666666 (result-expecting ~= 0.0): %s" % (result, (result - 0.66666))
cur.execute("DROP TABLE test")
assert (result - 0.66666) <= 0.0001
def testSQLiteFloorFunction():
vars = [0.1, 1.5, 2.6, 3.5, 4.9]
cur.execute("CREATE TABLE test(i float)")
for var in vars:
cur.execute("INSERT INTO test(i) values(%f)" % var)
cur.execute("SELECT floor(i) from test")
result = cur.fetchall()
print "DEBUG: result: %s" % result
answer = 0
for i in result:
print "DEBUG: int(var): %s" % int(i[0])
assert answer == int(i[0])
answer = answer + 1
cur.execute("DROP TABLE test")
def testSQLiteModFunction():
vars = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ,17, 18]
cur.execute("CREATE TABLE test(i int)")
for var in vars:
cur.execute("INSERT INTO test(i) values(%i)" % var)
cur.execute("SELECT mod(i,13) from test")
result = cur.fetchall()
idx = 0
for i in result:
print "DEBUG: int(var): %s" % i[0]
assert vars[idx]%13 == int(i[0])
idx = idx+1
assert 0 == 1
cur.execute("DROP TABLE test")