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

This commit is contained in:
Mika Bostrom 2009-11-19 12:40:49 +02:00
commit 9823221def
9 changed files with 188 additions and 130 deletions

View File

@ -361,16 +361,16 @@ class HudUI:
self.node = node self.node = node
self.label = node.getAttribute('label') 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_ring = string_to_bool(node.getAttribute('aggregate_ring_game_stats'))
self.aggregate_tour = string_to_bool(node.getAttribute('aggregate_tourney_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.agg_bb_mult = node.getAttribute('aggregation_level_multiplier')
# #
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_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_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_agg_bb_mult = node.getAttribute('hero_aggregation_level_multiplier') self.h_agg_bb_mult = node.getAttribute('hero_aggregation_level_multiplier')

View File

@ -432,16 +432,14 @@ class Database:
print "*** Database Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) 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" 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 , hud_params = {'hud_style':'A', 'agg_bb_mult':1000
,'h_aggregate_tour':False, 'h_aggregate_ring':False, 'h_hud_style':'S', 'h_hud_days':30, 'h_agg_bb_mult':100} ,'h_hud_style':'S', 'h_agg_bb_mult':1000}
, hero_id = -1 , hero_id = -1
): ):
aggregate = hud_params['aggregate_tour'] if type == "tour" else hud_params['aggregate_ring']
hud_style = hud_params['hud_style'] hud_style = hud_params['hud_style']
agg_bb_mult = hud_params['agg_bb_mult'] if aggregate else 1 agg_bb_mult = hud_params['agg_bb_mult']
h_aggregate = hud_params['h_aggregate_tour'] if type == "tour" else hud_params['h_aggregate_ring']
h_hud_style = hud_params['h_hud_style'] 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 = {} stat_dict = {}
if hud_style == 'S' or h_hud_style == 'S': if hud_style == 'S' or h_hud_style == 'S':
@ -468,13 +466,8 @@ class Database:
#elif h_hud_style == 'H': #elif h_hud_style == 'H':
# h_stylekey = date_nhands_ago needs array by player here ... # 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' 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) 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 #print "get stats: hud style =", hud_style, "query =", query, "subs =", subs
c = self.connection.cursor() c = self.connection.cursor()

View File

@ -4,91 +4,95 @@
<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>
<!-- These values need some explaining <!-- These values determine what stats are displayed in the HUD
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 : aggregate_ring_game_stats :
- True/False - 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 - defaults to False
aggregate_tourney_stats : aggregate_tourney_stats :
- True/False - 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 - 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 : aggregation_level_multiplier :
- float value - float value
- defines how many blind levels are used for aggregation - defines how many blind levels are included in stats displayed in HUD
- the logic is weird, at best - if value is M, stats for blind levels are combined if the higher level
- if value is 100, almost all levels are included is less than or equal to M times the lower blind level
- if value is 2.1, levels from half to double the current blind - defaults to 3, meaning blind levels from 1/3 of the current level to 3
level are included times the current level are included in the stats displayed in the HUD
- if value it 1, no aggregation is performed - e.g. if current big blind is 50, stats for blind levels from big blind
- defaults to 1 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 : aggregate_hero_ring_game_stats :
- True/False - 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 - defaults to False
aggregate_hero_tourney_stats : aggregate_hero_tourney_stats :
- True/False - 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 - 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 : hero_aggregation_level_multiplier :
- float value - float value
- defines how many blind levels are used for aggregation - defines how many blind levels are included in stats displayed in HUD
- the logic is weird, at best - if value is M, stats for blind levels are combined if the higher level
- if value is 100, almost all levels are included is less than or equal to M times the lower blind level
- if value is 2.1, levels from half to double the current blind - defaults to 1, meaning only stats from current blind level are included
level are included - e.g. if set to 3 and current big blind is 50, stats for blind levels from
- if value it 1, no aggregation is performed 16.7 (50 divided by 3) to big blind of 150 (50 times 3) are included
- defaults to 1
--> -->
<hud_ui <hud_ui
stat_range="A"
stat_days="90"
aggregate_ring_game_stats="False" aggregate_ring_game_stats="False"
aggregate_tourney_stats="False" aggregate_tourney_stats="True"
stat_aggregation_range="A" aggregation_level_multiplier="3"
aggregation_days="90"
aggregation_level_multiplier="1"
hero_stat_range="S"
hero_stat_days="30"
aggregate_hero_ring_game_stats="False" aggregate_hero_ring_game_stats="False"
aggregate_hero_tourney_stats="True" aggregate_hero_tourney_stats="False"
hero_stat_aggregation_range="S"
hero_aggregation_days="30"
hero_aggregation_level_multiplier="1" hero_aggregation_level_multiplier="1"
label="FPDB Menu - Right-click label="FPDB Menu - Right-click

View File

