Merge branch 'master' of git://git.assembla.com/fpdboz.git
This commit is contained in:
commit
22cf70358f
274
pyfpdb/GuiReplayer.py
Normal file
274
pyfpdb/GuiReplayer.py
Normal 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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,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
|
||||||
|
@ -778,6 +779,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">
|
||||||
|
@ -821,6 +823,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),
|
||||||
|
@ -1049,6 +1052,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!
|
||||||
|
|
Loading…
Reference in New Issue
Block a user