Merge from ray, minor conflicts

This commit is contained in:
Matt Turnbull 2009-07-15 00:20:26 +01:00
commit 79ca83c95a
22 changed files with 1011 additions and 764 deletions

View File

@ -86,14 +86,34 @@ class Site:
self.aux_window = node.getAttribute("aux_window") self.aux_window = node.getAttribute("aux_window")
self.font = node.getAttribute("font") self.font = node.getAttribute("font")
self.font_size = node.getAttribute("font_size") self.font_size = node.getAttribute("font_size")
self.use_frames = node.getAttribute("use_frames") self.use_frames = node.getAttribute("use_frames")
self.enabled = fix_tf(node.getAttribute("enabled"), default = True) self.enabled = fix_tf(node.getAttribute("enabled"), default = True)
self.xpad = node.getAttribute("xpad")
self.ypad = node.getAttribute("ypad")
self.layout = {} self.layout = {}
for layout_node in node.getElementsByTagName('layout'): for layout_node in node.getElementsByTagName('layout'):
lo = Layout(layout_node) lo = Layout(layout_node)
self.layout[lo.max] = lo self.layout[lo.max] = lo
# Site defaults
if self.xpad == "": self.xpad = 1
else: self.xpad = int(self.xpad)
if self.ypad == "": self.ypad = 0
else: self.ypad = int(self.ypad)
if self.font_size == "": self.font_size = 7
else: self.font_size = int(self.font_size)
if self.hudopacity == "": self.hudopacity = 1.0
else: self.hudopacity = float(self.hudopacity)
if self.use_frames == "": self.use_frames = False
if self.font == "": self.font = "Sans"
if self.hudbgcolor == "": self.hudbgcolor = "000000"
if self.hudfgcolor == "": self.hudfgcolor = "FFFFFF"
def __str__(self): def __str__(self):
temp = "Site = " + self.site_name + "\n" temp = "Site = " + self.site_name + "\n"
for key in dir(self): for key in dir(self):
@ -119,9 +139,16 @@ class Stat:
class Game: class Game:
def __init__(self, node): def __init__(self, node):
self.game_name = node.getAttribute("game_name") self.game_name = node.getAttribute("game_name")
self.db = node.getAttribute("db")
self.rows = int( node.getAttribute("rows") ) self.rows = int( node.getAttribute("rows") )
self.cols = int( node.getAttribute("cols") ) self.cols = int( node.getAttribute("cols") )
self.xpad = node.getAttribute("xpad")
self.ypad = node.getAttribute("ypad")
# Defaults
if self.xpad == "": self.xpad = 1
else: self.xpad = int(self.xpad)
if self.ypad == "": self.ypad = 0
else: self.ypad = int(self.ypad)
aux_text = node.getAttribute("aux") aux_text = node.getAttribute("aux")
aux_list = aux_text.split(',') aux_list = aux_text.split(',')
@ -146,9 +173,10 @@ class Game:
def __str__(self): def __str__(self):
temp = "Game = " + self.game_name + "\n" temp = "Game = " + self.game_name + "\n"
temp = temp + " db = %s\n" % self.db
temp = temp + " rows = %d\n" % self.rows temp = temp + " rows = %d\n" % self.rows
temp = temp + " cols = %d\n" % self.cols temp = temp + " cols = %d\n" % self.cols
temp = temp + " xpad = %d\n" % self.xpad
temp = temp + " ypad = %d\n" % self.ypad
temp = temp + " aux = %s\n" % self.aux temp = temp + " aux = %s\n" % self.aux
for stat in self.stats.keys(): for stat in self.stats.keys():
@ -633,6 +661,8 @@ class Config:
parms["font"] = self.supported_sites[site].font parms["font"] = self.supported_sites[site].font
parms["font_size"] = self.supported_sites[site].font_size parms["font_size"] = self.supported_sites[site].font_size
parms["enabled"] = self.supported_sites[site].enabled parms["enabled"] = self.supported_sites[site].enabled
parms["xpad"] = self.supported_sites[site].xpad
parms["ypad"] = self.supported_sites[site].ypad
return parms return parms
def set_site_parameters(self, site_name, converter = None, decoder = None, def set_site_parameters(self, site_name, converter = None, decoder = None,
@ -683,9 +713,10 @@ class Config:
param = {} param = {}
if self.supported_games.has_key(name): if self.supported_games.has_key(name):
param['game_name'] = self.supported_games[name].game_name param['game_name'] = self.supported_games[name].game_name
param['db'] = self.supported_games[name].db
param['rows'] = self.supported_games[name].rows param['rows'] = self.supported_games[name].rows
param['cols'] = self.supported_games[name].cols param['cols'] = self.supported_games[name].cols
param['xpad'] = self.supported_games[name].xpad
param['ypad'] = self.supported_games[name].ypad
param['aux'] = self.supported_games[name].aux param['aux'] = self.supported_games[name].aux
return param return param

View File

@ -39,7 +39,8 @@ import SQL
import Card import Card
class Database: class Database:
def __init__(self, c, db_name, game): def __init__(self, c, db_name = None, game = None, sql = None): # db_name and game not used any more
print "\ncreating Database instance, sql =", sql
self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
self.fdb.do_connect(c) self.fdb.do_connect(c)
self.connection = self.fdb.db self.connection = self.fdb.db
@ -48,7 +49,12 @@ class Database:
self.import_options = c.get_import_parameters() self.import_options = c.get_import_parameters()
self.type = db_params['db-type'] self.type = db_params['db-type']
self.backend = db_params['db-backend'] self.backend = db_params['db-backend']
self.sql = SQL.Sql(game = game, type = self.type, db_server = db_params['db-server']) self.db_server = db_params['db-server']
# where possible avoid creating new SQL instance by using the global one passed in
if sql == None:
self.sql = SQL.Sql(type = self.type, db_server = db_params['db-server'])
else:
self.sql = sql
self.connection.rollback() self.connection.rollback()
# To add to config: # To add to config:
@ -81,13 +87,28 @@ class Database:
#row = cur.fetchone() #row = cur.fetchone()
self.saveActions = False if self.import_options['saveActions'] == False else True self.saveActions = False if self.import_options['saveActions'] == False else True
def do_connect(self, c):
self.fdb.do_connect(c)
def commit(self): def commit(self):
self.fdb.db.commit() self.fdb.db.commit()
def close_connection(self): def close_connection(self):
self.connection.close() self.connection.close()
def disconnect(self, due_to_error=False):
"""Disconnects the DB (rolls back if param is true, otherwise commits"""
self.fdb.disconnect(due_to_error)
def reconnect(self, due_to_error=False):
"""Reconnects the DB"""
self.fdb.reconnect(due_to_error=False)
def get_backend_name(self):
"""Reconnects the DB"""
return self.fdb.get_backend_name()
def get_table_name(self, hand_id): def get_table_name(self, hand_id):
c = self.connection.cursor() c = self.connection.cursor()
c.execute(self.sql.query['get_table_name'], (hand_id, )) c.execute(self.sql.query['get_table_name'], (hand_id, ))
@ -138,12 +159,8 @@ class Database:
cards = {} cards = {}
c = self.connection.cursor() c = self.connection.cursor()
c.execute(self.sql.query['get_common_cards'], [hand]) c.execute(self.sql.query['get_common_cards'], [hand])
colnames = [desc[0] for desc in c.description] # row = c.fetchone()
for row in c.fetchall(): cards['common'] = c.fetchone()
s_dict = {}
for name, val in zip(colnames, row):
s_dict[name] = val
cards['common'] = (self.convert_cards(s_dict))
return cards return cards
def convert_cards(self, d): def convert_cards(self, d):
@ -285,7 +302,8 @@ class Database:
fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits)
hands_id = fpdb_simple.storeHands(self.backend, db, cursor, site_hand_no, gametype_id hands_id = fpdb_simple.storeHands(self.backend, db, cursor, site_hand_no, gametype_id
,hand_start_time, names, tableName, maxSeats, hudImportData) ,hand_start_time, names, tableName, maxSeats, hudImportData
,(None, None, None, None, None), (None, None, None, None, None))
#print "before calling store_hands_players_stud, antes:", antes #print "before calling store_hands_players_stud, antes:", antes
hands_players_ids = fpdb_simple.store_hands_players_stud(self.backend, db, cursor, hands_id, player_ids hands_players_ids = fpdb_simple.store_hands_players_stud(self.backend, db, cursor, hands_id, player_ids
@ -326,7 +344,6 @@ class Database:
if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop': if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop':
fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData)
t5 = time() t5 = time()
fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits)
t6 = time() t6 = time()
if self.saveActions: if self.saveActions:
fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos)
@ -361,8 +378,6 @@ class Database:
if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop': if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop':
fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData)
fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits)
if self.saveActions: if self.saveActions:
fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos)
return hands_id return hands_id

View File

@ -30,12 +30,11 @@ import fpdb_db
import FpdbSQLQueries import FpdbSQLQueries
class Filters(threading.Thread): class Filters(threading.Thread):
def __init__(self, db, settings, config, qdict, display = {},debug=True): def __init__(self, db, config, qdict, display = {}, debug=True):
self.debug=debug self.debug=debug
#print "start of GraphViewer constructor" #print "start of GraphViewer constructor"
self.db=db self.db=db
self.cursor=db.cursor self.cursor=db.cursor
self.settings=settings
self.sql=qdict self.sql=qdict
self.conf = config self.conf = config
self.display = display self.display = display
@ -235,7 +234,7 @@ class Filters(threading.Thread):
def __set_hero_name(self, w, site): def __set_hero_name(self, w, site):
self.heroes[site] = w.get_text() self.heroes[site] = w.get_text()
# print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site]) # print "DEBUG: setting heroes[%s]: %s"%(site, self.heroes[site])
def createSiteLine(self, hbox, site): def createSiteLine(self, hbox, site):
cb = gtk.CheckButton(site) cb = gtk.CheckButton(site)
@ -556,23 +555,12 @@ def main(argv=None):
config = Configuration.Config() config = Configuration.Config()
db = None db = None
settings = {}
settings.update(config.get_db_parameters())
settings.update(config.get_tv_parameters())
settings.update(config.get_import_parameters())
settings.update(config.get_default_paths())
db = fpdb_db.fpdb_db() db = fpdb_db.fpdb_db()
db.connect(settings['db-backend'], db.do_connect(config)
settings['db-host'],
settings['db-databaseName'],
settings['db-user'],
settings['db-password'])
qdict = FpdbSQLQueries.FpdbSQLQueries(db.get_backend_name()) qdict = FpdbSQLQueries.FpdbSQLQueries(db.get_backend_name())
i = Filters(db, settings, config, qdict) i = Filters(db, config, qdict)
main_window = gtk.Window() main_window = gtk.Window()
main_window.connect('destroy', destroy) main_window.connect('destroy', destroy)
main_window.add(i.get_vbox()) main_window.add(i.get_vbox())

View File

