p58 - added HUD from ray

fpdb_parse now returns hand id rather than site hand no
This commit is contained in:
steffen123 2008-08-18 23:53:25 +01:00
parent 999eac4019
commit c716dfd35e
15 changed files with 1798 additions and 10 deletions

View File

@ -4,6 +4,7 @@ Everything is subject to change and especially the order will often change. Patc
alpha2 (release by 17Aug) alpha2 (release by 17Aug)
====== ======
make windows use correct language version of Appdata, e.g. Anwendungdaten make windows use correct language version of Appdata, e.g. Anwendungdaten
stop bulk importer from executing HUD hook
seperate and improve instructions for update seperate and improve instructions for update
update status or make a support matrix table for website update status or make a support matrix table for website
add instructions for mailing list to contacts add instructions for mailing list to contacts

BIN
pyfpdb/Cards01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

211
pyfpdb/Configuration.py Normal file
View File

@ -0,0 +1,211 @@
#!/usr/bin/env python
"""Configuration.py
Handles HUD configuration files.
"""
# Copyright 2008, Ray E. Barker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
# Standard Library modules
import xml.dom.minidom
from xml.dom.minidom import Node
class Layout:
def __init__(self, max):
self.max = int(max)
self.location = []
for i in range(self.max + 1): self.location.append(None)
def __str__(self):
temp = " Layout = %d max, width= %d, height = %d, fav_seat = %d\n" % (self.max, self.width, self.height, self.fav_seat)
temp = temp + " Locations = "
for i in range(1, len(self.location)):
temp = temp + "(%d,%d)" % self.location[i]
return temp
class Site:
def __init__(self, node):
self.site_name = node.getAttribute("site_name")
self.table_finder = node.getAttribute("table_finder")
self.screen_name = node.getAttribute("screen_name")
self.site_path = node.getAttribute("site_path")
self.HH_path = node.getAttribute("HH_path")
self.decoder = node.getAttribute("decoder")
self.layout = {}
for layout_node in node.getElementsByTagName('layout'):
max = int( layout_node.getAttribute('max') )
lo = Layout(max)
lo.fav_seat = int( layout_node.getAttribute('fav_seat') )
lo.width = int( layout_node.getAttribute('width') )
lo.height = int( layout_node.getAttribute('height') )
for location_node in layout_node.getElementsByTagName('location'):
lo.location[int( location_node.getAttribute('seat') )] = (int( location_node.getAttribute('x') ), int( location_node.getAttribute('y')))
self.layout[lo.max] = lo
def __str__(self):
temp = "Site = " + self.site_name + "\n"
for key in dir(self):
if key.startswith('__'): continue
if key == 'layout': continue
value = getattr(self, key)
if callable(value): continue
temp = temp + ' ' + key + " = " + value + "\n"
for layout in self.layout:
temp = temp + "%s" % self.layout[layout]
return temp
class Stat:
def __init__(self):
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)
return temp
class Game:
def __init__(self, node):
self.game_name = node.getAttribute("game_name")
self.db = node.getAttribute("db")
self.rows = int( node.getAttribute("rows") )
self.cols = int( node.getAttribute("cols") )
self.stats = {}
for stat_node in node.getElementsByTagName('stat'):
stat = Stat()
stat.stat_name = stat_node.getAttribute("stat_name")
stat.row = int( stat_node.getAttribute("row") )
stat.col = int( stat_node.getAttribute("col") )
stat.tip = stat_node.getAttribute("tip")
stat.click = stat_node.getAttribute("click")
self.stats[stat.stat_name] = stat
def __str__(self):
temp = "Game = " + self.game_name + "\n"
temp = temp + " db = %s\n" % self.db
temp = temp + " rows = %d\n" % self.rows
temp = temp + " cols = %d\n" % self.cols
for stat in self.stats.keys():
temp = temp + "%s" % self.stats[stat]
return temp
class Database:
def __init__(self, node):
self.db_name = node.getAttribute("db_name")
self.db_server = node.getAttribute("db_server")
self.db_ip = node.getAttribute("db_ip")
self.db_user = node.getAttribute("db_user")
self.db_type = node.getAttribute("db_type")
self.db_pass = node.getAttribute("db_pass")
def __str__(self):
temp = 'Database = ' + self.db_name + '\n'
for key in dir(self):
if key.startswith('__'): continue
value = getattr(self, key)
if callable(value): continue
temp = temp + ' ' + key + " = " + value + "\n"
return temp
class Mucked:
def __init__(self, node):
self.name = node.getAttribute("mw_name")
self.cards = node.getAttribute("deck")
self.card_wd = node.getAttribute("card_wd")
self.card_ht = node.getAttribute("card_ht")
self.rows = node.getAttribute("rows")
self.cols = node.getAttribute("cols")
self.format = node.getAttribute("stud")
print "mw name = " + self.name
def __str__(self):
temp = 'Mucked = ' + self.name + "\n"
for key in dir(self):
if key.startswith('__'): continue
value = getattr(self, key)
if callable(value): continue
temp = temp + ' ' + key + " = " + value + "\n"
return temp
class Config:
def __init__(self, file = 'HUD_config.xml'):
doc = xml.dom.minidom.parse(file)
self.supported_sites = {}
self.supported_games = {}
self.supported_databases = {}
self.mucked_windows = {}
# s_sites = doc.getElementsByTagName("supported_sites")
for site_node in doc.getElementsByTagName("site"):
site = Site(node = site_node)
self.supported_sites[site.site_name] = site
s_games = doc.getElementsByTagName("supported_games")
for game_node in doc.getElementsByTagName("game"):
game = Game(node = game_node)
self.supported_games[game.game_name] = game
s_dbs = doc.getElementsByTagName("supported_databases")
for db_node in doc.getElementsByTagName("database"):
db = Database(node = db_node)
self.supported_databases[db.db_name] = db
s_dbs = doc.getElementsByTagName("mucked_windows")
for mw_node in doc.getElementsByTagName("mw"):
mw = Mucked(node = mw_node)
self.mucked_windows[mw.name] = mw
if __name__== "__main__":
c = Config()
print "\n----------- SUPPORTED SITES -----------"
for s in c.supported_sites.keys():
print c.supported_sites[s]
print "----------- END SUPPORTED SITES -----------"
print "\n----------- SUPPORTED GAMES -----------"
for game in c.supported_games.keys():
print c.supported_games[game]
print "----------- END SUPPORTED GAMES -----------"
print "\n----------- SUPPORTED DATABASES -----------"
for db in c.supported_databases.keys():
print c.supported_databases[db]
print "----------- END SUPPORTED DATABASES -----------"
print "\n----------- MUCKED WINDOW FORMATS -----------"
for w in c.mucked_windows.keys():
print c.mucked_windows[w]
print "----------- END MUCKED WINDOW FORMATS -----------"

156
pyfpdb/Database.py Normal file
View File

