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

This commit is contained in:
Eratosthenes 2010-12-05 12:53:28 -05:00
commit 78fdb37f38
17 changed files with 684 additions and 120 deletions

View File

@ -479,12 +479,13 @@ class Import:
self.hhArchiveBase = node.getAttribute("hhArchiveBase") self.hhArchiveBase = node.getAttribute("hhArchiveBase")
self.hhBulkPath = node.getAttribute("hhBulkPath") self.hhBulkPath = node.getAttribute("hhBulkPath")
self.saveActions = string_to_bool(node.getAttribute("saveActions"), default=False) self.saveActions = string_to_bool(node.getAttribute("saveActions"), default=False)
self.cacheSessions = string_to_bool(node.getAttribute("cacheSessions"), default=False)
self.fastStoreHudCache = string_to_bool(node.getAttribute("fastStoreHudCache"), default=False) self.fastStoreHudCache = string_to_bool(node.getAttribute("fastStoreHudCache"), default=False)
self.saveStarsHH = string_to_bool(node.getAttribute("saveStarsHH"), default=False) self.saveStarsHH = string_to_bool(node.getAttribute("saveStarsHH"), default=False)
def __str__(self): def __str__(self):
return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \ return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \
% (self.interval, self.callFpdbHud, self.hhArchiveBase, self.saveActions, self.fastStoreHudCache) % (self.interval, self.callFpdbHud, self.hhArchiveBase, self.saveActions, self.cacheSessions, self.fastStoreHudCache)
class HudUI: class HudUI:
def __init__(self, node): def __init__(self, node):
@ -1259,6 +1260,9 @@ class Config:
try: imp['saveActions'] = self.imp.saveActions try: imp['saveActions'] = self.imp.saveActions
except: imp['saveActions'] = False except: imp['saveActions'] = False
try: imp['cacheSessions'] = self.imp.cacheSessions
except: imp['cacheSessions'] = False
try: imp['saveStarsHH'] = self.imp.saveStarsHH try: imp['saveStarsHH'] = self.imp.saveStarsHH
except: imp['saveStarsHH'] = False except: imp['saveStarsHH'] = False

View File

@ -73,7 +73,7 @@ except ImportError:
use_numpy = False use_numpy = False
DB_VERSION = 145 DB_VERSION = 146
# Variance created as sqlite has a bunch of undefined aggregate functions. # Variance created as sqlite has a bunch of undefined aggregate functions.
@ -296,8 +296,8 @@ class Database:
# vars for hand ids or dates fetched according to above config: # vars for hand ids or dates fetched according to above config:
self.hand_1day_ago = 0 # max hand id more than 24 hrs earlier than now self.hand_1day_ago = 0 # max hand id more than 24 hrs earlier than now
self.date_ndays_ago = 'd00000000' # date N days ago ('d' + YYMMDD) self.date_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD)
self.h_date_ndays_ago = 'd00000000' # date N days ago ('d' + YYMMDD) for hero self.h_date_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD) for hero
self.date_nhands_ago = {} # dates N hands ago per player - not used yet self.date_nhands_ago = {} # dates N hands ago per player - not used yet
self.saveActions = False if self.import_options['saveActions'] == False else True self.saveActions = False if self.import_options['saveActions'] == False else True
@ -701,18 +701,18 @@ class Database:
d = timedelta(days=hud_days, hours=tz_day_start_offset) d = timedelta(days=hud_days, hours=tz_day_start_offset)
now = datetime.utcnow() - d now = datetime.utcnow() - d
self.date_ndays_ago = "d%02d%02d%02d%02d" % (now.year - 2000, now.month, now.day, tz_day_start_offset) self.date_ndays_ago = "d%02d%02d%02d" % (now.year - 2000, now.month, now.day)
d = timedelta(days=h_hud_days, hours=tz_day_start_offset) d = timedelta(days=h_hud_days, hours=tz_day_start_offset)
now = datetime.utcnow() - d now = datetime.utcnow() - d
self.h_date_ndays_ago = "d%02d%02d%02d%02d" % (now.year - 2000, now.month, now.day, tz_day_start_offset) self.h_date_ndays_ago = "d%02d%02d%02d" % (now.year - 2000, now.month, now.day)
def init_player_hud_stat_vars(self, playerid): def init_player_hud_stat_vars(self, playerid):
# not sure if this is workable, to be continued ... # not sure if this is workable, to be continued ...
try: try:
# self.date_nhands_ago is used for fetching stats for last n hands (hud_style = 'H') # self.date_nhands_ago is used for fetching stats for last n hands (hud_style = 'H')
# This option not used yet - needs to be called for each player :-( # This option not used yet - needs to be called for each player :-(
self.date_nhands_ago[str(playerid)] = 'd00000000' self.date_nhands_ago[str(playerid)] = 'd000000'
# should use aggregated version of query if appropriate # should use aggregated version of query if appropriate
c.execute(self.sql.query['get_date_nhands_ago'], (self.hud_hands, playerid)) c.execute(self.sql.query['get_date_nhands_ago'], (self.hud_hands, playerid))
@ -780,11 +780,11 @@ class Database:
if hud_style == 'T': if hud_style == 'T':
stylekey = self.date_ndays_ago stylekey = self.date_ndays_ago
elif hud_style == 'A': elif hud_style == 'A':
stylekey = '000000000' # all stylekey values should be higher than this stylekey = '0000000' # all stylekey values should be higher than this
elif hud_style == 'S': elif hud_style == 'S':
stylekey = 'zzzzzzzzz' # all stylekey values should be lower than this stylekey = 'zzzzzzz' # all stylekey values should be lower than this
else: else:
stylekey = '000000000' stylekey = '0000000'
log.info('hud_style: %s' % hud_style) log.info('hud_style: %s' % hud_style)
#elif hud_style == 'H': #elif hud_style == 'H':
@ -793,9 +793,9 @@ class Database:
if h_hud_style == 'T': if h_hud_style == 'T':
h_stylekey = self.h_date_ndays_ago h_stylekey = self.h_date_ndays_ago
elif h_hud_style == 'A': elif h_hud_style == 'A':
h_stylekey = '000000000' # all stylekey values should be higher than this h_stylekey = '0000000' # all stylekey values should be higher than this
elif h_hud_style == 'S': elif h_hud_style == 'S':
h_stylekey = 'zzzzzzzzz' # all stylekey values should be lower than this h_stylekey = 'zzzzzzz' # all stylekey values should be lower than this
else: else:
h_stylekey = '00000000' h_stylekey = '00000000'
log.info('h_hud_style: %s' % h_hud_style) log.info('h_hud_style: %s' % h_hud_style)
@ -1832,12 +1832,19 @@ class Database:
def storeHudCache(self, gid, pids, starttime, pdata): def storeHudCache(self, gid, pids, starttime, pdata):
"""Update cached statistics. If update fails because no record exists, do an insert.""" """Update cached statistics. If update fails because no record exists, do an insert."""
tz = datetime.utcnow() - datetime.today()
tz_offset = tz.seconds/3600
tz_day_start_offset = self.day_start + tz_offset
d = timedelta(hours=tz_day_start_offset)
starttime_offset = starttime - d
if self.use_date_in_hudcache: if self.use_date_in_hudcache:
styleKey = datetime.strftime(starttime, 'd%y%m%d%H') styleKey = datetime.strftime(starttime_offset, 'd%y%m%d')
#styleKey = "d%02d%02d%02d%02d" % (hand_start_time.year-2000, hand_start_time.month, hand_start_time.day, hand_start_time.hour) #styleKey = "d%02d%02d%02d" % (hand_start_time.year-2000, hand_start_time.month, hand_start_time.day)
else: else:
# hard-code styleKey as 'A00000000' (all-time cache, no key) for now # hard-code styleKey as 'A000000' (all-time cache, no key) for now
styleKey = 'A00000000' styleKey = 'A000000'
update_hudcache = self.sql.query['update_hudcache'] update_hudcache = self.sql.query['update_hudcache']
update_hudcache = update_hudcache.replace('%s', self.sql.query['placeholder']) update_hudcache = update_hudcache.replace('%s', self.sql.query['placeholder'])
@ -1959,6 +1966,53 @@ class Database:
else: else:
#print "DEBUG: Successfully updated HudCacho using UPDATE" #print "DEBUG: Successfully updated HudCacho using UPDATE"
pass pass
def storeSessionsCache(self, pids, starttime, pdata):
"""Update cached sessions. If update fails because no record exists, do an insert."""
#In development
pass
#update_sessionscache = self.sql.query['update_sessionscache']
#update_sessionscache = update_sessionscache.replace('%s', self.sql.query['placeholder'])
#insert_sessionscache = self.sql.query['insert_sessionscache']
#insert_sessionscache = insert_sessionscache.replace('%s', self.sql.query['placeholder'])
#merge_sessionscache = self.sql.query['merge_sessionscache']
#merge_sessionscache = merge_sessionscache.replace('%s', self.sql.query['placeholder'])
#print "DEBUG: %s %s %s" %(hid, pids, pdata)
#inserts = []
#for p in pdata:
#line = [0]*5
#line[0] = 1 # HDs
#line[1] = pdata[p]['totalProfit']
#line[2] = pids[p] # playerId
#line[3] = sessionStart
#line[4] = sessionEnd
#inserts.append(line)
#cursor = self.get_cursor()
#for row in inserts:
# Try to do the update first:
#num = cursor.execute(update_sessionscache, row)
#print "DEBUG: values: %s" % row[-3:]
# Test statusmessage to see if update worked, do insert if not
# num is a cursor in sqlite
#if ((self.backend == self.PGSQL and cursor.statusmessage != "UPDATE 1")
#or (self.backend == self.MYSQL_INNODB and num == 0)
#or (self.backend == self.SQLITE and num.rowcount == 0)):
#move the last 6 items in WHERE clause of row from the end of the array
# to the beginning for the INSERT statement
#print "DEBUG: using INSERT: %s" % num
#row = row[-3:] + row[:-3]
#num = cursor.execute(insert_sessionscache, row)
#print "DEBUG: Successfully(?: %s) updated HudCacho using INSERT" % num
#else:
#print "DEBUG: Successfully updated HudCacho using UPDATE"
#pass
def isDuplicate(self, gametypeID, siteHandNo): def isDuplicate(self, gametypeID, siteHandNo):
dup = False dup = False

