Merge branch 'master' into siteneutral

Conflicts:

	pyfpdb/fpdb_import.py
	pyfpdb/fpdb_parse_logic.py
	pyfpdb/fpdb_simple.py
This commit is contained in:
Worros 2009-03-20 00:27:08 +09:00
commit 444e780f29
14 changed files with 662 additions and 675 deletions

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

@ -32,6 +32,13 @@ import shutil
import xml.dom.minidom
from xml.dom.minidom import Node
def fix_tf(x):
if x == "1" or x == 1 or string.lower(x) == "true" or string.lower(x) == "t":
return True
if x == "0" or x == 0 or string.lower(x) == "false" or string.lower(x) == "f":
return False
return False
class Layout:
def __init__(self, node):
@ -205,9 +212,18 @@ class Import:
self.interval = node.getAttribute("interval")
self.callFpdbHud = node.getAttribute("callFpdbHud")
self.hhArchiveBase = node.getAttribute("hhArchiveBase")
if node.hasAttribute("saveActions"):
self.saveActions = fix_tf(node.getAttribute("saveActions"))
else:
self.saveActions = True
if node.hasAttribute("fastStoreHudCache"):
self.fastStoreHudCache = fix_tf(node.getAttribute("fastStoreHudCache"))
else:
self.fastStoreHudCache = False
def __str__(self):
return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s" % (self.interval, self.callFpdbHud, self.hhArchiveBase)
return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \
% (self.interval, self.callFpdbHud, self.hhArchiveBase, self.saveActions, self.saveActions)
class Tv:
def __init__(self, node):
@ -391,6 +407,11 @@ class Config:
return layout_node
def get_location_node(self, layout_node, seat):
if seat == "common":
for location_node in layout_node.getElementsByTagName("location"):
if location_node.hasAttribute("common"):
return location_node
else:
for location_node in layout_node.getElementsByTagName("location"):
if int( location_node.getAttribute("seat") ) == int( seat ):
return location_node
@ -420,29 +441,42 @@ class Config:
def edit_aux_layout(self, aux_name, max, width = None, height = None, locations = None):
aux_node = self.get_aux_node(aux_name)
layout_node = self.get_layout_node(aux_node, max)
if layout_node == None: return
for i in range(1, max + 1):
if layout_node == None:
print "aux node not found"
return
print "editing locations =", locations
for (i, pos) in locations.iteritems():
location_node = self.get_location_node(layout_node, i)
location_node.setAttribute("x", str( locations[i-1][0] ))
location_node.setAttribute("y", str( locations[i-1][1] ))
self.aux_windows[aux_name].layout[max].location[i] = ( locations[i-1][0], locations[i-1][1] )
location_node.setAttribute("x", str( locations[i][0] ))
location_node.setAttribute("y", str( locations[i][1] ))
if i == "common":
self.aux_windows[aux_name].layout[max].common = ( locations[i][0], locations[i][1] )
else:
self.aux_windows[aux_name].layout[max].location[i] = ( locations[i][0], locations[i][1] )
def get_db_parameters(self, name = None):
if name == None: name = 'fpdb'
db = {}
try:
db['db-databaseName'] = name
db['db-host'] = self.supported_databases[name].db_ip
db['db-user'] = self.supported_databases[name].db_user
db['db-password'] = self.supported_databases[name].db_pass
db['db-server'] = self.supported_databases[name].db_server
try: db['db-databaseName'] = name
except: pass
try: db['db-host'] = self.supported_databases[name].db_ip
except: pass
try: db['db-user'] = self.supported_databases[name].db_user
except: pass
try: db['db-password'] = self.supported_databases[name].db_pass
except: pass
try: db['db-server'] = self.supported_databases[name].db_server
except: pass
if string.lower(self.supported_databases[name].db_server) == 'mysql':
db['db-backend'] = 2
elif string.lower(self.supported_databases[name].db_server) == 'postgresql':
db['db-backend'] = 3
else: db['db-backend'] = None # this is big trouble
except:
pass
return db
def set_db_parameters(self, db_name = 'fpdb', db_ip = None, db_user = None,
@ -464,26 +498,32 @@ class Config:
def get_tv_parameters(self):
tv = {}
try:
tv['combinedStealFold'] = self.tv.combinedStealFold
tv['combined2B3B'] = self.tv.combined2B3B
tv['combinedPostflop'] = self.tv.combinedPostflop
except: # Default tv parameters
tv['combinedStealFold'] = True
tv['combined2B3B'] = True
tv['combinedPostflop'] = True
try: tv['combinedStealFold'] = self.tv.combinedStealFold
except: tv['combinedStealFold'] = True
try: tv['combined2B3B'] = self.tv.combined2B3B
except: tv['combined2B3B'] = True
try: tv['combinedPostflop'] = self.tv.combinedPostflop
except: tv['combinedPostflop'] = True
return tv
def get_import_parameters(self):
imp = {}
try:
imp['callFpdbHud'] = self.imp.callFpdbHud
imp['interval'] = self.imp.interval
imp['hhArchiveBase'] = self.imp.hhArchiveBase
except: # Default params
imp['callFpdbHud'] = True
imp['interval'] = 10
imp['hhArchiveBase'] = "~/.fpdb/HandHistories/"
try: imp['callFpdbHud'] = self.imp.callFpdbHud
except: imp['callFpdbHud'] = True
try: imp['interval'] = self.imp.interval
except: imp['interval'] = 10
try: imp['hhArchiveBase'] = self.imp.hhArchiveBase
except: imp['hhArchiveBase'] = "~/.fpdb/HandHistories/"
try: imp['saveActions'] = self.imp.saveActions
except: imp['saveActions'] = True
try: imp['fastStoreHudCache'] = self.imp.fastStoreHudCache
except: imp['fastStoreHudCache'] = True
return imp
def get_default_paths(self, site = "PokerStars"):
@ -689,9 +729,9 @@ if __name__== "__main__":
print c.get_aux_parameters(mw)
print "mucked locations =", c.get_aux_locations('mucked', 9)
c.edit_aux_layout('mucked', 9, locations = [(487, 113), (555, 469), (572, 276), (522, 345),
(333, 354), (217, 341), (150, 273), (150, 169), (230, 115)])
print "mucked locations =", c.get_aux_locations('mucked', 9)
# c.edit_aux_layout('mucked', 9, locations = [(487, 113), (555, 469), (572, 276), (522, 345),
# (333, 354), (217, 341), (150, 273), (150, 169), (230, 115)])
# print "mucked locations =", c.get_aux_locations('mucked', 9)
for site in c.supported_sites.keys():
print "site = ", site,

View File

@ -213,7 +213,7 @@ if __name__ == '__main__':
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename", help="Input file in quiet mode", metavar="FILE")
parser.add_option("-q", "--quiet", action="store_false", dest="gui", default=True, help="don't start gui")
parser.add_option("-x", "--convert", dest="filtername", help="Conversion filter", default="passthrough")
(options, sys.argv) = parser.parse_args()
config = Configuration.Config()
@ -240,7 +240,7 @@ if __name__ == '__main__':
importer = fpdb_import.Importer(False,settings, config)
importer.setDropIndexes("auto")
importer.setFailOnError(True)
importer.addImportFile(options.filename)
importer.addImportFile(options.filename, filter=options.filtername)
importer.setCallHud(False)
importer.runImport()
importer.clearFileList()

View File

@ -123,7 +123,7 @@ class HUD_main(object):
gtk.gdk.threads_enter()
try:
self.hud_dict[table_name].update(new_hand_id, config)
map(lambda aw: aw.update_gui(new_hand_id), self.hud_dict[table_name].aux_windows)
[aw.update_gui(new_hand_id) for aw in self.hud_dict[table_name].aux_windows]
return False
finally:
gtk.gdk.threads_leave()
@ -172,8 +172,7 @@ class HUD_main(object):
if temp_key in self.hud_dict:
self.hud_dict[temp_key].stat_dict = stat_dict
self.hud_dict[temp_key].cards = cards
for aw in self.hud_dict[temp_key].aux_windows:
aw.update_data(new_hand_id, self.db_connection)
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows]
self.update_HUD(new_hand_id, temp_key, self.config)
# Or create a new HUD