@ -0,0 +1,156 @@
#!/usr/bin/env python
"""Database.py
Create and manage the database objects.
"""
# Copyright 2008, Ray E. Barker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
# postmaster -D /var/lib/pgsql/data
# Standard Library modules
# pyGTK modules
# FreePokerTools modules
import Configuration
import SQL
# pgdb database module for posgres via DB-API
#import pgdb
# pgdb uses pyformat. is that fixed or an option?
# mysql bindings
import MySQLdb
class Database:
def __init__(self, c, db_name, game):
print "db_name = " + db_name
if c.supported_databases[db_name].db_server == 'postgresql':
self.connection = pgdb.connect(dsn = 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)
elif c.supported_databases[db_name].db_server == 'mysql':
self.connection = MySQLdb.connect(host = c.supported_databases[db_name].db_ip,
user = c.supported_databases[db_name].db_user,
passwd = c.supported_databases[db_name].db_pass,
db = c.supported_databases[db_name].db_name)
else:
print "Database not recognized."
return(0)
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 get_table_name(self, hand_id):
c = self.connection.cursor()
c.execute(self.sql.query['get_table_name'], (hand_id))
row = c.fetchone()
return row
def get_last_hand(self):
c = self.connection.cursor()
c.execute(self.sql.query['get_last_hand'])
row = c.fetchone()
return row[0]
def get_xml(self, hand_id):
c = self.connection.cursor()
c.execute(self.sql.query['get_xml'], (hand_id))
row = c.fetchone()
return row[0]
def get_recent_hands(self, last_hand):
c = self.connection.cursor()
c.execute(self.sql.query['get_recent_hands'], {'last_hand': last_hand})
return c.fetchall()
def get_hand_info(self, new_hand_id):
c = self.connection.cursor()
c.execute(self.sql.query['get_hand_info'], new_hand_id)
return c.fetchall()
def get_cards(self, hand):
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_stats_from_hand(self, hand, hero):
c = self.connection.cursor()
# get the players in the hand and their seats
c.execute(self.sql.query['get_players_from_hand'], (hand))
names = {}
seats = {}
for row in c.fetchall():
names[row[0]] = row[2]
seats[row[0]] = row[1]
# now get the stats
c.execute(self.sql.query['get_stats_from_hand'], (hand, hand))
colnames = [desc[0] for desc in c.description]
stat_dict = {}
for row in c.fetchall():
t_dict = {}
for name, val in zip(colnames, row):
t_dict[name] = val
# print t_dict
t_dict['screen_name'] = names[t_dict['player_id']]
t_dict['seat'] = seats[t_dict['player_id']]
stat_dict[t_dict['player_id']] = t_dict
return stat_dict
def get_player_id(self, config, site, player_name):
print "site = %s, player name = %s" % (site, player_name)
c = self.connection.cursor()
c.execute(self.sql.query['get_player_id'], {'player': player_name, 'site': site})
row = c.fetchone()
return row[0]
if __name__=="__main__":
c = Configuration.Config()
db_connection = Database(c, 'fpdb', 'holdem') # 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
h = db_connection.get_last_hand()
print "last hand = ", h
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, hero)
for p in stat_dict.keys():
print p, " ", stat_dict[p]
db_connection.close

View File

@ -55,7 +55,7 @@ class GuiAutoImport (threading.Thread):
else: else:
self.inputFile=self.path+os.sep+file self.inputFile=self.path+os.sep+file
fpdb_import.import_file_dict(self, self.settings) fpdb_import.import_file_dict(self, self.settings)
print "GuiBulkImport.import_dir done" print "GuiAutoImport.import_dir done"
interval=int(self.intervalTBuffer.get_text(self.intervalTBuffer.get_start_iter(), self.intervalTBuffer.get_end_iter())) interval=int(self.intervalTBuffer.get_text(self.intervalTBuffer.get_start_iter(), self.intervalTBuffer.get_end_iter()))
time.sleep(interval) time.sleep(interval)

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<FreePokerToolsConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FreePokerToolsConfig.xsd">
<supported_sites>
<site site_name="PokerStars" table_finder="PokerStars" screen_name="abc" site_path="~/.wine/drive_c/Program Files/PokerStars/" HH_path="~/.wine/drive_c/Program Files/PokerStars/HandHistory/" decoder="pokerstars_decode_table">
<layout max="8" width="792" height="546" fav_seat="0">
<location seat="1" x="684" y="61"> </location>
<location seat="2" x="689" y="239"> </location>
<location seat="3" x="692" y="346"> </location>
<location seat="4" x="525" y="402"> </location>
<location seat="5" x="259" y="402"> </location>
<location seat="6" x="0" y="348"> </location>
<location seat="7" x="0" y="240"> </location>
<location seat="8" x="0" y="35"> </location>
</layout>
<layout max="6" width="792" height="546" fav_seat="0">
<location seat="1" x="681" y="119"> </location>
<location seat="2" x="681" y="301"> </location>
<location seat="3" x="487" y="369"> </location>
<location seat="4" x="226" y="369"> </location>
<location seat="5" x="0" y="301"> </location>
<location seat="6" x="0" y="119"> </location>
</layout>
<layout max="10" width="792" height="546" fav_seat="0">
<location seat="1" x="684" y="61"> </location>
<location seat="2" x="689" y="239"> </location>
<location seat="3" x="692" y="346"> </location>
<location seat="4" x="586" y="393"> </location>
<location seat="5" x="421" y="440"> </location>
<location seat="6" x="267" y="440"> </location>
<location seat="7" x="0" y="361"> </location>
<location seat="8" x="0" y="280"> </location>
<location seat="9" x="121" y="280"> </location>
<location seat="10" x="46" y="30"> </location>
</layout>
<layout max="9" width="792" height="546" fav_seat="0">
<location seat="1" x="560" y="0"> </location>
<location seat="2" x="679" y="123"> </location>
<location seat="3" x="688" y="309"> </location>
<location seat="4" x="483" y="370"> </location>
<location seat="5" x="444" y="413"> </location>
<location seat="6" x="224" y="372"> </location>
<location seat="7" x="0" y="307"> </location>
<location seat="8" x="0" y="121"> </location>
<location seat="9" x="140" y="0"> </location>
</layout>
</site>
<site site_name="FullTilt" table_finder="FullTilt" screen_name="abc">
</site>
<site site_name="PokerStars.py" table_finder="PokerStars.py" screen_name="abc" site_path="~/.wine/drive_c/Program Files/PokerStars/" HH_path="~/.wine/drive_c/Program Files/PokerStars/HandHistory/" decoder="pokerstars_decode_table">
<layout max="6" width="792" height="546" fav_seat="0">
<location seat="1" x="681" y="119"> </location>
<location seat="2" x="681" y="301"> </location>
<location seat="3" x="487" y="369"> </location>
<location seat="4" x="226" y="369"> </location>
<location seat="5" x="0" y="301"> </location>
<location seat="6" x="0" y="119"> </location>
</layout>
<layout max="10" width="792" height="546" fav_seat="0">
<location seat="1" x="684" y="61"> </location>
<location seat="2" x="689" y="239"> </location>
<location seat="3" x="692" y="346"> </location>
<location seat="4" x="586" y="393"> </location>
<location seat="5" x="421" y="440"> </location>
<location seat="6" x="267" y="440"> </location>
<location seat="7" x="0" y="361"> </location>
<location seat="8" x="0" y="280"> </location>
<location seat="9" x="121" y="280"> </location>
<location seat="10" x="46" y="30"> </location>
</layout>
<layout max="8" width="792" height="546" fav_seat="0">
<location seat="1" x="559" y="62"> </location>
<location seat="2" x="678" y="117"> </location>
<location seat="3" x="678" y="282"> </location>
<location seat="4" x="525" y="402"> </location>
<location seat="5" x="259" y="402"> </location>
<location seat="6" x="0" y="348"> </location>
<location seat="7" x="0" y="240"> </location>
<location seat="8" x="0" y="35"> </location>
</layout>
<layout max="9" width="792" height="546" fav_seat="0">
<location seat="1" x="560" y="0"> </location>
<location seat="2" x="679" y="123"> </location>
<location seat="3" x="688" y="309"> </location>
<location seat="4" x="483" y="370"> </location>
<location seat="5" x="444" y="413"> </location>
<location seat="6" x="224" y="372"> </location>
<location seat="7" x="0" y="307"> </location>
<location seat="8" x="0" y="121"> </location>
<location seat="9" x="140" y="0"> </location>
</layout>
</site>
</supported_sites>
<supported_games>
<game game_name="holdem" db="fpdb" rows="2" cols="3">
<stat row="0" col="0" stat_name="vpip" tip="tip1" click="tog_decorate"> </stat>
<stat row="0" col="1" stat_name="pfr" tip="tip1" click="tog_decorate"> </stat>
<stat row="0" col="2" stat_name="saw_f" tip="tip1" click="tog_decorate"> </stat>
<stat row="1" col="0" stat_name="fold_f" tip="tip1" click="tog_decorate"> </stat>
<stat row="1" col="1" stat_name="n" tip="tip1" click="tog_decorate"> </stat>
<stat row="1" col="2" stat_name="wtsd" tip="tip1" click="tog_decorate"> </stat>
</game>
<game game_name="razz" db="ptracks" rows="2" cols="3">
<stat row="0" col="0" stat_name="vpip" tip="tip1" click="tog_decorate"> </stat>
<stat row="0" col="1" stat_name="pfr" tip="tip1" click="tog_decorate"> </stat>
<stat row="0" col="2" stat_name="saw_f" tip="tip1" click="tog_decorate"> </stat>
<stat row="1" col="0" stat_name="fold_f" tip="tip1" click="tog_decorate"> </stat>
<stat row="1" col="1" stat_name="n" tip="tip1" click="tog_decorate"> </stat>
<stat row="1" col="2" stat_name="wtsd" tip="tip1" click="tog_decorate"> </stat>
</game>
</supported_games>
<supported_databases>
<database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="yourPassword" db_type="fpdb"> </database>
</supported_databases>
<mucked_windows>
<mw mw_name="stud1" format="stud" rows="8" cols="11" deck="Cards01.png" card_wd="30" card_ht="42"> </mw>
</mucked_windows>
</FreePokerToolsConfig>

