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

This commit is contained in:
Ray 2008-12-11 10:25:40 -05:00
commit 8500851b99
10 changed files with 331 additions and 194 deletions

View File

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

View File

@ -312,11 +312,10 @@ The program itself is licensed under AGPLv3, see agpl-3.0.txt</p>
</TABLE> </TABLE>
<p><BR></P> <p><BR></P>
<p><B>Table HandsPlayers</B></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>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. If a player keeps some cards then those cards' spaces are filled with "k", short for "kept".<br> <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, k, k, 7, k, k<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, Q, K, k, 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, 5, 8, J, Q, K.</p>
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>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> <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> <TABLE BORDER=1 CELLPADDING=2 CELLSPACING=0>
<TR VALIGN=TOP> <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>char(1)</P></TD>
<TD><P>h=hearts, s=spades, d=diamonds, c=clubs, unknown/no card=x</P></TD> <TD><P>h=hearts, s=spades, d=diamonds, c=clubs, unknown/no card=x</P></TD>
</TR> </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> <TR VALIGN=TOP>
<TD><P>winnings</P></TD> <TD><P>winnings</P></TD>
<TD><P>int</P></TD> <TD><P>int</P></TD>

0
pyfpdb/CliFpdb.py Normal file → Executable file
View File

0
pyfpdb/Configuration.py Normal file → Executable file
View File

View File

@ -70,15 +70,16 @@ class Everleaf(HandHistoryConverter):
self.sitename = "Everleaf" self.sitename = "Everleaf"
self.setFileType("text") self.setFileType("text")
self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)') self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)')
self.rexx.setSplitHandRegex('\n\n\n\n') self.rexx.setSplitHandRegex('\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.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.setPlayerInfoRegex('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\s+(\$ (?P<CASH>[.0-9]+) USD|new player|All-in) \)')
self.rexx.setPostSbRegex('.*\n(?P<PNAME>.*): posts small blind \[\$? (?P<SB>[.0-9]+)') 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]+)') self.rexx.setPostBbRegex('.*\n(?P<PNAME>.*): posts big blind \[\$? (?P<BB>[.0-9]+)')
# mct : what about posting small & big blinds simultaneously? # 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.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.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.setShowdownActionRegex('.*\n(?P<PNAME>.*) shows \[ (?P<CARDS>.*) \]')
self.rexx.setCollectPotRegex('.*\n(?P<PNAME>.*) wins \$ (?P<POT>[.\d]+) USD.*')
self.rexx.compileRegexes() self.rexx.compileRegexes()
def readSupportedGames(self): def readSupportedGames(self):
@ -117,16 +118,38 @@ class Everleaf(HandHistoryConverter):
def readPlayerStacks(self, hand): def readPlayerStacks(self, hand):
m = self.rexx.player_info_re.finditer(hand.string) m = self.rexx.player_info_re.finditer(hand.string)
players = [] players = []
#print "\nReading stacks - players seen:"
for a in m: for a in m:
#print a.group('PNAME')
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH')) hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
def markStreets(self, hand): def markStreets(self, hand):
# PREFLOP = ** Dealing down cards ** # PREFLOP = ** Dealing down cards **
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) # This re fails if, say, river is missing; then we don't get the ** that starts the river.
# for street in m.groupdict(): #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)
# print "DEBUG: Street: %s\tspan: %s" %(street, str(m.span(street)))
m = re.search(r"\*\* Dealing down cards \*\*(?P<PREFLOP>.+(?=\*\* Dealing Flop \*\*)|.+)"
r"(\*\* Dealing Flop \*\* \[ \S\S, \S\S, \S\S \](?P<FLOP>.+(?=\*\* Dealing Turn \*\*)|.+))?"
r"(\*\* Dealing Turn \*\* \[ \S\S \](?P<TURN>.+(?=\*\* Dealing River \*\*)|.+))?"
r"(\*\* Dealing River \*\* \[ \S\S \](?P<RIVER>.+))?", hand.string,re.DOTALL)
# that wasn't easy.
#m1 = re.search(r'(\*\* Dealing down cards \*\*)?(?P<PREFLOP>.*?\n\*\*)',hand.string,re.DOTALL)
#m2 = re.search(r'(\*\* Dealing Flop \*\*)?(?P<FLOP>.*\n\*\*)',hand.string,re.DOTALL)
#print hand.string
#print "m groups:\n",m.groupdict()
#print "m1 groups:\n",m1.groupdict()
#print "m2 groups:\n",m2.groupdict()
#(\*\* 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 hand.streets = m
#sys.exit()
def readCommunityCards(self, hand): def readCommunityCards(self, hand):
# currently regex in wrong place pls fix my brain's fried # currently regex in wrong place pls fix my brain's fried
@ -165,15 +188,19 @@ class Everleaf(HandHistoryConverter):
m = self.rexx.action_re.finditer(hand.streets.group(street)) m = self.rexx.action_re.finditer(hand.streets.group(street))
hand.actions[street] = [] hand.actions[street] = []
for action in m: for action in m:
if action.group('ATYPE') == 'raises': if action.group('ATYPE') == ' raises':
hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') ) hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == 'calls': elif action.group('ATYPE') == ' calls':
hand.addCall( street, action.group('PNAME'), action.group('BET') ) hand.addCall( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == 'bets': elif action.group('ATYPE') == ': bets':
hand.addBet( street, action.group('PNAME'), action.group('BET') ) hand.addBet( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == ' folds':
hand.addFold( street, action.group('PNAME'))
elif action.group('ATYPE') == ' checks':
hand.addCheck( street, action.group('PNAME'))
else: else:
#print "DEBUG: unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),) print "DEBUG: unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),)
hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE')]] #hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE')]]
def readShowdownActions(self, hand): def readShowdownActions(self, hand):
@ -184,13 +211,19 @@ class Everleaf(HandHistoryConverter):
print cards print cards
hand.addHoleCards(cards, shows.group('PNAME')) hand.addHoleCards(cards, shows.group('PNAME'))
def readCollectPot(self,hand):
m = self.rexx.collect_pot_re.search(hand.string)
if m is not None:
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
else:
print "WARNING: Unusual, no one collected; can happen if it's folded to big blind with a dead small blind."
def getRake(self, hand): def getRake(self, hand):
hand.rake = hand.totalpot * Decimal('0.05') # probably not quite right hand.rake = hand.totalpot * Decimal('0.05') # probably not quite right
if __name__ == "__main__": if __name__ == "__main__":
c = Configuration.Config() c = Configuration.Config()
e = Everleaf(c, "Speed_Kuala.txt") e = Everleaf(c, "Speed_Kuala_full.txt")
e.processFile() e.processFile()
print str(e) print str(e)

