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

This commit is contained in:
Ray 2008-11-11 14:28:50 -05:00
commit 29a04f639d
10 changed files with 588 additions and 34 deletions

109
pyfpdb/CarbonToFpdb.py Normal file
View File

@ -0,0 +1,109 @@
#!/usr/bin/env python
# Copyright 2008, Carl Gherardi
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
# Standard Library modules
import Configuration
import traceback
import sys
import re
import xml.dom.minidom
from xml.dom.minidom import Node
from HandHistoryConverter import HandHistoryConverter
# Carbon format looks like:
# 1) <description type="Holdem" stakes="No Limit ($0.25/$0.50)"/>
# 2) <game id="14902583-5578" starttime="20081006145401" numholecards="2" gametype="2" realmoney="true" data="20081006|Niagara Falls (14902583)|14902583|14902583-5578|false">
# 3) <players dealer="8">
# <player seat="3" nickname="PlayerInSeat3" balance="$43.29" dealtin="true" />
# ...
# 4) <round id="BLINDS" sequence="1">
# <event sequence="1" type="SMALL_BLIND" player="0" amount="0.25"/>
# <event sequence="2" type="BIG_BLIND" player="1" amount="0.50"/>
# 5) <round id="PREFLOP" sequence="2">
# <event sequence="3" type="CALL" player="2" amount="0.50"/>
# 6) <round id="POSTFLOP" sequence="3">
# <event sequence="16" type="BET" player="3" amount="1.00"/>
# ....
# <cards type="COMMUNITY" cards="7d,Jd,Jh"/>
# The full sequence for a NHLE cash game is:
# BLINDS, PREFLOP, POSTFLOP, POSTTURN, POSTRIVER, SHOWDOWN, END_OF_GAME
# This sequence can be terminated after BLINDS at any time by END_OF_FOLDED_GAME
class CarbonPoker(HandHistoryConverter):
def __init__(self, config, filename):
print "Initialising Carbon Poker converter class"
HandHistoryConverter.__init__(self, config, filename, "Carbon") # Call super class init
self.setFileType("xml")
def readSupportedGames(self):
pass
def determineGameType(self):
gametype = []
desc_node = self.doc.getElementsByTagName("description")
#TODO: no examples of non ring type yet
gametype = gametype + ["ring"]
type = desc_node[0].getAttribute("type")
if(type == "Holdem"):
gametype = gametype + ["hold"]
else:
print "Unknown gametype: '%s'" % (type)
stakes = desc_node[0].getAttribute("stakes")
#TODO: no examples of anything except nlhe
m = re.match('(?P<LIMIT>No Limit)\s\(\$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\)', stakes)
if(m.group('LIMIT') == "No Limit"):
gametype = gametype + ["nl"]
gametype = gametype + [self.float2int(m.group('SB'))]
gametype = gametype + [self.float2int(m.group('BB'))]
return gametype
def readPlayerStacks(self):
pass
def readBlinds(self):
pass
def readAction(self):
pass
# Override read function as xml.minidom barfs on the Carbon layout
# This is pretty dodgy
def readFile(self, filename):
print "Carbon: Reading file: '%s'" %(filename)
infile=open(filename, "rU")
self.obs = infile.read()
infile.close()
self.obs = "<CarbonHHFile>\n" + self.obs + "</CarbonHHFile>"
try:
doc = xml.dom.minidom.parseString(self.obs)
self.doc = doc
except:
traceback.print_exc(file=sys.stderr)
if __name__ == "__main__":
c = Configuration.Config()
e = CarbonPoker(c, "regression-test-files/carbon-poker/Niagara Falls (15245216).xml")
e.processFile()
print str(e)

View File

@ -53,7 +53,7 @@ if __name__ == "__main__":
(options, sys.argv) = parser.parse_args() (options, sys.argv) = parser.parse_args()
settings={'imp-callFpdbHud':False, 'db-backend':2} settings={'callFpdbHud':False, 'db-backend':2}
settings['db-host']=options.server settings['db-host']=options.server
settings['db-user']=options.user settings['db-user']=options.user
settings['db-password']=options.password settings['db-password']=options.password