View File

@ -33,6 +33,7 @@ class FullTiltPokerSummary(TourneySummary):
games = { # base, category games = { # base, category
"Hold'em" : ('hold','holdem'), "Hold'em" : ('hold','holdem'),
'Omaha' : ('hold','omahahi'), 'Omaha' : ('hold','omahahi'),
'Omahai Hi' : ('hold','omahahi'),
'Omaha Hi/Lo' : ('hold','omahahilo'), 'Omaha Hi/Lo' : ('hold','omahahilo'),
'Razz' : ('stud','razz'), 'Razz' : ('stud','razz'),
'RAZZ' : ('stud','razz'), 'RAZZ' : ('stud','razz'),
@ -55,7 +56,7 @@ class FullTiltPokerSummary(TourneySummary):
re_TourneyInfo = re.compile(u""" re_TourneyInfo = re.compile(u"""
\s.* \s.*
(?P<TYPE>Tournament|Sit\s\&\sGo)\s\((?P<TOURNO>[0-9]+)\)(\s+)? (?P<TYPE>Tournament|Sit\s\&\sGo)\s\((?P<TOURNO>[0-9]+)\)(\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<GAME>Hold\'em|Razz|RAZZ|7\sCard\sStud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi|Omaha\sHi/Lo|Badugi|Triple\sDraw\s2\-7\sLowball|5\sCard\sDraw)\s+
(?P<LIMIT>No\sLimit|Limit|LIMIT|Pot\sLimit)\s+ (?P<LIMIT>No\sLimit|Limit|LIMIT|Pot\sLimit)\s+
(Buy-In:\s\$(?P<BUYIN>[.\d]+)(\s\+\s\$(?P<FEE>[.\d]+))?\s+)? (Buy-In:\s\$(?P<BUYIN>[.\d]+)(\s\+\s\$(?P<FEE>[.\d]+))?\s+)?
(Buy-In\sChips:\s(?P<CHIPS>\d+)\s+)? (Buy-In\sChips:\s(?P<CHIPS>\d+)\s+)?

274
pyfpdb/GuiReplayer.py Normal file
View File

@ -0,0 +1,274 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Copyright 2010 Maxime Grandchamp
#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 L10n
_ = L10n.get_translation()
from Hand import *
import Configuration
import Database
import SQL
import fpdb_import
import Filters
import pygtk
pygtk.require('2.0')
import gtk
import math
import gobject
class GuiReplayer:
def __init__(self, config, querylist, mainwin, debug=True):
self.debug = debug
self.conf = config
self.main_window = mainwin
self.sql = querylist
self.db = Database.Database(self.conf, sql=self.sql)
filters_display = { "Heroes" : True,
"Sites" : True,
"Games" : True,
"Limits" : True,
"LimitSep" : True,
"LimitType" : True,
"Type" : True,
"Seats" : True,
"SeatSep" : True,
"Dates" : True,
"Groups" : True,
"GroupsAll" : True,
"Button1" : True,
"Button2" : True
}
self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
#self.filters.registerButton1Name(_("Import Hand"))
#self.filters.registerButton1Callback(self.importhand)
#self.filters.registerButton2Name(_("temp"))
#self.filters.registerButton2Callback(self.temp())
# hierarchy: self.mainHBox / self.hpane / self.replayBox / self.area
self.mainHBox = gtk.HBox(False, 0)
self.mainHBox.show()
self.leftPanelBox = self.filters.get_vbox()
self.hpane = gtk.HPaned()
self.hpane.pack1(self.leftPanelBox)
self.mainHBox.add(self.hpane)
self.replayBox = gtk.VBox(False, 0)
self.replayBox.show()
self.hpane.pack2(self.replayBox)
self.hpane.show()
self.area=gtk.DrawingArea()
self.pangolayout = self.area.create_pango_layout("")
self.area.connect("expose-event", self.area_expose)
self.style = self.area.get_style()
self.gc = self.style.fg_gc[gtk.STATE_NORMAL]
self.area.show()
self.replayBox.pack_start(self.area)
self.MyHand = self.importhand()
self.maxseats=self.MyHand.maxseats
if self.MyHand.gametype['currency']=="USD": #TODO: check if there are others ..
self.currency="$"
elif self.MyHand.gametype['currency']=="EUR":
self.currency=""
self.table={} #create table with positions, player names, status (live/folded), stacks and chips on table
for i in range(0,self.maxseats): # radius: 200, center: 250,250
x= int (round(250+200*math.cos(2*i*math.pi/self.maxseats)))
y= int (round(250+200*math.sin(2*i*math.pi/self.maxseats)))
try:
self.table[i]={"name":self.MyHand.players[i][1],"stack":Decimal(self.MyHand.players[i][2]),"x":x,"y":y,"chips":0,"status":"live"} #save coordinates of each player
try:
self.table[i]['holecards']=self.MyHand.holecards["PREFLOP"][self.MyHand.players[i][1]][1]+' '+self.MyHand.holecards["PREFLOP"][self.MyHand.players[i][1]][2]
print "holecards",self.table[i]['holecards']
except:
self.table[i]['holecards']=''
except IndexError: #if seat is empty
print "seat",i+1,"out of",self.maxseats,"empty"
self.actions=[] #create list with all actions
if isinstance(self.MyHand, HoldemOmahaHand):
if self.MyHand.gametype['category'] == 'holdem':
self.play_holdem()
self.action_number=0
self.action_level=0
self.pot=0
gobject.timeout_add(1000,self.draw_action)
def area_expose(self, area, event):
self.style = self.area.get_style()
self.gc = self.style.fg_gc[gtk.STATE_NORMAL]
playerid='999' #makes sure we have an error if player is not recognised
for i in range(0,len(self.table)): #surely there must be a better way to find the player id in the table...
if self.table[i]['name']==self.actions[self.action_number][1]:
playerid=i
if self.actions[self.action_number][2]=="folds":
self.table[playerid]["status"]="folded"
if self.actions[self.action_number][3]:
self.table[playerid]["stack"] -= Decimal(self.actions[self.action_number][3]) #decreases stack if player bets
self.pot += Decimal(self.actions[self.action_number][3]) #increase pot
self.table[playerid]["chips"] += Decimal(self.actions[self.action_number][3]) #increase player's chips on table
cm = self.gc.get_colormap() #create colormap toi be able to play with colours
color = cm.alloc_color("black") #defaults to black
self.gc.set_foreground(color)
self.area.window.draw_arc(self.gc, 0, 125, 125, 300, 300, 0, 360*64) #table
for i in self.table:
if self.table[i]["status"]=="folded":
color = cm.alloc_color("grey") #player has folded => greyed out
self.gc.set_foreground(color)
else:
color = cm.alloc_color("black") #player is live
self.gc.set_foreground(color)
self.pangolayout.set_text(self.table[i]["name"]+self.table[i]["holecards"]) #player names + holecards
self.area.window.draw_layout(self.gc, self.table[i]["x"],self.table[i]["y"], self.pangolayout)
self.pangolayout.set_text('$'+str(self.table[i]["stack"])) #player stacks
self.area.window.draw_layout(self.gc, self.table[i]["x"]+10,self.table[i]["y"]+20, self.pangolayout)
color = cm.alloc_color("green")
self.gc.set_foreground(color)
self.pangolayout.set_text(self.currency+str(self.pot)) #displays pot
self.area.window.draw_layout(self.gc,270,270, self.pangolayout)
if self.actions[self.action_number][0]>1: #displays flop
self.pangolayout.set_text(self.MyHand.board['FLOP'][0]+" "+self.MyHand.board['FLOP'][1]+" "+self.MyHand.board['FLOP'][2])
self.area.window.draw_layout(self.gc,210,240, self.pangolayout)
if self.actions[self.action_number][0]>2: #displays turn
self.pangolayout.set_text(self.MyHand.board['TURN'][0])
self.area.window.draw_layout(self.gc,270,240, self.pangolayout)
if self.actions[self.action_number][0]>3: #displays river
self.pangolayout.set_text(self.MyHand.board['RIVER'][0])
self.area.window.draw_layout(self.gc,290,240, self.pangolayout)
color = cm.alloc_color("red") #highlights the action
self.gc.set_foreground(color)
self.pangolayout.set_text(self.actions[self.action_number][2]) #displays action
self.area.window.draw_layout(self.gc, self.table[playerid]["x"]+10,self.table[playerid]["y"]+35, self.pangolayout)
if self.actions[self.action_number][3]: #displays amount
self.pangolayout.set_text(self.currency+self.actions[self.action_number][3])
self.area.window.draw_layout(self.gc, self.table[playerid]["x"]+10,self.table[playerid]["y"]+55, self.pangolayout)
color = cm.alloc_color("black") #we don't want to draw the filters and others in red
self.gc.set_foreground(color)
def play_holdem(self):
actions=('BLINDSANTES','PREFLOP','FLOP','TURN','RIVER')
for action in actions:
for i in range(0,len(self.MyHand.actions[action])):
player=self.MyHand.actions[action][i][0]
act=self.MyHand.actions[action][i][1]
try:
amount=str(self.MyHand.actions[action][i][2])
except:
amount='' #no amount
self.actions.append([actions.index(action),player,act,amount]) #create table with all actions
def draw_action(self):
if self.action_number==len(self.actions)-1: #no more actions, we exit the loop
return False
if self.actions[self.action_number][0]!=self.action_level: #have we changed street ?
self.action_level=self.actions[self.action_number][0] #record the new street
if self.action_level>1: #we don't want to refresh if simply moving from antes/blinds to preflop action
alloc = self.area.get_allocation()
rect = gtk.gdk.Rectangle(0, 0, alloc.width, alloc.height)
self.area.window.invalidate_rect(rect, True) #make sure we refresh the whole screen
self.action_number+=1
if self.area.window:
playerid='999' #makes sure we have an error if player is not recognised
for i in range(0,len(self.table)): #surely there must be a better way to find the player id in the table...
if self.table[i]['name']==self.actions[self.action_number][1]:
playerid=i
rect = gtk.gdk.Rectangle(self.table[playerid]["x"],self.table[playerid]["y"],100,100)
self.area.window.invalidate_rect(rect, True) #refresh player area of the screen
rect = gtk.gdk.Rectangle(270,270,100,50)
self.area.window.invalidate_rect(rect, True) #refresh pot area
self.area.window.process_updates(True)
print "draw action",self.action_number,self.actions[self.action_number][1],self.actions[self.action_number][2],self.actions[self.action_number][3]
return True
def get_vbox(self):
"""returns the vbox of this thread"""
return self.mainHBox
def importhand(self, handnumber=1):
"""Temporary function that grabs a Hand object from a specified file. Obviously this will
be replaced by a function to select a hand from the db in the not so distant future.
This code has been shamelessly stolen from Carl
"""
config = Configuration.Config(file = "HUD_config.test.xml")
db = Database.Database(config)
sql = SQL.Sql(db_server = 'sqlite')
settings = {}
settings.update(config.get_db_parameters())
settings.update(config.get_import_parameters())
settings.update(config.get_default_paths())
#db.recreate_tables()
importer = fpdb_import.Importer(False, settings, config, None)
importer.setDropIndexes("don't drop")
importer.setFailOnError(True)
importer.setThreads(-1)
importer.setCallHud(False)
importer.setFakeCacheHHC(True)
#Get a simple regression file with a few hands of Hold'em
filename="regression-test-files/cash/Stars/Flop/NLHE-FR-USD-0.01-0.02-201005.microgrind.txt"
site="PokerStars"
importer.addBulkImportImportFileOrDir(filename, site=site)
(stored, dups, partial, errs, ttime) = importer.runImport()
hhc = importer.getCachedHHC()
handlist = hhc.getProcessedHands()
return handlist[0]
def temp(self):
pass

View File

@ -75,10 +75,6 @@ onlinehelp = {'Game':_('Type of Game'),
class DemoTips(TreeViewTooltips): class DemoTips(TreeViewTooltips):
def __init__(self, customer_column): def __init__(self, customer_column):
# customer_column is an instance of gtk.TreeViewColumn and
# is being used in the gtk.TreeView to show customer names.
# self.cust_col = customer_column
# call base class init # call base class init
TreeViewTooltips.__init__(self) TreeViewTooltips.__init__(self)
@ -91,11 +87,6 @@ class DemoTips(TreeViewTooltips):
return (display) return (display)
def location(self, x, y, w, h): def location(self, x, y, w, h):
# rename me to "location" so I override the base class
# method. This will demonstrate being able to change
# where the tooltip window popups, relative to the
# pointer.
# this will place the tooltip above and to the right # this will place the tooltip above and to the right
return x + 30, y - (h + 10) return x + 30, y - (h + 10)

View File

@ -2,7 +2,7 @@
<FreePokerToolsConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FreePokerToolsConfig.xsd"> <FreePokerToolsConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FreePokerToolsConfig.xsd">
<import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import> <import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True" cacheSessions="False"></import>
<!-- These values determine what stats are displayed in the HUD <!-- These values determine what stats are displayed in the HUD

View File

@ -12,7 +12,7 @@
config_difficulty="expert" config_difficulty="expert"
/> />
<import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import> <import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True" cacheSessions="False"></import>
<gui_cash_stats> <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="game" disp_all="True" disp_posn="True" col_title="Game" xalignment="0.0" field_format="%s" field_type="str" />

View File

@ -278,6 +278,9 @@ db: a connected Database object"""
def updateHudCache(self, db): def updateHudCache(self, db):
db.storeHudCache(self.dbid_gt, self.dbid_pids, self.startTime, self.stats.getHandsPlayers()) db.storeHudCache(self.dbid_gt, self.dbid_pids, self.startTime, self.stats.getHandsPlayers())
def updateSessionsCache(self, db):
db.storeSessionsCache(self.dbid_pids, self.startTime, self.stats.getHandsPlayers())
def select(self, handId): def select(self, handId):
""" Function to create Hand object from database """ """ Function to create Hand object from database """

View File

@ -45,22 +45,27 @@ class PartyPoker(HandHistoryConverter):
codepage = "utf8" codepage = "utf8"
siteId = 9 siteId = 9
filetype = "text" filetype = "text"
sym = {'USD': "\$", } sym = {'USD': "\$", 'EUR': u"\u20ac", 'T$': ""}
currencies = {"\$": "USD", "$": "USD", u"\xe2\x82\xac": "EUR", u"\u20ac": "EUR", '': "T$"}
substitutions = {
'LEGAL_ISO' : "USD|EUR", # legal ISO currency codes
'LS' : "\$|\u20AC|\xe2\x82\xac|" # legal currency symbols - Euro(cp1252, utf-8)
}
# Static regexes # Static regexes
# $5 USD NL Texas Hold'em - Saturday, July 25, 07:53:52 EDT 2009 # $5 USD NL Texas Hold'em - Saturday, July 25, 07:53:52 EDT 2009
# NL Texas Hold'em $1 USD Buy-in Trny:45685440 Level:8 Blinds-Antes(600/1 200 -50) - Sunday, May 17, 11:25:07 MSKS 2009 # NL Texas Hold'em $1 USD Buy-in Trny:45685440 Level:8 Blinds-Antes(600/1 200 -50) - Sunday, May 17, 11:25:07 MSKS 2009
re_GameInfoRing = re.compile(""" re_GameInfoRing = re.compile(u"""
(?P<CURRENCY>\$|)\s*(?P<RINGLIMIT>[.,0-9]+)([.,0-9/$]+)?\s*(?:USD)?\s* (?P<CURRENCY>[%(LS)s])\s*(?P<RINGLIMIT>[.,0-9]+)([.,0-9/$]+)?\s*(?:%(LEGAL_ISO)s)?\s*
(?P<LIMIT>(NL|PL|))\s* (?P<LIMIT>(NL|PL|))\s*
(?P<GAME>(Texas\ Hold\'em|Omaha|7 Card Stud Hi-Lo)) (?P<GAME>(Texas\ Hold\'em|Omaha|7\ Card\ Stud\ Hi-Lo))
\s*\-\s* \s*\-\s*
(?P<DATETIME>.+) (?P<DATETIME>.+)
""", re.VERBOSE | re.UNICODE) """ % substitutions, re.VERBOSE | re.UNICODE)
re_GameInfoTrny = re.compile(""" re_GameInfoTrny = re.compile("""
(?P<LIMIT>(NL|PL|))\s* (?P<LIMIT>(NL|PL|))\s*
(?P<GAME>(Texas\ Hold\'em|Omaha))\s+ (?P<GAME>(Texas\ Hold\'em|Omaha))\s+
(?:(?P<BUYIN>\$?[.,0-9]+)\s*(?P<BUYIN_CURRENCY>USD)?\s*Buy-in\s+)? (?:(?P<BUYIN>\$?[.,0-9]+)\s*(?P<BUYIN_CURRENCY>%(LEGAL_ISO)s)?\s*Buy-in\s+)?
Trny:\s?(?P<TOURNO>\d+)\s+ Trny:\s?(?P<TOURNO>\d+)\s+
Level:\s*(?P<LEVEL>\d+)\s+ Level:\s*(?P<LEVEL>\d+)\s+
((Blinds|Stakes)(?:-Antes)?)\( ((Blinds|Stakes)(?:-Antes)?)\(
@ -70,15 +75,14 @@ class PartyPoker(HandHistoryConverter):
\) \)
\s*\-\s* \s*\-\s*
(?P<DATETIME>.+) (?P<DATETIME>.+)
""", re.VERBOSE | re.UNICODE) """ % substitutions, re.VERBOSE | re.UNICODE)
re_Hid = re.compile("^Game \#(?P<HID>\d+) starts.") re_Hid = re.compile("Game \#(?P<HID>\d+) starts.")
re_PlayerInfo = re.compile(""" re_PlayerInfo = re.compile(u"""
Seat\s(?P<SEAT>\d+):\s Seat\s(?P<SEAT>\d+):\s
(?P<PNAME>.*)\s (?P<PNAME>.*)\s
\(\s*\$?(?P<CASH>[0-9,.]+)\s*(?:USD|)\s*\) \(\s*[%(LS)s]?(?P<CASH>[0-9,.]+)\s*(?:%(LEGAL_ISO)s|)\s*\)
""" , """ % substitutions, re.VERBOSE| re.UNICODE)
re.VERBOSE)
re_HandInfo = re.compile(""" re_HandInfo = re.compile("""
^Table\s+(?P<TTYPE>[$a-zA-Z0-9 ]+)?\s+ ^Table\s+(?P<TTYPE>[$a-zA-Z0-9 ]+)?\s+
@ -123,18 +127,16 @@ class PartyPoker(HandHistoryConverter):
self.compiledPlayers = players self.compiledPlayers = players
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")" player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
subst = {'PLYR': player_re, 'CUR_SYM': hand.SYMBOL[hand.gametype['currency']], subst = {'PLYR': player_re, 'CUR_SYM': self.sym[hand.gametype['currency']],
'CUR': hand.gametype['currency'] if hand.gametype['currency']!='T$' else ''} 'CUR': hand.gametype['currency'] if hand.gametype['currency']!='T$' else ''}
for key in ('CUR_SYM', 'CUR'):
subst[key] = re.escape(subst[key])
self.re_PostSB = re.compile( self.re_PostSB = re.compile(
r"^%(PLYR)s posts small blind \[%(CUR_SYM)s(?P<SB>[.,0-9]+) ?%(CUR)s\]\." % subst, r"^%(PLYR)s posts small blind \[%(CUR_SYM)s(?P<SB>[.,0-9]+) ?%(CUR)s\]\."
re.MULTILINE) % subst, re.MULTILINE)
self.re_PostBB = re.compile( self.re_PostBB = re.compile(
r"^%(PLYR)s posts big blind \[%(CUR_SYM)s(?P<BB>[.,0-9]+) ?%(CUR)s\]\." % subst, u"%(PLYR)s posts big blind \[%(CUR_SYM)s(?P<BB>[.,0-9]+) ?%(CUR)s\]\."
re.MULTILINE) % subst, re.MULTILINE)
self.re_PostDead = re.compile( self.re_PostDead = re.compile(
r"^%(PLYR)s posts big blind \+ dead \[(?P<BBNDEAD>[.,0-9]+) ?%(CUR_SYM)s\]\." % subst, r"^%(PLYR)s posts big blind + dead \[(?P<BBNDEAD>[.,0-9]+) ?%(CUR_SYM)s\]\." % subst,
re.MULTILINE) re.MULTILINE)
self.re_Antes = re.compile( self.re_Antes = re.compile(
r"^%(PLYR)s posts ante \[%(CUR_SYM)s(?P<ANTE>[.,0-9]+) ?%(CUR)s\]" % subst, r"^%(PLYR)s posts ante \[%(CUR_SYM)s(?P<ANTE>[.,0-9]+) ?%(CUR)s\]" % subst,
@ -142,11 +144,10 @@ class PartyPoker(HandHistoryConverter):
self.re_HeroCards = re.compile( self.re_HeroCards = re.compile(
r"^Dealt to %(PLYR)s \[\s*(?P<NEWCARDS>.+)\s*\]" % subst, r"^Dealt to %(PLYR)s \[\s*(?P<NEWCARDS>.+)\s*\]" % subst,
re.MULTILINE) re.MULTILINE)
self.re_Action = re.compile(r""" self.re_Action = re.compile(u"""
^%(PLYR)s\s+(?P<ATYPE>bets|checks|raises|calls|folds|is\sall-In) ^%(PLYR)s\s+(?P<ATYPE>bets|checks|raises|calls|folds|is\sall-In)
(?:\s+\[%(CUR_SYM)s(?P<BET>[.,\d]+)\s*%(CUR)s\])? (?:\s+\[%(CUR_SYM)s(?P<BET>[.,\d]+)\s*%(CUR)s\])?
""" % subst, """ % subst, re.MULTILINE|re.VERBOSE)
re.MULTILINE|re.VERBOSE)
self.re_ShownCards = re.compile( self.re_ShownCards = re.compile(
r"^%s (?P<SHOWED>(?:doesn\'t )?shows?) " % player_re + r"^%s (?P<SHOWED>(?:doesn\'t )?shows?) " % player_re +
r"\[ *(?P<CARDS>.+) *\](?P<COMBINATION>.+)\.", r"\[ *(?P<CARDS>.+) *\](?P<COMBINATION>.+)\.",
@ -181,10 +182,6 @@ class PartyPoker(HandHistoryConverter):
return self._gameType return self._gameType
return self._gameType return self._gameType
@staticmethod
def decode_hand_text(handText):
return handText.encode("latin1").decode(LOCALE_ENCODING)
def determineGameType(self, handText): def determineGameType(self, handText):
"""inspect the handText and return the gametype dict """inspect the handText and return the gametype dict
@ -192,7 +189,6 @@ class PartyPoker(HandHistoryConverter):
{'limitType': xxx, 'base': xxx, 'category': xxx}""" {'limitType': xxx, 'base': xxx, 'category': xxx}"""
info = {} info = {}
handText = self.decode_hand_text(handText)
m = self._getGameType(handText) m = self._getGameType(handText)
m_20BBmin = self.re_20BBmin.search(handText) m_20BBmin = self.re_20BBmin.search(handText)
if m is None: if m is None:
@ -210,7 +206,6 @@ class PartyPoker(HandHistoryConverter):
'Omaha' : ('hold','omahahi'), 'Omaha' : ('hold','omahahi'),
"7 Card Stud Hi-Lo" : ('stud','studhi'), "7 Card Stud Hi-Lo" : ('stud','studhi'),
} }
currencies = { '$':'USD', '':'T$' }
for expectedField in ['LIMIT', 'GAME']: for expectedField in ['LIMIT', 'GAME']:
if mg[expectedField] is None: if mg[expectedField] is None:
@ -243,7 +238,7 @@ class PartyPoker(HandHistoryConverter):
info['bb'] = "%.2f" % (bb) info['bb'] = "%.2f" % (bb)
info['sb'] = "%.2f" % (sb) info['sb'] = "%.2f" % (sb)
info['currency'] = currencies[mg['CURRENCY']] info['currency'] = self.currencies[mg['CURRENCY']]
else: else:
info['sb'] = clearMoneyString(mg['SB']) info['sb'] = clearMoneyString(mg['SB'])
info['bb'] = clearMoneyString(mg['BB']) info['bb'] = clearMoneyString(mg['BB'])
@ -253,15 +248,11 @@ class PartyPoker(HandHistoryConverter):
def readHandInfo(self, hand): def readHandInfo(self, hand):
# we should redecode handtext here (as it imposible to it above)
# if you know more accurate way to do it - tell me
hand.handText = self.decode_hand_text(hand.handText)
info = {} info = {}
try: try:
info.update(self.re_Hid.search(hand.handText).groupdict()) info.update(self.re_Hid.search(hand.handText).groupdict())
except: except AttributeError, e:
raise FpdbParseError(_("Cannot read HID for current hand")) raise FpdbParseError(_("Cannot read HID for current hand: %s" % e))
try: try:
info.update(self.re_HandInfo.search(hand.handText,re.DOTALL).groupdict()) info.update(self.re_HandInfo.search(hand.handText,re.DOTALL).groupdict())
@ -374,7 +365,6 @@ class PartyPoker(HandHistoryConverter):
else: else:
#zero stacked players are added later #zero stacked players are added later
zeroStackPlayers.append([int(a.group('SEAT')), a.group('PNAME'), clearMoneyString(a.group('CASH'))]) zeroStackPlayers.append([int(a.group('SEAT')), a.group('PNAME'), clearMoneyString(a.group('CASH'))])
if hand.gametype['type'] == 'ring': if hand.gametype['type'] == 'ring':
#finds first vacant seat after an exact seat #finds first vacant seat after an exact seat
def findFirstEmptySeat(startSeat): def findFirstEmptySeat(startSeat):

View File

@ -264,7 +264,7 @@ class PokerStars(HandHistoryConverter):
hand.buyinCurrency="PSFP" hand.buyinCurrency="PSFP"
else: else:
#FIXME: handle other currencies, FPP, play money #FIXME: handle other currencies, FPP, play money
raise FpdbParseError(_("failed to detect currency")) raise FpdbParseError(_("Failed to detect currency: '%s'" % info[key]))
info['BIAMT'] = info['BIAMT'].strip(u'$€FPP') info['BIAMT'] = info['BIAMT'].strip(u'$€FPP')

View File

@ -1064,7 +1064,7 @@ class Sql:
activeSeats SMALLINT NOT NULL, activeSeats SMALLINT NOT NULL,
position CHAR(1), position CHAR(1),
tourneyTypeId SMALLINT UNSIGNED, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId SMALLINT UNSIGNED, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
styleKey CHAR(9) NOT NULL, /* 1st char is style (A/T/H/S), other 8 are the key */ styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */
HDs INT NOT NULL, HDs INT NOT NULL,
wonWhenSeenStreet1 FLOAT, wonWhenSeenStreet1 FLOAT,
@ -1165,7 +1165,7 @@ class Sql:
activeSeats SMALLINT, activeSeats SMALLINT,
position CHAR(1), position CHAR(1),
tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
styleKey CHAR(9) NOT NULL, /* 1st char is style (A/T/H/S), other 8 are the key */ styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */
HDs INT, HDs INT,
wonWhenSeenStreet1 FLOAT, wonWhenSeenStreet1 FLOAT,
@ -2047,7 +2047,7 @@ class Sql:
# gets a date, would need to use handsplayers (not hudcache) to get exact hand Id # gets a date, would need to use handsplayers (not hudcache) to get exact hand Id
if db_server == 'mysql': if db_server == 'mysql':
self.query['get_date_nhands_ago'] = """ self.query['get_date_nhands_ago'] = """
select concat( 'd', date_format(max(h.startTime), '%Y%m%d%H') ) select concat( 'd', date_format(max(h.startTime), '%Y%m%d') )
from (select hp.playerId from (select hp.playerId
,coalesce(greatest(max(hp.handId)-%s,1),1) as maxminusx ,coalesce(greatest(max(hp.handId)-%s,1),1) as maxminusx
from HandsPlayers hp from HandsPlayers hp
@ -2059,7 +2059,7 @@ class Sql:
""" """
elif db_server == 'postgresql': elif db_server == 'postgresql':
self.query['get_date_nhands_ago'] = """ self.query['get_date_nhands_ago'] = """
select 'd' || to_char(max(h3.startTime), 'YYMMDDHH') select 'd' || to_char(max(h3.startTime), 'YYMMDD')
from (select hp.playerId from (select hp.playerId
,coalesce(greatest(max(hp.handId)-%s,1),1) as maxminusx ,coalesce(greatest(max(hp.handId)-%s,1),1) as maxminusx
from HandsPlayers hp from HandsPlayers hp
@ -2071,7 +2071,7 @@ class Sql:
""" """
elif db_server == 'sqlite': # untested guess at query: elif db_server == 'sqlite': # untested guess at query:
self.query['get_date_nhands_ago'] = """ self.query['get_date_nhands_ago'] = """
select 'd' || strftime(max(h3.startTime), 'YYMMDDHH') select 'd' || strftime(max(h3.startTime), 'YYMMDD')
from (select hp.playerId from (select hp.playerId
,coalesce(greatest(max(hp.handId)-%s,1),1) as maxminusx ,coalesce(greatest(max(hp.handId)-%s,1),1) as maxminusx
from HandsPlayers hp from HandsPlayers hp
@ -2479,7 +2479,11 @@ class Sql:
select s.name AS siteName select s.name AS siteName
,t.tourneyTypeId AS tourneyTypeId ,t.tourneyTypeId AS tourneyTypeId
,tt.currency AS currency ,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
WHEN tt.currency = 'EUR' THEN tt.buyIn/100.0
ELSE tt.buyIn
END) AS buyIn
,tt.fee/100.0 AS fee ,tt.fee/100.0 AS fee
,tt.category AS category ,tt.category AS category
,tt.limitType AS limitType ,tt.limitType AS limitType
@ -2512,7 +2516,11 @@ class Sql:
select s.name AS siteName select s.name AS siteName
,t.tourneyTypeId AS tourneyTypeId ,t.tourneyTypeId AS tourneyTypeId
,tt.currency AS currency ,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
WHEN tt.currency = 'EUR' THEN tt.buyIn/100.0
ELSE tt.buyIn
END) AS buyIn
,tt.fee/100.0 AS fee ,tt.fee/100.0 AS fee
,tt.category AS category ,tt.category AS category
,tt.limitType AS limitType ,tt.limitType AS limitType
@ -2546,7 +2554,11 @@ class Sql:
select s.name AS siteName select s.name AS siteName
,t.tourneyTypeId AS tourneyTypeId ,t.tourneyTypeId AS tourneyTypeId
,tt.currency AS currency ,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
WHEN tt.currency = 'EUR' THEN tt.buyIn/100.0
ELSE tt.buyIn
END) AS buyIn
,tt.fee/100.0 AS fee ,tt.fee/100.0 AS fee
,tt.category AS category ,tt.category AS category
,tt.limitType AS limitType ,tt.limitType AS limitType
@ -3290,7 +3302,7 @@ class Sql:
else 'E' else 'E'
end AS hc_position end AS hc_position
<tourney_select_clause> <tourney_select_clause>
,date_format(h.startTime, 'd%y%m%d%H') ,date_format(h.startTime, 'd%y%m%d')
,count(1) ,count(1)
,sum(wonWhenSeenStreet1) ,sum(wonWhenSeenStreet1)
,sum(wonWhenSeenStreet2) ,sum(wonWhenSeenStreet2)
@ -3379,7 +3391,7 @@ class Sql:
,h.seats ,h.seats
,hc_position ,hc_position
<tourney_group_clause> <tourney_group_clause>
,date_format(h.startTime, 'd%y%m%d%H') ,date_format(h.startTime, 'd%y%m%d')
""" """
elif db_server == 'postgresql': elif db_server == 'postgresql':
self.query['rebuildHudCache'] = """ self.query['rebuildHudCache'] = """
@ -3488,7 +3500,7 @@ class Sql:
else 'E' else 'E'
end AS hc_position end AS hc_position
<tourney_select_clause> <tourney_select_clause>
,'d' || to_char(h.startTime, 'YYMMDDHH') ,'d' || to_char(h.startTime, 'YYMMDD')
,count(1) ,count(1)
,sum(wonWhenSeenStreet1) ,sum(wonWhenSeenStreet1)
,sum(wonWhenSeenStreet2) ,sum(wonWhenSeenStreet2)
@ -3577,7 +3589,7 @@ class Sql:
,h.seats ,h.seats
,hc_position ,hc_position
<tourney_group_clause> <tourney_group_clause>
,to_char(h.startTime, 'YYMMDDHH') ,to_char(h.startTime, 'YYMMDD')
""" """
else: # assume sqlite else: # assume sqlite
self.query['rebuildHudCache'] = """ self.query['rebuildHudCache'] = """
@ -3686,7 +3698,7 @@ class Sql:
else 'E' else 'E'
end AS hc_position end AS hc_position
<tourney_select_clause> <tourney_select_clause>
,'d' || substr(strftime('%Y%m%d%H', h.startTime),3,9) ,'d' || substr(strftime('%Y%m%d', h.startTime),3,7)
,count(1) ,count(1)
,sum(wonWhenSeenStreet1) ,sum(wonWhenSeenStreet1)
,sum(wonWhenSeenStreet2) ,sum(wonWhenSeenStreet2)
@ -3775,7 +3787,7 @@ class Sql:
,h.seats ,h.seats
,hc_position ,hc_position
<tourney_group_clause> <tourney_group_clause>
,'d' || substr(strftime('%Y%m%d%H', h.startTime),3,9) ,'d' || substr(strftime('%Y%m%d', h.startTime),3,7)
""" """
self.query['insert_hudcache'] = """ self.query['insert_hudcache'] = """
@ -3968,7 +3980,8 @@ class Sql:
AND playerId=%s AND playerId=%s
AND activeSeats=%s AND activeSeats=%s
AND position=%s AND position=%s
AND tourneyTypeId+0=%s AND (case when tourneyTypeId is NULL then 1 else
(case when tourneyTypeId+0=%s then 1 else 0 end) end)=1
AND styleKey=%s""" AND styleKey=%s"""
self.query['get_hero_hudcache_start'] = """select min(hc.styleKey) self.query['get_hero_hudcache_start'] = """select min(hc.styleKey)

View File

@ -27,7 +27,7 @@ class Stove:
def __init__(self): def __init__(self):
self.hand = None self.hand = None
self.board = None self.board = None
self.range = None self.h_range = None
def set_board_with_list(self, board): def set_board_with_list(self, board):
pass pass
@ -58,7 +58,7 @@ class Stove:
def set_villain_range_string(self, string): def set_villain_range_string(self, string):
# Villain's range # Villain's range
range = Range() h_range = Range()
hands_in_range = string.strip().split(',') hands_in_range = string.strip().split(',')
for h in hands_in_range: for h in hands_in_range:
_h = h.strip() _h = h.strip()
@ -67,11 +67,11 @@ class Stove:
r1 = cc[0] r1 = cc[0]
r2 = cc[1] r2 = cc[1]
vp = Cards(r1, r2) vp = Cards(r1, r2)
range.add(vp) h_range.add(vp)
else: else:
range.expand(expand_hands(_h, pocket_cards, board)) h_range.expand(expand_hands(_h, self.hand, self.board))
self.range = range self.h_range = h_range
class Cards: class Cards:
@ -147,37 +147,17 @@ class SumEV:
self.n_ties += ev.n_ties self.n_ties += ev.n_ties
self.n_losses += ev.n_losses self.n_losses += ev.n_losses
def show(self, hand, range): def show(self, hand, h_range):
win_pct = 100 * (float(self.n_wins) / float(self.n_hands)) win_pct = 100 * (float(self.n_wins) / float(self.n_hands))
lose_pct = 100 * (float(self.n_losses) / float(self.n_hands)) lose_pct = 100 * (float(self.n_losses) / float(self.n_hands))
tie_pct = 100 * (float(self.n_ties) / float(self.n_hands)) tie_pct = 100 * (float(self.n_ties) / float(self.n_hands))
print 'Enumerated %d possible plays.' % self.n_hands print 'Enumerated %d possible plays.' % self.n_hands
print 'Your hand: (%s %s)' % (hand.c1, hand.c2) print 'Your hand: (%s %s)' % (hand.c1, hand.c2)
print 'Against the range: %s\n' % cards_from_range(range) print 'Against the range: %s\n' % cards_from_range(h_range)
print ' Win Lose Tie' print ' Win Lose Tie'
print ' %5.2f%% %5.2f%% %5.2f%%' % (win_pct, lose_pct, tie_pct) print ' %5.2f%% %5.2f%% %5.2f%%' % (win_pct, lose_pct, tie_pct)
def usage(me):
print """Texas Hold'Em odds calculator
Calculates odds against a range of hands.
To use: %s '<board cards>' '<your hand>' '<opponent's range>' [...]
Separate cards with space.
Separate hands in range with commas.
""" % me
def cards_from_range(range):
s = '{'
for h in range:
if h.c1 == '__' and h.c2 == '__':
s += 'random, '
else:
s += '%s%s, ' % (h.c1, h.c2)
s = s.rstrip(', ')
s += '}'
return s
# Expands hand abbreviations such as JJ and AK to full hand ranges. # Expands hand abbreviations such as JJ and AK to full hand ranges.
@ -202,7 +182,7 @@ def expand_hands(abbrev, hand, board):
else: else:
selection = ANY selection = ANY
range = [] h_range = []
considered = set() considered = set()
for s1 in SUITS: for s1 in SUITS:
c1 = r1 + s1 c1 = r1 + s1
@ -216,8 +196,8 @@ def expand_hands(abbrev, hand, board):
elif selection == OFFSUIT and s1 == s2: elif selection == OFFSUIT and s1 == s2:
continue continue
if c2 not in considered and c2 not in known_cards: if c2 not in considered and c2 not in known_cards:
range.append(Cards(c1, c2)) h_range.append(Cards(c1, c2))
return range return h_range
def parse_args(args, container): def parse_args(args, container):
@ -229,7 +209,6 @@ def parse_args(args, container):
container.set_hero_cards_string(args[2]) container.set_hero_cards_string(args[2])
container.set_villain_range_string(args[3]) container.set_villain_range_string(args[3])
return True return True
@ -281,7 +260,7 @@ def odds_for_range(holder):
iters = random.randint(25000, 125000) iters = random.randint(25000, 125000)
else: else:
iters = -1 iters = -1
for h in holder.range.get(): for h in holder.h_range.get():
e = odds_for_hand( e = odds_for_hand(
[holder.hand.c1, holder.hand.c2], [holder.hand.c1, holder.hand.c2],
[h.c1, h.c2], [h.c1, h.c2],
@ -290,7 +269,28 @@ def odds_for_range(holder):
) )
sev.add(e) sev.add(e)
sev.show(holder.hand, holder.range.get()) sev.show(holder.hand, holder.h_range.get())
def usage(me):
print """Texas Hold'Em odds calculator
Calculates odds against a range of hands.
To use: %s '<board cards>' '<your hand>' '<opponent's range>' [...]
Separate cards with space.
Separate hands in range with commas.
""" % me
def cards_from_range(h_range):
s = '{'
for h in h_range:
if h.c1 == '__' and h.c2 == '__':
s += 'random, '
else:
s += '%s%s, ' % (h.c1, h.c2)
s = s.rstrip(', ')
s += '}'
return s
def main(argv=None): def main(argv=None):
stove = Stove() stove = Stove()

View File

@ -116,6 +116,7 @@ import GuiAutoImport
import GuiGraphViewer import GuiGraphViewer
import GuiTourneyGraphViewer import GuiTourneyGraphViewer
import GuiSessionViewer import GuiSessionViewer
import GuiReplayer
import GuiStove import GuiStove
import SQL import SQL
import Database import Database
@ -779,6 +780,7 @@ class fpdb:
<menuitem action="tourneyviewer"/> <menuitem action="tourneyviewer"/>
<menuitem action="posnstats"/> <menuitem action="posnstats"/>
<menuitem action="sessionstats"/> <menuitem action="sessionstats"/>
<menuitem action="replayer"/>
<menuitem action="stove"/> <menuitem action="stove"/>
</menu> </menu>
<menu action="database"> <menu action="database">
@ -822,6 +824,7 @@ class fpdb:
('tourneyviewer', None, _('Tourney _Viewer'), None, 'Tourney Viewer)', self.tab_tourney_viewer_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, not on sqlite)', self.tab_positional_stats), ('posnstats', None, _('P_ositional Stats (tabulated view, not on sqlite)'), _('<control>O'), 'Positional Stats (tabulated view, not on sqlite)', self.tab_positional_stats),
('sessionstats', None, _('Session Stats'), None, 'Session Stats', self.tab_session_stats), ('sessionstats', None, _('Session Stats'), None, 'Session Stats', self.tab_session_stats),
('replayer', None, _('Hand _Replayer'), None, 'Hand Replayer', self.tab_replayer),
('database', None, _('_Database')), ('database', None, _('_Database')),
('maintaindbs', None, _('_Maintain Databases'), None, 'Maintain Databases', self.dia_maintain_dbs), ('maintaindbs', None, _('_Maintain Databases'), None, 'Maintain Databases', self.dia_maintain_dbs),
('createtabs', None, _('Create or Recreate _Tables'), None, 'Create or Recreate Tables ', self.dia_recreate_tables), ('createtabs', None, _('Create or Recreate _Tables'), None, 'Create or Recreate Tables ', self.dia_recreate_tables),
@ -1046,6 +1049,12 @@ class fpdb:
ps_tab=new_ps_thread.get_vbox() ps_tab=new_ps_thread.get_vbox()
self.add_and_display_tab(ps_tab, _("Session Stats")) self.add_and_display_tab(ps_tab, _("Session Stats"))
def tab_replayer(self, widget, data=None):
new_ps_thread = GuiReplayer.GuiReplayer(self.config, self.sql, self.window)
self.threads.append(new_ps_thread)
ps_tab=new_ps_thread.get_vbox()
self.add_and_display_tab(ps_tab, _("Hand Replayer"))
def tab_main_help(self, widget, data=None): def tab_main_help(self, widget, data=None):
"""Displays a tab with the main fpdb help screen""" """Displays a tab with the main fpdb help screen"""
mh_tab=gtk.Label(_("""Fpdb needs translators! mh_tab=gtk.Label(_("""Fpdb needs translators!

24
pyfpdb/fpdb_import.py Executable file → Normal file
View File

@ -83,6 +83,7 @@ class Importer:
self.pos_in_file = {} # dict to remember how far we have read in the file self.pos_in_file = {} # dict to remember how far we have read in the file
#Set defaults #Set defaults
self.callHud = self.config.get_import_parameters().get("callFpdbHud") self.callHud = self.config.get_import_parameters().get("callFpdbHud")
self.cacheSessions = self.config.get_import_parameters().get("cacheSessions")
# CONFIGURATION OPTIONS # CONFIGURATION OPTIONS
self.settings.setdefault("minPrint", 30) self.settings.setdefault("minPrint", 30)
@ -110,6 +111,9 @@ class Importer:
#Set functions #Set functions
def setCallHud(self, value): def setCallHud(self, value):
self.callHud = value self.callHud = value
def setCacheSessions(self, value):
self.cacheSessions = value
def setMinPrint(self, value): def setMinPrint(self, value):
self.settings['minPrint'] = int(value) self.settings['minPrint'] = int(value)
@ -491,14 +495,22 @@ class Importer:
if hand is not None and not hand.is_duplicate: if hand is not None and not hand.is_duplicate:
hand.updateHudCache(self.database) hand.updateHudCache(self.database)
self.database.commit() self.database.commit()
# Call sessionsCache update
if self.cacheSessions:
for hand in handlist:
if hand is not None and not hand.is_duplicate:
hand.updateSessionsCache(self.database)
self.database.commit()
#pipe the Hands.id out to the HUD #pipe the Hands.id out to the HUD
for hid in to_hud: if self.caller:
try: for hid in to_hud:
print _("fpdb_import: sending hand to hud"), hand.dbid_hands, "pipe =", self.caller.pipe_to_hud try:
self.caller.pipe_to_hud.stdin.write("%s" % (hid) + os.linesep) print _("fpdb_import: sending hand to hud"), hand.dbid_hands, "pipe =", self.caller.pipe_to_hud
except IOError, e: self.caller.pipe_to_hud.stdin.write("%s" % (hid) + os.linesep)
log.error(_("Failed to send hand to HUD: %s") % e) except IOError, e:
log.error(_("Failed to send hand to HUD: %s") % e)
errors = getattr(hhc, 'numErrors') errors = getattr(hhc, 'numErrors')
stored = getattr(hhc, 'numHands') stored = getattr(hhc, 'numHands')

View File

@ -0,0 +1,32 @@
Game #9864152000 starts.
#Game No : 9864152000
***** Hand History for Game 9864152000 *****
€10 EUR NL Texas Hold'em - Sunday, November 21, 19:00:00 CET 2010
Table Table 183347 (Real Money)
Seat 1 is the button
Total number of players : 5/6
Seat 3: Hero ( €10 EUR )
Seat 6: Player6 ( €16.49 EUR )
Seat 4: Player4 ( €10.73 EUR )
Seat 1: Player1 ( €8.56 EUR )
Seat 2: Player2 ( €4.90 EUR )
Player2 posts small blind [€0.05 EUR].
Hero posts big blind [€0.10 EUR].
** Dealing down cards **
Dealt to Hero [ Ah Kc ]
Player4 calls [€0.10 EUR]
Player6 calls [€0.10 EUR]
Player1 calls [€0.10 EUR]
Player2 calls [€0.05 EUR]
Hero raises [€0.56 EUR]
Player4 folds
Player6 folds
Player1 folds
Player2 calls [€0.56 EUR]
** Dealing Flop ** [ 5s, 9d, Ad ]
Player2 checks
Hero bets [€1.52 EUR]
Player2 folds
Hero does not show cards.
Hero wins €3.04 EUR

View File

@ -1,3 +1,6 @@
Game #9423586142 starts.
#Game No : 9423586142
***** Hand History For Game 9423586142 ***** ***** Hand History For Game 9423586142 *****
0.01/0.02 Texas Hold'em Game Table (NL) - Mon Jul 12 13:38:32 EDT 2010 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 Table 20BB Min Speed #1775757 (Real Money) -- Seat 1 is the button

178
utils/pypokertest.py Normal file
View File

@ -0,0 +1,178 @@
#
# Copyright (C) 2007, 2008 Loic Dachary <loic@dachary.org>
# Copyright (C) 2004, 2005, 2006 Mekensleep
#
# Mekensleep
# 24 rue vieille du temple
# 75004 Paris
# licensing@mekensleep.com
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#
# Authors:
# Loic Dachary <loic@dachary.org>
#
#
import sys
sys.path.insert(0, ".")
sys.path.insert(0, ".libs")
from pokereval import PokerEval
iterations_low = 100000
iterations_high = 200000
pokereval = PokerEval()
if pokereval.best_hand_value("hi", ["Ah", "Ad", "As", "Kh", "Ks" ]) != 101494784:
sys.exit(1)
if pokereval.string2card("2h") != 0:
sys.exit(1)
print ""
pockets = [ ["As", "Ad", "Ac", "Tc", "Ts", "2d", "5c" ],
["Js", "Jc", "7s", "8c", "8d", "3c", "3h" ],
[255, 255 ] ]
print "stud7 (1) result = %s\n" % pokereval.winners(game = "7stud", pockets = pockets, dead = [], board = [])
pockets = [[22, 18, 21, 3, 41, 1, 30], [39, 255, 255, 15, 13, 17, 255]]
print "stud7 (2) result = %s\n" % pokereval.winners(game = "7stud", pockets = pockets, dead = [], board = [])
print [ j + i + "/%d" % pokereval.string2card(j + i) for i in "hdcs" for j in "23456789TJQKA" ]
print "deck = %s\n" % pokereval.deck()
print "result = %s\n" % pokereval.poker_eval(game = "holdem", pockets = [ ["tc", "ac"], ["3h", "ah"], ["8c", "6h"]], dead = [], board = ["7h", "3s", "2c"])
print "winners = %s\n" % pokereval.winners(game = "holdem", pockets = [ ["tc", "ac"], ["3h", "ah"], ["8c", "6h"]], dead = [], board = ["7h", "3s", "2c"])
print "result = %s\n" % pokereval.poker_eval(game = "holdem", pockets = [ ["tc", "ac"], ["th", "ah"], ["8c", "6h"]], dead = [], board = ["7h", "3s", "2c", "7s", "7d"])
print "winners = %s\n" % pokereval.winners(game = "holdem", pockets = [ ["tc", "ac"], ["th", "ah"], ["8c", "6h"]], dead = [], board = ["7h", "3s", "2c", "7s", "7d"])
print "winners (filthy pockets) = %s\n" % pokereval.winners(game = "holdem", pockets = [ ["tc", "ac", 255], [], [255, 255], ["th", "ah"], ["8c", "6h"]], dead = [], board = ["7h", "3s", "2c", "7s", "7d"])
print "winners omaha = %s\n" % pokereval.winners(game = "omaha", pockets = [ ["tc", "ac", "ks", "kc" ], ["th", "ah", "qs", "qc" ], ["8c", "6h", "js", "jc" ]], dead = [], board = ["7h", "3s", "2c", "7s", "7d"])
print "winners omaha8 = %s\n" % pokereval.winners(game = "omaha8", pockets = [ ["tc", "ac", "ks", "kc" ], ["th", "ah", "qs", "qc" ], ["8c", "6h", "js", "jc" ]], dead = [], board = ["7h", "3s", "2c", "7s", "7d"])
hand = ["Ac", "As", "Td", "7s", "7h", "3s", "2c"]
best_hand = pokereval.best_hand("hi", hand)
print "best hand from %s = %s" % ( hand, pokereval.best_hand("hi", hand) )
print "best hand from %s = (%s) %s " % (hand, best_hand[0], [ pokereval.card2string(i) for i in best_hand[1:] ])
print ""
hand = ["Ah", "Ts", "Kh", "Qs", "Js" ]
best_hand = pokereval.best_hand("hi", hand)
print "best hand from %s = %s" % ( hand, pokereval.best_hand("hi", hand) )
print "best hand from %s = (%s) %s " % (hand, best_hand[0], [ pokereval.card2string(i) for i in best_hand[1:] ])
print ""
hand = ["2h", "Kh", "Qh", "Jh", "Th" ]
best_hand = pokereval.best_hand("hi", hand)
print "best hand from %s = %s" % ( hand, pokereval.best_hand("hi", hand) )
print "best hand from %s = (%s) %s " % (hand, best_hand[0], [ pokereval.card2string(i) for i in best_hand[1:] ])
print ""
hand = ['2s', '3s', 'Jd', 'Ks', 'As', '4d', '5h', '7d', '9c']
best_hand = pokereval.best_hand("hi", hand)
print "best hand from %s = %s" % ( hand, pokereval.best_hand("hi", hand) )
print "best hand from %s = (%s) %s " % (hand, best_hand[0], [ pokereval.card2string(i) for i in best_hand[1:] ])
print ""
hand = ['As', '2s', '4d', '4s', '5c', '5d', '7s']
best_hand = pokereval.best_hand("low", hand)
print "1/ low hand from %s = %s" % ( hand, pokereval.best("low", hand) )
print "best low hand from %s = (%s) %s " % (hand, best_hand[0], [ pokereval.card2string(i) for i in best_hand[1:] ])
print ""
hand = ['As', '2s', '4d', '4s', '5c', '5d', '8s']
best_hand = pokereval.best_hand("low", hand)
print "2/ low hand from %s = %s" % ( hand, pokereval.best("low", hand) )
print "best low hand from %s = (%s) %s " % (hand, best_hand[0], [ pokereval.card2string(i) for i in best_hand[1:] ])
print ""
hand = ['7d', '6c', '5h', '4d', 'As']
best_hand = pokereval.best_hand("low", hand)
print "3/ low hand from %s = %s" % ( hand, pokereval.best("low", hand) )
print "best low hand from %s = (%s) %s " % (hand, best_hand[0], [ pokereval.card2string(i) for i in best_hand[1:] ])
print ""
board = [ 'As', '4d', '5h', '7d', '9c' ]
hand = [ '2s', 'Ts', 'Jd', 'Ks' ]
best_hand = pokereval.best_hand("low", hand, board)
print "4/ low hand from %s / %s = %s" % ( hand, board, pokereval.best("low", hand, board) )
print "best low hand from %s / %s = (%s) %s " % (hand, board, best_hand[0], [ pokereval.card2string(i) for i in best_hand[1:] ])
print ""
board = [ 'As', '4d', '6h', '7d', '3c' ]
hand = [ '2s', '5s', 'Jd', 'Ks' ]
best_hand = pokereval.best_hand("low", hand, board)
print "low hand from %s / %s = %s" % ( hand, board, pokereval.best("low", hand, board) )
print "best low hand from %s / %s = (%s) %s " % (hand, board, best_hand[0], [ pokereval.card2string(i) for i in best_hand[1:] ])
print ""
board = [ 'Jc', '4c', '3c', '5c', '9c' ]
hand = [ '2c', 'Ac', '5h', '9d' ]
best_hand = pokereval.best_hand("hi", hand, board)
print "hi hand from %s / %s = %s" % ( hand, board, pokereval.best("hi", hand, board) )
print "best hi hand from %s / %s = (%s) %s " % (hand, board, best_hand[0], pokereval.card2string(best_hand[1:]))
print ""
board = [ 'Jd', '9c', 'Jc', 'Tc', '2h' ]
hand = [ '2c', '4c', 'Th', '6s' ]
best_hand = pokereval.best_hand("low", hand, board)
print "5/ low hand from %s / %s = %s" % ( hand, board, pokereval.best("low", hand, board) )
print "best low hand from %s / %s = (%s) %s " % (hand, board, best_hand[0], [ pokereval.card2string(i) for i in best_hand[1:] ])
print ""
board = [ 'Ks', 'Jd', '7s', '4d', 'Js' ]
hand = [ '2d', '6c', 'Ac', '5c' ]
best_hand = pokereval.best_hand("low", hand, board)
print "6/ low hand from %s / %s = %s" % ( hand, board, pokereval.best("low", hand, board) )
print "best low hand from %s / %s = (%s) %s " % (hand, board, best_hand[0], [ pokereval.card2string(i) for i in best_hand[1:] ])
if len(sys.argv) > 2:
print "f0 result = %s\n" % pokereval.poker_eval(game = "holdem", fill_pockets = 1, pockets = [ ["As", "3s"], ["__", "__"], ["__", "__"]], dead = [], board = ["__", "Qs", "2c", "Ac", "Kc"])
print ""
print "f1 result = %s\n" % pokereval.poker_eval(game = "holdem", fill_pockets = 1, pockets = [ ["As", "3s"], ["__", "__"], ["__", "__"]], dead = [], board = ["7s", "Qs", "2c", "Ac", "Kc"])
print ""
print "f2 result = %s\n" % pokereval.poker_eval(game = "holdem", fill_pockets = 1, iterations = iterations_low, pockets = [ ["As", "3s"], ["__", "__"], ["__", "__"]], dead = [], board = ["__", "__", "__", "__", "__"])
print ""
print "f3 result = %s\n" % pokereval.poker_eval(game = "holdem", fill_pockets = 1, iterations = iterations_high, pockets = [ ["As", "Ac"], ["__", "__"], ["__", "__"]], dead = [], board = ["__", "__", "__", "__", "__"])
print ""
print "f4 result = %s\n" % pokereval.poker_eval(game = "holdem", fill_pockets = 1, iterations = iterations_high, pockets = [ ["As", "Ks"], ["__", "__"], ["__", "__"]], dead = [], board = ["__", "__", "__", "__", "__"])
print ""
print "f5 result = %s\n" % pokereval.poker_eval(game = "holdem", fill_pockets = 1, iterations = iterations_high, pockets = [ ["2s", "2c"], ["__", "__"], ["__", "__"]], dead = [], board = ["__", "__", "__", "__", "__"])
print ""
print "f6 result = %s\n" % pokereval.poker_eval(game = "holdem", fill_pockets = 1, iterations = iterations_high, pockets = [ ["Js", "Jc"], ["__", "__"], ["__", "__"]], dead = [], board = ["__", "__", "__", "__", "__"])
print ""
print "f7 result = %s\n" % pokereval.poker_eval(game = "omaha", fill_pockets = 1, iterations = iterations_high, pockets = [ ["Js", "Jc", "7s", "8c"], ["__", "__", "__", "__"], ["__", "__", "__", "__"]], dead = [], board = ["__", "__", "__", "__", "__"])
print ""
hand = ['As', 'Ad']
print "handval %s = %d " % (hand, pokereval.evaln(hand))
print ""
hand = ['Qc', '7d']
print "handval %s = %d " % (hand, pokereval.evaln(hand))
pokereval = None