Merge branch 'carl'

This commit is contained in:
steffen123 2010-08-21 18:00:33 +02:00
commit ee7fc47dc1
4 changed files with 274 additions and 103 deletions

View File

@ -44,8 +44,9 @@ class Betfair(HandHistoryConverter):
siteId = 7 # Needs to match id entry in Sites database siteId = 7 # Needs to match id entry in Sites database
# Static regexes # Static regexes
#re_SplitHands = re.compile(r'\n\n+') # Betfair 1.0 version
re_GameInfo = re.compile("^(?P<LIMIT>NL|PL|) (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAME>(Texas Hold\'em|Omaha Hi|Razz))", re.MULTILINE) re_GameInfo = re.compile("^(?P<LIMIT>NL|PL|) (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAME>(Texas Hold\'em|Omaha Hi|Razz))", re.MULTILINE)
re_SplitHands = re.compile(r'\n\n+') re_SplitHands = re.compile(r'End of hand .{2}-\d{7,9}-\d+ \*\*\*\*\*\n')
re_HandInfo = re.compile("\*\*\*\*\* Betfair Poker Hand History for Game (?P<HID>[0-9]+) \*\*\*\*\*\n(?P<LIMIT>NL|PL|) (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>(Texas Hold\'em|Omaha Hi|Razz)) - (?P<DATETIME>[a-zA-Z]+, [a-zA-Z]+ \d+, \d\d:\d\d:\d\d GMT \d\d\d\d)\nTable (?P<TABLE>[ a-zA-Z0-9]+) \d-max \(Real Money\)\nSeat (?P<BUTTON>[0-9]+)", re.MULTILINE) re_HandInfo = re.compile("\*\*\*\*\* Betfair Poker Hand History for Game (?P<HID>[0-9]+) \*\*\*\*\*\n(?P<LIMIT>NL|PL|) (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>(Texas Hold\'em|Omaha Hi|Razz)) - (?P<DATETIME>[a-zA-Z]+, [a-zA-Z]+ \d+, \d\d:\d\d:\d\d GMT \d\d\d\d)\nTable (?P<TABLE>[ a-zA-Z0-9]+) \d-max \(Real Money\)\nSeat (?P<BUTTON>[0-9]+)", re.MULTILINE)
re_Button = re.compile(ur"^Seat (?P<BUTTON>\d+) is the button", re.MULTILINE) re_Button = re.compile(ur"^Seat (?P<BUTTON>\d+) is the button", re.MULTILINE)
re_PlayerInfo = re.compile("Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*)\s\(\s(\$(?P<CASH>[.0-9]+)) \)") re_PlayerInfo = re.compile("Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*)\s\(\s(\$(?P<CASH>[.0-9]+)) \)")

View File