View File

@ -504,6 +504,14 @@ Card ranks will be uppercased
if self.shown:
print >>fh, _("*** SHOW DOWN ***")
for name in self.shown:
# TODO: legacy importer can't handle only one holecard here, make sure there are 2 for holdem, 4 for omaha
# TOOD: If HoldHand subclass supports more than omahahi, omahahilo, holdem, add them here
numOfHoleCardsNeeded = None
if self.gametype['category'] in ('omahahi','omahahilo'):
numOfHoleCardsNeeded = 4
elif self.gametype['category'] in ('holdem'):
numOfHoleCardsNeeded = 2
if len(self.holecards[name]['PREFLOP']) == numOfHoleCardsNeeded:
print >>fh, _("%s shows [%s] (a hand...)" % (name, " ".join(self.holecards[name]['PREFLOP'])))
# Current PS format has the lines:

View File

@ -196,12 +196,12 @@ class Hud:
s.window.destroy()
self.stat_windows = {}
# also kill any aux windows
map(lambda m: m.destroy(), self.aux_windows)
[aux.destroy() for aux in self.aux_windows]
self.aux_windows = []
def reposition_windows(self, *args):
if self.stat_windows and len(self.stat_windows > 0):
map(lambda x: x.window.move(x.x, x.y), self.stat_windows)
if self.stat_windows != {} and len(self.stat_windows) > 0:
map(lambda x: x.window.move(x.x, x.y), self.stat_windows.itervalues())
return True
def debug_stat_windows(self, *args):
@ -216,6 +216,10 @@ class Hud:
new_loc = (loc[0] - self.table.x, loc[1] - self.table.y)
new_layout[self.stat_windows[sw].adj - 1] = new_loc
self.config.edit_layout(self.table.site, self.max, locations = new_layout)
# ask each aux to save its layout back to the config object
[aux.save_layout() for aux in self.aux_windows]
# save the config object back to the file
print "saving new xml file"
self.config.save()
def adj_seats(self, hand, config):
@ -346,6 +350,8 @@ class Hud:
style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE)
style |= win32con.WS_CLIPCHILDREN
win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style)
break
window.set_title(real_name)
class Stat_Window:
@ -570,6 +576,7 @@ class Popup_window:
style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE)
style |= win32con.WS_CLIPCHILDREN
win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style)
break
window.set_title(real_name)

View File

@ -49,6 +49,9 @@ class Aux_Window:
def create(self, *parms):
pass
def save_layout(self, *args):
pass
def destroy(self):
self.container.destroy()
@ -312,12 +315,13 @@ class Flop_Mucked(Aux_Window):
def __init__(self, hud, config, params):
self.hud = hud # hud object that this aux window supports
self.config = config # configuration object for this aux window to use
self.params = params # hash aux params from config
self.params = params # dict aux params from config
self.positions = {} # dict of window positions
self.displayed_cards = False
self.card_images = self.get_card_images()
def create(self):
adj = self.hud.adj_seats(0, self.config)
self.adj = self.hud.adj_seats(0, self.config)
loc = self.config.get_aux_locations(self.params['name'], int(self.hud.max))
self.m_windows = {} # windows to put the card images in
@ -328,7 +332,7 @@ class Flop_Mucked(Aux_Window):
if i == 'common':
(x, y) = self.params['layout'][self.hud.max].common
else:
(x, y) = loc[adj[i]]
(x, y) = loc[self.adj[i]]
self.m_windows[i] = gtk.Window()
self.m_windows[i].set_decorated(False)
self.m_windows[i].set_property("skip-taskbar-hint", True)
@ -340,6 +344,7 @@ class Flop_Mucked(Aux_Window):
self.seen_cards[i] = gtk.image_new_from_pixbuf(self.card_images[('B', 'H')])
self.eb[i].add(self.seen_cards[i])
self.m_windows[i].move(int(x) + self.hud.table.x, int(y) + self.hud.table.y)
self.positions[i] = (int(x) + self.hud.table.x, int(y) + self.hud.table.y)
self.m_windows[i].set_opacity(float(self.params['opacity']))
self.m_windows[i].show_all()
self.m_windows[i].hide()
@ -350,11 +355,9 @@ class Flop_Mucked(Aux_Window):
def update_gui(self, new_hand_id):
"""Prepare and show the mucked cards."""
pos = {}
for i, w in self.m_windows.iteritems():
pos[i] = w.get_position() # I hate this. I don't know why I have to save position and then move back
if self.displayed_cards:
self.hide_mucked_cards()
displayed_cards = False
self.displayed_cards = False
for (i, cards) in self.hud.cards.iteritems():
if self.has_cards(cards):
# scratch is a working pixbuf, used to assemble the image
@ -370,11 +373,12 @@ class Flop_Mucked(Aux_Window):
x = x + int(self.params['card_wd'])
self.seen_cards[i].set_from_pixbuf(scratch)
# self.m_windows[i].show_all()
self.m_windows[i].move(pos[i][0], pos[i][1]) # here is where I move back
self.m_windows[i].resize(1,1)
self.m_windows[i].present()
displayed_cards = True
self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) # here is where I move back
self.displayed_cards = True
if displayed_cards and float(self.params['timeout']) > 0:
if self.displayed_cards and float(self.params['timeout']) > 0:
gobject.timeout_add(int(1000*float(self.params['timeout'])), self.hide_mucked_cards)
def destroy(self):
@ -385,8 +389,10 @@ class Flop_Mucked(Aux_Window):
def hide_mucked_cards(self):
"""Hide the mucked card windows."""
# this is the callback from the timeout
for w in self.m_windows.values():
for (i, w) in self.m_windows.iteritems():
self.positions[i] = w.get_position()
w.hide()
self.displayed_cards = False
return False # this tells the system to NOT run this timeout again
def button_press_cb(self, widget, event, *args):
@ -403,17 +409,16 @@ class Flop_Mucked(Aux_Window):
def save_layout(self, *args):
"""Save new layout back to the aux element in the config file."""
# similar to same method in stat_windows
new_layout = [(0, 0)] * self.hud.max
for (i, w) in self.m_windows.iteritems():
(x, y) = w.get_position()
new_loc = (x - self.hud.table.x, y - self.hud.table.y)
if i != "common":
new_layout[self.hud.stat_windows[int(i)].adj - 1] = new_loc
new_locs = {}
print "adj =", self.adj
for (i, pos) in self.positions.iteritems():
if i != 'common':
new_locs[self.adj[int(i)]] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y)
else:
pass
self.config.edit_layout(self.table.site, self.max, locations = new_layout)
self.config.save()
new_locs[i] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y)
print "old locations =", self.params['layout'][self.hud.max]
print "saving locations =", new_locs
self.config.edit_aux_layout(self.params['name'], self.hud.max, locations = new_locs)
if __name__== "__main__":

View File

