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

This commit is contained in:
Ray 2009-08-08 09:29:41 -04:00
commit 0a1e6e57b5
16 changed files with 155 additions and 170 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.pyc
*~

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright 2008, Carl Gherardi # Copyright 2008, Carl Gherardi
@ -60,7 +60,7 @@ debugging: if False, pass on partially supported game types. If true, have a go
logging.info("Initialising Absolute converter class") logging.info("Initialising Absolute converter class")
self.filetype = "text" self.filetype = "text"
self.codepage = "cp1252" self.codepage = "cp1252"
self.siteId = 3 # Needs to match id entry in Sites database self.siteId = 8 # Needs to match id entry in Sites database
self.debugging = debugging self.debugging = debugging
if autostart: if autostart:
self.start() self.start()
@ -79,7 +79,7 @@ debugging: if False, pass on partially supported game types. If true, have a go
# TODO: Absolute posting when coming in new: %s - Posts $0.02 .. should that be a new Post line? where do we need to add support for that? *confused* # TODO: Absolute posting when coming in new: %s - Posts $0.02 .. should that be a new Post line? where do we need to add support for that? *confused*
self.re_PostBoth = re.compile(ur"^%s - Posts dead (?:\$| €|)(?P<SBBB>[0-9]*[.0-9]+)" % player_re, re.MULTILINE) self.re_PostBoth = re.compile(ur"^%s - Posts dead (?:\$| €|)(?P<SBBB>[0-9]*[.0-9]+)" % player_re, re.MULTILINE)
self.re_Action = re.compile(ur"^%s - (?P<ATYPE>Bets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P<BET>[0-9]*[.0-9]+)?" % player_re, re.MULTILINE) self.re_Action = re.compile(ur"^%s - (?P<ATYPE>Bets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P<BET>[0-9]*[.0-9]+)?" % player_re, re.MULTILINE)
print "^%s - (?P<ATYPE>Bets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P<BET>[0-9]*[.0-9]+)?" % player_re # print "^%s - (?P<ATYPE>Bets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P<BET>[0-9]*[.0-9]+)?" % player_re
self.re_ShowdownAction = re.compile(ur"^%s - Shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE) self.re_ShowdownAction = re.compile(ur"^%s - Shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
self.re_CollectPot = re.compile(ur"^Seat [0-9]: %s(?: \(dealer\)| \(big blind\)| \(small blind\)|) (?:won|collected) Total \((?:\$| €|)(?P<POT>[0-9]*[.0-9]+)\)" % player_re, re.MULTILINE) self.re_CollectPot = re.compile(ur"^Seat [0-9]: %s(?: \(dealer\)| \(big blind\)| \(small blind\)|) (?:won|collected) Total \((?:\$| €|)(?P<POT>[0-9]*[.0-9]+)\)" % player_re, re.MULTILINE)
#self.re_PostSB = re.compile(ur"^%s: posts small blind \[(?:\$| €|) (?P<SB>[.0-9]+)" % player_re, re.MULTILINE) #self.re_PostSB = re.compile(ur"^%s: posts small blind \[(?:\$| €|) (?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
@ -248,8 +248,7 @@ or None if we fail to get the info """
else: else:
#Not involved in hand #Not involved in hand
hand.involved = False hand.involved = False
def readStudPlayerCards(self, hand, street): def readStudPlayerCards(self, hand, street):
# lol. see Plymouth.txt # lol. see Plymouth.txt
logging.warning("Absolute readStudPlayerCards is only a stub.") logging.warning("Absolute readStudPlayerCards is only a stub.")
@ -283,7 +282,7 @@ or None if we fail to get the info """
logging.debug("readShowdownActions") logging.debug("readShowdownActions")
for shows in self.re_ShowdownAction.finditer(hand.handText): for shows in self.re_ShowdownAction.finditer(hand.handText):
cards = shows.group('CARDS') cards = shows.group('CARDS')
cards = [validCard(card) for card in cards.split(' ')] cards = [validCard(card) for card in cards.split(' ')]
logging.debug("readShowdownActions %s %s" %(cards, shows.group('PNAME'))) logging.debug("readShowdownActions %s %s" %(cards, shows.group('PNAME')))
hand.addShownCards(cards, shows.group('PNAME')) hand.addShownCards(cards, shows.group('PNAME'))

View File

@ -584,19 +584,20 @@ class Config:
return paths return paths
def get_frames(self, site = "PokerStars"): def get_frames(self, site = "PokerStars"):
if site not in self.supported_sites: return False
return self.supported_sites[site].use_frames == True return self.supported_sites[site].use_frames == True
def get_default_colors(self, site = "PokerStars"): def get_default_colors(self, site = "PokerStars"):
colors = {} colors = {}
if self.supported_sites[site].hudopacity == "": if site not in self.supported_sites or self.supported_sites[site].hudopacity == "":
colors['hudopacity'] = 0.90 colors['hudopacity'] = 0.90
else: else:
colors['hudopacity'] = float(self.supported_sites[site].hudopacity) colors['hudopacity'] = float(self.supported_sites[site].hudopacity)
if self.supported_sites[site].hudbgcolor == "": if site not in self.supported_sites or self.supported_sites[site].hudbgcolor == "":
colors['hudbgcolor'] = "#FFFFFF" colors['hudbgcolor'] = "#FFFFFF"
else: else:
colors['hudbgcolor'] = self.supported_sites[site].hudbgcolor colors['hudbgcolor'] = self.supported_sites[site].hudbgcolor
if self.supported_sites[site].hudfgcolor == "": if site not in self.supported_sites or self.supported_sites[site].hudfgcolor == "":
colors['hudfgcolor'] = "#000000" colors['hudfgcolor'] = "#000000"
else: else:
colors['hudfgcolor'] = self.supported_sites[site].hudfgcolor colors['hudfgcolor'] = self.supported_sites[site].hudfgcolor
@ -604,6 +605,8 @@ class Config:
def get_default_font(self, site = 'PokerStars'): def get_default_font(self, site = 'PokerStars'):
(font, font_size) = ("Sans", "8") (font, font_size) = ("Sans", "8")
if site not in self.supported_sites:
return ("Sans", "8")
if self.supported_sites[site].font == "": if self.supported_sites[site].font == "":
font = "Sans" font = "Sans"
else: else:

View File

@ -951,7 +951,7 @@ class Database:
#end def dropAllIndexes #end def dropAllIndexes
def fillDefaultData(self): def fillDefaultData(self):
c = self.get_cursor() c = self.get_cursor()
c.execute("INSERT INTO Settings (version) VALUES (118);") c.execute("INSERT INTO Settings (version) VALUES (118);")
c.execute("INSERT INTO Sites (name,currency) VALUES ('Full Tilt Poker', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('Full Tilt Poker', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('PokerStars', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('PokerStars', 'USD')")
@ -1040,10 +1040,15 @@ class Database:
def insertPlayer(self, name, site_id): def insertPlayer(self, name, site_id):
result = None result = None
c = self.get_cursor() c = self.get_cursor()
c.execute ("SELECT id FROM Players WHERE name=%s".replace('%s',self.sql.query['placeholder']) q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s"
,(name,)) q = q.replace('%s', self.sql.query['placeholder'])
#print "DEBUG: name: %s site: %s" %(name, site_id)
c.execute (q, (site_id, name))
tmp = c.fetchone() tmp = c.fetchone()
if (len(tmp)==0): #new player if (tmp == None): #new player
c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)".replace('%s',self.sql.query['placeholder']) c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)".replace('%s',self.sql.query['placeholder'])
,(name, site_id)) ,(name, site_id))
#Get last id might be faster here. #Get last id might be faster here.
@ -1116,70 +1121,70 @@ class Database:
def storeHand(self, p): def storeHand(self, p):
#stores into table hands: #stores into table hands:
self.cursor.execute ("""INSERT INTO Hands ( q = """INSERT INTO Hands (
tablename, tablename,
sitehandno,
gametypeid, gametypeid,
sitehandno,
handstart, handstart,
importtime, importtime,
seats,
maxseats, maxseats,
boardcard1, boardcard1,
boardcard2, boardcard2,
boardcard3, boardcard3,
boardcard4, boardcard4,
boardcard5, boardcard5
-- texture,
playersVpi,
playersAtStreet1,
playersAtStreet2,
playersAtStreet3,
playersAtStreet4,
playersAtShowdown,
street0Raises,
street1Raises,
street2Raises,
street3Raises,
street4Raises,
-- street1Pot,
-- street2Pot,
-- street3Pot,
-- street4Pot,
-- showdownPot
) )
VALUES VALUES
(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
%s, %s, %s, %s, %s, %s, %s)""", #--- texture,
( #-- playersVpi,
p['tablename'], #-- playersAtStreet1,
p['sitehandno'], #-- playersAtStreet2,
#-- playersAtStreet3,
#-- playersAtStreet4,
#-- playersAtShowdown,
#-- street0Raises,
#-- street1Raises,
#-- street2Raises,
#-- street3Raises,
#-- street4Raises,
#-- street1Pot,
#-- street2Pot,
#-- street3Pot,
#-- street4Pot,
#-- showdownPot
#-- seats,
q = q.replace('%s', self.sql.query['placeholder'])
self.cursor.execute(q, (
p['tableName'],
p['siteHandNo'],
p['gametypeid'], p['gametypeid'],
p['handStart'], p['handStart'],
datetime.datetime.today(), datetime.today(), #importtime
len(p['names']), # len(p['names']), #seats
p['maxSeats'], p['maxSeats'],
p['boardcard1'], p['boardcard1'],
p['boardcard2'], p['boardcard2'],
p['boardcard3'], p['boardcard3'],
p['boardcard4'], p['boardcard4'],
p['boardcard5'], p['boardcard5'])
hudCache['playersVpi'], # hudCache['playersVpi'],
hudCache['playersAtStreet1'], # hudCache['playersAtStreet1'],
hudCache['playersAtStreet2'], # hudCache['playersAtStreet2'],
hudCache['playersAtStreet3'], # hudCache['playersAtStreet3'],
hudCache['playersAtStreet4'], # hudCache['playersAtStreet4'],
hudCache['playersAtShowdown'], # hudCache['playersAtShowdown'],
hudCache['street0Raises'], # hudCache['street0Raises'],
hudCache['street1Raises'], # hudCache['street1Raises'],
hudCache['street2Raises'], # hudCache['street2Raises'],
hudCache['street3Raises'], # hudCache['street3Raises'],
hudCache['street4Raises'], # hudCache['street4Raises'],
hudCache['street1Pot'], # hudCache['street1Pot'],
hudCache['street2Pot'], # hudCache['street2Pot'],
hudCache['street3Pot'], # hudCache['street3Pot'],
hudCache['street4Pot'], # hudCache['street4Pot'],
hudCache['showdownPot'] # hudCache['showdownPot']
)
) )
#return getLastInsertId(backend, conn, cursor) #return getLastInsertId(backend, conn, cursor)
# def storeHand # def storeHand

View File

@ -17,6 +17,7 @@
import threading import threading
import subprocess import subprocess
import traceback
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')

View File

@ -20,6 +20,7 @@ import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import os import os
import traceback
from time import * from time import *
#import pokereval #import pokereval

View File

@ -132,7 +132,7 @@ class GuiPlayerStats (threading.Thread):
self.stats_vbox = gtk.VBox(False, 0) self.stats_vbox = gtk.VBox(False, 0)
self.stats_vbox.show() self.stats_vbox.show()
self.stats_frame.add(self.stats_vbox) self.stats_frame.add(self.stats_vbox)
self.fillStatsFrame(self.stats_vbox) # self.fillStatsFrame(self.stats_vbox)
self.main_hbox.pack_start(self.filters.get_vbox()) self.main_hbox.pack_start(self.filters.get_vbox())
self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True) self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True)
@ -167,7 +167,9 @@ class GuiPlayerStats (threading.Thread):
for site in sites: for site in sites:
if sites[site] == True: if sites[site] == True:
sitenos.append(siteids[site]) sitenos.append(siteids[site])
self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) # Nasty hack to deal with multiple sites + same player name -Eric
que = self.sql.query['getPlayerId'] + " AND siteId=%d" % siteids[site]
self.cursor.execute(que, (heroes[site],))
result = self.db.cursor.fetchall() result = self.db.cursor.fetchall()
if len(result) == 1: if len(result) == 1:
playerids.append(result[0][0]) playerids.append(result[0][0])

View File

@ -432,7 +432,8 @@
</hhcs> </hhcs>
<supported_databases> <supported_databases>
<database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD" db_type="fpdb"></database> <database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD" db_type="fpdb"></database>
<!-- <database db_ip="localhost" db_name="fpdb" db_pass="fpdb" db_server="sqlite" db_type="fpdb" db_user="fpdb"/> -->
</supported_databases> </supported_databases>
</FreePokerToolsConfig> </FreePokerToolsConfig>

View File

@ -37,7 +37,7 @@ import traceback
if not options.errorsToConsole: if not options.errorsToConsole:
print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_." print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_."
errorFile = open('fpdb-error-log.txt', 'w', 0) errorFile = open('HUD-error.txt', 'w', 0)
sys.stderr = errorFile sys.stderr = errorFile
import thread import thread

View File

@ -185,31 +185,49 @@ db: a connected fpdb_db object"""
# TODO: # TODO:
# Players - base playerid and siteid tuple # Players - base playerid and siteid tuple
sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId) sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId)
#Gametypes
print "DEBUG: self.gametype %s" % self.gametype
#Nice way to discover if the game is already listed in the db?
#Also this is using an old method from fpdb_simple - should probably conform to the rest of the inserts
hilo = "h"
if self.gametype['category'] in ['studhilo', 'omahahilo']:
hilo = "s"
elif self.gametype['category'] in ['razz','27_3draw','badugi']:
hilo = "l"
#FIXME - the two zeros are small_bet and big_bet for limit
gtid = db.insertGameTypes( (self.siteId, self.gametype['type'], self.gametype['base'],
self.gametype['category'], self.gametype['limitType'], hilo,
self.gametype['sb'], self.gametype['bb'], 0, 0) )
# HudCache data to come from DerivedStats class # HudCache data to come from DerivedStats class
# HandsActions - all actions for all players for all streets - self.actions # HandsActions - all actions for all players for all streets - self.actions
# BoardCards - Skip - no longer necessary
# Hands - Summary information of hand indexed by handId - gameinfo # Hands - Summary information of hand indexed by handId - gameinfo
#hh['siteHandNo'] = self.handid #This should be moved to prepInsert
# gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), hh = {}
# hh['siteHandNo'] = self.handid
#hh['handStart'] = self.starttime hh['handStart'] = self.starttime
# seats TINYINT NOT NULL, # seats TINYINT NOT NULL,
# hh['tableName'] = self.tablename
#hh['tableName'] = self.tablenam hh['maxSeats'] = self.maxseats
#hh['maxSeats'] = self.maxseats
# boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */ # boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
# boardcard2 smallint, # boardcard2 smallint,
# boardcard3 smallint, # boardcard3 smallint,
# boardcard4 smallint, # boardcard4 smallint,
# boardcard5 smallint, # boardcard5 smallint,
# Flop turn and river may all be empty - add (likely) too many elements and trim with range # Flop turn and river may all be empty - add (likely) too many elements and trim with range
# boardcards = board['FLOP'] + board['TURN'] + board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] boardcards = self.board['FLOP'] + self.board['TURN'] + self.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x']
# cards = [Card.cardFromValueSuit(v,s) for v,s in boardcards[0:4]] cards = [Card.encodeCard(c) for c in boardcards[0:5]]
# hh['boardcard1'] = cards[0] hh['boardcard1'] = cards[0]
# hh['boardcard2'] = cards[1] hh['boardcard2'] = cards[1]
# hh['boardcard3'] = cards[2] hh['boardcard3'] = cards[2]
# hh['boardcard4'] = cards[3] hh['boardcard4'] = cards[3]
# hh['boardcard5'] = cards[4] hh['boardcard5'] = cards[4]
print hh
# texture smallint, # texture smallint,
# playersVpi SMALLINT NOT NULL, /* num of players vpi */ # playersVpi SMALLINT NOT NULL, /* num of players vpi */
# Needs to be recorded # Needs to be recorded
@ -244,7 +262,7 @@ db: a connected fpdb_db object"""
# showdownPot INT, /* pot size at sd/street7 */ # showdownPot INT, /* pot size at sd/street7 */
# comment TEXT, # comment TEXT,
# commentTs DATETIME # commentTs DATETIME
# handid = db.storeHand(hh) handid = db.storeHand(hh)
# HandsPlayers - ? ... Do we fix winnings? # HandsPlayers - ? ... Do we fix winnings?
# Tourneys ? # Tourneys ?
# TourneysPlayers # TourneysPlayers
@ -453,6 +471,7 @@ Add a raise on [street] by [player] to [amountTo]
def addCheck(self, street, player): def addCheck(self, street, player):
#print "DEBUG: %s %s checked" % (street, player) #print "DEBUG: %s %s checked" % (street, player)
logging.debug("%s %s checks" % (street, player))
self.checkPlayerExists(player) self.checkPlayerExists(player)
self.actions[street].append((player, 'checks')) self.actions[street].append((player, 'checks'))

View File

@ -1,4 +1,5 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*-
#Copyright 2008 Carl Gherardi #Copyright 2008 Carl Gherardi
#This program is free software: you can redistribute it and/or modify #This program is free software: you can redistribute it and/or modify
@ -95,9 +96,14 @@ Otherwise, finish at eof.
else: else:
handsList = self.allHandsAsList() handsList = self.allHandsAsList()
logging.info("Parsing %d hands" % len(handsList)) logging.info("Parsing %d hands" % len(handsList))
nBadHangs = 0
for handText in handsList: for handText in handsList:
self.processedHands.append(self.processHand(handText)) try:
numHands= len(handsList) self.processedHands.append(self.processHand(handText))
except Exception, e: # TODO: it's better to replace it with s-t like HhcEception
nBadHangs += 1
logging.error("Caught exception while parsing hand: %s" % str(e))
numHands = len(handsList) - nBadHangs
endtime = time.time() endtime = time.time()
print "read %d hands in %.3f seconds" % (numHands, endtime - starttime) print "read %d hands in %.3f seconds" % (numHands, endtime - starttime)
if self.out_fh != sys.stdout: if self.out_fh != sys.stdout:

View File

@ -60,6 +60,8 @@ class Hud:
def __init__(self, parent, table, max, poker_game, config, db_connection): def __init__(self, parent, table, max, poker_game, config, db_connection):
# __init__ is (now) intended to be called from the stdin thread, so it # __init__ is (now) intended to be called from the stdin thread, so it
# cannot touch the gui # cannot touch the gui
if parent == None: # running from cli ..
self.parent = self
self.parent = parent self.parent = parent
self.table = table self.table = table
self.config = config self.config = config
@ -125,7 +127,8 @@ class Hud:
self.menu = gtk.Menu() self.menu = gtk.Menu()
self.item1 = gtk.MenuItem('Kill this HUD') self.item1 = gtk.MenuItem('Kill this HUD')
self.menu.append(self.item1) self.menu.append(self.item1)
self.item1.connect("activate", self.parent.kill_hud, self.table_name) if self.parent != None:
self.item1.connect("activate", self.parent.kill_hud, self.table_name)
self.item1.show() self.item1.show()
self.item2 = gtk.MenuItem('Save Layout') self.item2 = gtk.MenuItem('Save Layout')
@ -233,7 +236,7 @@ class Hud:
# Need range here, not xrange -> need the actual list # Need range here, not xrange -> need the actual list
adj = range(0, self.max + 1) # default seat adjustments = no adjustment adj = range(0, self.max + 1) # default seat adjustments = no adjustment
# does the user have a fav_seat? # does the user have a fav_seat?
if int(config.supported_sites[self.table.site].layout[self.max].fav_seat) > 0: if self.table.site != None and int(config.supported_sites[self.table.site].layout[self.max].fav_seat) > 0:
try: try:
fav_seat = config.supported_sites[self.table.site].layout[self.max].fav_seat fav_seat = config.supported_sites[self.table.site].layout[self.max].fav_seat
actual_seat = self.get_actual_seat(config.supported_sites[self.table.site].screen_name) actual_seat = self.get_actual_seat(config.supported_sites[self.table.site].screen_name)
@ -600,15 +603,17 @@ if __name__== "__main__":
c = Configuration.Config() c = Configuration.Config()
#tables = Tables.discover(c) #tables = Tables.discover(c)
t = Tables.discover_table_by_name(c, "Motorway") t = Tables.discover_table_by_name(c, "Patriot Dr")
if t is None: if t is None:
print "Table not found." print "Table not found."
db = Database.Database(c, 'fpdb', 'holdem') db = Database.Database(c, 'fpdb', 'holdem')
stat_dict = db.get_stats_from_hand(1)
# for t in tables: # for t in tables:
win = Hud(t, 10, 'holdem', c, db) win = Hud(None, t, 10, 'holdem', c, db) # parent, table, max, poker_game, config, db_connection
win.create(1, c) win.create(1, c, stat_dict, None) # hand, config, stat_dict, cards):
# t.get_details() # t.get_details()
win.update(8300, db, c) win.update(8300, c) # self, hand, config):
gtk.main() gtk.main()

View File

@ -70,25 +70,6 @@ class PartyPoker(HandHistoryConverter):
(?P<DATETIME>.+) (?P<DATETIME>.+)
""", re.VERBOSE) """, re.VERBOSE)
re_Hid = re.compile("^Game \#(?P<HID>\d+) starts.") re_Hid = re.compile("^Game \#(?P<HID>\d+) starts.")
#re_GameInfo = re.compile("""
#PartyPoker\sGame\s\#(?P<HID>[0-9]+):\s+
#(Tournament\s\# # open paren of tournament info
#(?P<TOURNO>\d+),\s
#(?P<BUYIN>[%(LS)s\+\d\.]+ # here's how I plan to use LS
#\s?(?P<TOUR_ISO>%(LEGAL_ISO)s)?
#)\s)? # close paren of tournament info
#(?P<MIXED>HORSE|8\-Game|HOSE)?\s?\(?
#(?P<GAME>Hold\'em|Razz|7\sCard\sStud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi|Triple\sDraw\s2\-7\sLowball)\s
#(?P<LIMIT>No\sLimit|Limit|Pot\sLimit)\)?,?\s
#(-\sLevel\s(?P<LEVEL>[IVXLC]+)\s)?
#\(? # open paren of the stakes
#(?P<CURRENCY>%(LS)s|)?
#(?P<SB>[.0-9]+)/(%(LS)s)?
#(?P<BB>[.0-9]+)
#\s?(?P<ISO>%(LEGAL_ISO)s)?
#\)\s-\s # close paren of the stakes
#(?P<DATETIME>.*$)""" % substitutions,
#re.MULTILINE|re.VERBOSE)
re_PlayerInfo = re.compile(""" re_PlayerInfo = re.compile("""
Seat\s(?P<SEAT>\d+):\s Seat\s(?P<SEAT>\d+):\s
@ -96,11 +77,6 @@ class PartyPoker(HandHistoryConverter):
\(\s*\$?(?P<CASH>[0-9,.]+)\s*(?:USD|)\s*\) \(\s*\$?(?P<CASH>[0-9,.]+)\s*(?:USD|)\s*\)
""" , """ ,
re.VERBOSE) re.VERBOSE)
#re_PlayerInfo = re.compile("""
#^Seat\s(?P<SEAT>[0-9]+):\s
#(?P<PNAME>.*)\s
#\((%(LS)s)?(?P<CASH>[.0-9]+)\sin\schips\)""" % substitutions,
#re.MULTILINE|re.VERBOSE)
re_HandInfo = re.compile(""" re_HandInfo = re.compile("""
^Table\s+ ^Table\s+
@ -111,12 +87,6 @@ class PartyPoker(HandHistoryConverter):
Seat\s+(?P<BUTTON>\d+)\sis\sthe\sbutton Seat\s+(?P<BUTTON>\d+)\sis\sthe\sbutton
""", """,
re.MULTILINE|re.VERBOSE) re.MULTILINE|re.VERBOSE)
#re_HandInfo = re.compile("""
#^Table\s\'(?P<TABLE>[-\ a-zA-Z\d]+)\'\s
#((?P<MAX>\d+)-max\s)?
#(?P<PLAY>\(Play\sMoney\)\s)?
#(Seat\s\#(?P<BUTTON>\d+)\sis\sthe\sbutton)?""",
#re.MULTILINE|re.VERBOSE)
re_SplitHands = re.compile('\x00+') re_SplitHands = re.compile('\x00+')
re_TailSplitHands = re.compile('(\x00+)') re_TailSplitHands = re.compile('(\x00+)')
@ -124,7 +94,6 @@ class PartyPoker(HandHistoryConverter):
re_Button = re.compile('Seat (?P<BUTTON>\d+) is the button', re.MULTILINE) re_Button = re.compile('Seat (?P<BUTTON>\d+) is the button', re.MULTILINE)
re_Board = re.compile(r"\[(?P<CARDS>.+)\]") re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
re_NoSmallBlind = re.compile('^There is no Small Blind in this hand as the Big Blind of the previous hand left the table') re_NoSmallBlind = re.compile('^There is no Small Blind in this hand as the Big Blind of the previous hand left the table')
# self.re_setHandInfoRegex('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[ a-zA-Z]+) - \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) - (?P<GAMETYPE>.*) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+) ET - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+)Table (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, index=0): def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, index=0):
@ -148,14 +117,12 @@ follow : whether to tail -f the input"""
def compilePlayerRegexs(self, hand): def compilePlayerRegexs(self, hand):
players = set([player[1] for player in hand.players]) players = set([player[1] for player in hand.players])
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
# we need to recompile the player regexs.
# TODO: should probably rename re_HeroCards and corresponding method,
# since they are used to find all cards on lines starting with "Dealt to:"
# They still identify the hero.
self.compiledPlayers = players self.compiledPlayers = players
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")" player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
subst = {'PLYR': player_re, 'CUR_SYM': hand.SYMBOL[hand.gametype['currency']], subst = {'PLYR': player_re, 'CUR_SYM': hand.SYMBOL[hand.gametype['currency']],
'CUR': hand.gametype['currency'] if hand.gametype['currency']!='T$' else ''} 'CUR': hand.gametype['currency'] if hand.gametype['currency']!='T$' else ''}
for key in ('CUR_SYM', 'CUR'):
subst[key] = re.escape(subst[key])
logging.debug("player_re: " + subst['PLYR']) logging.debug("player_re: " + subst['PLYR'])
logging.debug("CUR_SYM: " + subst['CUR_SYM']) logging.debug("CUR_SYM: " + subst['CUR_SYM'])
logging.debug("CUR: " + subst['CUR']) logging.debug("CUR: " + subst['CUR'])
@ -168,12 +135,6 @@ follow : whether to tail -f the input"""
self.re_Antes = re.compile( self.re_Antes = re.compile(
r"^%(PLYR)s posts ante \[%(CUR_SYM)s(?P<ANTE>[.0-9]+) ?%(CUR)s\]\." % subst, r"^%(PLYR)s posts ante \[%(CUR_SYM)s(?P<ANTE>[.0-9]+) ?%(CUR)s\]\." % subst,
re.MULTILINE) re.MULTILINE)
#self.re_BringIn = re.compile(
#r"^%(PLYR)s: brings[- ]in( low|) for %(CUR)s(?P<BRINGIN>[.0-9]+)" % subst,
#re.MULTILINE)
#self.re_PostBoth = re.compile(
#r"^%(PLYR)s: posts small \& big blinds \[%(CUR)s (?P<SBBB>[.0-9]+)" % subst,
#re.MULTILINE)
self.re_HeroCards = re.compile( self.re_HeroCards = re.compile(
r"^Dealt to %(PLYR)s \[\s*(?P<NEWCARDS>.+)\s*\]" % subst, r"^Dealt to %(PLYR)s \[\s*(?P<NEWCARDS>.+)\s*\]" % subst,
re.MULTILINE) re.MULTILINE)
@ -190,11 +151,6 @@ follow : whether to tail -f the input"""
r""""^%(PLYR)s \s+ wins \s+ r""""^%(PLYR)s \s+ wins \s+
%(CUR_SYM)s(?P<POT>[.\d]+)\s*%(CUR)s""" % subst, %(CUR_SYM)s(?P<POT>[.\d]+)\s*%(CUR)s""" % subst,
re.MULTILINE|re.VERBOSE) re.MULTILINE|re.VERBOSE)
#self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE)
#self.re_ShownCards = re.compile(
#"^Seat (?P<SEAT>[0-9]+): %s (\(.*\) )?
#(?P<SHOWED>showed|mucked) \[(?P<CARDS>.*)\].*" % player_re,
#re.MULTILINE)
def readSupportedGames(self): def readSupportedGames(self):
return [["ring", "hold", "nl"], return [["ring", "hold", "nl"],
@ -211,8 +167,6 @@ follow : whether to tail -f the input"""
# let's determine whether hand is trny # let's determine whether hand is trny
# and whether 5-th line contains head line # and whether 5-th line contains head line
headLine = handText.split(self.lineSplitter)[4] headLine = handText.split(self.lineSplitter)[4]
#print headLine
#sys.exit(1)
for headLineContainer in headLine, handText: for headLineContainer in headLine, handText:
for regexp in self.re_GameInfoTrny, self.re_GameInfoRing: for regexp in self.re_GameInfoTrny, self.re_GameInfoRing:
m = regexp.search(headLineContainer) m = regexp.search(headLineContainer)
@ -222,18 +176,18 @@ follow : whether to tail -f the input"""
return self._gameType return self._gameType
def determineGameType(self, handText): def determineGameType(self, handText):
# inspect the handText and return the gametype dict """inspect the handText and return the gametype dict
# gametype dict is:
# {'limitType': xxx, 'base': xxx, 'category': xxx} gametype dict is:
{'limitType': xxx, 'base': xxx, 'category': xxx}"""
print self.ParsingException().wrapHh( handText ) logging.debug(self.ParsingException().wrapHh( handText ))
info = {} info = {}
m = self._getGameType(handText) m = self._getGameType(handText)
if m is None: if m is None:
return None return None
mg = m.groupdict() mg = m.groupdict()
# translations from captured groups to fpdb info strings # translations from captured groups to fpdb info strings
limits = { 'NL':'nl', limits = { 'NL':'nl',
@ -273,13 +227,12 @@ follow : whether to tail -f the input"""
if info['type'] == 'ring': if info['type'] == 'ring':
info['sb'], info['bb'] = ringBlinds(mg['RINGLIMIT']) info['sb'], info['bb'] = ringBlinds(mg['RINGLIMIT'])
# FIXME: there are only $ and play money availible for cash # FIXME: there are only $ and play money availible for cash
info['currency'] = currencies(mg['CURRENCY']) info['currency'] = currencies[mg['CURRENCY']]
else: else:
info['sb'] = renderTrnyMoney(mg['SB']) info['sb'] = renderTrnyMoney(mg['SB'])
info['bb'] = renderTrnyMoney(mg['BB']) info['bb'] = renderTrnyMoney(mg['BB'])
info['currency'] = 'T$' info['currency'] = 'T$'
# NB: SB, BB must be interpreted as blinds or bets depending on limit type. # NB: SB, BB must be interpreted as blinds or bets depending on limit type.
return info return info
@ -297,10 +250,9 @@ follow : whether to tail -f the input"""
if m: info.update(m.groupdict()) if m: info.update(m.groupdict())
# FIXME: it's a hack cause party doesn't supply hand.maxseats info # FIXME: it's a hack cause party doesn't supply hand.maxseats info
#hand.maxseats = '9' #hand.maxseats = ???
hand.mixed = None hand.mixed = None
# TODO : I rather like the idea of just having this dict as hand.info
logging.debug("readHandInfo: %s" % info) logging.debug("readHandInfo: %s" % info)
for key in info: for key in info:
if key == 'DATETIME': if key == 'DATETIME':
@ -313,6 +265,7 @@ follow : whether to tail -f the input"""
month = months.index(m2.group('M')) + 1 month = months.index(m2.group('M')) + 1
datetimestr = "%s/%s/%s %s:%s:%s" % (m2.group('Y'), month,m2.group('D'),m2.group('H'),m2.group('MIN'),m2.group('S')) datetimestr = "%s/%s/%s %s:%s:%s" % (m2.group('Y'), month,m2.group('D'),m2.group('H'),m2.group('MIN'),m2.group('S'))
hand.starttime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") hand.starttime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S")
# FIXME: some timezone correction required
#tzShift = defaultdict(lambda:0, {'EDT': -5, 'EST': -6, 'MSKS': 3}) #tzShift = defaultdict(lambda:0, {'EDT': -5, 'EST': -6, 'MSKS': 3})
#hand.starttime -= datetime.timedelta(hours=tzShift[m2.group('TZ')]) #hand.starttime -= datetime.timedelta(hours=tzShift[m2.group('TZ')])
@ -373,13 +326,11 @@ follow : whether to tail -f the input"""
logging.debug("reading antes") logging.debug("reading antes")
m = self.re_Antes.finditer(hand.handText) m = self.re_Antes.finditer(hand.handText)
for player in m: for player in m:
#~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
hand.addAnte(player.group('PNAME'), player.group('ANTE')) hand.addAnte(player.group('PNAME'), player.group('ANTE'))
def readBringIn(self, hand): def readBringIn(self, hand):
m = self.re_BringIn.search(hand.handText,re.DOTALL) m = self.re_BringIn.search(hand.handText,re.DOTALL)
if m: if m:
#~ logging.debug("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN')) hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
def readBlinds(self, hand): def readBlinds(self, hand):
@ -426,15 +377,11 @@ follow : whether to tail -f the input"""
def readHeroCards(self, hand): def readHeroCards(self, hand):
# streets PREFLOP, PREDRAW, and THIRD are special cases beacause # we need to grab hero's cards
# we need to grab hero's cards
for street in ('PREFLOP',): for street in ('PREFLOP',):
if street in hand.streets.keys(): if street in hand.streets.keys():
m = self.re_HeroCards.finditer(hand.streets[street]) m = self.re_HeroCards.finditer(hand.streets[street])
for found in m: for found in m:
# if m == None:
# hand.involved = False
# else:
hand.hero = found.group('PNAME') hand.hero = found.group('PNAME')
newcards = renderCards(found.group('NEWCARDS')) newcards = renderCards(found.group('NEWCARDS'))
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True) hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
@ -445,13 +392,9 @@ follow : whether to tail -f the input"""
for action in m: for action in m:
acts = action.groupdict() acts = action.groupdict()
if action.group('ATYPE') in ('raises','is all-In'): if action.group('ATYPE') in ('raises','is all-In'):
#print action.groupdict()
#sys.exit(1)
hand.addRaiseBy( street, action.group('PNAME'), action.group('BET') ) hand.addRaiseBy( 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') )
#print action.groupdict()
#sys.exit(1)
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': elif action.group('ATYPE') == 'folds':
@ -465,10 +408,6 @@ follow : whether to tail -f the input"""
def readShowdownActions(self, hand): def readShowdownActions(self, hand):
# all action in readShownCards # all action in readShownCards
pass pass
## TODO: pick up mucks also??
#for shows in self.re_ShowdownAction.finditer(hand.handText):
#cards = shows.group('CARDS').split(' ')
#hand.addShownCards(cards, shows.group('PNAME'))
def readCollectPot(self,hand): def readCollectPot(self,hand):
for m in self.re_CollectPot.finditer(hand.handText): for m in self.re_CollectPot.finditer(hand.handText):
@ -503,7 +442,7 @@ def renderCards(string):
if __name__ == "__main__": if __name__ == "__main__":
parser = OptionParser() parser = OptionParser()
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="regression-test-files/stars/horse/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt") parser.add_option("-i", "--input", dest="ipath", help="parse input hand history")
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-") parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False) parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
parser.add_option("-q", "--quiet", parser.add_option("-q", "--quiet",

View File

@ -234,7 +234,7 @@ def discover_nt_by_name(c, tablename):
#print "Tables.py: tablename =", tablename, "title =", titles[hwnd] #print "Tables.py: tablename =", tablename, "title =", titles[hwnd]
try: try:
# this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html
if not tablename in titles[hwnd]: continue if not tablename.lower() in titles[hwnd].lower(): continue
except: except:
continue continue
if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window
@ -302,7 +302,9 @@ def decode_windows(c, title, hwnd):
return info return info
def win_enum_handler(hwnd, titles): def win_enum_handler(hwnd, titles):
titles[hwnd] = win32gui.GetWindowText(hwnd) str = win32gui.GetWindowText(hwnd)
if str != "":
titles[hwnd] = win32gui.GetWindowText(hwnd)
################################################################### ###################################################################
# Utility routines used by all the discoverers. # Utility routines used by all the discoverers.

View File

@ -64,7 +64,7 @@ class fpdb_db:
if backend==fpdb_db.MYSQL_INNODB: if backend==fpdb_db.MYSQL_INNODB:
import MySQLdb import MySQLdb
try: try:
self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True, charset="utf8") self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True)
except: except:
raise fpdb_simple.FpdbError("MySQL connection failed") raise fpdb_simple.FpdbError("MySQL connection failed")
elif backend==fpdb_db.PGSQL: elif backend==fpdb_db.PGSQL:

