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

This commit is contained in:
Mika Bostrom 2010-08-13 10:48:48 +03:00
commit 0166a1857c
24 changed files with 1091 additions and 217 deletions

View File

@ -49,7 +49,7 @@ src_install() {
make_desktop_entry ${PN}
prepgamesdirs
fperms +x "${GAMES_DATADIR}"/${PN}/pyfpdb/*.pyw
chmod +x ${D}/"${GAMES_DATADIR}"/${PN}/pyfpdb/*.pyw
}
pkg_postinst() {

View File

@ -49,7 +49,7 @@ src_install() {
make_desktop_entry ${PN}
prepgamesdirs
fperms +x "${GAMES_DATADIR}"/${PN}/pyfpdb/*.pyw
chmod +x ${D}/"${GAMES_DATADIR}"/${PN}/pyfpdb/*.pyw
}
pkg_postinst() {

View File

@ -0,0 +1,65 @@
# Copyright 1999-2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# created by Steffen Schaumburg, steffen@schaumburger.info
inherit eutils
inherit games
inherit git
EAPI="2"
NEED_PYTHON=2.5
DESCRIPTION="A free/open source tracker/HUD for use with online poker"
HOMEPAGE="http://fpdb.wiki.sourceforge.net/"
EGIT_REPO_URI="git://git.assembla.com/fpdb.git"
LICENSE="AGPL-3"
SLOT="0"
KEYWORDS="~amd64 ~x86"
#note: this should work on other architectures too, please send me your experiences
IUSE="graph mysql postgres sqlite"
RDEPEND="
mysql? ( virtual/mysql
dev-python/mysql-python )
postgres? ( dev-db/postgresql-server
dev-python/psycopg )
sqlite? ( dev-lang/python[sqlite]
dev-python/numpy )
>=x11-libs/gtk+-2.10
dev-python/pygtk
graph? ( dev-python/numpy
dev-python/matplotlib[gtk] )
dev-python/python-xlib
dev-python/pytz"
DEPEND="${RDEPEND}"
src_unpack() {
git_src_unpack
}
src_install() {
insinto "${GAMES_DATADIR}"/${PN}
doins -r gfx
doins -r pyfpdb
doins readme.txt
exeinto "${GAMES_DATADIR}"/${PN}
doexe run_fpdb.py
dodir "${GAMES_BINDIR}"
dosym "${GAMES_DATADIR}"/${PN}/run_fpdb.py "${GAMES_BINDIR}"/${PN}
newicon gfx/fpdb-icon.png ${PN}.png
make_desktop_entry ${PN}
prepgamesdirs
chmod +x ${D}/"${GAMES_DATADIR}"/${PN}/pyfpdb/*.pyw
}
pkg_postinst() {
games_pkg_postinst
elog "Note that if you really want to use mysql or postgresql you will have to create"
elog "the database and user yourself and enter it into the fpdb config."
elog "You can find the instructions on the project's website."
}

View File

@ -452,8 +452,8 @@ class Email:
self.fetchType = node.getAttribute("fetchType")
def __str__(self):
return " host = %s\n username = %s\n password = %s\n useSsl = %s\n folder = %s\n" \
% (self.host, self.username, self.password, self.useSsl, self.folder)
return " siteName=%s\n fetchType=%s\n host = %s\n username = %s\n password = %s\n useSsl = %s\n folder = %s\n" \
% (self.siteName, self.fetchType, self.host, self.username, self.password, self.useSsl, self.folder)
class HudUI:
def __init__(self, node):
@ -534,6 +534,39 @@ class GUICashStats(list):
self.append( [col_name, col_title, disp_all, disp_posn, field_format, field_type, xalignment] )
def get_defaults(self):
"""A list of defaults to be called, should there be no entry in config"""
defaults = [ [u'game', u'Game', True, True, u'%s', u'str', 0.0],
[u'hand', u'Hand', False, False, u'%s', u'str', 0.0],
[u'plposition', u'Posn', False, False, u'%s', u'str', 1.0],
[u'pname', u'Name', False, False, u'%s', u'str', 0.0],
[u'n', u'Hds', True, True, u'%1.0f', u'str', 1.0],
[u'avgseats', u'Seats', False, False, u'%3.1f', u'str', 1.0],
[u'vpip', u'VPIP', True, True, u'%3.1f', u'str', 1.0],
[u'pfr', u'PFR', True, True, u'%3.1f', u'str', 1.0],
[u'pf3', u'PF3', True, True, u'%3.1f', u'str', 1.0],
[u'aggfac', u'AggFac', True, True, u'%2.2f', u'str', 1.0],
[u'aggfrq', u'AggFreq', True, True, u'%3.1f', u'str', 1.0],
[u'conbet', u'ContBet', True, True, u'%3.1f', u'str', 1.0],
[u'rfi', u'RFI', True, True, u'%3.1f', u'str', 1.0],
[u'steals', u'Steals', True, True, u'%3.1f', u'str', 1.0],
[u'saw_f', u'Saw_F', True, True, u'%3.1f', u'str', 1.0],
[u'sawsd', u'SawSD', True, True, u'%3.1f', u'str', 1.0],
[u'wtsdwsf', u'WtSDwsF', True, True, u'%3.1f', u'str', 1.0],
[u'wmsd', u'W$SD', True, True, u'%3.1f', u'str', 1.0],
[u'flafq', u'FlAFq', True, True, u'%3.1f', u'str', 1.0],
[u'tuafq', u'TuAFq', True, True, u'%3.1f', u'str', 1.0],
[u'rvafq', u'RvAFq', True, True, u'%3.1f', u'str', 1.0],
[u'pofafq', u'PoFAFq', False, False, u'%3.1f', u'str', 1.0],
[u'net', u'Net($)', True, True, u'%6.2f', u'cash', 1.0],
[u'bbper100', u'bb/100', True, True, u'%4.2f', u'str', 1.0],
[u'rake', u'Rake($)', True, True, u'%6.2f', u'cash', 1.0],
[u'bb100xr', u'bbxr/100', True, True, u'%4.2f', u'str', 1.0],
[u'variance', u'Variance', True, True, u'%5.2f', u'str', 1.0]
]
for col in defaults:
self.append (col)
# def __str__(self):
# s = ""
# for l in self:
@ -595,11 +628,14 @@ class Config:
self.db_selected = None # database the user would like to use
self.tv = None
self.general = General()
self.emails = {}
self.gui_cash_stats = GUICashStats()
for gen_node in doc.getElementsByTagName("general"):
self.general.add_elements(node=gen_node) # add/overwrite elements in self.general
if doc.getElementsByTagName("gui_cash_stats") == []:
self.gui_cash_stats.get_defaults()
for gcs_node in doc.getElementsByTagName("gui_cash_stats"):
self.gui_cash_stats.add_elements(node=gcs_node) # add/overwrite elements in self.gui_cash_stats
@ -655,7 +691,8 @@ class Config:
for email_node in doc.getElementsByTagName("email"):
email = Email(node = email_node)
self.email = email
if email.siteName!="": #FIXME: Why on earth is this needed?
self.emails[email.siteName+"_"+email.fetchType]=email
for hui_node in doc.getElementsByTagName('hud_ui'):
hui = HudUI(node = hui_node)
@ -702,6 +739,12 @@ class Config:
if site_node.getAttribute("site_name") == site:
return site_node
def getEmailNode(self, siteName, fetchType):
for emailNode in self.doc.getElementsByTagName("email"):
if emailNode.getAttribute("siteName") == siteName and emailNode.getAttribute("fetchType") == fetchType:
return emailNode
#end def getEmailNode
def getGameNode(self,gameName):
"""returns DOM game node for a given game"""
for gameNode in self.doc.getElementsByTagName("game"):
@ -776,6 +819,15 @@ class Config:
else:
return(l)
def editEmail(self, siteName, fetchType, newEmail):
emailNode = self.getEmailNode(siteName, fetchType)
emailNode.setAttribute("host", newEmail.host)
emailNode.setAttribute("username", newEmail.username)
emailNode.setAttribute("password", newEmail.password)
emailNode.setAttribute("folder", newEmail.folder)
emailNode.setAttribute("useSsl", newEmail.useSsl)
#end def editEmail
def edit_layout(self, site_name, max, width = None, height = None,
fav_seat = None, locations = None):
site_node = self.get_site_node(site_name)

View File

@ -74,7 +74,7 @@ except ImportError:
use_numpy = False
DB_VERSION = 139
DB_VERSION = 142
# Variance created as sqlite has a bunch of undefined aggregate functions.
@ -140,7 +140,7 @@ class Database:
, {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0}
#, {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0} unique indexes not dropped
, {'tab':'TourneyTypes', 'col':'siteId', 'drop':0}
, {'tab':'Backings', 'col':'tourneysPlayerId', 'drop':0}
, {'tab':'Backings', 'col':'tourneysPlayersId', 'drop':0}
, {'tab':'Backings', 'col':'playerId', 'drop':0}
]
, [ # indexes for sqlite (list index 4)
@ -155,7 +155,7 @@ class Database:
, {'tab':'Tourneys', 'col':'tourneyTypeId', 'drop':1}
, {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0}
, {'tab':'TourneyTypes', 'col':'siteId', 'drop':0}
, {'tab':'Backings', 'col':'tourneysPlayerId', 'drop':0}
, {'tab':'Backings', 'col':'tourneysPlayersId', 'drop':0}
, {'tab':'Backings', 'col':'playerId', 'drop':0}
]
]
@ -265,7 +265,7 @@ class Database:
#ISOLATION_LEVEL_SERIALIZABLE = 2
if self.backend == self.SQLITE and self.database == ':memory:' and self.wrongDbVersion:
if self.backend == self.SQLITE and self.database == ':memory:' and self.wrongDbVersion and self.is_connected():
log.info("sqlite/:memory: - creating")
self.recreate_tables()
self.wrongDbVersion = False
@ -289,6 +289,7 @@ class Database:
self.saveActions = False if self.import_options['saveActions'] == False else True
if self.is_connected():
self.connection.rollback() # make sure any locks taken so far are released
#end def __init__
@ -342,7 +343,6 @@ class Database:
self.db_server = db_params['db-server']
self.database = db_params['db-databaseName']
self.host = db_params['db-host']
self.__connected = True
def connect(self, backend=None, host=None, database=None,
user=None, password=None, create=False):
@ -363,6 +363,7 @@ class Database:
MySQLdb = pool.manage(MySQLdb, pool_size=5)
try:
self.connection = MySQLdb.connect(host=host, user=user, passwd=password, db=database, use_unicode=True)
self.__connected = True
#TODO: Add port option
except MySQLdb.Error, ex:
if ex.args[0] == 1045:
@ -384,20 +385,21 @@ class Database:
# flat out wrong
# sqlcoder: This database only connect failed in my windows setup??
# Modifed it to try the 4 parameter style if the first connect fails - does this work everywhere?
connected = False
self.__connected = False
if self.host == "localhost" or self.host == "127.0.0.1":
try:
self.connection = psycopg2.connect(database = database)
connected = True
self.__connected = True
except:
# direct connection failed so try user/pass/... version
pass
if not connected:
if not self.is_connected():
try:
self.connection = psycopg2.connect(host = host,
user = user,
password = password,
database = database)
self.__connected = True
except Exception, ex:
if 'Connection refused' in ex.args[0]:
# meaning eg. db not running
@ -426,6 +428,7 @@ class Database:
log.info("Connecting to SQLite: %(database)s" % {'database':self.db_path})
if os.path.exists(database) or create:
self.connection = sqlite3.connect(self.db_path, detect_types=sqlite3.PARSE_DECLTYPES )
self.__connected = True
sqlite3.register_converter("bool", lambda x: bool(int(x)))
sqlite3.register_adapter(bool, lambda x: "1" if x else "0")
self.connection.create_function("floor", 1, math.floor)
@ -443,6 +446,7 @@ class Database:
else:
raise FpdbError("unrecognised database backend:"+str(backend))
if self.is_connected():
self.cursor = self.connection.cursor()
self.cursor.execute(self.sql.query['set tx level'])
self.check_version(database=database, create=create)
@ -499,6 +503,10 @@ class Database:
self.connection.rollback()
def connected(self):
""" now deprecated, use is_connected() instead """
return self.__connected
def is_connected(self):
return self.__connected
def get_cursor(self):
@ -1442,17 +1450,41 @@ class Database:
h_start = self.hero_hudstart_def
if v_start is None:
v_start = self.villain_hudstart_def
if self.hero_ids == {}:
where = ""
where = "WHERE hp.tourneysPlayersId IS NULL"
else:
where = "where ( hp.playerId not in " + str(tuple(self.hero_ids.values())) \
where = "where ((( hp.playerId not in " + str(tuple(self.hero_ids.values())) \
+ " and h.startTime > '" + v_start + "')" \
+ " or ( hp.playerId in " + str(tuple(self.hero_ids.values())) \
+ " and h.startTime > '" + h_start + "')"
rebuild_sql = self.sql.query['rebuildHudCache'].replace('<where_clause>', where)
+ " and h.startTime > '" + h_start + "'))" \
+ " AND hp.tourneysPlayersId IS NULL)"
rebuild_sql_cash = self.sql.query['rebuildHudCache'].replace('<tourney_insert_clause>', "")
rebuild_sql_cash = rebuild_sql_cash.replace('<tourney_select_clause>', "")
rebuild_sql_cash = rebuild_sql_cash.replace('<tourney_join_clause>', "")
rebuild_sql_cash = rebuild_sql_cash.replace('<tourney_group_clause>', "")
rebuild_sql_cash = rebuild_sql_cash.replace('<where_clause>', where)
#print "rebuild_sql_cash:",rebuild_sql_cash
self.get_cursor().execute(self.sql.query['clearHudCache'])
self.get_cursor().execute(rebuild_sql)
self.get_cursor().execute(rebuild_sql_cash)
if self.hero_ids == {}:
where = "WHERE hp.tourneysPlayersId >= 0"
else:
where = "where ((( hp.playerId not in " + str(tuple(self.hero_ids.values())) \
+ " and h.startTime > '" + v_start + "')" \
+ " or ( hp.playerId in " + str(tuple(self.hero_ids.values())) \
+ " and h.startTime > '" + h_start + "'))" \
+ " AND hp.tourneysPlayersId >= 0)"
rebuild_sql_tourney = self.sql.query['rebuildHudCache'].replace('<tourney_insert_clause>', ",tourneyTypeId")
rebuild_sql_tourney = rebuild_sql_tourney.replace('<tourney_select_clause>', ",t.tourneyTypeId")
rebuild_sql_tourney = rebuild_sql_tourney.replace('<tourney_join_clause>', """INNER JOIN TourneysPlayers tp ON (tp.id = hp.tourneysPlayersId)
INNER JOIN Tourneys t ON (t.id = tp.tourneyId)""")
rebuild_sql_tourney = rebuild_sql_tourney.replace('<tourney_group_clause>', ",t.tourneyTypeId")
rebuild_sql_tourney = rebuild_sql_tourney.replace('<where_clause>', where)
#print "rebuild_sql_tourney:",rebuild_sql_tourney
self.get_cursor().execute(rebuild_sql_tourney)
self.commit()
print "Rebuild hudcache took %.1f seconds" % (time() - stime,)
except:
@ -2021,6 +2053,10 @@ class Database:
result=cursor.fetchone()
if result != None:
if self.backend == Database.PGSQL:
expectedValues = ('comment', 'tourneyname', 'matrixIdProcessed', 'totalRebuyCount', 'totalAddOnCount',
'prizepool', 'startTime', 'entries', 'commentTs', 'endTime')
else:
expectedValues = ('comment', 'tourneyName', 'matrixIdProcessed', 'totalRebuyCount', 'totalAddOnCount',
'prizepool', 'startTime', 'entries', 'commentTs', 'endTime')
updateDb=False
@ -2115,6 +2151,32 @@ class Database:
result = c.fetchall()
return result
#end def getTourneyTypesIds
def getTourneyInfo(self, siteName, tourneyNo):
c = self.get_cursor()
c.execute(self.sql.query['getTourneyInfo'], (siteName, tourneyNo))
columnNames=c.description
names=[]
for column in columnNames:
names.append(column[0])
data=c.fetchone()
return (names,data)
#end def getTourneyInfo
def getTourneyPlayerInfo(self, siteName, tourneyNo, playerName):
c = self.get_cursor()
c.execute(self.sql.query['getTourneyPlayerInfo'], (siteName, tourneyNo, playerName))
columnNames=c.description
names=[]
for column in columnNames:
names.append(column[0])
data=c.fetchone()
return (names,data)
#end def getTourneyPlayerInfo
#end class Database
# Class used to hold all the data needed to write a hand to the db

View File

@ -290,9 +290,11 @@ class DerivedStats():
# print "p_actions:", self.pfba(actions), "p_folds:", self.pfba(actions, l=('folds',)), "alliners:", alliners
# pas = set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners)
# hand.players includes people that are sitting out on some sites.
# Those that posted an ante should have been deal cards.
p_in = set([x[0] for x in hand.actions['BLINDSANTES']] + [x[0] for x in hand.actions['PREFLOP']])
# hand.players includes people that are sitting out on some sites for cash games
# actionStreets[1] is 'DEAL', 'THIRD', 'PREFLOP', so any player dealt cards
# must act on this street if dealt cards. Almost certainly broken for the 'all-in blind' case
# and right now i don't care - CG
p_in = set([x[0] for x in hand.actions[hand.actionStreets[1]]])
for (i, street) in enumerate(hand.actionStreets):
actions = hand.actions[street]

View File

@ -31,18 +31,23 @@ class Fulltilt(HandHistoryConverter):
codepage = ["utf-16", "cp1252", "utf-8"]
siteId = 1 # Needs to match id entry in Sites database
substitutions = {
'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
'LS' : "\$|\xe2\x82\xac|" # legal currency symbols - Euro(cp1252, utf-8)
}
# Static regexes
re_GameInfo = re.compile('''.*\#(?P<HID>[0-9]+):\s
(?:(?P<TOURNAMENT>.+)\s\((?P<TOURNO>\d+)\),\s)?
.+
-\s(?P<CURRENCY>\$|)?
-\s(?P<CURRENCY>[%(LS)s]|)?
(?P<SB>[.0-9]+)/
\$?(?P<BB>[.0-9]+)\s
[%(LS)s]?(?P<BB>[.0-9]+)\s
(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s
\$?(?P<CAP>[.0-9]+\sCap\s)?
[%(LS)s]?(?P<CAP>[.0-9]+\sCap\s)?
(?P<LIMIT>(No\sLimit|Pot\sLimit|Limit))?\s
(?P<GAME>(Hold\'em|Omaha\sHi|Omaha\sH/L|7\sCard\sStud|Stud\sH/L|Razz|Stud\sHi))
''', re.VERBOSE)
''' % substitutions, re.VERBOSE)
re_SplitHands = re.compile(r"\n\n+")
re_TailSplitHands = re.compile(r"(\n\n+)")
re_HandInfo = re.compile(r'''.*\#(?P<HID>[0-9]+):\s
@ -51,29 +56,29 @@ class Fulltilt(HandHistoryConverter):
(?P<PLAY>Play\sChip\s|PC)?
(?P<TABLE>[-\s\da-zA-Z]+)\s
(\((?P<TABLEATTRIBUTES>.+)\)\s)?-\s
\$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\s(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s
\$?(?P<CAP>[.0-9]+\sCap\s)?
[%(LS)s]?(?P<SB>[.0-9]+)/[%(LS)s]?(?P<BB>[.0-9]+)\s(Ante\s[%(LS)s]?(?P<ANTE>[.0-9]+)\s)?-\s
[%(LS)s]?(?P<CAP>[.0-9]+\sCap\s)?
(?P<GAMETYPE>[a-zA-Z\/\'\s]+)\s-\s
(?P<DATETIME>\d+:\d+:\d+\s(?P<TZ1>\w+)\s-\s\d+/\d+/\d+|\d+:\d+\s(?P<TZ2>\w+)\s-\s\w+\,\s\w+\s\d+\,\s\d+)
(?P<PARTIAL>\(partial\))?\n
(?:.*?\n(?P<CANCELLED>Hand\s\#(?P=HID)\shas\sbeen\scanceled))?
''', re.VERBOSE|re.DOTALL)
''' % substitutions, re.VERBOSE|re.DOTALL)
re_TourneyExtraInfo = re.compile('''(((?P<TOURNEY_NAME>[^$]+)?
(?P<CURRENCY>\$)?(?P<BUYIN>[.0-9]+)?\s*\+\s*\$?(?P<FEE>[.0-9]+)?
(?P<CURRENCY>[%(LS)s])?(?P<BUYIN>[.0-9]+)?\s*\+\s*[%(LS)s]?(?P<FEE>[.0-9]+)?
(\s(?P<SPECIAL>(KO|Heads\sUp|Matrix\s\dx|Rebuy|Madness)))?
(\s(?P<SHOOTOUT>Shootout))?
(\s(?P<SNG>Sit\s&\sGo))?
(\s\((?P<TURBO>Turbo)\))?)|(?P<UNREADABLE_INFO>.+))
''', re.VERBOSE)
''' % substitutions, re.VERBOSE)
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \(\$(?P<CASH>[,.0-9]+)\)$', re.MULTILINE)
re_TourneysPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \(\$?(?P<CASH>[,.0-9]+)\)(, is sitting out)?$', re.MULTILINE)
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \([%(LS)s](?P<CASH>[,.0-9]+)\)$' % substitutions, re.MULTILINE)
re_TourneysPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \([%(LS)s]?(?P<CASH>[,.0-9]+)\)(, is sitting out)?$' % substitutions, re.MULTILINE)
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
#static regex for tourney purpose
re_TourneyInfo = re.compile('''Tournament\sSummary\s
(?P<TOURNAMENT_NAME>[^$(]+)?\s*
((?P<CURRENCY>\$|)?(?P<BUYIN>[.0-9]+)\s*\+\s*\$?(?P<FEE>[.0-9]+)\s)?
((?P<CURRENCY>[%(LS)s]|)?(?P<BUYIN>[.0-9]+)\s*\+\s*[%(LS)s]?(?P<FEE>[.0-9]+)\s)?
((?P<SPECIAL>(KO|Heads\sUp|Matrix\s\dx|Rebuy|Madness))\s)?
((?P<SHOOTOUT>Shootout)\s)?
((?P<SNG>Sit\s&\sGo)\s)?
@ -83,24 +88,24 @@ class Fulltilt(HandHistoryConverter):
(?P<GAME>(Hold\'em|Omaha\sHi|Omaha\sH/L|7\sCard\sStud|Stud\sH/L|Razz|Stud\sHi))\s
(\((?P<TURBO2>Turbo)\)\s)?
(?P<LIMIT>(No\sLimit|Pot\sLimit|Limit))?
''', re.VERBOSE)
re_TourneyBuyInFee = re.compile("Buy-In: (?P<BUYIN_CURRENCY>\$|)?(?P<BUYIN>[.0-9]+) \+ \$?(?P<FEE>[.0-9]+)")
''' % substitutions, re.VERBOSE)
re_TourneyBuyInFee = re.compile("Buy-In: (?P<BUYIN_CURRENCY>[%(LS)s]|)?(?P<BUYIN>[.0-9]+) \+ [%(LS)s]?(?P<FEE>[.0-9]+)" % substitutions)
re_TourneyBuyInChips = re.compile("Buy-In Chips: (?P<BUYINCHIPS>\d+)")
re_TourneyEntries = re.compile("(?P<ENTRIES>\d+) Entries")
re_TourneyPrizePool = re.compile("Total Prize Pool: (?P<PRIZEPOOL_CURRENCY>\$|)?(?P<PRIZEPOOL>[.,0-9]+)")
re_TourneyRebuyCost = re.compile("Rebuy: (?P<REBUY_CURRENCY>\$|)?(?P<REBUY_COST>[.,0-9]+)")
re_TourneyAddOnCost = re.compile("Add-On: (?P<ADDON_CURRENCY>\$|)?(?P<ADDON_COST>[.,0-9]+)")
re_TourneyPrizePool = re.compile("Total Prize Pool: (?P<PRIZEPOOL_CURRENCY>[%(LS)s]|)?(?P<PRIZEPOOL>[.,0-9]+)" % substitutions)
re_TourneyRebuyCost = re.compile("Rebuy: (?P<REBUY_CURRENCY>[%(LS)s]|)?(?P<REBUY_COST>[.,0-9]+)"% substitutions)
re_TourneyAddOnCost = re.compile("Add-On: (?P<ADDON_CURRENCY>[%(LS)s]|)?(?P<ADDON_COST>[.,0-9]+)"% substitutions)
re_TourneyRebuyCount = re.compile("performed (?P<REBUY_COUNT>\d+) Rebuy")
re_TourneyAddOnCount = re.compile("performed (?P<ADDON_COUNT>\d+) Add-On")
re_TourneyRebuysTotal = re.compile("Total Rebuys: (?P<REBUY_TOTAL>\d+)")
re_TourneyAddOnsTotal = re.compile("Total Add-Ons: (?P<ADDONS_TOTAL>\d+)")
re_TourneyRebuyChips = re.compile("Rebuy Chips: (?P<REBUY_CHIPS>\d+)")
re_TourneyAddOnChips = re.compile("Add-On Chips: (?P<ADDON_CHIPS>\d+)")
re_TourneyKOBounty = re.compile("Knockout Bounty: (?P<KO_BOUNTY_CURRENCY>\$|)?(?P<KO_BOUNTY_AMOUNT>[.,0-9]+)")
re_TourneyKOBounty = re.compile("Knockout Bounty: (?P<KO_BOUNTY_CURRENCY>[%(LS)s]|)?(?P<KO_BOUNTY_AMOUNT>[.,0-9]+)" % substitutions)
re_TourneyKoCount = re.compile("received (?P<COUNT_KO>\d+) Knockout Bounty Award(s)?")
re_TourneyTimeInfo = re.compile("Tournament started: (?P<STARTTIME>.*)\nTournament ((?P<IN_PROGRESS>is still in progress)?|(finished:(?P<ENDTIME>.*))?)$")
re_TourneysPlayersSummary = re.compile("^(?P<RANK>(Still Playing|\d+))( - |: )(?P<PNAME>[^\n,]+)(, )?(?P<WINNING_CURRENCY>\$|)?(?P<WINNING>[.\d]+)?", re.MULTILINE)
re_TourneysPlayersSummary = re.compile("^(?P<RANK>(Still Playing|\d+))( - |: )(?P<PNAME>[^\n,]+)(, )?(?P<WINNING_CURRENCY>[%(LS)s]|)?(?P<WINNING>[.\d]+)?" % substitutions, re.MULTILINE)
re_TourneyHeroFinishingP = re.compile("(?P<HERO_NAME>.*) finished in (?P<HERO_FINISHING_POS>\d+)(st|nd|rd|th) place")
#TODO: See if we need to deal with play money tourney summaries -- Not right now (they shouldn't pass the re_TourneyInfo)
@ -127,17 +132,19 @@ class Fulltilt(HandHistoryConverter):
# we need to recompile the player regexs.
self.compiledPlayers = players
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
self.substitutions['PLAYERS'] = player_re
logging.debug("player_re: " + player_re)
self.re_PostSB = re.compile(r"^%s posts the small blind of \$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostDead = re.compile(r"^%s posts a dead small blind of \$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBB = re.compile(r"^%s posts (the big blind of )?\$?(?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_Antes = re.compile(r"^%s antes \$?(?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE)
self.re_BringIn = re.compile(r"^%s brings in 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_PostSB = re.compile(r"^%(PLAYERS)s posts the small blind of [%(LS)s]?(?P<SB>[.0-9]+)" % self.substitutions, re.MULTILINE)
self.re_PostDead = re.compile(r"^%(PLAYERS)s posts a dead small blind of [%(LS)s]?(?P<SB>[.0-9]+)" % self.substitutions, re.MULTILINE)
self.re_PostBB = re.compile(r"^%(PLAYERS)s posts (the big blind of )?[%(LS)s]?(?P<BB>[.0-9]+)" % self.substitutions, re.MULTILINE)
self.re_Antes = re.compile(r"^%(PLAYERS)s antes [%(LS)s]?(?P<ANTE>[.0-9]+)" % self.substitutions, re.MULTILINE)
self.re_BringIn = re.compile(r"^%(PLAYERS)s brings in for [%(LS)s]?(?P<BRINGIN>[.0-9]+)" % self.substitutions, re.MULTILINE)
self.re_PostBoth = re.compile(r"^%(PLAYERS)s posts small \& big blinds \[[%(LS)s]? (?P<SBBB>[.0-9]+)" % self.substitutions, 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 to| completes it to| calls| folds)( \$?(?P<BET>[.,\d]+))?" % player_re, re.MULTILINE)
self.re_Action = re.compile(r"^%(PLAYERS)s(?P<ATYPE> bets| checks| raises to| completes it to| calls| folds)( [%(LS)s]?(?P<BET>[.,\d]+))?" % self.substitutions, 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]+): %(PLAYERS)s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \([%(LS)s]?(?P<POT>[.,\d]+)\)(, mucked| with.*)" % self.substitutions, re.MULTILINE)
self.re_SitsOut = re.compile(r"^%s sits out" % player_re, re.MULTILINE)
self.re_ShownCards = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(?P<ACT>showed|mucked) \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
@ -704,5 +711,3 @@ if __name__ == "__main__":
e = Fulltilt(in_path = options.ipath, out_path = options.opath, follow = options.follow)

View File

@ -349,11 +349,11 @@ def main(argv=None):
if options.usage == True:
#Print usage examples and exit
print "USAGE:"
print 'PokerStars converter: ./GuiBulkImport -c PokerStars -f filename'
print 'Full Tilt converter: ./GuiBulkImport -c "Full Tilt Poker" -f filename'
print "Everleaf converter: ./GuiBulkImport -c Everleaf -f filename"
print "Absolute converter: ./GuiBulkImport -c Absolute -f filename"
print "PartyPoker converter: ./GuiBulkImport -c PartyPoker -f filename"
print 'PokerStars converter: ./GuiBulkImport.py -c PokerStars -f filename'
print 'Full Tilt converter: ./GuiBulkImport.py -c "Full Tilt Poker" -f filename'
print "Everleaf converter: ./GuiBulkImport.py -c Everleaf -f filename"
print "Absolute converter: ./GuiBulkImport.py -c Absolute -f filename"
print "PartyPoker converter: ./GuiBulkImport.py -c PartyPoker -f filename"
sys.exit(0)
config = Configuration.Config()

154
pyfpdb/GuiImapFetcher.py Normal file
View File

@ -0,0 +1,154 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#Copyright 2010 Steffen Schaumburg
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU Affero General Public License as published by
#the Free Software Foundation, version 3 of the License.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU Affero General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.
#In the "official" distribution you can find the license in agpl-3.0.txt.
import threading
import pygtk
pygtk.require('2.0')
import gtk
from imaplib import IMAP4
from socket import gaierror
import ImapFetcher
class GuiImapFetcher (threading.Thread):
def __init__(self, config, db, sql, mainwin, debug=True):
self.config = config
self.db = db
self.mainVBox = gtk.VBox()
self.buttonsHBox = gtk.HBox()
self.mainVBox.pack_end(self.buttonsHBox, expand=False)
label=gtk.Label("To cancel just close this tab.")
self.buttonsHBox.add(label)
self.saveButton = gtk.Button("_Save")
self.saveButton.connect('clicked', self.saveClicked)
self.buttonsHBox.add(self.saveButton)
self.importAllButton = gtk.Button("_Import All")
self.importAllButton.connect('clicked', self.importAllClicked)
self.buttonsHBox.add(self.importAllButton)
self.statusLabel=gtk.Label("If you change the config you must save before importing")
self.mainVBox.pack_end(self.statusLabel, expand=False, padding=4)
self.passwords={}
self.displayConfig()
self.mainVBox.show_all()
#end def __init__
def saveClicked(self, widget, data=None):
row = self.rowVBox.get_children()
columns=row[0].get_children() #TODO: make save capable of handling multiple email entries - not relevant yet as only one entry is useful atm. The rest of this tab works fine for multiple entries though
siteName=columns[0].get_text()
fetchType=columns[1].get_text()
code=siteName+"_"+fetchType
for email in self.config.emails:
toSave=self.config.emails[email]
break
toSave.siteName=siteName
toSave.fetchType=fetchType
toSave.host=columns[2].get_text()
toSave.username=columns[3].get_text()
if columns[4].get_text()=="***":
toSave.password=self.passwords[code]
else:
toSave.password=columns[4].get_text()
toSave.folder=columns[5].get_text()
if columns[6].get_active() == 0:
toSave.useSsl="True"
else:
toSave.useSsl="False"
self.config.editEmail(siteName, fetchType, toSave)
self.config.save()
#def saveClicked
def importAllClicked(self, widget, data=None):
self.statusLabel.set_label("Starting import. Please wait.") #FIXME: why doesnt this one show?
for email in self.config.emails:
try:
result=ImapFetcher.run(self.config.emails[email], self.db)
self.statusLabel.set_label("Finished import without error.")
except IMAP4.error as error:
if str(error)=="[AUTHENTICATIONFAILED] Authentication failed.":
self.statusLabel.set_label("Login to mailserver failed: please check mailserver, username and password")
except gaierror as error:
if str(error)=="[Errno -2] Name or service not known":
self.statusLabel.set_label("Could not connect to mailserver: check mailserver and use SSL settings and internet connectivity")
#def importAllClicked
def get_vbox(self):
"""returns the vbox of this thread"""
return self.mainVBox
#end def get_vbox
def displayConfig(self):
box=gtk.HBox(homogeneous=True)
for text in ("Site", "Fetch Type", "Mailserver", "Username", "Password", "Mail Folder", "Use SSL"):
label=gtk.Label(text)
box.add(label)
self.mainVBox.pack_start(box, expand=False)
self.rowVBox = gtk.VBox()
self.mainVBox.add(self.rowVBox)
for email in self.config.emails:
config=self.config.emails[email]
box=gtk.HBox(homogeneous=True)
for field in (config.siteName, config.fetchType):
label=gtk.Label(field)
box.add(label)
for field in (config.host, config.username):
entry=gtk.Entry()
entry.set_text(field)
box.add(entry)
entry=gtk.Entry()
self.passwords[email]=config.password
entry.set_text("***")
box.add(entry)
entry=gtk.Entry()
entry.set_text(config.folder)
box.add(entry)
sslBox = gtk.combo_box_new_text()
sslBox.append_text("Yes")
sslBox.append_text("No")
sslBox.set_active(0)
box.add(sslBox)
#TODO: "run just this one" button
self.rowVBox.pack_start(box, expand=False)
#print
self.mainVBox.show_all()
#end def displayConfig
#end class GuiImapFetcher

View File

@ -86,9 +86,9 @@ class GuiTourneyPlayerStats (GuiPlayerStats.GuiPlayerStats):
, ["playerName", False, "Name", 0.0, "%s", "str"] # true not allowed for this line (set in code)
, ["tourneyCount", True, "#", 1.0, "%1.0f", "str"]
, ["itm", True, "ITM%", 1.0, "%3.2f", "str"]
, ["1st", False, "1st", 1.0, "%1.0f", "str"]
, ["2nd", True, "2nd", 1.0, "%1.0f", "str"]
, ["3rd", True, "3rd", 1.0, "%1.0f", "str"]
, ["_1st", False, "1st", 1.0, "%1.0f", "str"]
, ["_2nd", True, "2nd", 1.0, "%1.0f", "str"]
, ["_3rd", True, "3rd", 1.0, "%1.0f", "str"]
, ["unknownRank", True, "Rank?", 1.0, "%1.0f", "str"]
, ["spent", True, "Spent", 1.0, "%3.2f", "str"]
, ["won", True, "Won", 1.0, "%3.2f", "str"]

139
pyfpdb/GuiTourneyViewer.py Normal file
View File

@ -0,0 +1,139 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#Copyright 2010 Steffen Schaumburg
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU Affero General Public License as published by
#the Free Software Foundation, version 3 of the License.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU Affero General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.
#In the "official" distribution you can find the license in agpl-3.0.txt.
import threading
import pygtk
pygtk.require('2.0')
import gtk
class GuiTourneyViewer (threading.Thread):
def __init__(self, config, db, sql, mainwin, debug=True):
self.db = db
self.mainVBox = gtk.VBox()
self.interfaceHBox = gtk.HBox()
self.mainVBox.pack_start(self.interfaceHBox, expand=False)
self.siteBox = gtk.combo_box_new_text()
for site in config.supported_sites:
self.siteBox.append_text(site)
self.siteBox.set_active(0)
self.interfaceHBox.add(self.siteBox)
label=gtk.Label("Enter the tourney number you want to display:")
self.interfaceHBox.add(label)
self.entryTourney = gtk.Entry()
self.interfaceHBox.add(self.entryTourney)
self.displayButton = gtk.Button("_Display")
self.displayButton.connect('clicked', self.displayClicked)
self.interfaceHBox.add(self.displayButton)
self.entryPlayer = gtk.Entry()
self.interfaceHBox.add(self.entryPlayer)
self.playerButton = gtk.Button("Display _Player")
self.playerButton.connect('clicked', self.displayPlayerClicked)
self.interfaceHBox.add(self.playerButton)
self.table = gtk.Table(columns=10, rows=9)
self.mainVBox.add(self.table)
self.mainVBox.show_all()
#end def __init__
def displayClicked(self, widget, data=None):
if self.prepare(10, 9):
result=self.db.getTourneyInfo(self.siteName, self.tourneyNo)
if result[1] == None:
self.table.destroy()
self.errorLabel=gtk.Label("Tournament not found - please ensure you imported it and selected the correct site")
self.mainVBox.add(self.errorLabel)
else:
x=0
y=0
for i in range(1,len(result[0])):
if y==9:
x+=2
y=0
label=gtk.Label(result[0][i])
self.table.attach(label,x,x+1,y,y+1)
if result[1][i]==None:
label=gtk.Label("N/A")
else:
label=gtk.Label(result[1][i])
self.table.attach(label,x+1,x+2,y,y+1)
y+=1
self.mainVBox.show_all()
#def displayClicked
def displayPlayerClicked(self, widget, data=None):
if self.prepare(4, 5):
result=self.db.getTourneyPlayerInfo(self.siteName, self.tourneyNo, self.playerName)
if result[1] == None:
self.table.destroy()
self.errorLabel=gtk.Label("Player or tourney not found - please ensure you imported it and selected the correct site")
self.mainVBox.add(self.errorLabel)
else:
x=0
y=0
for i in range(1,len(result[0])):
if y==5:
x+=2
y=0
label=gtk.Label(result[0][i])
self.table.attach(label,x,x+1,y,y+1)
if result[1][i]==None:
label=gtk.Label("N/A")
else:
label=gtk.Label(result[1][i])
self.table.attach(label,x+1,x+2,y,y+1)
y+=1
self.mainVBox.show_all()
#def displayPlayerClicked
def get_vbox(self):
"""returns the vbox of this thread"""
return self.mainVBox
#end def get_vbox
def prepare(self, columns, rows):
try: self.errorLabel.destroy()
except: pass
try:
self.tourneyNo=int(self.entryTourney.get_text())
except ValueError:
self.errorLabel=gtk.Label("invalid entry in tourney number - must enter numbers only")
self.mainVBox.add(self.errorLabel)
return False
self.siteName=self.siteBox.get_active_text()
self.playerName=self.entryPlayer.get_text()
self.table.destroy()
self.table=gtk.Table(columns=columns, rows=rows)
self.mainVBox.add(self.table)
return True
#end def readInfo
#end class GuiTourneyViewer

View File

@ -11,6 +11,36 @@
<import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import>
<gui_cash_stats>
<col col_name="game" disp_all="True" disp_posn="True" col_title="Game" xalignment="0.0" field_format="%s" field_type="str" />
<col col_name="hand" disp_all="False" disp_posn="False" col_title="Hand" xalignment="0.0" field_format="%s" field_type="str" />
<col col_name="plposition" disp_all="False" disp_posn="False" col_title="Posn" xalignment="1.0" field_format="%s" field_type="str" />
<col col_name="pname" disp_all="False" disp_posn="False" col_title="Name" xalignment="0.0" field_format="%s" field_type="str" />
<col col_name="n" disp_all="True" disp_posn="True" col_title="Hds" xalignment="1.0" field_format="%1.0f" field_type="str" />
<col col_name="avgseats" disp_all="False" disp_posn="False" col_title="Seats" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="vpip" disp_all="True" disp_posn="True" col_title="VPIP" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="pfr" disp_all="True" disp_posn="True" col_title="PFR" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="pf3" disp_all="True" disp_posn="True" col_title="PF3" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="aggfac" disp_all="True" disp_posn="True" col_title="AggFac" xalignment="1.0" field_format="%2.2f" field_type="str" />
<col col_name="aggfrq" disp_all="True" disp_posn="True" col_title="AggFreq" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="conbet" disp_all="True" disp_posn="True" col_title="ContBet" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="rfi" disp_all="True" disp_posn="True" col_title="RFI" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="steals" disp_all="True" disp_posn="True" col_title="Steals" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="saw_f" disp_all="True" disp_posn="True" col_title="Saw_F" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="sawsd" disp_all="True" disp_posn="True" col_title="SawSD" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="wtsdwsf" disp_all="True" disp_posn="True" col_title="WtSDwsF" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="wmsd" disp_all="True" disp_posn="True" col_title="W$SD" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="flafq" disp_all="True" disp_posn="True" col_title="FlAFq" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="tuafq" disp_all="True" disp_posn="True" col_title="TuAFq" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="rvafq" disp_all="True" disp_posn="True" col_title="RvAFq" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="pofafq" disp_all="False" disp_posn="False" col_title="PoFAFq" xalignment="1.0" field_format="%3.1f" field_type="str" />
<col col_name="net" disp_all="True" disp_posn="True" col_title="Net($)" xalignment="1.0" field_format="%6.2f" field_type="cash" />
<col col_name="bbper100" disp_all="True" disp_posn="True" col_title="bb/100" xalignment="1.0" field_format="%4.2f" field_type="str" />
<col col_name="rake" disp_all="True" disp_posn="True" col_title="Rake($)" xalignment="1.0" field_format="%6.2f" field_type="cash" />
<col col_name="bb100xr" disp_all="True" disp_posn="True" col_title="bbxr/100" xalignment="1.0" field_format="%4.2f" field_type="str" />
<col col_name="variance" disp_all="True" disp_posn="True" col_title="Variance" xalignment="1.0" field_format="%5.2f" field_type="str" />
</gui_cash_stats>
<!-- These values determine what stats are displayed in the HUD
The following values define how opponents' stats are done, the first 2 determine
@ -222,48 +252,45 @@ Left-Drag to Move"
</layout>
</site>
<site enabled="False"
site_name="Everleaf"
table_finder="Everleaf.exe"
screen_name="YOUR SCREEN NAME HERE"
site_path=""
HH_path=""
decoder="everleaf_decode_table"
<site HH_path="C:\Users\WindowsUserName\Documents\EverleafSiteName\HandHistory\PlayerName"
bgcolor="#000000"
converter="EverleafToFpdb"
supported_games="holdem">
<layout fav_seat="0" height="547" max="8" width="794">
<location seat="1" x="640" y="64"> </location>
<location seat="2" x="650" y="230"> </location>
<location seat="3" x="650" y="385"> </location>
<location seat="4" x="588" y="425"> </location>
<location seat="5" x="92" y="425"> </location>
<location seat="6" x="0" y="373"> </location>
<location seat="7" x="0" y="223"> </location>
<location seat="8" x="25" y="50"> </location>
decoder="everleaf_decode_table"
enabled="False"
fgcolor="#EEEEEE"
hudopacity="0.75"
screen_name="PlayerName"
site_name="Everleaf"
site_path="C:\Users\WindowsUserName\AppData\Roaming\EverleafSiteName\"
supported_games="holdem,omahahi,omahahilo"
table_finder="Poker.exe">
<layout fav_seat="0" height="546" max="6" width="792">
<location seat="0" x="0" y="0"> </location>
<location seat="1" x="586" y="109"> </location>
<location seat="2" x="605" y="283"> </location>
<location seat="3" x="544" y="383"> </location>
<location seat="4" x="67" y="383"> </location>
<location seat="5" x="5" y="284"> </location>
<location seat="6" x="61" y="111"> </location>
</layout>
<layout fav_seat="0" height="547" max="6" width="794">
<location seat="1" x="640" y="58"> </location>
<location seat="2" x="654" y="288"> </location>
<location seat="3" x="615" y="424"> </location>
<location seat="4" x="70" y="421"> </location>
<location seat="5" x="0" y="280"> </location>
<location seat="6" x="70" y="58"> </location>
<layout fav_seat="0" height="546" max="10" width="792">
<location seat="0" x="182" y="69"> </location>
<location seat="1" x="456" y="74"> </location>
<location seat="2" x="630" y="81"> </location>
<location seat="3" x="637" y="208"> </location>
<location seat="4" x="629" y="347"> </location>
<location seat="5" x="412" y="377"> </location>
<location seat="6" x="232" y="377"> </location>
<location seat="7" x="21" y="349"> </location>
<location seat="8" x="4" y="208"> </location>
<location seat="9" x="7" y="88"> </location>
<location seat="10" x="196" y="69"> </location>
</layout>
<layout fav_seat="0" height="547" max="2" width="794">
<layout fav_seat="0" height="546" max="2" width="792">
<location seat="1" x="651" y="288"> </location>
<location seat="2" x="10" y="288"> </location>
</layout>
<layout fav_seat="0" height="547" max="9" width="794">
<location seat="1" x="634" y="38"> </location>
<location seat="2" x="667" y="184"> </location>
<location seat="3" x="667" y="321"> </location>
<location seat="4" x="667" y="445"> </location>
<location seat="5" x="337" y="459"> </location>
<location seat="6" x="0" y="400"> </location>
<location seat="7" x="0" y="322"> </location>
<location seat="8" x="0" y="181"> </location>
<location seat="9" x="70" y="53"> </location>
</layout>
</site>
<site enabled="False"
@ -559,6 +586,8 @@ Left-Drag to Move"
<pu_stat pu_stat_name="playername"> </pu_stat>
<pu_stat pu_stat_name="totalprofit"> </pu_stat>
<pu_stat pu_stat_name="profit100"> </pu_stat>
<pu_stat pu_stat_name="bbper100"> </pu_stat>
<pu_stat pu_stat_name="BBper100"> </pu_stat>
<pu_stat pu_stat_name="n"> </pu_stat>
<pu_stat pu_stat_name="vpip"> </pu_stat>
<pu_stat pu_stat_name="pfr"> </pu_stat>
@ -643,6 +672,37 @@ Left-Drag to Move"
<hhc site="Carbon" converter="CarbonToFpdb"/>
</hhcs>
<!-- attribute names chosen to be in alphabetic order so that order can be set when retrieved -->
<gui_cash_stats>
<col col_name="game" col_title="Game" disp_all="True" disp_posn="True" field_format="%s" field_type="str" xalignment="0.0"/>
<col col_name="hand" col_title="Hand" disp_all="False" disp_posn="False" field_format="%s" field_type="str" xalignment="0.0"/>
<col col_name="plposition" col_title="Posn" disp_all="False" disp_posn="False" field_format="%s" field_type="str" xalignment="1.0"/>
<col col_name="pname" col_title="Name" disp_all="False" disp_posn="False" field_format="%s" field_type="str" xalignment="0.0"/>
<col col_name="n" col_title="Hds" disp_all="True" disp_posn="True" field_format="%1.0f" field_type="str" xalignment="1.0"/>
<col col_name="avgseats" col_title="Seats" disp_all="False" disp_posn="False" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="vpip" col_title="VPIP" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="pfr" col_title="PFR" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="pf3" col_title="PF3" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="aggfac" col_title="AggFac" disp_all="True" disp_posn="True" field_format="%2.2f" field_type="str" xalignment="1.0"/>
<col col_name="aggfrq" col_title="AggFreq" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="conbet" col_title="ContBet" disp_all="False" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="rfi" col_title="RFI" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="steals" col_title="Steals" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="saw_f" col_title="Saw_F" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="sawsd" col_title="SawSD" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="wtsdwsf" col_title="WtSDwsF" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="wmsd" col_title="W$SD" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="flafq" col_title="FlAFq" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="tuafq" col_title="TuAFq" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="rvafq" col_title="RvAFq" disp_all="True" disp_posn="True" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="pofafq" col_title="PoFAFq" disp_all="False" disp_posn="False" field_format="%3.1f" field_type="str" xalignment="1.0"/>
<col col_name="net" col_title="Net($)" disp_all="True" disp_posn="True" field_format="%6.2f" field_type="cash" xalignment="1.0"/>
<col col_name="bbper100" col_title="bb/100" disp_all="True" disp_posn="True" field_format="%4.2f" field_type="str" xalignment="1.0"/>
<col col_name="rake" col_title="Rake($)" disp_all="True" disp_posn="True" field_format="%6.2f" field_type="cash" xalignment="1.0"/>
<col col_name="bb100xr" col_title="bbxr/100" disp_all="True" disp_posn="True" field_format="%4.2f" field_type="str" xalignment="1.0"/>
<col col_name="variance" col_title="Variance" disp_all="True" disp_posn="True" field_format="%5.2f" field_type="str" xalignment="1.0"/>
</gui_cash_stats>
<supported_databases>
<!-- <database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD"></database> -->
<database db_ip="localhost" db_server="sqlite" db_name="fpdb.db3" db_user="fpdb" db_pass="fpdb"/>

View File

@ -79,13 +79,13 @@ class Hand(object):
self.fee = None # the Database code is looking for this one .. ?
self.level = None
self.mixed = None
self.speed = None
self.isRebuy = None
self.isAddOn = None
self.isKO = None
self.speed = "Normal"
self.isRebuy = False
self.isAddOn = False
self.isKO = False
self.koBounty = None
self.isMatrix = None
self.isShootout = None
self.isMatrix = False
self.isShootout = False
self.added = None
self.addedCurrency = None
self.tourneyComment = None
@ -683,9 +683,15 @@ class HoldemOmahaHand(Hand):
hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(self)
hhc.markStreets(self)
if self.cancelled:
return
hhc.readBlinds(self)
try: hhc.readBlinds(self)
except:
print "*** Parse error reading blinds (check compilePlayerRegexs as a likely culprit)", self
return
hhc.readAntes(self)
hhc.readButton(self)
hhc.readHeroCards(self)

View File

@ -41,9 +41,9 @@ import Hand
from Exceptions import FpdbParseError
import Configuration
import gettext
gettext.install('fpdb')
#import gettext
#trans=gettext.translation("fpdb", "/home/steffen/poker/fpdb-dev/pyfpdb/locale", languages=["de"])
#trans.install()
import pygtk
import gtk
@ -441,6 +441,7 @@ or None if we fail to get the info """
pass
else:
print "unable to read file with any codec in list!", self.in_path
self.obs = ""
elif self.filetype == "xml":
doc = xml.dom.minidom.parse(filename)
self.doc = doc

View File

@ -33,16 +33,16 @@ def run(config, db):
#print "start of IS.run"
server=None
#try:
#print "useSSL",config.email.useSsl,"host",config.email.host
if config.email.useSsl:
server = IMAP4_SSL(config.email.host)
#print "useSSL",config.useSsl,"host",config.host
if config.useSsl:
server = IMAP4_SSL(config.host)
else:
server = IMAP4(config.email.host)
response = server.login(config.email.username, config.email.password) #TODO catch authentication error
server = IMAP4(config.host)
response = server.login(config.username, config.password) #TODO catch authentication error
print "response to logging in:",response
#print "server.list():",server.list() #prints list of folders
response = server.select(config.email.folder)
response = server.select(config.folder)
#print "response to selecting INBOX:",response
if response[0]!="OK":
raise error #TODO: show error message

View File

@ -96,7 +96,7 @@ class PartyPoker(HandHistoryConverter):
re_NoSmallBlind = re.compile(
'^There is no Small Blind in this hand as the Big Blind '
'of the previous hand left the table', re.MULTILINE)
re_20BBmin = re.compile(r"Table 20BB Min")
def allHandsAsList(self):
list = HandHistoryConverter.allHandsAsList(self)
@ -185,6 +185,7 @@ class PartyPoker(HandHistoryConverter):
info = {}
m = self._getGameType(handText)
m_20BBmin = self.re_20BBmin.search(handText)
if m is None:
return None
@ -216,7 +217,18 @@ class PartyPoker(HandHistoryConverter):
info['type'] = 'ring'
if info['type'] == 'ring':
info['sb'], info['bb'] = ringBlinds(mg['RINGLIMIT'])
if m_20BBmin is None:
bb = float(mg['RINGLIMIT'])/100.0
else:
bb = float(mg['RINGLIMIT'])/40.0
if bb == 0.25:
sb = 0.10
else:
sb = bb/2.0
info['bb'] = "%.2f" % (bb)
info['sb'] = "%.2f" % (sb)
info['currency'] = currencies[mg['CURRENCY']]
else:
info['sb'] = clearMoneyString(mg['SB'])
@ -483,13 +495,6 @@ class PartyPoker(HandHistoryConverter):
print 'party', 'getTableTitleRe', table_number
return table_name
def ringBlinds(ringLimit):
"Returns blinds for current limit in cash games"
ringLimit = float(clearMoneyString(ringLimit))
if ringLimit == 5.: ringLimit = 4.
return ('%.2f' % (ringLimit/200.), '%.2f' % (ringLimit/100.) )
def clearMoneyString(money):
"Renders 'numbers' like '1 200' and '2,000'"
return money.replace(' ', '').replace(',', '')

View File

@ -47,9 +47,13 @@ class PokerStars(HandHistoryConverter):
'0.40': ('0.10', '0.20'), '0.50': ('0.10', '0.25'), '1.00': ('0.25', '0.50'),
'2.00': ('0.50', '1.00'), '2': ('0.50', '1.00'), '4' : ('1.00', '2.00'),
'4.00': ('1.00', '2.00'), '6': ('1.00', '3.00'), '6.00': ('1.00', '3.00'),
'10.00': ('2.00', '5.00'), '20.00': ('5.00', '10.00'), '30.00': ('10.00', '15.00'),
'60.00': ('15.00', '30.00'), '100.00': ('25.00', '50.00'), '200.00': ('50.00', '100.00'),
'400.00': ('100.00', '200.00'), '1000.00': ('250.00', '500.00')}
'10.00': ('2.00', '5.00'), '10': ('2.00', '5.00'), '20.00': ('5.00', '10.00'),
'20': ('5.00', '10.00'), '30.00': ('10.00', '15.00'), '30': ('10.00', '15.00'),
'60.00': ('15.00', '30.00'), '60': ('15.00', '30.00'), '100.00': ('25.00', '50.00'),
'100': ('25.00', '50.00'),'200.00': ('50.00', '100.00'), '200': ('50.00', '100.00'),
'400.00': ('100.00', '200.00'), '400': ('100.00', '200.00'),'1000.00': ('250.00', '500.00'),
'1000': ('250.00', '500.00')
}
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl', 'LIMIT':'fl' }
games = { # base, category
@ -74,7 +78,7 @@ class PokerStars(HandHistoryConverter):
# here's how I plan to use LS
(?P<BUYIN>(?P<BIAMT>[%(LS)s\d\.]+)?\+?(?P<BIRAKE>[%(LS)s\d\.]+)?\+?(?P<BOUNTY>[%(LS)s\d\.]+)?\s?(?P<TOUR_ISO>%(LEGAL_ISO)s)?|Freeroll)\s+)?
# close paren of tournament info
(?P<MIXED>HORSE|8\-Game|HOSE)?\s?\(?
(?P<MIXED>HORSE|8\-Game|HOSE|Mixed PLH/PLO)?\s?\(?
(?P<GAME>Hold\'em|Razz|RAZZ|7\sCard\sStud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi|Triple\sDraw\s2\-7\sLowball|5\sCard\sDraw)\s
(?P<LIMIT>No\sLimit|Limit|LIMIT|Pot\sLimit)\)?,?\s
(-\s)?

View File

@ -137,21 +137,21 @@ class Sql:
if db_server == 'mysql':
self.query['createBackingsTable'] = """CREATE TABLE Backings (
id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
tourneysPlayerId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (tourneysPlayerId) REFERENCES TourneysPlayers(id),
tourneysPlayersId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id),
playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
buyInPercentage FLOAT UNSIGNED NOT NULL,
payOffPercentage FLOAT UNSIGNED NOT NULL) ENGINE=INNODB"""
elif db_server == 'postgresql':
self.query['createBackingsTable'] = """CREATE TABLE Backings (
id BIGSERIAL, PRIMARY KEY (id),
tourneysPlayerId INT NOT NULL, FOREIGN KEY (tourneysPlayerId) REFERENCES TourneysPlayers(id),
tourneysPlayersId INT NOT NULL, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id),
playerId INT NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
buyInPercentage FLOAT NOT NULL,
payOffPercentage FLOAT NOT NULL)"""
elif db_server == 'sqlite':
self.query['createBackingsTable'] = """CREATE TABLE Backings (
id INTEGER PRIMARY KEY,
tourneysPlayerId INT NOT NULL,
tourneysPlayersId INT NOT NULL,
playerId INT NOT NULL,
buyInPercentage REAL UNSIGNED NOT NULL,
payOffPercentage REAL UNSIGNED NOT NULL)"""
@ -543,6 +543,7 @@ class Sql:
position CHAR(1),
seatNo SMALLINT NOT NULL,
sitout BOOLEAN NOT NULL,
wentAllInOnStreet SMALLINT,
card1 smallint NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
card2 smallint NOT NULL,
@ -659,6 +660,7 @@ class Sql:
position CHAR(1),
seatNo SMALLINT NOT NULL,
sitout BOOLEAN NOT NULL,
wentAllInOnStreet SMALLINT,
card1 smallint NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
card2 smallint NOT NULL,
@ -774,6 +776,7 @@ class Sql:
position TEXT,
seatNo INT NOT NULL,
sitout BOOLEAN NOT NULL,
wentAllInOnStreet INT,
card1 INT NOT NULL, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
card2 INT NOT NULL,
@ -915,7 +918,7 @@ class Sql:
commentTs timestamp without time zone)"""
elif db_server == 'sqlite':
self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers (
id INT PRIMARY KEY,
id INTEGER PRIMARY KEY,
tourneyId INT,
playerId INT,
rank INT,
@ -960,7 +963,7 @@ class Sql:
commentTs timestamp without time zone)"""
elif db_server == 'sqlite':
self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions (
id INT PRIMARY KEY,
id INTEGER PRIMARY KEY,
handsPlayerId BIGINT,
street SMALLINT,
actionNo SMALLINT,
@ -1333,8 +1336,6 @@ class Sql:
and (p.siteId = %s or %s = -1)
"""
self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
self.query['get_stats_from_hand'] = """
SELECT hc.playerId AS player_id,
hp.seatNo AS seat,
@ -1397,6 +1398,7 @@ class Sql:
sum(hc.foldToStreet4CBChance) AS f_cb_opp_4,
sum(hc.foldToStreet4CBDone) AS f_cb_4,
sum(hc.totalProfit) AS net,
sum(gt.bigblind) AS bigblind,
sum(hc.street1CheckCallRaiseChance) AS ccr_opp_1,
sum(hc.street1CheckCallRaiseDone) AS ccr_1,
sum(hc.street2CheckCallRaiseChance) AS ccr_opp_2,
@ -1425,6 +1427,7 @@ class Sql:
INNER JOIN HudCache hc ON ( hc.PlayerId = hp.PlayerId+0
AND hc.gametypeId+0 = h.gametypeId+0)
INNER JOIN Players p ON (p.id = hp.PlayerId+0)
INNER JOIN Gametypes gt ON (gt.id = hc.gametypeId)
WHERE h.id = %s
AND hc.styleKey > %s
/* styleKey is currently 'd' (for date) followed by a yyyymmdd
@ -1496,6 +1499,7 @@ class Sql:
sum(hc.foldToStreet4CBChance) AS f_cb_opp_4,
sum(hc.foldToStreet4CBDone) AS f_cb_4,
sum(hc.totalProfit) AS net,
sum(gt.bigblind) AS bigblind,
sum(hc.street1CheckCallRaiseChance) AS ccr_opp_1,
sum(hc.street1CheckCallRaiseDone) AS ccr_1,
sum(hc.street2CheckCallRaiseChance) AS ccr_opp_2,
@ -1523,6 +1527,7 @@ class Sql:
INNER JOIN HandsPlayers hp ON (hp.handId = h.id)
INNER JOIN HudCache hc ON (hc.playerId = hp.playerId)
INNER JOIN Players p ON (p.id = hc.playerId)
INNER JOIN Gametypes gt ON (gt.id = hc.gametypeId)
WHERE h.id = %s
AND ( /* 2 separate parts for hero and opponents */
( hp.playerId != %s
@ -1622,6 +1627,7 @@ class Sql:
cast(hp2.foldToStreet4CBChance as <signed>integer) AS f_cb_opp_4,
cast(hp2.foldToStreet4CBDone as <signed>integer) AS f_cb_4,
cast(hp2.totalProfit as <signed>integer) AS net,
cast(gt.bigblind as <signed>integer) AS bigblind,
cast(hp2.street1CheckCallRaiseChance as <signed>integer) AS ccr_opp_1,
cast(hp2.street1CheckCallRaiseDone as <signed>integer) AS ccr_1,
cast(hp2.street2CheckCallRaiseChance as <signed>integer) AS ccr_opp_2,
@ -1651,6 +1657,7 @@ class Sql:
INNER JOIN HandsPlayers hp ON (h.id = hp.handId) /* players in this hand */
INNER JOIN HandsPlayers hp2 ON (hp2.playerId+0 = hp.playerId+0 AND (hp2.handId = h2.id+0)) /* other hands by these players */
INNER JOIN Players p ON (p.id = hp2.PlayerId+0)
INNER JOIN Gametypes gt ON (gt.id = h2.gametypeId)
WHERE hp.handId = %s
/* check activeseats once this data returned (don't want to do that here as it might
assume a session ended just because the number of seats dipped for a few hands)
@ -1724,6 +1731,7 @@ class Sql:
cast(hp2.foldToStreet4CBChance as <signed>integer) AS f_cb_opp_4,
cast(hp2.foldToStreet4CBDone as <signed>integer) AS f_cb_4,
cast(hp2.totalProfit as <signed>integer) AS net,
cast(gt.bigblind as <signed>integer) AS bigblind,
cast(hp2.street1CheckCallRaiseChance as <signed>integer) AS ccr_opp_1,
cast(hp2.street1CheckCallRaiseDone as <signed>integer) AS ccr_1,
cast(hp2.street2CheckCallRaiseChance as <signed>integer) AS ccr_opp_2,
@ -1754,6 +1762,7 @@ class Sql:
INNER JOIN HandsPlayers hp2 ON ( hp2.playerId+0 = hp.playerId+0
AND hp2.handId = h2.id) /* other hands by these players */
INNER JOIN Players p ON (p.id = hp2.PlayerId+0)
INNER JOIN Gametypes gt ON (gt.id = h2.gametypeId)
WHERE h.id = %s
/* check activeseats once this data returned (don't want to do that here as it might
assume a session ended just because the number of seats dipped for a few hands)
@ -1827,6 +1836,7 @@ class Sql:
cast(hp2.foldToStreet4CBChance as <signed>integer) AS f_cb_opp_4,
cast(hp2.foldToStreet4CBDone as <signed>integer) AS f_cb_4,
cast(hp2.totalProfit as <signed>integer) AS net,
cast(gt.bigblind as <signed>integer) AS bigblind,
cast(hp2.street1CheckCallRaiseChance as <signed>integer) AS ccr_opp_1,
cast(hp2.street1CheckCallRaiseDone as <signed>integer) AS ccr_1,
cast(hp2.street2CheckCallRaiseChance as <signed>integer) AS ccr_opp_2,
@ -1857,6 +1867,7 @@ class Sql:
INNER JOIN HandsPlayers hp2 ON ( hp2.playerId+0 = hp.playerId+0
AND hp2.handId = h2.id) /* other hands by these players */
INNER JOIN Players p ON (p.id = hp2.PlayerId+0)
INNER JOIN Gametypes gt ON (gt.id = h2.gametypeId)
WHERE h.id = %s
/* check activeseats once this data returned (don't want to do that here as it might
assume a session ended just because the number of seats dipped for a few hands)
@ -1997,8 +2008,6 @@ class Sql:
self.query['getPlayerIdBySite'] = """SELECT id from Players where name = %s AND siteId = %s"""
# used in *Filters:
self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
self.query['getGames'] = """SELECT DISTINCT category from Gametypes"""
#self.query['getLimits'] = already defined further up
self.query['getLimits2'] = """SELECT DISTINCT type, limitType, bigBlind
from Gametypes
@ -2016,6 +2025,7 @@ class Sql:
, limitType
, bigBlind as bb_or_buyin
from Gametypes gt
WHERE type = 'ring'
order by type, limitType DESC, bb_or_buyin DESC"""
if db_server == 'mysql':
@ -2389,7 +2399,7 @@ class Sql:
select s.name AS siteName
,t.tourneyTypeId AS tourneyTypeId
,tt.currency AS currency
,(CASE WHEN tt.currency = "USD" THEN tt.buyIn/100.0 ELSE tt.buyIn END) AS buyIn
,(CASE WHEN tt.currency = 'USD' THEN tt.buyIn/100.0 ELSE tt.buyIn END) AS buyIn
,tt.fee/100.0 AS fee
,tt.category AS category
,tt.limitType AS limitType
@ -2397,11 +2407,11 @@ class Sql:
,COUNT(1) AS tourneyCount
,SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END) AS unknownRank
,SUM(CASE WHEN winnings > 0 THEN 1 ELSE 0 END)/(COUNT(1) - SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END)) AS itm
,SUM(CASE WHEN rank = 1 THEN 1 ELSE 0 END) AS 1st
,SUM(CASE WHEN rank = 2 THEN 1 ELSE 0 END) AS 2nd
,SUM(CASE WHEN rank = 3 THEN 1 ELSE 0 END) AS 3rd
,SUM(CASE WHEN rank = 1 THEN 1 ELSE 0 END) AS _1st
,SUM(CASE WHEN rank = 2 THEN 1 ELSE 0 END) AS _2nd
,SUM(CASE WHEN rank = 3 THEN 1 ELSE 0 END) AS _3rd
,SUM(tp.winnings)/100.0 AS won
,SUM(CASE WHEN tt.currency = "USD" THEN (tt.buyIn+tt.fee)/100.0 ELSE tt.buyIn END) AS spent
,SUM(CASE WHEN tt.currency = 'USD' THEN (tt.buyIn+tt.fee)/100.0 ELSE tt.buyIn END) AS spent
,SUM(tp.winnings)/SUM(tt.buyin+tt.fee)*100.0-100 AS roi
,SUM(tp.winnings-(tt.buyin+tt.fee))/100.0/(COUNT(1)-SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END)) AS profitPerTourney
from TourneysPlayers tp
@ -2416,9 +2426,72 @@ class Sql:
,playerName
,siteName"""
elif db_server == 'postgresql':
self.query['tourneyPlayerDetailedStats'] = """TODO"""
# sc: itm and profitPerTourney changed to "ELSE 0" to avoid divide by zero error as temp fix
# proper fix should use coalesce() or case ... when ... to work in all circumstances
self.query['tourneyPlayerDetailedStats'] = """
select s.name AS siteName
,t.tourneyTypeId AS tourneyTypeId
,tt.currency AS currency
,(CASE WHEN tt.currency = 'USD' THEN tt.buyIn/100.0 ELSE tt.buyIn END) AS buyIn
,tt.fee/100.0 AS fee
,tt.category AS category
,tt.limitType AS limitType
,p.name AS playerName
,COUNT(1) AS tourneyCount
,SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END) AS unknownRank
,SUM(CASE WHEN winnings > 0 THEN 1 ELSE 0 END)
/(COUNT(1) - SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 0 END)) AS itm
,SUM(CASE WHEN rank = 1 THEN 1 ELSE 0 END) AS _1st
,SUM(CASE WHEN rank = 2 THEN 1 ELSE 0 END) AS _2nd
,SUM(CASE WHEN rank = 3 THEN 1 ELSE 0 END) AS _3rd
,SUM(tp.winnings)/100.0 AS won
,SUM(CASE WHEN tt.currency = 'USD' THEN (tt.buyIn+tt.fee)/100.0 ELSE tt.buyIn END) AS spent
,SUM(tp.winnings)/SUM(tt.buyin+tt.fee)*100.0-100 AS roi
,SUM(tp.winnings-(tt.buyin+tt.fee))/100.0
/(COUNT(1)-SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 0 END)) AS profitPerTourney
from TourneysPlayers tp
inner join Tourneys t on (t.id = tp.tourneyId)
inner join TourneyTypes tt on (tt.Id = t.tourneyTypeId)
inner join Sites s on (s.Id = tt.siteId)
inner join Players p on (p.Id = tp.playerId)
where tp.playerId in <nametest> <sitetest>
and to_char(t.startTime, 'YYYY-MM-DD HH24:MI:SS') <datestest>
group by tourneyTypeId, s.name, playerName, tt.currency, tt.buyin, tt.fee
, tt.category, tt.limitType
order by tourneyTypeId
,playerName
,siteName"""
elif db_server == 'sqlite':
self.query['tourneyPlayerDetailedStats'] = """TODO"""
self.query['tourneyPlayerDetailedStats'] = """
select s.name AS siteName
,t.tourneyTypeId AS tourneyTypeId
,tt.currency AS currency
,(CASE WHEN tt.currency = 'USD' THEN tt.buyIn/100.0 ELSE tt.buyIn END) AS buyIn
,tt.fee/100.0 AS fee
,tt.category AS category
,tt.limitType AS limitType
,p.name AS playerName
,COUNT(1) AS tourneyCount
,SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END) AS unknownRank
,SUM(CASE WHEN winnings > 0 THEN 1 ELSE 0 END)/(COUNT(1) - SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END)) AS itm
,SUM(CASE WHEN rank = 1 THEN 1 ELSE 0 END) AS _1st
,SUM(CASE WHEN rank = 2 THEN 1 ELSE 0 END) AS _2nd
,SUM(CASE WHEN rank = 3 THEN 1 ELSE 0 END) AS _3rd
,SUM(tp.winnings)/100.0 AS won
,SUM(CASE WHEN tt.currency = 'USD' THEN (tt.buyIn+tt.fee)/100.0 ELSE tt.buyIn END) AS spent
,SUM(tp.winnings)/SUM(tt.buyin+tt.fee)*100.0-100 AS roi
,SUM(tp.winnings-(tt.buyin+tt.fee))/100.0/(COUNT(1)-SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END)) AS profitPerTourney
from TourneysPlayers tp
inner join Tourneys t on (t.id = tp.tourneyId)
inner join TourneyTypes tt on (tt.Id = t.tourneyTypeId)
inner join Sites s on (s.Id = tt.siteId)
inner join Players p on (p.Id = tp.playerId)
where tp.playerId in <nametest> <sitetest>
and datetime(t.startTime) <datestest>
group by tourneyTypeId, playerName
order by tourneyTypeId
,playerName
,siteName"""
if db_server == 'mysql':
self.query['playerStats'] = """
@ -2767,6 +2840,8 @@ class Sql:
order by stats.category, stats.limitType, stats.bigBlindDesc desc
<orderbyseats>, cast(stats.PlPosition as signed)
"""
elif db_server == 'sqlite':
self.query['playerStatsByPosition'] = ""#TODO
else: # assume postgresql
self.query['playerStatsByPosition'] = """
select /* stats from hudcache */
@ -2937,7 +3012,7 @@ class Sql:
INNER JOIN Players p on (p.Id = hp.playerId)
WHERE hp.playerId in <player_test>
AND date_format(h.startTime, '%Y-%m-%d') <datestest>
AND gt.type is 'ring'
AND gt.type LIKE 'ring'
ORDER by time"""
elif db_server == 'postgresql':
self.query['sessionStats'] = """
@ -2949,7 +3024,7 @@ class Sql:
INNER JOIN Players p on (p.Id = hp.playerId)
WHERE hp.playerId in <player_test>
AND h.startTime <datestest>
AND gt.type is 'ring'
AND gt.type LIKE 'ring'
ORDER by time"""
elif db_server == 'sqlite':
self.query['sessionStats'] = """
@ -2978,7 +3053,7 @@ class Sql:
,playerId
,activeSeats
,position
,tourneyTypeId
<tourney_insert_clause>
,styleKey
,HDs
,wonWhenSeenStreet1
@ -3068,7 +3143,7 @@ class Sql:
when hp.position = '9' then 'E'
else 'E'
end AS hc_position
,t.tourneyTypeId
<tourney_select_clause>
,date_format(h.startTime, 'd%y%m%d')
,count(1)
,sum(wonWhenSeenStreet1)
@ -3142,14 +3217,13 @@ class Sql:
,sum(hp.street4Raises)
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
INNER JOIN TourneysPlayers tp ON (tp.id = hp.tourneysPlayersId)
INNER JOIN Tourneys t ON (t.id = tp.tourneyId)
<tourney_join_clause>
<where_clause>
GROUP BY h.gametypeId
,hp.playerId
,h.seats
,hc_position
,t.tourneyTypeId
<tourney_group_clause>
,date_format(h.startTime, 'd%y%m%d')
"""
elif db_server == 'postgresql':
@ -3159,7 +3233,7 @@ class Sql:
,playerId
,activeSeats
,position
,tourneyTypeId
<tourney_insert_clause>
,styleKey
,HDs
,wonWhenSeenStreet1
@ -3249,7 +3323,7 @@ class Sql:
when hp.position = '9' then 'E'
else 'E'
end AS hc_position
,t.tourneyTypeId
<tourney_select_clause>
,'d' || to_char(h.startTime, 'YYMMDD')
,count(1)
,sum(wonWhenSeenStreet1)
@ -3323,14 +3397,13 @@ class Sql:
,sum(CAST(hp.street4Raises as integer))
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
INNER JOIN TourneysPlayers tp ON (tp.id = hp.tourneysPlayersId)
INNER JOIN Tourneys t ON (t.id = tp.tourneyId)
<tourney_join_clause>
<where_clause>
GROUP BY h.gametypeId
,hp.playerId
,h.seats
,hc_position
,t.tourneyTypeId
<tourney_group_clause>
,to_char(h.startTime, 'YYMMDD')
"""
else: # assume sqlite
@ -3340,7 +3413,7 @@ class Sql:
,playerId
,activeSeats
,position
,tourneyTypeId
<tourney_insert_clause>
,styleKey
,HDs
,wonWhenSeenStreet1
@ -3430,7 +3503,7 @@ class Sql:
when hp.position = '9' then 'E'
else 'E'
end AS hc_position
,t.tourneyTypeId
<tourney_select_clause>
,'d' || substr(strftime('%Y%m%d', h.startTime),3,7)
,count(1)
,sum(wonWhenSeenStreet1)
@ -3504,14 +3577,13 @@ class Sql:
,sum(CAST(hp.street4Raises as integer))
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
INNER JOIN TourneysPlayers tp ON (tp.id = hp.tourneysPlayersId)
INNER JOIN Tourneys t ON (t.id = tp.tourneyId)
<tourney_join_clause>
<where_clause>
GROUP BY h.gametypeId
,hp.playerId
,h.seats
,hc_position
,t.tourneyTypeId
<tourney_group_clause>
,'d' || substr(strftime('%Y%m%d', h.startTime),3,7)
"""
@ -3798,6 +3870,22 @@ class Sql:
WHERE tt.siteId=%s AND t.siteTourneyNo=%s
"""
self.query['getTourneyInfo'] = """SELECT tt.*, t.*
FROM Tourneys t
INNER JOIN TourneyTypes tt ON (t.tourneyTypeId = tt.id)
INNER JOIN Sites s ON (tt.siteId = s.id)
WHERE s.name=%s AND t.siteTourneyNo=%s
"""
self.query['getTourneyPlayerInfo'] = """SELECT tp.*
FROM Tourneys t
INNER JOIN TourneyTypes tt ON (t.tourneyTypeId = tt.id)
INNER JOIN Sites s ON (tt.siteId = s.id)
INNER JOIN TourneysPlayers tp ON (tp.tourneyId = t.id)
INNER JOIN Players p ON (p.id = tp.playerId)
WHERE s.name=%s AND t.siteTourneyNo=%s AND p.name=%s
"""
self.query['insertTourney'] = """INSERT INTO Tourneys
(tourneyTypeId, siteTourneyNo, entries, prizepool,
startTime, endTime, tourneyName, matrixIdProcessed,

View File

@ -48,7 +48,7 @@
# 6 For each stat you make add a line to the __main__ function to test it.
# Standard Library modules
#import sys
import sys
# pyGTK modules
import pygtk
@ -60,6 +60,10 @@ import Configuration
import Database
import Charset
import logging
# logging has been set up in fpdb.py or HUD_main.py, use their settings:
log = logging.getLogger("db")
re_Places = re.compile("_[0-9]$")
re_Percent = re.compile("%$")
@ -79,12 +83,23 @@ def do_stat(stat_dict, player = 24, stat = 'vpip'):
else:
base = stat[0:-2]
places = int(stat[-1:])
result = (0.0, '0.0', 'notset=0', 'notset=0', '0', 'not set')
try:
result = eval("%(stat)s(stat_dict, %(player)d)" % {'stat': base, 'player': player})
except:
pass #
log.info("exception getting stat "+base+" for player "+str(player)+str(sys.exc_info()))
log.debug("result = %s" % str(result) )
match = re_Percent.search(result[1])
try:
if match is None:
result = (result[0], "%.*f" % (places, result[0]), result[2], result[3], result[4], result[5])
else:
result = (result[0], "%.*f%%" % (places, 100*result[0]), result[2], result[3], result[4], result[5])
except:
log.info( "error: %s" % str(sys.exc_info()))
raise
return result
# OK, for reference the tuple returned by the stat is:
@ -198,7 +213,7 @@ def wmsd(stat_dict, player):
)
def profit100(stat_dict, player):
""" Profit won per 100 hands (no decimal places)."""
""" Profit won per 100 hands."""
stat = 0.0
try:
stat = float(stat_dict[player]['net'])/float(stat_dict[player]['n'])
@ -212,13 +227,57 @@ def profit100(stat_dict, player):
except:
print "exception calcing p/100: 100 * %d / %d" % (stat_dict[player]['net'], stat_dict[player]['n'])
return (stat,
'%.0f' % (0),
'p=%.0f' % (0),
'p/100=%.0f' % (0),
'%.0f' % (0.0),
'p=%.0f' % (0.0),
'p/100=%.0f' % (0.0),
'(%d/%d)' % (0, 0),
'profit/100hands'
)
def bbper100(stat_dict, player):
""" big blinds won per 100 hands."""
stat = 0.0
try:
stat = 100.0 * float(stat_dict[player]['net']) / float(stat_dict[player]['bigblind'])
return (stat,
'%5.3f' % (stat),
'bb100=%5.3f' % (stat),
'bb100=%5.3f' % (stat),
'(%d,%d)' % (100*stat_dict[player]['net'],stat_dict[player]['bigblind']),
'big blinds/100 hands'
)
except:
log.info("exception calcing bb/100: "+str(stat_dict[player]))
return (stat,
'%.0f' % (0),
'bb100=%.0f' % (0),
'bb100=%.0f' % (0),
'(%f)' % (0),
'big blinds/100 hands'
)
def BBper100(stat_dict, player):
""" Big Bets won per 100 hands."""
stat = 0.0
try:
stat = 50 * float(stat_dict[player]['net']) / float(stat_dict[player]['bigblind'])
return (stat,
'%5.3f' % (stat),
'BB100=%5.3f' % (stat),
'BB100=%5.3f' % (stat),
'(%d,%d)' % (100*stat_dict[player]['net'],2*stat_dict[player]['bigblind']),
'Big Bets/100 hands'
)
except:
log.info("exception calcing BB/100: "+str(stat_dict[player]))
return (stat,
'%.0f' % (0.0),
'BB100=%.0f' % (0.0),
'BB100=%.0f' % (0.0),
'(%f)' % (0.0),
'Big Bets/100 hands'
)
def saw_f(stat_dict, player):
""" Saw flop/4th."""
try:
@ -711,10 +770,10 @@ def ffreq1(stat_dict, player):
)
except:
return (stat,
'%3.1f' % (0) + '%',
'ff1=%3.1f' % (0) + '%',
'ff_1=%3.1f' % (0) + '%',
'(%d/%d)' % (0, 0),
'NA',
'ff1=NA',
'ff_1=NA',
'(0/0)',
'% fold frequency flop/4th'
)
@ -782,13 +841,27 @@ def ffreq4(stat_dict, player):
)
if __name__== "__main__":
statlist = dir()
misslist = [ "Configuration", "Database", "Charset", "codecs", "encoder"
, "do_stat", "do_tip", "GInitiallyUnowned", "gtk", "pygtk"
, "re", "re_Percent", "re_Places"
]
statlist = [ x for x in statlist if x not in dir(sys) ]
statlist = [ x for x in statlist if x not in dir(codecs) ]
statlist = [ x for x in statlist if x not in misslist ]
#print "statlist is", statlist
c = Configuration.Config()
#TODO: restore the below code. somehow it creates a version 119 DB but commenting this out makes it print a stat list
#db_connection = Database.Database(c)
#h = db_connection.get_last_hand()
#stat_dict = db_connection.get_stats_from_hand(h, "ring")
db_connection = Database.Database(c)
h = db_connection.get_last_hand()
stat_dict = db_connection.get_stats_from_hand(h, "ring")
#for player in stat_dict.keys():
for player in stat_dict.keys():
print "Example stats, player =", player, "hand =", h, ":"
for attr in statlist:
print " ", do_stat(stat_dict, player=player, stat=attr)
break
#print "player = ", player, do_stat(stat_dict, player = player, stat = 'vpip')
#print "player = ", player, do_stat(stat_dict, player = player, stat = 'pfr')
#print "player = ", player, do_stat(stat_dict, player = player, stat = 'wtsd')
@ -820,11 +893,7 @@ if __name__== "__main__":
print "\n\nLegal stats:"
print "(add _0 to name to display with 0 decimal places, _1 to display with 1, etc)\n"
for attr in dir():
if attr.startswith('__'): continue
if attr in ("Configuration", "Database", "GInitiallyUnowned", "gtk", "pygtk",
"player", "c", "db_connection", "do_stat", "do_tip", "stat_dict",
"h", "re", "re_Percent", "re_Places"): continue
for attr in statlist:
print "%-14s %s" % (attr, eval("%s.__doc__" % (attr)))
# print " <pu_stat pu_stat_name = \"%s\"> </pu_stat>" % (attr)
print

View File

@ -20,6 +20,10 @@ import sys
import re
import Queue
#import gettext
#trans=gettext.translation("fpdb", "locale", ["en_GB"])
#trans.install()
# if path is set to use an old version of python look for a new one:
# (does this work in linux?)
if os.name == 'nt' and sys.version[0:3] not in ('2.5', '2.6') and '-r' not in sys.argv:
@ -103,9 +107,10 @@ import GuiPrefs
import GuiLogView
import GuiDatabase
import GuiBulkImport
import ImapFetcher
import GuiImapFetcher
import GuiRingPlayerStats
import GuiTourneyPlayerStats
import GuiTourneyViewer
import GuiPositionalStats
import GuiAutoImport
import GuiGraphViewer
@ -785,7 +790,7 @@ class fpdb:
<menu action="import">
<menuitem action="sethharchive"/>
<menuitem action="bulkimp"/>
<menuitem action="imapsummaries"/>
<menuitem action="imapimport"/>
<menuitem action="autoimp"/>
</menu>
<menu action="viewers">
@ -794,6 +799,7 @@ class fpdb:
<menuitem action="graphs"/>
<menuitem action="ringplayerstats"/>
<menuitem action="tourneyplayerstats"/>
<menuitem action="tourneyviewer"/>
<menuitem action="posnstats"/>
<menuitem action="sessionstats"/>
</menu>
@ -826,14 +832,15 @@ class fpdb:
('import', None, '_Import'),
('sethharchive', None, '_Set HandHistory Archive Directory', None, 'Set HandHistory Archive Directory', self.select_hhArchiveBase),
('bulkimp', None, '_Bulk Import', '<control>B', 'Bulk Import', self.tab_bulk_import),
('imapsummaries', None, '_Import Tourney Summaries through eMail/IMAP', '<control>I', 'Auto Import and HUD', self.import_imap_summaries),
('imapimport', None, '_Import through eMail/IMAP', '<control>I', 'Import through eMail/IMAP', self.tab_imap_import),
('viewers', None, '_Viewers'),
('autoimp', None, '_Auto Import and HUD', '<control>A', 'Auto Import and HUD', self.tab_auto_import),
('hudConfigurator', None, '_HUD Configurator', '<control>H', 'HUD Configurator', self.diaHudConfigurator),
('graphs', None, '_Graphs', '<control>G', 'Graphs', self.tabGraphViewer),
('ringplayerstats', None, 'Ring _Player Stats (tabulated view)', '<control>P', 'Ring Player Stats (tabulated view)', self.tab_ring_player_stats),
('tourneyplayerstats', None, '_Tourney Player Stats (tabulated view, mysql only)', '<control>T', 'Tourney Player Stats (tabulated view, mysql only)', self.tab_tourney_player_stats),
('posnstats', None, 'P_ositional Stats (tabulated view)', '<control>O', 'Positional Stats (tabulated view)', self.tab_positional_stats),
('tourneyplayerstats', None, '_Tourney Player Stats (tabulated view)', '<control>T', 'Tourney Player Stats (tabulated view, mysql only)', self.tab_tourney_player_stats),
('tourneyviewer', None, 'Tourney _Viewer', None, 'Tourney Viewer)', self.tab_tourney_viewer_stats),
('posnstats', None, 'P_ositional Stats (tabulated view, not on sqlite)', '<control>O', 'Positional Stats (tabulated view)', self.tab_positional_stats),
('sessionstats', None, 'Session Stats', None, 'Session Stats', self.tab_session_stats),
('database', None, '_Database'),
('maintaindbs', None, '_Maintain Databases', None, 'Maintain Databases', self.dia_maintain_dbs),
@ -857,10 +864,6 @@ class fpdb:
return menubar
#end def get_menu
def import_imap_summaries(self, widget, data=None):
result=ImapFetcher.run(self.config, self.db)
#print "import imap summaries result:", result
#end def import_imap_summaries
def load_profile(self, create_db = False):
"""Loads profile from the provided path name."""
@ -891,7 +894,7 @@ class fpdb:
self.settings.update(self.config.get_import_parameters())
self.settings.update(self.config.get_default_paths())
if self.db is not None and self.db.connected:
if self.db is not None and self.db.is_connected():
self.db.disconnect()
self.sql = SQL.Sql(db_server = self.settings['db-server'])
@ -914,6 +917,8 @@ class fpdb:
if err_msg is not None:
self.db = None
self.warning_box(err_msg)
if self.db is not None and not self.db.is_connected():
self.db = None
# except FpdbMySQLFailedError:
# self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR")
@ -954,7 +959,7 @@ class fpdb:
self.main_vbox.pack_end(self.status_bar, False, True, 0)
self.status_bar.show()
if self.db is not None and self.db.connected:
if self.db is not None and self.db.is_connected():
self.status_bar.set_text("Status: Connected to %s database named %s on host %s"
% (self.db.get_backend_name(),self.db.database, self.db.host))
# rollback to make sure any locks are cleared:
@ -988,12 +993,12 @@ class fpdb:
if self.db!=None:
if self.db.backend==self.db.MYSQL_INNODB:
try:
if self.db is not None and self.db.connected():
if self.db is not None and self.db.is_connected():
self.db.disconnect()
except _mysql_exceptions.OperationalError: # oh, damn, we're already disconnected
pass
else:
if self.db is not None and self.db.connected():
if self.db is not None and self.db.is_connected():
self.db.disconnect()
else:
pass
@ -1021,6 +1026,13 @@ class fpdb:
bulk_tab=new_import_thread.get_vbox()
self.add_and_display_tab(bulk_tab, "Bulk Import")
def tab_imap_import(self, widget, data=None):
new_thread = GuiImapFetcher.GuiImapFetcher(self.config, self.db, self.sql, self.window)
self.threads.append(new_thread)
tab=new_thread.get_vbox()
self.add_and_display_tab(tab, "IMAP Import")
#end def tab_import_imap_summaries
def tab_ring_player_stats(self, widget, data=None):
new_ps_thread = GuiRingPlayerStats.GuiRingPlayerStats(self.config, self.sql, self.window)
self.threads.append(new_ps_thread)
@ -1033,6 +1045,12 @@ class fpdb:
ps_tab=new_ps_thread.get_vbox()
self.add_and_display_tab(ps_tab, "Tourney Player Stats")
def tab_tourney_viewer_stats(self, widget, data=None):
new_thread = GuiTourneyViewer.GuiTourneyViewer(self.config, self.db, self.sql, self.window)
self.threads.append(new_thread)
tab=new_thread.get_vbox()
self.add_and_display_tab(tab, "Tourney Viewer")
def tab_positional_stats(self, widget, data=None):
new_ps_thread = GuiPositionalStats.GuiPositionalStats(self.config, self.sql)
self.threads.append(new_ps_thread)
@ -1047,14 +1065,17 @@ class fpdb:
def tab_main_help(self, widget, data=None):
"""Displays a tab with the main fpdb help screen"""
mh_tab=gtk.Label("""Welcome to Fpdb!
mh_tab=gtk.Label("""Fpdb needs translators!
If you speak another language and have a few minutes or more to spare get in touch by emailing steffen@schaumburger.info
Welcome to Fpdb!
To be notified of new snapshots and releases go to https://lists.sourceforge.net/lists/listinfo/fpdb-announce and subscribe.
If you want to follow development more closely go to https://lists.sourceforge.net/lists/listinfo/fpdb-main and subscribe.
This program is currently in an alpha-state, so our database format is still sometimes changed.
You should therefore always keep your hand history files so that you can re-import after an update, if necessary.
For documentation please visit our website at http://fpdb.sourceforge.net/.
For documentation please visit our website/wiki at http://fpdb.sourceforge.net/.
If you need help click on Contact - Get Help on our website.
Please note that default.conf is no longer needed nor used, all configuration now happens in HUD_config.xml.

View File

@ -0,0 +1,41 @@
***** Hand History For Game 9423586142 *****
0.01/0.02 Texas Hold'em Game Table (NL) - Mon Jul 12 13:38:32 EDT 2010
Table 20BB Min Speed #1775757 (Real Money) -- Seat 1 is the button
Total number of players : 9/9
Seat 1: Player1 ($0.95)
Seat 2: Player2 ($0.57)
Seat 3: Player3 ($0.86)
Seat 4: Player4 ($1.71)
Seat 5: Player5 ($1.76)
Seat 6: Player6 ($0.44)
Seat 7: Player7 ($0.76)
Seat 8: Player8 ($0.68)
Seat 9: Player9 ($0.38)
Player2 posts small blind (0.01)
Player3 posts big blind (0.02)
** Dealing down cards **
Dealt to Player5 [ Tc, 9d ]
Player5 folds
Player6 calls (0.02)
Player8 folds
Player9 folds
Player1 folds
Player2 calls (0.01)
Player3 raises 0.06 to 0.08
Player6 calls (0.06)
Player2 folds
** Dealing Flop ** : [ 5s, 7h, 6h ]
Player3 bets (0.13)
Player6 folds
** Summary **
Main Pot: $0.18 Rake: $0
Board: [ 5s 7h 6h ]
Player1 balance $0.95, didn't bet (folded)
Player2 balance $0.55, lost $0.02 (folded)
Player3 balance $0.96, bet $0.21, collected $0.31, net +$0.1
Player4 balance $1.71, sits out
Player5 balance $1.76, didn't bet (folded)
Player6 balance $0.36, lost $0.08 (folded)
Player7 balance $0.76, sits out
Player8 balance $0.68, didn't bet (folded)
Player9 balance $0.38, didn't bet (folded)

View File

@ -0,0 +1,63 @@
Game #9485557849 starts.
#Game No : 9485557849
***** Hand History for Game 9485557849 *****
$0.80 USD NL Texas Hold'em - Saturday, July 31, 13:52:16 EDT 2010
Table 20BB Min Speed #1770998 (Real Money)
Seat 1 is the button
Total number of players : 4/9
Seat 3: FErki84 ( $1.64 USD )
Seat 5: Vandercasses ( $0.01 USD )
Seat 9: jeremyho888 ( $1.02 USD )
Seat 1: sergeodem ( $1.20 USD )
FErki84 posts small blind [$0.01 USD].
Vandercasses posts big blind [$0.01 USD].
** Dealing down cards **
Dealt to FErki84 [ 8h Kc ]
jeremyho888 folds
sergeodem calls [$0.02 USD]
FErki84 calls [$0.01 USD]
** Dealing Flop ** [ Td, 7c, 9h ]
FErki84 checks
sergeodem checks
** Dealing Turn ** [ 3h ]
FErki84 checks
sergeodem checks
** Dealing River ** [ Jc ]
FErki84 bets [$0.04 USD]
sergeodem folds
FErki84 shows [ 8h, Kc ]a straight, Seven to Jack.
Vandercasses doesn't show [ Ts, Jd ]two pairs, Jacks and Tens.
FErki84 wins $0.06 USD from the side pot 1 with a straight, Seven to Jack.
FErki84 wins $0.03 USD from the main pot with a straight, Seven to Jack.
Vandercasses has left the table.
Game #9498788316 starts.
#Game No : 9498788316
***** Hand History for Game 9498788316 *****
$1.60 USD NL Texas Hold'em - Wednesday, August 04, 15:02:33 EDT 2010
Table 20BB Min #1847547 (No DP) (Real Money)
Seat 2 is the button
Total number of players : 5/6
Seat 5: CepguTbIu999 ( $1.60 USD )
Seat 1: Daytona_955 ( $2.45 USD )
Seat 4: FErki84 ( $2.18 USD )
Seat 2: anjl2009 ( $2.80 USD )
Seat 3: lukeman2 ( $0.01 USD )
lukeman2 posts small blind [$0.01 USD].
FErki84 posts big blind [$0.04 USD].
** Dealing down cards **
Dealt to FErki84 [ 6s 2c ]
CepguTbIu999 folds
Daytona_955 folds
anjl2009 folds
** Dealing Flop ** [ 9d, Ah, 3h ]
** Dealing Turn ** [ Js ]
** Dealing River ** [ Kc ]
lukeman2 shows [ 5h, 5s ]a pair of Fives.
FErki84 shows [ 6s, 2c ]high card Ace.
FErki84 wins $0.03 USD from the side pot 1 with high card, Ace.
lukeman2 wins $0.02 USD from the main pot with a pair of Fives.
lukeman2 has left the table.

View File

@ -1,5 +1,5 @@
fpdb database dump
DB version=136
DB version=142
###################
Table Autorates
@ -44,7 +44,7 @@ empty table
###################
Table Settings
###################
version=136
version=142
###################

View File

@ -0,0 +1,37 @@
***** Hand History For Game 9336845949 *****
30/60 Tourney Texas Hold'em Game Table (NL) (STT Tournament #52792286) - Sun Jun 13 12:21:39 EDT 2010
Table 174827 (Real Money) -- Seat 6 is the button
Total number of players : 6/6
Seat 1: Player1 (1520)
Seat 2: Player2 (1540)
Seat 3: Player3 (2120)
Seat 4: Player4 (2460)
Seat 5: Player5 (2600)
Seat 6: Player6 (1760)
Player1 posts small blind (30)
Player2 posts big blind (60)
** Dealing down cards **
Dealt to Player5 [ Jc, Js ]
Player3 folds
Player4 folds
Player6 folds
Player1 calls (210)
Player2 folds
** Dealing Flop ** : [ 4h, 7d, 5c ]
Player1 checks
Player1 calls (450)
** Dealing Turn ** : [ Kd ]
Player1 checks
Player1 calls (830)
Player1 is all-In.
** Dealing River ** : [ Jd ]
Creating Main Pot with 3100 with Player1
** Summary **
Main Pot: 3100
Board: [ 4h 7d 5c Kd Jd ]
Player1 balance 0, lost 1520 [ Ks 6c ] [ a pair of kings -- Ks,Kd,Jd,7d,6c ]
Player2 balance 1480, lost 60 (folded)
Player3 balance 2120, didn't bet (folded)
Player4 balance 2460, didn't bet (folded)
Player5 balance 4180, bet 1520, collected 3100, net +1580 [ Jc Js ] [ three of a kind, jacks -- Kd,Jc,Js,Jd,7d ]
Player6 balance 1760, didn't bet (folded)