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

This commit is contained in:
eblade 2008-12-11 02:57:08 -05:00
commit 51b62392e1
21 changed files with 4101 additions and 3349 deletions

View File

@ -29,8 +29,8 @@ cp -R regression-test fpdb-$1/
cp -R utils fpdb-$1/
cd fpdb-$1
zip -r ../../fpdb-1.0_$1.zip *
tar -cf - * | bzip2 >> ../../fpdb-1.0_$1.tar.bz2
zip -r releases/fpdb-1.0_$1.zip *
tar -cf - * | bzip2 >> releases/fpdb-1.0_$1.tar.bz2
cd ..
rm -r fpdb-$1

View File

@ -312,11 +312,10 @@ The program itself is licensed under AGPLv3, see agpl-3.0.txt</p>
</TABLE>
<p><BR></P>
<p><B>Table HandsPlayers</B></P>
<p>cardX: can be 1 through 20, one for each card. In holdem only 1-2 of these are used, in omaha 1-4, in stud/razz 1-7, in single draw games 1-10 is used and in badugi 1-16 (4*4) is used.</P>
<p>For the draw games: the first 5 (badugi: 4) cards are the initial cards, the next 5 (badugi: 4) are after the first draw. If a player keeps some cards then those cards' spaces are filled with "k", short for "kept".<br>
Example 1: If a player gets 2-6 spades for his first five cards and decides to throw away the 4 and then gets a 7 of spades then the first 10 fields of cardXValue would be as follows: 2, 3, 4, 5, 6, k, k, 7, k, k<br>
Example 2: If a player gets 2, 3, 5, 8, J of spades for his first five cards and decides to throw away the 2 and the 3 and then gets a Q and K of spades then the first 10 fields of cardXValue would be as follows: 2, 3, 5, 8, J, Q, K, k, k, k<br>
Note that it will k in the space of which card was there previously, so in example 2 where the player kept the last 3 cards, the last 3 fields of the first draw (ie. card8-10Value) are replaced with k.</p>
<p>cardX: can be 1 through 20, one for each card. In holdem only 1-2 of these are used, in omaha 1-4, in stud/razz 1-7, in single draw 1-10, in tripple draw all 20 and in badugi 1-16 (4*4).</P>
<p>For the draw games: the first 5 (badugi: 4) cards are the initial cards, the next 5 (badugi: 4) are after the first draw, etc.<br>
Example 1: If a player gets 2-6 spades for his first five cards and decides to throw away the 4 and then gets a 7 of spades then the first 10 fields of cardXValue would be as follows: 2, 3, 4, 5, 6, 2, 3, 5, 6, 7<br>
Example 2: If a player gets 2, 3, 5, 8, J of spades for his first five cards and decides to throw away the 2 and the 3 and then gets a Q and K of spades then the first 10 fields of cardXValue would be as follows: 2, 3, 5, 8, J, 5, 8, J, Q, K.</p>
<p>I did not separate this into an extra table because I felt the lost space is not sufficiently large. Also the benefit for searching is far less relevant.</P>
<TABLE BORDER=1 CELLPADDING=2 CELLSPACING=0>
<TR VALIGN=TOP>
@ -370,6 +369,17 @@ Note that it will k in the space of which card was there previously, so in examp
<TD><P>char(1)</P></TD>
<TD><P>h=hearts, s=spades, d=diamonds, c=clubs, unknown/no card=x</P></TD>
</TR>
<TR VALIGN=TOP>
<TD><P>cardXDiscarded</P></TD>
<TD><P>boolean</P></TD>
<TD><P>Whether the card was discarded (this only applies to draw games, X can be 1 through 15 since the final cards can obviously not be discarded).</P></TD>
</TR>
<TR VALIGN=TOP>
<TD><P>DrawnX</P></TD>
<TD><P>smallint</P></TD>
<TD><p>X can be 1 through 3.<br>
This field denotes how many cards the player has drawn on each draw.</P></TD>
</TR>
<TR VALIGN=TOP>
<TD><P>winnings</P></TD>
<TD><P>int</P></TD>

View File

@ -444,9 +444,9 @@ class Config:
def get_import_parameters(self):
imp = {}
try:
imp['callFpdbHud'] = self.callFpdbHud
imp['interval'] = self.interval
imp['hhArchiveBase'] = self.hhArchiveBase
imp['callFpdbHud'] = self.imp.callFpdbHud
imp['interval'] = self.imp.interval
imp['hhArchiveBase'] = self.imp.hhArchiveBase
except: # Default params
imp['callFpdbHud'] = True
imp['interval'] = 10
@ -613,9 +613,7 @@ if __name__== "__main__":
print "----------- END POPUP WINDOW FORMATS -----------"
print "\n----------- IMPORT -----------"
tmp = c.get_import_parameters()
for param in tmp:
print " " + str(param) + ": " + str(tmp[param])
print c.imp
print "----------- END IMPORT -----------"
print "\n----------- TABLE VIEW -----------"

73
pyfpdb/EverleafToFpdb.py Normal file → Executable file
View File

@ -58,23 +58,27 @@ from HandHistoryConverter import *
# smaragdar calls [$ 34.50 USD]
# ** Dealing Turn ** [ 2d ]
# ** Dealing River ** [ 6c ]
# dogge shows [ 9h, 9c ]a pair of nines
# spicybum shows [ 5d, 6d ]a straight, eight high
# harrydebeng does not show cards
# smaragdar wins $ 102 USD from main pot with a pair of aces [ ad, ah, qs, 8h, 6c ]
class Everleaf(HandHistoryConverter):
def __init__(self, config, file):
print "Initialising Everleaf converter class"
HandHistoryConverter.__init__(self, config, file, "Everleaf") # Call super class init.
HandHistoryConverter.__init__(self, config, file, sitename="Everleaf") # Call super class init.
self.sitename = "Everleaf"
self.setFileType("text")
self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)')
self.rexx.setSplitHandRegex('\n\n\n\n')
self.rexx.setHandInfoRegex('.*#(?P<HID>[0-9]+)\n.*\nBlinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>.*) - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+):(?P<SEC>[0-9]+)\nTable (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
self.rexx.setPlayerInfoRegex('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \( \$ (?P<CASH>[.0-9]+) USD \)')
self.rexx.setPostSbRegex('.*\n(?P<PNAME>.*): posts small blind \[')
self.rexx.setPostBbRegex('.*\n(?P<PNAME>.*): posts big blind \[')
self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<HOLECARDS>.*) \]')
self.rexx.setPostSbRegex('.*\n(?P<PNAME>.*): posts small blind \[\$? (?P<SB>[.0-9]+)')
self.rexx.setPostBbRegex('.*\n(?P<PNAME>.*): posts big blind \[\$? (?P<BB>[.0-9]+)')
# mct : what about posting small & big blinds simultaneously?
self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<HOLE1>\S\S), (?P<HOLE2>\S\S) \]')
self.rexx.setActionStepRegex('.*\n(?P<PNAME>.*) (?P<ATYPE>bets|checks|raises|calls|folds)(\s\[\$ (?P<BET>[.\d]+) USD\])?')
self.rexx.setShowdownActionRegex('.*\n(?P<PNAME>.*) shows \[ (?P<CARDS>.*) \]')
self.rexx.compileRegexes()
def readSupportedGames(self):
@ -115,26 +119,38 @@ class Everleaf(HandHistoryConverter):
players = []
for a in m:
players = players + [[a.group('SEAT'), a.group('PNAME'), a.group('CASH')]]
hand.players = players
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
def markStreets(self, hand):
# PREFLOP = ** Dealing down cards **
m = re.search('(\*\* Dealing down cards \*\*\n)(?P<PREFLOP>.*?\n\*\*)?( Dealing Flop \*\*)?(?P<FLOP>.*?\*\*)?( Dealing Turn \*\*)?(?P<TURN>.*?\*\*)?( Dealing River \*\*)?(?P<RIVER>.*)', hand.string,re.DOTALL)
m = re.search('(\*\* Dealing down cards \*\*\n)(?P<PREFLOP>.*?\n\*\*)?( Dealing Flop \*\* \[ (?P<FLOP1>\S\S), (?P<FLOP2>\S\S), (?P<FLOP3>\S\S) \])?(?P<FLOP>.*?\*\*)?( Dealing Turn \*\* \[ (?P<TURN1>\S\S) \])?(?P<TURN>.*?\*\*)?( Dealing River \*\* \[ (?P<RIVER1>\S\S) \])?(?P<RIVER>.*)', hand.string,re.DOTALL)
# for street in m.groupdict():
# print "DEBUG: Street: %s\tspan: %s" %(street, str(m.span(street)))
hand.streets = m
def readCommunityCards(self, hand):
# currently regex in wrong place pls fix my brain's fried
# what a mess!
re_board = re.compile('\*\* Dealing (?P<STREET>.*) \*\* \[ (?P<CARDS>.*) \]')
m = re_board.finditer(hand.string)
for street in m:
#print street.groups()
re_card = re.compile('(?P<CARD>[0-9tjqka][schd])') # look that's weird, hole cards have a capital rank but board cards are lower case?
cardsmatch = re_card.finditer(street.group('CARDS'))
hand.setCommunityCards(street.group('STREET'), [card.group('CARD') for card in cardsmatch])
def readBlinds(self, hand):
try:
m = self.rexx.small_blind_re.search(hand.string)
hand.posted = [m.group('PNAME')]
hand.addBlind(m.group('PNAME'), m.group('SB'))
#hand.posted = [m.group('PNAME')]
except:
hand.posted = ["FpdbNBP"]
hand.addBlind(None, 0)
#hand.posted = ["FpdbNBP"]
m = self.rexx.big_blind_re.finditer(hand.string)
for a in m:
hand.posted = hand.posted + [a.group('PNAME')]
hand.addBlind(a.group('PNAME'), a.group('BB'))
#hand.posted = hand.posted + [a.group('PNAME')]
def readHeroCards(self, hand):
m = self.rexx.hero_cards_re.search(hand.string)
@ -143,29 +159,38 @@ class Everleaf(HandHistoryConverter):
hand.involved = False
else:
hand.hero = m.group('PNAME')
hand.holecards = m.group('HOLECARDS')
hand.holecards = hand.holecards.replace(',','')
#Must be a better way to do the following tr akqjt AKQJT
hand.holecards = hand.holecards.replace('a','A')
hand.holecards = hand.holecards.replace('k','K')
hand.holecards = hand.holecards.replace('q','Q')
hand.holecards = hand.holecards.replace('j','J')
hand.holecards = hand.holecards.replace('t','T')
hand.addHoleCards([m.group('HOLE1'), m.group('HOLE2')], m.group('PNAME'))
def readAction(self, hand, street):
m = self.rexx.action_re.finditer(hand.streets.group(street))
hand.actions[street] = []
for action in m:
if action.group('ATYPE') == 'raises' or action.group('ATYPE') == 'calls':
hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE'), action.group('BET')]]
if action.group('ATYPE') == 'raises':
hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == 'calls':
hand.addCall( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == 'bets':
hand.addBet( street, action.group('PNAME'), action.group('BET') )
else:
#print "DEBUG: unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),)
hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE')]]
print "DEBUG: readAction: %s " %(hand.actions)
def readShowdownActions(self, hand):
for shows in self.rexx.showdown_action_re.finditer(hand.string):
print shows.groups()
re_card = re.compile('(?P<CARD>[0-9tjqka][schd])') # copied from earlier
cards = [card.group('CARD') for card in re_card.finditer(shows.group('CARDS'))]
print cards
hand.addHoleCards(cards, shows.group('PNAME'))
def getRake(self, hand):
hand.rake = hand.totalpot * Decimal('0.05') # probably not quite right
if __name__ == "__main__":
c = Configuration.Config()
e = Everleaf(c, "regression-test-files/everleaf/Speed_Kuala.txt")
e = Everleaf(c, "Speed_Kuala.txt")
e.processFile()
print str(e)

View File

@ -573,6 +573,27 @@ class FpdbSQLQueries:
elif(self.dbname == 'SQLite'):
self.query['createHudCacheTable'] = """ """
if(self.dbname == 'MySQL InnoDB'):
self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)"""
elif(self.dbname == 'PostgreSQL'):
self.query['addTourneyIndex'] = """CREATE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)"""
elif(self.dbname == 'SQLite'):
self.query['addHandsIndex'] = """ """
if(self.dbname == 'MySQL InnoDB'):
self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)"""
elif(self.dbname == 'PostgreSQL'):
self.query['addHandsIndex'] = """CREATE INDEX siteHandNo ON Hands (siteHandNo)"""
elif(self.dbname == 'SQLite'):
self.query['addHandsIndex'] = """ """
if(self.dbname == 'MySQL InnoDB'):
self.query['addPlayersIndex'] = """ALTER TABLE Players ADD INDEX name(name)"""
elif(self.dbname == 'PostgreSQL'):
self.query['addPlayersIndex'] = """CREATE INDEX name ON Players (name)"""
elif(self.dbname == 'SQLite'):
self.query['addPlayersIndex'] = """ """
################################
# Queries used in GuiGraphViewer
################################
@ -609,6 +630,11 @@ class FpdbSQLQueries:
WHERE Players.name = %s AND HandsPlayers.handId = %s
AND Players.siteId = %s AND (tourneysPlayersId IS NULL)"""
if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL'):
self.query['getPlayerId'] = """SELECT id from Players where name = %s"""
elif(self.dbname == 'SQLite'):
self.query['getPlayerId'] = """SELECT id from Players where name = %s"""
if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL'):
self.query['getRingProfitAllHandsPlayerIdSite'] = """
SELECT hp.handId, hp.winnings, SUM(ha.amount), hp.winnings - SUM(ha.amount)
@ -673,13 +699,11 @@ class FpdbSQLQueries:
,round(100*sum(street2Aggr)/sum(street2Seen)) AS TuAFq
,round(100*sum(street3Aggr)/sum(street3Seen)) AS RvAFq
,round(100*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr))
/(sum(street1Seen)+sum(street2Seen)+sum(street3Seen))) AS PFAFq
from Gametypes gt
inner join Sites s on s.Id = gt.siteId
inner join HudCache hc on hc.gameTypeId = gt.Id
where gt.limittype = 'nl'
and hc.playerId in (3) # use <player_test> here?
where hc.playerId in <player_test>
# use <gametype_test> here ?
group by hc.gametypeId
) stats
@ -692,7 +716,7 @@ class FpdbSQLQueries:
from HandsPlayers hp
inner join Hands h ON h.id = hp.handId
inner join HandsActions ha ON ha.handPlayerId = hp.id
where hp.playerId in (3) # use <player_test> here?
where hp.playerId in <player_test>
# use <gametype_test> here ?
and hp.tourneysPlayersId IS NULL
group by hp.handId, h.gameTypeId, hp.position, hp.winnings

