Merge branch 'master' of git://git.assembla.com/fpdboz
Conflicts: pyfpdb/GuiBulkImport.py pyfpdb/Hud.py
This commit is contained in:
commit
20514bd0cb
|
@ -62,6 +62,7 @@ class Site:
|
|||
self.aux_window = node.getAttribute("aux_window")
|
||||
self.font = node.getAttribute("font")
|
||||
self.font_size = node.getAttribute("font_size")
|
||||
self.use_frames = node.getAttribute("use_frames")
|
||||
self.layout = {}
|
||||
|
||||
for layout_node in node.getElementsByTagName('layout'):
|
||||
|
@ -466,6 +467,9 @@ class Config:
|
|||
paths['bulkImport-defaultPath'] = "default"
|
||||
return paths
|
||||
|
||||
def get_frames(self, site = "PokerStars"):
|
||||
return self.supported_sites[site].use_frames == "True"
|
||||
|
||||
def get_default_colors(self, site = "PokerStars"):
|
||||
colors = {}
|
||||
if self.supported_sites[site].hudopacity == "":
|
||||
|
|
|
@ -20,88 +20,94 @@
|
|||
import sys
|
||||
import Configuration
|
||||
from HandHistoryConverter import *
|
||||
from time import strftime
|
||||
|
||||
# Everleaf HH format
|
||||
|
||||
# Everleaf Gaming Game #55208539
|
||||
# ***** Hand history for game #55208539 *****
|
||||
# Blinds $0.50/$1 NL Hold'em - 2008/09/01 - 13:35:01
|
||||
# Table Speed Kuala
|
||||
# Seat 1 is the button
|
||||
# Total number of players: 9
|
||||
# Seat 1: BadBeatBox ( $ 98.97 USD )
|
||||
# Seat 3: EricBlade ( $ 73.96 USD )
|
||||
# Seat 4: randy888 ( $ 196.50 USD )
|
||||
# Seat 5: BaronSengir ( $ 182.80 USD )
|
||||
# Seat 6: dogge ( $ 186.06 USD )
|
||||
# Seat 7: wings ( $ 50 USD )
|
||||
# Seat 8: schoffeltje ( $ 282.05 USD )
|
||||
# Seat 9: harrydebeng ( $ 109.45 USD )
|
||||
# Seat 10: smaragdar ( $ 96.50 USD )
|
||||
# EricBlade: posts small blind [$ 0.50 USD]
|
||||
# randy888: posts big blind [$ 1 USD]
|
||||
# wings: posts big blind [$ 1 USD]
|
||||
# ** Dealing down cards **
|
||||
# Dealt to EricBlade [ qc, 3c ]
|
||||
# BaronSengir folds
|
||||
# dogge folds
|
||||
# wings raises [$ 2.50 USD]
|
||||
# schoffeltje folds
|
||||
# harrydebeng calls [$ 3.50 USD]
|
||||
# smaragdar raises [$ 15.50 USD]
|
||||
# BadBeatBox folds
|
||||
# EricBlade folds
|
||||
# randy888 folds
|
||||
# wings calls [$ 12 USD]
|
||||
# harrydebeng folds
|
||||
# ** Dealing Flop ** [ qs, 3d, 8h ]
|
||||
# wings: bets [$ 34.50 USD]
|
||||
# smaragdar calls [$ 34.50 USD]
|
||||
# ** Dealing Turn ** [ 2d ]
|
||||
# ** Dealing River ** [ 6c ]
|
||||
# dogge shows [ 9h, 9c ]a pair of nines
|
||||
# spicybum shows [ 5d, 6d ]a straight, eight high
|
||||
# harrydebeng does not show cards
|
||||
# smaragdar wins $ 102 USD from main pot with a pair of aces [ ad, ah, qs, 8h, 6c ]
|
||||
# Class for converting Everleaf HH format.
|
||||
|
||||
class Everleaf(HandHistoryConverter):
|
||||
|
||||
# Static regexes
|
||||
re_SplitHands = re.compile(r"\n\n+")
|
||||
re_GameInfo = re.compile(r".*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<LTYPE>(NL|PL)) (?P<GAME>(Hold\'em|Omaha|7 Card Stud))")
|
||||
re_HandInfo = re.compile(r".*#(?P<HID>[0-9]+)\n.*\nBlinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>.*) - (?P<DATETIME>\d\d\d\d/\d\d/\d\d - \d\d:\d\d:\d\d)\nTable (?P<TABLE>[- a-zA-Z]+)")
|
||||
re_Button = re.compile(r"^Seat (?P<BUTTON>\d+) is the button", re.MULTILINE)
|
||||
re_PlayerInfo = re.compile(r"^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\s+(\$ (?P<CASH>[.0-9]+) USD|new player|All-in) \)", re.MULTILINE)
|
||||
re_Board = re.compile(r"\[ (?P<CARDS>.+) \]")
|
||||
|
||||
|
||||
def __init__(self, config, file):
|
||||
print "Initialising Everleaf converter class"
|
||||
HandHistoryConverter.__init__(self, config, file, sitename="Everleaf") # Call super class init.
|
||||
self.sitename = "Everleaf"
|
||||
self.setFileType("text", "cp1252")
|
||||
self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)')
|
||||
self.rexx.setSplitHandRegex('\n\n+')
|
||||
self.rexx.setHandInfoRegex('.*#(?P<HID>[0-9]+)\n.*\nBlinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>.*) - (?P<DATETIME>\d\d\d\d/\d\d/\d\d - \d\d:\d\d:\d\d)\nTable (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
|
||||
self.rexx.setPlayerInfoRegex('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\s+(\$ (?P<CASH>[.0-9]+) USD|new player|All-in) \)')
|
||||
self.rexx.setPostSbRegex('.*\n(?P<PNAME>.*): posts small blind \[\$? (?P<SB>[.0-9]+)')
|
||||
self.rexx.setPostBbRegex('.*\n(?P<PNAME>.*): posts big blind \[\$? (?P<BB>[.0-9]+)')
|
||||
self.rexx.setPostBothRegex('.*\n(?P<PNAME>.*): posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)')
|
||||
self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<CARDS>.*) \]')
|
||||
self.rexx.setActionStepRegex('.*\n(?P<PNAME>.*)(?P<ATYPE>: bets| checks| raises| calls| folds)(\s\[\$ (?P<BET>[.\d]+) (USD|EUR)\])?')
|
||||
self.rexx.setShowdownActionRegex('.*\n(?P<PNAME>.*) shows \[ (?P<CARDS>.*) \]')
|
||||
self.rexx.setCollectPotRegex('.*\n(?P<PNAME>.*) wins \$ (?P<POT>[.\d]+) (USD|EUR)(.*?\[ (?P<CARDS>.*?) \])?')
|
||||
#self.rexx.setCollectPotRegex('.*\n(?P<PNAME>.*) wins \$ (?P<POT>[.\d]+) USD(.*\[ (?P<CARDS>) \S\S, \S\S, \S\S, \S\S, \S\S \])?')
|
||||
self.rexx.sits_out_re = re.compile('(?P<PNAME>.*) sits out')
|
||||
self.rexx.compileRegexes()
|
||||
|
||||
|
||||
try:
|
||||
self.ofile = os.path.join(self.hhdir, file.split(os.path.sep)[-2]+"-"+os.path.basename(file))
|
||||
except:
|
||||
self.ofile = os.path.join(self.hhdir, "x"+strftime("%d-%m-%y")+os.path.basename(file))
|
||||
|
||||
def compilePlayerRegexs(self):
|
||||
player_re = "(?P<PNAME>" + "|".join(map(re.escape, self.players)) + ")"
|
||||
#print "DEBUG player_re: " + player_re
|
||||
self.re_PostSB = re.compile(r"^%s: posts small blind \[\$? (?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_PostBB = re.compile(r"^%s: posts big blind \[\$? (?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_PostBoth = re.compile(r"^%s: posts both blinds \[\$? (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_HeroCards = re.compile(r"^Dealt to %s \[ (?P<CARDS>.*) \]" % player_re, re.MULTILINE)
|
||||
self.re_Action = re.compile(r"^%s(?P<ATYPE>: bets| checks| raises| calls| folds)(\s\[\$ (?P<BET>[.\d]+) (USD|EUR)\])?" % player_re, re.MULTILINE)
|
||||
self.re_ShowdownAction = re.compile(r"^%s shows \[ (?P<CARDS>.*) \]" % player_re, re.MULTILINE)
|
||||
self.re_CollectPot = re.compile(r"^%s wins \$ (?P<POT>[.\d]+) (USD|EUR)(.*?\[ (?P<CARDS>.*?) \])?" % player_re, re.MULTILINE)
|
||||
self.re_SitsOut = re.compile(r"^%s sits out" % player_re, re.MULTILINE)
|
||||
|
||||
def readSupportedGames(self):
|
||||
pass
|
||||
return [["ring", "hold", "nl"],
|
||||
["ring", "hold", "pl"],
|
||||
["ring", "omaha", "pl"]
|
||||
]
|
||||
|
||||
def determineGameType(self):
|
||||
# Cheating with this regex, only support nlhe at the moment
|
||||
gametype = ["ring", "hold", "nl"]
|
||||
# Blinds $0.50/$1 PL Omaha - 2008/12/07 - 21:59:48
|
||||
# Blinds $0.05/$0.10 NL Hold'em - 2009/02/21 - 11:21:57
|
||||
# $0.25/$0.50 7 Card Stud - 2008/12/05 - 21:43:59
|
||||
|
||||
m = self.rexx.game_info_re.search(self.obs)
|
||||
gametype = gametype + [m.group('SB')]
|
||||
gametype = gametype + [m.group('BB')]
|
||||
# Tourney:
|
||||
# Everleaf Gaming Game #75065769
|
||||
# ***** Hand history for game #75065769 *****
|
||||
# Blinds 10/20 NL Hold'em - 2009/02/25 - 17:30:32
|
||||
# Table 2
|
||||
|
||||
structure = "" # nl, pl, cn, cp, fl
|
||||
game = ""
|
||||
|
||||
m = self.re_GameInfo.search(self.obs)
|
||||
if m == None:
|
||||
return None
|
||||
if m.group('LTYPE') == "NL":
|
||||
structure = "nl"
|
||||
elif m.group('LTYPE') == "PL":
|
||||
structure = "pl"
|
||||
else:
|
||||
structure = "fl" # we don't support it, but there should be how to detect it at least.
|
||||
|
||||
if m.group('GAME') == "Hold\'em":
|
||||
game = "hold"
|
||||
elif m.group('GAME') == "Omaha":
|
||||
game = "omahahi"
|
||||
elif m.group('GAME') == "7 Card Stud":
|
||||
game = "studhi" # Everleaf currently only does Hi stud
|
||||
|
||||
gametype = ["ring", game, structure, m.group('SB'), m.group('BB')]
|
||||
|
||||
return gametype
|
||||
|
||||
def readHandInfo(self, hand):
|
||||
m = self.rexx.hand_info_re.search(hand.string)
|
||||
m = self.re_HandInfo.search(hand.string)
|
||||
if(m == None):
|
||||
print "DEBUG: re_HandInfo.search failed: '%s'" %(hand.string)
|
||||
hand.handid = m.group('HID')
|
||||
hand.tablename = m.group('TABLE')
|
||||
hand.max_seats = 6 # assume 6-max unless we have proof it's a larger/smaller game, since everleaf doesn't give seat max info
|
||||
# These work, but the info is already in the Hand class - should be used for tourneys though.
|
||||
# m.group('SB')
|
||||
# m.group('BB')
|
||||
|
@ -115,13 +121,16 @@ class Everleaf(HandHistoryConverter):
|
|||
#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 = time.strptime(m.group('DATETIME'), "%Y/%m/%d - %H:%M:%S")
|
||||
hand.buttonpos = int(m.group('BUTTON'))
|
||||
|
||||
def readPlayerStacks(self, hand):
|
||||
m = self.rexx.player_info_re.finditer(hand.string)
|
||||
players = []
|
||||
m = self.re_PlayerInfo.finditer(hand.string)
|
||||
for a in m:
|
||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
||||
seatnum = int(a.group('SEAT'))
|
||||
hand.addPlayer(seatnum, a.group('PNAME'), a.group('CASH'))
|
||||
if seatnum > 6:
|
||||
hand.max_seats = 10 # everleaf currently does 2/6/10 games, so if seats > 6 are in use, it must be 10-max.
|
||||
# TODO: implement lookup list by table-name to determine maxes, then fall back to 6 default/10 here, if there's no entry in the list?
|
||||
|
||||
|
||||
def markStreets(self, hand):
|
||||
# PREFLOP = ** Dealing down cards **
|
||||
|
@ -137,25 +146,29 @@ class Everleaf(HandHistoryConverter):
|
|||
|
||||
|
||||
def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand
|
||||
self.rexx.board_re = re.compile(r"\[ (?P<CARDS>.+) \]")
|
||||
print hand.streets.group(street)
|
||||
#print "DEBUG " + street + ":"
|
||||
#print hand.streets.group(street) + "\n"
|
||||
if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
|
||||
m = self.rexx.board_re.search(hand.streets.group(street))
|
||||
m = self.re_Board.search(hand.streets.group(street))
|
||||
hand.setCommunityCards(street, m.group('CARDS').split(', '))
|
||||
|
||||
def readBlinds(self, hand):
|
||||
try:
|
||||
m = self.rexx.small_blind_re.search(hand.string)
|
||||
m = self.re_PostSB.search(hand.string)
|
||||
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
|
||||
except: # no small blind
|
||||
except Exception, e: # no small blind
|
||||
#print e
|
||||
hand.addBlind(None, None, None)
|
||||
for a in self.rexx.big_blind_re.finditer(hand.string):
|
||||
for a in self.re_PostBB.finditer(hand.string):
|
||||
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
|
||||
for a in self.rexx.both_blinds_re.finditer(hand.string):
|
||||
hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB'))
|
||||
for a in self.re_PostBoth.finditer(hand.string):
|
||||
hand.addBlind(a.group('PNAME'), 'both', a.group('SBBB'))
|
||||
|
||||
def readButton(self, hand):
|
||||
hand.buttonpos = int(self.re_Button.search(hand.string).group('BUTTON'))
|
||||
|
||||
def readHeroCards(self, hand):
|
||||
m = self.rexx.hero_cards_re.search(hand.string)
|
||||
m = self.re_HeroCards.search(hand.string)
|
||||
if(m == None):
|
||||
#Not involved in hand
|
||||
hand.involved = False
|
||||
|
@ -168,7 +181,7 @@ class Everleaf(HandHistoryConverter):
|
|||
hand.addHoleCards(cards, m.group('PNAME'))
|
||||
|
||||
def readAction(self, hand, street):
|
||||
m = self.rexx.action_re.finditer(hand.streets.group(street))
|
||||
m = self.re_Action.finditer(hand.streets.group(street))
|
||||
for action in m:
|
||||
if action.group('ATYPE') == ' raises':
|
||||
hand.addCallandRaise( street, action.group('PNAME'), action.group('BET') )
|
||||
|
@ -185,17 +198,17 @@ class Everleaf(HandHistoryConverter):
|
|||
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
for shows in self.rexx.showdown_action_re.finditer(hand.string):
|
||||
for shows in self.re_ShowdownAction.finditer(hand.string):
|
||||
cards = shows.group('CARDS')
|
||||
cards = set(cards.split(', '))
|
||||
hand.addShownCards(cards, shows.group('PNAME'))
|
||||
|
||||
def readCollectPot(self,hand):
|
||||
for m in self.rexx.collect_pot_re.finditer(hand.string):
|
||||
for m in self.re_CollectPot.finditer(hand.string):
|
||||
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
|
||||
|
||||
def readShownCards(self,hand):
|
||||
for m in self.rexx.collect_pot_re.finditer(hand.string):
|
||||
for m in self.re_CollectPot.finditer(hand.string):
|
||||
if m.group('CARDS') is not None:
|
||||
cards = m.group('CARDS')
|
||||
cards = set(cards.split(', '))
|
||||
|
|
|
@ -20,94 +20,82 @@ import sys
|
|||
import Configuration
|
||||
from HandHistoryConverter import *
|
||||
|
||||
# FullTilt HH Format
|
||||
|
||||
#Full Tilt Poker Game #9403951181: Table CR - tay - $0.05/$0.10 - No Limit Hold'em - 9:40:20 ET - 2008/12/09
|
||||
#Seat 1: rigoise ($15.95)
|
||||
#Seat 2: K2dream ($6.70)
|
||||
#Seat 4: ravens2216 ($10)
|
||||
#Seat 5: rizkouner ($4)
|
||||
#Seat 6: Sorrowful ($8.35)
|
||||
#rigoise posts the small blind of $0.05
|
||||
#K2dream posts the big blind of $0.10
|
||||
#5 seconds left to act
|
||||
#rizkouner posts $0.10
|
||||
#The button is in seat #6
|
||||
#*** HOLE CARDS ***
|
||||
#Dealt to Sorrowful [8h Qc]
|
||||
#ravens2216 folds
|
||||
#rizkouner checks
|
||||
#Sorrowful has 15 seconds left to act
|
||||
#Sorrowful folds
|
||||
#rigoise folds
|
||||
#K2dream checks
|
||||
#*** FLOP *** [9d Kc 5c]
|
||||
#K2dream checks
|
||||
#rizkouner checks
|
||||
#*** TURN *** [9d Kc 5c] [5h]
|
||||
#K2dream has 15 seconds left to act
|
||||
#K2dream bets $0.20
|
||||
#rizkouner calls $0.20
|
||||
#*** RIVER *** [9d Kc 5c 5h] [6h]
|
||||
#K2dream checks
|
||||
#rizkouner has 15 seconds left to act
|
||||
#rizkouner bets $0.20
|
||||
#K2dream folds
|
||||
#Uncalled bet of $0.20 returned to rizkouner
|
||||
#rizkouner mucks
|
||||
#rizkouner wins the pot ($0.60)
|
||||
#*** SUMMARY ***
|
||||
#Total pot $0.65 | Rake $0.05
|
||||
#Board: [9d Kc 5c 5h 6h]
|
||||
#Seat 1: rigoise (small blind) folded before the Flop
|
||||
#Seat 2: K2dream (big blind) folded on the River
|
||||
#Seat 4: ravens2216 didn't bet (folded)
|
||||
#Seat 5: rizkouner collected ($0.60), mucked
|
||||
#Seat 6: Sorrowful (button) didn't bet (folded)
|
||||
#Seat N: rizkouner (button) showed [Jh Ah] and won ($0.70) with a pair of Threes
|
||||
# FullTilt HH Format converter
|
||||
|
||||
class FullTilt(HandHistoryConverter):
|
||||
|
||||
# Static regexes
|
||||
re_GameInfo = re.compile('- \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (Ante \$(?P<ANTE>[.0-9]+) )?- (?P<LTYPE>(No|Pot)? )?Limit (?P<GAME>(Hold\'em|Omaha|Razz))')
|
||||
re_SplitHands = re.compile(r"\n\n+")
|
||||
re_HandInfo = re.compile('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[- a-zA-Z]+) (\((?P<TABLEATTRIBUTES>.+)\) )?- \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (Ante \$(?P<ANTE>[.0-9]+) )?- (?P<GAMETYPE>[a-zA-Z\' ]+) - (?P<DATETIME>.*)')
|
||||
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
|
||||
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$(?P<CASH>[.0-9]+)\)\n')
|
||||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||
|
||||
def __init__(self, config, file):
|
||||
print "Initialising FullTilt converter class"
|
||||
HandHistoryConverter.__init__(self, config, file, sitename="FullTilt") # Call super class init.
|
||||
self.sitename = "FullTilt"
|
||||
self.setFileType("text", "cp1252")
|
||||
self.rexx.setGameInfoRegex('- \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) -')
|
||||
self.rexx.setSplitHandRegex('\n\n+')
|
||||
self.rexx.setHandInfoRegex('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[- a-zA-Z]+) (\((?P<TABLEATTRIBUTES>.+)\) )?- \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) - (?P<GAMETYPE>[a-zA-Z\' ]+) - (?P<DATETIME>.*)')
|
||||
# self.rexx.setHandInfoRegex('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[ a-zA-Z]+) - \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) - (?P<GAMETYPE>.*) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+) ET - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+)Table (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
|
||||
self.rexx.button_re = re.compile('The button is in seat #(?P<BUTTON>\d+)')
|
||||
self.rexx.setPlayerInfoRegex('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$(?P<CASH>[.0-9]+)\)\n')
|
||||
self.rexx.setPostSbRegex('.*\n(?P<PNAME>.*) posts the small blind of \$?(?P<SB>[.0-9]+)')
|
||||
self.rexx.setPostBbRegex('.*\n(?P<PNAME>.*) posts (the big blind of )?\$?(?P<BB>[.0-9]+)')
|
||||
self.rexx.setPostBothRegex('.*\n(?P<PNAME>.*) posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)')
|
||||
self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P<PNAME>.*)\s\[(?P<CARDS>.*)\]')
|
||||
self.rexx.setActionStepRegex('.*\n(?P<PNAME>.*)(?P<ATYPE> bets| checks| raises to| calls| folds)(\s\$(?P<BET>[.\d]+))?')
|
||||
self.rexx.setShowdownActionRegex('.*\n(?P<PNAME>.*) shows \[(?P<CARDS>.*)\]')
|
||||
self.rexx.setCollectPotRegex(r"Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*?) (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$(?P<POT>[.\d]+)\)(, mucked| with.*)")
|
||||
self.rexx.shown_cards_re = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(.*\) showed \[(?P<CARDS>.*)\].*')
|
||||
self.rexx.sits_out_re = re.compile('(?P<PNAME>.*) sits out')
|
||||
self.rexx.compileRegexes()
|
||||
|
||||
def compilePlayerRegexs(self):
|
||||
player_re = "(?P<PNAME>" + "|".join(map(re.escape, self.players)) + ")"
|
||||
print "DEBUG player_re: " + player_re
|
||||
self.re_PostSB = re.compile(r"^%s posts the small blind of \$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_PostBB = re.compile(r"^%s posts (the big blind of )?\$?(?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_Antes = re.compile(r"^%s antes \$?(?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_BringIn = re.compile(r"^%s brings in for \$?(?P<BRINGIN>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_PostBoth = re.compile(r"^%s posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_HeroCards = re.compile(r"^Dealt to %s \[(?P<CARDS>[AKQJT0-9hcsd ]+)\]( \[(?P<NEWCARD>[AKQJT0-9hcsd ]+)\])?" % player_re, re.MULTILINE)
|
||||
self.re_Action = re.compile(r"^%s(?P<ATYPE> bets| checks| raises to| calls| folds)(\s\$(?P<BET>[.\d]+))?" % player_re, re.MULTILINE)
|
||||
self.re_ShowdownAction = re.compile(r"^%s shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
|
||||
self.re_CollectPot = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$(?P<POT>[.\d]+)\)(, mucked| with.*)" % player_re, re.MULTILINE)
|
||||
self.re_SitsOut = re.compile(r"^%s sits out" % player_re, re.MULTILINE)
|
||||
self.re_ShownCards = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s \(.*\) showed \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
|
||||
|
||||
|
||||
def readSupportedGames(self):
|
||||
pass
|
||||
return [["ring", "hold", "nl"],
|
||||
["ring", "hold", "pl"],
|
||||
["ring", "razz", "fl"],
|
||||
["ring", "omaha", "pl"]
|
||||
]
|
||||
|
||||
def determineGameType(self):
|
||||
# Cheating with this regex, only support nlhe at the moment
|
||||
gametype = ["ring", "hold", "nl"]
|
||||
# Full Tilt Poker Game #10777181585: Table Deerfly (deep 6) - $0.01/$0.02 - Pot Limit Omaha Hi - 2:24:44 ET - 2009/02/22
|
||||
# Full Tilt Poker Game #10773265574: Table Butte (6 max) - $0.01/$0.02 - Pot Limit Hold'em - 21:33:46 ET - 2009/02/21
|
||||
# Full Tilt Poker Game #9403951181: Table CR - tay - $0.05/$0.10 - No Limit Hold'em - 9:40:20 ET - 2008/12/09
|
||||
structure = "" # nl, pl, cn, cp, fl
|
||||
game = ""
|
||||
|
||||
m = self.rexx.game_info_re.search(self.obs)
|
||||
gametype = gametype + [m.group('SB')]
|
||||
gametype = gametype + [m.group('BB')]
|
||||
|
||||
m = self.re_GameInfo.search(self.obs)
|
||||
if m.group('LTYPE') == "No ":
|
||||
structure = "nl"
|
||||
elif m.group('LTYPE') == "Pot ":
|
||||
structure = "pl"
|
||||
elif m.group('LTYPE') == None:
|
||||
structure = "fl"
|
||||
|
||||
if m.group('GAME') == "Hold\'em":
|
||||
game = "hold"
|
||||
elif m.group('GAME') == "Omaha":
|
||||
game = "omahahi"
|
||||
elif m.group('GAME') == "Razz":
|
||||
game = "razz"
|
||||
|
||||
print m.groups()
|
||||
|
||||
gametype = ["ring", game, structure, m.group('SB'), m.group('BB')]
|
||||
|
||||
return gametype
|
||||
|
||||
def readHandInfo(self, hand):
|
||||
m = self.rexx.hand_info_re.search(hand.string,re.DOTALL)
|
||||
m = self.re_HandInfo.search(hand.string,re.DOTALL)
|
||||
#print m.groups()
|
||||
hand.handid = m.group('HID')
|
||||
hand.tablename = m.group('TABLE')
|
||||
hand.buttonpos = int(self.rexx.button_re.search(hand.string).group('BUTTON'))
|
||||
hand.starttime = time.strptime(m.group('DATETIME'), "%H:%M:%S ET - %Y/%m/%d")
|
||||
# These work, but the info is already in the Hand class - should be used for tourneys though.
|
||||
# m.group('SB')
|
||||
|
@ -125,7 +113,7 @@ class FullTilt(HandHistoryConverter):
|
|||
#FIXME: hand.buttonpos = int(m.group('BUTTON'))
|
||||
|
||||
def readPlayerStacks(self, hand):
|
||||
m = self.rexx.player_info_re.finditer(hand.string)
|
||||
m = self.re_PlayerInfo.finditer(hand.string)
|
||||
players = []
|
||||
for a in m:
|
||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
||||
|
@ -134,34 +122,57 @@ class FullTilt(HandHistoryConverter):
|
|||
# PREFLOP = ** Dealing down cards **
|
||||
# This re fails if, say, river is missing; then we don't get the ** that starts the river.
|
||||
|
||||
if self.gametype[1] == "hold" or self.gametype[1] == "omaha":
|
||||
m = re.search(r"\*\*\* HOLE CARDS \*\*\*(?P<PREFLOP>.+(?=\*\*\* FLOP \*\*\*)|.+)"
|
||||
r"(\*\*\* FLOP \*\*\*(?P<FLOP> \[\S\S \S\S \S\S\].+(?=\*\*\* TURN \*\*\*)|.+))?"
|
||||
r"(\*\*\* TURN \*\*\* \[\S\S \S\S \S\S] (?P<TURN>\[\S\S\].+(?=\*\*\* RIVER \*\*\*)|.+))?"
|
||||
r"(\*\*\* RIVER \*\*\* \[\S\S \S\S \S\S \S\S] (?P<RIVER>\[\S\S\].+))?", hand.string,re.DOTALL)
|
||||
|
||||
elif self.gametype[1] == "razz":
|
||||
m = re.search(r"(?P<ANTES>.+(?=\*\*\* 3RD STREET \*\*\*)|.+)"
|
||||
r"(\*\*\* 3RD STREET \*\*\*(?P<THIRD>.+(?=\*\*\* 4TH STREET \*\*\*)|.+))?"
|
||||
r"(\*\*\* 4TH STREET \*\*\*(?P<FOURTH>.+(?=\*\*\* 5TH STREET \*\*\*)|.+))?"
|
||||
r"(\*\*\* 5TH STREET \*\*\*(?P<FIFTH>.+(?=\*\*\* 6TH STREET \*\*\*)|.+))?"
|
||||
r"(\*\*\* 6TH STREET \*\*\*(?P<SIXTH>.+(?=\*\*\* 7TH STREET \*\*\*)|.+))?"
|
||||
r"(\*\*\* 7TH STREET \*\*\*(?P<SEVENTH>.+))?", hand.string,re.DOTALL)
|
||||
hand.addStreets(m)
|
||||
|
||||
def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand
|
||||
if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
|
||||
self.rexx.board_re = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||
#print "DEBUG readCommunityCards:", street, hand.streets.group(street)
|
||||
m = self.rexx.board_re.search(hand.streets.group(street))
|
||||
m = self.re_Board.search(hand.streets.group(street))
|
||||
hand.setCommunityCards(street, m.group('CARDS').split(' '))
|
||||
|
||||
|
||||
def readBlinds(self, hand):
|
||||
try:
|
||||
m = self.rexx.small_blind_re.search(hand.string)
|
||||
m = self.re_PostSB.search(hand.string)
|
||||
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
|
||||
except: # no small blind
|
||||
hand.addBlind(None, None, None)
|
||||
for a in self.rexx.big_blind_re.finditer(hand.string):
|
||||
for a in self.re_PostBB.finditer(hand.string):
|
||||
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
|
||||
for a in self.rexx.both_blinds_re.finditer(hand.string):
|
||||
for a in self.re_PostBoth.finditer(hand.string):
|
||||
hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB'))
|
||||
|
||||
def readAntes(self, hand):
|
||||
print "DEBUG: reading antes"
|
||||
m = self.re_Antes.finditer(hand.string)
|
||||
for player in m:
|
||||
print "DEBUG: hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE'))
|
||||
hand.addAnte(player.group('PNAME'), player.group('ANTE'))
|
||||
|
||||
def readBringIn(self, hand):
|
||||
print "DEBUG: reading bring in"
|
||||
# print hand.string
|
||||
m = self.re_BringIn.search(hand.string,re.DOTALL)
|
||||
print "DEBUG: Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN'))
|
||||
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
|
||||
|
||||
def readButton(self, hand):
|
||||
hand.buttonpos = int(self.re_Button.search(hand.string).group('BUTTON'))
|
||||
|
||||
def readHeroCards(self, hand):
|
||||
m = self.rexx.hero_cards_re.search(hand.string)
|
||||
m = self.re_HeroCards.search(hand.string)
|
||||
if(m == None):
|
||||
#Not involved in hand
|
||||
hand.involved = False
|
||||
|
@ -173,8 +184,22 @@ class FullTilt(HandHistoryConverter):
|
|||
cards = set(cards.split(' '))
|
||||
hand.addHoleCards(cards, m.group('PNAME'))
|
||||
|
||||
def readPlayerCards(self, hand, street):
|
||||
#Used for stud hands - borrows the HeroCards regex for now.
|
||||
m = self.re_HeroCards.finditer(hand.streets.group(street))
|
||||
print "DEBUG: razz/stud readPlayerCards"
|
||||
print hand.streets.group(street)
|
||||
for player in m:
|
||||
print player.groups()
|
||||
cards = player.group('CARDS')
|
||||
if player.group('NEWCARD') != None:
|
||||
print cards
|
||||
cards = cards + " " + player.group('NEWCARD')
|
||||
cards = set(cards.split(' '))
|
||||
hand.addPlayerCards(cards, player.group('PNAME'))
|
||||
|
||||
def readAction(self, hand, street):
|
||||
m = self.rexx.action_re.finditer(hand.streets.group(street))
|
||||
m = self.re_Action.finditer(hand.streets.group(street))
|
||||
for action in m:
|
||||
if action.group('ATYPE') == ' raises to':
|
||||
hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') )
|
||||
|
@ -191,17 +216,17 @@ class FullTilt(HandHistoryConverter):
|
|||
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
for shows in self.rexx.showdown_action_re.finditer(hand.string):
|
||||
for shows in self.re_ShowdownAction.finditer(hand.string):
|
||||
cards = shows.group('CARDS')
|
||||
cards = set(cards.split(' '))
|
||||
hand.addShownCards(cards, shows.group('PNAME'))
|
||||
|
||||
def readCollectPot(self,hand):
|
||||
for m in self.rexx.collect_pot_re.finditer(hand.string):
|
||||
for m in self.re_CollectPot.finditer(hand.string):
|
||||
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
|
||||
|
||||
def readShownCards(self,hand):
|
||||
for m in self.rexx.shown_cards_re.finditer(hand.string):
|
||||
for m in self.re_ShownCards.finditer(hand.string):
|
||||
if m.group('CARDS') is not None:
|
||||
cards = m.group('CARDS')
|
||||
cards = set(cards.split(' '))
|
||||
|
@ -211,7 +236,7 @@ class FullTilt(HandHistoryConverter):
|
|||
if __name__ == "__main__":
|
||||
c = Configuration.Config()
|
||||
if len(sys.argv) == 1:
|
||||
testfile = "regression-test-files/FT20081209 CR - tay - $0.05-$0.10 - No Limit Hold'em.txt"
|
||||
testfile = "regression-test-files/fulltilt/razz/FT20090223 Danville - $0.50-$1 Ante $0.10 - Limit Razz.txt"
|
||||
else:
|
||||
testfile = sys.argv[1]
|
||||
print "Converting: ", testfile
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
|
||||
# Standard Library modules
|
||||
import os
|
||||
import sys
|
||||
from time import time
|
||||
from optparse import OptionParser
|
||||
|
||||
# pyGTK modules
|
||||
import pygtk
|
||||
|
@ -64,14 +66,15 @@ class GuiBulkImport():
|
|||
self.importer.setDropIndexes(cb_model[cb_index][0])
|
||||
else:
|
||||
self.importer.setDropIndexes("auto")
|
||||
|
||||
hhc=self.cbfilter.get_model()[self.cbfilter.get_active()][0]
|
||||
self.lab_info.set_text("Importing")
|
||||
if os.path.isdir(self.inputFile):
|
||||
self.import_dir()
|
||||
else:
|
||||
self.importer.addImportFile(self.inputFile)
|
||||
|
||||
self.importer.addBulkImportImportFileOrDir(self.inputFile,filter=hhc)
|
||||
self.importer.setCallHud(False)
|
||||
self.importer.runImport()
|
||||
starttime = time()
|
||||
(stored, dups, partial, errs, ttime) = self.importer.runImport()
|
||||
print 'GuiBulkImport.import_dir done: Stored: %d Duplicates: %d Partial: %d Errors: %d in %s seconds - %d/sec'\
|
||||
% (stored, dups, partial, errs, ttime, stored / ttime)
|
||||
self.importer.clearFileList()
|
||||
|
||||
self.lab_info.set_text("Import finished")
|
||||
|
@ -164,6 +167,20 @@ class GuiBulkImport():
|
|||
self.table.attach(self.cb, 4, 5, 1, 2, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK)
|
||||
self.cb.show()
|
||||
|
||||
# label - filter
|
||||
self.lab_filter = gtk.Label("Site filter:")
|
||||
self.table.attach(self.lab_filter, 2, 3, 2, 3, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK)
|
||||
self.lab_filter.show()
|
||||
self.lab_filter.set_justify(gtk.JUSTIFY_RIGHT)
|
||||
|
||||
# ComboBox - filter
|
||||
self.cbfilter = gtk.combo_box_new_text()
|
||||
self.cbfilter.append_text("passthrough")
|
||||
self.cbfilter.append_text("Everleaf")
|
||||
self.cbfilter.set_active(0)
|
||||
self.table.attach(self.cbfilter, 3, 4, 2, 3, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK)
|
||||
self.cbfilter.show()
|
||||
|
||||
# label - info
|
||||
self.lab_info = gtk.Label()
|
||||
self.table.attach(self.lab_info, 0, 4, 2, 3, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK)
|
||||
|
@ -199,6 +216,12 @@ if __name__ == '__main__':
|
|||
def destroy(*args): # call back for terminating the main eventloop
|
||||
gtk.main_quit()
|
||||
|
||||
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")
|
||||
|
||||
(options, sys.argv) = parser.parse_args()
|
||||
|
||||
config = Configuration.Config()
|
||||
db = fpdb_db.fpdb_db()
|
||||
|
||||
|
@ -211,9 +234,19 @@ if __name__ == '__main__':
|
|||
settings.update(config.get_import_parameters())
|
||||
settings.update(config.get_default_paths())
|
||||
|
||||
if(options.gui == True):
|
||||
i = GuiBulkImport(db, settings, config)
|
||||
main_window = gtk.Window()
|
||||
main_window.connect('destroy', destroy)
|
||||
main_window.add(i.vbox)
|
||||
main_window.show()
|
||||
gtk.main()
|
||||
else:
|
||||
#Do something useful
|
||||
importer = fpdb_import.Importer(False,settings, config)
|
||||
importer.setDropIndexes("auto")
|
||||
importer.setFailOnError(True)
|
||||
importer.addImportFile(options.filename)
|
||||
importer.setCallHud(False)
|
||||
importer.runImport()
|
||||
importer.clearFileList()
|
||||
|
|
240
pyfpdb/Hand.py
240
pyfpdb/Hand.py
|
@ -39,7 +39,10 @@ class Hand:
|
|||
self.gametype = gametype
|
||||
self.string = string
|
||||
|
||||
if gametype[1] == "hold" or self.gametype[1] == "omaha":
|
||||
self.streetList = ['PREFLOP','FLOP','TURN','RIVER'] # a list of the observed street names in order
|
||||
elif self.gametype[1] == "razz" or self.gametype[1] == "stud" or self.gametype[1] == "stud8":
|
||||
self.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order
|
||||
|
||||
self.handid = 0
|
||||
self.sb = gametype[3]
|
||||
|
@ -83,7 +86,8 @@ class Hand:
|
|||
self.stacks = {}
|
||||
|
||||
# dict from player names to amounts collected
|
||||
self.collected = {}
|
||||
self.collected = []
|
||||
self.collectees = {}
|
||||
|
||||
# Sets of players
|
||||
self.shown = set()
|
||||
|
@ -134,7 +138,23 @@ Assigns observed holecards to a player.
|
|||
cards set of card bigrams e.g. set(['2h','Jc'])
|
||||
player (string) name of player
|
||||
"""
|
||||
print "DEBUG: addHoleCards", cards,player
|
||||
#print "DEBUG: addHoleCards", cards,player
|
||||
try:
|
||||
self.checkPlayerExists(player)
|
||||
cards = set([self.card(c) for c in cards])
|
||||
self.holecards[player].update(cards)
|
||||
except FpdbParseError, e:
|
||||
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
|
||||
|
||||
def addPlayerCards(self, cards, player):
|
||||
"""\
|
||||
Assigns observed cards to a player.
|
||||
cards set of card bigrams e.g. set(['2h','Jc'])
|
||||
player (string) name of player
|
||||
|
||||
Should probably be merged with addHoleCards
|
||||
"""
|
||||
print "DEBUG: addPlayerCards", cards,player
|
||||
try:
|
||||
self.checkPlayerExists(player)
|
||||
cards = set([self.card(c) for c in cards])
|
||||
|
@ -147,7 +167,7 @@ player (string) name of player
|
|||
For when a player shows cards for any reason (for showdown or out of choice).
|
||||
Card ranks will be uppercased
|
||||
"""
|
||||
print "DEBUG: addShownCards", cards,player,holeandboard
|
||||
#print "DEBUG: addShownCards", cards,player,holeandboard
|
||||
if cards is not None:
|
||||
self.shown.add(player)
|
||||
self.addHoleCards(cards,player)
|
||||
|
@ -159,6 +179,7 @@ Card ranks will be uppercased
|
|||
|
||||
def checkPlayerExists(self,player):
|
||||
if player not in [p[1] for p in self.players]:
|
||||
print "checkPlayerExists", player, "fail"
|
||||
raise FpdbParseError
|
||||
|
||||
def discardHoleCards(self, cards, player):
|
||||
|
@ -180,6 +201,14 @@ Card ranks will be uppercased
|
|||
c = c.replace(k,v)
|
||||
return c
|
||||
|
||||
def addAnte(self, player, ante):
|
||||
if player is not None:
|
||||
self.bets['ANTES'][player].append(Decimal(ante))
|
||||
self.stacks[player] -= Decimal(ante)
|
||||
act = (player, 'posts', "ante", ante, self.stacks[player]==0)
|
||||
self.actions['ANTES'].append(act)
|
||||
self.pot.addMoney(player, Decimal(ante))
|
||||
|
||||
def addBlind(self, player, blindtype, amount):
|
||||
# if player is None, it's a missing small blind.
|
||||
# TODO:
|
||||
|
@ -190,9 +219,9 @@ Card ranks will be uppercased
|
|||
# - this is a bet of 1 bb and is the new uncalled
|
||||
#
|
||||
# If a player posts a big & small blind
|
||||
#
|
||||
# - FIXME: We dont record this for later printing yet
|
||||
|
||||
print "DEBUG addBlind: %s posts %s, %s" % (player, blindtype, amount)
|
||||
#print "DEBUG addBlind: %s posts %s, %s" % (player, blindtype, amount)
|
||||
if player is not None:
|
||||
self.bets['PREFLOP'][player].append(Decimal(amount))
|
||||
self.stacks[player] -= Decimal(amount)
|
||||
|
@ -202,10 +231,19 @@ Card ranks will be uppercased
|
|||
self.pot.addMoney(player, Decimal(amount))
|
||||
if blindtype == 'big blind':
|
||||
self.lastBet['PREFLOP'] = Decimal(amount)
|
||||
elif blindtype == 'small & big blinds':
|
||||
elif blindtype == 'both':
|
||||
# extra small blind is 'dead'
|
||||
self.lastBet['PREFLOP'] = Decimal(self.bb)
|
||||
self.posted += [player]
|
||||
self.posted = self.posted + [[player,blindtype]]
|
||||
#print "DEBUG: self.posted: %s" %(self.posted)
|
||||
|
||||
def addBringIn(self, player, ante):
|
||||
if player is not None:
|
||||
self.bets['THIRD'][player].append(Decimal(ante))
|
||||
self.stacks[player] -= Decimal(ante)
|
||||
act = (player, 'bringin', "bringin", ante, self.stacks[player]==0)
|
||||
self.actions['THIRD'].append(act)
|
||||
self.pot.addMoney(player, Decimal(ante))
|
||||
|
||||
|
||||
def addCall(self, street, player=None, amount=None):
|
||||
|
@ -215,7 +253,7 @@ Card ranks will be uppercased
|
|||
self.bets[street][player].append(Decimal(amount))
|
||||
#self.lastBet[street] = Decimal(amount)
|
||||
self.stacks[player] -= Decimal(amount)
|
||||
print "DEBUG %s calls %s, stack %s" % (player, amount, self.stacks[player])
|
||||
#print "DEBUG %s calls %s, stack %s" % (player, amount, self.stacks[player])
|
||||
act = (player, 'calls', amount, self.stacks[player]==0)
|
||||
self.actions[street].append(act)
|
||||
self.pot.addMoney(player, Decimal(amount))
|
||||
|
@ -264,7 +302,9 @@ For sites which by "raises x" mean "calls and raises putting a total of x in the
|
|||
"""\
|
||||
Add a raise on [street] by [player] to [amountTo]
|
||||
"""
|
||||
#CG - No idea if this function has been test/verified
|
||||
self.checkPlayerExists(player)
|
||||
Bp = self.lastBet[street]
|
||||
Bc = reduce(operator.add, self.bets[street][player], 0)
|
||||
Rt = Decimal(amountTo)
|
||||
C = Bp - Bc
|
||||
|
@ -285,7 +325,7 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
self.checkPlayerExists(player)
|
||||
self.bets[street][player].append(Decimal(amount))
|
||||
self.stacks[player] -= Decimal(amount)
|
||||
print "DEBUG %s bets %s, stack %s" % (player, amount, self.stacks[player])
|
||||
#print "DEBUG %s bets %s, stack %s" % (player, amount, self.stacks[player])
|
||||
act = (player, 'bets', amount, self.stacks[player]==0)
|
||||
self.actions[street].append(act)
|
||||
self.lastBet[street] = Decimal(amount)
|
||||
|
@ -293,7 +333,7 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
|
||||
|
||||
def addFold(self, street, player):
|
||||
print "DEBUG: %s %s folded" % (street, player)
|
||||
#print "DEBUG: %s %s folded" % (street, player)
|
||||
self.checkPlayerExists(player)
|
||||
self.folded.add(player)
|
||||
self.pot.addFold(player)
|
||||
|
@ -301,17 +341,19 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
|
||||
|
||||
def addCheck(self, street, player):
|
||||
print "DEBUG: %s %s checked" % (street, player)
|
||||
#print "DEBUG: %s %s checked" % (street, player)
|
||||
self.checkPlayerExists(player)
|
||||
self.actions[street].append((player, 'checks'))
|
||||
|
||||
|
||||
def addCollectPot(self,player, pot):
|
||||
print "DEBUG: %s collected %s" % (player, pot)
|
||||
#print "DEBUG: %s collected %s" % (player, pot)
|
||||
self.checkPlayerExists(player)
|
||||
if player not in self.collected:
|
||||
self.collected[player] = pot
|
||||
self.collected = self.collected + [[player, pot]]
|
||||
if player not in self.collectees:
|
||||
self.collectees[player] = Decimal(pot)
|
||||
else:
|
||||
print "[WARNING] %s collected pot more than once; avoidable by reading winnings only from summary lines?"
|
||||
self.collectees[player] += Decimal(pot)
|
||||
|
||||
|
||||
def totalPot(self):
|
||||
|
@ -325,8 +367,9 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
# This gives us the amount collected, i.e. after rake
|
||||
if self.totalcollected is None:
|
||||
self.totalcollected = 0;
|
||||
for amount in self.collected.values():
|
||||
self.totalcollected += Decimal(amount)
|
||||
#self.collected looks like [[p1,amount][px,amount]]
|
||||
for entry in self.collected:
|
||||
self.totalcollected += Decimal(entry[1])
|
||||
|
||||
|
||||
|
||||
|
@ -337,7 +380,7 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
|||
"""
|
||||
# currently it appears to be something like ["ring", "hold", "nl", sb, bb]:
|
||||
gs = {"hold" : "Hold'em",
|
||||
"omahahi" : "FIXME",
|
||||
"omahahi" : "Omaha",
|
||||
"omahahilo" : "FIXME",
|
||||
"razz" : "Razz",
|
||||
"studhi" : "FIXME",
|
||||
|
@ -354,11 +397,19 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
|||
"cp" : "Cap Pot Limit"
|
||||
}
|
||||
|
||||
print "DEBUG: self.gametype: %s" %(self.gametype)
|
||||
string = "%s %s" %(gs[self.gametype[1]], ls[self.gametype[2]])
|
||||
|
||||
return string
|
||||
|
||||
def writeHand(self, fh=sys.__stdout__):
|
||||
if self.gametype[1] == "hold" or self.gametype[1] == "omaha":
|
||||
self.writeHoldemHand(fh)
|
||||
else:
|
||||
self.writeStudHand(fh)
|
||||
|
||||
|
||||
def writeHoldemHand(self, fh=sys.__stdout__):
|
||||
# PokerStars format.
|
||||
#print "\n### Pseudo stars format ###"
|
||||
#print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %(self.sitename, self.handid, self.getGameTypeAsString(), self.sb, self.bb, self.starttime))
|
||||
|
@ -371,17 +422,15 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
|||
#Only print stacks of players who do something preflop
|
||||
print >>fh, _("Seat %s: %s ($%s)" %(player[0], player[1], player[2]))
|
||||
|
||||
if(self.posted[0] is None):
|
||||
#print >>fh, _("No small blind posted") # PS doesn't say this
|
||||
pass
|
||||
else:
|
||||
print >>fh, _("%s: posts small blind $%s" %(self.posted[0], self.sb))
|
||||
|
||||
#May be more than 1 bb posting
|
||||
for a in self.posted[1:]:
|
||||
print >>fh, _("%s: posts big blind $%s" %(self.posted[1], self.bb))
|
||||
|
||||
# TODO: What about big & small blinds?
|
||||
for a in self.posted:
|
||||
if(a[1] == "small blind"):
|
||||
print >>fh, _("%s: posts small blind $%s" %(a[0], self.sb))
|
||||
if(a[1] == "big blind"):
|
||||
print >>fh, _("%s: posts big blind $%s" %(a[0], self.bb))
|
||||
if(a[1] == "both"):
|
||||
print >>fh, _("%s: posts small & big blinds $%.2f" %(a[0], (Decimal(self.sb) + Decimal(self.bb))))
|
||||
|
||||
print >>fh, _("*** HOLE CARDS ***")
|
||||
if self.involved:
|
||||
|
@ -412,7 +461,123 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
|||
# we probably don't need a showdown section in pseudo stars format for our filtering purposes
|
||||
if 'SHOWDOWN' in self.actions:
|
||||
print >>fh, _("*** SHOW DOWN ***")
|
||||
print >>fh, "DEBUG: what do they show"
|
||||
#TODO: Complete SHOWDOWN
|
||||
|
||||
# Current PS format has the lines:
|
||||
# Uncalled bet ($111.25) returned to s0rrow
|
||||
# s0rrow collected $5.15 from side pot
|
||||
# stervels: shows [Ks Qs] (two pair, Kings and Queens)
|
||||
# stervels collected $45.35 from main pot
|
||||
# Immediately before the summary.
|
||||
# The current importer uses those lines for importing winning rather than the summary
|
||||
for name in self.pot.returned:
|
||||
print >>fh, _("Uncalled bet ($%s) returned to %s" %(self.pot.returned[name],name))
|
||||
for entry in self.collected:
|
||||
print >>fh, _("%s collected $%s from x pot" %(entry[0], entry[1]))
|
||||
|
||||
print >>fh, _("*** SUMMARY ***")
|
||||
print >>fh, "%s | Rake $%.2f" % (self.pot, self.rake)
|
||||
|
||||
board = []
|
||||
for s in self.board.values():
|
||||
board += s
|
||||
if board: # sometimes hand ends preflop without a board
|
||||
print >>fh, _("Board [%s]" % (" ".join(board)))
|
||||
|
||||
for player in [x for x in self.players if x[1] in players_who_act_preflop]:
|
||||
seatnum = player[0]
|
||||
name = player[1]
|
||||
if name in self.collectees and name in self.shown:
|
||||
print >>fh, _("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards[name]), self.collectees[name]))
|
||||
elif name in self.collectees:
|
||||
print >>fh, _("Seat %d: %s collected ($%s)" % (seatnum, name, self.collectees[name]))
|
||||
elif name in self.shown:
|
||||
print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, " ".join(self.holecards[name])))
|
||||
elif name in self.folded:
|
||||
print >>fh, _("Seat %d: %s folded" % (seatnum, name))
|
||||
else:
|
||||
print >>fh, _("Seat %d: %s mucked" % (seatnum, name))
|
||||
|
||||
print >>fh, "\n\n"
|
||||
# TODO:
|
||||
# logic for side pots
|
||||
# logic for which players get to showdown
|
||||
# I'm just not sure we need to do this so heavily.. and if we do, it's probably better to use pokerlib
|
||||
#if self.holecards[player[1]]: # empty list default is false
|
||||
#hole = self.holecards[player[1]]
|
||||
##board = []
|
||||
##for s in self.board.values():
|
||||
##board += s
|
||||
##playerhand = self.bestHand('hi', board+hole)
|
||||
##print "Seat %d: %s showed %s and won/lost with %s" % (player[0], player[1], hole, playerhand)
|
||||
#print "Seat %d: %s showed %s" % (player[0], player[1], hole)
|
||||
#else:
|
||||
#print "Seat %d: %s mucked or folded" % (player[0], player[1])
|
||||
|
||||
|
||||
def writeStudHand(self, fh=sys.__stdout__):
|
||||
# PokerStars format.
|
||||
#print "\n### Pseudo stars format ###"
|
||||
#print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %(self.sitename, self.handid, self.getGameTypeAsString(), self.sb, self.bb, self.starttime))
|
||||
print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d - %H:%M:%S (ET)', self.starttime)))
|
||||
print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos))
|
||||
|
||||
players_who_post_antes = set([x[0] for x in self.actions['ANTES']])
|
||||
|
||||
for player in [x for x in self.players if x[1] in players_who_post_antes]:
|
||||
#Only print stacks of players who do something preflop
|
||||
print >>fh, _("Seat %s: %s ($%s)" %(player[0], player[1], player[2]))
|
||||
|
||||
if 'ANTES' in self.actions:
|
||||
for act in self.actions['ANTES']:
|
||||
print >>fh, _("%s: posts the ante $%s" %(act[0], act[3]))
|
||||
|
||||
if 'THIRD' in self.actions:
|
||||
print >>fh, _("*** 3RD STREET ***")
|
||||
for player in [x for x in self.players if x[1] in players_who_post_antes]:
|
||||
print >>fh, _("Dealt to ")
|
||||
for act in self.actions['THIRD']:
|
||||
#FIXME: Need some logic here for bringin vs completes
|
||||
self.printActionLine(act, fh)
|
||||
|
||||
if 'FOURTH' in self.actions:
|
||||
print >>fh, _("*** 4TH STREET ***")
|
||||
for act in self.actions['FOURTH']:
|
||||
self.printActionLine(act, fh)
|
||||
|
||||
if 'FIFTH' in self.actions:
|
||||
print >>fh, _("*** 5TH STREET ***")
|
||||
for act in self.actions['FIFTH']:
|
||||
self.printActionLine(act, fh)
|
||||
|
||||
if 'SIXTH' in self.actions:
|
||||
print >>fh, _("*** 6TH STREET ***")
|
||||
for act in self.actions['SIXTH']:
|
||||
self.printActionLine(act, fh)
|
||||
|
||||
if 'SEVENTH' in self.actions:
|
||||
print >>fh, _("*** 7TH STREET ***")
|
||||
for act in self.actions['SEVENTH']:
|
||||
self.printActionLine(act, fh)
|
||||
|
||||
#Some sites don't have a showdown section so we have to figure out if there should be one
|
||||
# The logic for a showdown is: at the end of river action there are at least two players in the hand
|
||||
# we probably don't need a showdown section in pseudo stars format for our filtering purposes
|
||||
if 'SHOWDOWN' in self.actions:
|
||||
print >>fh, _("*** SHOW DOWN ***")
|
||||
# print >>fh, "DEBUG: what do they show"
|
||||
|
||||
# Current PS format has the lines:
|
||||
# Uncalled bet ($111.25) returned to s0rrow
|
||||
# s0rrow collected $5.15 from side pot
|
||||
# stervels: shows [Ks Qs] (two pair, Kings and Queens)
|
||||
# stervels collected $45.35 from main pot
|
||||
# Immediately before the summary.
|
||||
# The current importer uses those lines for importing winning rather than the summary
|
||||
for name in self.pot.returned:
|
||||
print >>fh, _("Uncalled bet ($%s) returned to %s" %(self.pot.returned[name],name))
|
||||
for entry in self.collected:
|
||||
print >>fh, _("%s collected $%s from x pot" %(entry[0], entry[1]))
|
||||
|
||||
print >>fh, _("*** SUMMARY ***")
|
||||
print >>fh, "%s | Rake $%.2f" % (self.pot, self.rake)
|
||||
|
@ -424,13 +589,13 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
|||
if board: # sometimes hand ends preflop without a board
|
||||
print >>fh, _("Board [%s]" % (" ".join(board)))
|
||||
|
||||
for player in [x for x in self.players if x[1] in players_who_act_preflop]:
|
||||
for player in [x for x in self.players if x[1] in players_who_post_antes]:
|
||||
seatnum = player[0]
|
||||
name = player[1]
|
||||
if name in self.collected and name in self.shown:
|
||||
print >>fh, _("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards[name]), self.collected[name]))
|
||||
elif name in self.collected:
|
||||
print >>fh, _("Seat %d: %s collected ($%s)" % (seatnum, name, self.collected[name]))
|
||||
if name in self.collectees and name in self.shown:
|
||||
print >>fh, _("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards[name]), self.collectees[name]))
|
||||
elif name in self.collectees:
|
||||
print >>fh, _("Seat %d: %s collected ($%s)" % (seatnum, name, self.collectees[name]))
|
||||
elif name in self.shown:
|
||||
print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, " ".join(self.holecards[name])))
|
||||
elif name in self.folded:
|
||||
|
@ -518,6 +683,7 @@ class Pot(object):
|
|||
self.contenders = set()
|
||||
self.committed = {}
|
||||
self.total = None
|
||||
self.returned = {}
|
||||
|
||||
def addPlayer(self,player):
|
||||
self.committed[player] = Decimal(0)
|
||||
|
@ -539,9 +705,10 @@ class Pot(object):
|
|||
lastbet = committed[-1][0] - committed[-2][0]
|
||||
if lastbet > 0: # uncalled
|
||||
returnto = committed[-1][1]
|
||||
#print "returning %f to %s" % (lastbet, returnto)
|
||||
#print "DEBUG: returning %f to %s" % (lastbet, returnto)
|
||||
self.total -= lastbet
|
||||
self.committed[returnto] -= lastbet
|
||||
self.returned[returnto] = lastbet
|
||||
|
||||
|
||||
# Work out side pots
|
||||
|
@ -575,8 +742,11 @@ class Pot(object):
|
|||
return "Total pot $%.2f Main pot $%.2f. Side pot $%2.f." % (self.total, self.pots[0], self.pots[1])
|
||||
elif len(self.pots) == 3:
|
||||
return "Total pot $%.2f Main pot $%.2f. Side pot-1 $%2.2f. Side pot-2 $%.2f." % (self.total, self.pots[0], self.pots[1], self.pots[2])
|
||||
elif len(self.pots) == 0:
|
||||
# no small blind and walk in bb (hopefully)
|
||||
return "Total pot $%.2f" % (self.total,)
|
||||
else:
|
||||
return "maybe no pot.. or too many pots.. no small blind and walk in bb?."
|
||||
return _("too many pots.. no small blind and walk in bb?. self.pots: %s" %(self.pots))
|
||||
# I don't know stars format for a walk in the bb when sb doesn't post.
|
||||
# The thing to do here is raise a Hand error like fpdb import does and file it into errors.txt
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import codecs
|
|||
from decimal import Decimal
|
||||
import operator
|
||||
from xml.dom.minidom import Node
|
||||
from pokereval import PokerEval
|
||||
# from pokereval import PokerEval
|
||||
import time
|
||||
import datetime
|
||||
import gettext
|
||||
|
@ -74,7 +74,7 @@ gettext.install('myapplication')
|
|||
|
||||
|
||||
class HandHistoryConverter:
|
||||
eval = PokerEval()
|
||||
# eval = PokerEval()
|
||||
def __init__(self, config, file, sitename):
|
||||
print "HandHistory init called"
|
||||
self.c = config
|
||||
|
@ -88,8 +88,10 @@ class HandHistoryConverter:
|
|||
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.ofile = os.path.join(self.hhdir, os.path.basename(file))
|
||||
self.rexx = FpdbRegex.FpdbRegex()
|
||||
self.players = set()
|
||||
self.maxseats = 10
|
||||
|
||||
def __str__(self):
|
||||
tmp = "HandHistoryConverter: '%s'\n" % (self.sitename)
|
||||
|
@ -97,11 +99,11 @@ class HandHistoryConverter:
|
|||
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])
|
||||
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):
|
||||
|
@ -110,23 +112,54 @@ class HandHistoryConverter:
|
|||
print "Cowardly refusing to continue after failed sanity check"
|
||||
return
|
||||
self.readFile(self.file)
|
||||
if self.obs == "" or self.obs == None:
|
||||
print "Did not read anything from file."
|
||||
return
|
||||
|
||||
self.obs = self.obs.replace('\r\n', '\n')
|
||||
self.gametype = self.determineGameType()
|
||||
if self.gametype == None:
|
||||
print "Unknown game type from file, aborting on this file."
|
||||
return
|
||||
self.hands = self.splitFileIntoHands()
|
||||
outfile = open(self.ofile, 'w')
|
||||
for hand in self.hands:
|
||||
print "\nInput:\n"+hand.string
|
||||
#print "\nDEBUG: Input:\n"+hand.string
|
||||
self.readHandInfo(hand)
|
||||
|
||||
self.readPlayerStacks(hand)
|
||||
print "DEBUG stacks:", hand.stacks
|
||||
#print "DEBUG stacks:", hand.stacks
|
||||
# at this point we know the player names, they are in hand.players
|
||||
playersThisHand = set([player[1] for player in hand.players])
|
||||
if playersThisHand <= self.players: # x <= y means 'x is subset of y'
|
||||
# we're ok; the regex should already cover them all.
|
||||
pass
|
||||
else:
|
||||
# we need to recompile the player regexs.
|
||||
self.players = playersThisHand
|
||||
self.compilePlayerRegexs()
|
||||
|
||||
self.markStreets(hand)
|
||||
# Different calls if stud or holdem like
|
||||
if self.gametype[1] == "hold" or self.gametype[1] == "omaha":
|
||||
self.readBlinds(hand)
|
||||
self.readButton(hand)
|
||||
self.readHeroCards(hand) # want to generalise to draw games
|
||||
elif self.gametype[1] == "razz" or self.gametype[1] == "stud" or self.gametype[1] == "stud8":
|
||||
self.readAntes(hand)
|
||||
self.readBringIn(hand)
|
||||
|
||||
self.readShowdownActions(hand)
|
||||
|
||||
# Read actions in street order
|
||||
for street in hand.streetList: # go through them in order
|
||||
print "DEBUG: ", street
|
||||
if hand.streets.group(street) is not None:
|
||||
if self.gametype[1] == "hold" or self.gametype[1] == "omaha":
|
||||
self.readCommunityCards(hand, street) # read community cards
|
||||
elif self.gametype[1] == "razz" or self.gametype[1] == "stud" or self.gametype[1] == "stud8":
|
||||
self.readPlayerCards(hand, street)
|
||||
|
||||
self.readAction(hand, street)
|
||||
|
||||
|
||||
|
@ -137,19 +170,22 @@ class HandHistoryConverter:
|
|||
hand.totalPot()
|
||||
self.getRake(hand)
|
||||
|
||||
hand.writeHand(sys.stderr)
|
||||
hand.writeHand(outfile)
|
||||
#if(hand.involved == True):
|
||||
#self.writeHand("output file", hand)
|
||||
#hand.printHand()
|
||||
#else:
|
||||
#pass #Don't write out observed hands
|
||||
|
||||
outfile.close()
|
||||
endtime = time.time()
|
||||
print "Processed %d hands in %d seconds" % (len(self.hands), endtime-starttime)
|
||||
print "Processed %d hands in %.3f seconds" % (len(self.hands), endtime - starttime)
|
||||
|
||||
#####
|
||||
# These functions are parse actions that may be overridden by the inheriting class
|
||||
#
|
||||
# This function should return a list of lists looking like:
|
||||
# return [["ring", "hold", "nl"], ["tour", "hold", "nl"]]
|
||||
# Showing all supported games limits and types
|
||||
|
||||
def readSupportedGames(self): abstract
|
||||
|
||||
|
@ -173,6 +209,9 @@ class HandHistoryConverter:
|
|||
# [['seat#', 'player1name', 'stacksize'] ['seat#', 'player2name', 'stacksize'] [...]]
|
||||
def readPlayerStacks(self, hand): abstract
|
||||
|
||||
def compilePlayerRegexs(self): abstract
|
||||
"""Compile dynamic regexes -- these explicitly match known player names and must be updated if a new player joins"""
|
||||
|
||||
# Needs to return a MatchObject with group names identifying the streets into the Hand object
|
||||
# so groups are called by street names 'PREFLOP', 'FLOP', 'STREET2' etc
|
||||
# blinds are done seperately
|
||||
|
@ -182,7 +221,11 @@ class HandHistoryConverter:
|
|||
# ['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 readAntes(self, hand): abstract
|
||||
def readBringIn(self, hand): abstract
|
||||
def readButton(self, hand): abstract
|
||||
def readHeroCards(self, hand): abstract
|
||||
def readPlayerCards(self, hand, street): abstract
|
||||
def readAction(self, hand, street): abstract
|
||||
def readCollectPot(self, hand): abstract
|
||||
def readShownCards(self, hand): abstract
|
||||
|
@ -212,6 +255,10 @@ class HandHistoryConverter:
|
|||
else:
|
||||
print "HH Sanity Check: Directory hhdir '" + self.hhdir + "' or its parent directory are not writable"
|
||||
|
||||
# Make sure input and output files are different or we'll overwrite the source file
|
||||
if(self.ofile == self.file):
|
||||
print "HH Sanity Check: output and input files are the same, check config"
|
||||
|
||||
return sane
|
||||
|
||||
# Functions not necessary to implement in sub class
|
||||
|
@ -222,7 +269,7 @@ class HandHistoryConverter:
|
|||
def splitFileIntoHands(self):
|
||||
hands = []
|
||||
self.obs.strip()
|
||||
list = self.rexx.split_hand_re.split(self.obs)
|
||||
list = self.re_SplitHands.split(self.obs)
|
||||
list.pop() #Last entry is empty
|
||||
for l in list:
|
||||
# print "'" + l + "'"
|
||||
|
@ -233,7 +280,7 @@ class HandHistoryConverter:
|
|||
"""Read file"""
|
||||
print "Reading file: '%s'" %(filename)
|
||||
if(self.filetype == "text"):
|
||||
infile=codecs.open(filename, "rU", self.codepage)
|
||||
infile=codecs.open(filename, "r", self.codepage)
|
||||
self.obs = infile.read()
|
||||
infile.close()
|
||||
elif(self.filetype == "xml"):
|
||||
|
@ -244,18 +291,9 @@ class HandHistoryConverter:
|
|||
traceback.print_exc(file=sys.stderr)
|
||||
|
||||
|
||||
#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:]
|
||||
def getStatus(self):
|
||||
#TODO: Return a status of true if file processed ok
|
||||
return True
|
||||
|
||||
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
|
||||
def getProcessedFile(self):
|
||||
return self.ofile
|
||||
|
|
|
@ -364,6 +364,7 @@ class Stat_Window:
|
|||
self.y = y + table.y # x and y are the location relative to table.x & y
|
||||
self.player_id = player_id # looks like this isn't used ;)
|
||||
self.sb_click = 0 # used to figure out button clicks
|
||||
self.useframes = parent.config.get_frames(parent.site)
|
||||
|
||||
self.window = gtk.Window()
|
||||
self.window.set_decorated(0)
|
||||
|
@ -381,10 +382,12 @@ class Stat_Window:
|
|||
self.frame = []
|
||||
self.label = []
|
||||
for r in range(self.game.rows):
|
||||
if self.useframes:
|
||||
self.frame.append([])
|
||||
self.e_box.append([])
|
||||
self.label.append([])
|
||||
for c in range(self.game.cols):
|
||||
if self.useframes:
|
||||
self.frame[r].append( gtk.Frame() )
|
||||
self.e_box[r].append( gtk.EventBox() )
|
||||
|
||||
|
@ -392,11 +395,14 @@ class Stat_Window:
|
|||
self.e_box[r][c].modify_fg(gtk.STATE_NORMAL, parent.foregroundcolor)
|
||||
|
||||
Stats.do_tip(self.e_box[r][c], 'stuff')
|
||||
# self.grid.attach(self.e_box[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0)
|
||||
if self.useframes:
|
||||
self.grid.attach(self.frame[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0)
|
||||
self.frame[r][c].add(self.e_box[r][c])
|
||||
else:
|
||||
self.grid.attach(self.e_box[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0)
|
||||
self.label[r].append( gtk.Label('xxx') )
|
||||
|
||||
if self.useframes:
|
||||
self.frame[r][c].modify_bg(gtk.STATE_NORMAL, parent.backgroundcolor)
|
||||
self.label[r][c].modify_bg(gtk.STATE_NORMAL, parent.backgroundcolor)
|
||||
self.label[r][c].modify_fg(gtk.STATE_NORMAL, parent.foregroundcolor)
|
||||
|
|
15
pyfpdb/RegressionTest.py
Normal file → Executable file
15
pyfpdb/RegressionTest.py
Normal file → Executable file
|
@ -90,6 +90,21 @@ class TestSequenceFunctions(unittest.TestCase):
|
|||
self.failUnless(result==datetime.datetime(2008,8,17,6,14,43),
|
||||
"Date incorrect, expected: 2008-08-17 01:14:43 got: " + str(result))
|
||||
|
||||
def testFullTiltHHDate(self):
|
||||
sitngo1 = "Full Tilt Poker Game #10311865543: $1 + $0.25 Sit & Go (78057629), Table 1 - 25/50 - No Limit Hold'em - 0:07:45 ET - 2009/01/29"
|
||||
cash1 = "Full Tilt Poker Game #9403951181: Table CR - tay - $0.05/$0.10 - No Limit Hold'em - 9:40:20 ET - 2008/12/09"
|
||||
cash2 = "Full Tilt Poker Game #9468383505: Table Bike (deep 6) - $0.05/$0.10 - No Limit Hold'em - 5:09:36 ET - 2008/12/13"
|
||||
|
||||
result = fpdb_simple.parseHandStartTime(sitngo1,"ftp")
|
||||
self.failUnless(result==datetime.datetime(2009,1,29,05,07,45),
|
||||
"Date incorrect, expected: 2009-01-29 05:07:45 got: " + str(result))
|
||||
result = fpdb_simple.parseHandStartTime(cash1,"ftp")
|
||||
self.failUnless(result==datetime.datetime(2008,12,9,14,40,20),
|
||||
"Date incorrect, expected: 2008-12-09 14:40:20 got: " + str(result))
|
||||
result = fpdb_simple.parseHandStartTime(cash2,"ftp")
|
||||
self.failUnless(result==datetime.datetime(2008,12,13,10,9,36),
|
||||
"Date incorrect, expected: 2008-12-13 10:09:36 got: " + str(result))
|
||||
|
||||
def testTableDetection(self):
|
||||
result = Tables.clean_title("French (deep)")
|
||||
self.failUnless(result == "French", "French (deep) parsed incorrectly. Expected 'French' got: " + str(result))
|
||||
|
|
|
@ -70,6 +70,13 @@ def do_stat(stat_dict, player = 24, stat = 'vpip'):
|
|||
###########################################
|
||||
# functions that return individual stats
|
||||
|
||||
def totalprofit(stat_dict, player):
|
||||
""" Total Profit."""
|
||||
if stat_dict[player]['net'] != 0:
|
||||
stat = float(stat_dict[player]['net']) / 100
|
||||
return (stat, '$%.2f' % stat, 'tp=$%.2f' % stat, 'totalprofit=$%.2f' % stat, str(stat), 'Total Profit')
|
||||
return ('0', '0', '0', '0', 'Total Profit')
|
||||
|
||||
def playername(stat_dict, player):
|
||||
""" Player Name."""
|
||||
return (stat_dict[player]['screen_name'],
|
||||
|
|
|
@ -361,7 +361,7 @@ def clean_title(name):
|
|||
' \(deep hu\)', ' \(deep 6\)', ' \(2\)',
|
||||
' \(edu\)', ' \(edu, 6 max\)', ' \(6\)',
|
||||
' \(speed\)',
|
||||
' no all-in', ' fast', ',', ' 50BB min', '\s+$']:
|
||||
' no all-in', ' fast', ',', ' 50BB min', '50bb min', '\s+$']:
|
||||
name = re.sub(pattern, '', name)
|
||||
name = name.rstrip()
|
||||
return name
|
||||
|
|
|
@ -33,6 +33,8 @@ import fpdb_simple
|
|||
import fpdb_db
|
||||
import fpdb_parse_logic
|
||||
import Configuration
|
||||
import EverleafToFpdb
|
||||
import FulltiltToFpdb
|
||||
|
||||
# database interface modules
|
||||
try:
|
||||
|
@ -58,6 +60,8 @@ class Importer:
|
|||
self.cursor = None
|
||||
self.filelist = {}
|
||||
self.dirlist = {}
|
||||
self.addToDirList = {}
|
||||
self.removeFromFileList = {} # to remove deleted files
|
||||
self.monitor = False
|
||||
self.updated = {} #Time last import was run {file:mtime}
|
||||
self.lines = None
|
||||
|
@ -66,8 +70,10 @@ class Importer:
|
|||
#Set defaults
|
||||
self.callHud = self.config.get_import_parameters().get("callFpdbHud")
|
||||
if 'minPrint' not in self.settings:
|
||||
#TODO: Is this value in the xml file?
|
||||
self.settings['minPrint'] = 30
|
||||
if 'handCount' not in self.settings:
|
||||
#TODO: Is this value in the xml file?
|
||||
self.settings['handCount'] = 0
|
||||
self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
|
||||
self.fdb.do_connect(self.config)
|
||||
|
@ -108,11 +114,27 @@ class Importer:
|
|||
#TODO: test it is a valid file -> put that in config!!
|
||||
self.filelist[filename] = [site] + [filter]
|
||||
|
||||
# Called from GuiBulkImport to add a file or directory.
|
||||
def addBulkImportImportFileOrDir(self, inputPath,filter = "passthrough"):
|
||||
"""Add a file or directory for bulk import"""
|
||||
# Bulk import never monitors
|
||||
|
||||
# if directory, add all files in it. Otherwise add single file.
|
||||
# TODO: only add sane files?
|
||||
if os.path.isdir(inputPath):
|
||||
for subdir in os.walk(inputPath):
|
||||
for file in subdir[2]:
|
||||
self.addImportFile(os.path.join(inputPath, subdir[0], file), site="default", filter=filter)
|
||||
else:
|
||||
self.addImportFile(inputPath, site="default", filter=filter)
|
||||
|
||||
#Add a directory of files to filelist
|
||||
#Only one import directory per site supported.
|
||||
#dirlist is a hash of lists:
|
||||
#dirlist{ 'PokerStars' => ["/path/to/import/", "filtername"] }
|
||||
def addImportDirectory(self,dir,monitor = False, site = "default", filter = "passthrough"):
|
||||
#This should really be using os.walk
|
||||
#http://docs.python.org/library/os.html
|
||||
if os.path.isdir(dir):
|
||||
if monitor == True:
|
||||
self.monitor = True
|
||||
|
@ -177,16 +199,54 @@ class Importer:
|
|||
self.updated[file] = time()
|
||||
# This codepath only runs first time the file is found, if modified in the last
|
||||
# minute run an immediate import.
|
||||
if (time() - stat_info.st_mtime) < 60: # TODO: figure out a way to dispatch this to the seperate thread so our main window doesn't lock up on initial import
|
||||
if (time() - stat_info.st_mtime) < 60 or os.path.isdir(file): # TODO: figure out a way to dispatch this to the seperate thread so our main window doesn't lock up on initial import
|
||||
self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1])
|
||||
|
||||
for dir in self.addToDirList:
|
||||
self.addImportDirectory(dir, True, self.addToDirList[dir][0], self.addToDirList[dir][1])
|
||||
|
||||
for file in self.removeFromFileList:
|
||||
if file in self.filelist:
|
||||
del self.filelist[file]
|
||||
|
||||
self.addToDirList = {}
|
||||
self.removeFromFileList = {}
|
||||
|
||||
# This is now an internal function that should not be called directly.
|
||||
def import_file_dict(self, file, site, filter):
|
||||
if(filter == "passthrough"):
|
||||
if os.path.isdir(file):
|
||||
self.addToDirList[file] = [site] + [filter]
|
||||
return
|
||||
if filter == "passthrough" or filter == "":
|
||||
(stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(file, site)
|
||||
else:
|
||||
# TODO: Load filter, and run filtered file though main importer
|
||||
(stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(file, site)
|
||||
conv = None
|
||||
# Load filter, process file, pass returned filename to import_fpdb_file
|
||||
|
||||
# TODO: Shouldn't we be able to use some sort of lambda or something to just call a Python object by whatever name we specify? then we don't have to hardcode them,
|
||||
# someone can just create their own python module for it
|
||||
if filter == "EverleafToFpdb":
|
||||
print "converting ", file
|
||||
conv = EverleafToFpdb.Everleaf(self.config, file)
|
||||
elif filter == "FulltiltToFpdb":
|
||||
print "converting ", file
|
||||
conv = FulltiltToFpdb.FullTilt(self.config, file)
|
||||
else:
|
||||
print "Unknown filter ", filter
|
||||
return
|
||||
|
||||
supp = conv.readSupportedGames() # Should this be done by HHC on init?
|
||||
#gt = conv.determineGameType()
|
||||
# TODO: Check that gt is in supp - error appropriately if not
|
||||
conv.processFile()
|
||||
if(conv.getStatus()):
|
||||
(stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(conv.getProcessedFile(), site)
|
||||
else:
|
||||
# conversion didn't work
|
||||
# TODO: appropriate response?
|
||||
return (0, 0, 0, 1, 0)
|
||||
|
||||
#This will barf if conv.getStatus != True
|
||||
return (stored, duplicates, partial, errors, ttime)
|
||||
|
||||
|
||||
|
@ -197,9 +257,15 @@ class Importer:
|
|||
if (file=="stdin"):
|
||||
inputFile=sys.stdin
|
||||
else:
|
||||
inputFile=open(file, "rU")
|
||||
try: loc = self.pos_in_file[file]
|
||||
except: pass
|
||||
if os.path.exists(file):
|
||||
inputFile = open(file, "rU")
|
||||
else:
|
||||
self.removeFromFileList[file] = True
|
||||
return (0, 0, 0, 1, 0)
|
||||
try:
|
||||
loc = self.pos_in_file[file]
|
||||
except:
|
||||
pass
|
||||
|
||||
# Read input file into class and close file
|
||||
inputFile.seek(loc)
|
||||
|
|
|
@ -1158,10 +1158,17 @@ def parseHandStartTime(topline, site):
|
|||
|
||||
isUTC=False
|
||||
if site=="ftp":
|
||||
# Full Tilt Sit'n'Go
|
||||
# Full Tilt Poker Game #10311865543: $1 + $0.25 Sit & Go (78057629), Table 1 - 25/50 - No Limit Hold'em - 0:07:45 ET - 2009/01/29
|
||||
# Cash Game:
|
||||
# Full Tilt Poker Game #9403951181: Table CR - tay - $0.05/$0.10 - No Limit Hold'em - 9:40:20 ET - 2008/12/09
|
||||
# Full Tilt Poker Game #9468383505: Table Bike (deep 6) - $0.05/$0.10 - No Limit Hold'em - 5:09:36 ET - 2008/12/13
|
||||
pos = topline.find(" ", len(topline)-26)+1
|
||||
tmp = topline[pos:]
|
||||
#print "year:", tmp[14:18], "month", tmp[19:21], "day", tmp[22:24], "hour", tmp[0:2], "minute", tmp[3:5], "second", tmp[6:8]
|
||||
result = datetime.datetime(int(tmp[14:18]), int(tmp[19:21]), int(tmp[22:24]), int(tmp[0:2]), int(tmp[3:5]), int(tmp[6:8]))
|
||||
|
||||
rexx = '(?P<HR>[0-9]+):(?P<MIN>[0-9]+):(?P<SEC>[0-9]+) ET [\- ]+(?P<YEAR>[0-9]{4})\/(?P<MON>[0-9]{2})\/(?P<DAY>[0-9]{2})'
|
||||
m = re.search(rexx,tmp)
|
||||
result = datetime.datetime(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC')))
|
||||
elif site=="ps":
|
||||
if topline.find("UTC")!=-1:
|
||||
pos1 = topline.find("-")+2
|
||||
|
|
Loading…
Reference in New Issue
Block a user