commit, time to pull carl's ftp stud stuff
This commit is contained in:
commit
2c44d634f9
|
@ -1,5 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
# Copyright 2008, Carl Gherardi
|
# Copyright 2008, Carl Gherardi
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -27,11 +28,12 @@ class Everleaf(HandHistoryConverter):
|
||||||
|
|
||||||
# Static regexes
|
# Static regexes
|
||||||
re_SplitHands = re.compile(r"\n\n+")
|
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_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_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.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_Button = re.compile(r"^Seat (?P<BUTTON>\d+) is the button", 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_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_Button = re.compile(ur"^Seat (?P<BUTTON>\d+) is the button", re.MULTILINE)
|
||||||
re_Board = re.compile(r"\[ (?P<CARDS>.+) \]")
|
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):
|
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):
|
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)
|
m = self.re_GameInfo.search(handText)
|
||||||
if not m:
|
if not m:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
info.update(m.groupdict())
|
mg = m.groupdict()
|
||||||
|
|
||||||
limits = { 'NL':'nl', 'PL':'pl', '':'fl' }
|
# translations from captured groups to our info strings
|
||||||
games = { 'Hold\'em':'hold', 'Omaha':'omahahi', 'Razz':'razz','7 Card Stud':'studhi' }
|
limits = { ' NL ':'nl', ' PL ':'pl', ' ':'fl' }
|
||||||
|
games = { # base, category
|
||||||
|
"Hold'em" : ('hold','holdem'),
|
||||||
|
'Omaha' : ('hold','omahahi'),
|
||||||
|
'Razz' : ('stud','razz'),
|
||||||
|
'7 Card Stud' : ('stud','studhi')
|
||||||
|
}
|
||||||
currencies = { u' €':'EUR', '$':'USD', '':'T$' }
|
currencies = { u' €':'EUR', '$':'USD', '':'T$' }
|
||||||
for key in info:
|
if 'LIMIT' in mg:
|
||||||
if key == 'limit':
|
info['limitType'] = limits[mg['LIMIT']]
|
||||||
info[key] = limits[info[key]]
|
if 'GAME' in mg:
|
||||||
if key == 'game':
|
(info['base'], info['category']) = games[mg['GAME']]
|
||||||
info[key] = games[info[key]]
|
if 'SB' in mg:
|
||||||
if key == 'sb':
|
info['sb'] = mg['SB']
|
||||||
pass
|
if 'BB' in mg:
|
||||||
if key == 'bb':
|
info['bb'] = mg['BB']
|
||||||
pass
|
if 'CURRENCY' in mg:
|
||||||
if key == 'currency':
|
info['currency'] = currencies[mg['CURRENCY']]
|
||||||
info[key] = currencies[info[key]]
|
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
|
||||||
|
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
# Copyright 2008, Carl Gherardi
|
# Copyright 2008, Carl Gherardi
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -25,7 +27,7 @@ from HandHistoryConverter import *
|
||||||
class FullTilt(HandHistoryConverter):
|
class FullTilt(HandHistoryConverter):
|
||||||
|
|
||||||
# Static regexes
|
# 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_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_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_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:
|
if autostart:
|
||||||
self.start()
|
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'
|
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
|
||||||
# we need to recompile the player regexs.
|
# we need to recompile the player regexs.
|
||||||
self.compiledPlayers = players
|
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 #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 #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
|
# 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
|
info = {'type':'ring'}
|
||||||
game = ""
|
|
||||||
|
|
||||||
|
|
||||||
m = self.re_GameInfo.search(handText)
|
m = self.re_GameInfo.search(handText)
|
||||||
if m.group('LTYPE') == "No ":
|
if not m:
|
||||||
structure = "nl"
|
return None
|
||||||
elif m.group('LTYPE') == "Pot ":
|
|
||||||
structure = "pl"
|
|
||||||
elif m.group('LTYPE') == None:
|
|
||||||
structure = "fl"
|
|
||||||
|
|
||||||
if m.group('GAME') == "Hold\'em":
|
mg = m.groupdict()
|
||||||
game = "hold"
|
|
||||||
elif m.group('GAME') == "Omaha":
|
|
||||||
game = "omahahi"
|
|
||||||
elif m.group('GAME') == "Razz":
|
|
||||||
game = "razz"
|
|
||||||
|
|
||||||
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 info
|
||||||
|
|
||||||
return gametype
|
|
||||||
|
|
||||||
def readHandInfo(self, hand):
|
def readHandInfo(self, hand):
|
||||||
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
|
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
|
||||||
|
@ -131,12 +141,12 @@ follow : whether to tail -f the input"""
|
||||||
def markStreets(self, hand):
|
def markStreets(self, hand):
|
||||||
# PREFLOP = ** Dealing down cards **
|
# 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 \*\*\*)|.+)"
|
m = re.search(r"\*\*\* HOLE CARDS \*\*\*(?P<PREFLOP>.+(?=\*\*\* FLOP \*\*\*)|.+)"
|
||||||
r"(\*\*\* FLOP \*\*\*(?P<FLOP> \[\S\S \S\S \S\S\].+(?=\*\*\* TURN \*\*\*)|.+))?"
|
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"(\*\*\* 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)
|
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 \*\*\*)|.+)"
|
m = re.search(r"(?P<ANTES>.+(?=\*\*\* 3RD STREET \*\*\*)|.+)"
|
||||||
r"(\*\*\* 3RD STREET \*\*\*(?P<THIRD>.+(?=\*\*\* 4TH STREET \*\*\*)|.+))?"
|
r"(\*\*\* 3RD STREET \*\*\*(?P<THIRD>.+(?=\*\*\* 4TH STREET \*\*\*)|.+))?"
|
||||||
r"(\*\*\* 4TH STREET \*\*\*(?P<FOURTH>.+(?=\*\*\* 5TH 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
|
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)
|
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)
|
#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(' '))
|
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
|
Map the tuple self.gametype onto the pokerstars string describing it
|
||||||
"""
|
"""
|
||||||
# currently it appears to be something like ["ring", "hold", "nl", sb, bb]:
|
# currently it appears to be something like ["ring", "hold", "nl", sb, bb]:
|
||||||
gs = {"hold" : "Hold'em",
|
gs = {"holdem" : "Hold'em",
|
||||||
"omahahi" : "Omaha",
|
"omahahi" : "Omaha",
|
||||||
"omahahilo" : "FIXME",
|
"omahahilo" : "FIXME",
|
||||||
"razz" : "Razz",
|
"razz" : "Razz",
|
||||||
|
@ -310,7 +310,7 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
||||||
}
|
}
|
||||||
|
|
||||||
logging.debug("gametype: %s" %(self.gametype))
|
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
|
return retstring
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
||||||
|
|
||||||
class HoldemOmahaHand(Hand):
|
class HoldemOmahaHand(Hand):
|
||||||
def __init__(self, hhc, sitename, gametype, handText):
|
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
|
pass # or indeed don't pass and complain instead
|
||||||
logging.debug("HoldemOmahaHand")
|
logging.debug("HoldemOmahaHand")
|
||||||
self.streetList = ['BLINDSANTES', 'PREFLOP','FLOP','TURN','RIVER'] # a list of the observed street names in order
|
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
|
#May be more than 1 bb posting
|
||||||
if self.gametype['limit'] == "fl":
|
if self.gametype['limitType'] == "fl":
|
||||||
(smallbet, bigbet) = self.lookupLimitBetSize()
|
(smallbet, bigbet) = self.lookupLimitBetSize()
|
||||||
else:
|
else:
|
||||||
smallbet = self.sb
|
smallbet = self.sb
|
||||||
|
@ -529,7 +529,7 @@ Card ranks will be uppercased
|
||||||
|
|
||||||
class DrawHand(Hand):
|
class DrawHand(Hand):
|
||||||
def __init__(self, hhc, sitename, gametype, handText):
|
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
|
pass # or indeed don't pass and complain instead
|
||||||
|
|
||||||
def discardHoleCards(self, cards, player):
|
def discardHoleCards(self, cards, player):
|
||||||
|
@ -544,7 +544,7 @@ class DrawHand(Hand):
|
||||||
|
|
||||||
class StudHand(Hand):
|
class StudHand(Hand):
|
||||||
def __init__(self, hhc, sitename, gametype, handText):
|
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
|
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.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order
|
||||||
self.holeStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH']
|
self.holeStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH']
|
||||||
|
|
|
@ -73,7 +73,7 @@ import gettext
|
||||||
gettext.install('myapplication')
|
gettext.install('myapplication')
|
||||||
|
|
||||||
class HandHistoryConverter(threading.Thread):
|
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):
|
def __init__(self, in_path = '-', out_path = '-', sitename = None, follow=False):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
logging.info("HandHistory init called")
|
logging.info("HandHistory init called")
|
||||||
|
@ -97,11 +97,11 @@ class HandHistoryConverter(threading.Thread):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
#TODO : I got rid of most of the hhdir stuff.
|
#TODO : I got rid of most of the hhdir stuff.
|
||||||
tmp = "HandHistoryConverter: '%s'\n" % (self.sitename)
|
tmp = "HandHistoryConverter: '%s'\n" % (self.sitename)
|
||||||
tmp = tmp + "\thhbase: '%s'\n" % (self.hhbase)
|
#tmp = tmp + "\thhbase: '%s'\n" % (self.hhbase)
|
||||||
tmp = tmp + "\thhdir: '%s'\n" % (self.hhdir)
|
#tmp = tmp + "\thhdir: '%s'\n" % (self.hhdir)
|
||||||
tmp = tmp + "\tfiletype: '%s'\n" % (self.filetype)
|
tmp = tmp + "\tfiletype: '%s'\n" % (self.filetype)
|
||||||
tmp = tmp + "\tinfile: '%s'\n" % (self.file)
|
tmp = tmp + "\tinfile: '%s'\n" % (self.in_path)
|
||||||
tmp = tmp + "\toutfile: '%s'\n" % (self.ofile)
|
tmp = tmp + "\toutfile: '%s'\n" % (self.out_path)
|
||||||
#tmp = tmp + "\tgametype: '%s'\n" % (self.gametype[0])
|
#tmp = tmp + "\tgametype: '%s'\n" % (self.gametype[0])
|
||||||
#tmp = tmp + "\tgamebase: '%s'\n" % (self.gametype[1])
|
#tmp = tmp + "\tgamebase: '%s'\n" % (self.gametype[1])
|
||||||
#tmp = tmp + "\tlimit: '%s'\n" % (self.gametype[2])
|
#tmp = tmp + "\tlimit: '%s'\n" % (self.gametype[2])
|
||||||
|
@ -109,29 +109,76 @@ class HandHistoryConverter(threading.Thread):
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
def run(self):
|
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:
|
if self.follow:
|
||||||
for handtext in self.tailHands():
|
for handText in self.tailHands():
|
||||||
self.processHand(handtext)
|
self.processHand(handText)
|
||||||
else:
|
else:
|
||||||
handsList = self.allHands()
|
handsList = self.allHandsAsList()
|
||||||
logging.info("Parsing %d hands" % len(handsList))
|
logging.info("Parsing %d hands" % len(handsList))
|
||||||
for handtext in handsList:
|
for handText in handsList:
|
||||||
self.processHand(handtext)
|
self.processHand(handText)
|
||||||
if self.out_fh != sys.stdout:
|
|
||||||
self.ouf_fh.close()
|
|
||||||
|
|
||||||
def tailHands(self):
|
def tailHands(self):
|
||||||
"""pseudo-code"""
|
"""Generator of handTexts from a tailed file:
|
||||||
while True:
|
Tail the in_path file and yield handTexts separated by re_SplitHands"""
|
||||||
ifile.tell()
|
if in_path == '-': raise StopIteration
|
||||||
text = ifile.read()
|
interval = 1.0 # seconds to sleep between reads for new data
|
||||||
if nomoretext:
|
fd = open(filename,'r')
|
||||||
wait or sleep
|
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:
|
||||||
|
print "%s changed inode numbers from %d to %d" % (filename, fd_results[1], st_results[1])
|
||||||
|
fd = open(filename, 'r')
|
||||||
|
fd.seek(where)
|
||||||
else:
|
else:
|
||||||
ahand = thenexthandinthetext
|
# yield hands
|
||||||
yield(ahand)
|
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"""
|
"""Return a list of handtexts in the file at self.in_path"""
|
||||||
self.readFile()
|
self.readFile()
|
||||||
self.obs = self.obs.strip()
|
self.obs = self.obs.strip()
|
||||||
|
@ -141,17 +188,19 @@ class HandHistoryConverter(threading.Thread):
|
||||||
return
|
return
|
||||||
return re.split(self.re_SplitHands, self.obs)
|
return re.split(self.re_SplitHands, self.obs)
|
||||||
|
|
||||||
def processHand(self, handtext):
|
def processHand(self, handText):
|
||||||
gametype = self.determineGameType(handtext)
|
gametype = self.determineGameType(handText)
|
||||||
logging.debug("gametype %s" % gametype)
|
logging.debug("gametype %s" % gametype)
|
||||||
if gametype is None:
|
if gametype is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
hand = None
|
hand = None
|
||||||
if gametype['game'] in ("hold", "omaha"):
|
if gametype['base'] == 'hold':
|
||||||
hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handtext)
|
hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handText)
|
||||||
elif gametype['game'] in ("razz","stud","stud8"):
|
elif gametype['base'] == 'stud':
|
||||||
hand = Hand.StudHand(self, self.sitename, gametype, handtext)
|
hand = Hand.StudHand(self, self.sitename, gametype, handText)
|
||||||
|
elif gametype['base'] == 'draw':
|
||||||
|
hand = Hand.DrawHand(self, self.sitename, gametype, handText)
|
||||||
|
|
||||||
if hand:
|
if hand:
|
||||||
hand.writeHand(self.out_fh)
|
hand.writeHand(self.out_fh)
|
||||||
|
@ -170,69 +219,7 @@ class HandHistoryConverter(threading.Thread):
|
||||||
if self.obs == "" or self.obs == None:
|
if self.obs == "" or self.obs == None:
|
||||||
print "Did not read anything from file."
|
print "Did not read anything from file."
|
||||||
return
|
return
|
||||||
|
### alala deleted
|
||||||
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()
|
|
||||||
endtime = time.time()
|
endtime = time.time()
|
||||||
print "Processed %d hands in %.3f seconds" % (len(self.hands), endtime - starttime)
|
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 ]
|
# [ ring, hold, nl , sb, bb ]
|
||||||
# Valid types specified in docs/tabledesign.html in Gametypes
|
# Valid types specified in docs/tabledesign.html in Gametypes
|
||||||
def determineGameType(self, handText): abstract
|
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:
|
# Read any of:
|
||||||
# HID HandID
|
# HID HandID
|
||||||
|
@ -331,7 +331,7 @@ class HandHistoryConverter(threading.Thread):
|
||||||
return hands
|
return hands
|
||||||
|
|
||||||
def readFile(self):
|
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.filetype == "text"):
|
||||||
if self.in_path == '-':
|
if self.in_path == '-':
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
# Copyright 2008, Carl Gherardi
|
# Copyright 2008, Carl Gherardi
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -67,7 +69,7 @@ from HandHistoryConverter import *
|
||||||
class PokerStars(HandHistoryConverter):
|
class PokerStars(HandHistoryConverter):
|
||||||
|
|
||||||
# Static regexes
|
# 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_SplitHands = re.compile('\n\n+')
|
||||||
re_HandInfo = re.compile("^Table \'(?P<TABLE>[- a-zA-Z]+)\'(?P<TABLEATTRIBUTES>.+?$)?", re.MULTILINE)
|
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)
|
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()
|
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'
|
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
|
||||||
# we need to recompile the player regexs.
|
# we need to recompile the player regexs.
|
||||||
self.compiledPlayers = players
|
self.compiledPlayers = players
|
||||||
|
@ -111,33 +114,37 @@ follow : whether to tail -f the input"""
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def determineGameType(self, handText):
|
def determineGameType(self, handText):
|
||||||
game = None
|
info = {'type':'ring'}
|
||||||
structure = None
|
|
||||||
sb = None
|
|
||||||
bb = None
|
|
||||||
info = {}
|
|
||||||
|
|
||||||
m = self.re_GameInfo.search(handText)
|
m = self.re_GameInfo.search(handText)
|
||||||
if m:
|
if not m:
|
||||||
info.update(m.groupdict())
|
|
||||||
else:
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
mg = m.groupdict()
|
||||||
|
|
||||||
ltypes = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' }
|
# translations from captured groups to our info strings
|
||||||
gtypes = { 'Hold\'em':'hold', 'Omaha':'omahahi', 'Razz':'razz','7 Card Stud':'studhi' }
|
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' }
|
||||||
for key in info:
|
games = { # base, category
|
||||||
if key == 'LTYPE':
|
"Hold'em" : ('hold','holdem'),
|
||||||
structure = ltypes[info[key]]
|
'Omaha Hi' : ('hold','omahahi'),
|
||||||
if key == 'GAME':
|
'Razz' : ('stud','razz'),
|
||||||
game = gtypes[info[key]]
|
'7 Card Stud' : ('stud','studhi')
|
||||||
if key == 'SB':
|
}
|
||||||
sb = info[key]
|
currencies = { u'€':'EUR', '$':'USD', '':'T$' }
|
||||||
if key == 'BB':
|
if 'LIMIT' in mg:
|
||||||
bb = info[key]
|
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):
|
def readHandInfo(self, hand):
|
||||||
info = {}
|
info = {}
|
||||||
|
|
|
@ -1,36 +1,38 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import EverleafToFpdb
|
import EverleafToFpdb
|
||||||
import py
|
import py
|
||||||
class TestEverleaf:
|
|
||||||
def testGameInfo1(self):
|
|
||||||
e = EverleafToFpdb.Everleaf(autostart=False)
|
def checkGameInfo(hhc, header, info):
|
||||||
g = """Everleaf Gaming Game #3732225
|
assert hhc.determineGameType(header) == info
|
||||||
|
|
||||||
|
def testGameInfo():
|
||||||
|
hhc = EverleafToFpdb.Everleaf(autostart=False)
|
||||||
|
pairs = (
|
||||||
|
(u"""Everleaf Gaming Game #3732225
|
||||||
***** Hand history for game #3732225 *****
|
***** Hand history for game #3732225 *****
|
||||||
Blinds €0.50/ €1 NL Hold'em - 2009/01/11 - 16:09:40
|
Blinds €0.50/ €1 NL Hold'em - 2009/01/11 - 16:09:40
|
||||||
Table Casino Lyon Vert 58
|
Table Casino Lyon Vert 58
|
||||||
Seat 3 is the button
|
Seat 3 is the button
|
||||||
Total number of players: 6"""
|
Total number of players: 6""",
|
||||||
assert e.determineGameType(g) == {'sb':'0.50', 'bb':'1','game':"hold", 'currency':'EUR', 'limit':'nl'}
|
{'type':'ring', 'base':"hold", 'category':'holdem', 'limitType':'nl', 'sb':'0.50', 'bb':'1', 'currency':'EUR'}),
|
||||||
|
("""Everleaf Gaming Game #55198191
|
||||||
|
|
||||||
def testGameInfo2(self):
|
|
||||||
e = EverleafToFpdb.Everleaf(autostart=False)
|
|
||||||
g = """Everleaf Gaming Game #55198191
|
|
||||||
***** Hand history for game #55198191 *****
|
***** Hand history for game #55198191 *****
|
||||||
Blinds $0.50/$1 NL Hold'em - 2008/09/01 - 10:02:11
|
Blinds $0.50/$1 NL Hold'em - 2008/09/01 - 10:02:11
|
||||||
Table Speed Kuala
|
Table Speed Kuala
|
||||||
Seat 8 is the button
|
Seat 8 is the button
|
||||||
Total number of players: 10"""
|
Total number of players: 10""",
|
||||||
assert e.determineGameType(g) == {'sb':'0.50', 'bb':'1','game':"hold", 'currency':'USD', 'limit':'nl'}
|
{'type':'ring', 'base':"hold", 'category':'holdem', 'limitType':'nl', 'sb':'0.50', 'bb':'1', 'currency':'USD'}),
|
||||||
|
("""Everleaf Gaming Game #75065769
|
||||||
def testGameInfo3(self):
|
|
||||||
# Note: It looks difficult to distinguish T$ from play money.
|
|
||||||
e = EverleafToFpdb.Everleaf(autostart=False)
|
|
||||||
g = """Everleaf Gaming Game #75065769
|
|
||||||
***** Hand history for game #75065769 *****
|
***** Hand history for game #75065769 *****
|
||||||
Blinds 10/20 NL Hold'em - 2009/02/25 - 17:30:32
|
Blinds 10/20 NL Hold'em - 2009/02/25 - 17:30:32
|
||||||
Table 2
|
Table 2
|
||||||
Seat 1 is the button
|
Seat 1 is the button
|
||||||
Total number of players: 10"""
|
Total number of players: 10""",
|
||||||
assert e.determineGameType(g) == {'sb':'10', 'bb':'20','game':"hold", 'currency':'T$', 'limit':'nl'}
|
{'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