@ -26,7 +26,7 @@ from HandHistoryConverter import *
class PokerStars(HandHistoryConverter):
# Static regexes
re_GameInfo = re.compile("PokerStars Game #(?P<HID>[0-9]+):\s+(HORSE)? \(?(?P<GAME>Hold\'em|Razz|7 Card Stud|Omaha Hi/Lo|Badugi) (?P<LIMIT>No Limit|Limit|Pot Limit),? \(?(?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\) - (?P<DATETIME>.*$)", re.MULTILINE)
re_GameInfo = re.compile("PokerStars Game #(?P<HID>[0-9]+):\s+(HORSE)? \(?(?P<GAME>Hold\'em|Razz|7 Card Stud|Omaha|Omaha Hi/Lo|Badugi) (?P<LIMIT>No Limit|Limit|Pot Limit),? \(?(?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\) - (?P<DATETIME>.*$)", re.MULTILINE)
re_SplitHands = re.compile('\n\n+')
re_HandInfo = re.compile("^Table \'(?P<TABLE>[- a-zA-Z]+)\'(?P<TABLEATTRIBUTES>.+?$)?", re.MULTILINE)
re_Button = re.compile('Seat #(?P<BUTTON>\d+) is the button', re.MULTILINE)
@ -89,7 +89,7 @@ follow : whether to tail -f the input"""
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' }
games = { # base, category
"Hold'em" : ('hold','holdem'),
'Omaha Hi' : ('hold','omahahi'),
'Omaha' : ('hold','omahahi'),
'Omaha Hi/Lo' : ('hold','omahahilo'),
'Razz' : ('stud','razz'),
'7 Card Stud' : ('stud','studhi'),

View File

@ -82,20 +82,10 @@ class fpdb:
"""displays the indicated tab"""
#print "start of display_tab, len(self.tab_names):",len(self.tab_names)
tab_no = -1
#if len(self.tab_names)>1:
for i in range(len(self.tab_names)):
#print "display_tab, new_tab_name:",new_tab_name," self.tab_names[i]:", self.tab_names[i]
if (new_tab_name==self.tab_names[i]):
for i, name in enumerate(self.tab_names):
if name == new_tab_name:
tab_no = i
#self.tab_buttons[i].set_active(False)
#else:
# tab_no=0
#current_tab_no=-1
for i in range(len(self.tab_names)):
if self.current_tab==self.tabs[i]:
#self.tab_buttons[i].set_active(False)
pass
break
if tab_no == -1:
raise fpdb_simple.FpdbError("invalid tab_no")
@ -199,9 +189,10 @@ class fpdb:
def dia_recreate_tables(self, widget, data):
"""Dialogue that asks user to confirm that he wants to delete and recreate the tables"""
self.obtain_global_lock()
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING,
buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables")
diastring=("Please confirm that you want to (re-)create the tables. If there already are tables in the database "+self.db.database+" on "+self.db.host+" they will be deleted.")
diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database "+self.db.database+" on "+self.db.host+" they will be deleted."
dia_confirm.format_secondary_text(diastring)#todo: make above string with bold for db, host and deleted
response = dia_confirm.run()

View File

@ -37,10 +37,7 @@ class fpdb_db:
raise FpdbError('Configuration not defined')
self.settings = {}
if (os.sep=="/"):
self.settings['os']="linuxmac"
else:
self.settings['os']="windows"
self.settings['os'] = "linuxmac" if os.name != "nt" else "windows"
self.settings.update(config.get_db_parameters())
self.connect(self.settings['db-backend'],

View File

@ -188,6 +188,7 @@ class Importer:
self.addImportDirectory(self.dirlist[site][0], False, site, self.dirlist[site][1])
for file in self.filelist:
if os.path.exists(file):
stat_info = os.stat(file)
try:
lastupdate = self.updated[file]
@ -205,7 +206,8 @@ class Importer:
# TODO we also test if directory, why?
#if os.path.isdir(file):
#self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1])
else:
removeFromFileList[file] = True
self.addToDirList = filter(lambda x: self.addImportDirectory(x, True, self.addToDirList[x][0], self.addToDirList[x][1]), self.addToDirList)
for file in self.removeFromFileList:
@ -251,7 +253,6 @@ class Importer:
print "Unknown filter filter_name:'%s' in filter:'%s'" %(filter_name, filter)
return
#This will barf if conv.getStatus != True
return (stored, duplicates, partial, errors, ttime)
@ -284,7 +285,13 @@ class Importer:
print "DEBUG: import_fpdb_file: failed on self.lines[0]: '%s' '%s' '%s' '%s' " %( file, site, self.lines, loc)
return (0,0,0,1,0)
# site=fpdb_simple.recogniseSite(firstline)
if firstline.find("Tournament Summary")!=-1:
print "TODO: implement importing tournament summaries"
#self.faobs = readfile(inputFile)
#self.parseTourneyHistory()
return 0
site=fpdb_simple.recogniseSite(firstline)
category=fpdb_simple.recogniseCategory(firstline)
startpos=0
@ -315,7 +322,7 @@ class Importer:
try:
handsId=fpdb_parse_logic.mainParser(self.settings['db-backend'], self.fdb.db
,self.fdb.cursor, category, hand)
,self.fdb.cursor, site, category, hand, self.config)
self.fdb.db.commit()
stored+=1

View File

@ -21,12 +21,11 @@ import fpdb_simple
import fpdb_save_to_db
#parses a holdem hand
def mainParser(backend, db, cursor, category, hand):
def mainParser(backend, db, cursor, category, hand, config):
category = fpdb_simple.recogniseCategory(hand[0])
if (category=="holdem" or category=="omahahi" or category=="omahahilo"):
base="hold"
else:
base="stud"
base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud"
#part 0: create the empty arrays
lineTypes = [] #char, valid values: header, name, cards, action, win, rake, ignore
lineStreets = [] #char, valid values: (predeal, preflop, flop, turn, river)
@ -41,14 +40,13 @@ def mainParser(backend, db, cursor, category, hand):
isTourney = fpdb_simple.isTourney(hand[0])
smallBlindLine = 0
for i in range(len(hand)):
if 'posts small blind' in hand[i] or 'posts the small blind' in hand[i]:
if hand[i][-2:] == "$0":
continue
for i, line in enumerate(hand):
if 'posts small blind' in line or 'posts the small blind' in line:
if line[-2:] == "$0": continue
smallBlindLine = i
#print "found small blind line:",smallBlindLine
break
#print "small blind line:",smallBlindLine
gametypeID = fpdb_simple.recogniseGametypeID(backend, db, cursor, hand[0], hand[smallBlindLine], siteID, category, isTourney)
if isTourney:
siteTourneyNo = fpdb_simple.parseTourneyNo(hand[0])
@ -61,6 +59,7 @@ def mainParser(backend, db, cursor, category, hand):
rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0])
tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(cursor, siteID, buyin, fee, knockout, rebuyOrAddon)
fpdb_simple.isAlreadyInDB(cursor, gametypeID, siteHandNo)
#part 2: classify lines by type (e.g. cards, action, win, sectionchange) and street
@ -68,9 +67,10 @@ def mainParser(backend, db, cursor, category, hand):
#part 3: read basic player info
#3a read player names, startcashes
for i in range (len(hand)): #todo: use maxseats+1 here.
if (lineTypes[i]=="name"):
seatLines.append(hand[i])
for i, line in enumerate(hand):
if lineTypes[i] == "name":
seatLines.append(line)
names = fpdb_simple.parseNames(seatLines)
playerIDs = fpdb_simple.recognisePlayerIDs(cursor, names, siteID)
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines)
@ -84,31 +84,29 @@ def mainParser(backend, db, cursor, category, hand):
positions = fpdb_simple.parsePositions(hand, names)
#part 4: take appropriate action for each line based on linetype
for i in range(len(hand)):
if (lineTypes[i]=="cards"):
fpdb_simple.parseCardLine (category, lineStreets[i], hand[i], names, cardValues, cardSuits, boardValues, boardSuits)
for i, line in enumerate(hand):
if lineTypes[i] == "cards":
fpdb_simple.parseCardLine(category, lineStreets[i], line, names, cardValues, cardSuits, boardValues, boardSuits)
#if category=="studhilo":
# print "hand[i]:", hand[i]
# print "cardValues:", cardValues
# print "cardSuits:", cardSuits
elif (lineTypes[i]=="action"):
fpdb_simple.parseActionLine (base, isTourney, hand[i], lineStreets[i], playerIDs, names, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo)
elif (lineTypes[i]=="win"):
fpdb_simple.parseWinLine (hand[i], names, winnings, isTourney)
elif (lineTypes[i]=="rake"):
if isTourney:
totalRake=0
else:
totalRake=fpdb_simple.parseRake(hand[i])
elif lineTypes[i] == "action":
fpdb_simple.parseActionLine(base, isTourney, line, lineStreets[i], playerIDs, names, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo)
elif lineTypes[i] == "win":
fpdb_simple.parseWinLine(line, names, winnings, isTourney)
elif lineTypes[i] == "rake":
totalRake = 0 if isTourney else fpdb_simple.parseRake(line)
fpdb_simple.splitRake(winnings, rakes, totalRake)
elif (lineTypes[i]=="header" or lineTypes[i]=="rake" or lineTypes[i]=="name" or lineTypes[i]=="ignore"):
elif lineTypes[i]=="header" or lineTypes[i]=="rake" or lineTypes[i]=="name" or lineTypes[i]=="ignore":
pass
elif (lineTypes[i]=="ante"):
fpdb_simple.parseAnteLine(hand[i], isTourney, names, antes)
elif (lineTypes[i]=="table"):
tableResult=fpdb_simple.parseTableLine(base, hand[i])
elif lineTypes[i]=="ante":
fpdb_simple.parseAnteLine(line, isTourney, names, antes)
elif lineTypes[i]=="table":
tableResult=fpdb_simple.parseTableLine(base, line)
else:
raise fpdb_simple.FpdbError("unrecognised lineType:"+lineTypes[i])
maxSeats = tableResult['maxSeats']
tableName = tableResult['tableName']
#print "before part5, antes:", antes
@ -125,10 +123,9 @@ def mainParser(backend, db, cursor, category, hand):
limit_type = cursor.fetchone()[0]
fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts)
totalWinnings=0
for i in range(len(winnings)):
totalWinnings+=winnings[i]
totalWinnings = sum(winnings)
# if hold'em, use positions and not antes, if stud do not use positions, use antes
if base == "hold":
hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes
, allIns, actionTypeByNo, winnings, totalWinnings, positions
@ -139,14 +136,12 @@ def mainParser(backend, db, cursor, category, hand):
, actionTypes, actionAmounts, antes)
if isTourney:
ranks=[]
for i in range (len(names)):
ranks.append(0)
ranks = map(lambda x: 0, names) # create an array of 0's equal to the length of names
payin_amounts = fpdb_simple.calcPayin(len(names), buyin, fee)
if base == "hold":
result = fpdb_save_to_db.tourney_holdem_omaha(
backend, db, cursor, base, category, siteTourneyNo, buyin
config, backend, db, cursor, base, category, siteTourneyNo, buyin
, fee, knockout, entries, prizepool, tourneyStartTime
, payin_amounts, ranks, tourneyTypeId, siteID, siteHandNo
, gametypeID, handStartTime, names, playerIDs, startCashes
@ -155,7 +150,7 @@ def mainParser(backend, db, cursor, category, hand):
, actionNos, hudImportData, maxSeats, tableName, seatNos)
elif base == "stud":
result = fpdb_save_to_db.tourney_stud(
backend, db, cursor, base, category, siteTourneyNo
config, backend, db, cursor, base, category, siteTourneyNo
, buyin, fee, knockout, entries, prizepool, tourneyStartTime
, payin_amounts, ranks, tourneyTypeId, siteID, siteHandNo
, gametypeID, handStartTime, names, playerIDs, startCashes
@ -167,7 +162,7 @@ def mainParser(backend, db, cursor, category, hand):
else:
if base == "hold":
result = fpdb_save_to_db.ring_holdem_omaha(
backend, db, cursor, base, category, siteHandNo
config, backend, db, cursor, base, category, siteHandNo
, gametypeID, handStartTime, names, playerIDs
, startCashes, positions, cardValues, cardSuits
, boardValues, boardSuits, winnings, rakes
@ -175,7 +170,7 @@ def mainParser(backend, db, cursor, category, hand):
, hudImportData, maxSeats, tableName, seatNos)
elif base == "stud":
result = fpdb_save_to_db.ring_stud(
backend, db, cursor, base, category, siteHandNo, gametypeID
config, backend, db, cursor, base, category, siteHandNo, gametypeID
, handStartTime, names, playerIDs, startCashes, antes
, cardValues, cardSuits, winnings, rakes, actionTypes, allIns
, actionAmounts, actionNos, hudImportData, maxSeats, tableName

View File

@ -26,18 +26,24 @@ MYSQL_INNODB=2
PGSQL = 3
SQLITE = 4
fastStoreHudCache=False # set this to True to test the new storeHudCache routine
fastStoreHudCache = True # set this to True to test the new storeHudCache routine
saveActions=True # set this to False to avoid storing action data
saveActions = False # set this to False to avoid storing action data
# Pros: speeds up imports
# Cons: no action data is saved, so you need to keep the hand histories
# variance not available on stats page
#stores a stud/razz hand into the database
def ring_stud(backend, db, cursor, base, category, site_hand_no, gametype_id, hand_start_time
def ring_stud(config, 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):
import_options = config.get_import_parameters()
saveActions = True if import_options['saveActions'] == 'True' else False
fastStoreHudCache = True if import_options['fastStoreHudCache'] == 'True' else False
fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits)
hands_id = fpdb_simple.storeHands(backend, db, cursor, site_hand_no, gametype_id
@ -56,11 +62,16 @@ def ring_stud(backend, db, cursor, base, category, site_hand_no, gametype_id, ha
return hands_id
#end def ring_stud
def ring_holdem_omaha(backend, db, cursor, base, category, site_hand_no, gametype_id
def ring_holdem_omaha(config, 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"""
import_options = config.get_import_parameters()
saveActions = True if import_options['saveActions'] == 'True' else False
fastStoreHudCache = True if import_options['fastStoreHudCache'] == 'True' else False
t0 = time()
fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits)
t1 = time()
@ -89,7 +100,7 @@ def ring_holdem_omaha(backend, db, cursor, base, category, site_hand_no, gametyp
return hands_id
#end def ring_holdem_omaha
def tourney_holdem_omaha(backend, db, cursor, base, category, siteTourneyNo, buyin, fee, knockout
def tourney_holdem_omaha(config, 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
@ -97,6 +108,11 @@ def tourney_holdem_omaha(backend, db, cursor, base, category, siteTourneyNo, buy
,board_suits, winnings, rakes, action_types, allIns, action_amounts
,actionNos, hudImportData, maxSeats, tableName, seatNos):
"""stores a tourney holdem/omaha hand into the database"""
import_options = config.get_import_parameters()
saveActions = True if import_options['saveActions'] == 'True' else False
fastStoreHudCache = True if import_options['fastStoreHudCache'] == 'True' else False
fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits)
fpdb_simple.fill_board_cards(board_values, board_suits)
@ -123,12 +139,17 @@ def tourney_holdem_omaha(backend, db, cursor, base, category, siteTourneyNo, buy
return hands_id
#end def tourney_holdem_omaha
def tourney_stud(backend, db, cursor, base, category, siteTourneyNo, buyin, fee, knockout, entries
def tourney_stud(config, 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
import_options = config.get_import_parameters()
saveActions = True if import_options['saveActions'] == 'True' else False
fastStoreHudCache = True if import_options['fastStoreHudCache'] == 'True' else False
fpdb_simple.fillCardArrays(len(names), base, category, cardValues, cardSuits)
tourney_id = fpdb_simple.store_tourneys(cursor, tourneyTypeId, siteTourneyNo, entries, prizepool, tourneyStartTime)

View File

@ -18,14 +18,17 @@
#This file contains simple functions for fpdb
import datetime
import time
import re
PS = 1
FTP = 2
# TODO: these constants are also used in fpdb_save_to_db and others, is there a way to do like C #define, and #include ?
MYSQL_INNODB = 2
PGSQL = 3
SQLITE = 4
# Data Structures for index and foreign key creation
# drop_code is an int with possible values: 0 - don't drop for bulk import
# 1 - drop during bulk import
@ -156,6 +159,7 @@ def prepareBulkImport(fdb):
except:
pass
elif fdb.backend == PGSQL:
# DON'T FORGET TO RECREATE THEM!!
print "dropping pg fk", fk['fktab'], fk['fkcol']
try:
fdb.cursor.execute("alter table " + fk['fktab'] + " drop constraint "
@ -175,10 +179,14 @@ def prepareBulkImport(fdb):
except:
pass
elif fdb.backend == PGSQL:
# DON'T FORGET TO RECREATE THEM!!
print "Index dropping disabled for postgresql."
print "dropping pg index ", idx['tab'], idx['col']
# mod to use tab_col for index name?
try:
print "drop index %s_%s_idx" % (idx['tab'],idx['col'])
fdb.cursor.execute( "drop index %s_%s_idx" % (idx['tab'],idx['col']) )
print "dropped pg index ", idx['tab'], idx['col']
except:
pass
else:
@ -241,6 +249,7 @@ def afterBulkImport(fdb):
except:
pass
elif fdb.backend == PGSQL:
# pass
# mod to use tab_col for index name?
print "creating pg index ", idx['tab'], idx['col']
try:
@ -380,20 +389,13 @@ def calcPayin(count, buyin, fee):
#end def calcPayin
def checkPositions(positions):
"""verifies that these positions are valid"""
for i in xrange(len(positions)):
pos=positions[i]
try:#todo: use type recognition instead of error
if (len(pos)!=1):
raise FpdbError("invalid position found in checkPositions. i: "+str(i)+" position: "+pos) #dont need to str() here
except TypeError:#->not string->is int->fine
pass
""" verify positions are valid """
for p in positions:
if not (p == "B" or p == "S" or (p >= 0 and p <= 9)):
raise FpdbError("invalid position '" + p + "' found in checkPositions")
### 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)):
raise FpdbError("invalid position found in checkPositions. i: "+str(i)+" position: "+str(pos))
#end def fpdb_simple.checkPositions
#classifies each line for further processing in later code. Manipulates the passed arrays.
def classifyLines(hand, category, lineTypes, lineStreets):
@ -409,20 +411,14 @@ def classifyLines(hand, category, lineTypes, lineStreets):
lineTypes.append("cards")
elif i == 0:
lineTypes.append("header")
elif line.startswith("Table '"):
lineTypes.append("table")
elif line.startswith("Seat ") and ( ("in chips" in line) or "($" in line):
lineTypes.append("name")
elif isActionLine(line):
lineTypes.append("action")
if " posts " in line or " posts the " in line:
currentStreet="preflop"
elif isWinLine(line):
lineTypes.append("win")
elif line.startswith("Total pot ") and "Rake" in line:
lineTypes.append("rake")
done=True
elif "*** SHOW DOWN ***" in line or "*** SUMMARY ***" in line:
lineTypes.append("ignore")
#print "in classifyLine, showdown or summary"
elif " antes " in line or " posts the ante " in line:
lineTypes.append("ante")
elif line.startswith("*** FLOP *** ["):
@ -449,10 +445,16 @@ def classifyLines(hand, category, lineTypes, lineStreets):
elif line.startswith("*** 7") or line == "*** RIVER ***":
lineTypes.append("ignore")
currentStreet=4
elif isWinLine(line):
lineTypes.append("win")
elif line.startswith("Total pot ") and "Rake" in line:
lineTypes.append("rake")
done=True
elif "*** SHOW DOWN ***" in line or "*** SUMMARY ***" in line:
lineTypes.append("ignore")
#print "in classifyLine, showdown or summary"
elif " shows [" in line:
lineTypes.append("cards")
elif line.startswith("Table '"):
lineTypes.append("table")
else:
raise FpdbError("unrecognised linetype in:"+hand[i])
lineStreets.append(currentStreet)
@ -508,68 +510,45 @@ def convertCardValues(arr):
map(convertCardValuesBoard, arr)
#end def convertCardValues
card_map = { "2": 2, "3" : 3, "4" : 4, "5" : 5, "6" : 6, "7" : 7, "8" : 8, "9" : 9, "T" : 10, "J" : 11, "Q" : 12, "K" : 13, "A" : 14}
#converts the strings in the given array to ints (changes the passed array, no returning). see table design for conversion details
def convertCardValuesBoard(arr):
for i in xrange(len(arr)):
if (arr[i]=="A"):
arr[i]=14
elif (arr[i]=="K"):
arr[i]=13
elif (arr[i]=="Q"):
arr[i]=12
elif (arr[i]=="J"):
arr[i]=11
elif (arr[i]=="T"):
arr[i]=10
else:
arr[i]=int(arr[i])
arr[i] = card_map[arr[i]]
#end def convertCardValuesBoard
#this creates the 2D/3D arrays. manipulates the passed arrays instead of returning.
def createArrays(category, seats, card_values, card_suits, antes, winnings, rakes, action_types, allIns, action_amounts, actionNos, actionTypeByNo):
for i in xrange(seats):#create second dimension arrays
tmp=[]
card_values.append(tmp)
tmp=[]
card_suits.append(tmp)
card_values.append( [] )
card_suits.append( [] )
antes.append(0)
winnings.append(0)
rakes.append(0)
if (category=="holdem" or category=="omahahi" or category=="omahahilo"):
streetCount=4
else:
streetCount=5
streetCount = 4 if category == "holdem" or category == "omahahi" or category == "omahahilo" else 5
for i in xrange(streetCount): #build the first dimension array, for streets
tmp=[]
action_types.append(tmp)
tmp=[]
allIns.append(tmp)
tmp=[]
action_amounts.append(tmp)
tmp=[]
actionNos.append(tmp)
tmp=[]
actionTypeByNo.append(tmp)
action_types.append([])
allIns.append([])
action_amounts.append([])
actionNos.append([])
actionTypeByNo.append([])
for j in xrange (seats): #second dimension arrays: players
tmp=[]
action_types[i].append(tmp)
tmp=[]
allIns[i].append(tmp)
tmp=[]
action_amounts[i].append(tmp)
tmp=[]
actionNos[i].append(tmp)
if (category=="holdem" or category=="omahahi" or category=="omahahilo"):
pass
elif (category=="razz" or category=="studhi" or category=="studhilo"):#need to fill card arrays.
action_types[i].append([])
allIns[i].append([])
action_amounts[i].append([])
actionNos[i].append([])
# if (category=="holdem" or category=="omahahi" or category=="omahahilo"):
# pass
if category=="razz" or category=="studhi" or category=="studhilo":#need to fill card arrays.
for i in xrange(seats):
for j in xrange(7):
card_values[i].append(0)
card_suits[i].append("x")
else:
raise FpdbError("invalid category")
# else:
# raise FpdbError("invalid category")
#end def createArrays
def fill_board_cards(board_values, board_suits):
@ -603,132 +582,128 @@ def filterAnteBlindFold(hand):
#todo: in tourneys this should not be removed but
#print "start of filterAnteBlindFold"
pre3rd=[]
for i in xrange (len(hand)):
if (hand[i].startswith("*** 3") or hand[i].startswith("*** HOLE")):
for i, line in enumerate(hand):
if line.startswith("*** 3") or line.startswith("*** HOLE"):
pre3rd = hand[0:i]
foldeeName=None
for i in xrange (len(pre3rd)):
if (pre3rd[i].endswith("folds") or pre3rd[i].endswith("is sitting out") or pre3rd[i].endswith(" stands up")): #found ante fold or timeout
pos=pre3rd[i].find (" folds")
foldeeName=pre3rd[i][0:pos]
if pos == -1 and pre3rd[i].find(" in chips)")==-1:
pos=pre3rd[i].find (" is sitting out")
foldeeName=pre3rd[i][0:pos]
for line in pre3rd:
if line.endswith("folds") or line.endswith("is sitting out") or line.endswith(" stands up"): #found ante fold or timeout
pos = line.find(" folds")
foldeeName = line[0:pos]
if pos == -1 and " in chips)" not in line:
pos = line.find(" is sitting out")
foldeeName = line[0:pos]
if pos == -1:
pos=pre3rd[i].find (" stands up")
foldeeName=pre3rd[i][0:pos]
if pos==-1:#this one is for PS tourney
pos1=pre3rd[i].find (": ")+2
pos2=pre3rd[i].find (" (")
foldeeName=pre3rd[i][pos1:pos2]
pos = line.find(" stands up")
foldeeName = line[0:pos]
if pos == -1:
pos1 = line.find(": ") + 2
pos2 = line.find(" (")
foldeeName = line[pos1:pos2]
if foldeeName!=None:
#print "filterAnteBlindFold, foldeeName:",foldeeName
toRemove=[]
for i in xrange(len(hand)): #using hand again to filter from all streets, just in case.
#todo: this will break it if sittin out BB wins a hand
if (hand[i].find(foldeeName)!=-1):
toRemove.append(hand[i])
for i, line in enumerate(hand):
if foldeeName in line:
hand[i] = None
for i in xrange(len(toRemove)):
hand.remove(toRemove[i])
hand = [line for line in hand if line]
#end def filterAnteFold
def stripEOLspaces(str):
if str[-1] == ' ':
str = str[:-1]
if str[-1] == ' ':
str = str[:-1]
return str
#removes useless lines as well as trailing spaces
def filterCrap(hand, isTourney):
#remove two trailing spaces at end of line
for i in xrange (len(hand)):
if (hand[i][-1]==' '):
hand[i]=hand[i][:-1]
if (hand[i][-1]==' '):
hand[i]=hand[i][:-1]
hand = [stripEOLspaces(line) for line in hand]
#print "hand after trailing space removal in filterCrap:",hand
#general variable position word filter/string filter
toRemove=[]
for i in xrange (len(hand)):
if (hand[i].startswith("Board [")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].find(" out of hand ")!=-1):
hand[i]=hand[i][:-56]
elif (hand[i].find("($0 in chips)") != -1):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i]=="*** HOLE CARDS ***"):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("has been disconnected")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("has requested TIME")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("has returned")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("will be allowed to play after the button")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("has timed out")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("has timed out while disconnected")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("has timed out while being disconnected")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("is connected")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("is disconnected")):
toRemove.append(hand[i])
elif (hand[i].find(" is low with [")!=-1):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith(" mucks")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith(": mucks hand")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i]=="No low hand qualified"):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i]=="Pair on board - a double bet is allowed"):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].find(" shows ")!=-1 and hand[i].find("[")==-1):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].startswith("The button is in seat #")):
toRemove.append(hand[i])
hand[i] = False
#above is alphabetic, reorder below if bored
elif (hand[i].startswith("Time has expired")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("has reconnected")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("seconds left to act")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("seconds to reconnect")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("was removed from the table for failing to post")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].find("joins the table at seat ")!=-1):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("leaves the table")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].find("is high with ")!=-1):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("doesn't show hand")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith("is being treated as all-in")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].find(" adds $")!=-1):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i]=="Betting is capped"):
toRemove.append(hand[i])
hand[i] = False
#site specific variable position filter
elif (hand[i].find(" said, \"")!=-1):
toRemove.append(hand[i])
hand[i] = False
if isTourney:
if (hand[i].endswith(" is sitting out") and (not hand[i].startswith("Seat "))):
toRemove.append(hand[i])
else:
hand[i] = False
elif:
if (hand[i].endswith(": sits out")):
toRemove.append(hand[i])
hand[i] = False
elif (hand[i].endswith(" is sitting out")):
toRemove.append(hand[i])
hand[i] = False
for i in xrange (len(toRemove)):
#print "removing in filterCr:",toRemove[i]
hand.remove(toRemove[i])
hand = [line for line in hand if line] # python docs say this is identical to filter(None, list)
#print "done with filterCrap, hand:", hand
return hand
@ -738,11 +713,11 @@ def filterCrap(hand, isTourney):
def float2int (string):
pos=string.find(",")
if (pos!=-1): #remove , the thousand seperator
string=string[0:pos]+string[pos+1:]
string = "%s%s" % (string[0:pos], string[pos+1:])
pos=string.find(".")
if (pos!=-1): #remove decimal point
string=string[0:pos]+string[pos+1:]
string = "%s%s" % (string[0:pos], string[pos+1:])
result = int(string)
if pos == -1: #no decimal point - was in full dollars - need to multiply with 100
@ -750,40 +725,24 @@ def float2int (string):
return result
#end def float2int
ActionLines = ( "calls $", ": calls ", "brings in for", "completes it to", "posts small blind",
"posts the small blind", "posts big blind", "posts the big blind",
"posts small & big blinds", "posts $", "posts a dead", "bets $",
": bets ", "raises")
#returns boolean whether the passed line is an action line
def isActionLine(line):
if (line.endswith("folds")):
return True
elif (line.endswith("checks")):
return True
elif (line.find("calls $")!=-1 or line.find(": calls ")!=-1):
return True
elif (line.find("brings in for")!=-1):
return True
elif (line.find("completes it to")!=-1):
return True
elif (line.find("posts small blind")!=-1):
return True
elif (line.find("posts the small blind")!=-1):
return True
elif (line.find("posts big blind")!=-1):
return True
elif (line.find("posts the big blind")!=-1):
return True
elif (line.find("posts small & big blinds")!=-1):
return True
elif (line.find(" posts $")!=-1): #this reads voluntary blind pay in FTP Holdem
return True
elif (line.find(" posts a dead ")!=-1): #this reads voluntary blind pay in FTP Holdem
return True
elif (line.find("bets $")!=-1 or line.find(": bets ")!=-1):
return True
elif (line.find("raises")!=-1):
return True
elif (line.startswith("Uncalled bet")):
return True
else:
return False
return len( [ x for x in ActionLines if x in line]) > 0
# ret = any(True for searchstr in ActionLines if searchstr in line)
# ret = len( [ x for x in ActionLines if line.find(x) > -1] ) > 0
# ret = any(searchstr in line for searchstr in ActionLines)
#end def isActionLine
#returns whether this is a duplicate
@ -802,46 +761,14 @@ def isRebuyOrAddon(topline):
#returns whether the passed topline indicates a tournament or not
def isTourney(topline):
if (topline.find("Tournament")!=-1):
return True
else:
return False
return "Tournament" in topline
#end def isTourney
WinLines = ( "wins the pot", "ties for the ", "wins side pot", "wins the low main pot", "wins the high main pot",
"wins the high pot", "wins the high side pot", "wins the main pot", "wins the side pot", "collected" )
#returns boolean whether the passed line is a win line
def isWinLine(line):
if (line.find("wins the pot")!=-1):
return True
elif (line.find("ties for the high pot")!=-1):
return True
elif (line.find("ties for the high main pot")!=-1):
return True
elif (line.find("ties for the high side pot")!=-1):
return True
elif (line.find("ties for the low pot")!=-1):
return True
elif (line.find("ties for the low main pot")!=-1):
return True
elif (line.find("ties for the low side pot")!=-1):
return True
elif (line.find("wins the low main pot")!=-1):
return True
elif (line.find("wins the low pot")!=-1):
return True
elif (line.find("wins the low side pot")!=-1):
return True
elif (line.find("wins the high main pot")!=-1):
return True
elif (line.find("wins the high pot")!=-1):
return True
elif (line.find("wins the high side pot")!=-1):
return True
elif (line.find("wins the main pot")!=-1):
return True
elif (line.find("collected")!=-1):
return True
else:
return False #not raising error here, any unknown line wouldve been detected in isActionLine already
return len( [ x for x in WinLines if x in line ] ) > 0
#end def isWinLine
#returns the amount of cash/chips put into the put in the given action line
@ -856,19 +783,15 @@ def parseActionAmount(line, atype, isTourney):
if line.endswith(" and is capped"):
line=line[:-14]
if (atype=="fold"):
if atype == "fold" or atype == "check":
amount = 0
elif (atype=="check"):
amount=0
elif (atype=="unbet"):
#print "ps unbet, line:",line
elif atype == "unbet":
pos1 = line.find("$") + 1
if pos1 == 0:
pos1 = line.find("(") + 1
pos2 = line.find(")")
amount = float2int(line[pos1:pos2])
elif (atype=="bet" and line.find(": raises $")!=-1 and line.find("to $")!=-1):
elif atype == "bet" and line.find(": raises $")!=-1 and line.find("to $")!=-1:
pos=line.find("to $")+4
amount=float2int(line[pos:])
else:
@ -892,13 +815,13 @@ def parseActionAmount(line, atype, isTourney):
# action_amounts. For stud this expects numeric streets (3-7), for
# holdem/omaha it expects predeal, preflop, flop, turn or river
def parseActionLine(base, isTourney, line, street, playerIDs, names, action_types, allIns, action_amounts, actionNos, actionTypeByNo):
if (street=="predeal" or street=="preflop"):
if street == "predeal" or street == "preflop":
street = 0
elif (street=="flop"):
elif street == "flop":
street = 1
elif (street=="turn"):
elif street == "turn":
street = 2
elif (street=="river"):
elif street == "river":
street = 3
nextActionNo = 0
@ -972,13 +895,13 @@ def parseActionType(line):
#parses the ante out of the given line and checks which player paid it, updates antes accordingly.
def parseAnteLine(line, isTourney, names, antes):
for i in xrange(len(names)):
if (line.startswith(names[i].encode("latin-1"))): #found the ante'er
for i, name in enumerate(names):
if line.startswith(name.encode("latin-1")):
pos = line.rfind("$") + 1
if not isTourney:
antes[i] += float2int(line[pos:])
else:
if line.find("all-in")==-1:
if "all-in" not in line:
pos = line.rfind(" ") + 1
antes[i] += int(line[pos:])
else:
@ -998,22 +921,22 @@ def parseBuyin(topline):
#parses a card line and changes the passed arrays accordingly
#todo: reorganise this messy method
def parseCardLine(category, street, line, names, cardValues, cardSuits, boardValues, boardSuits):
if (line.startswith("Dealt to ") or line.find(" shows [")!=-1 or line.find("mucked [")!=-1):
if line.startswith("Dealt to") or " shows [" in line or "mucked [" in line:
playerNo = recognisePlayerNo(line, names, "card") #anything but unbet will be ok for that string
pos = line.rfind("[")+1
if (category=="holdem"):
if category == "holdem":
for i in (pos, pos+3):
cardValues[playerNo].append(line[i:i+1])
cardSuits[playerNo].append(line[i+1:i+2])
if (len(cardValues[playerNo])!=2):
if len(cardValues[playerNo]) !=2:
if cardValues[playerNo][0]==cardValues[playerNo][2] and cardSuits[playerNo][1]==cardSuits[playerNo][3]: #two tests will do
cardValues[playerNo]=cardValues[playerNo][0:2]
cardSuits[playerNo]=cardSuits[playerNo][0:2]
else:
print "line:",line,"cardValues[playerNo]:",cardValues[playerNo]
raise FpdbError("read too many/too few holecards in parseCardLine")
elif (category=="omahahi" or category=="omahahilo"):
elif category == "omahahi" or category == "omahahilo":
for i in (pos, pos+3, pos+6, pos+9):
cardValues[playerNo].append(line[i:i+1])
cardSuits[playerNo].append(line[i+1:i+2])
@ -1024,8 +947,8 @@ def parseCardLine(category, street, line, names, cardValues, cardSuits, boardVal
else:
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):
elif category=="razz" or category=="studhi" or category=="studhilo":
if "shows" not in line and "mucked" not in line:
#print "parseCardLine(in stud if), street:", street
if line[pos+2]=="]": #-> not (hero and 3rd street)
cardValues[playerNo][street+2]=line[pos:pos+1]
@ -1145,12 +1068,8 @@ def parseNames(lines):
return result
#end def parseNames
#returns an array with the positions of the respective players
def parsePositions(hand, names):
#prep array
positions=[]
for i in xrange(len(names)):
positions.append(-1)
positions = map(lambda x: -1, names)
#find blinds
sb,bb=-1,-1
@ -1276,17 +1195,19 @@ def parseWinLine(line, names, winnings, isTourney):
#returns the category (as per database) string for the given line
def recogniseCategory(line):
if (line.find("Razz")!=-1):
if "Razz" in line:
return "razz"
elif (line.find("Hold'em")!=-1):
elif "Hold'em" in line:
return "holdem"
elif (line.find("Omaha")!=-1 and line.find("Hi/Lo")==-1 and line.find("H/L")==-1):
elif "Omaha" in line:
if "Hi/Lo" not in line and "H/L" not in line:
return "omahahi"
elif (line.find("Omaha")!=-1 and (line.find("Hi/Lo")!=-1 or line.find("H/L")!=-1)):
else:
return "omahahilo"
elif (line.find("Stud")!=-1 and line.find("Hi/Lo")==-1 and line.find("H/L")==-1):
elif "Stud" in line:
if "Hi/Lo" not in line and "H/L" not in line:
return "studhi"
elif (line.find("Stud")!=-1 and (line.find("Hi/Lo")!=-1 or line.find("H/L")!=-1)):
else:
return "studhilo"
else:
raise FpdbError("failed to recognise category, line:"+line)
@ -1678,19 +1599,20 @@ sure to also change the following storage method and table_viewer.prepare_data i
firstPfRaiserNo=-1
firstPfCallByNo=-1
firstPfCallerId=-1
for i in xrange(len(actionTypeByNo[0])):
if actionTypeByNo[0][i][1]=="bet":
for i, action in enumerate(actionTypeByNo[0]):
if action[1] == "bet":
firstPfRaiseByNo = i
firstPfRaiserId=actionTypeByNo[0][i][0]
for j in xrange(len(player_ids)):
if player_ids[j]==firstPfRaiserId:
firstPfRaiserId = action[0]
for j, pid in enumerate(player_ids):
if pid == firstPfRaiserId:
firstPfRaiserNo = j
break
break
for i in xrange(len(actionTypeByNo[0])):
if actionTypeByNo[0][i][1]=="call":
for i, action in enumerate(actionTypeByNo[0]):
if action[1] == "call":
firstPfCallByNo = i
firstPfCallerId=actionTypeByNo[0][i][0]
firstPfCallerId = action[0]
break
cutoffId=-1
@ -1698,14 +1620,14 @@ sure to also change the following storage method and table_viewer.prepare_data i
sbId=-1
bbId=-1
if base=="hold":
for player in xrange(len(positions)):
if positions==1:
for player, pos in enumerate(positions):
if pos == 1:
cutoffId = player_ids[player]
if positions==0:
if pos == 0:
buttonId = player_ids[player]
if positions=='S':
if pos == 'S':
sbId = player_ids[player]
if positions=='B':
if pos == 'B':
bbId = player_ids[player]
someoneStole=False
@ -1742,22 +1664,21 @@ sure to also change the following storage method and table_viewer.prepare_data i
#calculate VPIP and PFR
street=0
heroPfRaiseCount=0
for count in xrange(len(action_types[street][player])):#finally individual actions
currentAction=action_types[street][player][count]
for currentAction in action_types[street][player]: # finally individual actions
if currentAction == "bet":
myStreet0Aggr = True
if (currentAction=="bet" or currentAction=="call"):
if currentAction == "bet" or currentAction == "call":
myStreet0VPI = True
#PF3B4BChance and PF3B4B
pfFold=-1
pfRaise=-1
if firstPfRaiseByNo != -1:
for i in xrange(len(actionTypeByNo[0])):
if actionTypeByNo[0][i][0]==player_ids[player]:
if actionTypeByNo[0][i][1]=="bet" and pfRaise==-1 and i>firstPfRaiseByNo:
for i, actionType in enumerate(actionTypeByNo[0]):
if actionType[0] == player_ids[player]:
if actionType[1] == "bet" and pfRaise == -1 and i > firstPfRaiseByNo:
pfRaise = i
if actionTypeByNo[0][i][1]=="fold" and pfFold==-1:
if actionType[1] == "fold" and pfFold == -1:
pfFold = i
if pfFold == -1 or pfFold > firstPfRaiseByNo:
myStreet0_3B4BChance = True
@ -1794,20 +1715,17 @@ sure to also change the following storage method and table_viewer.prepare_data i
#calculate saw* values
isAllIn = False
for i in xrange(len(allIns[0][player])):
if allIns[0][player][i]:
if any(i for i in allIns[0][player]):
isAllIn = True
if (len(action_types[1][player])>0 or isAllIn):
myStreet1Seen = True
for i in xrange(len(allIns[1][player])):
if allIns[1][player][i]:
if any(i for i in allIns[1][player]):
isAllIn = True
if (len(action_types[2][player])>0 or isAllIn):
myStreet2Seen = True
for i in xrange(len(allIns[2][player])):
if allIns[2][player][i]:
if any(i for i in allIns[2][player]):
isAllIn = True
if (len(action_types[3][player])>0 or isAllIn):
myStreet3Seen = True
@ -1815,29 +1733,25 @@ sure to also change the following storage method and table_viewer.prepare_data i
#print "base:", base
if base=="hold":
mySawShowdown = True
for count in xrange(len(action_types[3][player])):
if action_types[3][player][count]=="fold":
if any(actiontype == "fold" for actiontype in action_types[3][player]):
mySawShowdown = False
else:
#print "in else"
for i in xrange(len(allIns[3][player])):
if allIns[3][player][i]:
if any(i for i in allIns[3][player]):
isAllIn = True
if (len(action_types[4][player])>0 or isAllIn):
#print "in if"
myStreet4Seen = True
mySawShowdown = True
for count in xrange(len(action_types[4][player])):
if action_types[4][player][count]=="fold":
if any(actiontype == "fold" for actiontype in action_types[4][player]):
mySawShowdown = False
#flop stuff
street=1
if myStreet1Seen:
for count in xrange(len(action_types[street][player])):
if action_types[street][player][count]=="bet":
if any(actiontype == "bet" for actiontype in action_types[street][player]):
myStreet1Aggr = True
for otherPlayer in xrange(len(player_ids)):
@ -1854,8 +1768,7 @@ sure to also change the following storage method and table_viewer.prepare_data i
#turn stuff - copy of flop with different vars
street=2
if myStreet2Seen:
for count in xrange(len(action_types[street][player])):
if action_types[street][player][count]=="bet":
if any(actiontype == "bet" for actiontype in action_types[street][player]):
myStreet2Aggr = True
for otherPlayer in xrange(len(player_ids)):
@ -1872,8 +1785,7 @@ sure to also change the following storage method and table_viewer.prepare_data i
#river stuff - copy of flop with different vars
street=3
if myStreet3Seen:
for count in xrange(len(action_types[street][player])):
if action_types[street][player][count]=="bet":
if any(actiontype == "bet" for actiontype in action_types[street][player]):
myStreet3Aggr = True
for otherPlayer in xrange(len(player_ids)):
@ -1890,8 +1802,7 @@ sure to also change the following storage method and table_viewer.prepare_data i
#stud river stuff - copy of flop with different vars
street=4
if myStreet4Seen:
for count in xrange(len(action_types[street][player])):
if action_types[street][player][count]=="bet":
if any(actiontype == "bet" for actiontype in action_types[street][player]):
myStreet4Aggr=True
for otherPlayer in xrange(len(player_ids)):