94
pyfpdb/HUD_main.py Executable file
View File

@ -0,0 +1,94 @@
#!/usr/bin/env python
"""Hud_main.py
Main for FreePokerTools HUD.
"""
# Copyright 2008, Ray E. Barker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
# to do kill window on my seat
# 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
# Standard Library modules
import sys
import os
# pyGTK modules
import pygtk
import gtk
import gobject
# FreePokerTools modules
import Configuration
import Database
import Tables
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):
# 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')
(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):
hud_dict[table_name].update(new_hand_id, db_connection, config)
# otherwise create a new hud
else:
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].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)
if __name__== "__main__":
main_window = gtk.Window()
main_window.connect("destroy", destroy)
label = gtk.Label('Fake main window, blah blah, blah\nblah, blah')
main_window.add(label)
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()

194
pyfpdb/HandHistory.py Normal file
View File

@ -0,0 +1,194 @@
#!/usr/bin/env python
"""HandHistory.py
Parses HandHistory xml files and returns requested objects.
"""
# Copyright 2008, Ray E. Barker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
# Standard Library modules
import xml.dom.minidom
from xml.dom.minidom import Node
class HandHistory:
def __init__(self, xml_string, elements = ('ALL')):
doc = xml.dom.minidom.parseString(xml_string)
if elements == ('ALL'):
elements = ('BETTING', 'AWARDS', 'POSTS', 'PLAYERS', 'GAME')
if 'BETTING' in elements:
self.BETTING = Betting(doc.getElementsByTagName('BETTING')[0])
if 'AWARDS' in elements:
self.AWARDS = Awards (doc.getElementsByTagName('AWARDS')[0])
if 'POSTS' in elements:
self.POSTS = Posts (doc.getElementsByTagName('POSTS')[0])
if 'GAME' in elements:
self.GAME = Game (doc.getElementsByTagName('GAME')[0])
if 'PLAYERS' in elements:
self.PLAYERS = {}
p_n = doc.getElementsByTagName('PLAYERS')[0]
for p in p_n.getElementsByTagName('PLAYER'):
a_player = Player(p)
self.PLAYERS[a_player.name] = a_player
class Player:
def __init__(self, node):
self.name = node.getAttribute('NAME')
self.seat = node.getAttribute('SEAT')
self.stack = node.getAttribute('STACK')
self.showed_hand = node.getAttribute('SHOWED_HAND')
self.cards = node.getAttribute('CARDS')
self.allin = node.getAttribute('ALLIN')
self.sitting_out = node.getAttribute('SITTING_OUT')
self.hand = node.getAttribute('HAND')
self.start_cards = node.getAttribute('START_CARDS')
if self.allin == '' or \
self.allin == '0' or \
self.allin.upper() == 'FALSE': self.allin = False
else: self.allin = True
if self.sitting_out == '' or \
self.sitting_out == '0' or \
self.sitting_out.upper() == 'FALSE': self.sitting_out = False
else: self.sitting_out = True
def __str__(self):
temp = "%s\n seat = %s\n stack = %s\n cards = %s\n" % \
(self.name, self.seat, self.stack, self.cards)
temp = temp + " showed_hand = %s\n allin = %s\n" % \
(self.showed_hand, self.allin)
temp = temp + " hand = %s\n start_cards = %s\n" % \
(self.hand, self.start_cards)
return temp
class Awards:
def __init__(self, node):
self.awards = [] # just an array of award objects
for a in node.getElementsByTagName('AWARD'):
self.awards.append(Award(a))
def __str__(self):
temp = ""
for a in self.awards:
temp = temp + "%s\n" % (a)
return temp
class Award:
def __init__(self, node):
self.player = node.getAttribute('PLAYER')
self.amount = node.getAttribute('AMOUNT')
self.pot = node.getAttribute('POT')
def __str__(self):
return self.player + " won " + self.amount + " from " + self.pot
class Game:
def __init__(self, node):
print node
self.tags = {}
for tag in ( ('GAME_NAME', 'game_name'), ('MAX', 'max'), ('HIGHLOW', 'high_low'),
('STRUCTURE', 'structure'), ('MIXED', 'mixed') ):
L = node.getElementsByTagName(tag[0])
if (not L): continue
print L
for node2 in L:
title = ""
for node3 in node2.childNodes:
if (node3.nodeType == Node.TEXT_NODE):
title +=node3.data
self.tags[tag[1]] = title
def __str__(self):
return "%s %s %s, (%s max), %s" % (self.tags['structure'],
self.tags['game_name'],
self.tags['game_name'],
self.tags['max'],
self.tags['game_name'])
class Posts:
def __init__(self, node):
self.posts = [] # just an array of post objects
for p in node.getElementsByTagName('POST'):
self.posts.append(Post(p))
def __str__(self):
temp = ""
for p in self.posts:
temp = temp + "%s\n" % (p)
return temp
class Post:
def __init__(self, node):
self.player = node.getAttribute('PLAYER')
self.amount = node.getAttribute('AMOUNT')
self.posted = node.getAttribute('POSTED')
self.live = node.getAttribute('LIVE')
def __str__(self):
return ("%s posted %s %s %s") % (self.player, self.amount, self.posted, self.live)
class Betting:
def __init__(self, node):
self.rounds = [] # a Betting object is just an array of rounds
for r in node.getElementsByTagName('ROUND'):
self.rounds.append(Round(r))
def __str__(self):
temp = ""
for r in self.rounds:
temp = temp + "%s\n" % (r)
return temp
class Round:
def __init__(self, node):
self.name = node.getAttribute('ROUND_NAME')
self.action = []
for a in node.getElementsByTagName('ACTION'):
self.action.append(Action(a))
def __str__(self):
temp = self.name + "\n"
for a in self.action:
temp = temp + " %s\n" % (a)
return temp
class Action:
def __init__(self, node):
self.player = node.getAttribute('PLAYER')
self.action = node.getAttribute('ACT')
self.amount = node.getAttribute('AMOUNT')
self.allin = node.getAttribute('ALLIN')
def __str__(self):
return self.player + " " + self.action + " " + self.amount + " " + self.allin
if __name__== "__main__":
file = open('test.xml', 'r')
xml_string = file.read()
file.close()
print xml_string + "\n\n\n"
h = HandHistory(xml_string, ('ALL'))
print h.GAME
print h.POSTS
print h.BETTING
print h.AWARDS
for p in h.PLAYERS.keys():
print h.PLAYERS[p]