View File

@ -178,11 +178,12 @@ class Popup:
class Import: class Import:
def __init__(self, node): def __init__(self, node):
self.interval = node.getAttribute("interval") self.interval = node.getAttribute("interval")
self.callFpdbHud = node.getAttribute("callFpdbHud") self.callFpdbHud = node.getAttribute("callFpdbHud")
self.hhArchiveBase = node.getAttribute("hhArchiveBase")
def __str__(self): def __str__(self):
return " interval = %s\n callFpdbHud = %s\n" % (self.interval, self.callFpdbHud) return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s" % (self.interval, self.callFpdbHud, self.hhArchiveBase)
class Tv: class Tv:
def __init__(self, node): def __init__(self, node):
@ -437,11 +438,13 @@ class Config:
def get_import_parameters(self): def get_import_parameters(self):
imp = {} imp = {}
try: try:
imp['imp-callFpdbHud'] = self.imp.callFpdbHud imp['callFpdbHud'] = self.callFpdbHud
imp['hud-defaultInterval'] = int(self.imp.interval) imp['interval'] = self.interval
except: # Default import parameters imp['hhArchiveBase'] = self.hhArchiveBase
imp['imp-callFpdbHud'] = True except: # Default params
imp['hud-defaultInterval'] = 10 imp['callFpdbHud'] = True
imp['interval'] = 10
imp['hhArchiveBase'] = "~/.fpdb/HandHistories/"
return imp return imp
def get_default_paths(self, site = "PokerStars"): def get_default_paths(self, site = "PokerStars"):
@ -565,7 +568,9 @@ if __name__== "__main__":
print "----------- END MUCKED WINDOW FORMATS -----------" print "----------- END MUCKED WINDOW FORMATS -----------"
print "\n----------- IMPORT -----------" print "\n----------- IMPORT -----------"
# print c.imp tmp = c.get_import_parameters()
for param in tmp:
print " " + str(param) + ": " + str(tmp[param])
print "----------- END IMPORT -----------" print "----------- END IMPORT -----------"
print "\n----------- TABLE VIEW -----------" print "\n----------- TABLE VIEW -----------"

View File