View File

@ -985,17 +985,17 @@ def recogniseTourneyTypeId(cursor, siteId, buyin, fee, knockout, rebuyOrAddon):
# return result # return result
def recognisePlayerIDs(db, names, site_id): def recognisePlayerIDs(db, names, site_id):
q = "SELECT name,id FROM Players WHERE name=" + " OR name=".join([db.sql.query['placeholder'] for n in names])
c = db.get_cursor() c = db.get_cursor()
q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([db.sql.query['placeholder'] for n in names]))
c.execute(q, names) # get all playerids by the names passed in c.execute(q, names) # get all playerids by the names passed in
ids = dict(c.fetchall()) # convert to dict ids = dict(c.fetchall()) # convert to dict
if len(ids) != len(names): if len(ids) != len(names):
notfound = [n for n in names if n not in ids] # make list of names not in database notfound = [n for n in names if n not in ids] # make list of names not in database
if notfound: # insert them into database if notfound: # insert them into database
#q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")" q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")"
#q_ins = q_ins.replace('%s', db.sql.query['placeholder']) q_ins = q_ins.replace('%s', db.sql.query['placeholder'])
c.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", [(n,) for n in notfound]) c.executemany(q_ins, [(n,) for n in notfound])
q2 = "SELECT name,id FROM Players WHERE name=%s" % " OR name=".join(["%s" for n in notfound]) q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound]))
q2 = q2.replace('%s', db.sql.query['placeholder']) q2 = q2.replace('%s', db.sql.query['placeholder'])
c.execute(q2, notfound) # get their new ids c.execute(q2, notfound) # get their new ids
tmp = c.fetchall() tmp = c.fetchall()