189
pyfpdb/Hud.py Normal file
View File

@ -0,0 +1,189 @@
#!/usr/bin/env python
"""Hud.py
Create and manage the hud overlays.
"""
# Copyright 2008, Ray E. Barker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
# Standard Library modules
# pyGTK modules
import pygtk
import gtk
import pango
import gobject
# FreePokerTools modules
import Tables # needed for testing only
import Configuration
import Stats
import Mucked
import Database
class Hud:
def __init__(self, table, max, poker_game, config, db_connection):
self.table = table
self.config = config
self.poker_game = poker_game
self.max = max
self.db_connection = db_connection
self.stat_windows = {}
self.font = pango.FontDescription("Sans 8")
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
#
# this method also manages the creating and destruction of stat
# windows via calls to the Stat_Window class
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],
table = self.table,
x = x,
y = y,
seat = i,
player_id = 'fake',
font = self.font)
self.stats = [['', '', ''], ['', '', '']]
for stat in config.supported_games[self.poker_game].stats.keys():
self.stats[config.supported_games[self.poker_game].stats[stat].row] \
[config.supported_games[self.poker_game].stats[stat].col] = \
config.supported_games[self.poker_game].stats[stat].stat_name
# self.mucked_window = gtk.Window()
# self.m = Mucked.Mucked(self.mucked_window, self.db_connection)
# self.mucked_window.show_all()
def update(self, hand, db, config):
stat_dict = db.get_stats_from_hand(hand, 3)
for s in stat_dict.keys():
for r in range(0, 2):
for c in range(0, 3):
number = Stats.do_stat(stat_dict, player = stat_dict[s]['player_id'], stat = self.stats[r][c])
self.stat_windows[stat_dict[s]['seat']].label[r][c].set_text(number[1])
tip = stat_dict[s]['screen_name'] + "\n" + number[5] + "\n" + \
number[3] + ", " + number[4]
Stats.do_tip(self.stat_windows[stat_dict[s]['seat']].e_box[r][c], tip)
# self.m.update(hand)
class Stat_Window:
def button_press_cb(self, widget, event, *args):
# This handles all callbacks from button presses on the event boxes in
# the stat windows. There is a bit of an ugly kludge to separate single-
# and double-clicks.
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)
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
print "middle button clicked"
if event.button == 3: # right button event
print "right button clicked"
def single_click(self):
# 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"
self.sb_click = 0
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 __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
self.window = gtk.Window()
self.window.set_decorated(0)
self.window.set_gravity(gtk.gdk.GRAVITY_STATIC)
self.window.set_title("%s" % seat)
self.grid = gtk.Table(rows = self.game.rows, columns = self.game.cols, homogeneous = False)
self.window.add(self.grid)
self.e_box = []
self.frame = []
self.label = []
for r in range(self.game.rows):
self.e_box.append([])
self.label.append([])
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.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)
# font = pango.FontDescription("Sans 8")
self.label[r][c].modify_font(font)
self.window.realize
self.window.move(self.x, self.y)
self.window.set_keep_above(1)
self.window.show_all()
def destroy(*args): # call back for terminating the main eventloop
gtk.main_quit()
if __name__== "__main__":
main_window = gtk.Window()
main_window.connect("destroy", destroy)
label = gtk.Label('Fake main window, blah blah, blah\nblah, blah')
main_window.add(label)
main_window.show_all()
c = Configuration.Config()
tables = Tables.discover(c)
db = Database.Database(c, 'PTrackSv2', 'razz')
for t in tables:
win = Hud(t, 8, c, db)
# t.get_details()
win.update(8300, db, c)
gtk.main()

241
pyfpdb/Mucked.py Normal file
View File

