Merge branch 'master' of git://git.assembla.com/fpdboz
This commit is contained in:
commit
29a04f639d
109
pyfpdb/CarbonToFpdb.py
Normal file
109
pyfpdb/CarbonToFpdb.py
Normal 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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 -----------"
|
||||||
|
|
|
@ -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'))]
|
||||||
|
|
||||||
def readBlinds(self):
|
return gametype
|
||||||
pass
|
|
||||||
|
def readHandInfo(self, hand):
|
||||||
|
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
161
pyfpdb/FpdbRegex.py
Normal 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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user