@ -282,43 +282,6 @@ class FpdbSQLQueries:
FOREIGN KEY(gametypeId) REFERENCES Gametypes(id) ON DELETE CASCADE)""" FOREIGN KEY(gametypeId) REFERENCES Gametypes(id) ON DELETE CASCADE)"""
################################
# Create BoardCards
################################
if(self.dbname == 'MySQL InnoDB'):
self.query['createBoardCardsTable'] = """CREATE TABLE BoardCards (
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
handId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handId) REFERENCES Hands(id),
card1Value smallint NOT NULL,
card1Suit char(1) NOT NULL,
card2Value smallint NOT NULL,
card2Suit char(1) NOT NULL,
card3Value smallint NOT NULL,
card3Suit char(1) NOT NULL,
card4Value smallint NOT NULL,
card4Suit char(1) NOT NULL,
card5Value smallint NOT NULL,
card5Suit char(1) NOT NULL)
ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'):
self.query['createBoardCardsTable'] = """CREATE TABLE BoardCards (
id BIGSERIAL, 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))"""
elif(self.dbname == 'SQLite'):
self.query['createBoardCardsTable'] = """ """
################################ ################################
# Create TourneyTypes # Create TourneyTypes
################################ ################################
@ -1598,136 +1561,6 @@ class FpdbSQLQueries:
elif(self.dbname == 'SQLite'): elif(self.dbname == 'SQLite'):
self.query['playerStatsByPosition'] = """ """ self.query['playerStatsByPosition'] = """ """
if(self.dbname == 'MySQL InnoDB'):
self.query['playerStatsByPositionAndHoleCards'] = """
SELECT
concat(upper(stats.limitType), ' '
,concat(upper(substring(stats.category,1,1)),substring(stats.category,2) ), ' '
,stats.name, ' $'
,cast(trim(leading ' ' from
case when stats.bigBlind < 100 then format(stats.bigBlind/100.0,2)
else format(stats.bigBlind/100.0,0)
end ) as char)
) AS Game
,case when stats.PlPosition = -2 then 'BB'
when stats.PlPosition = -1 then 'SB'
when stats.PlPosition = 0 then 'Btn'
when stats.PlPosition = 1 then 'CO'
when stats.PlPosition = 2 then 'MP'
when stats.PlPosition = 5 then 'EP'
else '??'
end AS PlPosition
/*,stats.n*/,hprof2.n
/*,stats.vpip*/,0
/*,stats.pfr*/,0
/*,stats.saw_f*/,0
/*,stats.sawsd*/,0
/*,stats.wtsdwsf*/,0
/*,stats.wmsd*/,0
/*,stats.FlAFq*/,0
/*,stats.TuAFq*/,0
/*,stats.RvAFq*/,0
/*,stats.PoFAFq*/,0
/* if you have handsactions data the next 3 fields should give same answer as
following 3 commented out fields */
/*,stats.Net
,stats.BBper100
,stats.Profitperhand*/
,format(hprof2.sum_profit/100.0,2) AS Net
/*,format((hprof2.sum_profit/(stats.bigBlind+0.0)) / (stats.n/100.0),2)*/,0
AS BBlPer100
,hprof2.profitperhand AS Profitperhand
,format(hprof2.variance,2) AS Variance
FROM
(select /* stats from hudcache */
gt.base
,gt.category
,upper(gt.limitType) as limitType
,s.name
,gt.bigBlind
,hc.gametypeId
,case when hc.position = 'B' then -2
when hc.position = 'S' then -1
when hc.position = 'D' then 0
when hc.position = 'C' then 1
when hc.position = 'M' then 2
when hc.position = 'E' then 5
else 9
end as PlPosition
,sum(HDs) AS n
,format(100.0*sum(street0VPI)/sum(HDs),1) AS vpip
,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr
,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f
,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd
,case when sum(street1Seen) = 0 then '-'
else format(100.0*sum(sawShowdown)/sum(street1Seen),1)
end AS wtsdwsf
,case when sum(sawShowdown) = 0 then '-'
end AS wtsdwsf
,case when sum(sawShowdown) = 0 then '-'
else format(100.0*sum(wonAtSD)/sum(sawShowdown),1)
end AS wmsd
,case when sum(street1Seen) = 0 then '-'
else format(100.0*sum(street1Aggr)/sum(street1Seen),1)
end AS FlAFq
,case when sum(street2Seen) = 0 then '-'
else format(100.0*sum(street2Aggr)/sum(street2Seen),1)
end AS TuAFq
,case when sum(street3Seen) = 0 then '-'
else format(100.0*sum(street3Aggr)/sum(street3Seen),1)
end AS RvAFq
,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-'
else format(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr))
/(sum(street1Seen)+sum(street2Seen)+sum(street3Seen)),1)
end AS PoFAFq
,format(sum(totalProfit)/100.0,2) AS Net
,format((sum(totalProfit)/(gt.bigBlind+0.0)) / (sum(HDs)/100.0),2)
AS BBper100
,format( (sum(totalProfit)/100.0) / sum(HDs), 4) AS Profitperhand
from Gametypes gt
inner join Sites s on s.Id = gt.siteId
inner join HudCache hc on hc.gameTypeId = gt.Id
where hc.playerId in <player_test>
# use <gametype_test> here ?
group by gt.base
,gt.category
,upper(gt.limitType)
,s.name
,gt.bigBlind
,hc.gametypeId
,PlPosition
) stats
inner join
( select # profit from handsplayers/handsactions
hprof.gameTypeId,
case when hprof.position = 'B' then -2
when hprof.position = 'S' then -1
when hprof.position in ('3','4') then 2
when hprof.position in ('6','7') then 5
else hprof.position
end as PlPosition,
sum(hprof.profit) as sum_profit,
avg(hprof.profit/100.0) as profitperhand,
variance(hprof.profit/100.0) as variance,
count(*) as n
from
(select hp.handId, h.gameTypeId, hp.position, hp.winnings, SUM(ha.amount) as costs
, hp.winnings - SUM(ha.amount) as profit
from HandsPlayers hp
inner join Hands h ON h.id = hp.handId
left join HandsActions ha ON ha.handsPlayerId = hp.id
where hp.playerId in <player_test>
# use <gametype_test> here ?
and hp.tourneysPlayersId IS NULL
and ((hp.card1Value = <first_card> and hp.card2Value = <second_card>) or (hp.card1Value = <second_card> and hp.card2Value = <first_card>))
group by hp.handId, h.gameTypeId, hp.position, hp.winnings
) hprof
group by hprof.gameTypeId, PlPosition
) hprof2
on ( hprof2.gameTypeId = stats.gameTypeId
and hprof2.PlPosition = stats.PlPosition)
order by stats.category, stats.limittype, stats.bigBlind, cast(stats.PlPosition as signed)
"""
if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'):
self.query['getGames'] = """SELECT DISTINCT category from Gametypes""" self.query['getGames'] = """SELECT DISTINCT category from Gametypes"""

View File

@ -43,14 +43,14 @@ import Filters
class GuiGraphViewer (threading.Thread): class GuiGraphViewer (threading.Thread):
def __init__(self, db, settings, querylist, config, debug=True): def __init__(self, querylist, config, debug=True):
"""Constructor for GraphViewer""" """Constructor for GraphViewer"""
self.debug=debug self.debug=debug
#print "start of GraphViewer constructor" #print "start of GraphViewer constructor"
self.db=db self.db = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
self.cursor=db.cursor self.db.do_connect(config)
self.settings=settings
self.sql=querylist self.sql = querylist
self.conf = config self.conf = config
filters_display = { "Heroes" : True, filters_display = { "Heroes" : True,
@ -63,7 +63,7 @@ class GuiGraphViewer (threading.Thread):
"Button2" : True "Button2" : True
} }
self.filters = Filters.Filters(db, settings, config, querylist, display = filters_display) self.filters = Filters.Filters(self.db, config, querylist, display = filters_display)
self.filters.registerButton1Name("Refresh Graph") self.filters.registerButton1Name("Refresh Graph")
self.filters.registerButton1Callback(self.generateGraph) self.filters.registerButton1Callback(self.generateGraph)
self.filters.registerButton2Name("Export to File") self.filters.registerButton2Name("Export to File")
@ -146,7 +146,7 @@ class GuiGraphViewer (threading.Thread):
for site in sites: for site in sites:
if sites[site] == True: if sites[site] == True:
sitenos.append(siteids[site]) sitenos.append(siteids[site])
self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) self.db.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],))
result = self.db.cursor.fetchall() result = self.db.cursor.fetchall()
if len(result) == 1: if len(result) == 1:
playerids.append(result[0][0]) playerids.append(result[0][0])
@ -226,7 +226,7 @@ class GuiGraphViewer (threading.Thread):
#print "DEBUG: sql query:" #print "DEBUG: sql query:"
#print tmp #print tmp
self.cursor.execute(tmp) self.db.cursor.execute(tmp)
#returns (HandId,Winnings,Costs,Profit) #returns (HandId,Winnings,Costs,Profit)
winnings = self.db.cursor.fetchall() winnings = self.db.cursor.fetchall()
self.db.db.rollback() self.db.db.rollback()

View File

@ -66,7 +66,7 @@ class GuiPlayerStats (threading.Thread):
"Button2" : True "Button2" : True
} }
self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display) self.filters = Filters.Filters(self.db, config, querylist, display = filters_display)
self.filters.registerButton1Name("_Filters") self.filters.registerButton1Name("_Filters")
self.filters.registerButton1Callback(self.showDetailFilter) self.filters.registerButton1Callback(self.showDetailFilter)
self.filters.registerButton2Name("_Refresh") self.filters.registerButton2Name("_Refresh")
@ -227,11 +227,6 @@ class GuiPlayerStats (threading.Thread):
if not flags: holecards = False if not flags: holecards = False
else: holecards = flags[0] else: holecards = flags[0]
self.stats_table = gtk.Table(1, 1, False)
self.stats_table.set_col_spacings(4)
self.stats_table.show()
tmp = self.sql.query[query] tmp = self.sql.query[query]
tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, seats, groups, dates) tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, seats, groups, dates)
self.cursor.execute(tmp) self.cursor.execute(tmp)
@ -279,10 +274,6 @@ class GuiPlayerStats (threading.Thread):
while sqlrow < rows: while sqlrow < rows:
treerow = [] treerow = []
if(row%2 == 0):
bgcolor = "white"
else:
bgcolor = "lightgrey"
for col,column in enumerate(cols_to_show): for col,column in enumerate(cols_to_show):
if column[colalias] in colnames: if column[colalias] in colnames:
value = result[sqlrow][colnames.index(column[colalias])] value = result[sqlrow][colnames.index(column[colalias])]

View File

@ -20,6 +20,7 @@ import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import os import os
from time import time, strftime
import fpdb_import import fpdb_import
import fpdb_db import fpdb_db
@ -58,21 +59,50 @@ class GuiPositionalStats (threading.Thread):
"Button2" : False "Button2" : False
} }
self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display) self.filters = Filters.Filters(self.db, config, querylist, display = filters_display)
self.filters.registerButton1Name("Refresh") self.filters.registerButton1Name("Refresh")
self.filters.registerButton1Callback(self.refreshStats) self.filters.registerButton1Callback(self.refreshStats)
# ToDo: store in config
# ToDo: create popup to adjust column config
# columns to display, keys match column name returned by sql, values in tuple are:
# is column displayed, column heading, xalignment, formatting
self.columns = [ ["game", True, "Game", 0.0, "%s"]
, ["hand", False, "Hand", 0.0, "%s"] # true not allowed for this line
, ["plposition", False, "Posn", 1.0, "%s"] # true not allowed for this line (set in code)
, ["n", True, "Hds", 1.0, "%d"]
, ["avgseats", True, "Seats", 1.0, "%3.1f"]
, ["vpip", True, "VPIP", 1.0, "%3.1f"]
, ["pfr", True, "PFR", 1.0, "%3.1f"]
, ["pf3", True, "PF3", 1.0, "%3.1f"]
, ["steals", True, "Steals", 1.0, "%3.1f"]
, ["saw_f", True, "Saw_F", 1.0, "%3.1f"]
, ["sawsd", True, "SawSD", 1.0, "%3.1f"]
, ["wtsdwsf", True, "WtSDwsF", 1.0, "%3.1f"]
, ["wmsd", True, "W$SD", 1.0, "%3.1f"]
, ["flafq", True, "FlAFq", 1.0, "%3.1f"]
, ["tuafq", True, "TuAFq", 1.0, "%3.1f"]
, ["rvafq", True, "RvAFq", 1.0, "%3.1f"]
, ["pofafq", False, "PoFAFq", 1.0, "%3.1f"]
, ["net", True, "Net($)", 1.0, "%6.2f"]
, ["bbper100", True, "bb/100", 1.0, "%4.2f"]
, ["rake", True, "Rake($)", 1.0, "%6.2f"]
, ["bb100xr", True, "bbxr/100", 1.0, "%4.2f"]
, ["variance", True, "Variance", 1.0, "%5.2f"]
]
self.stat_table = None self.stat_table = None
self.stats_frame = None self.stats_frame = None
self.stats_vbox = None
self.main_hbox = gtk.HBox(False, 0) self.main_hbox = gtk.HBox(False, 0)
self.main_hbox.show() self.main_hbox.show()
statsFrame = gtk.Frame("Stats:") self.stats_frame = gtk.Frame()
statsFrame.set_label_align(0.0, 0.0) self.stats_frame.set_label_align(0.0, 0.0)
statsFrame.show()
self.stats_frame = gtk.VBox(False, 0)
self.stats_frame.show() self.stats_frame.show()
self.stats_vbox = gtk.VBox(False, 0)
self.stats_vbox.show()
# This could be stored in config eventually, or maybe configured in this window somehow. # This could be stored in config eventually, or maybe configured in this window somehow.
# Each posncols element is the name of a column returned by the sql # Each posncols element is the name of a column returned by the sql
@ -90,11 +120,11 @@ class GuiPositionalStats (threading.Thread):
, "PoFAFq", "Net($)", "bb/100", "$/hand", "Variance", "Hds" , "PoFAFq", "Net($)", "bb/100", "$/hand", "Variance", "Hds"
) )
self.fillStatsFrame(self.stats_frame) self.fillStatsFrame(self.stats_vbox)
statsFrame.add(self.stats_frame) self.stats_frame.add(self.stats_vbox)
self.main_hbox.pack_start(self.filters.get_vbox()) self.main_hbox.pack_start(self.filters.get_vbox())
self.main_hbox.pack_start(statsFrame) self.main_hbox.pack_start(self.stats_frame)
def get_vbox(self): def get_vbox(self):
@ -107,9 +137,12 @@ class GuiPositionalStats (threading.Thread):
print "DEBUG: activesite set to %s" %(self.activesite) print "DEBUG: activesite set to %s" %(self.activesite)
def refreshStats(self, widget, data): def refreshStats(self, widget, data):
try: self.stats_table.destroy() try: self.stats_vbox.destroy()
except AttributeError: pass except AttributeError: pass
self.fillStatsFrame(self.stats_frame) self.stats_vbox = gtk.VBox(False, 0)
self.stats_vbox.show()
self.stats_frame.add(self.stats_vbox)
self.fillStatsFrame(self.stats_vbox)
def fillStatsFrame(self, vbox): def fillStatsFrame(self, vbox):
sites = self.filters.getSites() sites = self.filters.getSites()
@ -144,66 +177,104 @@ class GuiPositionalStats (threading.Thread):
self.createStatsTable(vbox, playerids, sitenos, limits, seats, dates) self.createStatsTable(vbox, playerids, sitenos, limits, seats, dates)
def createStatsTable(self, vbox, playerids, sitenos, limits, seats, dates): def createStatsTable(self, vbox, playerids, sitenos, limits, seats, dates):
self.stats_table = gtk.Table(1, 1, False) # gtk table expands as required
self.stats_table.set_col_spacings(4)
self.stats_table.show()
vbox.add(self.stats_table)
starttime = time()
colalias,colshow,colheading,colxalign,colformat = 0,1,2,3,4
row = 0 row = 0
col = 0 col = 0
for t in self.posnheads:
l = gtk.Label(self.posnheads[col])
l.show()
self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK)
col +=1
tmp = self.sql.query['playerStatsByPosition'] tmp = self.sql.query['playerStatsByPosition']
tmp = self.refineQuery(tmp, playerids, sitenos, limits, seats, dates) tmp = self.refineQuery(tmp, playerids, sitenos, limits, seats, dates)
self.cursor.execute(tmp) self.cursor.execute(tmp)
result = self.cursor.fetchall() result = self.cursor.fetchall()
colnames = [desc[0].lower() for desc in self.cursor.description]
liststore = gtk.ListStore(*([str] * len(colnames)))
view = gtk.TreeView(model=liststore)
view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
vbox.pack_start(view, expand=False, padding=3)
# left-aligned cells:
textcell = gtk.CellRendererText()
# centred cells:
textcell50 = gtk.CellRendererText()
textcell50.set_property('xalign', 0.5)
# right-aligned cells:
numcell = gtk.CellRendererText()
numcell.set_property('xalign', 1.0)
listcols = []
for t in self.posnheads:
listcols.append(gtk.TreeViewColumn(self.posnheads[col]))
view.append_column(listcols[col])
if col == 0:
listcols[col].pack_start(textcell, expand=True)
listcols[col].add_attribute(textcell, 'text', col)
listcols[col].set_expand(True)
elif col in (1, 2):
listcols[col].pack_start(textcell50, expand=True)
listcols[col].add_attribute(textcell50, 'text', col)
listcols[col].set_expand(True)
else:
listcols[col].pack_start(numcell, expand=True)
listcols[col].add_attribute(numcell, 'text', col)
listcols[col].set_expand(True)
col +=1
# Code below to be used when full column data structures implemented like in player stats:
# Create header row eg column: ("game", True, "Game", 0.0, "%s")
#for col, column in enumerate(cols_to_show):
# if column[colalias] == 'game' and holecards:
# s = [x for x in self.columns if x[colalias] == 'hand'][0][colheading]
# else:
# s = column[colheading]
# listcols.append(gtk.TreeViewColumn(s))
# view.append_column(listcols[col])
# if column[colformat] == '%s':
# if column[colxalign] == 0.0:
# listcols[col].pack_start(textcell, expand=True)
# listcols[col].add_attribute(textcell, 'text', col)
# else:
# listcols[col].pack_start(textcell50, expand=True)
# listcols[col].add_attribute(textcell50, 'text', col)
# listcols[col].set_expand(True)
# else:
# listcols[col].pack_start(numcell, expand=True)
# listcols[col].add_attribute(numcell, 'text', col)
# listcols[col].set_expand(True)
# #listcols[col].set_alignment(column[colxalign]) # no effect?
rows = len(result) rows = len(result)
colnames = [desc[0].lower() for desc in self.cursor.description]
last_game,last_seats,sqlrow = "","",0 last_game,last_seats,sqlrow = "","",0
while sqlrow < rows: while sqlrow < rows:
if(row%2 == 0):
bgcolor = "white"
else:
bgcolor = "lightgrey"
rowprinted=0 rowprinted=0
treerow = []
avgcol = colnames.index('avgseats') avgcol = colnames.index('avgseats')
for col,colname in enumerate(self.posncols): for col,colname in enumerate(self.posncols):
if colname in colnames: if colname in colnames:
sqlcol = colnames.index(colname) sqlcol = colnames.index(colname)
else: else:
continue continue
eb = gtk.EventBox()
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
# print blank row between levels:
if result[sqlrow][sqlcol]: if result[sqlrow][sqlcol]:
if sqlrow == 0: if sqlrow == 0:
l = gtk.Label(result[sqlrow][sqlcol]) value = result[sqlrow][sqlcol]
rowprinted=1 rowprinted=1
elif result[sqlrow][0] != last_game: elif result[sqlrow][0] != last_game:
l = gtk.Label(' ') value = ' '
elif 'show' in seats and seats['show'] and result[sqlrow][avgcol] != last_seats: elif 'show' in seats and seats['show'] and result[sqlrow][avgcol] != last_seats:
l = gtk.Label(' ') value = ' '
else: else:
l = gtk.Label(result[sqlrow][sqlcol]) value = result[sqlrow][sqlcol]
rowprinted=1 rowprinted=1
else: else:
l = gtk.Label(' ') l = gtk.Label(' ')
if col == 0: value = ' '
l.set_alignment(xalign=0.0, yalign=0.5) if value and value != -999:
elif col == 1: treerow.append(value)
l.set_alignment(xalign=0.5, yalign=0.5)
else: else:
l.set_alignment(xalign=1.0, yalign=0.5) treerow.append(' ')
eb.add(l) iter = liststore.append(treerow)
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
l.show()
eb.show()
last_game = result[sqlrow][0] last_game = result[sqlrow][0]
last_seats = result[sqlrow][avgcol] last_seats = result[sqlrow][avgcol]
if rowprinted: if rowprinted:
@ -220,50 +291,36 @@ class GuiPositionalStats (threading.Thread):
# blank row between main stats and totals: # blank row between main stats and totals:
col = 0 col = 0
if(row%2 == 0): treerow = [' ' for x in self.posncols]
bgcolor = "white" iter = liststore.append(treerow)
else:
bgcolor = "lightgrey"
eb = gtk.EventBox()
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
l = gtk.Label(' ')
eb.add(l)
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
l.show()
eb.show()
row = row + 1 row = row + 1
for sqlrow in range(rows): for sqlrow in range(rows):
if(row%2 == 0): treerow = []
bgcolor = "white"
else:
bgcolor = "lightgrey"
for col,colname in enumerate(self.posncols): for col,colname in enumerate(self.posncols):
if colname in colnames: if colname in colnames:
sqlcol = colnames.index(colname) sqlcol = colnames.index(colname)
elif colname != "plposition": elif colname != "plposition":
continue continue
eb = gtk.EventBox()
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
if colname == 'plposition': if colname == 'plposition':
l = gtk.Label('Totals') l = gtk.Label('Totals')
value = 'Totals'
elif result[sqlrow][sqlcol]: elif result[sqlrow][sqlcol]:
l = gtk.Label(result[sqlrow][sqlcol]) l = gtk.Label(result[sqlrow][sqlcol])
value = result[sqlrow][sqlcol]
else: else:
l = gtk.Label(' ') l = gtk.Label(' ')
if col == 0: value = ' '
l.set_alignment(xalign=0.0, yalign=0.5) if value and value != -999:
elif col == 1: treerow.append(value)
l.set_alignment(xalign=0.5, yalign=0.5)
else: else:
l.set_alignment(xalign=1.0, yalign=0.5) treerow.append(' ')
eb.add(l) iter = liststore.append(treerow)
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
l.show()
eb.show()
row = row + 1 row = row + 1
vbox.show_all()
self.db.db.rollback() self.db.db.rollback()
print "Positional Stats page displayed in %4.2f seconds" % (time() - starttime)
#end def fillStatsFrame(self, vbox): #end def fillStatsFrame(self, vbox):
def refineQuery(self, query, playerids, sitenos, limits, seats, dates): def refineQuery(self, query, playerids, sitenos, limits, seats, dates):

View File

@ -15,6 +15,8 @@
#In the "official" distribution you can find the license in #In the "official" distribution you can find the license in
#agpl-3.0.txt in the docs folder of the package. #agpl-3.0.txt in the docs folder of the package.
# TODO: get writehand() encoding correct
import re import re
import sys import sys
import traceback import traceback
@ -26,12 +28,20 @@ import operator
import time,datetime import time,datetime
from copy import deepcopy from copy import deepcopy
from Exceptions import * from Exceptions import *
import pprint
import DerivedStats import DerivedStats
import Card import Card
class Hand: class Hand:
###############################################################3
# Class Variables
UPS = {'a':'A', 't':'T', 'j':'J', 'q':'Q', 'k':'K', 'S':'s', 'C':'c', 'H':'h', 'D':'d'} UPS = {'a':'A', 't':'T', 'j':'J', 'q':'Q', 'k':'K', 'S':'s', 'C':'c', 'H':'h', 'D':'d'}
LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'} LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'}
SYMBOL = {'USD': '$', 'EUR': u'E', 'T$': '', 'play': ''}
MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose' : 'HOSE'}
def __init__(self, sitename, gametype, handText, builtFrom = "HHC"): def __init__(self, sitename, gametype, handText, builtFrom = "HHC"):
self.sitename = sitename self.sitename = sitename
self.stats = DerivedStats.DerivedStats(self) self.stats = DerivedStats.DerivedStats(self)
@ -44,6 +54,10 @@ class Hand:
self.maxseats = 10 self.maxseats = 10
self.counted_seats = 0 self.counted_seats = 0
self.buttonpos = 0 self.buttonpos = 0
self.tourNo = None
self.buyin = None
self.level = None
self.mixed = None
self.seating = [] self.seating = []
self.players = [] self.players = []
self.posted = [] self.posted = []
@ -55,17 +69,19 @@ class Hand:
self.actions = {} # [['mct','bets','$10'],['mika','folds'],['carlg','raises','$20']] self.actions = {} # [['mct','bets','$10'],['mika','folds'],['carlg','raises','$20']]
self.board = {} # dict from street names to community cards self.board = {} # dict from street names to community cards
self.holecards = {} self.holecards = {}
self.discards = {}
for street in self.allStreets: for street in self.allStreets:
self.streets[street] = "" # portions of the handText, filled by markStreets() self.streets[street] = "" # portions of the handText, filled by markStreets()
self.actions[street] = []
for street in self.actionStreets:
self.bets[street] = {} self.bets[street] = {}
self.lastBet[street] = 0 self.lastBet[street] = 0
self.actions[street] = []
self.board[street] = [] self.board[street] = []
for street in self.holeStreets:
self.holecards[street] = {} # dict from player names to holecards self.holecards[street] = {} # dict from player names to holecards
self.discards[street] = {} # dict from player names to dicts by street ... of tuples ... of discarded holecards
# Collections indexed by player names # Collections indexed by player names
# self.holecards = {} # dict from player names to dicts by street ... of tuples ... of holecards # self.holecards = {} # dict from player names to dicts by street ... of tuples ... of holecards
self.discards = {} # dict from player names to dicts by street ... of tuples ... of discarded holecards
self.stacks = {} self.stacks = {}
self.collected = [] #list of ? self.collected = [] #list of ?
self.collectees = {} # dict from player names to amounts collected (?) self.collectees = {} # dict from player names to amounts collected (?)
@ -74,6 +90,7 @@ class Hand:
self.folded = set() self.folded = set()
self.dealt = set() # 'dealt to' line to be printed self.dealt = set() # 'dealt to' line to be printed
self.shown = set() # cards were shown self.shown = set() # cards were shown
self.mucked = set() # cards were mucked at showdown
# self.action = [] # self.action = []
# Things to do with money # Things to do with money
@ -83,10 +100,77 @@ class Hand:
self.rake = None self.rake = None
def __str__(self): def __str__(self):
vars = ( ("BB", self.bb),
("SB", self.sb),
("BUTTONPOS", self.buttonpos),
("HAND NO.", self.handid),
("SITE", self.sitename),
("TABLE NAME", self.tablename),
("HERO", self.hero),
("MAXSEATS", self.maxseats),
("TOURNAMENT NO", self.tourNo),
("BUYIN", self.buyin),
("LEVEL", self.level),
("MIXED", self.mixed),
("LASTBET", self.lastBet),
("ACTION STREETS", self.actionStreets),
("STREETS", self.streets),
("ALL STREETS", self.allStreets),
("COMMUNITY STREETS", self.communityStreets),
("HOLE STREETS", self.holeStreets),
("COUNTED SEATS", self.counted_seats),
("DEALT", self.dealt),
("SHOWN", self.shown),
("MUCKED", self.mucked),
("TOTAL POT", self.totalpot),
("TOTAL COLLECTED", self.totalcollected),
("RAKE", self.rake),
("START TIME", self.starttime),
)
structs = ( ("PLAYERS", self.players),
("STACKS", self.stacks),
("POSTED", self.posted),
("POT", self.pot),
("SEATING", self.seating),
("GAMETYPE", self.gametype),
("ACTION", self.actions),
("COLLECTEES", self.collectees),
("BETS", self.bets),
("BOARD", self.board),
("DISCARDS", self.discards),
("HOLECARDS", self.holecards),
)
str = '' str = ''
str = str + "Hand Object for %s at %s" % (self.handid, self.sitename) for (name, var) in vars:
str = str + "\n%s = " % name + pprint.pformat(var)
for (name, struct) in structs:
str = str + "\n%s =\n" % name + pprint.pformat(struct, 4)
return str return str
def addHoleCards(self, street, player, open=[], closed=[], shown=False, mucked=False, dealt=False):
"""\
Assigns observed holecards to a player.
cards list of card bigrams e.g. ['2h','Jc']
player (string) name of player
shown whether they were revealed at showdown
mucked whether they were mucked at showdown
dealt whether they were seen in a 'dealt to' line
"""
# logging.debug("addHoleCards %s %s" % (open + closed, player))
try:
self.checkPlayerExists(player)
except FpdbParseError, e:
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
return
if dealt: self.dealt.add(player)
if shown: self.shown.add(player)
if mucked: self.mucked.add(player)
self.holecards[street][player] = [open, closed]
def insert(self, db): def insert(self, db):
""" Function to insert Hand into database """ Function to insert Hand into database
Should not commit, and do minimal selects. Callers may want to cache commits Should not commit, and do minimal selects. Callers may want to cache commits
@ -178,10 +262,10 @@ If a player has None chips he won't be added."""
self.players.append([seat, name, chips]) self.players.append([seat, name, chips])
self.stacks[name] = Decimal(chips) self.stacks[name] = Decimal(chips)
self.pot.addPlayer(name) self.pot.addPlayer(name)
for street in self.allStreets: for street in self.actionStreets:
self.bets[street][name] = [] self.bets[street][name] = []
#self.holecards[name] = {} # dict from street names. #self.holecards[name] = {} # dict from street names.
self.discards[name] = {} # dict from street names. #self.discards[name] = {} # dict from street names.
def addStreets(self, match): def addStreets(self, match):
@ -202,7 +286,7 @@ If a player has None chips he won't be added."""
def setCommunityCards(self, street, cards): def setCommunityCards(self, street, cards):
logging.debug("setCommunityCards %s %s" %(street, cards)) logging.debug("setCommunityCards %s %s" %(street, cards))
self.board[street] = [self.card(c) for c in cards] self.board[street] = [self.card(c) for c in cards]
print "DEBUG: self.board: %s" % self.board # print "DEBUG: self.board: %s" % self.board
def card(self,c): def card(self,c):
"""upper case the ranks but not suits, 'atjqk' => 'ATJQK'""" """upper case the ranks but not suits, 'atjqk' => 'ATJQK'"""
@ -367,6 +451,20 @@ Add a raise on [street] by [player] to [amountTo]
self.collectees[player] += Decimal(pot) self.collectees[player] += Decimal(pot)
def addShownCards(self, cards, player, holeandboard=None, shown=True, mucked=False):
"""\
For when a player shows cards for any reason (for showdown or out of choice).
Card ranks will be uppercased
"""
logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard))
if cards is not None:
self.addHoleCards(cards,player,shown, mucked)
elif holeandboard is not None:
holeandboard = set([self.card(c) for c in holeandboard])
board = set([c for s in self.board.values() for c in s])
self.addHoleCards(holeandboard.difference(board),player,shown, mucked)
def totalPot(self): def totalPot(self):
"""If all bets and blinds have been added, totals up the total pot size""" """If all bets and blinds have been added, totals up the total pot size"""
@ -390,7 +488,7 @@ Add a raise on [street] by [player] to [amountTo]
Map the tuple self.gametype onto the pokerstars string describing it Map the tuple self.gametype onto the pokerstars string describing it
""" """
# currently it appears to be something like ["ring", "hold", "nl", sb, bb]: # currently it appears to be something like ["ring", "hold", "nl", sb, bb]:
gs = {"holdem" : "Hold'em", gs = {"holdem" : "Hold'em",
"omahahi" : "Omaha", "omahahi" : "Omaha",
"omahahilo" : "Omaha Hi/Lo", "omahahilo" : "Omaha Hi/Lo",
"razz" : "Razz", "razz" : "Razz",
@ -410,7 +508,6 @@ Map the tuple self.gametype onto the pokerstars string describing it
logging.debug("gametype: %s" %(self.gametype)) logging.debug("gametype: %s" %(self.gametype))
retstring = "%s %s" %(gs[self.gametype['category']], ls[self.gametype['limitType']]) retstring = "%s %s" %(gs[self.gametype['category']], ls[self.gametype['limitType']])
return retstring return retstring
@ -447,6 +544,33 @@ Map the tuple self.gametype onto the pokerstars string describing it
elif act[1] == 'stands pat': elif act[1] == 'stands pat':
return ("%s: stands pat" %(act[0])) return ("%s: stands pat" %(act[0]))
def getStakesAsString(self):
retstring = "%s%s/%s%s" % (self.SYMBOL[self.gametype['currency']], self.sb, self.SYMBOL[self.gametype['currency']], self.bb)
return retstring
def writeGameLine(self):
# print >>fh, ("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET')))
game_string = "PokerStars Game #%s: " % self.handid
if self.tourNo != None:
game_string = game_string + "Tournament #%s, %s %s - Level %s (%s) - " % (self.tourNo,
self.buyin, self.getGameTypeAsString(), self.level, self.getStakesAsString())
elif self.mixed != None:
game_string = game_string + " %s (%s, %s) - " % (self.MS[self.mixed],
self.getGameTypeAsString(), self.getStakesAsString())
else:
game_string = game_string + " %s (%s) - " % (self.getGameTypeAsString(), self.getStakesAsString())
game_string = game_string + datetime.datetime.strftime(self.starttime,'%Y/%m/%d %H:%M:%S ET')
return game_string
def writeTableLine(self):
table_string = "Table \'%s\' %s-max" % (self.tablename, self.maxseats)
if self.gametype['currency'] == 'play':
table_string = table_string + " (Play Money)"
if self.buttonpos != None:
table_string = table_string + " Seat #%s is the button" % self.buttonpos
return table_string
class HoldemOmahaHand(Hand): class HoldemOmahaHand(Hand):
def __init__(self, hhc, sitename, gametype, handText, builtFrom = "HHC", handid=None): def __init__(self, hhc, sitename, gametype, handText, builtFrom = "HHC", handid=None):
@ -494,45 +618,12 @@ class HoldemOmahaHand(Hand):
pass pass
def addHoleCards(self, cards, player, shown=False, dealt=False): def addShownCards(self, cards, player, shown=True, mucked=False, dealt=False):
"""\ if player == self.hero: # we have hero's cards just update shown/mucked
Assigns observed holecards to a player. if shown: self.shown.add(player)
cards list of card bigrams e.g. ['2h','Jc'] if mucked: self.mucked.add(player)
player (string) name of player
shown whether they were revealed at showdown
dealt whether they were seen in a 'dealt to' line
"""
logging.debug("addHoleCards %s %s" % (cards, player))
try:
self.checkPlayerExists(player)
except FpdbParseError, e:
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
return
cardset = set((self.card(c) for c in cards))
if len(cardset) == 0:
return
if dealt:
self.dealt.add(player)
if shown:
self.shown.add(player)
if player in self.holecards['PREFLOP']:
self.holecards['PREFLOP'][player].update(cardset)
else: else:
self.holecards['PREFLOP'][player] = cardset self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt)
def addShownCards(self, cards, player, holeandboard=None):
"""\
For when a player shows cards for any reason (for showdown or out of choice).
Card ranks will be uppercased
"""
logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard))
if cards is not None:
self.addHoleCards(cards,player,shown=True)
elif holeandboard is not None:
holeandboard = set([self.card(c) for c in holeandboard])
board = set([c for s in self.board.values() for c in s])
self.addHoleCards(holeandboard.difference(board),player,shown=True)
def writeHTMLHand(self, fh=sys.__stdout__): def writeHTMLHand(self, fh=sys.__stdout__):
@ -632,8 +723,11 @@ Card ranks will be uppercased
def writeHand(self, fh=sys.__stdout__): def writeHand(self, fh=sys.__stdout__):
# PokerStars format. # PokerStars format.
print >>fh, ("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET'))) # print >>fh, ("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET')))
print >>fh, ("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos)) print >>fh, self.writeGameLine()
print >>fh, self.writeTableLine()
# print >>fh, ("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos))
players_who_act_preflop = set(([x[0] for x in self.actions['PREFLOP']]+[x[0] for x in self.actions['BLINDSANTES']])) players_who_act_preflop = set(([x[0] for x in self.actions['PREFLOP']]+[x[0] for x in self.actions['BLINDSANTES']]))
logging.debug(self.actions['PREFLOP']) logging.debug(self.actions['PREFLOP'])
@ -647,10 +741,10 @@ Card ranks will be uppercased
print >>fh, ("*** HOLE CARDS ***") print >>fh, ("*** HOLE CARDS ***")
for player in self.dealt: for player in self.dealt:
print >>fh, ("Dealt to %s [%s]" %(player, " ".join(self.holecards['PREFLOP'][player]))) print >>fh, ("Dealt to %s [%s]" %(player, " ".join(self.holecards['PREFLOP'][player][1])))
if self.hero == "": if self.hero == "":
for player in self.shown.difference(self.dealt): for player in self.shown.difference(self.dealt):
print >>fh, ("Dealt to %s [%s]" %(player, " ".join(self.holecards['PREFLOP'][player]))) print >>fh, ("Dealt to %s [%s]" %(player, " ".join(self.holecards['PREFLOP'][player][1])))
if self.actions['PREFLOP']: if self.actions['PREFLOP']:
for act in self.actions['PREFLOP']: for act in self.actions['PREFLOP']:
@ -689,7 +783,7 @@ Card ranks will be uppercased
elif self.gametype['category'] in ('holdem'): elif self.gametype['category'] in ('holdem'):
numOfHoleCardsNeeded = 2 numOfHoleCardsNeeded = 2
if len(self.holecards['PREFLOP'][name]) == numOfHoleCardsNeeded: if len(self.holecards['PREFLOP'][name]) == numOfHoleCardsNeeded:
print >>fh, ("%s shows [%s] (a hand...)" % (name, " ".join(self.holecards['PREFLOP'][name]))) print >>fh, ("%s shows [%s] (a hand...)" % (name, " ".join(self.holecards['PREFLOP'][name][1])))
# Current PS format has the lines: # Current PS format has the lines:
# Uncalled bet ($111.25) returned to s0rrow # Uncalled bet ($111.25) returned to s0rrow
@ -716,7 +810,7 @@ Card ranks will be uppercased
seatnum = player[0] seatnum = player[0]
name = player[1] name = player[1]
if name in self.collectees and name in self.shown: if name in self.collectees and name in self.shown:
print >>fh, ("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards['PREFLOP'][name]), self.collectees[name])) print >>fh, ("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards['PREFLOP'][name][1]), self.collectees[name]))
elif name in self.collectees: elif name in self.collectees:
print >>fh, ("Seat %d: %s collected ($%s)" % (seatnum, name, self.collectees[name])) print >>fh, ("Seat %d: %s collected ($%s)" % (seatnum, name, self.collectees[name]))
#~ elif name in self.shown: #~ elif name in self.shown:
@ -725,7 +819,9 @@ Card ranks will be uppercased
print >>fh, ("Seat %d: %s folded" % (seatnum, name)) print >>fh, ("Seat %d: %s folded" % (seatnum, name))
else: else:
if name in self.shown: if name in self.shown:
print >>fh, ("Seat %d: %s showed [%s] and lost with..." % (seatnum, name, " ".join(self.holecards['PREFLOP'][name]))) print >>fh, ("Seat %d: %s showed [%s] and lost with..." % (seatnum, name, " ".join(self.holecards['PREFLOP'][name][1])))
elif name in self.mucked:
print >>fh, ("Seat %d: %s mucked [%s] " % (seatnum, name, " ".join(self.holecards['PREFLOP'][name][1])))
else: else:
print >>fh, ("Seat %d: %s mucked" % (seatnum, name)) print >>fh, ("Seat %d: %s mucked" % (seatnum, name))
@ -736,8 +832,10 @@ class DrawHand(Hand):
if gametype['base'] != 'draw': if gametype['base'] != 'draw':
pass # or indeed don't pass and complain instead pass # or indeed don't pass and complain instead
self.streetList = ['BLINDSANTES', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE'] self.streetList = ['BLINDSANTES', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE']
self.allStreets = ['BLINDSANTES', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE']
self.holeStreets = ['DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE'] self.holeStreets = ['DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE']
self.actionStreets = ['PREDEAL', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE'] self.actionStreets = ['PREDEAL', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE']
self.communityStreets = []
Hand.__init__(self, sitename, gametype, handText) Hand.__init__(self, sitename, gametype, handText)
self.sb = gametype['sb'] self.sb = gametype['sb']
self.bb = gametype['bb'] self.bb = gametype['bb']
@ -749,12 +847,13 @@ class DrawHand(Hand):
hhc.markStreets(self) hhc.markStreets(self)
hhc.readBlinds(self) hhc.readBlinds(self)
hhc.readButton(self) hhc.readButton(self)
hhc.readHeroCards(self)
hhc.readShowdownActions(self) hhc.readShowdownActions(self)
# Read actions in street order # Read actions in street order
for street in self.streetList: for street in self.streetList:
if self.streets[street]: if self.streets[street]:
# hhc.readCommunityCards(self, street) # hhc.readCommunityCards(self, street)
hhc.readDrawCards(self, street) # hhc.readDrawCards(self, street)
hhc.readAction(self, street) hhc.readAction(self, street)
hhc.readCollectPot(self) hhc.readCollectPot(self)
hhc.readShownCards(self) hhc.readShownCards(self)
@ -790,25 +889,33 @@ class DrawHand(Hand):
#print "DEBUG: self.posted: %s" %(self.posted) #print "DEBUG: self.posted: %s" %(self.posted)
def addShownCards(self, cards, player, shown=True, mucked=False, dealt=False):
if player == self.hero: # we have hero's cards just update shown/mucked
if shown: self.shown.add(player)
if mucked: self.mucked.add(player)
else:
# TODO: Probably better to find the last street with action and add the hole cards to that street
self.addHoleCards('DRAWTHREE', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt)
def addDrawHoleCards(self, newcards, oldcards, player, street, shown=False):
"""\ # def addDrawHoleCards(self, newcards, oldcards, player, street, shown=False):
Assigns observed holecards to a player. # """\
cards list of card bigrams e.g. ['2h','Jc'] #Assigns observed holecards to a player.
player (string) name of player #cards list of card bigrams e.g. ['2h','Jc']
""" #player (string) name of player
try: #"""
self.checkPlayerExists(player) # try:
# if shown and len(cardset) > 0: # self.checkPlayerExists(player)
# self.shown.add(player) ## if shown and len(cardset) > 0:
self.holecards[player][street] = (newcards,oldcards) ## self.shown.add(player)
except FpdbParseError, e: # self.holecards[street][player] = (newcards,oldcards)
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,) # except FpdbParseError, e:
# print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
def discardDrawHoleCards(self, cards, player, street): def discardDrawHoleCards(self, cards, player, street):
logging.debug("discardDrawHoleCards '%s' '%s' '%s'" % (cards, player, street)) logging.debug("discardDrawHoleCards '%s' '%s' '%s'" % (cards, player, street))
self.discards[player][street] = set([cards]) self.discards[street][player] = set([cards])
def addDiscard(self, street, player, num, cards): def addDiscard(self, street, player, num, cards):
@ -821,12 +928,12 @@ player (string) name of player
self.actions[street].append(act) self.actions[street].append(act)
def addShownCards(self, cards, player, holeandboard=None): # def addShownCards(self, cards, player, holeandboard=None, shown=False, mucked=False):
"""\ # """\
For when a player shows cards for any reason (for showdown or out of choice). #For when a player shows cards for any reason (for showdown or out of choice).
Card ranks will be uppercased #Card ranks will be uppercased
""" #"""
logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard)) # logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard))
# if cards is not None: # if cards is not None:
# self.shown.add(player) # self.shown.add(player)
# self.addHoleCards(cards,player) # self.addHoleCards(cards,player)
@ -836,10 +943,39 @@ Card ranks will be uppercased
# self.addHoleCards(holeandboard.difference(board),player,shown=True) # self.addHoleCards(holeandboard.difference(board),player,shown=True)
# def addHoleCards(self, cards, player, shown, mucked, dealt=False):
# """\
#Assigns observed holecards to a player.
#cards list of card bigrams e.g. ['2h','Jc']
#player (string) name of player
#shown whether they were revealed at showdown
#mucked whether they were mucked at showdown
#dealt whether they were seen in a 'dealt to' line
#"""
## I think this only gets called for shown cards.
# logging.debug("addHoleCards %s %s" % (cards, player))
# try:
# self.checkPlayerExists(player)
# except FpdbParseError, e:
# print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
# return
#
# if dealt:
# self.dealt.add(player)
# if shown:
# self.shown.add(player)
# if mucked:
# self.mucked.add(player)
# if player != self.hero: #skip hero, we know his cards
# print "player, cards =", player, cards
# self.holecards[self.holeStreets[-1]][player] = (cards, set([]))
def writeHand(self, fh=sys.__stdout__): def writeHand(self, fh=sys.__stdout__):
# PokerStars format. # PokerStars format.
print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d %H:%M:%S ET', self.starttime))) # print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d %H:%M:%S ET', self.starttime)))
print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos)) print >>fh, self.writeGameLine()
# print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos))
print >>fh, self.writeTableLine()
players_who_act_ondeal = set(([x[0] for x in self.actions['DEAL']]+[x[0] for x in self.actions['BLINDSANTES']])) players_who_act_ondeal = set(([x[0] for x in self.actions['DEAL']]+[x[0] for x in self.actions['BLINDSANTES']]))
@ -865,8 +1001,8 @@ Card ranks will be uppercased
for act in self.actions['DRAWONE']: for act in self.actions['DRAWONE']:
print >>fh, self.actionString(act) print >>fh, self.actionString(act)
if act[0] == self.hero and act[1] == 'discards': if act[0] == self.hero and act[1] == 'discards':
(nc,oc) = self.holecards[act[0]]['DRAWONE'] (nc,oc) = self.holecards['DRAWONE'][act[0]]
dc = self.discards[act[0]]['DRAWONE'] dc = self.discards['DRAWONE'][act[0]]
kc = oc - dc kc = oc - dc
print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc))) print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc)))
@ -875,8 +1011,8 @@ Card ranks will be uppercased
for act in self.actions['DRAWTWO']: for act in self.actions['DRAWTWO']:
print >>fh, self.actionString(act) print >>fh, self.actionString(act)
if act[0] == self.hero and act[1] == 'discards': if act[0] == self.hero and act[1] == 'discards':
(nc,oc) = self.holecards[act[0]]['DRAWTWO'] (nc,oc) = self.holecards['DRAWTWO'][act[0]]
dc = self.discards[act[0]]['DRAWTWO'] dc = self.discards['DRAWTWO'][act[0]]
kc = oc - dc kc = oc - dc
print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc))) print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc)))
@ -885,8 +1021,8 @@ Card ranks will be uppercased
for act in self.actions['DRAWTHREE']: for act in self.actions['DRAWTHREE']:
print >>fh, self.actionString(act) print >>fh, self.actionString(act)
if act[0] == self.hero and act[1] == 'discards': if act[0] == self.hero and act[1] == 'discards':
(nc,oc) = self.holecards[act[0]]['DRAWTHREE'] (nc,oc) = self.holecards['DRAWTHREE'][act[0]]
dc = self.discards[act[0]]['DRAWTHREE'] dc = self.discards['DRAWTHREE'][act[0]]
kc = oc - dc kc = oc - dc
print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc))) print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc)))
@ -916,6 +1052,11 @@ class StudHand(Hand):
def __init__(self, hhc, sitename, gametype, handText, builtFrom = "HHC"): def __init__(self, hhc, sitename, gametype, handText, builtFrom = "HHC"):
if gametype['base'] != 'stud': if gametype['base'] != 'stud':
pass # or indeed don't pass and complain instead pass # or indeed don't pass and complain instead
self.allStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH']
self.communityStreets = []
self.actionStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH']
self.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order self.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order
self.holeStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] self.holeStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH']
Hand.__init__(self, sitename, gametype, handText) Hand.__init__(self, sitename, gametype, handText)
@ -931,21 +1072,35 @@ class StudHand(Hand):
hhc.markStreets(self) hhc.markStreets(self)
hhc.readAntes(self) hhc.readAntes(self)
hhc.readBringIn(self) hhc.readBringIn(self)
hhc.readHeroCards(self)
#hhc.readShowdownActions(self) # not done yet #hhc.readShowdownActions(self) # not done yet
# Read actions in street order # Read actions in street order
for street in self.streetList: for street in self.streetList:
if self.streets[street]: if self.streets[street]:
logging.debug(street) logging.debug(street)
logging.debug(self.streets[street]) logging.debug(self.streets[street])
hhc.readStudPlayerCards(self, street) # hhc.readStudPlayerCards(self, street)
hhc.readAction(self, street) hhc.readAction(self, street)
hhc.readCollectPot(self) hhc.readCollectPot(self)
#hhc.readShownCards(self) # not done yet hhc.readShownCards(self) # not done yet
self.totalPot() # finalise it (total the pot) self.totalPot() # finalise it (total the pot)
hhc.getRake(self) hhc.getRake(self)
elif builtFrom == "DB": elif builtFrom == "DB":
self.select("dummy") # Will need a handId self.select("dummy") # Will need a handId
def addShownCards(self, cards, player, shown=True, mucked=False, dealt=False):
if player == self.hero: # we have hero's cards just update shown/mucked
if shown: self.shown.add(player)
if mucked: self.mucked.add(player)
else:
# self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt)
self.addHoleCards('THIRD', player, open=[cards[2]], closed=cards[0:2], shown=shown, mucked=mucked)
self.addHoleCards('FOURTH', player, open=[cards[3]], closed=[], shown=shown, mucked=mucked)
self.addHoleCards('FIFTH', player, open=[cards[4]], closed=[], shown=shown, mucked=mucked)
self.addHoleCards('SIXTH', player, open=[cards[5]], closed=[], shown=shown, mucked=mucked)
self.addHoleCards('SEVENTH', player, open=[], closed=[cards[6]], shown=shown, mucked=mucked)
def addPlayerCards(self, player, street, open=[], closed=[]): def addPlayerCards(self, player, street, open=[], closed=[]):
"""\ """\
Assigns observed cards to a player. Assigns observed cards to a player.
@ -957,12 +1112,47 @@ closed likewise, but known only to player
logging.debug("addPlayerCards %s, o%s x%s" % (player, open, closed)) logging.debug("addPlayerCards %s, o%s x%s" % (player, open, closed))
try: try:
self.checkPlayerExists(player) self.checkPlayerExists(player)
self.holecards[player][street] = (open, closed) self.holecards[street][player] = (open, closed)
# cards = set([self.card(c) for c in cards]) # cards = set([self.card(c) for c in cards])
# self.holecards[player].update(cards) # self.holecards[player].update(cards)
except FpdbParseError, e: except FpdbParseError, e:
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,) print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
# def addHoleCards(self, cards, player, shown, mucked, dealt=False):
# """\
#Assigns observed holecards to a player.
#cards list of card bigrams e.g. ['2h','Jc']
#player (string) name of player
#shown whether they were revealed at showdown
#mucked whether they were mucked at showdown
#dealt whether they were seen in a 'dealt to' line
#"""
##
## For stud games we just need to do the routine setting of shown/mucked/etc
## and then update the cards 'THIRD' and 'SEVENTH'
# logging.debug("addHoleCards %s %s" % (cards, player))
# try:
# self.checkPlayerExists(player)
# except FpdbParseError, e:
# print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
# return
#
# if dealt:
# self.dealt.add(player)
# if shown:
# self.shown.add(player)
# if mucked:
# self.mucked.add(player)
# if player == self.hero:
# if len(cards) > 2:
# self.holecards['THIRD'][player] = ([cards[0:3]], [])
# if len(cards) > 6:
# self.holecards['SEVENTH'][player] = ([cards[6]], [])
# else:
# if len(cards) > 2:
# self.holecards['THIRD'][player] = ([cards[0]], cards[1:3])
# if len(cards) > 6:
# self.holecards['SEVENTH'][player] = ([], [cards[6]])
# TODO: def addComplete(self, player, amount): # TODO: def addComplete(self, player, amount):
def addComplete(self, street, player, amountTo): def addComplete(self, street, player, amountTo):
# assert street=='THIRD' # assert street=='THIRD'
@ -994,12 +1184,20 @@ Add a complete on [street] by [player] to [amountTo]
self.actions['THIRD'].append(act) self.actions['THIRD'].append(act)
self.lastBet['THIRD'] = Decimal(bringin) self.lastBet['THIRD'] = Decimal(bringin)
self.pot.addMoney(player, Decimal(bringin)) self.pot.addMoney(player, Decimal(bringin))
def writeHand(self, fh=sys.__stdout__): def writeHand(self, fh=sys.__stdout__):
# PokerStars format. # PokerStars format.
# print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d - %H:%M:%S (ET)', self.starttime))) # print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d - %H:%M:%S (ET)', self.starttime)))
print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET')))
print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos)) # TODO:
# Hole cards are not currently correctly written. Currently the down cards for non-heros
# are shown in the "dealt to" lines. They should be hidden in those lines. I tried to fix
# but mind got boggled, will try again.
# print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET')))
print >>fh, self.writeGameLine()
print >>fh, self.writeTableLine()
# print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos))
players_who_post_antes = set([x[0] for x in self.actions['ANTES']]) players_who_post_antes = set([x[0] for x in self.actions['ANTES']])
@ -1015,8 +1213,8 @@ Add a complete on [street] by [player] to [amountTo]
dealt = 0 dealt = 0
#~ print >>fh, _("*** 3RD STREET ***") #~ print >>fh, _("*** 3RD STREET ***")
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]: for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
if 'THIRD' in self.holecards[player]: if self.holecards['THIRD'].has_key(player):
(open, closed) = self.holecards[player]['THIRD'] (open, closed) = self.holecards['THIRD'][player]
dealt+=1 dealt+=1
if dealt==1: if dealt==1:
print >>fh, _("*** 3RD STREET ***") print >>fh, _("*** 3RD STREET ***")
@ -1029,12 +1227,12 @@ Add a complete on [street] by [player] to [amountTo]
dealt = 0 dealt = 0
#~ print >>fh, _("*** 4TH STREET ***") #~ print >>fh, _("*** 4TH STREET ***")
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]: for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
if 'FOURTH' in self.holecards[player]: if player in self.holecards['FOURTH']:
old = [] old = []
(o,c) = self.holecards[player]['THIRD'] (o,c) = self.holecards['THIRD'][player]
if o:old.extend(o) if o:old.extend(o)
if c:old.extend(c) if c:old.extend(c)
new = self.holecards[player]['FOURTH'][0] new = self.holecards['FOURTH'][player][0]
dealt+=1 dealt+=1
if dealt==1: if dealt==1:
print >>fh, _("*** 4TH STREET ***") print >>fh, _("*** 4TH STREET ***")
@ -1046,13 +1244,13 @@ Add a complete on [street] by [player] to [amountTo]
dealt = 0 dealt = 0
#~ print >>fh, _("*** 5TH STREET ***") #~ print >>fh, _("*** 5TH STREET ***")
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]: for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
if 'FIFTH' in self.holecards[player]: if self.holecards['FIFTH'].has_key(player):
old = [] old = []
for street in ('THIRD','FOURTH'): for street in ('THIRD','FOURTH'):
(o,c) = self.holecards[player][street] (o,c) = self.holecards[street][player]
if o:old.extend(o) if o:old.extend(o)
if c:old.extend(c) if c:old.extend(c)
new = self.holecards[player]['FIFTH'][0] new = self.holecards['FIFTH'][player][0]
dealt+=1 dealt+=1
if dealt==1: if dealt==1:
print >>fh, _("*** 5TH STREET ***") print >>fh, _("*** 5TH STREET ***")
@ -1064,13 +1262,13 @@ Add a complete on [street] by [player] to [amountTo]
dealt = 0 dealt = 0
#~ print >>fh, _("*** 6TH STREET ***") #~ print >>fh, _("*** 6TH STREET ***")
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]: for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
if 'SIXTH' in self.holecards[player]: if self.holecards['SIXTH'].has_key(player):
old = [] old = []
for street in ('THIRD','FOURTH','FIFTH'): for street in ('THIRD','FOURTH','FIFTH'):
(o,c) = self.holecards[player][street] (o,c) = self.holecards[street][player]
if o:old.extend(o) if o:old.extend(o)
if c:old.extend(c) if c:old.extend(c)
new = self.holecards[player]['SIXTH'][0] new = self.holecards['SIXTH'][player][0]
dealt += 1 dealt += 1
if dealt == 1: if dealt == 1:
print >>fh, _("*** 6TH STREET ***") print >>fh, _("*** 6TH STREET ***")
@ -1085,13 +1283,13 @@ Add a complete on [street] by [player] to [amountTo]
# i.e. are all but one players folded; is there an allin showdown; and all that. # i.e. are all but one players folded; is there an allin showdown; and all that.
print >>fh, _("*** 7TH STREET ***") print >>fh, _("*** 7TH STREET ***")
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]: for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
if 'SEVENTH' in self.holecards[player]: if self.holecards['SEVENTH'].has_key(player):
old = [] old = []
for street in ('THIRD','FOURTH','FIFTH','SIXTH'): for street in ('THIRD','FOURTH','FIFTH','SIXTH'):
(o,c) = self.holecards[player][street] (o,c) = self.holecards[street][player]
if o:old.extend(o) if o:old.extend(o)
if c:old.extend(c) if c:old.extend(c)
new = self.holecards[player]['SEVENTH'][0] new = self.holecards['SEVENTH'][player][0]
if new: if new:
print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(old) + "] " if old else " ", "[" + " ".join(new) + "]" if new else "") print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(old) + "] " if old else " ", "[" + " ".join(new) + "]" if new else "")
for act in self.actions['SEVENTH']: for act in self.actions['SEVENTH']:
@ -1130,11 +1328,13 @@ Add a complete on [street] by [player] to [amountTo]
seatnum = player[0] seatnum = player[0]
name = player[1] name = player[1]
if name in self.collectees and name in self.shown: if name in self.collectees and name in self.shown:
print >>fh, _("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards[name]), self.collectees[name])) print >>fh, _("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, self.join_holecards(name), self.collectees[name]))
elif name in self.collectees: elif name in self.collectees:
print >>fh, _("Seat %d: %s collected ($%s)" % (seatnum, name, self.collectees[name])) print >>fh, _("Seat %d: %s collected ($%s)" % (seatnum, name, self.collectees[name]))
elif name in self.shown: elif name in self.shown:
print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, " ".join(self.holecards[name]))) print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, self.join_holecards(name)))
elif name in self.mucked:
print >>fh, _("Seat %d: %s mucked [%s]" % (seatnum, name, self.join_holecards(name)))
elif name in self.folded: elif name in self.folded:
print >>fh, _("Seat %d: %s folded" % (seatnum, name)) print >>fh, _("Seat %d: %s folded" % (seatnum, name))
else: else:
@ -1143,6 +1343,12 @@ Add a complete on [street] by [player] to [amountTo]
print >>fh, "\n\n" print >>fh, "\n\n"
def join_holecards(self, player):
holecards = []
for street in self.holeStreets:
if self.holecards[street].has_key(player):
holecards = holecards + self.holecards[street][player][0]
return " ".join(holecards)
class Pot(object): class Pot(object):