@ -0,0 +1,241 @@
#!/usr/bin/env python
"""Mucked.py
Mucked cards display for FreePokerTools HUD.
"""
# Copyright 2008, Ray E. Barker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
# to do
# problem with hand 30586
# Standard Library modules
import sys
import os
import string
import xml.dom.minidom
from xml.dom.minidom import Node
# pyGTK modules
import pygtk
import gtk
import gobject
# FreePokerTools modules
import Configuration
import Database
import Tables
import Hud
import Mucked
import HandHistory
class Mucked:
def __init__(self, parent, db_connection):
self.parent = parent #this is the parent of the mucked cards widget
self.db_connection = db_connection
self.vbox = gtk.VBox()
self.parent.add(self.vbox)
self.mucked_list = MuckedList (self.vbox, db_connection)
self.mucked_cards = MuckedCards(self.vbox, db_connection)
self.mucked_list.mucked_cards = self.mucked_cards
def update(self, new_hand_id):
self.mucked_list.update(new_hand_id)
class MuckedList:
def __init__(self, parent, db_connection):
self.parent = parent
self.db_connection = db_connection
# set up a scrolled window to hold the listbox
self.scrolled_window = gtk.ScrolledWindow()
self.scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
self.parent.add(self.scrolled_window)
# create a ListStore to use as the model
self.liststore = gtk.ListStore(str, str, str)
self.treeview = gtk.TreeView(self.liststore)
self.tvcolumn0 = gtk.TreeViewColumn('HandID')
self.tvcolumn1 = gtk.TreeViewColumn('Cards')
self.tvcolumn2 = gtk.TreeViewColumn('Net')
# add tvcolumn to treeview
self.treeview.append_column(self.tvcolumn0)
self.treeview.append_column(self.tvcolumn1)
self.treeview.append_column(self.tvcolumn2)
# create a CellRendererText to render the data
self.cell = gtk.CellRendererText()
# add the cell to the tvcolumn and allow it to expand
self.tvcolumn0.pack_start(self.cell, True)
self.tvcolumn1.pack_start(self.cell, True)
self.tvcolumn2.pack_start(self.cell, True)
self.tvcolumn0.add_attribute(self.cell, 'text', 0)
self.tvcolumn1.add_attribute(self.cell, 'text', 1)
self.tvcolumn2.add_attribute(self.cell, 'text', 2)
# resize the cols if nec
self.tvcolumn0.set_resizable(True)
self.treeview.connect("row-activated", self.activated_event)
self.scrolled_window.add_with_viewport(self.treeview)
def activated_event(self, path, column, data=None):
sel = self.treeview.get_selection()
(model, iter) = sel.get_selected()
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)
iter = self.liststore.append(info_row[0])
sel = self.treeview.get_selection()
sel.select_iter(iter)
vadj = self.scrolled_window.get_vadjustment()
vadj.set_value(vadj.upper)
self.mucked_cards.update(new_hand_id)
class MuckedCards:
def __init__(self, parent, db_connection):
self.parent = parent #this is the parent of the mucked cards widget
self.db_connection = db_connection
self.card_images = self.get_card_images()
self.seen_cards = {}
self.grid_contents = {}
self.eb = {}
self.rows = 8
self.cols = 7
self.grid = gtk.Table(self.rows, self.cols + 4, homogeneous = False)
for r in range(0, self.rows):
for c in range(0, self.cols):
self.seen_cards[(c, r)] = gtk.image_new_from_pixbuf(self.card_images[('B', 'S')])
self.eb[(c, r)]= gtk.EventBox()
# set up the contents for the cells
for r in range(0, self.rows):
self.grid_contents[( 0, r)] = gtk.Label("%d" % (r + 1))
self.grid_contents[( 1, r)] = gtk.Label("player %d" % (r + 1))
self.grid_contents[( 4, r)] = gtk.Label("-")
self.grid_contents[( 9, r)] = gtk.Label("-")
self.grid_contents[( 2, r)] = self.eb[( 0, r)]
self.grid_contents[( 3, r)] = self.eb[( 1, r)]
self.grid_contents[( 5, r)] = self.eb[( 2, r)]
self.grid_contents[( 6, r)] = self.eb[( 3, r)]
self.grid_contents[( 7, r)] = self.eb[( 4, r)]
self.grid_contents[( 8, r)] = self.eb[( 5, r)]
self.grid_contents[(10, r)] = self.eb[( 6, r)]
for c in range(0, self.cols):
self.eb[(c, r)].add(self.seen_cards[(c, r)])
# add the cell contents to the table
for c in range(0, self.cols + 4):
for r in range(0, self.rows):
self.grid.attach(self.grid_contents[(c, r)], c, c+1, r, r+1, xpadding = 1, ypadding = 1)
self.parent.add(self.grid)
def update(self, new_hand_id):
cards = self.db_connection.get_cards(new_hand_id)
self.clear()
for c in cards.keys():
self.grid_contents[(1, cards[c]['seat_number'] - 1)].set_text(cards[c]['screen_name'])
for i in ((0, 'hole_card_1'), (1, 'hole_card_2'), (2, 'hole_card_3'), (3, 'hole_card_4'),
(4, 'hole_card_5'), (5, 'hole_card_6'), (6, 'hole_card_7')):
if not cards[c][i[1]] == "":
self.seen_cards[(i[0], cards[c]['seat_number'] - 1)]. \
set_from_pixbuf(self.card_images[self.split_cards(cards[c][i[1]])])
xml_text = self.db_connection.get_xml(new_hand_id)
hh = HandHistory.HandHistory(xml_text, ('BETTING'))
# action in tool tips for 3rd street cards
tip = "%s" % hh.BETTING.rounds[0]
for c in (0, 1, 2):
for r in range(0, self.rows):
self.eb[(c, r)].set_tooltip_text(tip)
# action in tools tips for later streets
round_to_col = (0, 3, 4, 5, 6)
for round in range(1, len(hh.BETTING.rounds)):
tip = "%s" % hh.BETTING.rounds[round]
for r in range(0, self.rows):
self.eb[(round_to_col[round], r)].set_tooltip_text(tip)
def split_cards(self, card):
return (card[0], card[1].upper())
def clear(self):
for r in range(0, self.rows):
self.grid_contents[(1, r)].set_text(" ")
for c in range(0, 7):
self.seen_cards[(c, r)].set_from_pixbuf(self.card_images[('B', 'S')])
self.eb[(c, r)].set_tooltip_text('')
def get_card_images(self):
card_images = {}
suits = ('S', 'H', 'D', 'C')
ranks = ('A', 'K', 'Q', 'J', 'T', '9', '8', '7', '6', '5', '4', '3', '2', 'B')
pb = gtk.gdk.pixbuf_new_from_file("Cards01.png")
for j in range(0, 14):
for i in range(0, 4):
temp_pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, pb.get_has_alpha(), pb.get_bits_per_sample(), 30, 42)
pb.copy_area(30*j, 42*i, 30, 42, temp_pb, 0, 0)
card_images[(ranks[j], suits[i])] = temp_pb
return(card_images)
# cards are 30 wide x 42 high
if __name__== "__main__":
def destroy(*args): # call back for terminating the main eventloop
gtk.main_quit() # used only for testing
def process_new_hand(source, condition): #callback from stdin watch -- testing only
# there is a new hand_id to be processed
# just read it and pass it to update
new_hand_id = sys.stdin.readline()
new_hand_id = new_hand_id.rstrip() # remove trailing whitespace
m.update(new_hand_id)
return(True)
print "system = %s" % (os.name)
config = Configuration.Config()
db_connection = Database.Database(config, 'PTrackSv2', 'razz')
main_window = gtk.Window()
main_window.set_keep_above(True)
main_window.connect("destroy", destroy)
m = Mucked(main_window, db_connection)
main_window.show_all()
s_id = gobject.io_add_watch(sys.stdin, gobject.IO_IN, process_new_hand)
gtk.main()

262
pyfpdb/SQL.py Normal file
View File