View File

@ -83,9 +83,11 @@ class GuiGraphViewer (threading.Thread):
self.ax.set_xlabel("Hands", fontsize = 12)
self.ax.set_ylabel("$", fontsize = 12)
self.ax.grid(color='g', linestyle=':', linewidth=0.2)
#This line will crash if no hands exist in the query.
text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line))
self.ax.annotate(text, xy=(10, -10),
self.ax.annotate(text,
xy=(10, -10),
xycoords='axes points',
horizontalalignment='left', verticalalignment='top',
fontsize=10)
@ -232,6 +234,18 @@ class GuiGraphViewer (threading.Thread):
entry.set_text(ds)
win.destroy()
def exportGraph (self, widget, data):
dia_chooser = gtk.FileChooserDialog(title="Please choose the directory you wish to export to:",
action=gtk.FILE_CHOOSER_ACTION_OPEN,
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
response = dia_chooser.run()
if response == gtk.RESPONSE_OK:
self.exportDir = dia_chooser.get_filename()
elif response == gtk.RESPONSE_CANCEL:
print 'Closed, no graph exported'
dia_chooser.destroy()
def __init__(self, db, settings, querylist, config, debug=True):
"""Constructor for GraphViewer"""
self.debug=debug
@ -296,7 +310,7 @@ class GuiGraphViewer (threading.Thread):
graphButton.show()
self.exportButton=gtk.Button("Export to File")
#@ self.exportButton.connect("clicked", self.exportGraph, "show clicked")
self.exportButton.connect("clicked", self.exportGraph, "show clicked")
self.exportButton.show()
self.leftPanelBox.add(playerFrame)
@ -307,6 +321,3 @@ class GuiGraphViewer (threading.Thread):
self.leftPanelBox.show()
self.graphBox.show()
#Note: Assumes PokerStars is in the config
# self.nameEntry.set_text(self.conf.supported_sites["PokerStars"].screen_name)

165
pyfpdb/GuiPlayerStats.py Normal file
View File

@ -0,0 +1,165 @@
#!/usr/bin/python
#Copyright 2008 Steffen Jobbagy-Felso
#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 in the docs folder of the package.
import threading
import pygtk
pygtk.require('2.0')
import gtk
import os
import fpdb_import
import fpdb_db
import FpdbSQLQueries
class GuiPlayerStats (threading.Thread):
def get_vbox(self):
"""returns the vbox of this thread"""
return self.main_hbox
def toggleCallback(self, widget, data=None):
# print "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
self.activesite = data
print "DEBUG: activesite set to %s" %(self.activesite)
def refreshStats(self, widget, data):
try: self.stats_table.destroy()
except AttributeError: pass
self.fillStatsFrame(self.stats_frame)
def fillStatsFrame(self, vbox):
# Get currently active site and grab playerid
tmp = self.sql.query['playerStats']
result = self.cursor.execute(self.sql.query['getPlayerId'], self.heroes[self.activesite])
result = self.db.cursor.fetchall()
pid = result[0][0]
tmp = tmp.replace("<player_test>", "(" + str(pid) + ")")
self.cursor.execute(tmp)
result = self.db.cursor.fetchall()
cols = 18
rows = len(result)+1 # +1 for title row
self.stats_table = gtk.Table(rows, cols, False)
self.stats_table.set_col_spacings(4)
self.stats_table.show()
vbox.add(self.stats_table)
# Create header row
titles = ("GID", "base", "Style", "Site", "$BB", "Hands", "VPIP", "PFR", "saw_f", "sawsd", "wtsdwsf", "wmsd", "FlAFq", "TuAFq", "RvAFq", "PFAFq", "Net($)", "BB/100")
col = 0
row = 0
for t in titles:
l = gtk.Label(titles[col])
l.show()
self.stats_table.attach(l, col, col+1, row, row+1)
col +=1
for row in range(rows-1):
for col in range(cols):
if(row%2 == 0):
bgcolor = "white"
else:
bgcolor = "lightgrey"
eb = gtk.EventBox()
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
l = gtk.Label(result[row-1][col])
eb.add(l)
self.stats_table.attach(eb, col, col+1, row+1, row+2)
l.show()
eb.show()
def fillPlayerFrame(self, vbox):
for site in self.conf.supported_sites.keys():
hbox = gtk.HBox(False, 0)
vbox.pack_start(hbox, False, True, 0)
hbox.show()
player = self.conf.supported_sites[site].screen_name
self.createPlayerLine(hbox, site, player)
hbox = gtk.HBox(False, 0)
button = gtk.Button("Refresh")
button.connect("clicked", self.refreshStats, False)
button.show()
hbox.add(button)
vbox.pack_start(hbox, False, True, 0)
hbox.show()
def createPlayerLine(self, hbox, site, player):
if(self.buttongroup == None):
button = gtk.RadioButton(None, site + " id:")
button.set_active(True)
self.buttongroup = button
self.activesite = site
else:
button = gtk.RadioButton(self.buttongroup, site + " id:")
hbox.pack_start(button, True, True, 0)
button.connect("toggled", self.toggleCallback, site)
button.show()
pname = gtk.Entry()
pname.set_text(player)
pname.set_width_chars(20)
hbox.pack_start(pname, False, True, 0)
pname.connect("changed", self.__set_hero_name, site)
#TODO: Look at GtkCompletion - to fill out usernames
pname.show()
self.__set_hero_name(pname, site)
def __set_hero_name(self, w, site):
self.heroes[site] = w.get_text()
print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site])
def __init__(self, db, config, querylist, debug=True):
self.debug=debug
self.db=db
self.cursor=db.cursor
self.conf=config
self.sql = querylist
self.activesite = None
self.buttongroup = None
self.heroes = {}
self.stat_table = None
self.stats_frame = None
self.main_hbox = gtk.HBox(False, 0)
self.main_hbox.show()
playerFrame = gtk.Frame("Hero:")
playerFrame.set_label_align(0.0, 0.0)
playerFrame.show()
vbox = gtk.VBox(False, 0)
vbox.show()
self.fillPlayerFrame(vbox)
playerFrame.add(vbox)
statsFrame = gtk.Frame("Stats:")
statsFrame.set_label_align(0.0, 0.0)
statsFrame.show()
self.stats_frame = gtk.VBox(False, 0)
self.stats_frame.show()
self.fillStatsFrame(self.stats_frame)
statsFrame.add(self.stats_frame)
self.main_hbox.pack_start(playerFrame)
self.main_hbox.pack_start(statsFrame)

View File

@ -169,4 +169,3 @@ if __name__== "__main__":
main_window.show_all()
gtk.main()

View File