View File

@ -73,13 +73,13 @@ class FpdbSQLQueries:
if(self.dbname == 'MySQL InnoDB'): if(self.dbname == 'MySQL InnoDB'):
self.query['createSitesTable'] = """CREATE TABLE Sites ( self.query['createSitesTable'] = """CREATE TABLE Sites (
id SMALLINT UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
name varchar(32) NOT NULL, name varchar(32) NOT NULL,
currency char(3) NOT NULL) currency char(3) NOT NULL)
ENGINE=INNODB""" ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'): elif(self.dbname == 'PostgreSQL'):
self.query['createSitesTable'] = """CREATE TABLE Sites ( self.query['createSitesTable'] = """CREATE TABLE Sites (
id SERIAL UNIQUE, PRIMARY KEY (id), id SERIAL, PRIMARY KEY (id),
name varchar(32), name varchar(32),
currency char(3))""" currency char(3))"""
elif(self.dbname == 'SQLite'): elif(self.dbname == 'SQLite'):
@ -92,7 +92,7 @@ class FpdbSQLQueries:
if(self.dbname == 'MySQL InnoDB'): if(self.dbname == 'MySQL InnoDB'):
self.query['createGametypesTable'] = """CREATE TABLE Gametypes ( self.query['createGametypesTable'] = """CREATE TABLE Gametypes (
id SMALLINT UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id), siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
type char(4) NOT NULL, type char(4) NOT NULL,
base char(4) NOT NULL, base char(4) NOT NULL,
@ -106,7 +106,7 @@ class FpdbSQLQueries:
ENGINE=INNODB""" ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'): elif(self.dbname == 'PostgreSQL'):
self.query['createGametypesTable'] = """CREATE TABLE Gametypes ( self.query['createGametypesTable'] = """CREATE TABLE Gametypes (
id SERIAL UNIQUE, PRIMARY KEY (id), id SERIAL, PRIMARY KEY (id),
siteId INTEGER, FOREIGN KEY (siteId) REFERENCES Sites(id), siteId INTEGER, FOREIGN KEY (siteId) REFERENCES Sites(id),
type char(4), type char(4),
base char(4), base char(4),
@ -127,7 +127,7 @@ class FpdbSQLQueries:
if(self.dbname == 'MySQL InnoDB'): if(self.dbname == 'MySQL InnoDB'):
self.query['createPlayersTable'] = """CREATE TABLE Players ( self.query['createPlayersTable'] = """CREATE TABLE Players (
id INT UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id INT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
name VARCHAR(32) CHARACTER SET utf8 NOT NULL, name VARCHAR(32) CHARACTER SET utf8 NOT NULL,
siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id), siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
comment text, comment text,
@ -135,7 +135,7 @@ class FpdbSQLQueries:
ENGINE=INNODB""" ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'): elif(self.dbname == 'PostgreSQL'):
self.query['createPlayersTable'] = """CREATE TABLE Players ( self.query['createPlayersTable'] = """CREATE TABLE Players (
id SERIAL UNIQUE, PRIMARY KEY (id), id SERIAL, PRIMARY KEY (id),
name VARCHAR(32), name VARCHAR(32),
siteId INTEGER, FOREIGN KEY (siteId) REFERENCES Sites(id), siteId INTEGER, FOREIGN KEY (siteId) REFERENCES Sites(id),
comment text, comment text,
@ -150,7 +150,7 @@ class FpdbSQLQueries:
if(self.dbname == 'MySQL InnoDB'): if(self.dbname == 'MySQL InnoDB'):
self.query['createAutoratesTable'] = """CREATE TABLE Autorates ( self.query['createAutoratesTable'] = """CREATE TABLE Autorates (
id BIGINT UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
description varchar(50) NOT NULL, description varchar(50) NOT NULL,
@ -160,7 +160,7 @@ class FpdbSQLQueries:
ENGINE=INNODB""" ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'): elif(self.dbname == 'PostgreSQL'):
self.query['createAutoratesTable'] = """CREATE TABLE Autorates ( self.query['createAutoratesTable'] = """CREATE TABLE Autorates (
id BIGSERIAL UNIQUE, PRIMARY KEY (id), id BIGSERIAL, PRIMARY KEY (id),
playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id), playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id),
gametypeId INT, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), gametypeId INT, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
description varchar(50), description varchar(50),
@ -177,7 +177,7 @@ class FpdbSQLQueries:
if(self.dbname == 'MySQL InnoDB'): if(self.dbname == 'MySQL InnoDB'):
self.query['createHandsTable'] = """CREATE TABLE Hands ( self.query['createHandsTable'] = """CREATE TABLE Hands (
id BIGINT UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
tableName VARCHAR(20) NOT NULL, tableName VARCHAR(20) NOT NULL,
siteHandNo BIGINT NOT NULL, siteHandNo BIGINT NOT NULL,
gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
@ -190,7 +190,7 @@ class FpdbSQLQueries:
ENGINE=INNODB""" ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'): elif(self.dbname == 'PostgreSQL'):
self.query['createHandsTable'] = """CREATE TABLE Hands ( self.query['createHandsTable'] = """CREATE TABLE Hands (
id BIGSERIAL UNIQUE, PRIMARY KEY (id), id BIGSERIAL, PRIMARY KEY (id),
tableName VARCHAR(20), tableName VARCHAR(20),
siteHandNo BIGINT, siteHandNo BIGINT,
gametypeId INT, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), gametypeId INT, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
@ -210,7 +210,7 @@ class FpdbSQLQueries:
if(self.dbname == 'MySQL InnoDB'): if(self.dbname == 'MySQL InnoDB'):
self.query['createBoardCardsTable'] = """CREATE TABLE BoardCards ( self.query['createBoardCardsTable'] = """CREATE TABLE BoardCards (
id BIGINT UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
handId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handId) REFERENCES Hands(id), handId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handId) REFERENCES Hands(id),
card1Value smallint NOT NULL, card1Value smallint NOT NULL,
card1Suit char(1) NOT NULL, card1Suit char(1) NOT NULL,
@ -225,7 +225,7 @@ class FpdbSQLQueries:
ENGINE=INNODB""" ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'): elif(self.dbname == 'PostgreSQL'):
self.query['createBoardCardsTable'] = """CREATE TABLE BoardCards ( self.query['createBoardCardsTable'] = """CREATE TABLE BoardCards (
id BIGSERIAL UNIQUE, PRIMARY KEY (id), id BIGSERIAL, PRIMARY KEY (id),
handId BIGINT, FOREIGN KEY (handId) REFERENCES Hands(id), handId BIGINT, FOREIGN KEY (handId) REFERENCES Hands(id),
card1Value smallint, card1Value smallint,
card1Suit char(1), card1Suit char(1),
@ -247,7 +247,7 @@ class FpdbSQLQueries:
if(self.dbname == 'MySQL InnoDB'): if(self.dbname == 'MySQL InnoDB'):
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes ( self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
id SMALLINT UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id), siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
buyin INT NOT NULL, buyin INT NOT NULL,
fee INT NOT NULL, fee INT NOT NULL,
@ -272,7 +272,7 @@ class FpdbSQLQueries:
if(self.dbname == 'MySQL InnoDB'): if(self.dbname == 'MySQL InnoDB'):
self.query['createTourneysTable'] = """CREATE TABLE Tourneys ( self.query['createTourneysTable'] = """CREATE TABLE Tourneys (
id INT UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id INT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
tourneyTypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
siteTourneyNo BIGINT NOT NULL, siteTourneyNo BIGINT NOT NULL,
entries INT NOT NULL, entries INT NOT NULL,
@ -283,7 +283,7 @@ class FpdbSQLQueries:
ENGINE=INNODB""" ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'): elif(self.dbname == 'PostgreSQL'):
self.query['createTourneysTable'] = """CREATE TABLE Tourneys ( self.query['createTourneysTable'] = """CREATE TABLE Tourneys (
id SERIAL UNIQUE, PRIMARY KEY (id), id SERIAL, PRIMARY KEY (id),
tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
siteTourneyNo BIGINT, siteTourneyNo BIGINT,
entries INT, entries INT,
@ -300,7 +300,7 @@ class FpdbSQLQueries:
if(self.dbname == 'MySQL InnoDB'): if(self.dbname == 'MySQL InnoDB'):
self.query['createHandsPlayersTable'] = """CREATE TABLE HandsPlayers ( self.query['createHandsPlayersTable'] = """CREATE TABLE HandsPlayers (
id BIGINT UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
handId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handId) REFERENCES Hands(id), handId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handId) REFERENCES Hands(id),
playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
startCash INT NOT NULL, startCash INT NOT NULL,
@ -332,7 +332,7 @@ class FpdbSQLQueries:
ENGINE=INNODB""" ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'): elif(self.dbname == 'PostgreSQL'):
self.query['createHandsPlayersTable'] = """CREATE TABLE HandsPlayers ( self.query['createHandsPlayersTable'] = """CREATE TABLE HandsPlayers (
id BIGSERIAL UNIQUE, PRIMARY KEY (id), id BIGSERIAL, PRIMARY KEY (id),
handId BIGINT, FOREIGN KEY (handId) REFERENCES Hands(id), handId BIGINT, FOREIGN KEY (handId) REFERENCES Hands(id),
playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id), playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id),
startCash INT, startCash INT,
@ -370,7 +370,7 @@ class FpdbSQLQueries:
if(self.dbname == 'MySQL InnoDB'): if(self.dbname == 'MySQL InnoDB'):
self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers ( self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers (
id BIGINT UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
tourneyId INT UNSIGNED NOT NULL, FOREIGN KEY (tourneyId) REFERENCES Tourneys(id), tourneyId INT UNSIGNED NOT NULL, FOREIGN KEY (tourneyId) REFERENCES Tourneys(id),
playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
payinAmount INT NOT NULL, payinAmount INT NOT NULL,
@ -381,7 +381,7 @@ class FpdbSQLQueries:
ENGINE=INNODB""" ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'): elif(self.dbname == 'PostgreSQL'):
self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers ( self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers (
id BIGSERIAL UNIQUE, PRIMARY KEY (id), id BIGSERIAL, PRIMARY KEY (id),
tourneyId INT, FOREIGN KEY (tourneyId) REFERENCES Tourneys(id), tourneyId INT, FOREIGN KEY (tourneyId) REFERENCES Tourneys(id),
playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id), playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id),
payinAmount INT, payinAmount INT,
@ -399,7 +399,7 @@ class FpdbSQLQueries:
if(self.dbname == 'MySQL InnoDB'): if(self.dbname == 'MySQL InnoDB'):
self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions ( self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions (
id BIGINT UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
handPlayerId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handPlayerId) REFERENCES HandsPlayers(id), handPlayerId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handPlayerId) REFERENCES HandsPlayers(id),
street SMALLINT NOT NULL, street SMALLINT NOT NULL,
actionNo SMALLINT NOT NULL, actionNo SMALLINT NOT NULL,
@ -411,7 +411,7 @@ class FpdbSQLQueries:
ENGINE=INNODB""" ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'): elif(self.dbname == 'PostgreSQL'):
self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions ( self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions (
id BIGSERIAL UNIQUE, PRIMARY KEY (id), id BIGSERIAL, PRIMARY KEY (id),
handPlayerId BIGINT, FOREIGN KEY (handPlayerId) REFERENCES HandsPlayers(id), handPlayerId BIGINT, FOREIGN KEY (handPlayerId) REFERENCES HandsPlayers(id),
street SMALLINT, street SMALLINT,
actionNo SMALLINT, actionNo SMALLINT,
@ -430,7 +430,7 @@ class FpdbSQLQueries:
if(self.dbname == 'MySQL InnoDB'): if(self.dbname == 'MySQL InnoDB'):
self.query['createHudCacheTable'] = """CREATE TABLE HudCache ( self.query['createHudCacheTable'] = """CREATE TABLE HudCache (
id BIGINT UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
activeSeats SMALLINT NOT NULL, activeSeats SMALLINT NOT NULL,
@ -503,7 +503,7 @@ class FpdbSQLQueries:
ENGINE=INNODB""" ENGINE=INNODB"""
elif(self.dbname == 'PostgreSQL'): elif(self.dbname == 'PostgreSQL'):
self.query['createHudCacheTable'] = """CREATE TABLE HudCache ( self.query['createHudCacheTable'] = """CREATE TABLE HudCache (
id BIGSERIAL UNIQUE, PRIMARY KEY (id), id BIGSERIAL, PRIMARY KEY (id),
gametypeId INT, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), gametypeId INT, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id), playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id),
activeSeats SMALLINT, activeSeats SMALLINT,
@ -726,7 +726,72 @@ class FpdbSQLQueries:
on hprof2.gameTypeId = stats.gameTypeId on hprof2.gameTypeId = stats.gameTypeId
order by stats.base, stats.limittype, stats.bigBlind""" order by stats.base, stats.limittype, stats.bigBlind"""
elif(self.dbname == 'PostgreSQL'): elif(self.dbname == 'PostgreSQL'):
self.query['playerStats'] = """ """ self.query['playerStats'] = """
SELECT stats.gametypeId
,stats.base
,stats.limitType
,stats.name
,(stats.bigBlind/100) as BigBlind
,stats.n
,stats.vpip
,stats.pfr
,stats.saw_f
,stats.sawsd
,stats.wtsdwsf
,stats.wmsd
,stats.FlAFq
,stats.TuAFq
,stats.RvAFq
,stats.PFAFq
,hprof2.sum_profit/100 as Net
,(hprof2.sum_profit/stats.bigBlind)/(stats.n/100) as BBlPer100
FROM
(select gt.base
,upper(gt.limitType) as limitType
,s.name
,gt.bigBlind
,hc.gametypeId
,sum(HDs) as n
,round(100*sum(street0VPI)/sum(HDs)) as vpip
,round(100*sum(street0Aggr)/sum(HDs)) as pfr
,round(100*sum(street1Seen)/sum(HDs)) AS saw_f
,round(100*sum(sawShowdown)/sum(HDs)) AS sawsd
,round(100*sum(sawShowdown)/sum(street1Seen)) AS wtsdwsf
,round(100*sum(wonAtSD)/sum(sawShowdown)) AS wmsd
,round(100*sum(street1Aggr)/sum(street1Seen)) AS FlAFq
,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 hc.playerId in <player_test>
group by gt.base
,upper(gt.limitType)
,s.name
,gt.bigBlind
,hc.gametypeId
) stats
inner join
( select hprof.gameTypeId, sum(hprof.profit) as sum_profit
from
(select hp.handId,
h.gameTypeId,
hp.winnings,
SUM(ha.amount) as costs,
hp.winnings - SUM(ha.amount) as profit
from HandsPlayers hp
inner join Hands h ON h.id = hp.handId
inner join HandsActions ha ON ha.handPlayerId = hp.id
where hp.playerId in <player_test>
and hp.tourneysPlayersId IS NULL
group by hp.handId, h.gameTypeId, hp.position, hp.winnings
) hprof
group by hprof.gameTypeId
) hprof2
on hprof2.gameTypeId = stats.gameTypeId
order by stats.base, stats.limittype, stats.bigBlind"""
elif(self.dbname == 'SQLite'): elif(self.dbname == 'SQLite'):
self.query['playerStats'] = """ """ self.query['playerStats'] = """ """

View File

@ -83,22 +83,24 @@ class GuiGraphViewer (threading.Thread):
self.ax.set_xlabel("Hands", fontsize = 12) self.ax.set_xlabel("Hands", fontsize = 12)
self.ax.set_ylabel("$", fontsize = 12) self.ax.set_ylabel("$", fontsize = 12)
self.ax.grid(color='g', linestyle=':', linewidth=0.2) self.ax.grid(color='g', linestyle=':', linewidth=0.2)
#This line will crash if no hands exist in the query. if(line == None):
text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) #TODO: Do something useful like alert user
print "No hands returned by graph query"
else:
text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line))
self.ax.annotate(text, self.ax.annotate(text,
xy=(10, -10), xy=(10, -10),
xycoords='axes points', xycoords='axes points',
horizontalalignment='left', verticalalignment='top', horizontalalignment='left', verticalalignment='top',
fontsize=10) fontsize=10)
#Draw plot
self.ax.plot(line,)
#Draw plot self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea
self.ax.plot(line,) self.graphBox.add(self.canvas)
self.canvas.show()
self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea
self.graphBox.add(self.canvas)
self.canvas.show()
#end of def showClicked #end of def showClicked
def getRingProfitGraph(self, name, site): def getRingProfitGraph(self, name, site):
@ -106,6 +108,9 @@ class GuiGraphViewer (threading.Thread):
#returns (HandId,Winnings,Costs,Profit) #returns (HandId,Winnings,Costs,Profit)
winnings = self.db.cursor.fetchall() winnings = self.db.cursor.fetchall()
if(winnings == ()):
return None
y=map(lambda x:float(x[3]), winnings) y=map(lambda x:float(x[3]), winnings)
line = cumsum(y) line = cumsum(y)
return line/100 return line/100

View File

@ -44,43 +44,44 @@ class GuiPlayerStats (threading.Thread):
# Get currently active site and grab playerid # Get currently active site and grab playerid
tmp = self.sql.query['playerStats'] tmp = self.sql.query['playerStats']
result = self.cursor.execute(self.sql.query['getPlayerId'], self.heroes[self.activesite]) result = self.cursor.execute(self.sql.query['getPlayerId'], (self.heroes[self.activesite],))
result = self.db.cursor.fetchall() result = self.db.cursor.fetchall()
pid = result[0][0] if not result == ():
tmp = tmp.replace("<player_test>", "(" + str(pid) + ")") pid = result[0][0]
self.cursor.execute(tmp) tmp = tmp.replace("<player_test>", "(" + str(pid) + ")")
result = self.db.cursor.fetchall() self.cursor.execute(tmp)
cols = 18 result = self.db.cursor.fetchall()
rows = len(result)+1 # +1 for title row cols = 18
self.stats_table = gtk.Table(rows, cols, False) rows = len(result)+1 # +1 for title row
self.stats_table.set_col_spacings(4) self.stats_table = gtk.Table(rows, cols, False)
self.stats_table.show() self.stats_table.set_col_spacings(4)
vbox.add(self.stats_table) self.stats_table.show()
vbox.add(self.stats_table)
# Create header row # Create header row
titles = ("GID", "base", "Style", "Site", "$BB", "Hands", "VPIP", "PFR", "saw_f", "sawsd", "wtsdwsf", "wmsd", "FlAFq", "TuAFq", "RvAFq", "PFAFq", "Net($)", "BB/100") titles = ("GID", "base", "Style", "Site", "$BB", "Hands", "VPIP", "PFR", "saw_f", "sawsd", "wtsdwsf", "wmsd", "FlAFq", "TuAFq", "RvAFq", "PFAFq", "Net($)", "BB/100")
col = 0 col = 0
row = 0 row = 0
for t in titles: for t in titles:
l = gtk.Label(titles[col]) l = gtk.Label(titles[col])
l.show() l.show()
self.stats_table.attach(l, col, col+1, row, row+1) self.stats_table.attach(l, col, col+1, row, row+1)
col +=1 col +=1
for row in range(rows-1): for row in range(rows-1):
for col in range(cols): for col in range(cols):
if(row%2 == 0): if(row%2 == 0):
bgcolor = "white" bgcolor = "white"
else: else:
bgcolor = "lightgrey" bgcolor = "lightgrey"
eb = gtk.EventBox() eb = gtk.EventBox()
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor)) eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
l = gtk.Label(result[row-1][col]) l = gtk.Label(result[row-1][col])
eb.add(l) eb.add(l)
self.stats_table.attach(eb, col, col+1, row+1, row+2) self.stats_table.attach(eb, col, col+1, row+1, row+2)
l.show() l.show()
eb.show() eb.show()
def fillPlayerFrame(self, vbox): def fillPlayerFrame(self, vbox):

View File

@ -28,6 +28,41 @@ import operator
from xml.dom.minidom import Node from xml.dom.minidom import Node
from pokereval import PokerEval from pokereval import PokerEval
#from pokerengine.pokercards import *
# provides letter2name{}, letter2names{}, visible_card(), not_visible_card(), is_visible(), card_value(), class PokerCards
# but it's probably not installed so here are the ones we may want:
letter2name = {
'A': 'Ace',
'K': 'King',
'Q': 'Queen',
'J': 'Jack',
'T': 'Ten',
'9': 'Nine',
'8': 'Eight',
'7': 'Seven',
'6': 'Six',
'5': 'Five',
'4': 'Four',
'3': 'Trey',
'2': 'Deuce'
}
letter2names = {
'A': 'Aces',
'K': 'Kings',
'Q': 'Queens',
'J': 'Jacks',
'T': 'Tens',
'9': 'Nines',
'8': 'Eights',
'7': 'Sevens',
'6': 'Sixes',
'5': 'Fives',
'4': 'Fours',
'3': 'Treys',
'2': 'Deuces'
}
class HandHistoryConverter: class HandHistoryConverter:
eval = PokerEval() eval = PokerEval()
def __init__(self, config, file, sitename): def __init__(self, config, file, sitename):
@ -67,6 +102,7 @@ class HandHistoryConverter:
self.gametype = self.determineGameType() self.gametype = self.determineGameType()
self.hands = self.splitFileIntoHands() self.hands = self.splitFileIntoHands()
for hand in self.hands: for hand in self.hands:
print "\nInput:\n"+hand.string
self.readHandInfo(hand) self.readHandInfo(hand)
self.readPlayerStacks(hand) self.readPlayerStacks(hand)
self.markStreets(hand) self.markStreets(hand)
@ -76,17 +112,21 @@ class HandHistoryConverter:
self.readShowdownActions(hand) self.readShowdownActions(hand)
# Read action (Note: no guarantee this is in hand order. # Read action (Note: no guarantee this is in hand order.
for street in hand.streets.groupdict(): for street in hand.streets.groupdict():
self.readAction(hand, street) if hand.streets.group(street) is not None:
self.readAction(hand, street)
self.readCollectPot(hand)
# finalise it (total the pot) # finalise it (total the pot)
hand.totalPot() hand.totalPot()
self.getRake(hand) self.getRake(hand)
if(hand.involved == True): hand.printHand()
#if(hand.involved == True):
#self.writeHand("output file", hand) #self.writeHand("output file", hand)
hand.printHand() #hand.printHand()
else: #else:
pass #Don't write out observed hands #pass #Don't write out observed hands
##### #####
# These functions are parse actions that may be overridden by the inheriting class # These functions are parse actions that may be overridden by the inheriting class
@ -124,6 +164,7 @@ class HandHistoryConverter:
def readBlinds(self, hand): abstract def readBlinds(self, hand): abstract
def readHeroCards(self, hand): abstract def readHeroCards(self, hand): abstract
def readAction(self, hand, street): abstract def readAction(self, hand, street): abstract
def readCollectPot(self, hand): 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 # 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. # so that an inheriting class can calculate it for the specific site if need be.
@ -156,6 +197,7 @@ class HandHistoryConverter:
def splitFileIntoHands(self): def splitFileIntoHands(self):
hands = [] hands = []
self.obs.strip()
list = self.rexx.split_hand_re.split(self.obs) list = self.rexx.split_hand_re.split(self.obs)
list.pop() #Last entry is empty list.pop() #Last entry is empty
for l in list: for l in list:
@ -177,66 +219,6 @@ class HandHistoryConverter:
except: except:
traceback.print_exc(file=sys.stderr) traceback.print_exc(file=sys.stderr)
def writeHand(self, file, hand):
"""Write out parsed data"""
print "DEBUG: *************************"
print "DEBUG: Start of print hand"
print "DEBUG: *************************"
print "%s Game #%s: %s ($%s/$%s) - %s" %(hand.sitename, hand.handid, "XXXXhand.gametype", hand.sb, hand.bb, hand.starttime)
print "Table '%s' %d-max Seat #%s is the button" %(hand.tablename, hand.maxseats, hand.buttonpos)
for player in hand.players:
print "Seat %s: %s ($%s)" %(player[0], player[1], player[2])
if(hand.posted[0] == "FpdbNBP"):
print "No small blind posted"
else:
print "%s: posts small blind $%s" %(hand.posted[0], hand.sb)
#May be more than 1 bb posting
print "%s: posts big blind $%s" %(hand.posted[1], hand.bb)
if(len(hand.posted) > 2):
# Need to loop on all remaining big blinds - lazy
print "XXXXXXXXX FIXME XXXXXXXX"
print "*** HOLE CARDS ***"
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 %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 %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 %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"
def printActionLine(self, act, pot):
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 XXXpottotalXXX" %(act[0], act[1], act[2])
#takes a poker float (including , for thousand seperator and converts it to an int #takes a poker float (including , for thousand seperator and converts it to an int
def float2int (self, string): def float2int (self, string):
@ -282,6 +264,7 @@ class Hand:
self.hero = "Hiro" self.hero = "Hiro"
self.holecards = {} # dict from player names to lists of hole cards self.holecards = {} # dict from player names to lists of hole cards
self.board = {} # dict from street names to community cards self.board = {} # dict from street names to community cards
self.collected = {} # dict from player names to amounts collected
self.action = [] self.action = []
self.totalpot = None self.totalpot = None
@ -296,8 +279,7 @@ class Hand:
def addPlayer(self, seat, name, chips): def addPlayer(self, seat, name, chips):
"""seat, an int indicating the seat """seat, an int indicating the seat
name, the player name name, the player name
chips, the chips the player has at the start of the hand""" chips, the chips the player has at the start of the hand (can be None)"""
#self.players.append(name)
self.players.append([seat, name, chips]) self.players.append([seat, name, chips])
self.holecards[name] = [] self.holecards[name] = []
#self.startChips[name] = chips #self.startChips[name] = chips
@ -324,7 +306,7 @@ class Hand:
def setCommunityCards(self, street, cards): def setCommunityCards(self, street, cards):
self.board[street] = [self.card(c) for c in cards] self.board[street] = [self.card(c) for c in cards]
print self.board[street] #print self.board[street]
def card(self,c): def card(self,c):
"""upper case the ranks but not suits, 'atjqk' => 'ATJQK'""" """upper case the ranks but not suits, 'atjqk' => 'ATJQK'"""
@ -370,10 +352,25 @@ class Hand:
self.actions[street] += [[player, 'raises', amountBy, amountTo]] self.actions[street] += [[player, 'raises', amountBy, amountTo]]
def addBet(self, street, player=None, amount=0): def addBet(self, street, player=None, amount=0):
self.bets[street][name].append(Decimal(amount)) self.bets[street][player].append(Decimal(amount))
self.orderedBets[street].append(Decimal(amount)) #self.orderedBets[street].append(Decimal(amount))
self.actions[street] += [[player, 'bets', amount]] self.actions[street] += [[player, 'bets', amount]]
def addFold(self, street, player):
self.actions[street] += [[player, 'folds']]
def addCheck(self, street, player):
self.actions[street] += [[player, 'checks']]
def addCollectPot(self,player, pot):
if player not in self.collected:
self.collected[player] = pot
else:
# possibly lines like "p collected $ from pot" appear during the showdown
# but they are usually unique in the summary.
print "%s collected pot more than once; avoidable by reading winnings only from summary lines?"
def totalPot(self): def totalPot(self):
"""If all bets and blinds have been added, totals up the total pot size """If all bets and blinds have been added, totals up the total pot size
Known bug: doesn't take into account side pots""" Known bug: doesn't take into account side pots"""
@ -391,7 +388,7 @@ Known bug: doesn't take into account side pots"""
def printHand(self): def printHand(self):
# PokerStars format. # PokerStars format.
print "### DEBUG ###" print "\n### Pseudo stars format ###"
print "%s Game #%s: %s ($%s/$%s) - %s" %(self.sitename, self.handid, "XXXXhand.gametype", self.sb, self.bb, self.starttime) 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) print "Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos)
for player in self.players: for player in self.players:
@ -409,24 +406,25 @@ Known bug: doesn't take into account side pots"""
# What about big & small blinds? # What about big & small blinds?
print "*** HOLE CARDS ***" print "*** HOLE CARDS ***"
print "Dealt to %s [%s %s]" %(self.hero , self.holecards[self.hero][0], self.holecards[self.hero][1]) if self.involved:
print "Dealt to %s [%s]" %(self.hero , " ".join(self.holecards[self.hero]))
if 'PREFLOP' in self.actions: if 'PREFLOP' in self.actions:
for act in self.actions['PREFLOP']: for act in self.actions['PREFLOP']:
self.printActionLine(act) self.printActionLine(act)
if 'FLOP' in self.actions: if 'FLOP' in self.actions:
print "*** FLOP *** [%s %s %s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3")) print "*** FLOP *** [%s]" %( " ".join(self.board['Flop']))
for act in self.actions['FLOP']: for act in self.actions['FLOP']:
self.printActionLine(act) self.printActionLine(act)
if 'TURN' in self.actions: 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")) print "*** TURN *** [%s] [%s]" %( " ".join(self.board['Flop']), " ".join(self.board['Turn']))
for act in self.actions['TURN']: for act in self.actions['TURN']:
self.printActionLine(act) self.printActionLine(act)
if 'RIVER' in self.actions: 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")) print "*** RIVER *** [%s] [%s]" %(" ".join(self.board['Flop']+self.board['Turn']), " ".join(self.board['River']) )
for act in self.actions['RIVER']: for act in self.actions['RIVER']:
self.printActionLine(act) self.printActionLine(act)
@ -438,21 +436,42 @@ Known bug: doesn't take into account side pots"""
print "what do they show" print "what do they show"
print "*** SUMMARY ***" print "*** SUMMARY ***"
print "Total pot $%s | Rake $%s)" % (self.totalpot, self.rake) print "Total pot $%s | Rake $%.2f)" % (self.totalpot, self.rake) # TODO side pots
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")) board = []
for s in self.board.values():
board += s
if board: # sometimes hand ends preflop without a board
print "Board [%s]" % (" ".join(board))
#print self.board #print self.board
for player in self.players: for player in self.players:
if self.holecards[player[1]]: # empty list default is false seatnum = player[0]
hole = self.holecards[player[1]] name = player[1]
#print self.board.values() if name in self.collected and self.holecards[name]:
board = [] # TODO: (bug) hero cards will always be 'shown' because they are known to us. Better to explicitly flag those who 'show' their cards.
for s in self.board.values(): print "Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards[name]), self.collected[name])
board += s elif name in self.collected:
playerhand = self.bestHand('hi', board+hole) print "Seat %d: %s collected ($%s)" % (seatnum, name, self.collected[name])
print "Seat %d: %s showed %s and won/lost with %s" % (player[0], player[1], hole, playerhand) elif self.holecards[player[1]]:
print "Seat %d: %s showed [%s]" % (seatnum, name, " ".join(self.holecards[name]))
else: else:
print "Seat %d: %s mucked or folded" % (player[0], player[1]) print "Seat %d: %s folded or mucked" % (seatnum, name)
print
# TODO:
# logic for side pots
# logic for which players get to showdown
# I'm just not sure we need to do this so heavily.. and if we do, it's probably better to use pokerlib
#if self.holecards[player[1]]: # empty list default is false
#hole = self.holecards[player[1]]
##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)
#print "Seat %d: %s showed %s" % (player[0], player[1], hole)
#else:
#print "Seat %d: %s mucked or folded" % (player[0], player[1])
def printActionLine(self, act): def printActionLine(self, act):
@ -460,13 +479,13 @@ Known bug: doesn't take into account side pots"""
print "%s: %s " %(act[0], act[1]) print "%s: %s " %(act[0], act[1])
if act[1] == 'calls': if act[1] == 'calls':
print "%s: %s $%s" %(act[0], act[1], act[2]) print "%s: %s $%s" %(act[0], act[1], act[2])
if act[1] == 'bets':
print "%s: %s $%s" %(act[0], act[1], act[2])
if act[1] == 'raises': if act[1] == 'raises':
print "%s: %s $%s to $%s" %(act[0], act[1], act[2], act[3]) print "%s: %s $%s to $%s" %(act[0], act[1], act[2], act[3])
# going to use pokereval to figure out hands # going to use pokereval to figure out hands at some point.
# these functions are copied from pokergame.py # 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): def bestHand(self, side, cards):
#if self.variant == "omaha" or self.variant == "omaha8": #if self.variant == "omaha" or self.variant == "omaha8":
#hand = self.serial2player[serial].hand.tolist(True) #hand = self.serial2player[serial].hand.tolist(True)
@ -477,38 +496,39 @@ Known bug: doesn't take into account side pots"""
print cards print cards
return HandHistoryConverter.eval.best('hi', cards, []) return HandHistoryConverter.eval.best('hi', cards, [])
# from pokergame.py
def bestHandValue(self, side, serial): def bestHandValue(self, side, serial):
(value, cards) = self.bestHand(side, serial) (value, cards) = self.bestHand(side, serial)
return value return value
# from pokergame.py
# got rid of the _ for internationalisation
def readableHandValueLong(self, side, value, cards): def readableHandValueLong(self, side, value, cards):
cards = self.eval.card2string(cards)
if value == "NoPair": if value == "NoPair":
if side == "low": if side == "low":
if cards[0][0] == '5': if cards[0][0] == '5':
return _("The wheel") return ("The wheel")
else: else:
return join(map(lambda card: card[0], cards), ", ") return join(map(lambda card: card[0], cards), ", ")
else: else:
return _("High card %(card)s") % { 'card' : _(letter2name[cards[0][0]]) } return ("High card %(card)s") % { 'card' : (letter2name[cards[0][0]]) }
elif value == "OnePair": elif value == "OnePair":
return _("A pair of %(card)s") % { 'card' : _(letter2names[cards[0][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[2][0]]) } return ("A pair of %(card)s") % { 'card' : (letter2names[cards[0][0]]) } + (", %(card)s kicker") % { 'card' : (letter2name[cards[2][0]]) }
elif value == "TwoPair": 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]]) } 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": elif value == "Trips":
return _("Three of a kind %(card)s") % { 'card' : _(letter2names[cards[0][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[3][0]]) } return ("Three of a kind %(card)s") % { 'card' : (letter2names[cards[0][0]]) } + (", %(card)s kicker") % { 'card' : (letter2name[cards[3][0]]) }
elif value == "Straight": elif value == "Straight":
return _("Straight %(card1)s to %(card2)s") % { 'card1' : _(letter2name[cards[0][0]]), 'card2' : _(letter2name[cards[4][0]]) } return ("Straight %(card1)s to %(card2)s") % { 'card1' : (letter2name[cards[0][0]]), 'card2' : (letter2name[cards[4][0]]) }
elif value == "Flush": elif value == "Flush":
return _("Flush %(card)s high") % { 'card' : _(letter2name[cards[0][0]]) } return ("Flush %(card)s high") % { 'card' : (letter2name[cards[0][0]]) }
elif value == "FlHouse": elif value == "FlHouse":
return _("%(card1)ss full of %(card2)ss") % { 'card1' : _(letter2name[cards[0][0]]), 'card2' : _(letter2name[cards[3][0]]) } return ("%(card1)ss full of %(card2)ss") % { 'card1' : (letter2name[cards[0][0]]), 'card2' : (letter2name[cards[3][0]]) }
elif value == "Quads": elif value == "Quads":
return _("Four of a kind %(card)s") % { 'card' : _(letter2names[cards[0][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[4][0]]) } return _("Four of a kind %(card)s") % { 'card' : (letter2names[cards[0][0]]) } + (", %(card)s kicker") % { 'card' : (letter2name[cards[4][0]]) }
elif value == "StFlush": elif value == "StFlush":
if letter2name[cards[0][0]] == 'Ace': if letter2name[cards[0][0]] == 'Ace':
return _("Royal flush") return ("Royal flush")
else: else:
return _("Straight flush %(card)s high") % { 'card' : _(letter2name[cards[0][0]]) } return ("Straight flush %(card)s high") % { 'card' : (letter2name[cards[0][0]]) }
return value return value

View File

@ -134,6 +134,8 @@ class Hud:
(x, y) = loc[adj[i]] (x, y) = loc[adj[i]]
if self.stat_windows.has_key(i): if self.stat_windows.has_key(i):
self.stat_windows[i].relocate(x, y) self.stat_windows[i].relocate(x, y)
return True
def on_button_press(self, widget, event): def on_button_press(self, widget, event):
if event.button == 1: if event.button == 1:
@ -152,6 +154,7 @@ class Hud:
def reposition_windows(self, *args): def reposition_windows(self, *args):
self.update_table_position() self.update_table_position()
return True
def debug_stat_windows(self, *args): def debug_stat_windows(self, *args):
print self.table, "\n", self.main_window.window.get_transient_for() print self.table, "\n", self.main_window.window.get_transient_for()
@ -226,7 +229,7 @@ class Hud:
aux_params = config.get_aux_parameters(game_params['aux']) aux_params = config.get_aux_parameters(game_params['aux'])
self.aux_windows.append(eval("%s.%s(gtk.Window(), self, config, 'fpdb')" % (aux_params['module'], aux_params['class']))) self.aux_windows.append(eval("%s.%s(gtk.Window(), self, config, 'fpdb')" % (aux_params['module'], aux_params['class'])))
gobject.timeout_add(0.5, self.update_table_position) gobject.timeout_add(500, self.update_table_position)
def update(self, hand, config, stat_dict): def update(self, hand, config, stat_dict):
self.hand = hand # this is the last hand, so it is available later self.hand = hand # this is the last hand, so it is available later