@ -0,0 +1,262 @@
#!/usr/bin/env python
"""SQL.py
Set up all of the SQL statements for a given game and database type.
"""
# Copyright 2008, Ray E. Barker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
# Standard Library modules
# pyGTK modules
# FreePokerTools modules
class Sql:
def __init__(self, game = 'holdem', type = 'PT3'):
self.query = {}
if game == 'razz' and type == 'ptracks':
self.query['get_table_name'] = "select table_name from game where game_id = %s"
self.query['get_last_hand'] = "select max(game_id) from game"
self.query['get_recent_hands'] = "select game_id from game where game_id > %(last_hand)d"
self.query['get_xml'] = "select xml from hand_history where game_id = %s"
self.query['get_player_id'] = """
select player_id from players
where screen_name = %(player)s
"""
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
"""
self.query['get_cards'] = """
select
seat_number,
screen_name,
hole_card_1,
hole_card_2,
hole_card_3,
hole_card_4,
hole_card_5,
hole_card_6,
hole_card_7
from game_players, players
where game_id = %s and game_players.player_id = players.player_id
order by seat_number
"""
self.query['get_stats_from_hand'] = """
SELECT player_id,
count(*) AS n,
sum(pre_fourth_raise_n) AS pfr,
sum(fourth_raise_n) AS raise_n_2,
sum(fourth_ck_raise_n) AS cr_n_2,
sum(fifth_bet_raise_n) AS br_n_3,
sum(fifth_bet_ck_raise_n) AS cr_n_3,
sum(sixth_bet_raise_n) AS br_n_4,
sum(sixth_bet_ck_raise_n) AS cr_n_4,
sum(river_bet_raise_n) AS br_n_5,
sum(river_bet_ck_raise_n) AS cr_n_5,
sum(went_to_showdown_n) AS sd,
sum(saw_fourth_n) AS saw_f,
sum(raised_first_pf) AS first_pfr,
sum(vol_put_money_in_pot) AS vpip,
sum(limp_with_prev_callers) AS limp_w_callers,
sum(ppossible_actions) AS poss_a_pf,
sum(pfold) AS fold_pf,
sum(pcheck) AS check_pf,
sum(praise) AS raise_pf,
sum(pcall) AS raise_pf,
sum(limp_call_reraise_pf) AS limp_call_pf,
sum(pfr_check) AS check_after_raise,
sum(pfr_call) AS call_after_raise,
sum(pfr_fold) AS fold_after_raise,
sum(pfr_bet) AS bet_after_raise,
sum(pfr_raise) AS raise_after_raise,
sum(folded_to_river_bet) AS fold_to_r_bet,
sum(fpossible_actions) AS poss_a_2,
sum(ffold) AS fold_2,
sum(fcheck) AS check_2,
sum(fbet) AS bet_2,
sum(fraise) AS raise_2,
sum(fcall) AS raise_2,
sum(fifpossible_actions) AS poss_a_3,
sum(fiffold) AS fold_3,
sum(fifcheck) AS check_3,
sum(fifbet) AS bet_3,
sum(fifraise) AS raise_3,
sum(fifcall) AS call_3,
sum(spossible_actions) AS poss_a_4,
sum(sfold) AS fold_4,
sum(scheck) AS check_4,
sum(sbet) AS bet_4,
sum(sraise) AS raise_4,
sum(scall) AS call_4,
sum(rpossible_actions) AS poss_a_5,
sum(rfold) AS fold_5,
sum(rcheck) AS check_5,
sum(rbet) AS bet_5,
sum(rraise) AS raise_5,
sum(rcall) AS call_5,
sum(cold_call_pf) AS cc_pf,
sum(saw_fifth_n) AS saw_3,
sum(saw_sixth_n) AS saw_4,
sum(saw_river_n) AS saw_5
FROM game_players
WHERE player_id in
(SELECT player_id FROM game_players
WHERE game_id = %s AND NOT player_id = %s)
GROUP BY player_id
"""
# alternate form of WHERE for above
# WHERE game_id = %(hand)d AND NOT player_id = %(hero)d)
# WHERE game_id = %s AND NOT player_id = %s)
self.query['get_players_from_hand'] = """
SELECT game_players.player_id, seat_number, screen_name
FROM game_players INNER JOIN players ON (game_players.player_id = players.player_id)
WHERE game_id = %s
"""
if game == 'holdem' and type == 'PT3':
self.query['get_last_hand'] = "select max(id_hand) from holdem_hand_summary"
self.query['get_player_id'] = """
select id_player from player, lookup_sites
where player_name = %(player)s
and site_name = %(site)s
and player.id_site = lookup_sites.id_site
"""
self.query['get_stats_from_hand'] = """
select id_player AS player_id,
count(*) AS n,
sum(CAST (flg_vpip AS integer)) as vpip,
sum(CAST (flg_p_first_raise AS integer)) as p_first_raise,
sum(CAST (flg_f_saw AS integer)) as f_saw,
sum(CAST (flg_p_open AS integer)) as p_open,
sum(CAST (flg_p_limp AS integer)) as p_limp,
sum(CAST (flg_p_fold AS integer)) as p_fold,
sum(CAST (flg_p_ccall AS integer)) as p_ccall,
sum(CAST (flg_f_bet AS integer)) as f_bet,
sum(CAST (flg_f_first_raise AS integer)) as f_first_raise,
sum(CAST (flg_f_check AS integer)) as f_check,
sum(CAST (flg_f_check_raise AS integer)) as f_check_raise,
sum(CAST (flg_f_fold AS integer)) as f_fold,
sum(CAST (flg_f_saw AS integer)) as f_saw,
sum(CAST (flg_t_bet AS integer)) as t_bet,
sum(CAST (flg_t_first_raise AS integer)) as t_first_raise,
sum(CAST (flg_t_check AS integer)) as t_check,
sum(CAST (flg_t_check_raise AS integer)) as t_check_raise,
sum(CAST (flg_t_fold AS integer)) as t_fold,
sum(CAST (flg_t_saw AS integer)) as t_saw,
sum(CAST (flg_r_bet AS integer)) as r_bet,
sum(CAST (flg_r_first_raise AS integer)) as r_first_raise,
sum(CAST (flg_r_check AS integer)) as r_check,
sum(CAST (flg_r_check_raise AS integer)) as r_check_raise,
sum(CAST (flg_r_fold AS integer)) as r_fold,
sum(CAST (flg_r_saw AS integer)) as r_saw,
sum(CAST (flg_sb_steal_fold AS integer)) as sb_steal_fold,
sum(CAST (flg_bb_steal_fold AS integer)) as bb_steal_fold,
sum(CAST (flg_blind_def_opp AS integer)) as blind_def_opp,
sum(CAST (flg_steal_att AS integer)) as steal_att,
sum(CAST (flg_steal_opp AS integer)) as steal_opp,
sum(CAST (flg_blind_k AS integer)) as blind_k,
sum(CAST (flg_showdown AS integer)) as showdown,
sum(CAST (flg_p_squeeze AS integer)) as p_squeeze,
sum(CAST (flg_p_squeeze_opp AS integer)) as p_squeeze_opp,
sum(CAST (flg_p_squeeze_def_opp AS integer)) as p_squeeze_def_opp,
sum(CAST (flg_f_cbet AS integer)) as f_cbet,
sum(CAST (flg_f_cbet_opp AS integer)) as f_cbet_opp,
sum(CAST (flg_f_cbet_def_opp AS integer)) as f_cbet_def_opp
from holdem_hand_player_statistics
where id_hand = %(hand)d and not id_player = %(hero)d
group by id_player
"""
if game == 'holdem' and type == 'fpdb':
self.query['get_last_hand'] = "select max(id) from Hands"
self.query['get_player_id'] = """
select Players.id AS player_id from Players, Sites
where Players.name = %(player)s
and Sites.name = %(site)s
and Players.SiteId = Sites.id
"""
self.query['get_stats_from_hand'] = """
SELECT HudCache.playerId AS player_id,
sum(HDs) AS n,
sum(street0Aggr) AS pfr,
sum(street0VPI) AS vpip,
sum(sawShowdown) AS sd,
sum(wonAtSD) AS wmsd,
sum(street1Seen) AS saw_f,
sum(totalProfit) AS net
FROM HudCache, Hands
WHERE HudCache.PlayerId in
(SELECT PlayerId FROM HandsPlayers
WHERE handId = %s)
AND Hands.id = %s
AND Hands.gametypeId = HudCache.gametypeId
GROUP BY HudCache.PlayerId
"""
self.query['get_players_from_hand'] = """
SELECT HandsPlayers.playerId, seatNo, name
FROM HandsPlayers INNER JOIN Players ON (HandsPlayers.playerId = Players.id)
WHERE handId = %s
"""
self.query['get_table_name'] = """
select tableName, maxSeats, category
from Hands,Gametypes
where Hands.id = %s
and Gametypes.id = Hands.gametypeId
"""
if __name__== "__main__":
# just print the default queries and exit
s = Sql(game = 'razz', type = 'ptracks')
for key in s.query:
print "For query " + key + ", sql ="
print s.query[key]

186
pyfpdb/Stats.py Normal file
View File

@ -0,0 +1,186 @@
#!/usr/bin/env python
"""Manage collecting and formatting of stats and tooltips.
"""
# Copyright 2008, Ray E. Barker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
# Standard Library modules
# pyGTK modules
import pygtk
import gtk
# FreePokerTools modules
import Configuration
import Database
def do_tip(widget, tip):
widget.set_tooltip_text(tip)
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:
# 0 - The stat, raw, no formating, eg 0.33333333
# 1 - formatted stat with appropriate precision and punctuation, eg 33%
# 2 - formatted stat with appropriate precision, punctuation and a hint, eg v=33%
# 3 - same as #2 except name of stat instead of hint, eg vpip=33%
# 4 - the calculation that got the stat, eg 9/27
# 5 - the name of the stat, useful for a tooltip, eg vpip
###########################################
# functions that return individual stats
def vpip(stat_dict, player):
stat = 0.0
try:
stat = float(stat_dict[player]['vpip'])/float(stat_dict[player]['n'])
return (stat,
'%3.1f' % (100*stat) + '%',
'v=%3.1f' % (100*stat) + '%',
'vpip=%3.1f' % (100*stat) + '%',
'(%d/%d)' % (stat_dict[player]['vpip'], stat_dict[player]['n']),
'vpip'
)
except: return (stat,
'%3.1f' % (0) + '%',
'w=%3.1f' % (0) + '%',
'wtsd=%3.1f' % (0) + '%',
'(%d/%d)' % (0, 0),
'wtsd'
)
def pfr(stat_dict, player):
stat = 0.0
try:
stat = float(stat_dict[player]['pfr'])/float(stat_dict[player]['n'])
return (stat,
'%3.1f' % (100*stat) + '%',
'p=%3.1f' % (100*stat) + '%',
'pfr=%3.1f' % (100*stat) + '%',
'(%d/%d)' % (stat_dict[player]['pfr'], stat_dict[player]['n']),
'pfr'
)
except:
return (stat,
'%3.1f' % (0) + '%',
'w=%3.1f' % (0) + '%',
'wtsd=%3.1f' % (0) + '%',
'(%d/%d)' % (0, 0),
'wtsd'
)
def wtsd(stat_dict, player):
stat = 0.0
try:
stat = float(stat_dict[player]['sd'])/float(stat_dict[player]['saw_f'])
return (stat,
'%3.1f' % (100*stat) + '%',
'w=%3.1f' % (100*stat) + '%',
'wtsd=%3.1f' % (100*stat) + '%',
'(%d/%d)' % (stat_dict[player]['sd'], stat_dict[player]['saw_f']),
'wtsd'
)
except:
return (stat,
'%3.1f' % (0) + '%',
'w=%3.1f' % (0) + '%',
'wtsd=%3.1f' % (0) + '%',
'(%d/%d)' % (0, 0),
'wtsd'
)
def saw_f(stat_dict, player):
try:
num = float(stat_dict[player]['saw_f'])
den = float(stat_dict[player]['n'])
stat = num/den
return (stat,
'%3.1f' % (100*stat) + '%',
'sf=%3.1f' % (100*stat) + '%',
'saw_f=%3.1f' % (100*stat) + '%',
'(%d/%d)' % (stat_dict[player]['saw_f'], stat_dict[player]['n']),
'saw_f'
)
except:
stat = 0.0
num = 0
den = 0
return (stat,
'%3.1f' % (stat) + '%',
'sf=%3.1f' % (stat) + '%',
'saw_f=%3.1f' % (stat) + '%',
'(%d/%d)' % (num, den),
'saw_f'
)
def n(stat_dict, player):
try:
return (stat_dict[player]['n'],
'%d' % (stat_dict[player]['n']),
'n=%d' % (stat_dict[player]['n']),
'n=%d' % (stat_dict[player]['n']),
'(%d)' % (stat_dict[player]['n']),
'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]),
'number hands seen'
)
def fold_f(stat_dict, player):
stat = 0.0
try:
stat = stat_dict[player]['fold_2']/stat_dict[player]['saw_f']
return (stat,
'%3.1f' % (100*stat) + '%',
'ff=%3.1f' % (100*stat) + '%',
'fold_f=%3.1f' % (100*stat) + '%',
'(%d/%d)' % (stat_dict[player]['fold_2'], stat_dict[player]['saw_f']),
'folded fourth'
)
except:
return (stat,
'%3.1f' % (0) + '%',
'ff=%3.1f' % (0) + '%',
'fold_f=%3.1f' % (0) + '%',
'(%d/%d)' % (0, 0),
'folded fourth'
)
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)
for player in stat_dict.keys():
print "player = ", player, do_stat(stat_dict, player = player, stat = 'vpip')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'pfr')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'wtsd')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'saw_f')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'n')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'fold_f')
db_connection.close

135
pyfpdb/Tables.py Normal file
View File

@ -0,0 +1,135 @@
#!/usr/bin/env python
"""Discover_Tables.py
Inspects the currently open windows and finds those of interest to us--that is
poker table windows from supported sites. Returns a list
of Table_Window objects representing the windows found.
"""
# Copyright 2008, Ray E. Barker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
# Standard Library modules
import os
import re
# FreePokerTools modules
import Configuration
class Table_Window:
def __str__(self):
# __str__ method for testing
temp = 'TableWindow object\n'
temp = temp + " name = %s\n site = %s\n number = %s\n title = %s\n" % (self.name, self.site, self.number, self.title)
temp = temp + " game = %s\n structure = %s\n max = %s\n" % (self.game, self.structure, self.max)
temp = temp + " width = %d\n height = %d\n x = %d\n y = %d\n" % (self.width, self.height, self.x, self.y)
if getattr(self, 'tournament', 0):
temp = temp + " tournament = %d\n table = %d" % (self.tournament, self.table)
return temp
def get_details(table):
table.game = 'razz'
table.max = 8
table.struture = 'limit'
table.tournament = 0
def discover(c):
tables = {}
for listing in os.popen('xwininfo -root -tree').readlines():
if re.search('Lobby', listing): continue
if re.search('Instant Hand History', listing): continue
if not re.search('Logged In as ', listing): continue
for s in c.supported_sites.keys():
if re.search(c.supported_sites[s].table_finder, listing):
mo = re.match('\s+([\dxabcdef]+) (.+):.+ (\d+)x(\d+)\+\d+\+\d+ \+(\d+)\+(\d+)', listing)
if mo.group(2) == '(has no name)': continue
if re.match('[\(\)\d\s]+', mo.group(2)): continue # this is a popup
tw = Table_Window()
tw.site = c.supported_sites[s].site_name
tw.number = mo.group(1)
tw.title = mo.group(2)
tw.width = int( mo.group(3) )
tw.height = int( mo.group(4) )
tw.x = int (mo.group(5) )
tw.y = int (mo.group(6) )
tw.title = re.sub('\"', '', tw.title)
# this rather ugly hack makes my fake table used for debugging work
if tw.title == "PokerStars.py": continue
# use this eval thingie to call the title bar decoder specified in the config file
eval("%s(tw)" % c.supported_sites[s].decoder)
tables[tw.name] = tw
return tables
def pokerstars_decode_table(tw):
# extract the table name OR the tournament number and table name from the title
# other info in title is redundant with data in the database
title_bits = re.split(' - ', tw.title)
name = title_bits[0]
mo = re.search('Tournament (\d+) Table (\d+)', name)
if mo:
tw.tournament = int( mo.group(1) )
tw.table = int( mo.group(2) )
tw.name = name
else:
tw.tournament = None
for pattern in [' no all-in', ' fast', ',']:
name = re.sub(pattern, '', name)
name = re.sub('\s+$', '', name)
tw.name = name
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)
mo = re.search('(No Limit|Pot Limit)', tw.title)
if mo:
tw.structure = mo.group(1).lower()
else:
tw.structure = 'limit'
tw.max = None
if tw.game in ('razz', 'stud', 'stud hi/lo'):
tw.max = 8
elif tw.game in ('5-card draw', 'triple draw 2-7 lowball'):
tw.max = 6
elif tw.game == 'holdem':
pass
elif tw.game in ('omaha', 'omaha hi/lo'):
pass
if __name__=="__main__":
c = Configuration.Config()
tables = discover(c)
for t in tables.keys():
print tables[t]

View File

@ -102,12 +102,12 @@ def import_file_dict(options, settings):
try: try:
if (category=="razz" or category=="studhi" or category=="studhilo"): if (category=="razz" or category=="studhi" or category=="studhilo"):
raise fpdb_simple.FpdbError ("stud/razz currently out of order") raise fpdb_simple.FpdbError ("stud/razz currently out of order")
last_read_hand=fpdb_parse_logic.mainParser(db, cursor, site, category, hand) handsId=fpdb_parse_logic.mainParser(db, cursor, site, category, hand)
db.commit() db.commit()
stored+=1 stored+=1
if settings['imp-callFpdbHud']: if settings['imp-callFpdbHud']:
print "call to HUD here" print "call to HUD here. handsId:",handsId
db.commit() db.commit()
except fpdb_simple.DuplicateError: except fpdb_simple.DuplicateError:
duplicates+=1 duplicates+=1
@ -156,13 +156,13 @@ def import_file_dict(options, settings):
for line_no in range(len(lines)): for line_no in range(len(lines)):
if lines[line_no].find("Game #")!=-1: if lines[line_no].find("Game #")!=-1:
final_game_line=lines[line_no] final_game_line=lines[line_no]
last_read_hand=fpdb_simple.parseSiteHandNo(final_game_line) handsId=fpdb_simple.parseSiteHandNo(final_game_line)
#todo: this will cause return of an unstored hand number if the last hadn was error or partial #todo: this will cause return of an unstored hand number if the last hadn was error or partial
db.commit() db.commit()
inputFile.close() inputFile.close()
cursor.close() cursor.close()
db.close() db.close()
return last_read_hand return handsId
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -34,7 +34,7 @@ def ring_stud(cursor, category, site_hand_no, gametype_id, hand_start_time,
fpdb_simple.storeHudData(cursor, category, player_ids, hudImportData) fpdb_simple.storeHudData(cursor, category, player_ids, hudImportData)
fpdb_simple.storeActions(cursor, hands_players_ids, action_types, action_amounts) fpdb_simple.storeActions(cursor, hands_players_ids, action_types, action_amounts)
return site_hand_no return hands_id
#end def ring_stud #end def ring_stud
def ring_holdem_omaha(cursor, category, site_hand_no, gametype_id, hand_start_time, names, player_ids, start_cashes, positions, card_values, card_suits, board_values, board_suits, winnings, rakes, action_types, action_amounts, actionNos, hudImportData, maxSeats, tableName, seatNos): def ring_holdem_omaha(cursor, category, site_hand_no, gametype_id, hand_start_time, names, player_ids, start_cashes, positions, card_values, card_suits, board_values, board_suits, winnings, rakes, action_types, action_amounts, actionNos, hudImportData, maxSeats, tableName, seatNos):
@ -51,7 +51,7 @@ def ring_holdem_omaha(cursor, category, site_hand_no, gametype_id, hand_start_ti
fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits) fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits)
fpdb_simple.storeActions(cursor, hands_players_ids, action_types, action_amounts, actionNos) fpdb_simple.storeActions(cursor, hands_players_ids, action_types, action_amounts, actionNos)
return site_hand_no return hands_id
#end def ring_holdem_omaha #end def ring_holdem_omaha
def tourney_holdem_omaha(cursor, category, siteTourneyNo, buyin, fee, knockout, entries, prizepool, tourney_start, payin_amounts, ranks, tourneyTypeId, siteId, #end of tourney specific params def tourney_holdem_omaha(cursor, category, siteTourneyNo, buyin, fee, knockout, entries, prizepool, tourney_start, payin_amounts, ranks, tourneyTypeId, siteId, #end of tourney specific params
@ -72,7 +72,7 @@ def tourney_holdem_omaha(cursor, category, siteTourneyNo, buyin, fee, knockout,
fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits) fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits)
fpdb_simple.storeActions(cursor, hands_players_ids, action_types, action_amounts, actionNos) fpdb_simple.storeActions(cursor, hands_players_ids, action_types, action_amounts, actionNos)
return site_hand_no return hands_id
#end def tourney_holdem_omaha #end def tourney_holdem_omaha
def tourney_stud(cursor, category, site_tourney_no, buyin, fee, knockout, entries, prizepool, def tourney_stud(cursor, category, site_tourney_no, buyin, fee, knockout, entries, prizepool,
@ -95,6 +95,5 @@ def tourney_stud(cursor, category, site_tourney_no, buyin, fee, knockout, entrie
fpdb_simple.storeHudData(cursor, category, player_ids, hudImportData) fpdb_simple.storeHudData(cursor, category, player_ids, hudImportData)
fpdb_simple.storeActions(cursor, hands_players_ids, action_types, action_amounts) fpdb_simple.storeActions(cursor, hands_players_ids, action_types, action_amounts)
return site_hand_no return hands_id
#end def tourney_stud #end def tourney_stud