@ -16,25 +16,117 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
######################################################################## ########################################################################
from HandHistoryConverter import HandHistoryConverter import sys
import Configuration
from HandHistoryConverter import *
# Everleaf HH format
#Everleaf Gaming Game #55198191
#***** Hand history for game #55198191 *****
#Blinds $0.50/$1 NL Hold'em - 2008/09/01 - 10:02:11
#Table Speed Kuala
#Seat 8 is the button
#Total number of players: 10
#Seat 1: spicybum ( $ 77.50 USD )
#Seat 2: harrydebeng ( new player )
#Seat 3: EricBlade ( new player )
#Seat 4: dollar_hecht ( $ 16.40 USD )
#Seat 5: Apolon76 ( $ 154.10 USD )
#Seat 6: dogge ( new player )
#Seat 7: RonKoro ( $ 25.53 USD )
#Seat 8: jay68w ( $ 48.50 USD )
#Seat 9: KillerQueen1 ( $ 51.28 USD )
#Seat 10: Cheburashka ( $ 49.61 USD )
#KillerQueen1: posts small blind [$ 0.50 USD]
#Cheburashka: posts big blind [$ 1 USD]
#** Dealing down cards **
#spicybum folds
#dollar_hecht calls [$ 1 USD]
#Apolon76 folds
#RonKoro folds
#jay68w raises [$ 4.50 USD]
#KillerQueen1 folds
#Cheburashka folds
#dollar_hecht folds
#jay68w does not show cards
#jay68w wins $ 3.50 USD from main pot
class Everleaf(HandHistoryConverter): class Everleaf(HandHistoryConverter):
def __init__(self): def __init__(self, config, file):
print "Initialising Everleaf converter class" print "Initialising Everleaf converter class"
HandHistoryConverter.__init__(self, config, file, "Everleaf") # Call super class init.
self.sitename = "Everleaf"
self.setFileType("text")
self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)')
self.rexx.setSplitHandRegex('\n\n\n\n')
self.rexx.setHandInfoRegex('.*#(?P<HID>[0-9]+)\n.*\nBlinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>.*) - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+):(?P<SEC>[0-9]+)\nTable (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
self.rexx.setPlayerInfoRegex('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \( \$ (?P<CASH>[.0-9]+) USD \)')
self.rexx.setPostSbRegex('.*\n(?P<PNAME>.*): posts small blind \[')
self.rexx.setPostBbRegex('.*\n(?P<PNAME>.*): posts big blind \[')
self.rexx.compileRegexes()
def readSupportedGames(self): def readSupportedGames(self):
pass pass
def determineGameType(self): def determineGameType(self):
pass # Cheating with this regex, only support nlhe at the moment
gametype = ["ring", "hold", "nl"]
def readPlayerStacks(self): m = self.rexx.game_info_re.search(self.obs)
pass gametype = gametype + [m.group('SB')]
gametype = gametype + [m.group('BB')]
# gametype = gametype + [self.float2int(m.group('SB'))]
# gametype = gametype + [self.float2int(m.group('BB'))]
return gametype
def readBlinds(self): def readHandInfo(self, hand):
pass m = self.rexx.hand_info_re.search(hand.string)
hand.handid = m.group('HID')
hand.tablename = m.group('TABLE')
# These work, but the info is already in the Hand class - should be usecd for tourneys though.
# m.group('SB')
# m.group('BB')
# m.group('GAMETYPE')
# Believe Everleaf time is GMT/UTC, no transation necessary
# Stars format (Nov 10 2008): 2008/11/07 12:38:49 UTC [2008/11/07 7:38:49 ET]
# Not getting it in my HH files yet, so using
# 2008/11/10 3:58:52 ET
#TODO: Do conversion from GMT to ET
#TODO: Need some date functions to convert to different timezones (Date::Manip for perl rocked for this)
hand.starttime = "%d/%02d/%02d %d:%02d:%02d ET" %(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')),
int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC')))
hand.buttonpos = int(m.group('BUTTON'))
def readPlayerStacks(self, hand):
m = self.rexx.player_info_re.finditer(hand.string)
players = []
for a in m:
players = players + [[a.group('SEAT'), a.group('PNAME'), a.group('CASH')]]
hand.players = players
def readBlinds(self, hand):
try:
m = self.rexx.small_blind_re.search(hand.string)
hand.posted = [m.group('PNAME')]
except:
hand.posted = ["FpdbNBP"]
m = self.rexx.big_blind_re.finditer(hand.string)
for a in m:
hand.posted = hand.posted + [a.group('PNAME')]
def readAction(self): def readAction(self):
pass pass
if __name__ == "__main__": if __name__ == "__main__":
e = Everleaf() c = Configuration.Config()
e = Everleaf(c, "regression-test-files/everleaf/Speed_Kuala.txt")
e.processFile()
print str(e)

161
pyfpdb/FpdbRegex.py Normal file
View File

@ -0,0 +1,161 @@
# pokerstars_cash.py
# -*- coding: iso-8859-15
#
# PokerStats, an online poker statistics tracking software for Linux
# Copyright (C) 2007-2008 Mika Boström <bostik@iki.fi>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# Modified for use in fpdb by Carl Gherardi
import re
# These are PokerStars specific;
# More importantly, they are currently valid for cash game only.
#####
# XXX: There was a weird problem with saved hand histories in PokerStars
# client 2.491; if a user was present on the table (and thus anywhere in
# the hand history), with non-standard characters in their username, the
# client would prepend a literal Ctrl-P (ASCII 16, 0x10) character to
# the hand history title line. Hence, to allow these strangely saved
# hands to be parsed and imported, there is a conditional "one extra
# character" allowed at the start of the new hand regex.
class FpdbRegex:
def __init__(self):
self.__GAME_INFO_REGEX=''
self.__SPLIT_HAND_REGEX='\n\n\n'
self.__NEW_HAND_REGEX='^.?PokerStars Game #\d+:\s+Hold\'em'
self.__HAND_INFO_REGEX='^.*#(\d+):\s+(\S+)\s([\s\S]+)\s\(\$?([.0-9]+)/\$?([.0-9]+)\)\s-\s(\S+)\s-?\s?(\S+)\s\(?(\w+)\)?'
self.__TABLE_INFO_REGEX='^\S+\s+\'.*\'\s+(\d+)-max\s+Seat\s#(\d+)'
self.__PLAYER_INFO_REGEX='^Seat\s(\d+):\s(.*)\s\(\$?([.\d]+)\s'
self.__POST_SB_REGEX='^(.*):\sposts small blind'
self.__POST_BB_REGEX='^(.*):\sposts big blind'
self.__POST_BOTH_REGEX='^(.*):\sposts small & big blinds'
self.__HAND_STAGE_REGEX='^\*{3}\s(.*)\s\*{3}'
self.__HOLE_CARD_REGEX='^\*{3}\sHOLE CARDS'
self.__FLOP_CARD_REGEX='^\*{3}\sFLOP\s\*{3}\s\[(\S{2})\s(\S{2})\s(\S{2})\]'
self.__TURN_CARD_REGEX='^\*{3}\sTURN\s\*{3}\s\[\S{2}\s\S{2}\s\S{2}\]\s\[(\S{2})\]'
self.__RIVER_CARD_REGEX='^\*{3}\sRIVER\s\*{3}\s\[\S{2}\s\S{2}\s\S{2}\s\S{2}\]\s\[(\S{2})\]'
self.__SHOWDOWN_REGEX='^\*{3}\sSHOW DOWN'
self.__SUMMARY_REGEX='^\*{3}\sSUMMARY'
self.__UNCALLED_BET_REGEX='^Uncalled bet \(\$([.\d]+)\) returned to (.*)'
self.__POT_AND_RAKE_REGEX='^Total\spot\s\$([.\d]+).*\|\sRake\s\$([.\d]+)'
self.__COLLECT_POT_REGEX='^(.*)\scollected\s\$([.\d]+)\sfrom\s((main|side)\s)?pot'
self.__POCKET_CARDS_REGEX='^Dealt\sto\s(.*)\s\[(\S{2})\s(\S{2})\]'
self.__SHOWN_CARDS_REGEX='^(.*):\sshows\s\[(\S{2})\s(\S{2})\]'
self.__ACTION_STEP_REGEX='^(.*):\s(bets|checks|raises|calls|folds)((\s\$([.\d]+))?(\sto\s\$([.\d]+))?)?'
self.__SHOWDOWN_ACTION_REGEX='^(.*):\s(shows|mucks)'
self.__SUMMARY_CARDS_REGEX='^Seat\s\d+:\s(.*)\s(showed|mucked)\s\[(\S{2})\s(\S{2})\]'
self.__SUMMARY_CARDS_EXTRA_REGEX='^Seat\s\d+:\s(.*)\s(\(.*\)\s)(showed|mucked)\s\[(\S{2})\s(\S{2})\]'
def compileRegexes(self):
### Compile the regexes
self.game_info_re = re.compile(self.__GAME_INFO_REGEX)
self.split_hand_re = re.compile(self.__SPLIT_HAND_REGEX)
self.hand_start_re = re.compile(self.__NEW_HAND_REGEX)
self.hand_info_re = re.compile(self.__HAND_INFO_REGEX)
self.table_info_re = re.compile(self.__TABLE_INFO_REGEX)
self.player_info_re = re.compile(self.__PLAYER_INFO_REGEX)
self.small_blind_re = re.compile(self.__POST_SB_REGEX)
self.big_blind_re = re.compile(self.__POST_BB_REGEX)
self.both_blinds_re = re.compile(self.__POST_BOTH_REGEX)
self.hand_stage_re = re.compile(self.__HAND_STAGE_REGEX)
self.hole_cards_re = re.compile(self.__HOLE_CARD_REGEX)
self.flop_cards_re = re.compile(self.__FLOP_CARD_REGEX)
self.turn_card_re = re.compile(self.__TURN_CARD_REGEX)
self.river_card_re = re.compile(self.__RIVER_CARD_REGEX)
self.showdown_re = re.compile(self.__SHOWDOWN_REGEX)
self.summary_re = re.compile(self.__SUMMARY_REGEX)
self.uncalled_bet_re = re.compile(self.__UNCALLED_BET_REGEX)
self.collect_pot_re = re.compile(self.__COLLECT_POT_REGEX)
self.pocket_cards_re = re.compile(self.__POCKET_CARDS_REGEX)
self.cards_shown_re = re.compile(self.__SHOWN_CARDS_REGEX)
self.summary_cards_re = re.compile(self.__SUMMARY_CARDS_REGEX)
self.summary_cards_extra_re = re.compile(self.__SUMMARY_CARDS_EXTRA_REGEX)
self.action_re = re.compile(self.__ACTION_STEP_REGEX)
self.rake_re = re.compile(self.__POT_AND_RAKE_REGEX)
self.showdown_action_re = re.compile(self.__SHOWDOWN_ACTION_REGEX)
# Set methods for plugins to override
def setGameInfoRegex(self, string):
self.__GAME_INFO_REGEX = string
def setSplitHandRegex(self, string):
self.__SPLIT_HAND_REGEX = string
def setNewHandRegex(self, string):
self.__NEW_HAND_REGEX = string
def setHandInfoRegex(self, string):
self.__HAND_INFO_REGEX = string
def setTableInfoRegex(self, string):
self.__TABLE_INFO_REGEX = string
def setPlayerInfoRegex(self, string):
self.__PLAYER_INFO_REGEX = string
def setPostSbRegex(self, string):
self.__POST_SB_REGEX = string
def setPostBbRegex(self, string):
self.__POST_BB_REGEX = string
def setPostBothRegex(self, string):
self.__POST_BOTH_REGEX = string
def setHandStageRegex(self, string):
self.__HAND_STAGE_REGEX = string
def setHoleCardRegex(self, string):
self.__HOLE_CARD_REGEX = string
def setFlopCardRegex(self, string):
self.__FLOP_CARD_REGEX = string
def setTurnCardRegex(self, string):
self.__TURN_CARD_REGEX = string
def setRiverCardRegex(self, string):
self.__RIVER_CARD_REGEX = string
def setShowdownRegex(self, string):
self.__SHOWDOWN_REGEX = string
def setSummaryRegex(self, string):
self.__SUMMARY_REGEX = string
def setUncalledBetRegex(self, string):
self.__UNCALLED_BET_REGEX = string
def setCollectPotRegex(self, string):
self.__COLLECT_POT_REGEX = string
def setPocketCardsRegex(self, string):
self.__POCKET_CARDS_REGEX = string
def setShownCardsRegex(self, string):
self.__SHOWN_CARDS_REGEX = string
def setSummaryCardsRegex(self, string):
self.__SUMMARY_CARDS_REGEX = string
def setSummaryCardsExtraRegex(self, string):
self.__SUMMARY_CARDS_EXTRA_REGEX = string
def setActionStepRegex(self, string):
self.__ACTION_STEP_REGEX = string
def setPotAndRakeRegex(self, string):
self.__POT_AND_RAKE_REGEX = string
def setShowdownActionRegex(self, string):
self.__SHOWDOWN_ACTION_REGEX = string

View File

@ -33,9 +33,14 @@ class GuiAutoImport (threading.Thread):
self.settings=settings self.settings=settings
self.config=config self.config=config
imp = self.config.get_import_parameters()
print "Import parameters"
print imp
self.input_settings = {} self.input_settings = {}
self.importer = fpdb_import.Importer(self,self.settings) self.importer = fpdb_import.Importer(self,self.settings, self.config)
self.importer.setCallHud(True) self.importer.setCallHud(True)
self.importer.setMinPrint(30) self.importer.setMinPrint(30)
self.importer.setQuiet(False) self.importer.setQuiet(False)
@ -60,7 +65,7 @@ class GuiAutoImport (threading.Thread):
self.intervalLabel.show() self.intervalLabel.show()
self.intervalEntry=gtk.Entry() self.intervalEntry=gtk.Entry()
self.intervalEntry.set_text(str(self.settings['hud-defaultInterval'])) self.intervalEntry.set_text(str(self.config.get_import_parameters().get("interval")))
self.settingsHBox.pack_start(self.intervalEntry) self.settingsHBox.pack_start(self.intervalEntry)
self.intervalEntry.show() self.intervalEntry.show()
@ -196,7 +201,7 @@ if __name__== "__main__":
settings['db-databaseName'] = "fpdb" settings['db-databaseName'] = "fpdb"
settings['hud-defaultInterval'] = 10 settings['hud-defaultInterval'] = 10
settings['hud-defaultPath'] = 'C:/Program Files/PokerStars/HandHistory/nutOmatic' settings['hud-defaultPath'] = 'C:/Program Files/PokerStars/HandHistory/nutOmatic'
settings['imp-callFpdbHud'] = True settings['callFpdbHud'] = True
i = GuiAutoImport(settings) i = GuiAutoImport(settings)
main_window = gtk.Window() main_window = gtk.Window()

View File

@ -80,7 +80,7 @@ class GuiBulkImport (threading.Thread):
self.db=db self.db=db
self.settings=settings self.settings=settings
self.config=config self.config=config
self.importer = fpdb_import.Importer(self,self.settings) self.importer = fpdb_import.Importer(self,self.settings, config)
self.vbox=gtk.VBox(False,1) self.vbox=gtk.VBox(False,1)
self.vbox.show() self.vbox.show()

View File

@ -187,7 +187,7 @@
<pu_stat pu_stat_name="ffreq_4"> </pu_stat> <pu_stat pu_stat_name="ffreq_4"> </pu_stat>
</pu> </pu>
</popup_windows> </popup_windows>
<import callFpdbHud = "True" interval = "10" ></import> <import callFpdbHud = "True" interval = "10" hhArchiveBase="~/.fpdb/HandHistories/"></import>
<tv combinedStealFold = "True" combined2B3B = "True" combinedPostflop = "True"></tv> <tv combinedStealFold = "True" combined2B3B = "True" combinedPostflop = "True"></tv>
<supported_databases> <supported_databases>

View File

@ -15,21 +15,205 @@
#In the "official" distribution you can find the license in #In the "official" distribution you can find the license in
#agpl-3.0.txt in the docs folder of the package. #agpl-3.0.txt in the docs folder of the package.
import Configuration
import FpdbRegex
import re
import sys
import traceback
import os
import os.path
import xml.dom.minidom
from xml.dom.minidom import Node
class HandHistoryConverter: class HandHistoryConverter:
def __init__(self): def __init__(self, config, file, sitename):
pass print "HandHistory init called"
self.c = config
self.sitename = sitename
self.obs = "" # One big string
self.filetype = "text"
self.doc = None # For XML based HH files
self.file = file
self.hhbase = self.c.get_import_parameters().get("hhArchiveBase")
self.hhbase = os.path.expanduser(self.hhbase)
self.hhdir = os.path.join(self.hhbase,sitename)
self.gametype = []
# self.ofile = os.path.join(self.hhdir,file)
self.rexx = FpdbRegex.FpdbRegex()
def __str__(self):
tmp = "HandHistoryConverter: '%s'\n" % (self.sitename)
tmp = tmp + "\thhbase: '%s'\n" % (self.hhbase)
tmp = tmp + "\thhdir: '%s'\n" % (self.hhdir)
tmp = tmp + "\tfiletype: '%s'\n" % (self.filetype)
tmp = tmp + "\tinfile: '%s'\n" % (self.file)
# tmp = tmp + "\toutfile: '%s'\n" % (self.ofile)
tmp = tmp + "\tgametype: '%s'\n" % (self.gametype[0])
tmp = tmp + "\tgamebase: '%s'\n" % (self.gametype[1])
tmp = tmp + "\tlimit: '%s'\n" % (self.gametype[2])
tmp = tmp + "\tsb/bb: '%s/%s'\n" % (self.gametype[3], self.gametype[4])
return tmp
def processFile(self):
if not self.sanityCheck():
print "Cowardly refusing to continue after failed sanity check"
return
self.readFile(self.file)
self.gametype = self.determineGameType()
self.hands = self.splitFileIntoHands()
for hand in self.hands:
self.readHandInfo(hand)
self.readPlayerStacks(hand)
self.readBlinds(hand)
self.writeHand("output file", hand)
# Functions to be implemented in the inheriting class # Functions to be implemented in the inheriting class
def readSupportedGames(self): abstract def readSupportedGames(self): abstract
# should return a list
# type base limit
# [ ring, hold, nl , sb, bb ]
# Valid types specified in docs/tabledesign.html in Gametypes
def determineGameType(self): abstract def determineGameType(self): abstract
def readPlayerStacks(self): abstract
def readBlinds(self): abstract #TODO: Comment
def readHandInfo(self, hand): abstract
# Needs to return a list of lists in the format
# [['seat#', 'player1name', 'stacksize'] ['seat#', 'player2name', 'stacksize'] [...]]
def readPlayerStacks(self, hand): abstract
#Needs to return a list in the format
# ['player1name', 'player2name', ...] where player1name is the sb and player2name is bb,
# addtional players are assumed to post a bb oop
def readBlinds(self, hand): abstract
def readAction(self): abstract def readAction(self): abstract
def sanityCheck(self):
sane = False
base_w = False
#Check if hhbase exists and is writable
#Note: Will not try to create the base HH directory
if not (os.access(self.hhbase, os.W_OK) and os.path.isdir(self.hhbase)):
print "HH Sanity Check: Directory hhbase '" + self.hhbase + "' doesn't exist or is not writable"
else:
#Check if hhdir exists and is writable
if not os.path.isdir(self.hhdir):
# In first pass, dir may not exist. Attempt to create dir
print "Creating directory: '%s'" % (self.hhdir)
os.mkdir(self.hhdir)
sane = True
elif os.access(self.hhdir, os.W_OK):
sane = True
else:
print "HH Sanity Check: Directory hhdir '" + self.hhdir + "' or its parent directory are not writable"
return sane
# Functions not necessary to implement in sub class # Functions not necessary to implement in sub class
def setFileType(self, filetype = "text"):
self.filetype = filetype
def splitFileIntoHands(self):
hands = []
list = self.rexx.split_hand_re.split(self.obs)
list.pop() #Last entry is empty
for l in list:
# print "'" + l + "'"
hands = hands + [Hand(self.sitename, self.gametype, l)]
return hands
def readFile(self, filename): def readFile(self, filename):
"""Read file""" """Read file"""
print "Reading file: '%s'" %(filename)
if(self.filetype == "text"):
infile=open(filename, "rU")
self.obs = infile.read()
infile.close()
elif(self.filetype == "xml"):
try:
doc = xml.dom.minidom.parse(filename)
self.doc = doc
except:
traceback.print_exc(file=sys.stderr)
def writeStars(self): def writeHand(self, file, hand):
"""Write out parsed data""" """Write out parsed data"""
print "%s Game #%s: %s ($%s/$%s) - %s" %(hand.sitename, hand.handid, "XXXXhand.gametype", hand.sb, hand.bb, hand.starttime)
print "Table '%s' %d-max Seat #%s is the button" %(hand.tablename, hand.maxseats, hand.buttonpos)
for player in hand.players:
print "Seat %s: %s ($%s)" %(player[0], player[1], player[2])
if(hand.posted[0] == "FpdbNBP"):
print "No small blind posted"
else:
print "%s: posts small blind $%s" %(hand.posted[0], hand.sb)
#May be more than 1 bb posting
print "%s: posts big blind $%s" %(hand.posted[1], hand.bb)
if(len(hand.posted) > 2):
# Need to loop on all remaining big blinds - lazy
print "XXXXXXXXX FIXME XXXXXXXX"
print "*** HOLE CARDS ***"
# print "Dealt to " + hero + " [" + holecards + "]"
#
## ACTION STUFF
#
print "*** SUMMARY ***"
# print "Total pot $" + totalpot + " | Rake $" + rake
# print "Board [" + boardcards + "]"
#
## SUMMARY STUFF
#takes a poker float (including , for thousand seperator and converts it to an int
def float2int (self, string):
pos=string.find(",")
if (pos!=-1): #remove , the thousand seperator
string=string[0:pos]+string[pos+1:]
pos=string.find(".")
if (pos!=-1): #remove decimal point
string=string[0:pos]+string[pos+1:]
result = int(string)
if pos==-1: #no decimal point - was in full dollars - need to multiply with 100
result*=100
return result
#end def float2int
class Hand:
# def __init__(self, sitename, gametype, sb, bb, string):
def __init__(self, sitename, gametype, string):
self.sitename = sitename
self.gametype = gametype
self.string = string
self.handid = 0
self.sb = gametype[3]
self.bb = gametype[4]
self.tablename = "Slartibartfast"
self.maxseats = 10
self.counted_seats = 0
self.buttonpos = 0
self.seating = []
self.players = []
self.posted = []
self.action = []
def printHand(self):
print self.sitename
print self.gametype
print self.string
print self.handid
print self.sb
print self.bb
print self.tablename
print self.maxseats
print self.counted_seats
print self.buttonpos
print self.seating
print self.players
print self.posted
print self.action

View File

@ -41,23 +41,22 @@ from time import time
class Importer: class Importer:
def __init__(self, caller, settings): def __init__(self, caller, settings, config):
"""Constructor""" """Constructor"""
self.settings=settings self.settings=settings
self.caller=caller self.caller=caller
self.config = config
self.db = None self.db = None
self.cursor = None self.cursor = None
self.filelist = {} self.filelist = {}
self.dirlist = {} self.dirlist = {}
self.monitor = False self.monitor = False
self.updated = {} #Time last import was run {file:mtime} self.updated = {} #Time last import was run {file:mtime}
self.callHud = False
self.lines = None self.lines = None
self.faobs = None #File as one big string self.faobs = None #File as one big string
self.pos_in_file = {} # dict to remember how far we have read in the file self.pos_in_file = {} # dict to remember how far we have read in the file
#Set defaults #Set defaults
if not self.settings.has_key('imp-callFpdbHud'): self.callHud = self.config.get_import_parameters().get("callFpdbHud")
self.settings['imp-callFpdbHud'] = False
if not self.settings.has_key('minPrint'): if not self.settings.has_key('minPrint'):
self.settings['minPrint'] = 30 self.settings['minPrint'] = 30
self.dbConnect() self.dbConnect()
@ -241,8 +240,7 @@ class Importer:
stored+=1 stored+=1
self.db.commit() self.db.commit()
# if settings['imp-callFpdbHud'] and self.callHud and os.sep=='/': if self.callHud:
if self.settings['imp-callFpdbHud'] and self.callHud:
#print "call to HUD here. handsId:",handsId #print "call to HUD here. handsId:",handsId
#pipe the Hands.id out to the HUD #pipe the Hands.id out to the HUD
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)