View File

@ -197,6 +197,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
logging.info("Unsupported game type: %s" % gametype) logging.info("Unsupported game type: %s" % gametype)
if hand: if hand:
# print hand
hand.writeHand(self.out_fh) hand.writeHand(self.out_fh)
else: else:
logging.info("Unsupported game type: %s" % gametype) logging.info("Unsupported game type: %s" % gametype)

View File

@ -34,10 +34,13 @@ import gobject
# FreePokerTools modules # FreePokerTools modules
from Mucked import Aux_Window from Mucked import Aux_Window
from Mucked import Seat_Window
from Mucked import Aux_Seats
class Hello(Aux_Window): class Hello(Aux_Window):
"""A 'Hello World' Aux_Window demo.""" """A 'Hello World' Aux_Window demo."""
def create(self): def create(self):
print "creating Hello"
# This demo simply creates a label in a window. # This demo simply creates a label in a window.
self.container = gtk.Window() self.container = gtk.Window()
self.container.add(gtk.Label("Hello World")) self.container.add(gtk.Label("Hello World"))
@ -99,15 +102,18 @@ class Hello_plus(Aux_Window):
# hands played that was updated in the "update_data()" function. # hands played that was updated in the "update_data()" function.
self.label.set_text("Hello %s\nYou have played %d hands\n on %s." % (self.hero, self.hands_played, self.site)) self.label.set_text("Hello %s\nYou have played %d hands\n on %s." % (self.hero, self.hands_played, self.site))
class Hello_Menu(Aux_Window): class Hello_Seats(Aux_Seats):
"""A 'Hello World' Aux_Window demo.""" """A 'Hello World' Seat_Window demo."""
def create(self):
# This demo puts a menu item on the HUD mainwindow.
self.item = gtk.MenuItem('Print cards')
self.hud.menu.append(self.item)
self.item.connect("activate", self.print_cards)
self.item.show()
def print_cards(self, *args): def create_contents(self, container, i):
# callback for the menu item container.label = gtk.Label("empty")
print "cards =", self.hud.cards container.add(container.label)
container.show_all()
def update_contents(self, container, i):
if i == "common": return
id = self.get_id_from_seat(i)
if id == None:
container.label.set_text("empty")
else:
container.label.set_text("player = %s" % self.hud.stat_dict[id]['screen_name'])

