p80 - a great many updates from Ray
This commit is contained in:
parent
2c251d94f2
commit
7b13331331
|
@ -22,6 +22,8 @@ rm pyfpdb/*.pyc
|
|||
mkdir fpdb-$1
|
||||
cp -R docs fpdb-$1/
|
||||
cp -R pyfpdb fpdb-$1/
|
||||
rm fpdb-$1/HUD_config.*
|
||||
cp pyfpdb/HUD_config.xml.example fpdb-$1/
|
||||
cp -R regression-test fpdb-$1/
|
||||
cp -R utils fpdb-$1/
|
||||
cd fpdb-$1
|
||||
|
|
|
@ -2,9 +2,8 @@ todolist (db=database, imp=importer, tv=tableviewer)
|
|||
Everything is subject to change and the order does not indicate priority. Patches for any of these or other features are very welcome, see readme-overview.txt for contacts.
|
||||
Please also see db-todo.txt
|
||||
|
||||
alpha3 (release 1-2Sep?)
|
||||
alpha3 (release 15Sep)
|
||||
======
|
||||
(fixed by ray) auto import only runs on one file per start
|
||||
find correct sf logo link
|
||||
|
||||
windows integrated installer
|
||||
|
@ -20,7 +19,7 @@ fill check-/call-raise cache fields
|
|||
|
||||
printhand each and the 2/3 relevant printplayerflags respectively on ps-lhe-ring-successful-steal-by-cutoff.txt and ps-lhe-ring-call-3B-preflop-cb-no2b.txt
|
||||
|
||||
alpha4 (release 8Sep?)
|
||||
alpha4 (release 22-29Sep)
|
||||
======
|
||||
change to savannah?
|
||||
implement steal and positions in stud
|
||||
|
@ -33,9 +32,25 @@ change tabledesign VALIGN
|
|||
finish updating filelist
|
||||
finish todos in git instructions
|
||||
debian/ubuntu package http://www.debian.org/doc/maint-guide/ch-start.en.html
|
||||
howto remote DB
|
||||
move all user docs to webpage
|
||||
|
||||
before beta
|
||||
===========
|
||||
No Full Tilt support in HUD
|
||||
No river stats for stud games
|
||||
hole/board cards are not correctly stored in the db for stud games
|
||||
HORSE (and presumably other mixed games) hand history files not handled correctly
|
||||
HUD stat windows are too big on Windows
|
||||
HUD task bar entries on Windows won't go away
|
||||
Some MTTs won't import (rebuys??)
|
||||
Many STTs won't import
|
||||
MTT/STT not tested in HUD
|
||||
HUD stats not aggregated
|
||||
Player names with non-Latin chars throw warnings in HUD
|
||||
HUD doesn't start when fpdb is started from the Windows "Start Menu"
|
||||
Exiting HUD on Windows doesn't properly clean up stat windows
|
||||
|
||||
finish bringing back tourney
|
||||
ebuild: USE gtk, set permissions in it, copy docs to correct place, use games eclass or whatever to get games group notice, git-ebuild, get it into sunrise
|
||||
make hud display W$SD etc as fraction.
|
||||
|
@ -49,6 +64,7 @@ split hud data generation into separate for loops and make it more efficient
|
|||
fix bug that sawFlop/Turn/River/CBChance/etc gets miscalculated if someone is allin - might as well add all-in recognition for this
|
||||
make 3 default HUD configs (easy (4-5 fields), advanced (10ish fields), crazy (20 or so))
|
||||
make it work with postgres
|
||||
gentoo ebuild: USE postgresql
|
||||
expand instructions for profile file
|
||||
maybe remove siteId from gametypes
|
||||
?change most cache fields to bigint to allow extremely big databases in excess of 2 or 4 million hands per stake and position?
|
||||
|
|
72
pyfpdb/Configuration.py
Normal file → Executable file
72
pyfpdb/Configuration.py
Normal file → Executable file
|
@ -23,6 +23,7 @@ Handles HUD configuration files.
|
|||
########################################################################
|
||||
|
||||
# Standard Library modules
|
||||
import shutil
|
||||
import xml.dom.minidom
|
||||
from xml.dom.minidom import Node
|
||||
|
||||
|
@ -38,7 +39,7 @@ class Layout:
|
|||
for i in range(1, len(self.location)):
|
||||
temp = temp + "(%d,%d)" % self.location[i]
|
||||
|
||||
return temp
|
||||
return temp + "\n"
|
||||
|
||||
class Site:
|
||||
def __init__(self, node):
|
||||
|
@ -81,7 +82,7 @@ class Stat:
|
|||
pass
|
||||
|
||||
def __str__(self):
|
||||
temp = " stat_name = %s, row = %d, col = %d, tip = %s, click = %s\n" % (self.stat_name, self.row, self.col, self.tip, self.click)
|
||||
temp = " stat_name = %s, row = %d, col = %d, tip = %s, click = %s, popup = %s\n" % (self.stat_name, self.row, self.col, self.tip, self.click, self.popup)
|
||||
return temp
|
||||
|
||||
class Game:
|
||||
|
@ -99,6 +100,7 @@ class Game:
|
|||
stat.col = int( stat_node.getAttribute("col") )
|
||||
stat.tip = stat_node.getAttribute("tip")
|
||||
stat.click = stat_node.getAttribute("click")
|
||||
stat.popup = stat_node.getAttribute("popup")
|
||||
|
||||
self.stats[stat.stat_name] = stat
|
||||
|
||||
|
@ -150,15 +152,31 @@ class Mucked:
|
|||
temp = temp + ' ' + key + " = " + value + "\n"
|
||||
return temp
|
||||
|
||||
class Popup:
|
||||
def __init__(self, node):
|
||||
self.name = node.getAttribute("pu_name")
|
||||
self.pu_stats = []
|
||||
for stat_node in node.getElementsByTagName('pu_stat'):
|
||||
self.pu_stats.append(stat_node.getAttribute("pu_stat_name"))
|
||||
|
||||
def __str__(self):
|
||||
temp = "Popup = " + self.name + "\n"
|
||||
for stat in self.pu_stats:
|
||||
temp = temp + " " + stat
|
||||
return temp + "\n"
|
||||
|
||||
class Config:
|
||||
def __init__(self, file = 'HUD_config.xml'):
|
||||
|
||||
doc = xml.dom.minidom.parse(file)
|
||||
|
||||
self.doc = doc
|
||||
self.file = file
|
||||
self.supported_sites = {}
|
||||
self.supported_games = {}
|
||||
self.supported_databases = {}
|
||||
self.mucked_windows = {}
|
||||
self.popup_windows = {}
|
||||
|
||||
# s_sites = doc.getElementsByTagName("supported_sites")
|
||||
for site_node in doc.getElementsByTagName("site"):
|
||||
|
@ -180,6 +198,47 @@ class Config:
|
|||
mw = Mucked(node = mw_node)
|
||||
self.mucked_windows[mw.name] = mw
|
||||
|
||||
s_dbs = doc.getElementsByTagName("popup_windows")
|
||||
for pu_node in doc.getElementsByTagName("pu"):
|
||||
pu = Popup(node = pu_node)
|
||||
self.popup_windows[pu.name] = pu
|
||||
|
||||
def get_site_node(self, site):
|
||||
for site_node in self.doc.getElementsByTagName("site"):
|
||||
if site_node.getAttribute("site_name") == site:
|
||||
return site_node
|
||||
|
||||
def get_layout_node(self, site_node, layout):
|
||||
for layout_node in site_node.getElementsByTagName("layout"):
|
||||
if int( layout_node.getAttribute("max") ) == int( layout ):
|
||||
return layout_node
|
||||
|
||||
def get_location_node(self, layout_node, seat):
|
||||
for location_node in layout_node.getElementsByTagName("location"):
|
||||
if int( location_node.getAttribute("seat") ) == int( seat ):
|
||||
return location_node
|
||||
|
||||
def save(self, file = None):
|
||||
if not file == None:
|
||||
f = open(file, 'w')
|
||||
self.doc.writexml(f)
|
||||
f.close()
|
||||
else:
|
||||
shutil.move(self.file, self.file+".backup")
|
||||
f = open(self.file, 'w')
|
||||
self.doc.writexml(f)
|
||||
f.close
|
||||
|
||||
def edit_layout(self, site_name, max, width = None, height = None,
|
||||
fav_seat = None, locations = None):
|
||||
site_node = self.get_site_node(site_name)
|
||||
layout_node = self.get_layout_node(site_node, max)
|
||||
for i in range(1, max + 1):
|
||||
location_node = self.get_location_node(layout_node, i)
|
||||
location_node.setAttribute("x", str( locations[i-1][0] ))
|
||||
location_node.setAttribute("y", str( locations[i-1][1] ))
|
||||
self.supported_sites[site_name].layout[max].location[i] = ( locations[i-1][0], locations[i-1][1] )
|
||||
|
||||
if __name__== "__main__":
|
||||
c = Config()
|
||||
|
||||
|
@ -208,3 +267,12 @@ if __name__== "__main__":
|
|||
print c.mucked_windows[w]
|
||||
|
||||
print "----------- END MUCKED WINDOW FORMATS -----------"
|
||||
|
||||
print "\n----------- POPUP WINDOW FORMATS -----------"
|
||||
for w in c.popup_windows.keys():
|
||||
print c.popup_windows[w]
|
||||
|
||||
print "----------- END MUCKED WINDOW FORMATS -----------"
|
||||
|
||||
c.edit_layout("PokerStars", 6, locations=( (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) ))
|
||||
c.save(file="testout.xml")
|
|
@ -24,6 +24,7 @@ Create and manage the database objects.
|
|||
# postmaster -D /var/lib/pgsql/data
|
||||
|
||||
# Standard Library modules
|
||||
import sys
|
||||
|
||||
# pyGTK modules
|
||||
|
||||
|
@ -32,7 +33,7 @@ import Configuration
|
|||
import SQL
|
||||
|
||||
# pgdb database module for posgres via DB-API
|
||||
#import pgdb
|
||||
import psycopg2
|
||||
# pgdb uses pyformat. is that fixed or an option?
|
||||
|
||||
# mysql bindings
|
||||
|
@ -41,7 +42,7 @@ import MySQLdb
|
|||
class Database:
|
||||
def __init__(self, c, db_name, game):
|
||||
if c.supported_databases[db_name].db_server == 'postgresql':
|
||||
self.connection = pgdb.connect(dsn = c.supported_databases[db_name].db_ip,
|
||||
self.connection = psycopg2.connect(host = c.supported_databases[db_name].db_ip,
|
||||
user = c.supported_databases[db_name].db_user,
|
||||
password = c.supported_databases[db_name].db_pass,
|
||||
database = c.supported_databases[db_name].db_name)
|
||||
|
@ -59,12 +60,12 @@ class Database:
|
|||
self.type = c.supported_databases[db_name].db_type
|
||||
self.sql = SQL.Sql(game = game, type = self.type)
|
||||
|
||||
def close(self):
|
||||
self.connection.close
|
||||
def close_connection(self):
|
||||
self.connection.close()
|
||||
|
||||
def get_table_name(self, hand_id):
|
||||
c = self.connection.cursor()
|
||||
c.execute(self.sql.query['get_table_name'], (hand_id))
|
||||
c.execute(self.sql.query['get_table_name'], (hand_id, ))
|
||||
row = c.fetchone()
|
||||
return row
|
||||
|
||||
|
@ -90,7 +91,21 @@ class Database:
|
|||
c.execute(self.sql.query['get_hand_info'], new_hand_id)
|
||||
return c.fetchall()
|
||||
|
||||
# def get_cards(self, hand):
|
||||
# this version is for the PTrackSv2 db
|
||||
# c = self.connection.cursor()
|
||||
# c.execute(self.sql.query['get_cards'], hand)
|
||||
# colnames = [desc[0] for desc in c.description]
|
||||
# cards = {}
|
||||
# for row in c.fetchall():
|
||||
# s_dict = {}
|
||||
# for name, val in zip(colnames, row):
|
||||
# s_dict[name] = val
|
||||
# cards[s_dict['seat_number']] = s_dict
|
||||
# return (cards)
|
||||
|
||||
def get_cards(self, hand):
|
||||
# this version is for the fpdb db
|
||||
c = self.connection.cursor()
|
||||
c.execute(self.sql.query['get_cards'], hand)
|
||||
colnames = [desc[0] for desc in c.description]
|
||||
|
@ -101,12 +116,14 @@ class Database:
|
|||
s_dict[name] = val
|
||||
cards[s_dict['seat_number']] = s_dict
|
||||
return (cards)
|
||||
|
||||
def get_stats_from_hand(self, hand, hero):
|
||||
|
||||
def get_stats_from_hand(self, hand, player_id = False):
|
||||
c = self.connection.cursor()
|
||||
|
||||
if not player_id: player_id = "%"
|
||||
# get the players in the hand and their seats
|
||||
c.execute(self.sql.query['get_players_from_hand'], (hand))
|
||||
# c.execute(self.sql.query['get_players_from_hand'], (hand, player_id))
|
||||
c.execute(self.sql.query['get_players_from_hand'], (hand, ))
|
||||
names = {}
|
||||
seats = {}
|
||||
for row in c.fetchall():
|
||||
|
@ -114,6 +131,7 @@ class Database:
|
|||
seats[row[0]] = row[1]
|
||||
|
||||
# now get the stats
|
||||
# c.execute(self.sql.query['get_stats_from_hand'], (hand, hand, player_id))
|
||||
c.execute(self.sql.query['get_stats_from_hand'], (hand, hand))
|
||||
colnames = [desc[0] for desc in c.description]
|
||||
stat_dict = {}
|
||||
|
@ -137,7 +155,8 @@ class Database:
|
|||
if __name__=="__main__":
|
||||
c = Configuration.Config()
|
||||
|
||||
db_connection = Database(c, 'fpdb', 'holdem') # mysql fpdb holdem
|
||||
# db_connection = Database(c, 'fpdb', 'holdem') # 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
|
||||
|
@ -149,7 +168,16 @@ if __name__=="__main__":
|
|||
hero = db_connection.get_player_id(c, 'PokerStars', 'nutOmatic')
|
||||
print "nutOmatic is id_player = %d" % hero
|
||||
|
||||
stat_dict = db_connection.get_stats_from_hand(h)
|
||||
for p in stat_dict.keys():
|
||||
print p, " ", stat_dict[p]
|
||||
|
||||
print "nutOmatics stats:"
|
||||
stat_dict = db_connection.get_stats_from_hand(h, hero)
|
||||
for p in stat_dict.keys():
|
||||
print p, " ", stat_dict[p]
|
||||
db_connection.close
|
||||
|
||||
db_connection.close_connection
|
||||
|
||||
print "press enter to continue"
|
||||
sys.stdin.readline()
|
||||
|
|
|
@ -33,12 +33,12 @@ class GuiAutoImport (threading.Thread):
|
|||
current_path=self.pathTBuffer.get_text(self.pathTBuffer.get_start_iter(), self.pathTBuffer.get_end_iter())
|
||||
|
||||
dia_chooser = gtk.FileChooserDialog(title="Please choose the path that you want to auto import",
|
||||
action=gtk.FILE_CHOOSER_ACTION_OPEN,
|
||||
action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
||||
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
|
||||
#dia_chooser.set_current_folder(pathname)
|
||||
dia_chooser.set_filename(current_path)
|
||||
#dia_chooser.set_select_multiple(select_multiple) #not in tv, but want this in bulk import
|
||||
|
||||
|
||||
response = dia_chooser.run()
|
||||
if response == gtk.RESPONSE_OK:
|
||||
#print dia_chooser.get_filename(), 'selected'
|
||||
|
@ -50,8 +50,18 @@ class GuiAutoImport (threading.Thread):
|
|||
|
||||
def do_import(self):
|
||||
"""Callback for timer to do an import iteration."""
|
||||
fpdb_import.import_file_dict(self, self.settings)
|
||||
return(1)
|
||||
for file in os.listdir(self.path):
|
||||
if os.path.isdir(file):
|
||||
print "AutoImport is not recursive - please select the final directory in which the history files are"
|
||||
else:
|
||||
self.inputFile = os.path.join(self.path, file)
|
||||
stat_info = os.stat(self.inputFile)
|
||||
if not self.import_files.has_key(self.inputFile) or stat_info.st_mtime > self.import_files[self.inputFile]:
|
||||
fpdb_import.import_file_dict(self, self.settings, callHud = True)
|
||||
self.import_files[self.inputFile] = stat_info.st_mtime
|
||||
|
||||
print "GuiAutoImport.import_dir done"
|
||||
return True
|
||||
|
||||
def startClicked(self, widget, data):
|
||||
"""runs when user clicks start on auto import tab"""
|
||||
|
@ -59,24 +69,48 @@ class GuiAutoImport (threading.Thread):
|
|||
# Check to see if we have an open file handle to the HUD and open one if we do not.
|
||||
# bufsize = 1 means unbuffered
|
||||
# We need to close this file handle sometime.
|
||||
|
||||
# TODO: Allow for importing from multiple dirs - REB 29AUG2008
|
||||
# As presently written this function does nothing if there is already a pipe open.
|
||||
# That is not correct. It should open another dir for importing while piping the
|
||||
# results to the same pipe. This means that self.path should be a a list of dirs
|
||||
# to watch.
|
||||
try: #uhhh, I don't this this is the best way to check for the existence of an attr
|
||||
getattr(self, "pipe_to_hud")
|
||||
except AttributeError:
|
||||
cwd = os.getcwd()
|
||||
command = os.path.join(cwd, 'HUD_main.py')
|
||||
self.pipe_to_hud = subprocess.Popen(command, bufsize = 1, stdin = subprocess.PIPE)
|
||||
|
||||
self.path=self.pathTBuffer.get_text(self.pathTBuffer.get_start_iter(), self.pathTBuffer.get_end_iter())
|
||||
for file in os.listdir(self.path):
|
||||
if os.path.isdir(file):
|
||||
print "AutoImport is not recursive - please select the final directory in which the history files are"
|
||||
if os.name == 'nt':
|
||||
command = "python HUD_main.py" + " %s" % (self.database)
|
||||
bs = 0 # windows is not happy with line buffing here
|
||||
self.pipe_to_hud = subprocess.Popen(command, bufsize = bs, stdin = subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
else:
|
||||
self.inputFile=self.path+os.sep+file
|
||||
self.do_import()
|
||||
print "GuiAutoImport.import_dir done"
|
||||
cwd = os.getcwd()
|
||||
command = os.path.join(cwd, 'HUD_main.py')
|
||||
bs = 1
|
||||
self.pipe_to_hud = subprocess.Popen((command, self.database), bufsize = bs, stdin = subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
# self.pipe_to_hud = subprocess.Popen((command, self.database), bufsize = bs, stdin = subprocess.PIPE,
|
||||
# universal_newlines=True)
|
||||
# command = command + " %s" % (self.database)
|
||||
# print "command = ", command
|
||||
# self.pipe_to_hud = os.popen(command, 'w')
|
||||
self.path=self.pathTBuffer.get_text(self.pathTBuffer.get_start_iter(), self.pathTBuffer.get_end_iter())
|
||||
|
||||
# Iniitally populate the self.import_files dict, which keeps mtimes for the files watched
|
||||
|
||||
self.import_files = {}
|
||||
for file in os.listdir(self.path):
|
||||
if os.path.isdir(file):
|
||||
pass # skip subdirs for now
|
||||
else:
|
||||
inputFile = os.path.join(self.path, file)
|
||||
stat_info = os.stat(inputFile)
|
||||
self.import_files[inputFile] = stat_info.st_mtime
|
||||
|
||||
self.do_import()
|
||||
|
||||
interval=int(self.intervalTBuffer.get_text(self.intervalTBuffer.get_start_iter(), self.intervalTBuffer.get_end_iter()))
|
||||
gobject.timeout_add(interval*1000, self.do_import)
|
||||
interval=int(self.intervalTBuffer.get_text(self.intervalTBuffer.get_start_iter(), self.intervalTBuffer.get_end_iter()))
|
||||
gobject.timeout_add(interval*1000, self.do_import)
|
||||
#end def GuiAutoImport.browseClicked
|
||||
|
||||
def get_vbox(self):
|
||||
|
@ -140,3 +174,22 @@ class GuiAutoImport (threading.Thread):
|
|||
self.mainVBox.add(self.startButton)
|
||||
self.startButton.show()
|
||||
#end of GuiAutoImport.__init__
|
||||
if __name__== "__main__":
|
||||
def destroy(*args): # call back for terminating the main eventloop
|
||||
gtk.main_quit()
|
||||
|
||||
settings = {}
|
||||
settings['db-host'] = "192.168.1.100"
|
||||
settings['db-user'] = "mythtv"
|
||||
settings['db-password'] = "mythtv"
|
||||
settings['db-databaseName'] = "fpdb"
|
||||
settings['hud-defaultInterval'] = 10
|
||||
settings['hud-defaultPath'] = 'C:/Program Files/PokerStars/HandHistory/nutOmatic'
|
||||
settings['imp-callFpdbHud'] = True
|
||||
|
||||
i = GuiAutoImport(settings)
|
||||
main_window = gtk.Window()
|
||||
main_window.connect("destroy", destroy)
|
||||
main_window.add(i.mainVBox)
|
||||
main_window.show()
|
||||
gtk.main()
|
||||
|
|
|
@ -26,15 +26,17 @@ Main for FreePokerTools HUD.
|
|||
# to do adjust for preferred seat
|
||||
# to do allow window resizing
|
||||
# to do hud to echo, but ignore non numbers
|
||||
# to do kill a hud
|
||||
# to do no hud window for hero
|
||||
# to do single click to display detailed stats
|
||||
# to do things to add to config.xml
|
||||
# to do font and size
|
||||
# to do bg and fg color
|
||||
# to do opacity
|
||||
|
||||
# Standard Library modules
|
||||
import sys
|
||||
import os
|
||||
import thread
|
||||
import Queue
|
||||
|
||||
# pyGTK modules
|
||||
import pygtk
|
||||
|
@ -49,19 +51,23 @@ import Hud
|
|||
|
||||
# global dict for keeping the huds
|
||||
hud_dict = {}
|
||||
|
||||
db_connection = 0;
|
||||
config = 0;
|
||||
|
||||
def destroy(*args): # call back for terminating the main eventloop
|
||||
gtk.main_quit()
|
||||
|
||||
def process_new_hand(source, condition):
|
||||
|
||||
def process_new_hand(new_hand_id, db_name):
|
||||
# there is a new hand_id to be processed
|
||||
# read the hand_id from stdin and strip whitespace
|
||||
new_hand_id = sys.stdin.readline()
|
||||
new_hand_id = new_hand_id.rstrip()
|
||||
db_connection = Database.Database(config, 'fpdb', 'holdem')
|
||||
global hud_dict
|
||||
|
||||
for h in hud_dict.keys():
|
||||
if hud_dict[h].deleted:
|
||||
del(hud_dict[h])
|
||||
|
||||
db_connection = Database.Database(config, db_name, 'temp')
|
||||
(table_name, max, poker_game) = db_connection.get_table_name(new_hand_id)
|
||||
# if a hud for this table exists, just update it
|
||||
if hud_dict.has_key(table_name):
|
||||
|
@ -71,29 +77,61 @@ def process_new_hand(source, condition):
|
|||
table_windows = Tables.discover(config)
|
||||
for t in table_windows.keys():
|
||||
if table_windows[t].name == table_name:
|
||||
hud_dict[table_name] = Hud.Hud(table_windows[t], max, poker_game, config, db_connection)
|
||||
hud_dict[table_name] = Hud.Hud(table_windows[t], max, poker_game, config, db_name)
|
||||
hud_dict[table_name].create(new_hand_id, config)
|
||||
hud_dict[table_name].update(new_hand_id, db_connection, config)
|
||||
break
|
||||
# print "table name \"%s\" not identified, no hud created" % (table_name)
|
||||
return(1)
|
||||
db_connection.close_connection()
|
||||
return(1)
|
||||
|
||||
def check_stdin(db_name):
|
||||
try:
|
||||
hand_no = dataQueue.get(block=False)
|
||||
process_new_hand(hand_no, db_name)
|
||||
except:
|
||||
pass
|
||||
|
||||
return True
|
||||
|
||||
def read_stdin(source, condition, db_name):
|
||||
new_hand_id = sys.stdin.readline()
|
||||
process_new_hand(new_hand_id, db_name)
|
||||
return True
|
||||
|
||||
def producer(): # This is the thread function
|
||||
while True:
|
||||
hand_no = sys.stdin.readline() # reads stdin
|
||||
dataQueue.put(hand_no) # and puts result on the queue
|
||||
|
||||
if __name__== "__main__":
|
||||
|
||||
if not os.name == 'posix':
|
||||
print "This version of the HUD only works with Linux or compatible.\nHUD exiting."
|
||||
print "HUD_main starting"
|
||||
|
||||
try:
|
||||
db_name = sys.argv[1]
|
||||
except:
|
||||
db_name = 'fpdb-p'
|
||||
print "Using db name = ", db_name
|
||||
|
||||
config = Configuration.Config()
|
||||
# db_connection = Database.Database(config, 'fpdb', 'holdem')
|
||||
|
||||
if os.name == 'posix':
|
||||
s_id = gobject.io_add_watch(sys.stdin, gobject.IO_IN, read_stdin, db_name)
|
||||
elif os.name == 'nt':
|
||||
dataQueue = Queue.Queue() # shared global. infinite size
|
||||
gobject.threads_init() # this is required
|
||||
thread.start_new_thread(producer, ()) # starts the thread
|
||||
gobject.timeout_add(1000, check_stdin, db_name)
|
||||
else:
|
||||
print "Sorry your operating system is not supported."
|
||||
sys.exit()
|
||||
|
||||
main_window = gtk.Window()
|
||||
main_window.connect("destroy", destroy)
|
||||
label = gtk.Label('Fake main window, blah blah, blah\nblah, blah')
|
||||
label = gtk.Label('Closing this window will exit from the HUD.')
|
||||
main_window.add(label)
|
||||
main_window.set_title("HUD Main Window")
|
||||
main_window.show_all()
|
||||
|
||||
config = Configuration.Config()
|
||||
|
||||
db_connection = Database.Database(config, 'fpdb', 'holdem')
|
||||
|
||||
s_id = gobject.io_add_watch(sys.stdin, gobject.IO_IN, process_new_hand)
|
||||
|
||||
gtk.main()
|
||||
|
|
301
pyfpdb/Hud.py
Normal file → Executable file
301
pyfpdb/Hud.py
Normal file → Executable file
|
@ -22,6 +22,7 @@ Create and manage the hud overlays.
|
|||
|
||||
########################################################################
|
||||
# Standard Library modules
|
||||
import os
|
||||
|
||||
# pyGTK modules
|
||||
import pygtk
|
||||
|
@ -29,26 +30,85 @@ import gtk
|
|||
import pango
|
||||
import gobject
|
||||
|
||||
# win32 modules -- only imported on windows systems
|
||||
if os.name == 'nt':
|
||||
import win32gui
|
||||
import win32con
|
||||
|
||||
# FreePokerTools modules
|
||||
import Tables # needed for testing only
|
||||
import Configuration
|
||||
import Stats
|
||||
import Mucked
|
||||
import Database
|
||||
import HUD_main
|
||||
|
||||
class Hud:
|
||||
|
||||
def __init__(self, table, max, poker_game, config, db_connection):
|
||||
def __init__(self, table, max, poker_game, config, db_name):
|
||||
self.table = table
|
||||
self.config = config
|
||||
self.poker_game = poker_game
|
||||
self.max = max
|
||||
self.db_connection = db_connection
|
||||
self.db_name = db_name
|
||||
self.deleted = False
|
||||
|
||||
self.stat_windows = {}
|
||||
self.popup_windows = {}
|
||||
self.font = pango.FontDescription("Sans 8")
|
||||
|
||||
|
||||
# Set up a main window for this this instance of the HUD
|
||||
self.main_window = gtk.Window()
|
||||
# self.window.set_decorated(0)
|
||||
self.main_window.set_gravity(gtk.gdk.GRAVITY_STATIC)
|
||||
self.main_window.set_keep_above(1)
|
||||
self.main_window.set_title(table.name)
|
||||
self.main_window.connect("destroy", self.kill_hud)
|
||||
|
||||
self.ebox = gtk.EventBox()
|
||||
self.label = gtk.Label("Close this window to\nkill the HUD for\n %s" % (table.name))
|
||||
self.main_window.add(self.ebox)
|
||||
self.ebox.add(self.label)
|
||||
self.main_window.move(self.table.x, self.table.y)
|
||||
|
||||
# A popup window for the main window
|
||||
self.menu = gtk.Menu()
|
||||
self.item1 = gtk.MenuItem('Kill this HUD')
|
||||
self.menu.append(self.item1)
|
||||
self.item1.connect("activate", self.kill_hud)
|
||||
self.item1.show()
|
||||
self.item2 = gtk.MenuItem('Save Layout')
|
||||
self.menu.append(self.item2)
|
||||
self.item2.connect("activate", self.save_layout)
|
||||
self.item2.show()
|
||||
self.ebox.connect_object("button-press-event", self.on_button_press, self.menu)
|
||||
|
||||
self.main_window.show_all()
|
||||
# set_keep_above(1) for windows
|
||||
if os.name == 'nt': self.topify_window(self.main_window)
|
||||
|
||||
def on_button_press(self, widget, event):
|
||||
if event.button == 3:
|
||||
widget.popup(None, None, None, event.button, event.time)
|
||||
return True
|
||||
return False
|
||||
|
||||
def kill_hud(self, args):
|
||||
for k in self.stat_windows.keys():
|
||||
self.stat_windows[k].window.destroy()
|
||||
self.main_window.destroy()
|
||||
self.deleted = True
|
||||
|
||||
def save_layout(self, *args):
|
||||
new_layout = []
|
||||
for sw in self.stat_windows:
|
||||
loc = self.stat_windows[sw].window.get_position()
|
||||
new_loc = (loc[0] - self.table.x, loc[1] - self.table.y)
|
||||
new_layout.append(new_loc)
|
||||
print new_layout
|
||||
self.config.edit_layout(self.table.site, self.table.max, locations = new_layout)
|
||||
self.config.save()
|
||||
|
||||
def create(self, hand, config):
|
||||
# update this hud, to the stats and players as of "hand"
|
||||
# hand is the hand id of the most recent hand played at this table
|
||||
|
@ -58,6 +118,7 @@ class Hud:
|
|||
for i in range(1, self.max + 1):
|
||||
(x, y) = config.supported_sites[self.table.site].layout[self.max].location[i]
|
||||
self.stat_windows[i] = Stat_Window(game = config.supported_games[self.poker_game],
|
||||
parent = self,
|
||||
table = self.table,
|
||||
x = x,
|
||||
y = y,
|
||||
|
@ -79,10 +140,10 @@ class Hud:
|
|||
# self.mucked_window.show_all()
|
||||
|
||||
def update(self, hand, db, config):
|
||||
stat_dict = db.get_stats_from_hand(hand, 3)
|
||||
self.hand = hand # this is the last hand, so it is available later
|
||||
stat_dict = db.get_stats_from_hand(hand)
|
||||
for s in stat_dict.keys():
|
||||
# for r in range(0, 2):
|
||||
# for c in range(0, 3):
|
||||
self.stat_windows[stat_dict[s]['seat']].player_id = stat_dict[s]['player_id']
|
||||
for r in range(0, config.supported_games[self.poker_game].rows):
|
||||
for c in range(0, config.supported_games[self.poker_game].cols):
|
||||
number = Stats.do_stat(stat_dict, player = stat_dict[s]['player_id'], stat = self.stats[r][c])
|
||||
|
@ -91,7 +152,33 @@ class Hud:
|
|||
number[3] + ", " + number[4]
|
||||
Stats.do_tip(self.stat_windows[stat_dict[s]['seat']].e_box[r][c], tip)
|
||||
# self.m.update(hand)
|
||||
|
||||
def topify_window(self, window):
|
||||
"""Set the specified gtk window to stayontop in MS Windows."""
|
||||
|
||||
def windowEnumerationHandler(hwnd, resultList):
|
||||
'''Callback for win32gui.EnumWindows() to generate list of window handles.'''
|
||||
resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
|
||||
|
||||
unique_name = 'unique name for finding this window'
|
||||
real_name = window.get_title()
|
||||
window.set_title(unique_name)
|
||||
tl_windows = []
|
||||
win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
|
||||
|
||||
for w in tl_windows:
|
||||
if w[1] == unique_name:
|
||||
win32gui.SetWindowPos(w[0], win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE|win32con.SWP_NOSIZE)
|
||||
# notify_id = (w[0],
|
||||
# 0,
|
||||
# win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP,
|
||||
# win32con.WM_USER+20,
|
||||
# 0,
|
||||
# '')
|
||||
# win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, notify_id)
|
||||
#
|
||||
window.set_title(real_name)
|
||||
|
||||
class Stat_Window:
|
||||
|
||||
def button_press_cb(self, widget, event, *args):
|
||||
|
@ -101,7 +188,7 @@ class Stat_Window:
|
|||
if event.button == 1: # left button event
|
||||
if event.type == gtk.gdk.BUTTON_PRESS: # left button single click
|
||||
if self.sb_click > 0: return
|
||||
self.sb_click = gobject.timeout_add(250, self.single_click)
|
||||
self.sb_click = gobject.timeout_add(250, self.single_click, widget)
|
||||
elif event.type == gtk.gdk._2BUTTON_PRESS: # left button double click
|
||||
if self.sb_click > 0:
|
||||
gobject.source_remove(self.sb_click)
|
||||
|
@ -109,17 +196,20 @@ class Stat_Window:
|
|||
self.double_click(widget, event, *args)
|
||||
|
||||
if event.button == 2: # middle button event
|
||||
print "middle button clicked"
|
||||
pass
|
||||
# print "middle button clicked"
|
||||
|
||||
if event.button == 3: # right button event
|
||||
print "right button clicked"
|
||||
pass
|
||||
# print "right button clicked"
|
||||
|
||||
def single_click(self):
|
||||
def single_click(self, widget):
|
||||
# Callback from the timeout in the single-click finding part of the
|
||||
# button press call back. This needs to be modified to get all the
|
||||
# arguments from the call.
|
||||
print "left button clicked"
|
||||
# print "left button clicked"
|
||||
self.sb_click = 0
|
||||
Popup_window(widget, self)
|
||||
return False
|
||||
|
||||
def double_click(self, widget, event, *args):
|
||||
|
@ -136,13 +226,14 @@ class Stat_Window:
|
|||
top.set_decorated(1)
|
||||
top.move(x, y)
|
||||
|
||||
def __init__(self, game, table, seat, x, y, player_id, font):
|
||||
self.game = game
|
||||
self.table = table
|
||||
self.x = x + table.x
|
||||
self.y = y + table.y
|
||||
self.player_id = player_id
|
||||
self.sb_click = 0
|
||||
def __init__(self, parent, game, table, seat, x, y, player_id, font):
|
||||
self.parent = parent # Hud object that this stat window belongs to
|
||||
self.game = game # Configuration object for the curren
|
||||
self.table = table # Table object where this is going
|
||||
self.x = x + table.x # table.x and y are the location of the table
|
||||
self.y = y + table.y # x and y are the location relative to table.x & y
|
||||
self.player_id = player_id # looks like this isn't used ;)
|
||||
self.sb_click = 0 # used to figure out button clicks
|
||||
|
||||
self.window = gtk.Window()
|
||||
self.window.set_decorated(0)
|
||||
|
@ -163,7 +254,7 @@ class Stat_Window:
|
|||
for c in range(self.game.cols):
|
||||
self.e_box[r].append( gtk.EventBox() )
|
||||
Stats.do_tip(self.e_box[r][c], 'farts')
|
||||
self.grid.attach(self.e_box[r][c], c, c+1, r, r+1, xpadding = 1, ypadding = 1)
|
||||
self.grid.attach(self.e_box[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0)
|
||||
self.label[r].append( gtk.Label('xxx') )
|
||||
self.e_box[r][c].add(self.label[r][c])
|
||||
self.e_box[r][c].connect("button_press_event", self.button_press_cb)
|
||||
|
@ -172,10 +263,173 @@ class Stat_Window:
|
|||
self.window.realize
|
||||
self.window.move(self.x, self.y)
|
||||
self.window.show_all()
|
||||
# set_keep_above(1) for windows
|
||||
if os.name == 'nt': self.topify_window(self.window)
|
||||
|
||||
def topify_window(self, window):
|
||||
"""Set the specified gtk window to stayontop in MS Windows."""
|
||||
|
||||
def windowEnumerationHandler(hwnd, resultList):
|
||||
'''Callback for win32gui.EnumWindows() to generate list of window handles.'''
|
||||
resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
|
||||
|
||||
unique_name = 'unique name for finding this window'
|
||||
real_name = window.get_title()
|
||||
window.set_title(unique_name)
|
||||
tl_windows = []
|
||||
win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
|
||||
|
||||
for w in tl_windows:
|
||||
if w[1] == unique_name:
|
||||
win32gui.SetWindowPos(w[0], win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE|win32con.SWP_NOSIZE)
|
||||
# notify_id = (w[0],
|
||||
# 0,
|
||||
# win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP,
|
||||
# win32con.WM_USER+20,
|
||||
# 0,
|
||||
# '')
|
||||
# win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, notify_id)
|
||||
#
|
||||
window.set_title(real_name)
|
||||
|
||||
def destroy(*args): # call back for terminating the main eventloop
|
||||
gtk.main_quit()
|
||||
|
||||
class Popup_window:
|
||||
def __init__(self, parent, stat_window):
|
||||
self.sb_click = 0
|
||||
|
||||
# create the popup window
|
||||
self.window = gtk.Window()
|
||||
self.window.set_decorated(0)
|
||||
self.window.set_gravity(gtk.gdk.GRAVITY_STATIC)
|
||||
self.window.set_keep_above(1)
|
||||
self.window.set_title("popup")
|
||||
self.window.set_property("skip-taskbar-hint", True)
|
||||
self.window.set_transient_for(parent.get_toplevel())
|
||||
self.window.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||
|
||||
self.ebox = gtk.EventBox()
|
||||
self.ebox.connect("button_press_event", self.button_press_cb)
|
||||
self.lab = gtk.Label("stuff\nstuff\nstuff")
|
||||
|
||||
# need an event box so we can respond to clicks
|
||||
self.window.add(self.ebox)
|
||||
self.ebox.add(self.lab)
|
||||
self.window.realize
|
||||
|
||||
# figure out the row, col address of the click that activated the popup
|
||||
row = 0
|
||||
col = 0
|
||||
for r in range(0, stat_window.game.rows):
|
||||
for c in range(0, stat_window.game.cols):
|
||||
if stat_window.e_box[r][c] == parent:
|
||||
row = r
|
||||
col = c
|
||||
break
|
||||
|
||||
# figure out what popup format we're using
|
||||
popup_format = "default"
|
||||
for stat in stat_window.game.stats.keys():
|
||||
if stat_window.game.stats[stat].row == row and stat_window.game.stats[stat].col == col:
|
||||
popup_format = stat_window.game.stats[stat].popup
|
||||
break
|
||||
|
||||
# get the list of stats to be presented from the config
|
||||
stat_list = []
|
||||
for w in stat_window.parent.config.popup_windows.keys():
|
||||
if w == popup_format:
|
||||
stat_list = stat_window.parent.config.popup_windows[w].pu_stats
|
||||
break
|
||||
|
||||
# get a database connection
|
||||
db_connection = Database.Database(stat_window.parent.config, stat_window.parent.db_name, 'temp')
|
||||
|
||||
# calculate the stat_dict and then create the text for the pu
|
||||
# stat_dict = db_connection.get_stats_from_hand(stat_window.parent.hand, stat_window.player_id)
|
||||
stat_dict = db_connection.get_stats_from_hand(stat_window.parent.hand)
|
||||
db_connection.close_connection()
|
||||
|
||||
pu_text = ""
|
||||
for s in stat_list:
|
||||
number = Stats.do_stat(stat_dict, player = int(stat_window.player_id), stat = s)
|
||||
pu_text += number[3] + "\n"
|
||||
|
||||
self.lab.set_text(pu_text)
|
||||
self.window.show_all()
|
||||
# set_keep_above(1) for windows
|
||||
if os.name == 'nt': self.topify_window(self.window)
|
||||
|
||||
def button_press_cb(self, widget, event, *args):
|
||||
# This handles all callbacks from button presses on the event boxes in
|
||||
# the popup windows. There is a bit of an ugly kludge to separate single-
|
||||
# and double-clicks. This is the same code as in the Stat_window class
|
||||
if event.button == 1: # left button event
|
||||
if event.type == gtk.gdk.BUTTON_PRESS: # left button single click
|
||||
if self.sb_click > 0: return
|
||||
self.sb_click = gobject.timeout_add(250, self.single_click, widget)
|
||||
elif event.type == gtk.gdk._2BUTTON_PRESS: # left button double click
|
||||
if self.sb_click > 0:
|
||||
gobject.source_remove(self.sb_click)
|
||||
self.sb_click = 0
|
||||
self.double_click(widget, event, *args)
|
||||
|
||||
if event.button == 2: # middle button event
|
||||
pass
|
||||
# print "middle button clicked"
|
||||
|
||||
if event.button == 3: # right button event
|
||||
pass
|
||||
# print "right button clicked"
|
||||
|
||||
def single_click(self, widget):
|
||||
# Callback from the timeout in the single-click finding part of the
|
||||
# button press call back. This needs to be modified to get all the
|
||||
# arguments from the call.
|
||||
self.sb_click = 0
|
||||
self.window.destroy()
|
||||
return False
|
||||
|
||||
def double_click(self, widget, event, *args):
|
||||
self.toggle_decorated(widget)
|
||||
|
||||
def toggle_decorated(self, widget):
|
||||
top = widget.get_toplevel()
|
||||
(x, y) = top.get_position()
|
||||
|
||||
if top.get_decorated():
|
||||
top.set_decorated(0)
|
||||
top.move(x, y)
|
||||
else:
|
||||
top.set_decorated(1)
|
||||
top.move(x, y)
|
||||
|
||||
def topify_window(self, window):
|
||||
"""Set the specified gtk window to stayontop in MS Windows."""
|
||||
|
||||
def windowEnumerationHandler(hwnd, resultList):
|
||||
'''Callback for win32gui.EnumWindows() to generate list of window handles.'''
|
||||
resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
|
||||
|
||||
unique_name = 'unique name for finding this window'
|
||||
real_name = window.get_title()
|
||||
window.set_title(unique_name)
|
||||
tl_windows = []
|
||||
win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
|
||||
|
||||
for w in tl_windows:
|
||||
if w[1] == unique_name:
|
||||
win32gui.SetWindowPos(w[0], win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE|win32con.SWP_NOSIZE)
|
||||
# notify_id = (w[0],
|
||||
# 0,
|
||||
# win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP,
|
||||
# win32con.WM_USER+20,
|
||||
# 0,
|
||||
# '')
|
||||
# win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, notify_id)
|
||||
#
|
||||
window.set_title(real_name)
|
||||
|
||||
if __name__== "__main__":
|
||||
main_window = gtk.Window()
|
||||
main_window.connect("destroy", destroy)
|
||||
|
@ -187,15 +441,6 @@ if __name__== "__main__":
|
|||
tables = Tables.discover(c)
|
||||
db = Database.Database(c, 'fpdb', 'holdem')
|
||||
|
||||
for attr in dir(Stats):
|
||||
if attr.startswith('__'): continue
|
||||
if attr == 'Configuration' or attr == 'Database': continue
|
||||
if attr == 'GInitiallyUnowned': continue
|
||||
# print Stats.attr.__doc__
|
||||
|
||||
print Stats.vpip.__doc__
|
||||
|
||||
|
||||
for t in tables:
|
||||
win = Hud(t, 8, c, db)
|
||||
# t.get_details()
|
||||
|
|
|
@ -105,7 +105,8 @@ class MuckedList:
|
|||
self.mucked_cards.update(model.get_value(iter, 0))
|
||||
|
||||
def update(self, new_hand_id):
|
||||
info_row = self.db_connection.get_hand_info(new_hand_id)
|
||||
# info_row = self.db_connection.get_hand_info(new_hand_id)
|
||||
info_row = ((new_hand_id, "xxxx", 0), )
|
||||
iter = self.liststore.append(info_row[0])
|
||||
sel = self.treeview.get_selection()
|
||||
sel.select_iter(iter)
|
||||
|
@ -156,11 +157,15 @@ class MuckedCards:
|
|||
self.grid.attach(self.grid_contents[(c, r)], c, c+1, r, r+1, xpadding = 1, ypadding = 1)
|
||||
|
||||
self.parent.add(self.grid)
|
||||
|
||||
|
||||
def translate_cards(self, old_cards):
|
||||
pass
|
||||
|
||||
def update(self, new_hand_id):
|
||||
cards = self.db_connection.get_cards(new_hand_id)
|
||||
self.clear()
|
||||
|
||||
cards = self.translate_cards(cards)
|
||||
for c in cards.keys():
|
||||
self.grid_contents[(1, cards[c]['seat_number'] - 1)].set_text(cards[c]['screen_name'])
|
||||
|
||||
|
@ -224,7 +229,7 @@ if __name__== "__main__":
|
|||
return(True)
|
||||
|
||||
config = Configuration.Config()
|
||||
db_connection = Database.Database(config, 'PTrackSv2', 'razz')
|
||||
db_connection = Database.Database(config, 'fpdb', '')
|
||||
|
||||
main_window = gtk.Window()
|
||||
main_window.set_keep_above(True)
|
||||
|
@ -236,4 +241,3 @@ if __name__== "__main__":
|
|||
s_id = gobject.io_add_watch(sys.stdin, gobject.IO_IN, process_new_hand)
|
||||
|
||||
gtk.main()
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ class Sql:
|
|||
FROM game_players
|
||||
WHERE game_id = %s AND player_id = 3
|
||||
"""
|
||||
|
||||
|
||||
self.query['get_cards'] = """
|
||||
select
|
||||
seat_number,
|
||||
|
@ -173,10 +173,6 @@ class Sql:
|
|||
|
||||
self.query['get_stats_from_hand'] = """
|
||||
SELECT HudCache.playerId AS player_id,
|
||||
HudCache.gametypeId AS gametypeId,
|
||||
activeSeats AS n_active,
|
||||
position AS position,
|
||||
HudCache.tourneyTypeId AS tourneyTypeId,
|
||||
sum(HDs) AS n,
|
||||
sum(street0VPI) AS vpip,
|
||||
sum(street0Aggr) AS pfr,
|
||||
|
@ -241,12 +237,18 @@ class Sql:
|
|||
AND Hands.gametypeId = HudCache.gametypeId
|
||||
GROUP BY HudCache.PlayerId
|
||||
"""
|
||||
# AND PlayerId LIKE %s
|
||||
# HudCache.gametypeId AS gametypeId,
|
||||
# activeSeats AS n_active,
|
||||
# position AS position,
|
||||
# HudCache.tourneyTypeId AS tourneyTypeId,
|
||||
|
||||
self.query['get_players_from_hand'] = """
|
||||
SELECT HandsPlayers.playerId, seatNo, name
|
||||
FROM HandsPlayers INNER JOIN Players ON (HandsPlayers.playerId = Players.id)
|
||||
WHERE handId = %s
|
||||
"""
|
||||
# WHERE handId = %s AND Players.id LIKE %s
|
||||
|
||||
self.query['get_table_name'] = """
|
||||
select tableName, maxSeats, category
|
||||
|
@ -255,6 +257,31 @@ class Sql:
|
|||
and Gametypes.id = Hands.gametypeId
|
||||
"""
|
||||
|
||||
self.query['get_cards'] = """
|
||||
select
|
||||
seatNo AS seat_number,
|
||||
name AS screen_name,
|
||||
card1Value, card1Suit,
|
||||
card2Value, card2Suit,
|
||||
card3Value, card3Suit,
|
||||
card4Value, card4Suit,
|
||||
card5Value, card5Suit,
|
||||
card6Value, card6Suit,
|
||||
card7Value, card7Suit
|
||||
from HandsPlayers, Players
|
||||
where handID = %s and HandsPlayers.playerId = Players.id
|
||||
order by seatNo
|
||||
"""
|
||||
|
||||
# self.query['get_hand_info'] = """
|
||||
# SELECT
|
||||
# game_id,
|
||||
# CONCAT(hole_card_1, hole_card_2, hole_card_3, hole_card_4, hole_card_5, hole_card_6, hole_card_7) AS hand,
|
||||
# total_won-total_bet AS net
|
||||
# FROM game_players
|
||||
# WHERE game_id = %s AND player_id = 3
|
||||
# """
|
||||
|
||||
if __name__== "__main__":
|
||||
# just print the default queries and exit
|
||||
s = Sql(game = 'razz', type = 'ptracks')
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
# 6 For each stat you make add a line to the __main__ function to test it.
|
||||
|
||||
# Standard Library modules
|
||||
#import sys
|
||||
|
||||
# pyGTK modules
|
||||
import pygtk
|
||||
|
@ -55,10 +56,6 @@ import Database
|
|||
def do_tip(widget, tip):
|
||||
widget.set_tooltip_text(tip)
|
||||
|
||||
def list_stats():
|
||||
for key in dir():
|
||||
print key
|
||||
|
||||
def do_stat(stat_dict, player = 24, stat = 'vpip'):
|
||||
return eval("%(stat)s(stat_dict, %(player)d)" % {'stat': stat, 'player': player})
|
||||
# OK, for reference the tuple returned by the stat is:
|
||||
|
@ -72,9 +69,7 @@ def do_stat(stat_dict, player = 24, stat = 'vpip'):
|
|||
###########################################
|
||||
# functions that return individual stats
|
||||
def vpip(stat_dict, player):
|
||||
"""
|
||||
Voluntarily put $ in the pot
|
||||
"""
|
||||
""" Voluntarily put $ in the pot."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['vpip'])/float(stat_dict[player]['n'])
|
||||
|
@ -94,6 +89,7 @@ def vpip(stat_dict, player):
|
|||
)
|
||||
|
||||
def pfr(stat_dict, player):
|
||||
""" Preflop (3rd street) raise."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['pfr'])/float(stat_dict[player]['n'])
|
||||
|
@ -114,6 +110,7 @@ def pfr(stat_dict, player):
|
|||
)
|
||||
|
||||
def wtsd(stat_dict, player):
|
||||
""" Went to SD when saw flop/4th."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['sd'])/float(stat_dict[player]['saw_f'])
|
||||
|
@ -134,6 +131,7 @@ def wtsd(stat_dict, player):
|
|||
)
|
||||
|
||||
def wmsd(stat_dict, player):
|
||||
""" Won $ at showdown."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['wmsd'])/float(stat_dict[player]['sd'])
|
||||
|
@ -141,7 +139,7 @@ def wmsd(stat_dict, player):
|
|||
'%3.1f' % (100*stat) + '%',
|
||||
'w=%3.1f' % (100*stat) + '%',
|
||||
'wmsd=%3.1f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['wmsd'], stat_dict[player]['sd']),
|
||||
'(%f5.0/%d)' % (stat_dict[player]['wmsd'], stat_dict[player]['sd']),
|
||||
'% won money at showdown'
|
||||
)
|
||||
except:
|
||||
|
@ -154,6 +152,7 @@ def wmsd(stat_dict, player):
|
|||
)
|
||||
|
||||
def saw_f(stat_dict, player):
|
||||
""" Saw flop/4th."""
|
||||
try:
|
||||
num = float(stat_dict[player]['saw_f'])
|
||||
den = float(stat_dict[player]['n'])
|
||||
|
@ -178,6 +177,7 @@ def saw_f(stat_dict, player):
|
|||
)
|
||||
|
||||
def n(stat_dict, player):
|
||||
""" Number of hands played."""
|
||||
try:
|
||||
return (stat_dict[player]['n'],
|
||||
'%d' % (stat_dict[player]['n']),
|
||||
|
@ -187,15 +187,16 @@ def n(stat_dict, player):
|
|||
'number hands seen'
|
||||
)
|
||||
except:
|
||||
return (stat_dict[player][0],
|
||||
'%d' % (stat_dict[player][0]),
|
||||
'n=%d' % (stat_dict[player][0]),
|
||||
'n=%d' % (stat_dict[player][0]),
|
||||
'(%d)' % (stat_dict[player][0]),
|
||||
return (0,
|
||||
'%d' % (0),
|
||||
'n=%d' % (0),
|
||||
'n=%d' % (0),
|
||||
'(%d)' % (0),
|
||||
'number hands seen'
|
||||
)
|
||||
|
||||
def fold_f(stat_dict, player):
|
||||
""" Folded flop/4th."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['fold_2'])/fold(stat_dict[player]['saw_f'])
|
||||
|
@ -216,6 +217,7 @@ def fold_f(stat_dict, player):
|
|||
)
|
||||
|
||||
def steal(stat_dict, player):
|
||||
""" Steal %."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['steal'])/float(stat_dict[player]['steal_opp'])
|
||||
|
@ -236,6 +238,7 @@ def steal(stat_dict, player):
|
|||
)
|
||||
|
||||
def f_SB_steal(stat_dict, player):
|
||||
""" Folded SB to steal."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['SBnotDef'])/float(stat_dict[player]['SBstolen'])
|
||||
|
@ -256,6 +259,7 @@ def f_SB_steal(stat_dict, player):
|
|||
)
|
||||
|
||||
def f_BB_steal(stat_dict, player):
|
||||
""" Folded BB to steal."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['BBnotDef'])/float(stat_dict[player]['BBstolen'])
|
||||
|
@ -276,6 +280,7 @@ def f_BB_steal(stat_dict, player):
|
|||
)
|
||||
|
||||
def three_B_0(stat_dict, player):
|
||||
""" Three bet preflop/3rd."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['TB_0'])/float(stat_dict[player]['TB_opp_0'])
|
||||
|
@ -296,6 +301,7 @@ def three_B_0(stat_dict, player):
|
|||
)
|
||||
|
||||
def WMsF(stat_dict, player):
|
||||
""" Won $ when saw flop/4th."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['w_w_s_1'])/float(stat_dict[player]['saw_1'])
|
||||
|
@ -316,6 +322,7 @@ def WMsF(stat_dict, player):
|
|||
)
|
||||
|
||||
def a_freq_1(stat_dict, player):
|
||||
""" Flop/4th aggression frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['aggr_1'])/float(stat_dict[player]['saw_f'])
|
||||
|
@ -336,6 +343,7 @@ def a_freq_1(stat_dict, player):
|
|||
)
|
||||
|
||||
def a_freq_2(stat_dict, player):
|
||||
""" Turn/5th aggression frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['aggr_2'])/float(stat_dict[player]['saw_2'])
|
||||
|
@ -356,6 +364,7 @@ def a_freq_2(stat_dict, player):
|
|||
)
|
||||
|
||||
def a_freq_3(stat_dict, player):
|
||||
""" River/6th aggression frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['aggr_3'])/float(stat_dict[player]['saw_3'])
|
||||
|
@ -376,6 +385,7 @@ def a_freq_3(stat_dict, player):
|
|||
)
|
||||
|
||||
def a_freq_4(stat_dict, player):
|
||||
""" 7th street aggression frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['aggr_4'])/float(stat_dict[player]['saw_4'])
|
||||
|
@ -389,13 +399,14 @@ def a_freq_4(stat_dict, player):
|
|||
except:
|
||||
return (stat,
|
||||
'%3.1f' % (0) + '%',
|
||||
'a1=%3.1f' % (0) + '%',
|
||||
'a_fq_1=%3.1f' % (0) + '%',
|
||||
'a4=%3.1f' % (0) + '%',
|
||||
'a_fq_4=%3.1f' % (0) + '%',
|
||||
'(%d/%d)' % (0, 0),
|
||||
'Aggression Freq flop/4th'
|
||||
)
|
||||
|
||||
def cb_1(stat_dict, player):
|
||||
""" Flop continuation bet."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['CB_1'])/float(stat_dict[player]['CB_opp_1'])
|
||||
|
@ -416,6 +427,7 @@ def cb_1(stat_dict, player):
|
|||
)
|
||||
|
||||
def cb_2(stat_dict, player):
|
||||
""" Turn continuation bet."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['CB_2'])/float(stat_dict[player]['CB_opp_2'])
|
||||
|
@ -436,6 +448,7 @@ def cb_2(stat_dict, player):
|
|||
)
|
||||
|
||||
def cb_3(stat_dict, player):
|
||||
""" River continuation bet."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['CB_3'])/float(stat_dict[player]['CB_opp_3'])
|
||||
|
@ -456,6 +469,7 @@ def cb_3(stat_dict, player):
|
|||
)
|
||||
|
||||
def cb_4(stat_dict, player):
|
||||
""" 7th street continuation bet."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['CB_4'])/float(stat_dict[player]['CB_opp_4'])
|
||||
|
@ -476,6 +490,7 @@ def cb_4(stat_dict, player):
|
|||
)
|
||||
|
||||
def ffreq_1(stat_dict, player):
|
||||
""" Flop/4th fold frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['f_freq_1'])/float(stat_dict[player]['was_raised_1'])
|
||||
|
@ -496,6 +511,7 @@ def ffreq_1(stat_dict, player):
|
|||
)
|
||||
|
||||
def ffreq_2(stat_dict, player):
|
||||
""" Turn/5th fold frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['f_freq_2'])/float(stat_dict[player]['was_raised_2'])
|
||||
|
@ -516,6 +532,7 @@ def ffreq_2(stat_dict, player):
|
|||
)
|
||||
|
||||
def ffreq_3(stat_dict, player):
|
||||
""" River/6th fold frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['f_freq_3'])/float(stat_dict[player]['was_raised_3'])
|
||||
|
@ -536,6 +553,7 @@ def ffreq_3(stat_dict, player):
|
|||
)
|
||||
|
||||
def ffreq_4(stat_dict, player):
|
||||
""" 7th fold frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['f_freq_4'])/float(stat_dict[player]['was_raised_4'])
|
||||
|
@ -559,7 +577,7 @@ if __name__== "__main__":
|
|||
c = Configuration.Config()
|
||||
db_connection = Database.Database(c, 'fpdb', 'holdem')
|
||||
h = db_connection.get_last_hand()
|
||||
stat_dict = db_connection.get_stats_from_hand(h, 0)
|
||||
stat_dict = db_connection.get_stats_from_hand(h)
|
||||
|
||||
for player in stat_dict.keys():
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'vpip')
|
||||
|
@ -587,13 +605,14 @@ if __name__== "__main__":
|
|||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_3')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_4')
|
||||
|
||||
# print "\n\nLegal stats:"
|
||||
# for attr in dir():
|
||||
# if attr.startswith('__'): continue
|
||||
# if attr == 'Configuration' or attr == 'Database': continue
|
||||
# if attr == 'GInitiallyUnowned': continue
|
||||
# print attr.__doc__
|
||||
#
|
||||
# print vpip.__doc__
|
||||
print "\n\nLegal stats:"
|
||||
for attr in dir():
|
||||
if attr.startswith('__'): continue
|
||||
if attr in ("Configuration", "Database", "GInitiallyUnowned", "gtk", "pygtk",
|
||||
"player", "c", "db_connection", "do_stat", "do_tip", "stat_dict",
|
||||
"h"): continue
|
||||
print attr, eval("%s.__doc__" % (attr))
|
||||
# print " <pu_stat pu_stat_name = \"%s\"> </pu_stat>" % (attr)
|
||||
|
||||
db_connection.close
|
||||
|
||||
|
|
102
pyfpdb/Tables.py
102
pyfpdb/Tables.py
|
@ -26,8 +26,14 @@ of Table_Window objects representing the windows found.
|
|||
|
||||
# Standard Library modules
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
# Win32 modules
|
||||
|
||||
if os.name == 'nt':
|
||||
import win32gui
|
||||
|
||||
# FreePokerTools modules
|
||||
import Configuration
|
||||
|
||||
|
@ -49,8 +55,24 @@ class Table_Window:
|
|||
table.tournament = 0
|
||||
|
||||
def discover(c):
|
||||
if os.name == 'posix':
|
||||
tables = discover_posix(c)
|
||||
return tables
|
||||
elif os.name == 'nt':
|
||||
tables = discover_nt(c)
|
||||
return tables
|
||||
elif ox.name == 'mac':
|
||||
tables = discover_mac(c)
|
||||
return tables
|
||||
else: tables = {}
|
||||
|
||||
return(tables)
|
||||
|
||||
def discover_posix(c):
|
||||
""" Poker client table window finder for posix/Linux = XWindows."""
|
||||
tables = {}
|
||||
for listing in os.popen('xwininfo -root -tree').readlines():
|
||||
# xwininfo -root -tree -id 0xnnnnn gets the info on a single window
|
||||
if re.search('Lobby', listing): continue
|
||||
if re.search('Instant Hand History', listing): continue
|
||||
if not re.search('Logged In as ', listing): continue
|
||||
|
@ -75,6 +97,68 @@ def discover(c):
|
|||
eval("%s(tw)" % c.supported_sites[s].decoder)
|
||||
tables[tw.name] = tw
|
||||
return tables
|
||||
#
|
||||
# The discover_xx functions query the system and report on the poker clients
|
||||
# currently displayed on the screen. The discover_posix should give you
|
||||
# some idea how to support other systems.
|
||||
#
|
||||
# discover_xx() returns a dict of TableWindow objects--one TableWindow
|
||||
# object for each poker client table on the screen.
|
||||
#
|
||||
# Each TableWindow object must have the following attributes correctly populated:
|
||||
# tw.site = the site name, e.g. PokerStars, FullTilt. This must match the site
|
||||
# name specified in the config file.
|
||||
# tw.number = This is the system id number for the client table window in the
|
||||
# format that the system presents it.
|
||||
# tw.title = The full title from the window title bar.
|
||||
# tw.width, tw.height = The width and height of the window in pixels. This is
|
||||
# the internal width and height, not including the title bar and
|
||||
# window borders.
|
||||
# tw.x, tw.y = The x, y (horizontal, vertical) location of the window relative
|
||||
# to the top left of the display screen. This also does not include the
|
||||
# title bar and window borders. To put it another way, this is the
|
||||
# screen location of (0, 0) in the working window.
|
||||
|
||||
def win_enum_handler(hwnd, titles):
|
||||
titles[hwnd] = win32gui.GetWindowText(hwnd)
|
||||
|
||||
def child_enum_handler(hwnd, children):
|
||||
print hwnd, win32.GetWindowRect(hwnd)
|
||||
|
||||
def discover_nt(c):
|
||||
""" Poker client table window finder for Windows."""
|
||||
#
|
||||
# I cannot figure out how to get the inside dimensions of the poker table
|
||||
# windows. So I just assume all borders are 3 thick and all title bars
|
||||
# are 29 high. No doubt this will be off when used with certain themes.
|
||||
#
|
||||
b_width = 3
|
||||
tb_height = 29
|
||||
titles = {}
|
||||
tables = {}
|
||||
win32gui.EnumWindows(win_enum_handler, titles)
|
||||
for hwnd in titles.keys():
|
||||
if re.search('Logged In as', titles[hwnd]) and not re.search('Lobby', titles[hwnd]):
|
||||
tw = Table_Window()
|
||||
# tw.site = c.supported_sites[s].site_name
|
||||
tw.number = hwnd
|
||||
(x, y, width, height) = win32gui.GetWindowRect(hwnd)
|
||||
tw.title = titles[hwnd]
|
||||
tw.width = int( width ) - 2*b_width
|
||||
tw.height = int( height ) - b_width - tb_height
|
||||
tw.x = int( x ) + b_width
|
||||
tw.y = int( y ) + tb_height
|
||||
eval("%s(tw)" % "pokerstars_decode_table")
|
||||
tw.site = "PokerStars"
|
||||
|
||||
|
||||
tables[tw.name] = tw
|
||||
return tables
|
||||
|
||||
def discover_mac(c):
|
||||
""" Poker client table window finder for Macintosh."""
|
||||
tables = {}
|
||||
return tables
|
||||
|
||||
def pokerstars_decode_table(tw):
|
||||
# extract the table name OR the tournament number and table name from the title
|
||||
|
@ -95,18 +179,6 @@ def pokerstars_decode_table(tw):
|
|||
|
||||
mo = re.search('(Razz|Stud H/L|Stud|Omaha H/L|Omaha|Hold\'em|5-Card Draw|Triple Draw 2-7 Lowball)', tw.title)
|
||||
|
||||
#Traceback (most recent call last):
|
||||
# File "/home/fatray/razz-poker-productio/HUD_main.py", line 41, in process_new_hand
|
||||
# table_windows = Tables.discover(config)
|
||||
# File "/home/fatray/razz-poker-productio/Tables.py", line 58, in discover
|
||||
# eval("%s(tw)" % c.supported_sites[s].decoder)
|
||||
# File "<string>", line 1, in <module>
|
||||
# File "/home/fatray/razz-poker-productio/Tables.py", line 80, in pokerstars_decode_table
|
||||
# tw.game = mo.group(1).lower()
|
||||
#AttributeError: 'NoneType' object has no attribute 'group'
|
||||
#
|
||||
#This problem happens with observed windows!!
|
||||
|
||||
tw.game = mo.group(1).lower()
|
||||
tw.game = re.sub('\'', '', tw.game)
|
||||
tw.game = re.sub('h/l', 'hi/lo', tw.game)
|
||||
|
@ -132,4 +204,8 @@ if __name__=="__main__":
|
|||
tables = discover(c)
|
||||
|
||||
for t in tables.keys():
|
||||
print tables[t]
|
||||
print "t = ", t
|
||||
print tables[t]
|
||||
|
||||
print "press enter to continue"
|
||||
sys.stdin.readline()
|
||||
|
|
|
@ -407,7 +407,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
|
|||
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
self.window.connect("delete_event", self.delete_event)
|
||||
self.window.connect("destroy", self.destroy)
|
||||
self.window.set_title("Free Poker DB - version: alpha2+, p78")
|
||||
self.window.set_title("Free Poker DB - version: alpha3, p80")
|
||||
self.window.set_border_width(1)
|
||||
self.window.set_size_request(1020,400)
|
||||
self.window.set_resizable(True)
|
||||
|
|
|
@ -25,6 +25,7 @@ class fpdb_db:
|
|||
self.cursor=None
|
||||
self.MYSQL_INNODB=2
|
||||
self.PGSQL=3
|
||||
self.SQLITE=4
|
||||
#end def __init__
|
||||
|
||||
def connect(self, backend, host, database, user, password):
|
||||
|
@ -39,8 +40,10 @@ class fpdb_db:
|
|||
import MySQLdb
|
||||
self.db=MySQLdb.connect(host = host, user = user, passwd = password, db = database)
|
||||
elif backend==self.PGSQL:
|
||||
import pgdb
|
||||
self.db = pgdb.connect(dsn=host+":"+database, user='postgres', password=password)
|
||||
# import pgdb
|
||||
# self.db = pgdb.connect(dsn=host+":"+database, user='postgres', password=password)
|
||||
import psycopg2
|
||||
self.db = psycopg2.connect(host = host, user = user, password = password, database = database)
|
||||
else:
|
||||
raise fpdb_simple.FpdbError("unrecognised database backend:"+backend)
|
||||
self.cursor=self.db.cursor()
|
||||
|
@ -153,6 +156,24 @@ class fpdb_db:
|
|||
|
||||
def recreate_tables(self):
|
||||
"""(Re-)creates the tables of the current DB"""
|
||||
|
||||
if self.backend == 3:
|
||||
# postgresql
|
||||
print "recreating tables in postgres db"
|
||||
schema_file = open('schema.postgres.sql', 'r')
|
||||
schema = schema_file.read()
|
||||
schema_file.close()
|
||||
curse = self.db.cursor()
|
||||
# curse.executemany(schema, [1, 2])
|
||||
for sql in schema.split(';'):
|
||||
sql = sql.rstrip()
|
||||
if sql == '':
|
||||
continue
|
||||
curse.execute(sql)
|
||||
self.db.commit()
|
||||
curse.close()
|
||||
return
|
||||
|
||||
self.drop_tables()
|
||||
|
||||
self.create_table("""Settings (
|
||||
|
|
21
pyfpdb/fpdb_import.py
Executable file → Normal file
21
pyfpdb/fpdb_import.py
Executable file → Normal file
|
@ -19,6 +19,7 @@
|
|||
|
||||
import sys
|
||||
import MySQLdb
|
||||
import psycopg2
|
||||
#import pgdb
|
||||
import math
|
||||
import os
|
||||
|
@ -37,7 +38,7 @@ def import_file(server, database, user, password, inputFile):
|
|||
self.settings={'imp-callFpdbHud':False}
|
||||
import_file_dict(self, settings)
|
||||
|
||||
def import_file_dict(options, settings, callHud=True):
|
||||
def import_file_dict(options, settings, callHud=False):
|
||||
last_read_hand=0
|
||||
if (options.inputFile=="stdin"):
|
||||
inputFile=sys.stdin
|
||||
|
@ -45,8 +46,16 @@ def import_file_dict(options, settings, callHud=True):
|
|||
inputFile=open(options.inputFile, "rU")
|
||||
|
||||
#connect to DB
|
||||
db = MySQLdb.connect(host = options.server, user = options.user,
|
||||
if options.settings['db-backend'] == 2:
|
||||
db = MySQLdb.connect(host = options.server, user = options.user,
|
||||
passwd = options.password, db = options.database)
|
||||
elif options.settings['db-backend'] == 3:
|
||||
db = psycopg2.connect(host = options.server, user = options.user,
|
||||
password = options.password, database = options.database)
|
||||
elif options.settings['db-backend'] == 4:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
cursor = db.cursor()
|
||||
|
||||
if (not options.quiet):
|
||||
|
@ -104,11 +113,13 @@ def import_file_dict(options, settings, callHud=True):
|
|||
db.commit()
|
||||
|
||||
stored+=1
|
||||
if settings['imp-callFpdbHud'] and callHud and os.sep=='/':
|
||||
db.commit()
|
||||
# if settings['imp-callFpdbHud'] and callHud and os.sep=='/':
|
||||
if settings['imp-callFpdbHud'] and callHud:
|
||||
#print "call to HUD here. handsId:",handsId
|
||||
#pipe the Hands.id out to the HUD
|
||||
options.pipe_to_hud.stdin.write("%s\n" % (handsId))
|
||||
db.commit()
|
||||
# options.pipe_to_hud.write("%s" % (handsId) + os.linesep)
|
||||
options.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
|
||||
except fpdb_simple.DuplicateError:
|
||||
duplicates+=1
|
||||
except (ValueError), fe:
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#This file contains simple functions for fpdb
|
||||
|
||||
import datetime
|
||||
import re
|
||||
|
||||
PS=1
|
||||
FTP=2
|
||||
|
@ -781,8 +782,10 @@ def parseHandStartTime(topline, site):
|
|||
#print "parsehandStartTime, tmp:", tmp
|
||||
pos = tmp.find("-")+2
|
||||
tmp = tmp[pos:]
|
||||
#print "year:", tmp[0:4], "month", tmp[5:7], "day", tmp[8:10], "hour", tmp[13:15], "minute", tmp[16:18], "second", tmp[19:21]
|
||||
result = datetime.datetime(int(tmp[0:4]), int(tmp[5:7]), int(tmp[8:10]), int(tmp[13:15]), int(tmp[16:18]), int(tmp[19:21]))
|
||||
if re.search('\(ET\)', tmp): # the old datetime format at ps
|
||||
result = datetime.datetime(int(tmp[0:4]), int(tmp[5:7]), int(tmp[8:10]), int(tmp[13:15]), int(tmp[16:18]), int(tmp[19:21]))
|
||||
else: # new format
|
||||
result = datetime.datetime(int(tmp[0:4]), int(tmp[5:7]), int(tmp[8:10]), int(tmp[11:13]), int(tmp[14:16]), int(tmp[17:19]))
|
||||
else:
|
||||
raise FpdbError("invalid site in parseHandStartTime")
|
||||
|
||||
|
@ -1951,7 +1954,7 @@ def storeHudCache(cursor, base, category, gametypeId, playerIds, hudImportData):
|
|||
row[31], row[32], row[33], row[34], row[35], row[36], row[37], row[38], row[39], row[40],
|
||||
row[41], row[42], row[43], row[44], row[45], row[46], row[47], row[48], row[49], row[50],
|
||||
row[51], row[52], row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60],
|
||||
row[1], row[2], row[3], row[4], row[5]))
|
||||
row[1], row[2], row[3], str(row[4]), row[5]))
|
||||
# else:
|
||||
# print "todo: implement storeHudCache for stud base"
|
||||
#end def storeHudCache
|
||||
|
|
217
pyfpdb/schema.postgres.sql
Normal file
217
pyfpdb/schema.postgres.sql
Normal file
|
@ -0,0 +1,217 @@
|
|||
|
||||
DROP TABLE IF EXISTS Settings CASCADE;
|
||||
CREATE TABLE Settings (version SMALLINT);
|
||||
|
||||
DROP TABLE IF EXISTS Sites CASCADE;
|
||||
CREATE TABLE Sites (
|
||||
id SERIAL UNIQUE, PRIMARY KEY (id),
|
||||
name varchar(32),
|
||||
currency char(3));
|
||||
|
||||
DROP TABLE IF EXISTS Gametypes CASCADE;
|
||||
CREATE TABLE Gametypes (
|
||||
id SERIAL UNIQUE, PRIMARY KEY (id),
|
||||
siteId INTEGER, FOREIGN KEY (siteId) REFERENCES Sites(id),
|
||||
type char(4),
|
||||
base char(4),
|
||||
category varchar(9),
|
||||
limitType char(2),
|
||||
hiLo char(1),
|
||||
smallBlind int,
|
||||
bigBlind int,
|
||||
smallBet int,
|
||||
bigBet int);
|
||||
|
||||
DROP TABLE IF EXISTS Players CASCADE;
|
||||
CREATE TABLE Players (
|
||||
id SERIAL UNIQUE, PRIMARY KEY (id),
|
||||
name VARCHAR(32),
|
||||
siteId INTEGER, FOREIGN KEY (siteId) REFERENCES Sites(id),
|
||||
comment text,
|
||||
commentTs timestamp without time zone);
|
||||
|
||||
DROP TABLE IF EXISTS Autorates CASCADE;
|
||||
CREATE TABLE Autorates (
|
||||
id BIGSERIAL UNIQUE, PRIMARY KEY (id),
|
||||
playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id),
|
||||
gametypeId INT, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
||||
description varchar(50),
|
||||
shortDesc char(8),
|
||||
ratingTime timestamp without time zone,
|
||||
handCount int);
|
||||
|
||||
DROP TABLE IF EXISTS Hands CASCADE;
|
||||
CREATE TABLE Hands (
|
||||
id BIGSERIAL UNIQUE, PRIMARY KEY (id),
|
||||
tableName VARCHAR(20),
|
||||
siteHandNo BIGINT,
|
||||
gametypeId INT, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
||||
handStart timestamp without time zone,
|
||||
importTime timestamp without time zone,
|
||||
seats SMALLINT,
|
||||
maxSeats SMALLINT,
|
||||
comment TEXT,
|
||||
commentTs timestamp without time zone);
|
||||
|
||||
DROP TABLE IF EXISTS BoardCards CASCADE;
|
||||
CREATE TABLE BoardCards (
|
||||
id BIGSERIAL UNIQUE, PRIMARY KEY (id),
|
||||
handId BIGINT, FOREIGN KEY (handId) REFERENCES Hands(id),
|
||||
card1Value smallint,
|
||||
card1Suit char(1),
|
||||
card2Value smallint,
|
||||
card2Suit char(1),
|
||||
card3Value smallint,
|
||||
card3Suit char(1),
|
||||
card4Value smallint,
|
||||
card4Suit char(1),
|
||||
card5Value smallint,
|
||||
card5Suit char(1));
|
||||
|
||||
DROP TABLE IF EXISTS TourneyTypes CASCADE;
|
||||
CREATE TABLE TourneyTypes (
|
||||
id SERIAL, PRIMARY KEY (id),
|
||||
siteId INT, FOREIGN KEY (siteId) REFERENCES Sites(id),
|
||||
buyin INT,
|
||||
fee INT,
|
||||
knockout INT,
|
||||
rebuyOrAddon BOOLEAN);
|
||||
|
||||
DROP TABLE IF EXISTS Tourneys CASCADE;
|
||||
CREATE TABLE Tourneys (
|
||||
id SERIAL UNIQUE, PRIMARY KEY (id),
|
||||
tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
|
||||
siteTourneyNo BIGINT,
|
||||
entries INT,
|
||||
prizepool INT,
|
||||
startTime timestamp without time zone,
|
||||
comment TEXT,
|
||||
commentTs timestamp without time zone);
|
||||
|
||||
DROP TABLE IF EXISTS TourneysPlayers CASCADE;
|
||||
CREATE TABLE TourneysPlayers (
|
||||
id BIGSERIAL UNIQUE, PRIMARY KEY (id),
|
||||
tourneyId INT, FOREIGN KEY (tourneyId) REFERENCES Tourneys(id),
|
||||
playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id),
|
||||
payinAmount INT,
|
||||
rank INT,
|
||||
winnings INT,
|
||||
comment TEXT,
|
||||
commentTs timestamp without time zone);
|
||||
|
||||
DROP TABLE IF EXISTS HandsPlayers CASCADE;
|
||||
CREATE TABLE HandsPlayers (
|
||||
id BIGSERIAL UNIQUE, PRIMARY KEY (id),
|
||||
handId BIGINT, FOREIGN KEY (handId) REFERENCES Hands(id),
|
||||
playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id),
|
||||
startCash INT,
|
||||
position CHAR(1),
|
||||
seatNo SMALLINT,
|
||||
ante INT,
|
||||
|
||||
card1Value smallint,
|
||||
card1Suit char(1),
|
||||
card2Value smallint,
|
||||
card2Suit char(1),
|
||||
card3Value smallint,
|
||||
card3Suit char(1),
|
||||
card4Value smallint,
|
||||
card4Suit char(1),
|
||||
card5Value smallint,
|
||||
card5Suit char(1),
|
||||
card6Value smallint,
|
||||
card6Suit char(1),
|
||||
card7Value smallint,
|
||||
card7Suit char(1),
|
||||
|
||||
winnings int,
|
||||
rake int,
|
||||
comment text,
|
||||
commentTs timestamp without time zone,
|
||||
tourneysPlayersId BIGINT, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id));
|
||||
|
||||
DROP TABLE IF EXISTS HandsActions CASCADE;
|
||||
CREATE TABLE HandsActions (
|
||||
id BIGSERIAL UNIQUE, PRIMARY KEY (id),
|
||||
handPlayerId BIGINT, FOREIGN KEY (handPlayerId) REFERENCES HandsPlayers(id),
|
||||
street SMALLINT,
|
||||
actionNo SMALLINT,
|
||||
action CHAR(5),
|
||||
amount INT,
|
||||
comment TEXT,
|
||||
commentTs timestamp without time zone);
|
||||
|
||||
DROP TABLE IF EXISTS HudCache CASCADE;
|
||||
CREATE TABLE HudCache (
|
||||
id BIGSERIAL UNIQUE, PRIMARY KEY (id),
|
||||
gametypeId INT, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
||||
playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id),
|
||||
activeSeats SMALLINT,
|
||||
position CHAR(1),
|
||||
tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
|
||||
|
||||
HDs INT,
|
||||
street0VPI INT,
|
||||
street0Aggr INT,
|
||||
street0_3B4BChance INT,
|
||||
street0_3B4BDone INT,
|
||||
street1Seen INT,
|
||||
street2Seen INT,
|
||||
street3Seen INT,
|
||||
street4Seen INT,
|
||||
sawShowdown INT,
|
||||
street1Aggr INT,
|
||||
street2Aggr INT,
|
||||
street3Aggr INT,
|
||||
street4Aggr INT,
|
||||
otherRaisedStreet1 INT,
|
||||
otherRaisedStreet2 INT,
|
||||
otherRaisedStreet3 INT,
|
||||
otherRaisedStreet4 INT,
|
||||
foldToOtherRaisedStreet1 INT,
|
||||
foldToOtherRaisedStreet2 INT,
|
||||
foldToOtherRaisedStreet3 INT,
|
||||
foldToOtherRaisedStreet4 INT,
|
||||
wonWhenSeenStreet1 FLOAT,
|
||||
wonAtSD FLOAT,
|
||||
|
||||
stealAttemptChance INT,
|
||||
stealAttempted INT,
|
||||
foldBbToStealChance INT,
|
||||
foldedBbToSteal INT,
|
||||
foldSbToStealChance INT,
|
||||
foldedSbToSteal INT,
|
||||
|
||||
street1CBChance INT,
|
||||
street1CBDone INT,
|
||||
street2CBChance INT,
|
||||
street2CBDone INT,
|
||||
street3CBChance INT,
|
||||
street3CBDone INT,
|
||||
street4CBChance INT,
|
||||
street4CBDone INT,
|
||||
|
||||
foldToStreet1CBChance INT,
|
||||
foldToStreet1CBDone INT,
|
||||
foldToStreet2CBChance INT,
|
||||
foldToStreet2CBDone INT,
|
||||
foldToStreet3CBChance INT,
|
||||
foldToStreet3CBDone INT,
|
||||
foldToStreet4CBChance INT,
|
||||
foldToStreet4CBDone INT,
|
||||
|
||||
totalProfit INT,
|
||||
|
||||
street1CheckCallRaiseChance INT,
|
||||
street1CheckCallRaiseDone INT,
|
||||
street2CheckCallRaiseChance INT,
|
||||
street2CheckCallRaiseDone INT,
|
||||
street3CheckCallRaiseChance INT,
|
||||
street3CheckCallRaiseDone INT,
|
||||
street4CheckCallRaiseChance INT,
|
||||
street4CheckCallRaiseDone INT);
|
||||
|
||||
INSERT INTO Settings VALUES (76);
|
||||
INSERT INTO Sites ("name", currency) VALUES ('Full Tilt Poker', 'USD');
|
||||
INSERT INTO Sites ("name", currency) VALUES ('PokerStars', 'USD');
|
||||
INSERT INTO TourneyTypes (buyin, fee, knockout, rebuyOrAddon) VALUES (0, 0, 0, FALSE);
|
Loading…
Reference in New Issue
Block a user