@ -23,11 +23,16 @@ import traceback
import os
import os.path
import xml.dom.minidom
from decimal import Decimal
import operator
from xml.dom.minidom import Node
from pokereval import PokerEval
class HandHistoryConverter:
eval = PokerEval()
def __init__(self, config, file, sitename):
print "HandHistory init called"
self.c = config
self.sitename = sitename
self.obs = "" # One big string
@ -66,18 +71,27 @@ class HandHistoryConverter:
self.readPlayerStacks(hand)
self.markStreets(hand)
self.readBlinds(hand)
self.readHeroCards(hand)
self.readHeroCards(hand) # want to generalise to draw games
self.readCommunityCards(hand) # read community cards
self.readShowdownActions(hand)
# Read action (Note: no guarantee this is in hand order.
for street in hand.streets.groupdict():
self.readAction(hand, street)
# finalise it (total the pot)
hand.totalPot()
self.getRake(hand)
if(hand.involved == True):
self.writeHand("output file", hand)
#self.writeHand("output file", hand)
hand.printHand()
else:
pass #Don't write out observed hands
# Functions to be implemented in the inheriting class
#####
# These functions are parse actions that may be overridden by the inheriting class
#
def readSupportedGames(self): abstract
# should return a list
@ -86,7 +100,14 @@ class HandHistoryConverter:
# Valid types specified in docs/tabledesign.html in Gametypes
def determineGameType(self): abstract
#TODO: Comment
# Read any of:
# HID HandID
# TABLE Table name
# SB small blind
# BB big blind
# GAMETYPE gametype
# YEAR MON DAY HR MIN SEC datetime
# BUTTON button seat number
def readHandInfo(self, hand): abstract
# Needs to return a list of lists in the format
@ -94,6 +115,7 @@ class HandHistoryConverter:
def readPlayerStacks(self, hand): abstract
# Needs to return a MatchObject with group names identifying the streets into the Hand object
# that is, pulls the chunks of preflop, flop, turn and river text into hand.streets MatchObject.
def markStreets(self, hand): abstract
#Needs to return a list in the format
@ -103,8 +125,12 @@ class HandHistoryConverter:
def readHeroCards(self, hand): abstract
def readAction(self, hand, street): abstract
# Some sites don't report the rake. This will be called at the end of the hand after the pot total has been calculated
# so that an inheriting class can calculate it for the specific site if need be.
def getRake(self, hand): abstract
def sanityCheck(self):
sane = False
sane = True
base_w = False
#Check if hhbase exists and is writable
#Note: Will not try to create the base HH directory
@ -175,35 +201,32 @@ class HandHistoryConverter:
print "XXXXXXXXX FIXME XXXXXXXX"
print "*** HOLE CARDS ***"
print "Dealt to %s [%s]" %(hand.hero ,hand.holecards)
#
## ACTION STUFF
# This is no limit only at the moment
print "Dealt to %s [%s %s]" %(hand.hero , hand.holecards[0], hand.holecards[1])
for act in hand.actions['PREFLOP']:
self.printActionLine(act, 0)
if 'PREFLOP' in hand.actions:
for act in hand.actions['PREFLOP']:
print "PF action"
if 'FLOP' in hand.actions:
print "*** FLOP *** [%s]" %("XXXXX Flop cards XXXXXX")
print "*** FLOP *** [%s %s %s]" %(hand.streets.group("FLOP1"), hand.streets.group("FLOP2"), hand.streets.group("FLOP3"))
for act in hand.actions['FLOP']:
self.printActionLine(act, 0)
if 'TURN' in hand.actions:
print "*** TURN *** [%s] [%s]" %("XXXXX Flop cards XXXXXX", "XXXXX Turn Card XXXXX")
print "*** TURN *** [%s %s %s] [%s]" %(hand.streets.group("FLOP1"), hand.streets.group("FLOP2"), hand.streets.group("FLOP3"), hand.streets.group("TURN1"))
for act in hand.actions['TURN']:
self.printActionLine(act, 0)
if 'RIVER' in hand.actions:
print "*** RIVER *** [%s %s] [%s]" %("XXXXX Flop cards XXXXXX", "XXXXX Turn Card XXXXX", "XXXXX River Card XXXXX")
print "*** RIVER *** [%s %s %s %s] [%s]" %(hand.streets.group("FLOP1"), hand.streets.group("FLOP2"), hand.streets.group("FLOP3"), hand.streets.group("TURN1"), hand.streets.group("RIVER1"))
for act in hand.actions['RIVER']:
self.printActionLine(act, 0)
print "*** SUMMARY ***"
print "XXXXXXXXXXXX Need sumary info XXXXXXXXXXX"
# print "Total pot $%s | Rake $%s)" %(hand.totalpot $" + hand.rake)
# print "Board [" + boardcards + "]"
#
# SUMMARY STUFF
def printActionLine(self, act, pot):
@ -214,6 +237,7 @@ class HandHistoryConverter:
if act[1] == 'raises':
print "%s: %s $%s to XXXpottotalXXX" %(act[0], act[1], act[2])
#takes a poker float (including , for thousand seperator and converts it to an int
def float2int (self, string):
pos=string.find(",")
@ -232,12 +256,15 @@ class HandHistoryConverter:
class Hand:
# def __init__(self, sitename, gametype, sb, bb, string):
UPS = {'a':'A', 't':'T', 'j':'J', 'q':'Q', 'k':'K'}
def __init__(self, sitename, gametype, string):
self.sitename = sitename
self.gametype = gametype
self.string = string
self.streets = None # A MatchObject using a groupnames to identify streets.
self.streetList = ['BLINDS','PREFLOP','FLOP','TURN','RIVER'] # a list of the observed street names in order
self.actions = {}
self.handid = 0
@ -251,26 +278,237 @@ class Hand:
self.players = []
self.posted = []
self.involved = True
self.hero = "Hiro"
self.holecards = "Xx Xx"
self.holecards = {} # dict from player names to lists of hole cards
self.board = {} # dict from street names to community cards
self.action = []
self.totalpot = None
self.rake = None
self.bets = {}
self.lastBet = {}
for street in self.streetList:
self.bets[street] = {}
self.lastBet[street] = 0
def addPlayer(self, seat, name, chips):
"""seat, an int indicating the seat
name, the player name
chips, the chips the player has at the start of the hand"""
#self.players.append(name)
self.players.append([seat, name, chips])
self.holecards[name] = []
#self.startChips[name] = chips
#self.endChips[name] = chips
#self.winners[name] = 0
for street in self.streetList:
self.bets[street][name] = []
def addHoleCards(self, cards, player=None): # generalise to add hole cards for a specific seat or player
for c in cards:
self.holecards[player].append(self.card(c))
def discardHoleCards(self, cards, player=None):
if seat is None:
#raise something
pass
for card in cards:
try:
self.holecards[player].remove(card)
except ValueError:
print "tried to discard a card player apparently didn't have"
def setCommunityCards(self, street, cards):
self.board[street] = [self.card(c) for c in cards]
print self.board[street]
def card(self,c):
"""upper case the ranks but not suits, 'atjqk' => 'ATJQK'"""
# don't know how to make this 'static'
for k,v in self.UPS.items():
c = c.replace(k,v)
return c
def addBlind(self, player, amount):
# if player is None, it's a missing small blind.
if player is not None:
self.bets['PREFLOP'][player].append(Decimal(amount))
self.lastBet['PREFLOP'] = Decimal(amount)
self.posted += [player]
#def addFold(self, street, player=None):
## Called when a player folds.
#self.bets[street][player].append(None)
#def addCheck(self, street, player=None):
#self.bets[street][player].append(0)
def addCall(self, street, player=None, amount=None):
# Potentially calculate the amount of the call if not supplied
# corner cases include if player would be all in
if amount is not None:
self.bets[street][player].append(Decimal(amount))
#self.lastBet[street] = Decimal(amount)
self.actions[street] += [[player, 'calls', amount]]
def addRaiseTo(self, street, player, amountTo):
# Given only the amount raised to, the amount of the raise can be calculated by
# working out how much this player has already in the pot
# (which is the sum of self.bets[street][player])
# and how much he needs to call to match the previous player
# (which is tracked by self.lastBet)
committedThisStreet = reduce(operator.add, self.bets[street][player], 0)
amountToCall = self.lastBet[street] - committedThisStreet
self.lastBet[street] = Decimal(amountTo)
amountBy = Decimal(amountTo) - amountToCall
self.bets[street][player].append(amountBy+amountToCall)
self.actions[street] += [[player, 'raises', amountBy, amountTo]]
def addBet(self, street, player=None, amount=0):
self.bets[street][name].append(Decimal(amount))
self.orderedBets[street].append(Decimal(amount))
self.actions[street] += [[player, 'bets', amount]]
def totalPot(self):
"""If all bets and blinds have been added, totals up the total pot size
Known bug: doesn't take into account side pots"""
if self.totalpot is None:
self.totalpot = 0
self.rake = 0
# player names:
# print [x[1] for x in self.players]
for player in [x[1] for x in self.players]:
for street in self.streetList:
#print street, self.bets[street][player]
self.totalpot += reduce(operator.add, self.bets[street][player], 0)
def printHand(self):
print self.sitename
print self.gametype
print self.string
print self.handid
print self.sb
print self.bb
print self.tablename
print self.maxseats
print self.counted_seats
print self.buttonpos
print self.seating
print self.players
print self.posted
print self.action
print self.involved
print self.hero
# PokerStars format.
print "### DEBUG ###"
print "%s Game #%s: %s ($%s/$%s) - %s" %(self.sitename, self.handid, "XXXXhand.gametype", self.sb, self.bb, self.starttime)
print "Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos)
for player in self.players:
print "Seat %s: %s ($%s)" %(player[0], player[1], player[2])
if(self.posted[0] is None):
print "No small blind posted"
else:
print "%s: posts small blind $%s" %(self.posted[0], self.sb)
#May be more than 1 bb posting
for a in self.posted[1:]:
print "%s: posts big blind $%s" %(self.posted[1], self.bb)
# What about big & small blinds?
print "*** HOLE CARDS ***"
print "Dealt to %s [%s %s]" %(self.hero , self.holecards[self.hero][0], self.holecards[self.hero][1])
if 'PREFLOP' in self.actions:
for act in self.actions['PREFLOP']:
self.printActionLine(act)
if 'FLOP' in self.actions:
print "*** FLOP *** [%s %s %s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"))
for act in self.actions['FLOP']:
self.printActionLine(act)
if 'TURN' in self.actions:
print "*** TURN *** [%s %s %s] [%s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"), self.streets.group("TURN1"))
for act in self.actions['TURN']:
self.printActionLine(act)
if 'RIVER' in self.actions:
print "*** RIVER *** [%s %s %s %s] [%s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"), self.streets.group("TURN1"), self.streets.group("RIVER1"))
for act in self.actions['RIVER']:
self.printActionLine(act)
#Some sites don't have a showdown section so we have to figure out if there should be one
# The logic for a showdown is: at the end of river action there are at least two players in the hand
if 'SHOWDOWN' in self.actions:
print "*** SHOW DOWN ***"
print "what do they show"
print "*** SUMMARY ***"
print "Total pot $%s | Rake $%s)" % (self.totalpot, self.rake)
print "Board [%s %s %s %s %s]" % (self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"), self.streets.group("TURN1"), self.streets.group("RIVER1"))
#print self.board
for player in self.players:
if self.holecards[player[1]]: # empty list default is false
hole = self.holecards[player[1]]
#print self.board.values()
board = []
for s in self.board.values():
board += s
playerhand = self.bestHand('hi', board+hole)
print "Seat %d: %s showed %s and won/lost with %s" % (player[0], player[1], hole, playerhand)
else:
print "Seat %d: %s mucked or folded" % (player[0], player[1])
def printActionLine(self, act):
if act[1] == 'folds' or act[1] == 'checks':
print "%s: %s " %(act[0], act[1])
if act[1] == 'calls':
print "%s: %s $%s" %(act[0], act[1], act[2])
if act[1] == 'raises':
print "%s: %s $%s to $%s" %(act[0], act[1], act[2], act[3])
# going to use pokereval to figure out hands
# these functions are copied from pokergame.py
# im thinking perhaps its best to use all the functionality of pokergame instead
# of reinventing the wheel
def bestHand(self, side, cards):
#if self.variant == "omaha" or self.variant == "omaha8":
#hand = self.serial2player[serial].hand.tolist(True)
#board = self.board.tolist(True)
#else:
#hand = hand.tolist(True) + board.tolist(True)
#board = []
print cards
return HandHistoryConverter.eval.best('hi', cards, [])
def bestHandValue(self, side, serial):
(value, cards) = self.bestHand(side, serial)
return value
def readableHandValueLong(self, side, value, cards):
cards = self.eval.card2string(cards)
if value == "NoPair":
if side == "low":
if cards[0][0] == '5':
return _("The wheel")
else:
return join(map(lambda card: card[0], cards), ", ")
else:
return _("High card %(card)s") % { 'card' : _(letter2name[cards[0][0]]) }
elif value == "OnePair":
return _("A pair of %(card)s") % { 'card' : _(letter2names[cards[0][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[2][0]]) }
elif value == "TwoPair":
return _("Two pairs %(card1)s and %(card2)s") % { 'card1' : _(letter2names[cards[0][0]]), 'card2' : _(letter2names[cards[2][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[4][0]]) }
elif value == "Trips":
return _("Three of a kind %(card)s") % { 'card' : _(letter2names[cards[0][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[3][0]]) }
elif value == "Straight":
return _("Straight %(card1)s to %(card2)s") % { 'card1' : _(letter2name[cards[0][0]]), 'card2' : _(letter2name[cards[4][0]]) }
elif value == "Flush":
return _("Flush %(card)s high") % { 'card' : _(letter2name[cards[0][0]]) }
elif value == "FlHouse":
return _("%(card1)ss full of %(card2)ss") % { 'card1' : _(letter2name[cards[0][0]]), 'card2' : _(letter2name[cards[3][0]]) }
elif value == "Quads":
return _("Four of a kind %(card)s") % { 'card' : _(letter2names[cards[0][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[4][0]]) }
elif value == "StFlush":
if letter2name[cards[0][0]] == 'Ace':
return _("Royal flush")
else:
return _("Straight flush %(card)s high") % { 'card' : _(letter2name[cards[0][0]]) }
return value

1
pyfpdb/Mucked.py Normal file → Executable file
View File

@ -170,6 +170,7 @@ class Stud_cards:
for r in range(0, self.rows):
self.grid_contents[( 0, r)] = gtk.Label("%d" % (r + 1))
self.grid_contents[( 1, r)] = gtk.Label("player %d" % (r + 1))
self.grid_contents[( 1, r)].set_property("width-chars", 12)
self.grid_contents[( 4, r)] = gtk.Label("-")
self.grid_contents[( 9, r)] = gtk.Label("-")
self.grid_contents[( 2, r)] = self.eb[( 0, r)]

View File

@ -229,12 +229,11 @@ class Sql:
sum(street3CheckCallRaiseDone) AS ccr_3,
sum(street4CheckCallRaiseChance) AS ccr_opp_4,
sum(street4CheckCallRaiseDone) AS ccr_4
FROM HudCache, Hands
WHERE HudCache.PlayerId in
(SELECT PlayerId FROM HandsPlayers
WHERE handId = %s)
AND Hands.id = %s
AND Hands.gametypeId = HudCache.gametypeId
FROM Hands
INNER JOIN HandsPlayers ON (HandsPlayers.handId = %s)
INNER JOIN HudCache ON ( HudCache.PlayerId = HandsPlayers.PlayerId+0
AND HudCache.gametypeId+0 = Hands.gametypeId+0)
WHERE Hands.id = %s
GROUP BY HudCache.PlayerId
"""

View File

@ -71,6 +71,7 @@ def do_stat(stat_dict, player = 24, stat = 'vpip'):
# functions that return individual stats
def playername(stat_dict, player):
""" Player Name."""
return (stat_dict[player]['screen_name'],
stat_dict[player]['screen_name'],
stat_dict[player]['screen_name'],
@ -98,6 +99,26 @@ def vpip(stat_dict, player):
'Voluntarily Put In Pot %'
)
def vpip_0(stat_dict, player):
""" Voluntarily put $ in the pot (no decimals)."""
stat = 0.0
try:
stat = float(stat_dict[player]['vpip'])/float(stat_dict[player]['n'])
return (stat,
'%2.0f' % (100*stat) + '%',
'v=%2.0f' % (100*stat) + '%',
'vpip=%2.0f' % (100*stat) + '%',
'(%d/%d)' % (stat_dict[player]['vpip'], stat_dict[player]['n']),
'vpip'
)
except: return (stat,
'%2.0f' % (0) + '%',
'w=%2.0f' % (0) + '%',
'wtsd=%2.0f' % (0) + '%',
'(%d/%d)' % (0, 0),
'wtsd'
)
def pfr(stat_dict, player):
""" Preflop (3rd street) raise."""
stat = 0.0
@ -119,6 +140,27 @@ def pfr(stat_dict, player):
'Pre-Flop Raise %'
)
def pfr_0(stat_dict, player):
""" Preflop (3rd street) raise (no decimals)."""
stat = 0.0
try:
stat = float(stat_dict[player]['pfr'])/float(stat_dict[player]['n'])
return (stat,
'%2.0f' % (100*stat) + '%',
'p=%2.0f' % (100*stat) + '%',
'pfr=%2.0f' % (100*stat) + '%',
'(%d/%d)' % (stat_dict[player]['pfr'], stat_dict[player]['n']),
'pfr'
)
except:
return (stat,
'%2.0f' % (0) + '%',
'p=%2.0f' % (0) + '%',
'pfr=%2.0f' % (0) + '%',
'(%d/%d)' % (0, 0),
'pfr'
)
def wtsd(stat_dict, player):
""" Went to SD when saw flop/4th."""
stat = 0.0
@ -149,7 +191,7 @@ def wmsd(stat_dict, player):
'%3.1f' % (100*stat) + '%',
'w=%3.1f' % (100*stat) + '%',
'wmsd=%3.1f' % (100*stat) + '%',
'(%f5.0/%d)' % (stat_dict[player]['wmsd'], stat_dict[player]['sd']),
'(%5.1f/%d)' % (float(stat_dict[player]['wmsd']), stat_dict[player]['sd']),
'% won money at showdown'
)
except:
@ -413,6 +455,61 @@ def a_freq_4(stat_dict, player):
'Aggression Freq 7th'
)
def a_freq_123(stat_dict, player):
""" Post-Flop aggression frequency."""
stat = 0.0
try:
stat = float( stat_dict[player]['aggr_1'] + stat_dict[player]['aggr_2'] + stat_dict[player]['aggr_3']
) / float( stat_dict[player]['saw_1'] + stat_dict[player]['saw_2'] + stat_dict[player]['saw_3']);
return (stat,
'%3.1f' % (100*stat) + '%',
'afq=%3.1f' % (100*stat) + '%',
'postf_aggfq=%3.1f' % (100*stat) + '%',
'(%d/%d)' % ( stat_dict[player]['aggr_1']
+ stat_dict[player]['aggr_2']
+ stat_dict[player]['aggr_3']
, stat_dict[player]['saw_1']
+ stat_dict[player]['saw_2']
+ stat_dict[player]['saw_3']
),
'Post-Flop Aggression Freq'
)
except:
return (stat,
'%2.0f' % (0) + '%',
'a3=%2.0f' % (0) + '%',
'a_fq_3=%2.0f' % (0) + '%',
'(%d/%d)' % (0, 0),
'Post-Flop Aggression Freq'
)
def a_freq_123_0(stat_dict, player):
""" Post-Flop aggression frequency (no decimals)."""
stat = 0.0
try:
stat = float( stat_dict[player]['aggr_1'] + stat_dict[player]['aggr_2'] + stat_dict[player]['aggr_3']) / float( stat_dict[player]['saw_1'] + stat_dict[player]['saw_2'] + stat_dict[player]['saw_3']);
return (stat,
'%2.0f' % (100*stat) + '%',
'afq=%2.0f' % (100*stat) + '%',
'postf_aggfq=%2.0f' % (100*stat) + '%',
'(%d/%d)' % ( stat_dict[player]['aggr_1']
+ stat_dict[player]['aggr_2']
+ stat_dict[player]['aggr_3']
, stat_dict[player]['saw_1']
+ stat_dict[player]['saw_2']
+ stat_dict[player]['saw_3']
),
'Post-Flop Aggression Freq'
)
except:
return (stat,
'%2.0f' % (0) + '%',
'a3=%2.0f' % (0) + '%',
'a_fq_3=%2.0f' % (0) + '%',
'(%d/%d)' % (0, 0),
'Post-Flop Aggression Freq'
)
def cb_1(stat_dict, player):
""" Flop continuation bet."""
stat = 0.0
@ -589,7 +686,9 @@ if __name__== "__main__":
for player in stat_dict.keys():
print "player = ", player, do_stat(stat_dict, player = player, stat = 'vpip')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'vpip_0')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'pfr')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'pfr_0')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'wtsd')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'saw_f')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'n')
@ -604,6 +703,8 @@ if __name__== "__main__":
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_2')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_3')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_4')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_123')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_123_0')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_1')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_2')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_3')
@ -612,6 +713,7 @@ if __name__== "__main__":
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_2')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_3')
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_4')
print "\n"
print "\n\nLegal stats:"
for attr in dir():
@ -619,8 +721,8 @@ if __name__== "__main__":
if attr in ("Configuration", "Database", "GInitiallyUnowned", "gtk", "pygtk",
"player", "c", "db_connection", "do_stat", "do_tip", "stat_dict",
"h"): continue
print attr, eval("%s.__doc__" % (attr))
print "%-14s %s" % (attr, eval("%s.__doc__" % (attr)))
# print " <pu_stat pu_stat_name = \"%s\"> </pu_stat>" % (attr)
db_connection.close
db_connection.close_connection

View File

@ -37,6 +37,7 @@ import gtk
import fpdb_db
import fpdb_simple
import GuiBulkImport
import GuiPlayerStats
import GuiTableViewer
import GuiAutoImport
import GuiGraphViewer
@ -117,12 +118,12 @@ class fpdb:
def dia_create_del_database(self, widget, data):
print "todo: implement dia_create_del_database"
obtain_global_lock()
self.obtain_global_lock()
#end def dia_create_del_database
def dia_create_del_user(self, widget, data):
print "todo: implement dia_create_del_user"
obtain_global_lock()
self.obtain_global_lock()
#end def dia_create_del_user
def dia_database_stats(self, widget, data):
@ -132,17 +133,17 @@ class fpdb:
def dia_delete_db_parts(self, widget, data):
print "todo: implement dia_delete_db_parts"
obtain_global_lock()
self.obtain_global_lock()
#end def dia_delete_db_parts
def dia_edit_profile(self, widget=None, data=None, create_default=False, path=None):
print "todo: implement dia_edit_profile"
obtain_global_lock()
self.obtain_global_lock()
#end def dia_edit_profile
def dia_export_db(self, widget, data):
print "todo: implement dia_export_db"
obtain_global_lock()
self.obtain_global_lock()
#end def dia_export_db
def dia_get_db_root_credentials(self):
@ -167,7 +168,7 @@ class fpdb:
def dia_import_db(self, widget, data):
print "todo: implement dia_import_db"
obtain_global_lock()
self.obtain_global_lock()
#end def dia_import_db
def dia_licensing(self, widget, data):
@ -263,7 +264,11 @@ class fpdb:
self.db = fpdb_db.fpdb_db()
#print "end of fpdb.load_profile, databaseName:",self.settings['db-databaseName']
self.db.connect(self.settings['db-backend'], self.settings['db-host'], self.settings['db-databaseName'], self.settings['db-user'], self.settings['db-password'])
self.db.connect(self.settings['db-backend'],
self.settings['db-host'],
self.settings['db-databaseName'],
self.settings['db-user'],
self.settings['db-password'])
if self.db.wrongDbVersion:
diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK))
@ -326,6 +331,13 @@ class fpdb:
self.add_and_display_tab(bulk_tab, "Bulk Import")
#end def tab_bulk_import
def tab_player_stats(self, widget, data):
new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.db, self.config, self.querydict)
self.threads.append(new_ps_thread)
ps_tab=new_ps_thread.get_vbox()
self.add_and_display_tab(ps_tab, "Player Stats")
def tab_main_help(self, widget, data):
"""Displays a tab with the main fpdb help screen"""
#print "start of tab_main_help"
@ -384,7 +396,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
("/Viewers/_Graphs", "<control>G", self.tabGraphViewer, 0, None ),
("/Viewers/Hand _Replayer (todo)", None, self.not_implemented, 0, None ),
("/Viewers/Player _Details (todo)", None, self.not_implemented, 0, None ),
("/Viewers/_Player Stats (tabulated view) (todo)", None, self.not_implemented, 0, None ),
("/Viewers/_Player Stats (tabulated view)", None, self.tab_player_stats, 0, None ),
("/Viewers/Starting _Hands (todo)", None, self.not_implemented, 0, None ),
("/Viewers/_Session Replayer (todo)", None, self.not_implemented, 0, None ),
("/Viewers/Poker_table Viewer (mostly obselete)", "<control>T", self.tab_table_viewer, 0, None ),

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

@ -31,19 +31,34 @@ class fpdb_db:
self.SQLITE=4
#end def __init__
def connect(self, backend, host, database, user, password):
def connect(self, backend=None, host=None, database=None,
user=None, password=None):
"""Connects a database with the given parameters"""
if backend is None:
raise FpdbError('Database backend not defined')
self.backend=backend
self.host=host
self.database=database
self.user=user
self.password=password
self.database=database
if backend==self.MYSQL_INNODB:
import MySQLdb
self.db=MySQLdb.connect(host = host, user = user, passwd = password, db = database)
elif backend==self.PGSQL:
import psycopg2
self.db = psycopg2.connect(host = host, user = user, password = password, database = database)
# If DB connection is made over TCP, then the variables
# host, user and password are required
print "host=%s user=%s pass=%s." % (host, user, password)
if self.host and self.user and self.password:
self.db = psycopg2.connect(host = host,
user = user,
password = password,
database = database)
# For local domain-socket connections, only DB name is
# needed, and everything else is in fact undefined and/or
# flat out wrong
else:
self.db = psycopg2.connect(database = database)
else:
raise fpdb_simple.FpdbError("unrecognised database backend:"+backend)
self.cursor=self.db.cursor()
@ -93,6 +108,9 @@ class fpdb_db:
self.cursor.execute(self.sql.query['createHandsPlayersTable'])
self.cursor.execute(self.sql.query['createHandsActionsTable'])
self.cursor.execute(self.sql.query['createHudCacheTable'])
self.cursor.execute(self.sql.query['addTourneyIndex'])
self.cursor.execute(self.sql.query['addHandsIndex'])
self.cursor.execute(self.sql.query['addPlayersIndex'])
self.fillDefaultData()
self.db.commit()
#end def disconnect

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

@ -62,6 +62,8 @@ class Importer:
self.settings['minPrint'] = 30
self.dbConnect()
# XXX: Why is this here, when fpdb_db.connect() already does the
# same?
def dbConnect(self):
#connect to DB
if self.settings['db-backend'] == 2:
@ -73,10 +75,15 @@ class Importer:
if not pgsqlLibFound:
raise fpdb_simple.FpdbError("interface library psycopg2 not found but PostgreSQL selected as backend - please install the library or change the config file")
print self.settings
if self.settings.has_key('db-host') and \
self.settings.has_key('db-user'):
self.db = psycopg2.connect(host = self.settings['db-host'],
user = self.settings['db-user'],
password = self.settings['db-password'],
database = self.settings['db-databaseName'])
else:
dbname = self.settings['db-databaseName']
self.db = psycopg2.connect(database = dbname)
elif self.settings['db-backend'] == 4:
pass
else:
@ -236,7 +243,8 @@ class Importer:
self.hand=hand
try:
handsId=fpdb_parse_logic.mainParser(self.db, self.cursor, site, category, hand)
handsId=fpdb_parse_logic.mainParser(self.settings['db-backend'], self.db
,self.cursor, site, category, hand)
self.db.commit()
stored+=1

View File

@ -21,7 +21,7 @@ import fpdb_simple
import fpdb_save_to_db
#parses a holdem hand
def mainParser(db, cursor, site, category, hand):
def mainParser(backend, db, cursor, site, category, hand):
if (category=="holdem" or category=="omahahi" or category=="omahahilo"):
base="hold"
else:
@ -48,7 +48,7 @@ def mainParser(db, cursor, site, category, hand):
#print "found small blind line:",smallBlindLine
break
#print "small blind line:",smallBlindLine
gametypeID=fpdb_simple.recogniseGametypeID(cursor, hand[0], hand[smallBlindLine], siteID, category, isTourney)
gametypeID=fpdb_simple.recogniseGametypeID(backend, db, cursor, hand[0], hand[smallBlindLine], siteID, category, isTourney)
if isTourney:
if site!="ps":
raise fpdb_simple.FpdbError("tourneys are only supported on PS right now")
@ -133,9 +133,13 @@ def mainParser(db, cursor, site, category, hand):
totalWinnings+=winnings[i]
if base=="hold":
hudImportData=fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes, allIns, actionTypeByNo, winnings, totalWinnings, positions)
hudImportData=fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes
, allIns, actionTypeByNo, winnings, totalWinnings, positions
, actionTypes, actionAmounts)
else:
hudImportData=fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes, allIns, actionTypeByNo, winnings, totalWinnings, None)
hudImportData=fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes
, allIns, actionTypeByNo, winnings, totalWinnings, None
, actionTypes, actionAmounts)
if isTourney:
ranks=[]
@ -144,20 +148,41 @@ def mainParser(db, cursor, site, category, hand):
payin_amounts=fpdb_simple.calcPayin(len(names), buyin, fee)
if base=="hold":
result = fpdb_save_to_db.tourney_holdem_omaha(cursor, base, category, siteTourneyNo, buyin, fee, knockout, entries, prizepool, tourneyStartTime, payin_amounts, ranks, tourneyTypeId, siteID,
siteHandNo, gametypeID, handStartTime, names, playerIDs, startCashes, positions, cardValues, cardSuits, boardValues, boardSuits, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, hudImportData, maxSeats, tableName, seatNos)
result = fpdb_save_to_db.tourney_holdem_omaha(
backend, db, cursor, base, category, siteTourneyNo, buyin
, fee, knockout, entries, prizepool, tourneyStartTime
, payin_amounts, ranks, tourneyTypeId, siteID, siteHandNo
, gametypeID, handStartTime, names, playerIDs, startCashes
, positions, cardValues, cardSuits, boardValues, boardSuits
, winnings, rakes, actionTypes, allIns, actionAmounts
, actionNos, hudImportData, maxSeats, tableName, seatNos)
elif base=="stud":
result = fpdb_save_to_db.tourney_stud(cursor, base, category, siteTourneyNo, buyin, fee, knockout, entries, prizepool, tourneyStartTime, payin_amounts, ranks, tourneyTypeId, siteID,
siteHandNo, gametypeID, handStartTime, names, playerIDs, startCashes, antes, cardValues, cardSuits, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, hudImportData, maxSeats, tableName, seatNos)
result = fpdb_save_to_db.tourney_stud(
backend, db, cursor, base, category, siteTourneyNo
, buyin, fee, knockout, entries, prizepool, tourneyStartTime
, payin_amounts, ranks, tourneyTypeId, siteID, siteHandNo
, gametypeID, handStartTime, names, playerIDs, startCashes
, antes, cardValues, cardSuits, winnings, rakes, actionTypes
, allIns, actionAmounts, actionNos, hudImportData, maxSeats
, tableName, seatNos)
else:
raise fpdb_simple.FpdbError ("unrecognised category")
else:
if base=="hold":
result = fpdb_save_to_db.ring_holdem_omaha(cursor, base, category, siteHandNo, gametypeID, handStartTime, names, playerIDs, startCashes, positions, cardValues, cardSuits, boardValues, boardSuits, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, hudImportData, maxSeats, tableName, seatNos)
result = fpdb_save_to_db.ring_holdem_omaha(
backend, db, cursor, base, category, siteHandNo
, gametypeID, handStartTime, names, playerIDs
, startCashes, positions, cardValues, cardSuits
, boardValues, boardSuits, winnings, rakes
, actionTypes, allIns, actionAmounts, actionNos
, hudImportData, maxSeats, tableName, seatNos)
elif base=="stud":
result = fpdb_save_to_db.ring_stud(cursor, base, category, siteHandNo, gametypeID,
handStartTime, names, playerIDs, startCashes, antes, cardValues,
cardSuits, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, hudImportData, maxSeats, tableName, seatNos)
result = fpdb_save_to_db.ring_stud(
backend, db, cursor, base, category, siteHandNo, gametypeID
, handStartTime, names, playerIDs, startCashes, antes
, cardValues, cardSuits, winnings, rakes, actionTypes, allIns
, actionAmounts, actionNos, hudImportData, maxSeats, tableName
, seatNos)
else:
raise fpdb_simple.FpdbError ("unrecognised category")
db.commit()

View File

@ -18,43 +18,68 @@
#This file contains methods to store hands into the db. decides to move this
#into a seperate file since its ugly, fairly long and just generally in the way.
from time import time
import fpdb_simple
#stores a stud/razz hand into the database
def ring_stud(cursor, base, category, site_hand_no, gametype_id, hand_start_time, names, player_ids, start_cashes, antes, card_values, card_suits, winnings, rakes, action_types, allIns, action_amounts, actionNos, hudImportData, maxSeats, tableName, seatNos):
def ring_stud(backend, db, cursor, base, category, site_hand_no, gametype_id, hand_start_time
,names, player_ids, start_cashes, antes, card_values, card_suits, winnings, rakes
,action_types, allIns, action_amounts, actionNos, hudImportData, maxSeats, tableName
,seatNos):
fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits)
hands_id=fpdb_simple.storeHands(cursor, site_hand_no, gametype_id, hand_start_time, names, tableName, maxSeats)
hands_id=fpdb_simple.storeHands(backend, db, cursor, site_hand_no, gametype_id
,hand_start_time, names, tableName, maxSeats)
#print "before calling store_hands_players_stud, antes:", antes
hands_players_ids=fpdb_simple.store_hands_players_stud(cursor, hands_id, player_ids,
start_cashes, antes, card_values, card_suits, winnings, rakes, seatNos)
hands_players_ids=fpdb_simple.store_hands_players_stud(backend, db, cursor, hands_id, player_ids
,start_cashes, antes, card_values
,card_suits, winnings, rakes, seatNos)
fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData)
fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos)
fpdb_simple.storeActions(cursor, hands_players_ids, action_types
,allIns, action_amounts, actionNos)
return hands_id
#end def ring_stud
def ring_holdem_omaha(cursor, base, category, site_hand_no, gametype_id, hand_start_time, names, player_ids, start_cashes, positions, card_values, card_suits, board_values, board_suits, winnings, rakes, action_types, allIns, action_amounts, actionNos, hudImportData, maxSeats, tableName, seatNos):
def ring_holdem_omaha(backend, db, cursor, base, category, site_hand_no, gametype_id
,hand_start_time, names, player_ids, start_cashes, positions, card_values
,card_suits, board_values, board_suits, winnings, rakes, action_types, allIns
,action_amounts, actionNos, hudImportData, maxSeats, tableName, seatNos):
"""stores a holdem/omaha hand into the database"""
t0 = time()
fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits)
t1 = time()
fpdb_simple.fill_board_cards(board_values, board_suits)
t2 = time()
hands_id=fpdb_simple.storeHands(cursor, site_hand_no, gametype_id, hand_start_time, names, tableName, maxSeats)
hands_players_ids=fpdb_simple.store_hands_players_holdem_omaha(cursor, category, hands_id, player_ids, start_cashes, positions, card_values, card_suits, winnings, rakes, seatNos)
hands_id=fpdb_simple.storeHands(backend, db, cursor, site_hand_no, gametype_id
,hand_start_time, names, tableName, maxSeats)
t3 = time()
hands_players_ids=fpdb_simple.store_hands_players_holdem_omaha(
backend, db, cursor, category, hands_id, player_ids, start_cashes
, positions, card_values, card_suits, winnings, rakes, seatNos)
t4 = time()
fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData)
t5 = time()
fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits)
t6 = time()
fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos)
t7 = time()
print "cards=%4.3f board=%4.3f hands=%4.3f plyrs=%4.3f hudcache=%4.3f board=%4.3f actions=%4.3f" \
% (t1-t0, t2-t1, t3-t2, t4-t3, t5-t4, t6-t5, t7-t6)
return hands_id
#end def ring_holdem_omaha
def tourney_holdem_omaha(cursor, base, category, siteTourneyNo, buyin, fee, knockout, entries, prizepool, tourney_start, payin_amounts, ranks, tourneyTypeId, siteId, #end of tourney specific params
site_hand_no, gametype_id, hand_start_time, names, player_ids, start_cashes, positions, card_values, card_suits, board_values, board_suits, winnings, rakes, action_types, allIns, action_amounts, actionNos, hudImportData, maxSeats, tableName, seatNos):
def tourney_holdem_omaha(backend, db, cursor, base, category, siteTourneyNo, buyin, fee, knockout
,entries, prizepool, tourney_start, payin_amounts, ranks, tourneyTypeId
,siteId #end of tourney specific params
,site_hand_no, gametype_id, hand_start_time, names, player_ids
,start_cashes, positions, card_values, card_suits, board_values
,board_suits, winnings, rakes, action_types, allIns, action_amounts
,actionNos, hudImportData, maxSeats, tableName, seatNos):
"""stores a tourney holdem/omaha hand into the database"""
fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits)
fpdb_simple.fill_board_cards(board_values, board_suits)
@ -62,9 +87,12 @@ def tourney_holdem_omaha(cursor, base, category, siteTourneyNo, buyin, fee, knoc
tourney_id=fpdb_simple.store_tourneys(cursor, tourneyTypeId, siteTourneyNo, entries, prizepool, tourney_start)
tourneys_players_ids=fpdb_simple.store_tourneys_players(cursor, tourney_id, player_ids, payin_amounts, ranks, winnings)
hands_id=fpdb_simple.storeHands(cursor, site_hand_no, gametype_id, hand_start_time, names, tableName, maxSeats)
hands_id=fpdb_simple.storeHands(backend, db, cursor, site_hand_no, gametype_id
,hand_start_time, names, tableName, maxSeats)
hands_players_ids=fpdb_simple.store_hands_players_holdem_omaha_tourney(cursor, category, hands_id, player_ids, start_cashes, positions, card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids)
hands_players_ids=fpdb_simple.store_hands_players_holdem_omaha_tourney(
backend, db, cursor, category, hands_id, player_ids, start_cashes, positions
, card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids)
fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData)
@ -74,8 +102,11 @@ def tourney_holdem_omaha(cursor, base, category, siteTourneyNo, buyin, fee, knoc
return hands_id
#end def tourney_holdem_omaha
def tourney_stud(cursor, base, category, siteTourneyNo, buyin, fee, knockout, entries, prizepool, tourneyStartTime, payin_amounts, ranks, tourneyTypeId, siteId,
siteHandNo, gametypeId, handStartTime, names, playerIds, startCashes, antes, cardValues, cardSuits, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, hudImportData, maxSeats, tableName, seatNos):
def tourney_stud(backend, db, cursor, base, category, siteTourneyNo, buyin, fee, knockout, entries
,prizepool, tourneyStartTime, payin_amounts, ranks, tourneyTypeId, siteId
,siteHandNo, gametypeId, handStartTime, names, playerIds, startCashes, antes
,cardValues, cardSuits, winnings, rakes, actionTypes, allIns, actionAmounts
,actionNos, hudImportData, maxSeats, tableName, seatNos):
#stores a tourney stud/razz hand into the database
fpdb_simple.fillCardArrays(len(names), base, category, cardValues, cardSuits)
@ -83,9 +114,11 @@ def tourney_stud(cursor, base, category, siteTourneyNo, buyin, fee, knockout, en
tourneys_players_ids=fpdb_simple.store_tourneys_players(cursor, tourney_id, playerIds, payin_amounts, ranks, winnings)
hands_id=fpdb_simple.storeHands(cursor, siteHandNo, gametypeId, handStartTime, names, tableName, maxSeats)
hands_id=fpdb_simple.storeHands(backend, db, cursor, siteHandNo, gametypeId, handStartTime, names, tableName, maxSeats)
hands_players_ids=fpdb_simple.store_hands_players_stud_tourney(cursor, hands_id, playerIds, startCashes, antes, cardValues, cardSuits, winnings, rakes, seatNos, tourneys_players_ids)
hands_players_ids=fpdb_simple.store_hands_players_stud_tourney(backend, db, cursor, hands_id
, playerIds, startCashes, antes, cardValues, cardSuits
, winnings, rakes, seatNos, tourneys_players_ids)
fpdb_simple.storeHudCache(cursor, base, category, gametypeId, playerIds, hudImportData)

189
pyfpdb/fpdb_simple.py Normal file → Executable file
View File

@ -23,6 +23,11 @@ import re
PS=1
FTP=2
MYSQL_INNODB=2
PGSQL=3
SQLITE=4
class DuplicateError(Exception):
def __init__(self, value):
self.value = value
@ -35,6 +40,37 @@ class FpdbError(Exception):
def __str__(self):
return repr(self.value)
# gets value for last auto-increment key generated
# returns -1 if a problem occurs
def getLastInsertId(backend, conn, cursor):
if backend == MYSQL_INNODB:
ret = conn.insert_id()
if ret < 1 or ret > 999999999:
print "getLastInsertId(): problem fetching insert_id? ret=", ret
ret = -1
elif backend == PGSQL:
# some options:
# currval(hands_id_seq) - use name of implicit seq here
# lastval() - still needs sequences set up?
# insert ... returning is useful syntax (but postgres specific?)
# see rules (fancy trigger type things)
cursor.execute ("SELECT lastval()")
row = cursor.fetchone()
if not row:
print "getLastInsertId(%s): problem fetching lastval? row=" % seq, row
ret = -1
else:
ret = row[0]
elif backend == SQLITE:
# don't know how to do this in sqlite
print "getLastInsertId(): not coded for sqlite yet"
ret = -1
else:
print "getLastInsertId(): unknown backend ", backend
ret = -1
return ret
#end def getLastInsertId
#returns an array of the total money paid. intending to add rebuys/addons here
def calcPayin(count, buyin, fee):
result=[]
@ -54,8 +90,7 @@ def checkPositions(positions):
pass
### RHH modified to allow for "position 9" here (pos==9 is when you're a dead hand before the BB
### eric - position 8 could be valid - if only one blind is posted, but there's still 10 people, ie a sitout is present, and the small is dead...
if not (pos == "B" or pos == "S" or (pos >= 0 and pos <= 9)):
if (pos!="B" and pos!="S" and pos!=0 and pos!=1 and pos!=2 and pos!=3 and pos!=4 and pos!=5 and pos!=6 and pos!=7 and pos!=9):
raise FpdbError("invalid position found in checkPositions. i: "+str(i)+" position: "+str(pos))
#end def fpdb_simple.checkPositions
@ -485,6 +520,7 @@ def isActionLine(line):
#returns whether this is a duplicate
def isAlreadyInDB(cursor, gametypeID, siteHandNo):
#print "isAlreadyInDB gtid,shand:",gametypeID, siteHandNo
cursor.execute ("SELECT id FROM Hands WHERE gametypeId=%s AND siteHandNo=%s", (gametypeID, siteHandNo))
result=cursor.fetchall()
if (len(result)>=1):
@ -735,7 +771,7 @@ def parseCardLine(site, category, street, line, names, cardValues, cardSuits, bo
print "line:",line,"cardValues[playerNo]:",cardValues[playerNo]
raise FpdbError("read too many/too few holecards in parseCardLine")
elif (category=="razz" or category=="studhi" or category=="studhilo"):
if (line.find("shows")==-1 and line.find("mucked") == -1):
if (line.find("shows")==-1):
#print "parseCardLine(in stud if), street:", street
if line[pos+2]=="]": #-> not (hero and 3rd street)
cardValues[playerNo][street+2]=line[pos:pos+1]
@ -832,16 +868,14 @@ def parseHandStartTime(topline, site):
tmp=topline[pos1:pos2]
isUTC=True
else:
tmp=topline
tmp=topline[-30:]
#print "parsehandStartTime, tmp:", tmp
pos = tmp.find("-")+2
tmp = tmp[pos:]
#Need to match either
# 2008/09/07 06:23:14 ET or
# 2008/08/17 - 01:14:43 (ET) or
# 2008/11/12 9:33:31 CET [2008/11/12 3:33:31 ET]
rexx = '(?P<YEAR>[0-9]{4})\/(?P<MON>[0-9]{2})\/(?P<DAY>[0-9]{2})[\- ]+(?P<HR>[0-9]+):(?P<MIN>[0-9]+):(?P<SEC>[0-9]+)'
m = re.search(rexx,tmp)
# 2008/08/17 - 01:14:43 (ET)
m = re.match('(?P<YEAR>[0-9]{4})\/(?P<MON>[0-9]{2})\/(?P<DAY>[0-9]{2})[\- ]+(?P<HR>[0-9]{2}):(?P<MIN>[0-9]{2}):(?P<SEC>[0-9]{2})',tmp)
#print "year:", int(m.group('YEAR')), "month", int(m.group('MON')), "day", int(m.group('DAY')), "hour", int(m.group('HR')), "minute", int(m.group('MIN')), "second", int(m.group('SEC'))
result = datetime.datetime(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC')))
else:
@ -894,17 +928,11 @@ def parsePositions (hand, names):
if (bb!=-1):
bb=recognisePlayerNo(bb, names, "bet")
# print "sb = ", sb, "bb = ", bb
if bb == sb:
sbExists = False
sb = -1
#write blinds into array
if (sbExists):
positions[sb]="S"
positions[bb]="B"
#fill up rest of array
if (sbExists):
arraypos=sb-1
@ -917,24 +945,15 @@ def parsePositions (hand, names):
arraypos-=1
distFromBtn+=1
# eric - this takes into account dead seats between blinds
if sbExists:
i = bb - 1
while positions[i] < 0 and i != sb:
positions[i] = 9
i -= 1
### RHH - Changed to set the null seats before BB to "9"
if sbExists:
i = sb-1
else:
i=bb-1
while positions[i] < 0:
positions[i]=9
i-=1
arraypos=len(names)-1
if (bb!=0 or (bb==0 and sbExists==False) or (bb == 1 and sb != arraypos) ):
while (arraypos>bb and arraypos > sb):
if (bb!=0 or (bb==0 and sbExists==False)):
while (arraypos>bb):
positions[arraypos]=distFromBtn
arraypos-=1
distFromBtn+=1
@ -944,7 +963,6 @@ def parsePositions (hand, names):
print "parsePositions names:",names
print "result:",positions
raise FpdbError ("failed to read positions")
# print str(positions), "\n"
return positions
#end def parsePositions
@ -1040,7 +1058,7 @@ def recogniseCategory(line):
#end def recogniseCategory
#returns the int for the gametype_id for the given line
def recogniseGametypeID(cursor, topline, smallBlindLine, site_id, category, isTourney):#todo: this method is messy
def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, category, isTourney):#todo: this method is messy
#if (topline.find("HORSE")!=-1):
# raise FpdbError("recogniseGametypeID: HORSE is not yet supported.")
@ -1091,6 +1109,9 @@ def recogniseGametypeID(cursor, topline, smallBlindLine, site_id, category, isTo
else:
cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s AND limitType=%s AND smallBlind=%s AND bigBlind=%s", (site_id, type, category, limit_type, small_bet, big_bet))
result=cursor.fetchone()
#print "recgt1 result=",result
#ret=result[0]
#print "recgt1 ret=",ret
#print "tried SELECTing gametypes.id, result:",result
try:
@ -1121,18 +1142,24 @@ def recogniseGametypeID(cursor, topline, smallBlindLine, site_id, category, isTo
small_blind=float2int(smallBlindLine[pos:])
else:
small_blind=0
cursor.execute("""INSERT INTO Gametypes
(siteId, type, base, category, limitType, hiLo, smallBlind, bigBlind, smallBet, bigBet)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", (site_id, type, base, category, limit_type, hiLo, small_blind, big_blind, small_bet, big_bet))
cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s AND limitType=%s AND smallBet=%s AND bigBet=%s", (site_id, type, category, limit_type, small_bet, big_bet))
cursor.execute( """INSERT INTO Gametypes(siteId, type, base, category, limitType
,hiLo, smallBlind, bigBlind, smallBet, bigBet)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
, (site_id, type, base, category, limit_type, hiLo
,small_blind, big_blind, small_bet, big_bet) )
#cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s
#AND limitType=%s AND smallBet=%s AND bigBet=%s", (site_id, type, category, limit_type, small_bet, big_bet))
else:
cursor.execute("""INSERT INTO Gametypes
(siteId, type, base, category, limitType, hiLo, smallBlind, bigBlind, smallBet, bigBet)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", (site_id, type, base, category, limit_type, hiLo, small_bet, big_bet, 0, 0))#remember, for these bet means blind
cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s AND limitType=%s AND smallBlind=%s AND bigBlind=%s", (site_id, type, category, limit_type, small_bet, big_bet))
cursor.execute( """INSERT INTO Gametypes(siteId, type, base, category, limitType
,hiLo, smallBlind, bigBlind, smallBet, bigBet)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
, (site_id, type, base, category, limit_type
,hiLo, small_bet, big_bet, 0, 0))#remember, for these bet means blind
#cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s
#AND limitType=%s AND smallBlind=%s AND bigBlind=%s", (site_id, type, category, limit_type, small_bet, big_bet))
result=cursor.fetchone()
#print "created new gametypes.id:",result
#result=(db.insert_id(),)
result=(getLastInsertId(backend,db,cursor),)
return result[0]
#end def recogniseGametypeID
@ -1254,7 +1281,8 @@ def storeActions(cursor, handsPlayersIds, actionTypes, allIns, actionAmounts, ac
for i in range (len(actionTypes)): #iterate through streets
for j in range (len(actionTypes[i])): #iterate through names
for k in range (len(actionTypes[i][j])): #iterate through individual actions of that player on that street
cursor.execute ("INSERT INTO HandsActions (handPlayerId, street, actionNo, action, allIn, amount) VALUES (%s, %s, %s, %s, %s, %s)", (handsPlayersIds[j], i, actionNos[i][j][k], actionTypes[i][j][k], allIns[i][j][k], actionAmounts[i][j][k]))
cursor.execute ("INSERT INTO HandsActions (handPlayerId, street, actionNo, action, allIn, amount) VALUES (%s, %s, %s, %s, %s, %s)"
, (handsPlayersIds[j], i, actionNos[i][j][k], actionTypes[i][j][k], allIns[i][j][k], actionAmounts[i][j][k]))
#end def storeActions
def store_board_cards(cursor, hands_id, board_values, board_suits):
@ -1267,15 +1295,19 @@ def store_board_cards(cursor, hands_id, board_values, board_suits):
board_values[4], board_suits[4]))
#end def store_board_cards
def storeHands(cursor, site_hand_no, gametype_id, hand_start_time, names, tableName, maxSeats):
def storeHands(backend, conn, cursor, site_hand_no, gametype_id
,hand_start_time, names, tableName, maxSeats):
#stores into table hands
cursor.execute ("INSERT INTO Hands (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats) VALUES (%s, %s, %s, %s, %s, %s, %s)", (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.datetime.today(), maxSeats))
#todo: find a better way of doing this...
cursor.execute("SELECT id FROM Hands WHERE siteHandNo=%s AND gametypeId=%s", (site_hand_no, gametype_id))
return cursor.fetchall()[0][0]
#cursor.execute("SELECT id FROM Hands WHERE siteHandNo=%s AND gametypeId=%s", (site_hand_no, gametype_id))
#return cursor.fetchall()[0][0]
return getLastInsertId(backend, conn, cursor)
#return db.insert_id() # mysql only
#end def storeHands
def store_hands_players_holdem_omaha(cursor, category, hands_id, player_ids, start_cashes, positions, card_values, card_suits, winnings, rakes, seatNos):
def store_hands_players_holdem_omaha(backend, conn, cursor, category, hands_id, player_ids, start_cashes
,positions, card_values, card_suits, winnings, rakes, seatNos):
result=[]
if (category=="holdem"):
for i in range (len(player_ids)):
@ -1287,8 +1319,9 @@ def store_hands_players_holdem_omaha(cursor, category, hands_id, player_ids, sta
(hands_id, player_ids[i], start_cashes[i], positions[i],
card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1],
winnings[i], rakes[i], seatNos[i]))
cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId=%s", (hands_id, player_ids[i]))
result.append(cursor.fetchall()[0][0])
#cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId=%s", (hands_id, player_ids[i]))
#result.append(cursor.fetchall()[0][0])
result.append( getLastInsertId(backend, conn, cursor) ) # mysql only
elif (category=="omahahi" or category=="omahahilo"):
for i in range (len(player_ids)):
cursor.execute ("""INSERT INTO HandsPlayers
@ -1300,14 +1333,15 @@ def store_hands_players_holdem_omaha(cursor, category, hands_id, player_ids, sta
card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1],
card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3],
winnings[i], rakes[i], seatNos[i]))
cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId=%s", (hands_id, player_ids[i]))
result.append(cursor.fetchall()[0][0])
#cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i]))
#result.append(cursor.fetchall()[0][0])
result.append( getLastInsertId(backend, conn, cursor) ) # mysql only
else:
raise FpdbError("invalid category")
return result
#end def store_hands_players_holdem_omaha
def store_hands_players_stud(cursor, hands_id, player_ids, start_cashes, antes,
def store_hands_players_stud(backend, conn, cursor, hands_id, player_ids, start_cashes, antes,
card_values, card_suits, winnings, rakes, seatNos):
#stores hands_players rows for stud/razz games. returns an array of the resulting IDs
result=[]
@ -1326,12 +1360,15 @@ def store_hands_players_stud(cursor, hands_id, player_ids, start_cashes, antes,
card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3],
card_values[i][4], card_suits[i][4], card_values[i][5], card_suits[i][5],
card_values[i][6], card_suits[i][6], winnings[i], rakes[i], seatNos[i]))
cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId=%s", (hands_id, player_ids[i]))
result.append(cursor.fetchall()[0][0])
#cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i]))
#result.append(cursor.fetchall()[0][0])
result.append( getLastInsertId(backend, conn, cursor) ) # mysql only
return result
#end def store_hands_players_stud
def store_hands_players_holdem_omaha_tourney(cursor, category, hands_id, player_ids, start_cashes, positions, card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids):
def store_hands_players_holdem_omaha_tourney(backend, conn, cursor, category, hands_id, player_ids
,start_cashes, positions, card_values, card_suits
, winnings, rakes, seatNos, tourneys_players_ids):
#stores hands_players for tourney holdem/omaha hands
result=[]
for i in range (len(player_ids)):
@ -1357,13 +1394,14 @@ def store_hands_players_holdem_omaha_tourney(cursor, category, hands_id, player_
winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i]))
else:
raise FpdbError ("invalid card_values length:"+str(len(card_values[0])))
cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId=%s", (hands_id, player_ids[i]))
result.append(cursor.fetchall()[0][0])
#cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i]))
#result.append(cursor.fetchall()[0][0])
result.append( getLastInsertId(backend, conn, cursor) ) # mysql only
return result
#end def store_hands_players_holdem_omaha_tourney
def store_hands_players_stud_tourney(cursor, hands_id, player_ids, start_cashes,
def store_hands_players_stud_tourney(backend, conn, cursor, hands_id, player_ids, start_cashes,
antes, card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids):
#stores hands_players for tourney stud/razz hands
result=[]
@ -1381,13 +1419,18 @@ def store_hands_players_stud_tourney(cursor, hands_id, player_ids, start_cashes,
card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3],
card_values[i][4], card_suits[i][4], card_values[i][5], card_suits[i][5],
card_values[i][6], card_suits[i][6], winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i]))
cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId=%s", (hands_id, player_ids[i]))
result.append(cursor.fetchall()[0][0])
#cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i]))
#result.append(cursor.fetchall()[0][0])
result.append( getLastInsertId(backend, conn, cursor) ) # mysql only
return result
#end def store_hands_players_stud_tourney
def generateHudCacheData(player_ids, base, category, action_types, allIns, actionTypeByNo, winnings, totalWinnings, positions):
"""calculates data for the HUD during import. IMPORTANT: if you change this method make sure to also change the following storage method and table_viewer.prepare_data if necessary"""
def generateHudCacheData(player_ids, base, category, action_types, allIns, actionTypeByNo
,winnings, totalWinnings, positions, actionTypes, actionAmounts):
"""calculates data for the HUD during import. IMPORTANT: if you change this method make
sure to also change the following storage method and table_viewer.prepare_data if necessary
"""
#print "generateHudCacheData, len(player_ids)=", len(player_ids)
#setup subarrays of the result dictionary.
street0VPI=[]
street0Aggr=[]
@ -1693,7 +1736,7 @@ def generateHudCacheData(player_ids, base, category, action_types, allIns, actio
hudDataPositions.append('C')
elif pos>=2 and pos<=4:
hudDataPositions.append('M')
elif pos>=5 and pos<=8:
elif pos>=5 and pos<=7:
hudDataPositions.append('E')
### RHH Added this elif to handle being a dead hand before the BB (pos==9)
elif pos==9:
@ -1907,8 +1950,14 @@ def generateHudCacheData(player_ids, base, category, action_types, allIns, actio
street3CheckCallRaiseDone=[]
street4CheckCallRaiseChance=[]
street4CheckCallRaiseDone=[]
for player in range (len(player_ids)):
myTotalProfit=0
#print "b4 totprof calc, len(playerIds)=", len(player_ids)
for pl in range (len(player_ids)):
#print "pl=", pl
myTotalProfit=winnings[pl] # still need to deduct costs
for i in range (len(actionTypes)): #iterate through streets
#for j in range (len(actionTypes[i])): #iterate through names (using pl loop above)
for k in range (len(actionTypes[i][pl])): #iterate through individual actions of that player on that street
myTotalProfit -= actionAmounts[i][pl][k]
myStreet1CheckCallRaiseChance=False
myStreet1CheckCallRaiseDone=False
@ -1919,7 +1968,9 @@ def generateHudCacheData(player_ids, base, category, action_types, allIns, actio
myStreet4CheckCallRaiseChance=False
myStreet4CheckCallRaiseDone=False
#print "myTotalProfit=", myTotalProfit
totalProfit.append(myTotalProfit)
#print "totalProfit[]=", totalProfit
street1CheckCallRaiseChance.append(myStreet1CheckCallRaiseChance)
street1CheckCallRaiseDone.append(myStreet1CheckCallRaiseDone)
@ -1931,6 +1982,7 @@ def generateHudCacheData(player_ids, base, category, action_types, allIns, actio
street4CheckCallRaiseDone.append(myStreet4CheckCallRaiseDone)
result['totalProfit']=totalProfit
#print "res[totalProfit]=", result['totalProfit']
result['street1CheckCallRaiseChance']=street1CheckCallRaiseChance
result['street1CheckCallRaiseDone']=street1CheckCallRaiseDone
@ -1966,11 +2018,13 @@ def generateFoldToCB(street, playerIDs, didStreetCB, streetCBDone, foldToStreetC
def storeHudCache(cursor, base, category, gametypeId, playerIds, hudImportData):
# if (category=="holdem" or category=="omahahi" or category=="omahahilo"):
#print "storeHudCache, len(playerIds)=", len(playerIds), " len(vpip)=" \
#, len(hudImportData['street0VPI']), " len(totprof)=", len(hudImportData['totalProfit'])
for player in range (len(playerIds)):
if base=="hold":
cursor.execute("SELECT * FROM HudCache WHERE gametypeId=%s AND playerId=%s AND activeSeats=%s AND position=%s", (gametypeId, playerIds[player], len(playerIds), hudImportData['position'][player]))
cursor.execute("SELECT * FROM HudCache WHERE gametypeId+0=%s AND playerId=%s AND activeSeats=%s AND position=%s", (gametypeId, playerIds[player], len(playerIds), hudImportData['position'][player]))
else:
cursor.execute("SELECT * FROM HudCache WHERE gametypeId=%s AND playerId=%s AND activeSeats=%s", (gametypeId, playerIds[player], len(playerIds)))
cursor.execute("SELECT * FROM HudCache WHERE gametypeId+0=%s AND playerId=%s AND activeSeats=%s", (gametypeId, playerIds[player], len(playerIds)))
row=cursor.fetchone()
#print "gametypeId:", gametypeId, "playerIds[player]",playerIds[player], "len(playerIds):",len(playerIds), "row:",row
@ -2050,6 +2104,9 @@ def storeHudCache(cursor, base, category, gametypeId, playerIds, hudImportData):
if hudImportData['foldToStreet4CBChance'][player]: row[50]+=1
if hudImportData['foldToStreet4CBDone'][player]: row[51]+=1
#print "player=", player
#print "len(totalProfit)=", len(hudImportData['totalProfit'])
if hudImportData['totalProfit'][player]:
row[52]+=hudImportData['totalProfit'][player]
if hudImportData['street1CheckCallRaiseChance'][player]: row[53]+=1
@ -2116,7 +2173,7 @@ def storeHudCache(cursor, base, category, gametypeId, playerIds, hudImportData):
#end def storeHudCache
def store_tourneys(cursor, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime):
cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId=%s", (siteTourneyNo, tourneyTypeId))
cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId))
tmp=cursor.fetchone()
#print "tried SELECTing tourneys.id, result:",tmp
@ -2126,7 +2183,7 @@ def store_tourneys(cursor, tourneyTypeId, siteTourneyNo, entries, prizepool, sta
cursor.execute("""INSERT INTO Tourneys
(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)
VALUES (%s, %s, %s, %s, %s)""", (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime))
cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId=%s", (siteTourneyNo, tourneyTypeId))
cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId))
tmp=cursor.fetchone()
#print "created new tourneys.id:",tmp
return tmp[0]
@ -2140,7 +2197,7 @@ def store_tourneys_players(cursor, tourney_id, player_ids, payin_amounts, ranks,
#print "ranks:",ranks
#print "winnings:",winnings
for i in range (len(player_ids)):
cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId=%s", (tourney_id, player_ids[i]))
cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s", (tourney_id, player_ids[i]))
tmp=cursor.fetchone()
#print "tried SELECTing tourneys_players.id:",tmp
@ -2151,7 +2208,7 @@ def store_tourneys_players(cursor, tourney_id, player_ids, payin_amounts, ranks,
(tourneyId, playerId, payinAmount, rank, winnings) VALUES (%s, %s, %s, %s, %s)""",
(tourney_id, player_ids[i], payin_amounts[i], ranks[i], winnings[i]))
cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId=%s",
cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s",
(tourney_id, player_ids[i]))
tmp=cursor.fetchone()
#print "created new tourneys_players.id:",tmp

27
pyfpdb/upd_indexes.sql Executable file
View File

@ -0,0 +1,27 @@
# script to update indexes on mysql (+other?) database
select '1. Dropping indexes' as ' ';
select 'Can''t drop messages indicate index already gone' as ' ';
ALTER TABLE `fpdb`.`Settings` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Sites` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Gametypes` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Players` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Autorates` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Hands` DROP INDEX `id`;
ALTER TABLE `fpdb`.`BoardCards` DROP INDEX `id`;
ALTER TABLE `fpdb`.`TourneyTypes` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Tourneys` DROP INDEX `id`;
ALTER TABLE `fpdb`.`TourneysPlayers` DROP INDEX `id`;
ALTER TABLE `fpdb`.`HandsPlayers` DROP INDEX `id`;
ALTER TABLE `fpdb`.`HandsActions` DROP INDEX `id`;
ALTER TABLE `fpdb`.`HudCache` DROP INDEX `id`;
select '2. Adding extra indexes on useful fields' as ' ';
select 'Duplicate key name messages indicate new indexes already there' as ' ';
ALTER TABLE `fpdb`.`tourneys` ADD INDEX `siteTourneyNo`(`siteTourneyNo`);
ALTER TABLE `fpdb`.`hands` ADD INDEX `siteHandNo`(`siteHandNo`);
ALTER TABLE `fpdb`.`players` ADD INDEX `name`(`name`);

0
readme.txt Normal file
View File