View File

@ -339,30 +339,30 @@ class Hud:
Stats.do_tip(window.e_box[r][c], tip) Stats.do_tip(window.e_box[r][c], tip)
def topify_window(self, window): def topify_window(self, window):
"""Set the specified gtk window to stayontop in MS Windows.""" # """Set the specified gtk window to stayontop in MS Windows."""
#
def windowEnumerationHandler(hwnd, resultList): # def windowEnumerationHandler(hwnd, resultList):
'''Callback for win32gui.EnumWindows() to generate list of window handles.''' # '''Callback for win32gui.EnumWindows() to generate list of window handles.'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd))) # resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
# unique_name = 'unique name for finding this window'
unique_name = 'unique name for finding this window' # real_name = window.get_title()
real_name = window.get_title() # window.set_title(unique_name)
window.set_title(unique_name) # tl_windows = []
tl_windows = [] # win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
win32gui.EnumWindows(windowEnumerationHandler, tl_windows) #
# for w in tl_windows:
for w in tl_windows: # if w[1] == unique_name:
if w[1] == unique_name:
self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(long(self.table.number)) self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(long(self.table.number))
self.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0]) # self.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0])
self.main_window.gdkhandle = self.main_window.window
self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle) self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle)
style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE) style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE)
style |= win32con.WS_CLIPCHILDREN style |= win32con.WS_CLIPCHILDREN
win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style) win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style)
break # break
window.set_title(real_name) # window.set_title(real_name)
class Stat_Window: class Stat_Window:
@ -445,10 +445,10 @@ class Stat_Window:
Stats.do_tip(e_box[r][c], 'stuff') Stats.do_tip(e_box[r][c], 'stuff')
if usegtkframes: if usegtkframes:
grid.attach(self.frame[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0) grid.attach(self.frame[r][c], c, c+1, r, r+1, xpadding = game.xpad, ypadding = game.ypad)
self.frame[r][c].add(e_box[r][c]) self.frame[r][c].add(e_box[r][c])
else: else:
grid.attach(e_box[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0) grid.attach(e_box[r][c], c, c+1, r, r+1, xpadding = game.xpad, ypadding = game.ypad)
label[r].append( gtk.Label('xxx') ) label[r].append( gtk.Label('xxx') )
if usegtkframes: if usegtkframes:
@ -473,6 +473,7 @@ class Popup_window:
def __init__(self, parent, stat_window): def __init__(self, parent, stat_window):
self.sb_click = 0 self.sb_click = 0
self.stat_window = stat_window self.stat_window = stat_window
self.parent = parent
# create the popup window # create the popup window
self.window = gtk.Window() self.window = gtk.Window()
@ -532,11 +533,15 @@ class Popup_window:
# db_connection.close_connection() # db_connection.close_connection()
stat_dict = stat_window.parent.stat_dict stat_dict = stat_window.parent.stat_dict
pu_text = "" pu_text = ""
mo_text = ""
for s in stat_list: for s in stat_list:
number = Stats.do_stat(stat_dict, player = int(stat_window.player_id), stat = s) number = Stats.do_stat(stat_dict, player = int(stat_window.player_id), stat = s)
mo_text += number[5] + " " + number[4] + "\n"
pu_text += number[3] + "\n" pu_text += number[3] + "\n"
self.lab.set_text(pu_text) self.lab.set_text(pu_text)
Stats.do_tip(self.lab, mo_text)
self.window.show_all() self.window.show_all()
self.window.set_transient_for(stat_window.window) self.window.set_transient_for(stat_window.window)
@ -572,25 +577,25 @@ class Popup_window:
def topify_window(self, window): def topify_window(self, window):
"""Set the specified gtk window to stayontop in MS Windows.""" """Set the specified gtk window to stayontop in MS Windows."""
def windowEnumerationHandler(hwnd, resultList): # def windowEnumerationHandler(hwnd, resultList):
'''Callback for win32gui.EnumWindows() to generate list of window handles.''' # '''Callback for win32gui.EnumWindows() to generate list of window handles.'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd))) # resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
unique_name = 'unique name for finding this window' # unique_name = 'unique name for finding this window'
real_name = window.get_title() # real_name = window.get_title()
window.set_title(unique_name) # window.set_title(unique_name)
tl_windows = [] # tl_windows = []
win32gui.EnumWindows(windowEnumerationHandler, tl_windows) # win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
for w in tl_windows: # for w in tl_windows:
if w[1] == unique_name: # if w[1] == unique_name:
window.set_transient_for(self.parent.main_window) window.set_transient_for(self.parent.main_window)
style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE) style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE)
style |= win32con.WS_CLIPCHILDREN style |= win32con.WS_CLIPCHILDREN
win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style) win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style)
break # break
window.set_title(real_name) # window.set_title(real_name)
if __name__== "__main__": if __name__== "__main__":
main_window = gtk.Window() main_window = gtk.Window()

