commit, time to pull carl's ftp stud stuff
This commit is contained in:
commit
2c44d634f9
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2008, Carl Gherardi
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -27,11 +28,12 @@ class Everleaf(HandHistoryConverter):
|
|||
|
||||
# Static regexes
|
||||
re_SplitHands = re.compile(r"\n\n+")
|
||||
re_GameInfo = re.compile(u"^(Blinds )?(?P<currency>\$| €|)(?P<sb>[.0-9]+)/(?:\$| €)?(?P<bb>[.0-9]+) (?P<limit>NL|PL|) (?P<game>(Hold\'em|Omaha|7 Card Stud))", re.MULTILINE)
|
||||
re_HandInfo = re.compile(u".*#(?P<HID>[0-9]+)\n.*\n(Blinds )?(?:\$| €|)(?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(u"^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\s+((?:\$| €|) (?P<CASH>[.0-9]+) (USD|EUR|)|new player|All-in) \)", re.MULTILINE)
|
||||
re_Board = re.compile(r"\[ (?P<CARDS>.+) \]")
|
||||
re_GameInfo = re.compile(ur"^(Blinds )?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/(?:\$| €)?(?P<BB>[.0-9]+)(?P<LIMIT> NL | PL | )(?P<GAME>(Hold\'em|Omaha|7 Card Stud))", re.MULTILINE)
|
||||
#re.compile(ur"^(Blinds )?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/(?:\$| €)?(?P<BB>[.0-9]+) (?P<LIMIT>NL|PL|) (?P<GAME>(Hold\'em|Omaha|7 Card Stud))", re.MULTILINE)
|
||||
re_HandInfo = re.compile(ur".*#(?P<HID>[0-9]+)\n.*\n(Blinds )?(?:\$| €|)(?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>.+$)")
|
||||
re_Button = re.compile(ur"^Seat (?P<BUTTON>\d+) is the button", re.MULTILINE)
|
||||
re_PlayerInfo = re.compile(ur"^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\s+((?:\$| €|) (?P<CASH>[.0-9]+) (USD|EUR|)|new player|All-in) \)", re.MULTILINE)
|
||||
re_Board = re.compile(ur"\[ (?P<CARDS>.+) \]")
|
||||
|
||||
|
||||
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True):
|
||||
|
@ -70,28 +72,57 @@ follow : whether to tail -f the input"""
|
|||
]
|
||||
|
||||
def determineGameType(self, handText):
|
||||
info = {}
|
||||
"""return dict with keys/values:
|
||||
'type' in ('ring', 'tour')
|
||||
'limitType' in ('nl', 'cn', 'pl', 'cp', 'fl')
|
||||
'base' in ('hold', 'stud', 'draw')
|
||||
'category' in ('holdem', 'omahahi', omahahilo', 'razz', 'studhi', 'studhilo', 'fivedraw', '27_1draw', '27_3draw', 'badugi')
|
||||
'hilo' in ('h','l','s')
|
||||
'smallBlind' int?
|
||||
'bigBlind' int?
|
||||
'smallBet'
|
||||
'bigBet'
|
||||
'currency' in ('USD', 'EUR', 'T$', <countrycode>)
|
||||
or None if we fail to get the info """
|
||||
#(TODO: which parts are optional/required?)
|
||||
|
||||
# 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
|
||||
|
||||
# Tourney:
|
||||
# Everleaf Gaming Game #75065769
|
||||
# ***** Hand history for game #75065769 *****
|
||||
# Blinds 10/20 NL Hold'em - 2009/02/25 - 17:30:32
|
||||
# Table 2
|
||||
info = {'type':'ring'}
|
||||
|
||||
m = self.re_GameInfo.search(handText)
|
||||
if not m:
|
||||
return None
|
||||
|
||||
info.update(m.groupdict())
|
||||
mg = m.groupdict()
|
||||
|
||||
# translations from captured groups to our info strings
|
||||
limits = { ' NL ':'nl', ' PL ':'pl', ' ':'fl' }
|
||||
games = { 'Hold\'em':'hold', 'Omaha':'omahahi', 'Razz':'razz','7 Card Stud':'studhi' }
|
||||
games = { # base, category
|
||||
"Hold'em" : ('hold','holdem'),
|
||||
'Omaha' : ('hold','omahahi'),
|
||||
'Razz' : ('stud','razz'),
|
||||
'7 Card Stud' : ('stud','studhi')
|
||||
}
|
||||
currencies = { u' €':'EUR', '$':'USD', '':'T$' }
|
||||
for key in info:
|
||||
if key == 'limit':
|
||||
info[key] = limits[info[key]]
|
||||
if key == 'game':
|
||||
info[key] = games[info[key]]
|
||||
if key == 'sb':
|
||||
pass
|
||||
if key == 'bb':
|
||||
pass
|
||||
if key == 'currency':
|
||||
info[key] = currencies[info[key]]
|
||||
if 'LIMIT' in mg:
|
||||
info['limitType'] = limits[mg['LIMIT']]
|
||||
if 'GAME' in mg:
|
||||
(info['base'], info['category']) = games[mg['GAME']]
|
||||
if 'SB' in mg:
|
||||
info['sb'] = mg['SB']
|
||||
if 'BB' in mg:
|
||||
info['bb'] = mg['BB']
|
||||
if 'CURRENCY' in mg:
|
||||
info['currency'] = currencies[mg['CURRENCY']]
|
||||
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
|
||||
|
||||
return info
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2008, Carl Gherardi
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -25,7 +27,7 @@ from HandHistoryConverter import *
|
|||
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_GameInfo = re.compile('- (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (Ante \$(?P<ANTE>[.0-9]+) )?- (?P<LIMIT>(No Limit|Pot Limit|Limit))? (?P<GAME>(Hold\'em|Omaha Hi|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)
|
||||
|
@ -44,7 +46,9 @@ follow : whether to tail -f the input"""
|
|||
if autostart:
|
||||
self.start()
|
||||
|
||||
def compilePlayerRegexs(self, players):
|
||||
|
||||
def compilePlayerRegexs(self, hand):
|
||||
players = set([player[1] for player in hand.players])
|
||||
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
|
||||
# we need to recompile the player regexs.
|
||||
self.compiledPlayers = players
|
||||
|
@ -76,30 +80,36 @@ follow : whether to tail -f the input"""
|
|||
# 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
|
||||
# Full Tilt Poker Game #10809877615: Table Danville - $0.50/$1 Ante $0.10 - Limit Razz - 21:47:27 ET - 2009/02/23
|
||||
structure = "" # nl, pl, cn, cp, fl
|
||||
game = ""
|
||||
|
||||
info = {'type':'ring'}
|
||||
|
||||
m = self.re_GameInfo.search(handText)
|
||||
if m.group('LTYPE') == "No ":
|
||||
structure = "nl"
|
||||
elif m.group('LTYPE') == "Pot ":
|
||||
structure = "pl"
|
||||
elif m.group('LTYPE') == None:
|
||||
structure = "fl"
|
||||
if not m:
|
||||
return None
|
||||
|
||||
if m.group('GAME') == "Hold\'em":
|
||||
game = "hold"
|
||||
elif m.group('GAME') == "Omaha":
|
||||
game = "omahahi"
|
||||
elif m.group('GAME') == "Razz":
|
||||
game = "razz"
|
||||
mg = m.groupdict()
|
||||
|
||||
logging.debug("HandInfo: %s", m.groupdict())
|
||||
# translations from captured groups to our info strings
|
||||
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' }
|
||||
games = { # base, category
|
||||
"Hold'em" : ('hold','holdem'),
|
||||
'Omaha Hi' : ('hold','omahahi'),
|
||||
'Razz' : ('stud','razz'),
|
||||
'7 Card Stud' : ('stud','studhi')
|
||||
}
|
||||
currencies = { u' €':'EUR', '$':'USD', '':'T$' }
|
||||
if 'LIMIT' in mg:
|
||||
info['limitType'] = limits[mg['LIMIT']]
|
||||
if 'GAME' in mg:
|
||||
(info['base'], info['category']) = games[mg['GAME']]
|
||||
if 'SB' in mg:
|
||||
info['sb'] = mg['SB']
|
||||
if 'BB' in mg:
|
||||
info['bb'] = mg['BB']
|
||||
if 'CURRENCY' in mg:
|
||||
info['currency'] = currencies[mg['CURRENCY']]
|
||||
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
|
||||
|
||||
gametype = ["ring", game, structure, m.group('SB'), m.group('BB')]
|
||||
|
||||
return gametype
|
||||
return info
|
||||
|
||||
def readHandInfo(self, hand):
|
||||
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
|
||||
|
@ -131,12 +141,12 @@ follow : whether to tail -f the input"""
|
|||
def markStreets(self, hand):
|
||||
# PREFLOP = ** Dealing down cards **
|
||||
|
||||
if hand.gametype[1] in ("hold", "omaha"):
|
||||
if hand.gametype['base'] == 'hold':
|
||||
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.handText,re.DOTALL)
|
||||
elif hand.gametype[1] == "razz":
|
||||
elif hand.gametype['base'] == "stud": # or should this be gametype['category'] == 'razz'
|
||||
m = re.search(r"(?P<ANTES>.+(?=\*\*\* 3RD STREET \*\*\*)|.+)"
|
||||
r"(\*\*\* 3RD STREET \*\*\*(?P<THIRD>.+(?=\*\*\* 4TH STREET \*\*\*)|.+))?"
|
||||
r"(\*\*\* 4TH STREET \*\*\*(?P<FOURTH>.+(?=\*\*\* 5TH STREET \*\*\*)|.+))?"
|
||||
|
@ -148,7 +158,7 @@ follow : whether to tail -f the input"""
|
|||
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)
|
||||
#print "DEBUG readCommunityCards:", street, hand.streets.group(street)
|
||||
m = self.re_Board.search(hand.streets.group(street))
|
||||
m = self.re_Board.search(hand.streets[street])
|
||||
hand.setCommunityCards(street, m.group('CARDS').split(' '))
|
||||
|
||||
|
||||
|
|
|
@ -291,7 +291,7 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
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",
|
||||
gs = {"holdem" : "Hold'em",
|
||||
"omahahi" : "Omaha",
|
||||
"omahahilo" : "FIXME",
|
||||
"razz" : "Razz",
|
||||
|
@ -310,7 +310,7 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
|||
}
|
||||
|
||||
logging.debug("gametype: %s" %(self.gametype))
|
||||
retstring = "%s %s" %(gs[self.gametype['game']], ls[self.gametype['limit']])
|
||||
retstring = "%s %s" %(gs[self.gametype['category']], ls[self.gametype['limitType']])
|
||||
|
||||
return retstring
|
||||
|
||||
|
@ -359,7 +359,7 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
|||
|
||||
class HoldemOmahaHand(Hand):
|
||||
def __init__(self, hhc, sitename, gametype, handText):
|
||||
if gametype['game'] not in ["hold","omaha"]:
|
||||
if gametype['base'] != 'hold':
|
||||
pass # or indeed don't pass and complain instead
|
||||
logging.debug("HoldemOmahaHand")
|
||||
self.streetList = ['BLINDSANTES', 'PREFLOP','FLOP','TURN','RIVER'] # a list of the observed street names in order
|
||||
|
@ -437,7 +437,7 @@ Card ranks will be uppercased
|
|||
|
||||
|
||||
#May be more than 1 bb posting
|
||||
if self.gametype['limit'] == "fl":
|
||||
if self.gametype['limitType'] == "fl":
|
||||
(smallbet, bigbet) = self.lookupLimitBetSize()
|
||||
else:
|
||||
smallbet = self.sb
|
||||
|
@ -529,7 +529,7 @@ Card ranks will be uppercased
|
|||
|
||||
class DrawHand(Hand):
|
||||
def __init__(self, hhc, sitename, gametype, handText):
|
||||
if gametype['game'] not in ["badugi","5-card-draw"]:
|
||||
if gametype['base'] != 'draw':
|
||||
pass # or indeed don't pass and complain instead
|
||||
|
||||
def discardHoleCards(self, cards, player):
|
||||
|
@ -544,7 +544,7 @@ class DrawHand(Hand):
|
|||
|
||||
class StudHand(Hand):
|
||||
def __init__(self, hhc, sitename, gametype, handText):
|
||||
if gametype['game'] not in ["razz","stud","stud8"]:
|
||||
if gametype['base'] != 'stud':
|
||||
pass # or indeed don't pass and complain instead
|
||||
self.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order
|
||||
self.holeStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH']
|
||||
|
|
|
@ -73,7 +73,7 @@ import gettext
|
|||
gettext.install('myapplication')
|
||||
|
||||
class HandHistoryConverter(threading.Thread):
|
||||
|
||||
READ_CHUNK_SIZE = 1000 # bytes to read at a time from file
|
||||
def __init__(self, in_path = '-', out_path = '-', sitename = None, follow=False):
|
||||
threading.Thread.__init__(self)
|
||||
logging.info("HandHistory init called")
|
||||
|
@ -97,11 +97,11 @@ class HandHistoryConverter(threading.Thread):
|
|||
def __str__(self):
|
||||
#TODO : I got rid of most of the hhdir stuff.
|
||||
tmp = "HandHistoryConverter: '%s'\n" % (self.sitename)
|
||||
tmp = tmp + "\thhbase: '%s'\n" % (self.hhbase)
|
||||
tmp = tmp + "\thhdir: '%s'\n" % (self.hhdir)
|
||||
#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 + "\tinfile: '%s'\n" % (self.in_path)
|
||||
tmp = tmp + "\toutfile: '%s'\n" % (self.out_path)
|
||||
#tmp = tmp + "\tgametype: '%s'\n" % (self.gametype[0])
|
||||
#tmp = tmp + "\tgamebase: '%s'\n" % (self.gametype[1])
|
||||
#tmp = tmp + "\tlimit: '%s'\n" % (self.gametype[2])
|
||||
|
@ -109,29 +109,76 @@ class HandHistoryConverter(threading.Thread):
|
|||
return tmp
|
||||
|
||||
def run(self):
|
||||
"""process a hand at a time from the input specified by in_path.
|
||||
If in follow mode, wait for more data to turn up.
|
||||
Otherwise, finish at eof..."""
|
||||
if self.follow:
|
||||
for handtext in self.tailHands():
|
||||
self.processHand(handtext)
|
||||
for handText in self.tailHands():
|
||||
self.processHand(handText)
|
||||
else:
|
||||
handsList = self.allHands()
|
||||
handsList = self.allHandsAsList()
|
||||
logging.info("Parsing %d hands" % len(handsList))
|
||||
for handtext in handsList:
|
||||
self.processHand(handtext)
|
||||
if self.out_fh != sys.stdout:
|
||||
self.ouf_fh.close()
|
||||
for handText in handsList:
|
||||
self.processHand(handText)
|
||||
|
||||
|
||||
def tailHands(self):
|
||||
"""pseudo-code"""
|
||||
while True:
|
||||
ifile.tell()
|
||||
text = ifile.read()
|
||||
if nomoretext:
|
||||
wait or sleep
|
||||
"""Generator of handTexts from a tailed file:
|
||||
Tail the in_path file and yield handTexts separated by re_SplitHands"""
|
||||
if in_path == '-': raise StopIteration
|
||||
interval = 1.0 # seconds to sleep between reads for new data
|
||||
fd = open(filename,'r')
|
||||
data = ''
|
||||
while 1:
|
||||
where = fd.tell()
|
||||
newdata = fd.read(self.READ_CHUNK_SIZE)
|
||||
if not newdata:
|
||||
fd_results = os.fstat(fd.fileno())
|
||||
try:
|
||||
st_results = os.stat(filename)
|
||||
except OSError:
|
||||
st_results = fd_results
|
||||
if st_results[1] == fd_results[1]:
|
||||
time.sleep(interval)
|
||||
fd.seek(where)
|
||||
else:
|
||||
ahand = thenexthandinthetext
|
||||
yield(ahand)
|
||||
print "%s changed inode numbers from %d to %d" % (filename, fd_results[1], st_results[1])
|
||||
fd = open(filename, 'r')
|
||||
fd.seek(where)
|
||||
else:
|
||||
# yield hands
|
||||
data = data + newdata
|
||||
result = self.re_SplitHands.split(data)
|
||||
result = iter(result)
|
||||
# --x data (- is bit of splitter, x is paragraph) yield,...,keep
|
||||
# [,--,x] result of re.split (with group around splitter)
|
||||
# ,x our output: yield nothing, keep x
|
||||
#
|
||||
# --x--x [,--,x,--,x] x,x
|
||||
# -x--x [-x,--,x] x,x
|
||||
# x- [x-] ,x-
|
||||
# x-- [x,--,] x,--
|
||||
# x--x [x,--,x] x,x
|
||||
# x--x-- [x,--,x,--,] x,x,--
|
||||
|
||||
def allHands(self):
|
||||
# The length is always odd.
|
||||
# 'odd' indices are always splitters.
|
||||
# 'even' indices are always paragraphs or ''
|
||||
# We want to discard all the ''
|
||||
# We want to discard splitters unless the final item is '' (because the splitter could grow with new data)
|
||||
# We want to yield all paragraphs followed by a splitter, i.e. all even indices except the last.
|
||||
for para in result:
|
||||
try:
|
||||
splitter = result.next()
|
||||
except StopIteration:
|
||||
splitter = None
|
||||
if splitter: # para is followed by a splitter
|
||||
if para: yield para # para not ''
|
||||
else:
|
||||
data = para # keep final partial paragraph
|
||||
|
||||
|
||||
def allHandsAsList(self):
|
||||
"""Return a list of handtexts in the file at self.in_path"""
|
||||
self.readFile()
|
||||
self.obs = self.obs.strip()
|
||||
|
@ -141,17 +188,19 @@ class HandHistoryConverter(threading.Thread):
|
|||
return
|
||||
return re.split(self.re_SplitHands, self.obs)
|
||||
|
||||
def processHand(self, handtext):
|
||||
gametype = self.determineGameType(handtext)
|
||||
def processHand(self, handText):
|
||||
gametype = self.determineGameType(handText)
|
||||
logging.debug("gametype %s" % gametype)
|
||||
if gametype is None:
|
||||
return
|
||||
|
||||
hand = None
|
||||
if gametype['game'] in ("hold", "omaha"):
|
||||
hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handtext)
|
||||
elif gametype['game'] in ("razz","stud","stud8"):
|
||||
hand = Hand.StudHand(self, self.sitename, gametype, handtext)
|
||||
if gametype['base'] == 'hold':
|
||||
hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handText)
|
||||
elif gametype['base'] == 'stud':
|
||||
hand = Hand.StudHand(self, self.sitename, gametype, handText)
|
||||
elif gametype['base'] == 'draw':
|
||||
hand = Hand.DrawHand(self, self.sitename, gametype, handText)
|
||||
|
||||
if hand:
|
||||
hand.writeHand(self.out_fh)
|
||||
|
@ -170,69 +219,7 @@ class HandHistoryConverter(threading.Thread):
|
|||
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(self.obs)
|
||||
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 "\nDEBUG: Input:\n"+hand.handText
|
||||
self.readHandInfo(hand)
|
||||
|
||||
self.readPlayerStacks(hand)
|
||||
#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] == "omahahi":
|
||||
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] == "omahahi":
|
||||
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)
|
||||
|
||||
|
||||
self.readCollectPot(hand)
|
||||
self.readShownCards(hand)
|
||||
|
||||
# finalise it (total the pot)
|
||||
hand.totalPot()
|
||||
self.getRake(hand)
|
||||
|
||||
hand.writeHand(outfile)
|
||||
#if(hand.involved == True):
|
||||
#self.writeHand("output file", hand)
|
||||
#hand.printHand()
|
||||
#else:
|
||||
#pass #Don't write out observed hands
|
||||
|
||||
outfile.close()
|
||||
### alala deleted
|
||||
endtime = time.time()
|
||||
print "Processed %d hands in %.3f seconds" % (len(self.hands), endtime - starttime)
|
||||
|
||||
|
@ -248,6 +235,19 @@ class HandHistoryConverter(threading.Thread):
|
|||
# [ ring, hold, nl , sb, bb ]
|
||||
# Valid types specified in docs/tabledesign.html in Gametypes
|
||||
def determineGameType(self, handText): abstract
|
||||
"""return dict with keys/values:
|
||||
'type' in ('ring', 'tour')
|
||||
'limitType' in ('nl', 'cn', 'pl', 'cp', 'fl')
|
||||
'base' in ('hold', 'stud', 'draw')
|
||||
'category' in ('holdem', 'omahahi', omahahilo', 'razz', 'studhi', 'studhilo', 'fivedraw', '27_1draw', '27_3draw', 'badugi')
|
||||
'hilo' in ('h','l','s')
|
||||
'smallBlind' int?
|
||||
'bigBlind' int?
|
||||
'smallBet'
|
||||
'bigBet'
|
||||
'currency' in ('USD', 'EUR', 'T$', <countrycode>)
|
||||
or None if we fail to get the info """
|
||||
#TODO: which parts are optional/required?
|
||||
|
||||
# Read any of:
|
||||
# HID HandID
|
||||
|
@ -331,7 +331,7 @@ class HandHistoryConverter(threading.Thread):
|
|||
return hands
|
||||
|
||||
def readFile(self):
|
||||
"""Read in path into self.obs or self.doc"""
|
||||
"""open in_path according to self.codepage"""
|
||||
|
||||
if(self.filetype == "text"):
|
||||
if self.in_path == '-':
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2008, Carl Gherardi
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -67,7 +69,7 @@ from HandHistoryConverter import *
|
|||
class PokerStars(HandHistoryConverter):
|
||||
|
||||
# Static regexes
|
||||
re_GameInfo = re.compile('PokerStars Game #(?P<HID>[0-9]+):\s+(HORSE)? \(?(?P<GAME>Hold\'em|Razz|7 Card Stud) (?P<LTYPE>No Limit|Limit|Pot Limit),? \(?\$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\) - (?P<DATETIME>.*$)', re.MULTILINE)
|
||||
re_GameInfo = re.compile('PokerStars Game #(?P<HID>[0-9]+):\s+(HORSE)? \(?(?P<GAME>Hold\'em|Razz|7 Card Stud) (?P<LIMIT>No Limit|Limit|Pot Limit),? \(?(?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\) - (?P<DATETIME>.*$)', re.MULTILINE)
|
||||
re_SplitHands = re.compile('\n\n+')
|
||||
re_HandInfo = re.compile("^Table \'(?P<TABLE>[- a-zA-Z]+)\'(?P<TABLEATTRIBUTES>.+?$)?", re.MULTILINE)
|
||||
re_Button = re.compile('Seat #(?P<BUTTON>\d+) is the button', re.MULTILINE)
|
||||
|
@ -88,7 +90,8 @@ follow : whether to tail -f the input"""
|
|||
self.start()
|
||||
|
||||
|
||||
def compilePlayerRegexs(self, players):
|
||||
def compilePlayerRegexs(self, hand):
|
||||
players = set([player[1] for player in hand.players])
|
||||
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
|
||||
# we need to recompile the player regexs.
|
||||
self.compiledPlayers = players
|
||||
|
@ -111,33 +114,37 @@ follow : whether to tail -f the input"""
|
|||
return []
|
||||
|
||||
def determineGameType(self, handText):
|
||||
game = None
|
||||
structure = None
|
||||
sb = None
|
||||
bb = None
|
||||
info = {}
|
||||
info = {'type':'ring'}
|
||||
|
||||
m = self.re_GameInfo.search(handText)
|
||||
if m:
|
||||
info.update(m.groupdict())
|
||||
else:
|
||||
if not m:
|
||||
return None
|
||||
|
||||
mg = m.groupdict()
|
||||
|
||||
ltypes = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' }
|
||||
gtypes = { 'Hold\'em':'hold', 'Omaha':'omahahi', 'Razz':'razz','7 Card Stud':'studhi' }
|
||||
for key in info:
|
||||
if key == 'LTYPE':
|
||||
structure = ltypes[info[key]]
|
||||
if key == 'GAME':
|
||||
game = gtypes[info[key]]
|
||||
if key == 'SB':
|
||||
sb = info[key]
|
||||
if key == 'BB':
|
||||
bb = info[key]
|
||||
# translations from captured groups to our info strings
|
||||
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' }
|
||||
games = { # base, category
|
||||
"Hold'em" : ('hold','holdem'),
|
||||
'Omaha Hi' : ('hold','omahahi'),
|
||||
'Razz' : ('stud','razz'),
|
||||
'7 Card Stud' : ('stud','studhi')
|
||||
}
|
||||
currencies = { u'€':'EUR', '$':'USD', '':'T$' }
|
||||
if 'LIMIT' in mg:
|
||||
info['limitType'] = limits[mg['LIMIT']]
|
||||
if 'GAME' in mg:
|
||||
(info['base'], info['category']) = games[mg['GAME']]
|
||||
if 'SB' in mg:
|
||||
info['sb'] = mg['SB']
|
||||
if 'BB' in mg:
|
||||
info['bb'] = mg['BB']
|
||||
if 'CURRENCY' in mg:
|
||||
info['currency'] = currencies[mg['CURRENCY']]
|
||||
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
|
||||
|
||||
return info
|
||||
|
||||
gametype = ["ring", game, structure, sb, bb]
|
||||
return gametype
|
||||
|
||||
def readHandInfo(self, hand):
|
||||
info = {}
|
||||
|
|
|
@ -1,36 +1,38 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import EverleafToFpdb
|
||||
import py
|
||||
class TestEverleaf:
|
||||
def testGameInfo1(self):
|
||||
e = EverleafToFpdb.Everleaf(autostart=False)
|
||||
g = """Everleaf Gaming Game #3732225
|
||||
|
||||
|
||||
def checkGameInfo(hhc, header, info):
|
||||
assert hhc.determineGameType(header) == info
|
||||
|
||||
def testGameInfo():
|
||||
hhc = EverleafToFpdb.Everleaf(autostart=False)
|
||||
pairs = (
|
||||
(u"""Everleaf Gaming Game #3732225
|
||||
***** Hand history for game #3732225 *****
|
||||
Blinds €0.50/ €1 NL Hold'em - 2009/01/11 - 16:09:40
|
||||
Table Casino Lyon Vert 58
|
||||
Seat 3 is the button
|
||||
Total number of players: 6"""
|
||||
assert e.determineGameType(g) == {'sb':'0.50', 'bb':'1','game':"hold", 'currency':'EUR', 'limit':'nl'}
|
||||
|
||||
|
||||
def testGameInfo2(self):
|
||||
e = EverleafToFpdb.Everleaf(autostart=False)
|
||||
g = """Everleaf Gaming Game #55198191
|
||||
Total number of players: 6""",
|
||||
{'type':'ring', 'base':"hold", 'category':'holdem', 'limitType':'nl', 'sb':'0.50', 'bb':'1', 'currency':'EUR'}),
|
||||
("""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"""
|
||||
assert e.determineGameType(g) == {'sb':'0.50', 'bb':'1','game':"hold", 'currency':'USD', 'limit':'nl'}
|
||||
|
||||
def testGameInfo3(self):
|
||||
# Note: It looks difficult to distinguish T$ from play money.
|
||||
e = EverleafToFpdb.Everleaf(autostart=False)
|
||||
g = """Everleaf Gaming Game #75065769
|
||||
Total number of players: 10""",
|
||||
{'type':'ring', 'base':"hold", 'category':'holdem', 'limitType':'nl', 'sb':'0.50', 'bb':'1', 'currency':'USD'}),
|
||||
("""Everleaf Gaming Game #75065769
|
||||
***** Hand history for game #75065769 *****
|
||||
Blinds 10/20 NL Hold'em - 2009/02/25 - 17:30:32
|
||||
Table 2
|
||||
Seat 1 is the button
|
||||
Total number of players: 10"""
|
||||
assert e.determineGameType(g) == {'sb':'10', 'bb':'20','game':"hold", 'currency':'T$', 'limit':'nl'}
|
||||
Total number of players: 10""",
|
||||
{'type':'ring', 'base':"hold", 'category':'holdem', 'limitType':'nl', 'sb':'10', 'bb':'20', 'currency':'T$'})
|
||||
)
|
||||
for (header, info) in pairs:
|
||||
yield checkGameInfo, hhc, header, info
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user