View File

@ -4,7 +4,10 @@ from Hand import *
import py
#regression-test-files/stars/badugi/ring-fl-badugi.txt
# s0rrow: start $30.00 end: $22.65 total: ($7.35)
# s0rrow: input: $30.00 end: $22.65 total: ($7.35)
#regression-test-files/stars/plo/PLO-6max.txt
# s0rrow: input: $18.35 end: $0 total: ($18.35)
# Notes: last hand #25975302416 s0rrow aifp against 2 players
gametype = {'type':'ring', 'base':'draw', 'category':'badugi', 'limitType':'fl', 'sb':'0.25', 'bb':'0.50','currency':'USD'}
text = ""
@ -30,7 +33,10 @@ def testGameInfo():
{'type':'ring', 'base':'hold', 'category':'omahahilo', 'limitType':'fl', 'sb':'2', 'bb':'4','currency':'USD'}),
(u"PokerStars Game #25923772706: Badugi Limit ($0.25/$0.50) - 2009/03/13 16:40:58 ET",
{'type':'ring', 'base':'draw', 'category':'badugi', 'limitType':'fl', 'sb':'0.25', 'bb':'0.50','currency':'USD'})
{'type':'ring', 'base':'draw', 'category':'badugi', 'limitType':'fl', 'sb':'0.25', 'bb':'0.50','currency':'USD'}),
(u"PokerStars Game #25974627364: Omaha Pot Limit ($0.05/$0.10) - 2009/03/15 0:29:00 ET",
{'type':'ring', 'base':'hold', 'category':'omahahi', 'limitType':'pl', 'sb':'0.05', 'bb':'0.10','currency':'USD'})
)
for (header, info) in pairs:
yield checkGameInfo, hhc, header, info