View File

@ -37,27 +37,18 @@ import Configuration
import Database import Database
import Card import Card
class Aux_Window: class Aux_Window(object):
def __init__(self, hud, params, config): def __init__(self, hud, params, config):
self.hud = hud self.hud = hud
self.params = params self.params = params
self.config = config self.config = config
def update_data(self, *args): # Override these methods as needed
pass def update_data(self, *args): pass
def update_gui(self, *args): pass
def update_gui(self, *args): def create(self, *args): pass
pass def relocate(self, *args): pass
def save_layout(self, *args): pass
def create(self, *args):
pass
def relocate(self, *args):
pass
def save_layout(self, *args):
pass
def destroy(self): def destroy(self):
try: try:
self.container.destroy() self.container.destroy()
@ -89,15 +80,20 @@ class Aux_Window:
pb.copy_area(30*j, 42*i, 30, 42, temp_pb, 0, 0) pb.copy_area(30*j, 42*i, 30, 42, temp_pb, 0, 0)
return temp_pb return temp_pb
def split_cards(self, card):
if card == 'xx': return ('B', 'S')
return (card[0], card[1].upper())
def has_cards(self, cards): def has_cards(self, cards):
"""Returns the number of cards in the list."""
n = 0
for c in cards: for c in cards:
if c in set('shdc'): return True if c != None and c > 0: n = n + 1
return False return n
def get_id_from_seat(self, seat):
"""Determine player id from seat number, given stat_dict."""
for id, dict in self.hud.stat_dict.iteritems():
if seat == dict['seat']:
return id
return None
class Stud_mucked(Aux_Window): class Stud_mucked(Aux_Window):
def __init__(self, hud, config, params): def __init__(self, hud, config, params):
@ -329,87 +325,152 @@ class Stud_cards:
self.seen_cards[(c, r)].set_from_pixbuf(self.card_images[0]) self.seen_cards[(c, r)].set_from_pixbuf(self.card_images[0])
self.eb[(c, r)].set_tooltip_text('') self.eb[(c, r)].set_tooltip_text('')
class Flop_Mucked(Aux_Window): class Seat_Window(gtk.Window):
"""Aux_Window class for displaying mucked cards for flop games.""" """Subclass gtk.Window for the seat windows."""
class Aux_Seats(Aux_Window):
"""A super class to display an aux_window at each seat."""
def __init__(self, hud, config, params): def __init__(self, hud, config, params):
self.hud = hud # hud object that this aux window supports self.hud = hud # hud object that this aux window supports
self.config = config # configuration object for this aux window to use self.config = config # configuration object for this aux window to use
self.params = params # dict aux params from config self.params = params # dict aux params from config
self.positions = {} # dict of window positions self.positions = {} # dict of window positions
# self.rel_positions = {} # dict of window positions, relative to the table origin self.displayed = False # the seat windows are displayed
self.displayed_cards = False self.uses_timer = False # the Aux_seats object uses a timer to control hiding
self.timer_on = False # bool = Ture if the timeout for removing the cards is on self.timer_on = False # bool = Ture if the timeout for removing the cards is on
self.card_images = self.get_card_images()
# placeholders that should be overridden--so we don't throw errors
def create_contents(self): pass
def update_contents(self): pass
def create(self): def create(self):
self.adj = self.hud.adj_seats(0, self.config) self.adj = self.hud.adj_seats(0, self.config) # move adj_seats to aux and get rid of it in Hud.py
loc = self.config.get_aux_locations(self.params['name'], int(self.hud.max)) loc = self.config.get_aux_locations(self.params['name'], int(self.hud.max))
self.m_windows = {} # windows to put the card images in self.m_windows = {} # windows to put the card images in
self.eb = {} # event boxes so we can interact with the mucked cards
self.seen_cards = {} # image objects to stash the cards in
for i in (range(1, self.hud.max + 1) + ['common']): for i in (range(1, self.hud.max + 1) + ['common']):
if i == 'common': if i == 'common':
(x, y) = self.params['layout'][self.hud.max].common (x, y) = self.params['layout'][self.hud.max].common
else: else:
(x, y) = loc[self.adj[i]] (x, y) = loc[self.adj[i]]
self.m_windows[i] = gtk.Window() self.m_windows[i] = Seat_Window()
self.m_windows[i].set_decorated(False) self.m_windows[i].set_decorated(False)
self.m_windows[i].set_property("skip-taskbar-hint", True) self.m_windows[i].set_property("skip-taskbar-hint", True)
self.m_windows[i].set_transient_for(self.hud.main_window) self.m_windows[i].set_transient_for(self.hud.main_window)
self.m_windows[i].set_focus_on_map(False) self.m_windows[i].set_focus_on_map(False)
self.eb[i] = gtk.EventBox()
self.eb[i].connect("button_press_event", self.button_press_cb)
self.m_windows[i].connect("configure_event", self.configure_event_cb, i) self.m_windows[i].connect("configure_event", self.configure_event_cb, i)
self.m_windows[i].add(self.eb[i])
self.seen_cards[i] = gtk.image_new_from_pixbuf(self.card_images[('B', 'H')])
self.eb[i].add(self.seen_cards[i])
self.positions[i] = (int(x) + self.hud.table.x, int(y) + self.hud.table.y) self.positions[i] = (int(x) + self.hud.table.x, int(y) + self.hud.table.y)
# self.rel_positions[i] = (int(x), int(y))
self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) self.m_windows[i].move(self.positions[i][0], self.positions[i][1])
self.m_windows[i].set_opacity(float(self.params['opacity'])) if self.params.has_key('opacity'):
self.m_windows[i].set_opacity(float(self.params['opacity']))
# the create_contents method is supplied by the subclass
self.create_contents(self.m_windows[i], i)
self.m_windows[i].show_all() self.m_windows[i].show_all()
self.m_windows[i].hide() if self.uses_timer:
self.m_windows[i].hide()
def update_gui(self, new_hand_id):
"""Update the gui, LDO."""
for i in self.m_windows.keys():
self.update_contents(self.m_windows[i], i)
# Methods likely to be of use for any Seat_Window implementation
def destroy(self):
"""Destroy all of the seat windows."""
for i in self.m_windows.keys():
self.m_windows[i].destroy()
del(self.m_windows[i])
# Methods likely to be useful for mucked card windows (or similar) only
def hide(self):
"""Hide the seat windows."""
for (i, w) in self.m_windows.iteritems():
w.hide()
self.displayed = False
def save_layout(self, *args):
"""Save new layout back to the aux element in the config file."""
new_locs = {}
# print "adj =", self.adj
for (i, pos) in self.positions.iteritems():
if i != 'common':
new_locs[self.adj[int(i)]] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y)
else:
new_locs[i] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y)
self.config.edit_aux_layout(self.params['name'], self.hud.max, locations = new_locs)
def configure_event_cb(self, widget, event, i, *args):
self.positions[i] = widget.get_position()
# self.rel_positions[i] = (self.positions[i][0] - self.hud.table.x, self.positions[i][1] - self.hud.table.y)
class Flop_Mucked(Aux_Seats):
"""Aux_Window class for displaying mucked cards for flop games."""
def __init__(self, hud, config, params):
super(Flop_Mucked, self).__init__(hud, config, params)
self.card_images = self.get_card_images()
self.uses_timer = True # this Aux_seats object uses a timer to control hiding
def create_contents(self, container, i):
"""Create the widgets for showing the contents of the Aux_seats window."""
container.eb = gtk.EventBox()
container.eb.connect("button_press_event", self.button_press_cb)
container.add(container.eb)
container.seen_cards = gtk.image_new_from_pixbuf(self.card_images[0])
container.eb.add(container.seen_cards)
def update_contents(self, container, i):
if not self.hud.cards.has_key(i): return
cards = self.hud.cards[i]
n_cards = self.has_cards(cards)
if n_cards > 1:
# scratch is a working pixbuf, used to assemble the image
scratch = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
int(self.params['card_wd'])*n_cards,
int(self.params['card_ht']))
x = 0 # x coord where the next card starts in scratch
for card in cards:
# concatenate each card image to scratch
if card == None or card ==0:
break
self.card_images[card].copy_area(0, 0,
int(self.params['card_wd']), int(self.params['card_ht']),
scratch, x, 0)
x = x + int(self.params['card_wd'])
container.seen_cards.set_from_pixbuf(scratch)
container.resize(1,1)
container.show()
container.move(self.positions[i][0], self.positions[i][1]) # here is where I move back
self.displayed = True
if i != "common":
id = self.get_id_from_seat(i)
self.m_windows[i].eb.set_tooltip_text(self.hud.stat_dict[id]['screen_name'])
def update_gui(self, new_hand_id): def update_gui(self, new_hand_id):
"""Prepare and show the mucked cards.""" """Prepare and show the mucked cards."""
if self.displayed_cards: if self.displayed: self.hide()
self.hide_mucked_cards()
self.displayed_cards = False # See how many players showed a hand. Skip if only 1 shows (= hero)
n_sd = 0
for (i, cards) in self.hud.cards.iteritems(): for (i, cards) in self.hud.cards.iteritems():
if self.has_cards(cards): n_cards = self.has_cards(cards)
# scratch is a working pixbuf, used to assemble the image if n_cards > 0 and i != 'common':
scratch = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, n_sd = n_sd + 1
int(self.params['card_wd'])*len(cards)/2, if n_sd < 2:
int(self.params['card_ht'])) print "skipping, n_sd =", n_sd
x = 0 # x coord where the next card starts in scratch return
for card in [cards[k:k+2] for k in xrange(0, len(cards), 2)]:
# concatenate each card image to scratch
self.card_images[self.split_cards(card)].copy_area(0, 0,
int(self.params['card_wd']), int(self.params['card_ht']),
scratch, x, 0)
x = x + int(self.params['card_wd'])
self.seen_cards[i].set_from_pixbuf(scratch)
# self.m_windows[i].show_all()
self.m_windows[i].resize(1,1)
self.m_windows[i].show()
self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) # here is where I move back
self.displayed_cards = True
for stats in self.hud.stat_dict.itervalues(): super(Flop_Mucked, self).update_gui(new_hand_id)
self.eb[stats['seat']].set_tooltip_text(stats['screen_name'])
if self.displayed_cards and float(self.params['timeout']) > 0: if self.displayed and float(self.params['timeout']) > 0:
self.timer_on = True self.timer_on = True
gobject.timeout_add(int(1000*float(self.params['timeout'])), self.timed_out) gobject.timeout_add(int(1000*float(self.params['timeout'])), self.timed_out)
def destroy(self):
"""Destroy all of the mucked windows."""
for w in self.m_windows.values():
w.destroy()
def timed_out(self): def timed_out(self):
# this is the callback from the timeout # this is the callback from the timeout
@ -418,15 +479,9 @@ class Flop_Mucked(Aux_Window):
if not self.timer_on: if not self.timer_on:
return False return False
else: else:
self.hide_mucked_cards() self.hide()
return False return False
def hide_mucked_cards(self):
"""Hide the mucked card windows."""
for (i, w) in self.m_windows.iteritems():
w.hide()
self.displayed_cards = False
def button_press_cb(self, widget, event, *args): def button_press_cb(self, widget, event, *args):
"""Handle button clicks in the event boxes.""" """Handle button clicks in the event boxes."""
@ -444,58 +499,14 @@ class Flop_Mucked(Aux_Window):
self.timer_on = False self.timer_on = False
else: else:
self.timer_on = False self.timer_on = False
self.hide_mucked_cards() self.hide()
elif event.button == 1: # left button event elif event.button == 1: # left button event
window = widget.get_parent() window = widget.get_parent()
window.begin_move_drag(event.button, int(event.x_root), int(event.y_root), event.time) window.begin_move_drag(event.button, int(event.x_root), int(event.y_root), event.time)
def configure_event_cb(self, widget, event, i, *args):
self.positions[i] = widget.get_position()
# self.rel_positions[i] = (self.positions[i][0] - self.hud.table.x, self.positions[i][1] - self.hud.table.y)
def expose_all(self): def expose_all(self):
for (i, cards) in self.hud.cards.iteritems(): for (i, cards) in self.hud.cards.iteritems():
self.m_windows[i].show() self.m_windows[i].show()
self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) # here is where I move back self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) # here is where I move back
self.displayed_cards = True self.displayed = True
def save_layout(self, *args):
"""Save new layout back to the aux element in the config file."""
new_locs = {}
# print "adj =", self.adj
for (i, pos) in self.positions.iteritems():
if i != 'common':
new_locs[self.adj[int(i)]] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y)
else:
new_locs[i] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y)
self.config.edit_aux_layout(self.params['name'], self.hud.max, locations = new_locs)
# This test program doesn't work
#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, db_connection): #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_data(new_hand_id, db_connection)
# m.update_gui(new_hand_id)
# return(True)
#
# config = Configuration.Config()
# db_connection = Database.Database(config, 'fpdbTEST', '')
# main_window = gtk.Window()
# main_window.set_keep_above(True)
# main_window.connect("destroy", destroy)
#
# aux_to_call = "stud_mucked"
# aux_params = config.get_aux_parameters(aux_to_call)
# m = eval("%s(None, config, aux_params)" % aux_params['class'])
#
# s_id = gobject.io_add_watch(sys.stdin, gobject.IO_IN, process_new_hand, db_connection)
# gtk.main()