@ -326,33 +326,104 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
or None if we fail to get the info """ or None if we fail to get the info """
#TODO: which parts are optional/required? #TODO: which parts are optional/required?
# Read any of:
# HID HandID
# TABLE Table name
# SB small blind
# BB big blind
# GAMETYPE gametype
# YEAR MON DAY HR MIN SEC datetime
# BUTTON button seat number
def readHandInfo(self, hand): abstract def readHandInfo(self, hand): abstract
"""Read and set information about the hand being dealt, and set the correct
variables in the Hand object 'hand
* hand.startTime - a datetime object
* hand.handid - The site identified for the hand - a string.
* hand.tablename
* hand.buttonpos
* hand.maxseats
* hand.mixed
Tournament fields:
* hand.tourNo - The site identified tournament id as appropriate - a string.
* hand.buyin
* hand.fee
* hand.buyinCurrency
* hand.koBounty
* hand.isKO
* hand.level
"""
#TODO: which parts are optional/required?
# Needs to return a list of lists in the format
# [['seat#', 'player1name', 'stacksize'] ['seat#', 'player2name', 'stacksize'] [...]]
def readPlayerStacks(self, hand): abstract def readPlayerStacks(self, hand): abstract
"""This function is for identifying players at the table, and to pass the
information on to 'hand' via Hand.addPlayer(seat, name, chips)
At the time of writing the reference function in the PS converter is:
log.debug("readPlayerStacks")
m = self.re_PlayerInfo.finditer(hand.handText)
for a in m:
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
Which is pretty simple because the hand history format is consistent. Other hh formats aren't so nice.
This is the appropriate place to identify players that are sitting out and ignore them
*** NOTE: You may find this is a more appropriate place to set hand.maxseats ***
"""
def compilePlayerRegexs(self): abstract def compilePlayerRegexs(self): abstract
"""Compile dynamic regexes -- these explicitly match known player names and must be updated if a new player joins""" """Compile dynamic regexes -- compile player dependent regexes.
Depending on the ambiguity of lines you may need to match, and the complexity of
player names - we found that we needed to recompile some regexes for player actions so that they actually contained the player names.
eg.
We need to match the ante line:
<Player> antes $1.00
But <Player> is actually named
YesI antes $4000 - A perfectly legal playername
Giving:
YesI antes $4000 antes $1.00
Which without care in your regexes most people would match 'YesI' and not 'YesI antes $4000'
"""
# Needs to return a MatchObject with group names identifying the streets into the Hand object # 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 # so groups are called by street names 'PREFLOP', 'FLOP', 'STREET2' etc
# blinds are done seperately # blinds are done seperately
def markStreets(self, hand): abstract def markStreets(self, hand): abstract
"""For dividing the handText into sections.
The function requires you to pass a MatchObject with groups specifically labeled with
the 'correct' street names.
The Hand object will use the various matches for assigning actions to the correct streets.
Flop Based Games:
PREFLOP, FLOP, TURN, RIVER
Draw Based Games:
PREDEAL, DEAL, DRAWONE, DRAWTWO, DRAWTHREE
Stud Based Games:
ANTES, THIRD, FOURTH, FIFTH, SIXTH, SEVENTH
The Stars HHC has a good reference implementation
"""
#Needs to return a list in the format #Needs to return a list in the format
# ['player1name', 'player2name', ...] where player1name is the sb and player2name is bb, # ['player1name', 'player2name', ...] where player1name is the sb and player2name is bb,
# addtional players are assumed to post a bb oop # addtional players are assumed to post a bb oop
def readBlinds(self, hand): abstract def readBlinds(self, hand): abstract
"""Function for reading the various blinds from the hand history.
Pass any small blind to hand.addBlind(<name>, "small blind", <value>)
- unless it is a single dead small blind then use:
hand.addBlind(<name>, 'secondsb', <value>)
Pass any big blind to hand.addBlind(<name>, "big blind", <value>)
Pass any play posting both big and small blinds to hand.addBlind(<name>, 'both', <vale>)
"""
def readAntes(self, hand): abstract def readAntes(self, hand): abstract
"""Function for reading the antes from the hand history and passing the hand.addAnte"""
def readBringIn(self, hand): abstract def readBringIn(self, hand): abstract
def readButton(self, hand): abstract def readButton(self, hand): abstract
def readHeroCards(self, hand): abstract def readHeroCards(self, hand): abstract
@ -409,18 +480,6 @@ or None if we fail to get the info """
self.filetype = filetype self.filetype = filetype
self.codepage = codepage self.codepage = codepage
#This function doesn't appear to be used
def splitFileIntoHands(self):
hands = []
self.obs = self.obs.strip()
list = self.re_SplitHands.split(self.obs)
list.pop() #Last entry is empty
for l in list:
# print "'" + l + "'"
hands = hands + [Hand.Hand(self.config, self.sitename, self.gametype, l)]
# TODO: This looks like it could be replaced with a list comp.. ?
return hands
def __listof(self, x): def __listof(self, x):
if isinstance(x, list) or isinstance(x, tuple): if isinstance(x, list) or isinstance(x, tuple):
return x return x

View File

@ -43,45 +43,101 @@ class OnGame(HandHistoryConverter):
codepage = ("utf8", "cp1252") codepage = ("utf8", "cp1252")
siteId = 5 # Needs to match id entry in Sites database siteId = 5 # Needs to match id entry in Sites database
substitutions = {
'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
'LS' : "\$|\xe2\x82\xac|" # legal currency symbols - Euro(cp1252, utf-8)
}
limits = { 'NO_LIMIT':'nl', 'LIMIT':'fl'}
games = { # base, category
"TEXAS_HOLDEM" : ('hold','holdem'),
# 'Omaha' : ('hold','omahahi'),
# 'Omaha Hi/Lo' : ('hold','omahahilo'),
# 'Razz' : ('stud','razz'),
# 'RAZZ' : ('stud','razz'),
# '7 Card Stud' : ('stud','studhi'),
# '7 Card Stud Hi/Lo' : ('stud','studhilo'),
# 'Badugi' : ('draw','badugi'),
# 'Triple Draw 2-7 Lowball' : ('draw','27_3draw'),
# '5 Card Draw' : ('draw','fivedraw')
}
#self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)') #self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)')
# Static regexes # Static regexes
re_SplitHands = re.compile('\n\n\n+') re_SplitHands = re.compile(r'End of hand .{2}-\d{7,9}-\d+ \*\*\*\*\*\n')
#Texas Hold'em $.5-$1 NL (real money), hand #P4-76915775-797 # ***** History for hand R5-75443872-57 *****
#Table Kuopio, 20 Sep 2008 11:59 PM # Start hand: Wed Aug 18 19:29:10 GMT+0100 2010
re_HandInfo = re.compile(r"Texas Hold'em \$?(?P<SB>[.0-9]+)-\$?(?P<BB>[.0-9]+) NL \(real money\), hand #(?P<HID>[-A-Z\d]+)\nTable\ (?P<TABLE>[\' \w]+), (?P<DATETIME>\d\d \w+ \d\d\d\d \d\d:\d\d (AM|PM))") # Table: someplace [75443872] (LIMIT TEXAS_HOLDEM 0.50/1, Real money)
# SB BB HID TABLE DAY MON YEAR HR12 MIN AMPM re_HandInfo = re.compile(u"""
\*\*\*\*\*\sHistory\sfor\shand\s(?P<HID>[-A-Z\d]+).*
Start\shand:\s(?P<DATETIME>.*)
Table:\s(?P<TABLE>[\'\w]+)\s\[\d+\]\s\(
(
(?P<LIMIT>No\sLimit|Limit|LIMIT|Pot\sLimit)\s
(?P<GAME>TEXAS_HOLDEM|RAZZ)\s
(?P<SB>[.0-9]+)/
(?P<BB>[.0-9]+)
)?
""" % substitutions, re.MULTILINE|re.DOTALL|re.VERBOSE)
# Wed Aug 18 19:45:30 GMT+0100 2010
re_DateTime = re.compile("""
[a-zA-Z]{3}\s
(?P<M>[a-zA-Z]{3})\s
(?P<D>[0-9]{2})\s
(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)\sGMT
(?P<OFFSET>[-+]\d+)\s
(?P<Y>[0-9]{4})
""", re.MULTILINE|re.VERBOSE)
# self.rexx.button_re = re.compile('#SUMMARY\nDealer: (?P<BUTTONPNAME>.*)\n') # self.rexx.button_re = re.compile('#SUMMARY\nDealer: (?P<BUTTONPNAME>.*)\n')
#Seat 1: .Lucchess ($4.17 in chips) #Seat 1: .Lucchess ($4.17 in chips)
re_PlayerInfo = re.compile(u'Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \((\$(?P<CASH>[.0-9]+) in chips)\)') re_PlayerInfo = re.compile(u'Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \((?P<CASH>[.0-9]+) \)')
#ANTES/BLINDS def compilePlayerRegexs(self, hand):
#helander2222 posts blind ($0.25), lopllopl posts blind ($0.50). players = set([player[1] for player in hand.players])
re_PostSB = re.compile('(?P<PNAME>.*) posts blind \(\$?(?P<SB>[.0-9]+)\), ') if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
re_PostBB = re.compile('\), (?P<PNAME>.*) posts blind \(\$?(?P<BB>[.0-9]+)\).') # we need to recompile the player regexs.
re_PostBoth = re.compile('.*\n(?P<PNAME>.*): posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)') # TODO: should probably rename re_HeroCards and corresponding method,
re_HeroCards = re.compile('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<CARDS>.*) \]') # since they are used to find all cards on lines starting with "Dealt to:"
# They still identify the hero.
#lopllopl checks, Eurolll checks, .Lucchess checks.
re_Action = re.compile('(, )?(?P<PNAME>.*?)(?P<ATYPE> bets| checks| raises| calls| folds)( \$(?P<BET>\d*\.?\d*))?( and is all-in)?') #ANTES/BLINDS
re_Board = re.compile(r"\[board cards (?P<CARDS>.+) \]") #helander2222 posts blind ($0.25), lopllopl posts blind ($0.50).
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
#Uchilka shows [ KC,JD ] subst = {'PLYR': player_re, 'CUR': self.sym[hand.gametype['currency']]}
re_ShowdownAction = re.compile('(?P<PNAME>.*) shows \[ (?P<CARDS>.+) \]') re_PostSB = re.compile('(?P<PNAME>.*) posts blind \(\$?(?P<SB>[.0-9]+)\), ')
re_PostBB = re.compile('\), (?P<PNAME>.*) posts blind \(\$?(?P<BB>[.0-9]+)\).')
# TODO: read SUMMARY correctly for collected pot stuff. re_Antes = re.compile(r"^%(PLYR)s: posts the ante %(CUR)s(?P<ANTE>[.0-9]+)" % subst, re.MULTILINE)
#Uchilka, bets $11.75, collects $23.04, net $11.29 re_BringIn = re.compile(r"^%(PLYR)s: brings[- ]in( low|) for %(CUR)s(?P<BRINGIN>[.0-9]+)" % subst, re.MULTILINE)
re_CollectPot = re.compile('(?P<PNAME>.*), bets.+, collects \$(?P<POT>\d*\.?\d*), net.* ') re_PostBoth = re.compile('.*\n(?P<PNAME>.*): posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)')
re_sitsOut = re.compile('(?P<PNAME>.*) sits out') re_HeroCards = re.compile('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<CARDS>.*) \]')
#lopllopl checks, Eurolll checks, .Lucchess checks.
re_Action = re.compile('(, )?(?P<PNAME>.*?)(?P<ATYPE> bets| checks| raises| calls| folds)( \$(?P<BET>\d*\.?\d*))?( and is all-in)?')
re_Board = re.compile(r"\[board cards (?P<CARDS>.+) \]")
#Uchilka shows [ KC,JD ]
re_ShowdownAction = re.compile('(?P<PNAME>.*) shows \[ (?P<CARDS>.+) \]')
# TODO: read SUMMARY correctly for collected pot stuff.
#Uchilka, bets $11.75, collects $23.04, net $11.29
re_CollectPot = re.compile('(?P<PNAME>.*), bets.+, collects \$(?P<POT>\d*\.?\d*), net.* ')
re_sitsOut = re.compile('(?P<PNAME>.*) sits out')
def readSupportedGames(self): def readSupportedGames(self):
pass return [
["ring", "hold", "fl"],
["ring", "hold", "nl"],
]
def determineGameType(self, handText): def determineGameType(self, handText):
# Cheating with this regex, only support nlhe at the moment # Inspect the handText and return the gametype dict
gametype = ["ring", "hold", "nl"] # gametype dict is: {'limitType': xxx, 'base': xxx, 'category': xxx}
info = {}
m = self.re_HandInfo.search(handText) m = self.re_HandInfo.search(handText)
if not m: if not m:
@ -90,36 +146,54 @@ class OnGame(HandHistoryConverter):
log.error(_("determineGameType: Raising FpdbParseError")) log.error(_("determineGameType: Raising FpdbParseError"))
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp) raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
gametype = gametype + [m.group('SB')] mg = m.groupdict()
gametype = gametype + [m.group('BB')]
info['type'] = 'ring'
return gametype info['currency'] = 'USD'
if 'LIMIT' in mg:
info['limitType'] = self.limits[mg['LIMIT']]
if 'GAME' in mg:
(info['base'], info['category']) = self.games[mg['GAME']]
if 'SB' in mg:
info['sb'] = mg['SB']
if 'BB' in mg:
info['bb'] = mg['BB']
return info
def readHandInfo(self, hand): def readHandInfo(self, hand):
m = self.re_HandInfo.search(hand.string) info = {}
hand.handid = m.group('HID') m = self.re_HandInfo.search(hand.handText)
hand.tablename = m.group('TABLE')
#hand.buttonpos = self.rexx.button_re.search(hand.string).group('BUTTONPNAME')
# These work, but the info is already in the Hand class - should be used for tourneys though.
# m.group('SB')
# m.group('BB')
# m.group('GAMETYPE')
# Believe Everleaf time is GMT/UTC, no transation necessary if m:
# Stars format (Nov 10 2008): 2008/11/07 12:38:49 CET [2008/11/07 7:38:49 ET] info.update(m.groupdict())
# or : 2008/11/07 12:38:49 ET
# Not getting it in my HH files yet, so using log.debug("readHandInfo: %s" % info)
# 2008/11/10 3:58:52 ET for key in info:
#TODO: Do conversion from GMT to ET if key == 'DATETIME':
#TODO: Need some date functions to convert to different timezones (Date::Manip for perl rocked for this) #'Wed Aug 18 19:45:30 GMT+0100 2010
# %a %b %d %H:%M:%S %z %Y
hand.startTime = time.strptime(m.group('DATETIME'), "%d %b %Y %I:%M %p") #hand.startTime = time.strptime(m.group('DATETIME'), "%a %b %d %H:%M:%S GMT%z %Y")
#hand.starttime = "%d/%02d/%02d %d:%02d:%02d ET" %(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), # Stupid library doesn't seem to support %z (http://docs.python.org/library/time.html?highlight=strptime#time.strptime)
#int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC'))) # So we need to re-interpret te string to be useful
m1 = self.re_DateTime.finditer(info[key])
for a in m1:
datetimestr = "%s %s %s %s:%s:%s" % (a.group('M'),a.group('D'), a.group('Y'), a.group('H'),a.group('MIN'),a.group('S'))
hand.startTime = time.strptime(datetimestr, "%b %d %Y %H:%M:%S")
# TODO: Manually adjust time against OFFSET
if key == 'HID':
hand.handid = info[key]
if key == 'TABLE':
hand.tablename = info[key]
# TODO: These
hand.buttonpos = 1
hand.maxseats = 10
hand.mixed = None
def readPlayerStacks(self, hand): def readPlayerStacks(self, hand):
m = self.re_PlayerInf.finditer(hand.string) m = self.re_PlayerInfo.finditer(hand.handText)
players = []
for a in m: for a in m:
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH')) hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
@ -128,13 +202,27 @@ class OnGame(HandHistoryConverter):
# This re fails if, say, river is missing; then we don't get the ** that starts the river. # This re fails if, say, river is missing; then we don't get the ** that starts the river.
#m = re.search('(\*\* Dealing down cards \*\*\n)(?P<PREFLOP>.*?\n\*\*)?( Dealing Flop \*\* \[ (?P<FLOP1>\S\S), (?P<FLOP2>\S\S), (?P<FLOP3>\S\S) \])?(?P<FLOP>.*?\*\*)?( Dealing Turn \*\* \[ (?P<TURN1>\S\S) \])?(?P<TURN>.*?\*\*)?( Dealing River \*\* \[ (?P<RIVER1>\S\S) \])?(?P<RIVER>.*)', hand.string,re.DOTALL) #m = re.search('(\*\* Dealing down cards \*\*\n)(?P<PREFLOP>.*?\n\*\*)?( Dealing Flop \*\* \[ (?P<FLOP1>\S\S), (?P<FLOP2>\S\S), (?P<FLOP3>\S\S) \])?(?P<FLOP>.*?\*\*)?( Dealing Turn \*\* \[ (?P<TURN1>\S\S) \])?(?P<TURN>.*?\*\*)?( Dealing River \*\* \[ (?P<RIVER1>\S\S) \])?(?P<RIVER>.*)', hand.string,re.DOTALL)
m = re.search(r"PRE-FLOP(?P<PREFLOP>.+(?=FLOP)|.+(?=SHOWDOWN))" #if hand.gametype['base'] in ("hold"):
r"(FLOP (?P<FLOP>\[board cards .+ \].+(?=TURN)|.+(?=SHOWDOWN)))?" #elif hand.gametype['base'] in ("stud"):
r"(TURN (?P<TURN>\[board cards .+ \].+(?=RIVER)|.+(?=SHOWDOWN)))?" #elif hand.gametype['base'] in ("draw"):
r"(RIVER (?P<RIVER>\[board cards .+ \].+(?=SHOWDOWN)))?", hand.string,re.DOTALL) # only holdem so far:
m = re.search(r"pocket cards(?P<PREFLOP>.+(?=flop)|.+(?=Summary))"
r"(flop (?P<FLOP>\[\S\S, \S\S, \S\S\].+(?=turn)|.+(?=Summary)))?"
r"(turn (?P<TURN>\[\S\S, \S\S, \S\S\, \S\S\].+(?=river)|.+(?=Summary)))?"
r"(river (?P<RIVER>\[\S\S, \S\S, \S\S\, \S\S, \S\S\].+(?=Summary)))?", hand.handText, re.DOTALL)
hand.addStreets(m) hand.addStreets(m)
#Needs to return a list in the format
# ['player1name', 'player2name', ...] where player1name is the sb and player2name is bb,
# addtional players are assumed to post a bb oop
def readButton(self, hand):
m = self.re_Button.search(hand.handText)
if m:
hand.buttonpos = int(m.group('BUTTON'))
else:
log.info(_('readButton: not found'))
def readCommunityCards(self, hand, street): def readCommunityCards(self, hand, street):
print hand.streets.group(street) print hand.streets.group(street)
@ -144,17 +232,30 @@ class OnGame(HandHistoryConverter):
def readBlinds(self, hand): def readBlinds(self, hand):
try: try:
m = self.re_PostSB.search(hand.string) m = self.re_PostSB.search(hand.handText)
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
except: # no small blind except: # no small blind
hand.addBlind(None, None, None) hand.addBlind(None, None, None)
for a in self.re_PostBB.finditer(hand.string): for a in self.re_PostBB.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
for a in self.re_PostBoth.finditer(hand.string): for a in self.re_PostBoth.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB')) hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB'))
def readAntes(self, hand):
log.debug(_("reading antes"))
m = self.re_Antes.finditer(hand.handText)
for player in m:
#~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
hand.addAnte(player.group('PNAME'), player.group('ANTE'))
def readBringIn(self, hand):
m = self.re_BringIn.search(hand.handText,re.DOTALL)
if m:
#~ logging.debug("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
def readHeroCards(self, hand): def readHeroCards(self, hand):
m = self.re_HeroCards.search(hand.string) m = self.re_HeroCards.search(hand.handText)
if(m == None): if(m == None):
#Not involved in hand #Not involved in hand
hand.involved = False hand.involved = False
@ -185,13 +286,13 @@ class OnGame(HandHistoryConverter):
# TODO: Everleaf does not record uncalled bets. # TODO: Everleaf does not record uncalled bets.
def readShowdownActions(self, hand): def readShowdownActions(self, hand):
for shows in self.re_ShowdownAction.finditer(hand.string): for shows in self.re_ShowdownAction.finditer(hand.handText):
cards = shows.group('CARDS') cards = shows.group('CARDS')
cards = set(cards.split(',')) cards = set(cards.split(','))
hand.addShownCards(cards, shows.group('PNAME')) hand.addShownCards(cards, shows.group('PNAME'))
def readCollectPot(self,hand): def readCollectPot(self,hand):
for m in self.re_CollectPot.finditer(hand.string): for m in self.re_CollectPot.finditer(hand.handText):
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT')) hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
def readShownCards(self,hand): def readShownCards(self,hand):

View File

@ -1093,6 +1093,7 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
self.status_bar = None self.status_bar = None
self.quitting = False self.quitting = False
self.visible = False
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("delete_event", self.delete_event) self.window.connect("delete_event", self.delete_event)
self.window.connect("destroy", self.destroy) self.window.connect("destroy", self.destroy)
@ -1130,6 +1131,7 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
self.tab_main_help(None, None) self.tab_main_help(None, None)
self.window.show() self.window.show()
self.visible = True # Flip on
self.load_profile(create_db = True) self.load_profile(create_db = True)
if not options.errorsToConsole: if not options.errorsToConsole:
@ -1165,21 +1167,31 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
self.window.connect('window-state-event', self.window_state_event_cb) self.window.connect('window-state-event', self.window_state_event_cb)
sys.stderr.write(_("fpdb starting ...")) sys.stderr.write(_("fpdb starting ..."))
def __iconify(self):
self.visible = False
self.window.set_skip_taskbar_hint(True)
self.window.set_skip_pager_hind(True)
def __deiconify(self):
self.visible = True
self.window.set_skip_taskbar_hint(False)
self.window.set_skip_pager_hind(False)
def window_state_event_cb(self, window, event): def window_state_event_cb(self, window, event):
# Deal with iconification first
if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED: if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
# -20 = GWL_EXSTYLE can't find it in the pywin32 libs
#bits = win32api.GetWindowLong(self.window.window.handle, -20)
#bits = bits ^ (win32con.WS_EX_TOOLWINDOW | win32con.WS_EX_APPWINDOW)
#win32api.SetWindowLong(self.window.window.handle, -20, bits)
if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED: if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
self.window.hide() self.__iconify()
self.window.set_skip_taskbar_hint(True)
self.window.set_skip_pager_hint(True)
else: else:
self.window.set_skip_taskbar_hint(False) self.__deiconify()
self.window.set_skip_pager_hint(False) if not event.new_window_state & gtk.gdk.WINDOW_STATE_WITHDRAWN:
return True
# And then the tray icon click
if event.new_window_state & gtk.gdk.WINDOW_STATE_WITHDRAWN:
self.__iconify()
else:
self.__deiconify()
# Tell GTK not to propagate this signal any further # Tell GTK not to propagate this signal any further
return True return True
@ -1197,11 +1209,9 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
def statusicon_activate(self, widget, data = None): def statusicon_activate(self, widget, data = None):
# Let's allow the tray icon to toggle window visibility, the way # Let's allow the tray icon to toggle window visibility, the way
# most other apps work # most other apps work
shown = self.window.get_property('visible') if self.visible:
if shown:
self.window.hide() self.window.hide()
else: else:
self.window.show()
self.window.present() self.window.present()
def info_box(self, str1, str2): def info_box(self, str1, str2):