@ -63,34 +63,6 @@ elif os.name == 'nt':
import Hud 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): 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."""
# This class mainly provides state for controlling the multiple HUDs. # This class mainly provides state for controlling the multiple HUDs.
@ -159,6 +131,8 @@ class HUD_main(object):
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
# 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: if type == "tour" and self.hud_params['aggregate_tour'] == False:
self.hud_dict[table_name].hud_params['agg_bb_mult'] = 1 self.hud_dict[table_name].hud_params['agg_bb_mult'] = 1
elif type == "ring" and self.hud_params['aggregate_ring'] == False: elif type == "ring" and self.hud_params['aggregate_ring'] == False:
@ -167,8 +141,13 @@ class HUD_main(object):
self.hud_dict[table_name].hud_params['h_agg_bb_mult'] = 1 self.hud_dict[table_name].hud_params['h_agg_bb_mult'] = 1
elif type == "ring" and self.hud_params['h_aggregate_ring'] == False: 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_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['aggregate_ring'] == True
self.hud_params['h_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] [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)

View File

@ -90,11 +90,11 @@ if __name__=="__main__":
table.gdk_handle = gtk.gdk.window_foreign_new(table.number) table.gdk_handle = gtk.gdk.window_foreign_new(table.number)
print "table =", table print "table =", table
print "game =", table.get_game() # print "game =", table.get_game()
fake = fake_hud(table) fake = fake_hud(table)
print "fake =", fake print "fake =", fake
gobject.timeout_add(100, check_on_table, table, fake) # gobject.timeout_add(100, check_on_table, table, fake)
print "calling main" print "calling main"
gtk.main() gtk.main()

View File

@ -69,36 +69,42 @@ class Table(Table_Window):
for listing in os.popen('xwininfo -root -tree').readlines(): for listing in os.popen('xwininfo -root -tree').readlines():
if re.search(search_string, listing): if re.search(search_string, listing):
print listing print listing
mo = re.match('\s+([\dxabcdef]+)\s', listing) mo = re.match('\s+([\dxabcdef]+) (.+):\s\(\"([a-zA-Z.]+)\".+ (\d+)x(\d+)\+\d+\+\d+ \+(\d+)\+(\d+)', listing)
window_number = int( mo.group(1), 0) self.number = int( mo.group(1), 0)
self.width = int( mo.group(4) )
done_looping = False self.height = int( mo.group(5) )
for outside in root.query_tree().children: self.x = int( mo.group(6) )
for inside in outside.query_tree().children: self.y = int( mo.group(7) )
if done_looping: break self.title = re.sub('\"', '', mo.group(2))
if inside.id == window_number: self.exe = "" # not used?
self.window = inside self.hud = None
self.parent = outside # done_looping = False
done_looping = True # for outside in root.query_tree().children:
break # 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: if window_number is None:
print "Window %s not found. Skipping." % search_string print "Window %s not found. Skipping." % search_string
return None return None
my_geo = self.window.get_geometry() # my_geo = self.window.get_geometry()
pa_geo = self.parent.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 # window_string = str(self.window)
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)
mo = re.match('Xlib\.display\.Window\(([\dxabcdef]+)', window_string) mo = re.match('Xlib\.display\.Window\(([\dxabcdef]+)', window_string)
if not mo: if not mo:
print "Not matched" print "Not matched"

View File

@ -20,6 +20,7 @@ import os
import re import re
import sys import sys
import logging import logging
import math
from time import time, strftime from time import time, strftime
from Exceptions import * from Exceptions import *
@ -53,6 +54,10 @@ class VARIANCE:
def finalize(self): def finalize(self):
return float(var(self.store)) return float(var(self.store))
class sqlitemath:
def mod(self, a, b):
return a%b
class fpdb_db: class fpdb_db:
MYSQL_INNODB = 2 MYSQL_INNODB = 2
PGSQL = 3 PGSQL = 3
@ -148,6 +153,9 @@ class fpdb_db:
, detect_types=sqlite3.PARSE_DECLTYPES ) , 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")
self.db.create_function("floor", 1, math.floor)
tmp = sqlitemath()
self.db.create_function("mod", 2, tmp.mod)
if use_numpy: if use_numpy:
self.db.create_aggregate("variance", 1, VARIANCE) self.db.create_aggregate("variance", 1, VARIANCE)
else: else:

View File

@ -927,7 +927,7 @@ def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebu
except: except:
cursor.execute( """SELECT id FROM TourneyTypes cursor.execute( """SELECT id FROM TourneyTypes
WHERE siteId=%s AND buyin=%s AND fee=%s 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) ) , (siteId, buyin, fee, knockout, rebuyOrAddon) )
result = cursor.fetchone() result = cursor.fetchone()
#print "tried selecting tourneytypes.id, result:", result #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 ..." #print "insert new tourneytype record ..."
try: try:
cursor.execute( """INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon) 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) ) , (siteId, buyin, fee, knockout, rebuyOrAddon) )
ret = db.get_last_insert_id(cursor) ret = db.get_last_insert_id(cursor)
except: except:
#print "maybe tourneytype was created since select, try selecting again ..." #print "maybe tourneytype was created since select, try selecting again ..."
cursor.execute( """SELECT id FROM TourneyTypes cursor.execute( """SELECT id FROM TourneyTypes
WHERE siteId=%s AND buyin=%s AND fee=%s 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) ) , (siteId, buyin, fee, knockout, rebuyOrAddon) )
result = cursor.fetchone() result = cursor.fetchone()
try: try:

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")