View File

@ -18,6 +18,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
######################################################################## ########################################################################
# TODO: straighten out discards for draw games
import sys import sys
from HandHistoryConverter import * from HandHistoryConverter import *
@ -25,16 +26,35 @@ from HandHistoryConverter import *
class PokerStars(HandHistoryConverter): class PokerStars(HandHistoryConverter):
############################################################
# Class Variables
# Static regexes # Static regexes
re_GameInfo = re.compile("PokerStars Game #(?P<HID>[0-9]+):\s+(HORSE)? \(?(?P<GAME>Hold\'em|Razz|7 Card Stud|7 Card Stud Hi/Lo|Omaha|Omaha Hi/Lo|Badugi) (?P<LIMIT>No Limit|Limit|Pot Limit),? \(?(?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\) - (?P<DATETIME>.*$)", re.MULTILINE) re_GameInfo = re.compile("""PokerStars\sGame\s\#(?P<HID>[0-9]+):\s+
(Tournament\s\#(?P<TOURNO>\d+),\s(?P<BUYIN>[\$\+\d\.]+)\s)?
(?P<MIXED>HORSE|8\-Game|HOSE)?\s?\(?
(?P<GAME>Hold\'em|Razz|7\sCard\sStud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi|Triple\sDraw\s2\-7\sLowball)\s
(?P<LIMIT>No\sLimit|Limit|Pot\sLimit)\)?,?\s
(-\sLevel\s(?P<LEVEL>[IVXLC]+)\s)?\(?
(?P<CURRENCY>\$|)?
(?P<SB>[.0-9]+)/\$?
(?P<BB>[.0-9]+)\)\s-\s
(?P<DATETIME>.*$)""",
re.MULTILINE|re.VERBOSE)
re_SplitHands = re.compile('\n\n+') re_SplitHands = re.compile('\n\n+')
re_TailSplitHands = re.compile('(\n\n\n+)') re_TailSplitHands = re.compile('(\n\n\n+)')
re_HandInfo = re.compile("^Table \'(?P<TABLE>[- a-zA-Z]+)\'(?P<TABLEATTRIBUTES>.+?$)?", re.MULTILINE) re_HandInfo = re.compile("""^Table\s\'(?P<TABLE>[-\ a-zA-Z\d]+)\'\s
((?P<MAX>\d+)-max\s)?
(?P<PLAY>\(Play\sMoney\)\s)?
(Seat\s\#(?P<BUTTON>\d+)\sis\sthe\sbutton)?""",
re.MULTILINE|re.VERBOSE)
re_Button = re.compile('Seat #(?P<BUTTON>\d+) is the button', re.MULTILINE) re_Button = re.compile('Seat #(?P<BUTTON>\d+) is the button', re.MULTILINE)
re_PlayerInfo = re.compile('^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$?(?P<CASH>[.0-9]+) in chips\)', re.MULTILINE) re_PlayerInfo = re.compile('^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$?(?P<CASH>[.0-9]+) in chips\)', re.MULTILINE)
re_Board = re.compile(r"\[(?P<CARDS>.+)\]") re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
# self.re_setHandInfoRegex('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[ a-zA-Z]+) - \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) - (?P<GAMETYPE>.*) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+) ET - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+)Table (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)') # self.re_setHandInfoRegex('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[ a-zA-Z]+) - \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) - (?P<GAMETYPE>.*) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+) ET - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+)Table (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'}
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True): def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True):
"""\ """\
in_path (default '-' = sys.stdin) in_path (default '-' = sys.stdin)
@ -53,6 +73,9 @@ follow : whether to tail -f the input"""
players = set([player[1] for player in hand.players]) players = set([player[1] for player in hand.players])
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
# we need to recompile the player regexs. # we need to recompile the player regexs.
# TODO: should probably rename re_HeroCards and corresponding method,
# since they are used to find all cards on lines starting with "Dealt to:"
# They still identify the hero.
self.compiledPlayers = players self.compiledPlayers = players
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")" player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
logging.debug("player_re: " + player_re) logging.debug("player_re: " + player_re)
@ -62,43 +85,59 @@ follow : whether to tail -f the input"""
self.re_BringIn = re.compile(r"^%s: brings[- ]in( low|) for \$?(?P<BRINGIN>[.0-9]+)" % player_re, re.MULTILINE) self.re_BringIn = re.compile(r"^%s: brings[- ]in( low|) for \$?(?P<BRINGIN>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBoth = re.compile(r"^%s: posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE) self.re_PostBoth = re.compile(r"^%s: posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_HeroCards = re.compile(r"^Dealt to %s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % player_re, re.MULTILINE) self.re_HeroCards = re.compile(r"^Dealt to %s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % player_re, re.MULTILINE)
self.re_Action = re.compile(r"^%s:(?P<ATYPE> bets| checks| raises| calls| folds| discards| stands pat)( \$(?P<BET>[.\d]+))?( to \$(?P<BETTO>[.\d]+))?( (?P<NODISCARDED>\d) cards?( \[(?P<DISCARDED>.+?)\])?)?" % player_re, re.MULTILINE) self.re_Action = re.compile(r"""^%s:(?P<ATYPE>\sbets|\schecks|\sraises|\scalls|\sfolds|\sdiscards|\sstands\spat)
(\s\$?(?P<BET>[.\d]+))?(\sto\s\$?(?P<BETTO>[.\d]+))? # the number discarded goes in <BET>
(\scards?(\s\[(?P<DISCARDED>.+?)\])?)?"""
% player_re, re.MULTILINE|re.VERBOSE)
self.re_ShowdownAction = re.compile(r"^%s: shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE) self.re_ShowdownAction = re.compile(r"^%s: shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
self.re_CollectPot = re.compile(r"Seat (?P<SEAT>[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$(?P<POT>[.\d]+)\)(, mucked| with.*|)" % player_re, re.MULTILINE) self.re_CollectPot = re.compile(r"Seat (?P<SEAT>[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$?(?P<POT>[.\d]+)\)(, mucked| with.*|)" % player_re, re.MULTILINE)
self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE) self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE)
self.re_ShownCards = re.compile("^Seat (?P<SEAT>[0-9]+): %s \(.*\) showed \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE) self.re_ShownCards = re.compile("^Seat (?P<SEAT>[0-9]+): %s (\(.*\) )?(?P<SHOWED>showed|mucked) \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
def readSupportedGames(self): def readSupportedGames(self):
return [["ring", "hold", "nl"], return [["ring", "hold", "nl"],
["ring", "hold", "pl"], ["ring", "hold", "pl"],
["ring", "hold", "fl"], ["ring", "hold", "fl"],
["ring", "stud", "fl"], ["ring", "stud", "fl"],
#["ring", "draw", "fl"],
["ring", "omaha", "pl"] ["ring", "draw", "fl"],
["tour", "hold", "nl"],
["tour", "hold", "pl"],
["tour", "hold", "fl"],
["tour", "stud", "fl"],
] ]
def determineGameType(self, handText): def determineGameType(self, handText):
info = {'type':'ring'} # inspect the handText and return the gametype dict
# gametype dict is:
# {'limitType': xxx, 'base': xxx, 'category': xxx}
info = {}
m = self.re_GameInfo.search(handText) m = self.re_GameInfo.search(handText)
if not m: if not m:
return None return None
mg = m.groupdict() mg = m.groupdict()
# translations from captured groups to fpdb info strings
# translations from captured groups to our info strings
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' } limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' }
games = { # base, category games = { # base, category
"Hold'em" : ('hold','holdem'), "Hold'em" : ('hold','holdem'),
'Omaha' : ('hold','omahahi'), 'Omaha' : ('hold','omahahi'),
'Omaha Hi/Lo' : ('hold','omahahilo'), 'Omaha Hi/Lo' : ('hold','omahahilo'),
'Razz' : ('stud','razz'), 'Razz' : ('stud','razz'),
'7 Card Stud' : ('stud','studhi'), '7 Card Stud' : ('stud','studhi'),
'7 Card Stud Hi/Lo' : ('stud','studhilo'), '7 Card Stud Hi/Lo' : ('stud','studhilo'),
'Badugi' : ('draw','badugi') 'Badugi' : ('draw','badugi'),
'Triple Draw 2-7 Lowball' : ('draw','27_3draw'),
} }
currencies = { u'':'EUR', '$':'USD', '':'T$' } currencies = { u'':'EUR', '$':'USD', '':'T$' }
# I don't think this is doing what we think. mg will always have all
# the expected keys, but the ones that didn't match in the regex will
# have a value of None. It is OK if it throws an exception when it
# runs across an unknown game or limit or whatever.
if 'LIMIT' in mg: if 'LIMIT' in mg:
info['limitType'] = limits[mg['LIMIT']] info['limitType'] = limits[mg['LIMIT']]
if 'GAME' in mg: if 'GAME' in mg:
@ -109,8 +148,13 @@ follow : whether to tail -f the input"""
info['bb'] = mg['BB'] info['bb'] = mg['BB']
if 'CURRENCY' in mg: if 'CURRENCY' in mg:
info['currency'] = currencies[mg['CURRENCY']] info['currency'] = currencies[mg['CURRENCY']]
if 'TOURNO' in mg and mg['TOURNO'] == None:
info['type'] = 'ring'
else:
info['type'] = 'tour'
# NB: SB, BB must be interpreted as blinds or bets depending on limit type. # NB: SB, BB must be interpreted as blinds or bets depending on limit type.
return info return info
@ -119,14 +163,13 @@ follow : whether to tail -f the input"""
m = self.re_HandInfo.search(hand.handText,re.DOTALL) m = self.re_HandInfo.search(hand.handText,re.DOTALL)
if m: if m:
info.update(m.groupdict()) info.update(m.groupdict())
# TODO: Be less lazy and parse maxseats from the HandInfo regex # hand.maxseats = int(m2.group(1))
if m.group('TABLEATTRIBUTES'): else:
m2 = re.search("\s*(\d+)-max", m.group('TABLEATTRIBUTES')) pass # throw an exception here, eh?
hand.maxseats = int(m2.group(1))
m = self.re_GameInfo.search(hand.handText) m = self.re_GameInfo.search(hand.handText)
if m: info.update(m.groupdict()) if m: info.update(m.groupdict())
m = self.re_Button.search(hand.handText) # m = self.re_Button.search(hand.handText)
if m: info.update(m.groupdict()) # if m: info.update(m.groupdict())
# TODO : I rather like the idea of just having this dict as hand.info # TODO : I rather like the idea of just having this dict as hand.info
logging.debug("readHandInfo: %s" % info) logging.debug("readHandInfo: %s" % info)
for key in info: for key in info:
@ -143,7 +186,23 @@ follow : whether to tail -f the input"""
hand.tablename = info[key] hand.tablename = info[key]
if key == 'BUTTON': if key == 'BUTTON':
hand.buttonpos = info[key] hand.buttonpos = info[key]
if key == 'MAX':
hand.maxseats = int(info[key])
if key == 'MIXED':
if info[key] == None: hand.mixed = None
else: hand.mixed = self.mixes[info[key]]
if key == 'TOURNO':
hand.tourNo = info[key]
if key == 'BUYIN':
hand.buyin = info[key]
if key == 'LEVEL':
hand.level = info[key]
if key == 'PLAY' and info['PLAY'] != None:
# hand.currency = 'play' # overrides previously set value
hand.gametype['currency'] = 'play'
def readButton(self, hand): def readButton(self, hand):
m = self.re_Button.search(hand.handText) m = self.re_Button.search(hand.handText)
if m: if m:
@ -211,78 +270,115 @@ follow : whether to tail -f the input"""
for a in self.re_PostBoth.finditer(hand.handText): for a in self.re_PostBoth.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'both', a.group('SBBB')) hand.addBlind(a.group('PNAME'), 'both', a.group('SBBB'))
# def readHeroCards(self, hand):
# m = self.re_HeroCards.search(hand.handText)
# if(m == None):
# #Not involved in hand
# hand.involved = False
# else:
# hand.hero = m.group('PNAME')
# # "2c, qh" -> set(["2c","qc"])
# # Also works with Omaha hands.
# cards = m.group('NEWCARDS')
# cards = set(cards.split(' '))
# hand.addHoleCards(cards, m.group('PNAME'), shown=False, mucked=False, dealt=True)
def readHeroCards(self, hand): def readHeroCards(self, hand):
m = self.re_HeroCards.search(hand.handText) # streets PREFLOP, PREDRAW, and THIRD are special cases beacause
if(m == None): # we need to grab hero's cards
#Not involved in hand for street in ('PREFLOP', 'DEAL'):
hand.involved = False if street in hand.streets.keys():
else: m = self.re_HeroCards.finditer(hand.streets[street])
hand.hero = m.group('PNAME') for found in m:
# "2c, qh" -> set(["2c","qc"]) # if m == None:
# Also works with Omaha hands. # hand.involved = False
cards = m.group('NEWCARDS') # else:
cards = set(cards.split(' ')) hand.hero = found.group('PNAME')
hand.addHoleCards(cards, m.group('PNAME')) newcards = found.group('NEWCARDS').split(' ')
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
def readDrawCards(self, hand, street): for street, text in hand.streets.iteritems():
logging.debug("readDrawCards") if street in ('PREFLOP', 'DEAL'): continue # already done these
m = self.re_HeroCards.finditer(hand.streets[street]) m = self.re_HeroCards.finditer(hand.streets[street])
if m == None: for found in m:
hand.involved = False player = found.group('PNAME')
else: if found.group('NEWCARDS') == None:
for player in m: newcards = []
hand.hero = player.group('PNAME') # Only really need to do this once
newcards = player.group('NEWCARDS')
oldcards = player.group('OLDCARDS')
if newcards == None:
newcards = set()
else: else:
newcards = set(newcards.split(' ')) newcards = found.group('NEWCARDS').split(' ')
if oldcards == None: if found.group('OLDCARDS') == None:
oldcards = set() oldcards = []
else: else:
oldcards = set(oldcards.split(' ')) oldcards = found.group('OLDCARDS').split(' ')
hand.addDrawHoleCards(newcards, oldcards, player.group('PNAME'), street)
if street == 'THIRD' and len(newcards) == 3: # hero in stud game
hand.hero = player
hand.dealt.add(player) # need this for stud??
hand.addHoleCards(street, player, closed=newcards[0:2], open=[newcards[2]], shown=False, mucked=False, dealt=False)
else:
hand.addHoleCards(street, player, open=newcards, closed=oldcards, shown=False, mucked=False, dealt=False)
# def readDrawCards(self, hand, street):
# logging.debug("readDrawCards")
# m = self.re_HeroCards.finditer(hand.streets[street])
# if m == None:
# hand.involved = False
# else:
# for player in m:
# hand.hero = player.group('PNAME') # Only really need to do this once
# newcards = player.group('NEWCARDS')
# oldcards = player.group('OLDCARDS')
# if newcards == None:
# newcards = set()
# else:
# newcards = set(newcards.split(' '))
# if oldcards == None:
# oldcards = set()
# else:
# oldcards = set(oldcards.split(' '))
# hand.addDrawHoleCards(newcards, oldcards, player.group('PNAME'), street)
def readStudPlayerCards(self, hand, street): # def readStudPlayerCards(self, hand, street):
# See comments of reference implementation in FullTiltToFpdb.py # # See comments of reference implementation in FullTiltToFpdb.py
logging.debug("readStudPlayerCards") # logging.debug("readStudPlayerCards")
m = self.re_HeroCards.finditer(hand.streets[street]) # m = self.re_HeroCards.finditer(hand.streets[street])
for player in m: # for player in m:
#~ logging.debug(player.groupdict()) # #~ logging.debug(player.groupdict())
(pname, oldcards, newcards) = (player.group('PNAME'), player.group('OLDCARDS'), player.group('NEWCARDS')) # (pname, oldcards, newcards) = (player.group('PNAME'), player.group('OLDCARDS'), player.group('NEWCARDS'))
if oldcards: # if oldcards:
oldcards = [c.strip() for c in oldcards.split(' ')] # oldcards = [c.strip() for c in oldcards.split(' ')]
if newcards: # if newcards:
newcards = [c.strip() for c in newcards.split(' ')] # newcards = [c.strip() for c in newcards.split(' ')]
if street=='ANTES': # if street=='ANTES':
return # return
elif street=='THIRD': # elif street=='THIRD':
# we'll have observed hero holecards in CARDS and thirdstreet open cards in 'NEWCARDS' # # we'll have observed hero holecards in CARDS and thirdstreet open cards in 'NEWCARDS'
# hero: [xx][o] # # hero: [xx][o]
# others: [o] # # others: [o]
hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = oldcards, open = newcards) # hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = oldcards, open = newcards)
elif street in ('FOURTH', 'FIFTH', 'SIXTH'): # elif street in ('FOURTH', 'FIFTH', 'SIXTH'):
# 4th: # # 4th:
# hero: [xxo] [o] # # hero: [xxo] [o]
# others: [o] [o] # # others: [o] [o]
# 5th: # # 5th:
# hero: [xxoo] [o] # # hero: [xxoo] [o]
# others: [oo] [o] # # others: [oo] [o]
# 6th: # # 6th:
# hero: [xxooo] [o] # # hero: [xxooo] [o]
# others: [ooo] [o] # # others: [ooo] [o]
hand.addPlayerCards(player = player.group('PNAME'), street = street, open = newcards) # hand.addPlayerCards(player = player.group('PNAME'), street = street, open = newcards)
# we may additionally want to check the earlier streets tally with what we have but lets trust it for now. # # we may additionally want to check the earlier streets tally with what we have but lets trust it for now.
elif street=='SEVENTH' and newcards: # elif street=='SEVENTH' and newcards:
# hero: [xxoooo] [x] # # hero: [xxoooo] [x]
# others: not reported. # # others: not reported.
hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = newcards) # hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = newcards)
def readAction(self, hand, street): def readAction(self, hand, street):
m = self.re_Action.finditer(hand.streets[street]) m = self.re_Action.finditer(hand.streets[street])
for action in m: for action in m:
acts = action.groupdict()
if action.group('ATYPE') == ' raises': if action.group('ATYPE') == ' raises':
hand.addRaiseBy( street, action.group('PNAME'), action.group('BET') ) hand.addRaiseBy( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == ' calls': elif action.group('ATYPE') == ' calls':
@ -294,7 +390,7 @@ follow : whether to tail -f the input"""
elif action.group('ATYPE') == ' checks': elif action.group('ATYPE') == ' checks':
hand.addCheck( street, action.group('PNAME')) hand.addCheck( street, action.group('PNAME'))
elif action.group('ATYPE') == ' discards': elif action.group('ATYPE') == ' discards':
hand.addDiscard(street, action.group('PNAME'), action.group('NODISCARDED'), action.group('DISCARDED')) hand.addDiscard(street, action.group('PNAME'), action.group('BET'), action.group('DISCARDED'))
elif action.group('ATYPE') == ' stands pat': elif action.group('ATYPE') == ' stands pat':
hand.addStandsPat( street, action.group('PNAME')) hand.addStandsPat( street, action.group('PNAME'))
else: else:
@ -302,9 +398,9 @@ follow : whether to tail -f the input"""
def readShowdownActions(self, hand): def readShowdownActions(self, hand):
# TODO: pick up mucks also
for shows in self.re_ShowdownAction.finditer(hand.handText): for shows in self.re_ShowdownAction.finditer(hand.handText):
cards = shows.group('CARDS') cards = shows.group('CARDS').split(' ')
cards = set(cards.split(' '))
hand.addShownCards(cards, shows.group('PNAME')) hand.addShownCards(cards, shows.group('PNAME'))
def readCollectPot(self,hand): def readCollectPot(self,hand):
@ -315,8 +411,13 @@ follow : whether to tail -f the input"""
for m in self.re_ShownCards.finditer(hand.handText): for m in self.re_ShownCards.finditer(hand.handText):
if m.group('CARDS') is not None: if m.group('CARDS') is not None:
cards = m.group('CARDS') cards = m.group('CARDS')
cards = set(cards.split(' ')) cards = cards.split(' ') # needs to be a list, not a set--stud needs the order
hand.addShownCards(cards=cards, player=m.group('PNAME'))
(shown, mucked) = (False, False)
if m.group('SHOWED') == "showed": shown = True
elif m.group('SHOWED') == "mucked": mucked = True
hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked)
if __name__ == "__main__": if __name__ == "__main__":
parser = OptionParser() parser = OptionParser()

View File

@ -541,19 +541,14 @@ class Sql:
""" """
self.query['get_common_cards'] = """ self.query['get_common_cards'] = """
select select
card1Value AS card1value, boardcard1,
card1Suit AS card1suit, boardcard2,
card2Value AS card2value, boardcard3,
card2Suit AS card2suit, boardcard4,
card3Value AS card3value, boardcard5
card3Suit AS card3suit, from Hands
card4Value AS card4value, where Id = %s
card4Suit AS card4suit,
card5Value AS card5value,
card5Suit AS card5suit
from BoardCards
where handId = %s
""" """
self.query['get_action_from_hand'] = """ self.query['get_action_from_hand'] = """

View File

@ -231,7 +231,7 @@ def discover_nt_by_name(c, tablename):
titles = {} titles = {}
win32gui.EnumWindows(win_enum_handler, titles) win32gui.EnumWindows(win_enum_handler, titles)
for hwnd in titles: for hwnd in titles:
print "Tbales.py: tablename =", tablename, "title =", titles[hwnd] #print "Tables.py: tablename =", tablename, "title =", titles[hwnd]
try: try:
# this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html
if not tablename in titles[hwnd]: continue if not tablename in titles[hwnd]: continue
@ -314,6 +314,10 @@ def get_site_from_exe(c, exe):
return params['site_name'] return params['site_name']
return None return None
def everleaf_decode_table(tw):
# 2 - Tournament ID: 573256 - NL Hold'em - 150/300 blinds - Good luck <username>! - [Connection is ...]
pass
def pokerstars_decode_table(tw): def pokerstars_decode_table(tw):
# Extract poker information from the window title. This is not needed for # Extract poker information from the window title. This is not needed for
# fpdb, since all that information is available in the db via new_hand_number. # fpdb, since all that information is available in the db via new_hand_number.
@ -365,7 +369,7 @@ def clean_title(name):
for pattern in [' \(6 max\)', ' \(heads up\)', ' \(deep\)', for pattern in [' \(6 max\)', ' \(heads up\)', ' \(deep\)',
' \(deep hu\)', ' \(deep 6\)', ' \(2\)', ' \(deep hu\)', ' \(deep 6\)', ' \(2\)',
' \(edu\)', ' \(edu, 6 max\)', ' \(6\)', ' \(edu\)', ' \(edu, 6 max\)', ' \(6\)',
' \(speed\)', ' \(speed\)', 'special', 'newVPP',
' no all-in', ' fast', ',', ' 50BB min', '50bb min', '\s+$']: ' no all-in', ' fast', ',', ' 50BB min', '50bb min', '\s+$']:
name = re.sub(pattern, '', name) name = re.sub(pattern, '', name)
name = name.rstrip() name = name.rstrip()

View File

@ -92,6 +92,8 @@ if __name__=="__main__":
print "game =", table.get_game() print "game =", table.get_game()
fake = fake_hud(table) fake = fake_hud(table)
print "fake =", fake
gobject.timeout_add(100, check_on_table, table, fake) gobject.timeout_add(100, check_on_table, table, fake)
print "calling main"
gtk.main() gtk.main()

View File

@ -65,8 +65,11 @@ class Table(Table_Window):
print "x = %s y = %s width = %s height = %s" % (x, y, width, height) print "x = %s y = %s width = %s height = %s" % (x, y, width, height)
self.x = int(x) + b_width self.x = int(x) + b_width
self.y = int(y) + tb_height self.y = int(y) + tb_height
self.height = int(height) - b_width - tb_height self.width = width - x
self.width = int(width) - 2*b_width self.height = height - y
print "x = %s y = %s width = %s height = %s" % (self.x, self.y, self.width, self.height)
#self.height = int(height) - b_width - tb_height
#self.width = int(width) - 2*b_width
self.exe = self.get_nt_exe(hwnd) self.exe = self.get_nt_exe(hwnd)
self.title = titles[hwnd] self.title = titles[hwnd]
@ -76,12 +79,13 @@ class Table(Table_Window):
self.gdkhandle = gtk.gdk.window_foreign_new(long(self.window)) self.gdkhandle = gtk.gdk.window_foreign_new(long(self.window))
def get_geometry(self): def get_geometry(self):
if not win32gui.IsWindow(self.number): # window closed
if not win32gui.IsWindow(self.window): # window closed
return None return None
try: try:
(x, y, width, height) = win32gui.GetWindowRect(hwnd) (x, y, width, height) = win32gui.GetWindowRect(self.number)
width = width - x
height = height - y
return {'x' : int(x) + b_width, return {'x' : int(x) + b_width,
'y' : int(y) + tb_height, 'y' : int(y) + tb_height,
'width' : int(height) - b_width - tb_height, 'width' : int(height) - b_width - tb_height,
@ -116,27 +120,32 @@ class Table(Table_Window):
def topify(self, hud): def topify(self, hud):
"""Set the specified gtk window to stayontop in MS Windows.""" """Set the specified gtk window to stayontop in MS Windows."""
def windowEnumerationHandler(hwnd, resultList): # def windowEnumerationHandler(hwnd, resultList):
'''Callback for win32gui.EnumWindows() to generate list of window handles.''' # '''Callback for win32gui.EnumWindows() to generate list of window handles.'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd))) # resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
#
unique_name = 'unique name for finding this window' # unique_name = 'unique name for finding this window'
real_name = hud.main_window.get_title() # real_name = hud.main_window.get_title()
hud.main_window.set_title(unique_name) # hud.main_window.set_title(unique_name)
tl_windows = [] # tl_windows = []
win32gui.EnumWindows(windowEnumerationHandler, tl_windows) # win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
#
for w in tl_windows: # for w in tl_windows:
if w[1] == unique_name: # if w[1] == unique_name:
hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0]) # hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0])
hud.main_window.gdkhandle.set_transient_for(self.gdkhandle) hud.main_window.gdkhandle = hud.main_window.window
hud.main_window.gdkhandle.set_transient_for(self.gdkhandle)
rect = self.gdkhandle.get_frame_extents()
(innerx, innery) = self.gdkhandle.get_origin()
b_width = rect.x - innerx
tb_height = rect.y - innery
# #
# style = win32gui.GetWindowLong(self.number, win32con.GWL_EXSTYLE) # style = win32gui.GetWindowLong(self.number, win32con.GWL_EXSTYLE)
# style |= win32con.WS_CLIPCHILDREN # style |= win32con.WS_CLIPCHILDREN
# win32gui.SetWindowLong(self.number, win32con.GWL_EXSTYLE, style) # win32gui.SetWindowLong(self.number, win32con.GWL_EXSTYLE, style)
break # break
hud.main_window.set_title(real_name) # hud.main_window.set_title(real_name)
def win_enum_handler(hwnd, titles): def win_enum_handler(hwnd, titles):
titles[hwnd] = win32gui.GetWindowText(hwnd) titles[hwnd] = win32gui.GetWindowText(hwnd)

View File

@ -33,7 +33,7 @@ import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import fpdb_db
import fpdb_simple import fpdb_simple
import GuiBulkImport import GuiBulkImport
import GuiPlayerStats import GuiPlayerStats
@ -42,6 +42,8 @@ import GuiTableViewer
import GuiAutoImport import GuiAutoImport
import GuiGraphViewer import GuiGraphViewer
import GuiSessionViewer import GuiSessionViewer
import SQL
import Database
import FpdbSQLQueries import FpdbSQLQueries
import Configuration import Configuration
@ -179,20 +181,21 @@ class fpdb:
def dia_load_profile(self, widget, data=None): def dia_load_profile(self, widget, data=None):
"""Dialogue to select a file to load a profile from""" """Dialogue to select a file to load a profile from"""
if self.obtain_global_lock() == 0: # returns 0 if successful if self.obtain_global_lock() == 0: # returns 0 if successful
try: #try:
chooser = gtk.FileChooserDialog(title="Please select a profile file to load", # chooser = gtk.FileChooserDialog(title="Please select a profile file to load",
action=gtk.FILE_CHOOSER_ACTION_OPEN, # action=gtk.FILE_CHOOSER_ACTION_OPEN,
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) # buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
chooser.set_filename(self.profile) # chooser.set_filename(self.profile)
response = chooser.run() # response = chooser.run()
chooser.destroy() # chooser.destroy()
if response == gtk.RESPONSE_OK: # if response == gtk.RESPONSE_OK:
self.load_profile(chooser.get_filename()) # self.load_profile(chooser.get_filename())
elif response == gtk.RESPONSE_CANCEL: # elif response == gtk.RESPONSE_CANCEL:
print 'User cancelled loading profile' # print 'User cancelled loading profile'
except: #except:
pass # pass
self.load_profile()
self.release_global_lock() self.release_global_lock()
#end def dia_load_profile #end def dia_load_profile
@ -204,22 +207,23 @@ class fpdb:
try: try:
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING,
buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables") buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables")
diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database "+self.db.database+" on "+self.db.host+" they will be deleted." diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database " \
+self.db.fdb.database+" on "+self.db.fdb.host+" they will be deleted."
dia_confirm.format_secondary_text(diastring)#todo: make above string with bold for db, host and deleted dia_confirm.format_secondary_text(diastring)#todo: make above string with bold for db, host and deleted
response = dia_confirm.run() response = dia_confirm.run()
dia_confirm.destroy() dia_confirm.destroy()
if response == gtk.RESPONSE_YES: if response == gtk.RESPONSE_YES:
if self.db.backend == self.fdb_lock.MYSQL_INNODB: if self.db.fdb.backend == self.fdb_lock.fdb.MYSQL_INNODB:
# mysql requires locks on all tables or none - easier to release this lock # mysql requires locks on all tables or none - easier to release this lock
# than lock all the other tables # than lock all the other tables
# ToDo: lock all other tables so that lock doesn't have to be released # ToDo: lock all other tables so that lock doesn't have to be released
self.release_global_lock() self.release_global_lock()
lock_released = True lock_released = True
self.db.recreate_tables() self.db.fdb.recreate_tables()
else: else:
# for other dbs use same connection as holds global lock # for other dbs use same connection as holds global lock
self.fdb_lock.recreate_tables() self.fdb_lock.fdb.recreate_tables()
elif response == gtk.RESPONSE_NO: elif response == gtk.RESPONSE_NO:
print 'User cancelled recreating tables' print 'User cancelled recreating tables'
except: except:
@ -347,6 +351,7 @@ class fpdb:
def load_profile(self): def load_profile(self):
"""Loads profile from the provided path name.""" """Loads profile from the provided path name."""
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
self.settings = {} self.settings = {}
if (os.sep=="/"): if (os.sep=="/"):
self.settings['os']="linuxmac" self.settings['os']="linuxmac"
@ -359,17 +364,13 @@ class fpdb:
self.settings.update(self.config.get_import_parameters()) self.settings.update(self.config.get_import_parameters())
self.settings.update(self.config.get_default_paths()) self.settings.update(self.config.get_default_paths())
if self.db!=None: if self.db != None and self.db.fdb != None:
self.db.disconnect() self.db.disconnect()
self.db = fpdb_db.fpdb_db() self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server'])
#print "end of fpdb.load_profile, databaseName:",self.settings['db-databaseName'] self.db = Database.Database(self.config, sql = self.sql)
self.db.connect(self.settings['db-backend'],
self.settings['db-host'], if self.db.fdb.wrongDbVersion:
self.settings['db-databaseName'],
self.settings['db-user'],
self.settings['db-password'])
if self.db.wrongDbVersion:
diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK))
label = gtk.Label("An invalid DB version or missing tables have been detected.") label = gtk.Label("An invalid DB version or missing tables have been detected.")
@ -387,9 +388,16 @@ class fpdb:
response = diaDbVersionWarning.run() response = diaDbVersionWarning.run()
diaDbVersionWarning.destroy() diaDbVersionWarning.destroy()
if self.status_bar == None:
self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host))
self.main_vbox.pack_end(self.status_bar, False, True, 0)
self.status_bar.show()
else:
self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host))
# Database connected to successfully, load queries to pass on to other classes # Database connected to successfully, load queries to pass on to other classes
self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name()) self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name())
self.db.db.rollback() self.db.connection.rollback()
#end def load_profile #end def load_profile
def not_implemented(self, widget, data=None): def not_implemented(self, widget, data=None):
@ -398,13 +406,9 @@ class fpdb:
def obtain_global_lock(self): def obtain_global_lock(self):
print "\nTaking global lock ..." print "\nTaking global lock ..."
self.fdb_lock = fpdb_db.fpdb_db() self.fdb_lock = Database.Database(self.config, sql = self.sql)
self.fdb_lock.connect(self.settings['db-backend'], self.fdb_lock.do_connect(self.config)
self.settings['db-host'], return self.fdb_lock.fdb.get_global_lock()
self.settings['db-databaseName'],
self.settings['db-user'],
self.settings['db-password'])
return self.fdb_lock.get_global_lock()
#end def obtain_global_lock #end def obtain_global_lock
def quit(self, widget, data=None): def quit(self, widget, data=None):
@ -415,9 +419,9 @@ class fpdb:
#end def quit_cliecked #end def quit_cliecked
def release_global_lock(self): def release_global_lock(self):
self.fdb_lock.db.rollback() self.fdb_lock.fdb.db.rollback()
self.fdb_lock.disconnect() self.fdb_lock.fdb.disconnect()
print "Global lock released." print "Global lock released.\n"
#end def release_global_lock #end def release_global_lock
def tab_abbreviations(self, widget, data=None): def tab_abbreviations(self, widget, data=None):
@ -466,7 +470,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
def tab_table_viewer(self, widget, data=None): def tab_table_viewer(self, widget, data=None):
"""opens a table viewer tab""" """opens a table viewer tab"""
#print "start of tab_table_viewer" #print "start of tab_table_viewer"
new_tv_thread=GuiTableViewer.GuiTableViewer(self.db, self.settings) new_tv_thread=GuiTableViewer.GuiTableViewer(self.db.fdb, self.settings)
self.threads.append(new_tv_thread) self.threads.append(new_tv_thread)
tv_tab=new_tv_thread.get_vbox() tv_tab=new_tv_thread.get_vbox()
self.add_and_display_tab(tv_tab, "Table Viewer") self.add_and_display_tab(tv_tab, "Table Viewer")
@ -475,22 +479,16 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
def tabGraphViewer(self, widget, data=None): def tabGraphViewer(self, widget, data=None):
"""opens a graph viewer tab""" """opens a graph viewer tab"""
#print "start of tabGraphViewer" #print "start of tabGraphViewer"
new_gv_thread=GuiGraphViewer.GuiGraphViewer(self.db, self.settings, self.querydict, self.config) new_gv_thread = GuiGraphViewer.GuiGraphViewer(self.querydict, self.config)
self.threads.append(new_gv_thread) self.threads.append(new_gv_thread)
gv_tab=new_gv_thread.get_vbox() gv_tab=new_gv_thread.get_vbox()
self.add_and_display_tab(gv_tab, "Graphs") self.add_and_display_tab(gv_tab, "Graphs")
#end def tabGraphViewer #end def tabGraphViewer
def __init__(self): def __init__(self):
LOG_FILENAME = './logging.out' self.threads = []
LOG_FORMAT = "%(asctime)-15s %(levelname)-8s %(message)s" self.db = None
logging.basicConfig(filename=LOG_FILENAME,level=10,format=LOG_FORMAT) self.status_bar = None
logging.info("Fpdb started")
self.threads=[]
self.db=None
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
self.load_profile()
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("delete_event", self.delete_event) self.window.connect("delete_event", self.delete_event)
@ -525,11 +523,8 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.tab_main_help(None, None) self.tab_main_help(None, None)
self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.database, self.db.host))
self.main_vbox.pack_end(self.status_bar, False, True, 0)
self.status_bar.show()
self.window.show() self.window.show()
self.load_profile()
sys.stderr.write("fpdb starting ...") sys.stderr.write("fpdb starting ...")
#end def __init__ #end def __init__

View File

@ -255,7 +255,6 @@ class fpdb_db:
self.cursor.execute(self.sql.query['createPlayersTable']) self.cursor.execute(self.sql.query['createPlayersTable'])
self.cursor.execute(self.sql.query['createAutoratesTable']) self.cursor.execute(self.sql.query['createAutoratesTable'])
self.cursor.execute(self.sql.query['createHandsTable']) self.cursor.execute(self.sql.query['createHandsTable'])
self.cursor.execute(self.sql.query['createBoardCardsTable'])
self.cursor.execute(self.sql.query['createTourneyTypesTable']) self.cursor.execute(self.sql.query['createTourneyTypesTable'])
self.cursor.execute(self.sql.query['createTourneysTable']) self.cursor.execute(self.sql.query['createTourneysTable'])
self.cursor.execute(self.sql.query['createTourneysPlayersTable']) self.cursor.execute(self.sql.query['createTourneysPlayersTable'])
@ -587,17 +586,18 @@ class fpdb_db:
print "analyze took", atime, "seconds" print "analyze took", atime, "seconds"
#end def analyzeDB #end def analyzeDB
# Currently uses an exclusive lock on the Hands table as a global lock # Currently uses an exclusive lock on the Players table as a global lock
# ( Changed because Hands is used in Database.init() )
# Return values are Unix style, 0 for success, positive integers for errors # Return values are Unix style, 0 for success, positive integers for errors
# 1 = generic error # 1 = generic error
# 2 = hands table does not exist (error message is suppressed) # 2 = players table does not exist (error message is suppressed)
def get_global_lock(self): def get_global_lock(self):
if self.backend == self.MYSQL_INNODB: if self.backend == self.MYSQL_INNODB:
try: try:
self.cursor.execute( "lock tables Hands write" ) self.cursor.execute( "lock tables Players write" )
except: except:
# Table 'fpdb.hands' doesn't exist # Table 'fpdb.players' doesn't exist
if str(sys.exc_value).find(".Hands' doesn't exist") >= 0: if str(sys.exc_value).find(".Players' doesn't exist") >= 0:
return(2) return(2)
print "Error! failed to obtain global lock. Close all programs accessing " \ print "Error! failed to obtain global lock. Close all programs accessing " \
+ "database (including fpdb) and try again (%s)." \ + "database (including fpdb) and try again (%s)." \
@ -605,11 +605,11 @@ class fpdb_db:
return(1) return(1)
elif self.backend == self.PGSQL: elif self.backend == self.PGSQL:
try: try:
self.cursor.execute( "lock table Hands in exclusive mode nowait" ) self.cursor.execute( "lock table Players in exclusive mode nowait" )
#print "... after lock table, status =", self.cursor.statusmessage #print "... after lock table, status =", self.cursor.statusmessage
except: except:
# relation "hands" does not exist # relation "players" does not exist
if str(sys.exc_value).find('relation "hands" does not exist') >= 0: if str(sys.exc_value).find('relation "players" does not exist') >= 0:
return(2) return(2)
print "Error! failed to obtain global lock. Close all programs accessing " \ print "Error! failed to obtain global lock. Close all programs accessing " \
+ "database (including fpdb) and try again (%s)." \ + "database (including fpdb) and try again (%s)." \

View File

@ -32,6 +32,7 @@ import re
import fpdb_simple import fpdb_simple
import fpdb_db import fpdb_db
import Database
import fpdb_parse_logic import fpdb_parse_logic
import Configuration import Configuration
@ -58,7 +59,8 @@ class Importer:
self.settings = settings self.settings = settings
self.caller = caller self.caller = caller
self.config = config self.config = config
self.fdb = None self.database = None # database will be the main db interface eventually
self.fdb = None # fdb may disappear or just hold the simple db connection
self.cursor = None self.cursor = None
self.filelist = {} self.filelist = {}
self.dirlist = {} self.dirlist = {}
@ -76,6 +78,7 @@ class Importer:
self.settings.setdefault("minPrint", 30) self.settings.setdefault("minPrint", 30)
self.settings.setdefault("handCount", 0) self.settings.setdefault("handCount", 0)
self.database = Database.Database(self.config) # includes .connection and .sql variables
self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
self.fdb.do_connect(self.config) self.fdb.do_connect(self.config)
self.fdb.db.rollback() self.fdb.db.rollback()
@ -393,8 +396,9 @@ class Importer:
self.hand=hand self.hand=hand
try: try:
handsId = fpdb_parse_logic.mainParser(self.settings, self.fdb handsId = fpdb_parse_logic.mainParser( self.settings, self.fdb
, self.siteIds[site], category, hand, self.config) , self.siteIds[site], category, hand
, self.config, self.database )
self.fdb.db.commit() self.fdb.db.commit()
stored += 1 stored += 1

View File

@ -21,10 +21,13 @@ import fpdb_simple
import Database import Database
#parses a holdem hand #parses a holdem hand
def mainParser(settings, fdb, siteID, category, hand, config): def mainParser(settings, fdb, siteID, category, hand, config, db = None):
backend = settings['db-backend'] backend = settings['db-backend']
#This is redundant - hopefully fdb will be a Database object in an interation soon if db == None:
db = Database.Database(config, 'fpdb', '') #This is redundant - hopefully fdb will be a Database object in an iteration soon
db = Database.Database(c = config, sql = None)
else:
db = db
category = fpdb_simple.recogniseCategory(hand[0]) category = fpdb_simple.recogniseCategory(hand[0])
base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud" base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud"

View File

@ -1136,16 +1136,6 @@ def storeActions(cursor, handsPlayersIds, actionTypes, allIns, actionAmounts, ac
cursor.executemany("INSERT INTO HandsActions (handsPlayerId, street, actionNo, action, allIn, amount) VALUES (%s, %s, %s, %s, %s, %s)", inserts) cursor.executemany("INSERT INTO HandsActions (handsPlayerId, street, actionNo, action, allIn, amount) VALUES (%s, %s, %s, %s, %s, %s)", inserts)
#end def storeActions #end def storeActions
def store_board_cards(cursor, hands_id, board_values, board_suits):
#stores into table board_cards
cursor.execute ("""INSERT INTO BoardCards (handId, card1Value, card1Suit,
card2Value, card2Suit, card3Value, card3Suit, card4Value, card4Suit,
card5Value, card5Suit) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""",
(hands_id, board_values[0], board_suits[0], board_values[1], board_suits[1],
board_values[2], board_suits[2], board_values[3], board_suits[3],
board_values[4], board_suits[4]))
#end def store_board_cards
def storeHands(backend, conn, cursor, site_hand_no, gametype_id def storeHands(backend, conn, cursor, site_hand_no, gametype_id
,hand_start_time, names, tableName, maxSeats, hudCache, ,hand_start_time, names, tableName, maxSeats, hudCache,
board_values, board_suits): board_values, board_suits):