2010-07-08 20:01:03 +02:00
#!/usr/bin/env python
2009-03-10 00:03:17 +01:00
# -*- coding: utf-8 -*-
#
2011-03-10 06:16:31 +01:00
# Copyright 2008-2011, Carl Gherardi
2009-03-06 02:24:38 +01:00
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
2010-09-23 08:31:16 +02:00
import L10n
_ = L10n . get_translation ( )
2009-07-13 06:37:51 +02:00
# TODO: straighten out discards for draw games
2009-08-09 16:19:43 +02:00
2009-03-06 02:24:38 +01:00
import sys
from HandHistoryConverter import *
2011-02-25 20:18:12 +01:00
from decimal_wrapper import Decimal
2009-03-06 02:24:38 +01:00
# PokerStars HH Format
class PokerStars ( HandHistoryConverter ) :
2009-03-15 06:32:52 +01:00
2009-08-09 16:19:43 +02:00
# Class Variables
sitename = " PokerStars "
filetype = " text "
2009-11-22 05:34:11 +01:00
codepage = ( " utf8 " , " cp1252 " )
2009-08-09 16:19:43 +02:00
siteId = 2 # Needs to match id entry in Sites database
2009-07-13 06:37:51 +02:00
2009-08-01 17:51:37 +02:00
mixes = { ' HORSE ' : ' horse ' , ' 8-Game ' : ' 8game ' , ' HOSE ' : ' hose ' } # Legal mixed games
2010-10-11 10:40:15 +02:00
sym = { ' USD ' : " \ $ " , ' CAD ' : " \ $ " , ' T$ ' : " " , " EUR " : " \xe2 \x82 \xac " , " GBP " : " \xa3 " , " play " : " " } # ADD Euro, Sterling, etc HERE
2009-07-31 00:06:13 +02:00
substitutions = {
2009-08-07 01:27:52 +02:00
' LEGAL_ISO ' : " USD|EUR|GBP|CAD|FPP " , # legal ISO currency codes
2009-11-22 05:34:11 +01:00
' LS ' : " \ $| \xe2 \x82 \xac | " # legal currency symbols - Euro(cp1252, utf-8)
2009-07-31 00:06:13 +02:00
}
2010-07-07 06:58:42 +02:00
# translations from captured groups to fpdb info strings
Lim_Blinds = { ' 0.04 ' : ( ' 0.01 ' , ' 0.02 ' ) , ' 0.10 ' : ( ' 0.02 ' , ' 0.05 ' ) , ' 0.20 ' : ( ' 0.05 ' , ' 0.10 ' ) ,
2010-08-16 00:31:17 +02:00
' 0.40 ' : ( ' 0.10 ' , ' 0.20 ' ) , ' 0.50 ' : ( ' 0.10 ' , ' 0.25 ' ) ,
' 1.00 ' : ( ' 0.25 ' , ' 0.50 ' ) , ' 1 ' : ( ' 0.25 ' , ' 0.50 ' ) ,
' 2.00 ' : ( ' 0.50 ' , ' 1.00 ' ) , ' 2 ' : ( ' 0.50 ' , ' 1.00 ' ) ,
' 4.00 ' : ( ' 1.00 ' , ' 2.00 ' ) , ' 4 ' : ( ' 1.00 ' , ' 2.00 ' ) ,
' 6.00 ' : ( ' 1.00 ' , ' 3.00 ' ) , ' 6 ' : ( ' 1.00 ' , ' 3.00 ' ) ,
' 8.00 ' : ( ' 2.00 ' , ' 4.00 ' ) , ' 8 ' : ( ' 2.00 ' , ' 4.00 ' ) ,
' 10.00 ' : ( ' 2.00 ' , ' 5.00 ' ) , ' 10 ' : ( ' 2.00 ' , ' 5.00 ' ) ,
' 20.00 ' : ( ' 5.00 ' , ' 10.00 ' ) , ' 20 ' : ( ' 5.00 ' , ' 10.00 ' ) ,
' 30.00 ' : ( ' 10.00 ' , ' 15.00 ' ) , ' 30 ' : ( ' 10.00 ' , ' 15.00 ' ) ,
2011-01-12 08:09:27 +01:00
' 40.00 ' : ( ' 10.00 ' , ' 20.00 ' ) , ' 40 ' : ( ' 10.00 ' , ' 20.00 ' ) ,
2010-08-16 00:31:17 +02:00
' 60.00 ' : ( ' 15.00 ' , ' 30.00 ' ) , ' 60 ' : ( ' 15.00 ' , ' 30.00 ' ) ,
2010-12-17 04:24:07 +01:00
' 80.00 ' : ( ' 20.00 ' , ' 40.00 ' ) , ' 80 ' : ( ' 20.00 ' , ' 40.00 ' ) ,
2010-08-16 00:31:17 +02:00
' 100.00 ' : ( ' 25.00 ' , ' 50.00 ' ) , ' 100 ' : ( ' 25.00 ' , ' 50.00 ' ) ,
' 200.00 ' : ( ' 50.00 ' , ' 100.00 ' ) , ' 200 ' : ( ' 50.00 ' , ' 100.00 ' ) ,
' 400.00 ' : ( ' 100.00 ' , ' 200.00 ' ) , ' 400 ' : ( ' 100.00 ' , ' 200.00 ' ) ,
2010-12-17 04:24:07 +01:00
' 800.00 ' : ( ' 200.00 ' , ' 400.00 ' ) , ' 800 ' : ( ' 200.00 ' , ' 400.00 ' ) ,
2010-08-16 00:31:17 +02:00
' 1000.00 ' : ( ' 250.00 ' , ' 500.00 ' ) , ' 1000 ' : ( ' 250.00 ' , ' 500.00 ' )
2010-08-12 09:35:29 +02:00
}
2010-07-07 06:58:42 +02:00
limits = { ' No Limit ' : ' nl ' , ' Pot Limit ' : ' pl ' , ' Limit ' : ' fl ' , ' LIMIT ' : ' fl ' }
games = { # base, category
" Hold ' em " : ( ' 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 ' ) ,
2010-09-01 18:40:36 +02:00
' Single Draw 2-7 Lowball ' : ( ' draw ' , ' 27_1draw ' ) ,
2010-07-07 06:58:42 +02:00
' 5 Card Draw ' : ( ' draw ' , ' fivedraw ' )
}
currencies = { u ' € ' : ' EUR ' , ' $ ' : ' USD ' , ' ' : ' T$ ' }
2009-07-31 00:06:13 +02:00
2009-03-06 02:24:38 +01:00
# Static regexes
2009-11-22 05:34:11 +01:00
re_GameInfo = re . compile ( u """
2011-02-06 23:39:42 +01:00
PokerStars ( \sHome ) ? \sGame \s \#(?P<HID>[0-9]+):\s+
( \{ . * \} \s + ) ? ( Tournament \s \# # open paren of tournament info
2009-07-31 00:06:13 +02:00
( ? P < TOURNO > \d + ) , \s
2010-01-22 23:42:44 +01:00
# here's how I plan to use LS
2010-08-03 13:52:49 +02:00
( ? P < BUYIN > ( ? P < BIAMT > [ % ( LS ) s \d \. ] + ) ? \+ ? ( ? P < BIRAKE > [ % ( LS ) s \d \. ] + ) ? \+ ? ( ? P < BOUNTY > [ % ( LS ) s \d \. ] + ) ? \s ? ( ? P < TOUR_ISO > % ( LEGAL_ISO ) s ) ? | Freeroll ) \s + ) ?
2010-01-22 23:42:44 +01:00
# close paren of tournament info
2010-08-04 07:16:34 +02:00
( ? P < MIXED > HORSE | 8 \- Game | HOSE | Mixed PLH / PLO ) ? \s ? \( ?
2010-09-01 18:40:36 +02:00
( ? P < GAME > Hold \' em|Razz|RAZZ|7 \ sCard \ sStud|7 \ sCard \ sStud \ sHi/Lo|Omaha|Omaha \ sHi/Lo|Badugi|Triple \ sDraw \ s2 \ -7 \ sLowball|Single \ sDraw \ s2 \ -7 \ sLowball|5 \ sCard \ sDraw) \ s
2010-03-30 07:04:39 +02:00
( ? P < LIMIT > No \sLimit | Limit | LIMIT | Pot \sLimit ) \) ? , ? \s
2010-07-10 21:29:07 +02:00
( - \s ) ?
( Match . * ) ? #TODO: waiting for reply from user as to what this means
2010-07-10 20:39:43 +02:00
( Level \s ( ? P < LEVEL > [ IVXLC ] + ) \s ) ?
2009-07-31 00:06:13 +02:00
\( ? # open paren of the stakes
( ? P < CURRENCY > % ( LS ) s | ) ?
2009-08-03 05:50:44 +02:00
( ? P < SB > [ .0 - 9 ] + ) / ( % ( LS ) s ) ?
2009-07-31 00:06:13 +02:00
( ? P < BB > [ .0 - 9 ] + )
2010-11-04 11:31:14 +01:00
( ? P < BLAH > \s - \s [ % ( LS ) s \d \. ] + \sCap \s - \s ) ? # Optional Cap part
2009-07-31 00:06:13 +02:00
\s ? ( ? P < ISO > % ( LEGAL_ISO ) s ) ?
2010-11-13 05:04:13 +01:00
\) # close paren of the stakes
2010-11-16 05:50:36 +01:00
( ? P < BLAH2 > \s \[ AAMS \sID : \s [ A - Z0 - 9 ] + \] ) ? # AAMS ID: in .it HH's
2010-11-13 05:04:13 +01:00
\s - \s
2010-11-04 11:31:14 +01:00
( ? P < DATETIME > . * $ )
""" % s ubstitutions, re.MULTILINE|re.VERBOSE)
2009-08-01 17:51:37 +02:00
2009-11-22 05:34:11 +01:00
re_PlayerInfo = re . compile ( u """
2009-08-01 17:51:37 +02:00
^ Seat \s ( ? P < SEAT > [ 0 - 9 ] + ) : \s
( ? P < PNAME > . * ) \s
2009-08-03 05:50:44 +02:00
\( ( % ( LS ) s ) ? ( ? P < CASH > [ .0 - 9 ] + ) \sin \schips \) """ % s ubstitutions,
2009-08-01 17:51:37 +02:00
re . MULTILINE | re . VERBOSE )
re_HandInfo = re . compile ( """
2010-02-03 14:52:44 +01:00
^ Table \s \' (?P<TABLE>[- \ \ #a-zA-Z \ d]+) \' \ s
2009-08-01 17:51:37 +02:00
( ( ? P < MAX > \d + ) - max \s ) ?
( ? P < PLAY > \( Play \sMoney \) \s ) ?
( Seat \s \#(?P<BUTTON>\d+)\sis\sthe\sbutton)?""",
re . MULTILINE | re . VERBOSE )
2009-03-31 08:44:19 +02:00
re_SplitHands = re . compile ( ' \n \n + ' )
re_TailSplitHands = re . compile ( ' ( \n \n \n +) ' )
2009-03-06 02:24:38 +01:00
re_Button = re . compile ( ' Seat #(?P<BUTTON> \ d+) is the button ' , re . MULTILINE )
re_Board = re . compile ( r " \ [(?P<CARDS>.+) \ ] " )
# self.re_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]+)')
2009-07-13 22:21:20 +02:00
2010-01-17 19:54:40 +01:00
re_DateTime = re . compile ( """ (?P<Y>[0-9] {4} ) \ /(?P<M>[0-9] {2} ) \ /(?P<D>[0-9] {2} )[ \ - ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+) """ , re . MULTILINE )
2010-03-16 23:32:31 +01:00
# revised re including timezone (not currently used):
#re_DateTime = re.compile("""(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+) \(?(?P<TZ>[A-Z0-9]+)""", re.MULTILINE)
2009-07-13 22:21:20 +02:00
2011-02-25 10:19:00 +01:00
# These used to be compiled per player, but regression tests say
# we don't have to, and it makes life faster.
short_subst = { ' PLYR ' : r ' (?P<PNAME>.+?) ' , ' CUR ' : ' \ $? ' }
re_PostSB = re . compile ( r " ^ %(PLYR)s : posts small blind %(CUR)s (?P<SB>[.0-9]+) " % short_subst , re . MULTILINE )
re_PostBB = re . compile ( r " ^ %(PLYR)s : posts big blind %(CUR)s (?P<BB>[.0-9]+) " % short_subst , re . MULTILINE )
re_Antes = re . compile ( r " ^ %(PLYR)s : posts the ante %(CUR)s (?P<ANTE>[.0-9]+) " % short_subst , re . MULTILINE )
re_BringIn = re . compile ( r " ^ %(PLYR)s : brings[- ]in( low|) for %(CUR)s (?P<BRINGIN>[.0-9]+) " % short_subst , re . MULTILINE )
re_PostBoth = re . compile ( r " ^ %(PLYR)s : posts small \ & big blinds %(CUR)s (?P<SBBB>[.0-9]+) " % short_subst , re . MULTILINE )
re_HeroCards = re . compile ( r " ^Dealt to %(PLYR)s (?: \ [(?P<OLDCARDS>.+?) \ ])?( \ [(?P<NEWCARDS>.+?) \ ]) " % short_subst , re . MULTILINE )
re_Action = re . compile ( r """
2010-02-15 00:27:34 +01:00
^ % ( PLYR ) s : ( ? P < ATYPE > \sbets | \schecks | \sraises | \scalls | \sfolds | \sdiscards | \sstands \spat )
2009-11-29 07:40:32 +01:00
( \s ( % ( CUR ) s ) ? ( ? P < BET > [ . \d ] + ) ) ? ( \sto \s % ( CUR ) s ( ? P < BETTO > [ . \d ] + ) ) ? # the number discarded goes in <BET>
2010-02-15 00:27:34 +01:00
\s * ( and \sis \sall . in ) ?
2010-11-04 12:59:16 +01:00
( and \shas \sreached \sthe \s [ % ( CUR ) s \d \. ] + \scap ) ?
2010-02-15 00:27:34 +01:00
( \scards ? ( \s \[ ( ? P < DISCARDED > . + ? ) \] ) ? ) ? \s * $ """
2011-02-25 10:19:00 +01:00
% short_subst , re . MULTILINE | re . VERBOSE )
re_ShowdownAction = re . compile ( r " ^ %s : shows \ [(?P<CARDS>.*) \ ] " % short_subst [ ' PLYR ' ] , re . MULTILINE )
re_sitsOut = re . compile ( " ^ %s sits out " % short_subst [ ' PLYR ' ] , re . MULTILINE )
re_ShownCards = re . compile ( " ^Seat (?P<SEAT>[0-9]+): %s ( \ (.* \ ) )?(?P<SHOWED>showed|mucked) \ [(?P<CARDS>.*) \ ].* " % short_subst [ ' PLYR ' ] , re . MULTILINE )
re_CollectPot = re . compile ( r " Seat (?P<SEAT>[0-9]+): %(PLYR)s ( \ (button \ ) | \ (small blind \ ) | \ (big blind \ ) | \ (button \ ) \ (small blind \ ) | \ (button \ ) \ (big blind \ ) )?(collected|showed \ [.* \ ] and won) \ ( %(CUR)s (?P<POT>[. \ d]+) \ )(, mucked| with.*|) " % short_subst , re . MULTILINE )
def compilePlayerRegexs ( self , hand ) :
pass
2009-03-06 02:24:38 +01:00
def readSupportedGames ( self ) :
2009-03-14 11:48:34 +01:00
return [ [ " ring " , " hold " , " nl " ] ,
[ " ring " , " hold " , " pl " ] ,
[ " ring " , " hold " , " fl " ] ,
2009-07-07 19:48:43 +02:00
2009-03-14 11:48:34 +01:00
[ " ring " , " stud " , " fl " ] ,
2009-07-11 19:44:32 +02:00
[ " ring " , " draw " , " fl " ] ,
2010-09-21 07:47:06 +02:00
[ " ring " , " draw " , " pl " ] ,
2010-09-01 18:40:36 +02:00
[ " ring " , " draw " , " nl " ] ,
2009-07-07 19:48:43 +02:00
[ " tour " , " hold " , " nl " ] ,
[ " tour " , " hold " , " pl " ] ,
[ " tour " , " hold " , " fl " ] ,
[ " tour " , " stud " , " fl " ] ,
2010-11-09 23:18:44 +01:00
[ " tour " , " draw " , " fl " ] ,
[ " tour " , " draw " , " pl " ] ,
[ " tour " , " draw " , " nl " ] ,
]
2009-03-06 02:24:38 +01:00
def determineGameType ( self , handText ) :
2009-07-07 19:48:43 +02:00
info = { }
2009-03-06 02:24:38 +01:00
m = self . re_GameInfo . search ( handText )
2009-03-15 06:32:52 +01:00
if not m :
2010-04-22 18:33:24 +02:00
tmp = handText [ 0 : 100 ]
2011-03-10 04:29:16 +01:00
log . error ( _ ( " Unable to recognise gametype from: ' %s ' " ) % tmp )
2010-08-14 16:27:23 +02:00
log . error ( _ ( " determineGameType: Raising FpdbParseError " ) )
raise FpdbParseError ( _ ( " Unable to recognise gametype from: ' %s ' " ) % tmp )
2009-03-10 00:03:17 +01:00
mg = m . groupdict ( )
if ' LIMIT ' in mg :
2010-07-07 06:58:42 +02:00
info [ ' limitType ' ] = self . limits [ mg [ ' LIMIT ' ] ]
2009-03-10 00:03:17 +01:00
if ' GAME ' in mg :
2010-07-07 06:58:42 +02:00
( info [ ' base ' ] , info [ ' category ' ] ) = self . games [ mg [ ' GAME ' ] ]
2009-03-10 00:03:17 +01:00
if ' SB ' in mg :
info [ ' sb ' ] = mg [ ' SB ' ]
if ' BB ' in mg :
info [ ' bb ' ] = mg [ ' BB ' ]
if ' CURRENCY ' in mg :
2010-07-07 06:58:42 +02:00
info [ ' currency ' ] = self . currencies [ mg [ ' CURRENCY ' ] ]
2009-07-11 19:44:32 +02:00
2009-11-03 20:30:52 +01:00
if ' TOURNO ' in mg and mg [ ' TOURNO ' ] is None :
2009-07-07 19:48:43 +02:00
info [ ' type ' ] = ' ring '
else :
info [ ' type ' ] = ' tour '
2009-07-11 19:44:32 +02:00
2010-03-04 17:50:03 +01:00
if info [ ' limitType ' ] == ' fl ' and info [ ' bb ' ] is not None and info [ ' type ' ] == ' ring ' and info [ ' base ' ] != ' stud ' :
2010-04-22 18:33:24 +02:00
try :
2010-07-07 06:58:42 +02:00
info [ ' sb ' ] = self . Lim_Blinds [ mg [ ' BB ' ] ] [ 0 ]
info [ ' bb ' ] = self . Lim_Blinds [ mg [ ' BB ' ] ] [ 1 ]
2010-04-22 18:33:24 +02:00
except KeyError :
2011-03-10 04:36:20 +01:00
log . error ( _ ( " Lim_Blinds has no lookup for ' %s ' " ) % mg [ ' BB ' ] )
2010-08-14 16:27:23 +02:00
log . error ( _ ( " determineGameType: Raising FpdbParseError " ) )
raise FpdbParseError ( _ ( " Lim_Blinds has no lookup for ' %s ' " ) % mg [ ' BB ' ] )
2010-02-18 22:12:01 +01:00
2009-03-10 00:03:17 +01:00
return info
2009-03-06 02:24:38 +01:00
def readHandInfo ( self , hand ) :
info = { }
2010-08-27 08:44:19 +02:00
m = self . re_HandInfo . search ( hand . handText , re . DOTALL )
m2 = self . re_GameInfo . search ( hand . handText )
if m is None or m2 is None :
2011-03-12 21:47:14 +01:00
log . error ( _ ( " No match in readHandInfo: ' %s ' " ) % hand . handText [ 0 : 100 ] )
raise FpdbParseError ( _ ( " No match in readHandInfo: ' %s ' " ) % hand . handText [ 0 : 100 ] )
2010-08-27 08:44:19 +02:00
info . update ( m . groupdict ( ) )
info . update ( m2 . groupdict ( ) )
2010-07-31 10:57:25 +02:00
2009-11-10 01:24:46 +01:00
log . debug ( " readHandInfo: %s " % info )
2009-03-06 02:24:38 +01:00
for key in info :
if key == ' DATETIME ' :
2010-07-31 10:57:25 +02:00
#2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET] # (both dates are parsed so ET date overrides the other)
2009-03-25 10:35:19 +01:00
#2008/08/17 - 01:14:43 (ET)
#2008/09/07 06:23:14 ET
2010-01-17 19:54:40 +01:00
m1 = self . re_DateTime . finditer ( info [ key ] )
2010-07-31 10:57:25 +02:00
datetimestr = " 2000/01/01 00:00:00 " # default used if time not found
2010-01-17 19:54:40 +01:00
for a in m1 :
datetimestr = " %s / %s / %s %s : %s : %s " % ( a . group ( ' Y ' ) , a . group ( ' M ' ) , a . group ( ' D ' ) , a . group ( ' H ' ) , a . group ( ' MIN ' ) , a . group ( ' S ' ) )
2010-03-16 23:32:31 +01:00
#tz = a.group('TZ') # just assume ET??
#print " tz = ", tz, " datetime =", datetimestr
2010-07-08 17:14:55 +02:00
hand . startTime = datetime . datetime . strptime ( datetimestr , " % Y/ % m/ %d % H: % M: % S " ) # also timezone at end, e.g. " ET"
2010-07-13 20:37:06 +02:00
hand . startTime = HandHistoryConverter . changeTimezone ( hand . startTime , " ET " , " UTC " )
2009-03-06 02:24:38 +01:00
if key == ' HID ' :
hand . handid = info [ key ]
2009-11-05 17:27:33 +01:00
if key == ' TOURNO ' :
hand . tourNo = info [ key ]
if key == ' BUYIN ' :
2010-07-05 11:48:26 +02:00
if hand . tourNo != None :
2010-07-31 10:57:25 +02:00
#print "DEBUG: info['BUYIN']: %s" % info['BUYIN']
#print "DEBUG: info['BIAMT']: %s" % info['BIAMT']
#print "DEBUG: info['BIRAKE']: %s" % info['BIRAKE']
#print "DEBUG: info['BOUNTY']: %s" % info['BOUNTY']
2010-07-05 11:48:26 +02:00
if info [ key ] == ' Freeroll ' :
hand . buyin = 0
hand . fee = 0
hand . buyinCurrency = " FREE "
else :
if info [ key ] . find ( " $ " ) != - 1 :
hand . buyinCurrency = " USD "
elif info [ key ] . find ( u " € " ) != - 1 :
hand . buyinCurrency = " EUR "
2010-07-10 23:08:05 +02:00
elif info [ key ] . find ( " FPP " ) != - 1 :
hand . buyinCurrency = " PSFP "
2010-07-05 11:48:26 +02:00
else :
2011-03-10 02:44:40 +01:00
#FIXME: handle other currencies, play money
2011-03-12 21:47:14 +01:00
raise FpdbParseError ( _ ( " Failed to detect currency. Hand ID: %s : ' %s ' " ) % ( hand . handid , info [ key ] ) )
2010-08-03 13:52:49 +02:00
info [ ' BIAMT ' ] = info [ ' BIAMT ' ] . strip ( u ' $€FPP ' )
2010-07-10 23:08:05 +02:00
2010-08-02 13:35:20 +02:00
if hand . buyinCurrency != " PSFP " :
2010-08-03 13:22:52 +02:00
if info [ ' BOUNTY ' ] != None :
# There is a bounty, Which means we need to switch BOUNTY and BIRAKE values
tmp = info [ ' BOUNTY ' ]
info [ ' BOUNTY ' ] = info [ ' BIRAKE ' ]
info [ ' BIRAKE ' ] = tmp
info [ ' BOUNTY ' ] = info [ ' BOUNTY ' ] . strip ( u ' $€ ' ) # Strip here where it isn't 'None'
hand . koBounty = int ( 100 * Decimal ( info [ ' BOUNTY ' ] ) )
2010-08-03 13:52:49 +02:00
hand . isKO = True
2010-08-03 22:25:49 +02:00
else :
hand . isKO = False
2010-08-03 13:22:52 +02:00
info [ ' BIRAKE ' ] = info [ ' BIRAKE ' ] . strip ( u ' $€ ' )
hand . buyin = int ( 100 * Decimal ( info [ ' BIAMT ' ] ) )
hand . fee = int ( 100 * Decimal ( info [ ' BIRAKE ' ] ) )
2010-08-02 13:35:20 +02:00
else :
2010-08-03 13:52:49 +02:00
hand . buyin = int ( Decimal ( info [ ' BIAMT ' ] ) )
2010-07-10 23:08:05 +02:00
hand . fee = 0
2009-11-05 17:27:33 +01:00
if key == ' LEVEL ' :
hand . level = info [ key ]
2009-03-06 02:24:38 +01:00
if key == ' TABLE ' :
2009-11-05 17:27:33 +01:00
if hand . tourNo != None :
hand . tablename = re . split ( " " , info [ key ] ) [ 1 ]
else :
hand . tablename = info [ key ]
2009-03-06 02:24:38 +01:00
if key == ' BUTTON ' :
hand . buttonpos = info [ key ]
2010-12-06 05:48:25 +01:00
if key == ' MAX ' and info [ key ] != None :
2010-11-27 00:15:28 +01:00
hand . maxseats = int ( info [ key ] )
2009-07-11 19:44:32 +02:00
if key == ' MIXED ' :
2009-11-03 20:30:52 +01:00
hand . mixed = self . mixes [ info [ key ] ] if info [ key ] is not None else None
if key == ' PLAY ' and info [ ' PLAY ' ] is not None :
2009-07-13 22:21:20 +02:00
# hand.currency = 'play' # overrides previously set value
hand . gametype [ ' currency ' ] = ' play '
2010-07-08 21:28:21 +02:00
2009-03-06 02:24:38 +01:00
def readButton ( self , hand ) :
m = self . re_Button . search ( hand . handText )
if m :
hand . buttonpos = int ( m . group ( ' BUTTON ' ) )
else :
2010-08-14 16:27:23 +02:00
log . info ( _ ( ' readButton: not found ' ) )
2009-03-06 02:24:38 +01:00
def readPlayerStacks ( self , hand ) :
2009-11-10 01:24:46 +01:00
log . debug ( " readPlayerStacks " )
2009-03-06 02:24:38 +01:00
m = self . re_PlayerInfo . finditer ( hand . handText )
for a in m :
hand . addPlayer ( int ( a . group ( ' SEAT ' ) ) , a . group ( ' PNAME ' ) , a . group ( ' CASH ' ) )
def markStreets ( self , hand ) :
# PREFLOP = ** Dealing down cards **
# This re fails if, say, river is missing; then we don't get the ** that starts the river.
2009-03-11 15:42:49 +01:00
if hand . gametype [ ' base ' ] in ( " hold " ) :
2009-03-06 02:24:38 +01:00
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 )
2009-03-11 15:42:49 +01:00
elif hand . gametype [ ' base ' ] in ( " stud " ) :
2009-03-06 02:24:38 +01:00
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 \ * \ * \ *)|.+))? "
2009-03-11 19:40:17 +01:00
r " ( \ * \ * \ * 6th STREET \ * \ * \ *(?P<SIXTH>.+(?= \ * \ * \ * RIVER \ * \ * \ *)|.+))? "
r " ( \ * \ * \ * RIVER \ * \ * \ *(?P<SEVENTH>.+))? " , hand . handText , re . DOTALL )
2009-03-14 11:48:34 +01:00
elif hand . gametype [ ' base ' ] in ( " draw " ) :
2011-02-16 08:10:48 +01:00
if hand . gametype [ ' category ' ] in ( ' 27_1draw ' , ' fivedraw ' ) :
# There is no marker between deal and draw in Stars single draw games
# This unfortunately affects the accounting.
m = re . search ( r " (?P<PREDEAL>.+(?= \ * \ * \ * DEALING HANDS \ * \ * \ *)|.+) "
r " ( \ * \ * \ * DEALING HANDS \ * \ * \ *(?P<DEAL>.+(?=(: stands pat on|: discards))|.+))? "
r " ((: stands pat on|: discards)(?P<DRAWONE>.+))? " , hand . handText , re . DOTALL )
else :
m = re . search ( r " (?P<PREDEAL>.+(?= \ * \ * \ * DEALING HANDS \ * \ * \ *)|.+) "
2009-03-14 11:48:34 +01:00
r " ( \ * \ * \ * DEALING HANDS \ * \ * \ *(?P<DEAL>.+(?= \ * \ * \ * FIRST DRAW \ * \ * \ *)|.+))? "
r " ( \ * \ * \ * FIRST DRAW \ * \ * \ *(?P<DRAWONE>.+(?= \ * \ * \ * SECOND DRAW \ * \ * \ *)|.+))? "
r " ( \ * \ * \ * SECOND DRAW \ * \ * \ *(?P<DRAWTWO>.+(?= \ * \ * \ * THIRD DRAW \ * \ * \ *)|.+))? "
r " ( \ * \ * \ * THIRD DRAW \ * \ * \ *(?P<DRAWTHREE>.+))? " , hand . handText , re . DOTALL )
2009-03-06 02:24:38 +01:00
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)
#print "DEBUG readCommunityCards:", street, hand.streets.group(street)
m = self . re_Board . search ( hand . streets [ street ] )
hand . setCommunityCards ( street , m . group ( ' CARDS ' ) . split ( ' ' ) )
def readAntes ( self , hand ) :
2010-08-14 16:27:23 +02:00
log . debug ( _ ( " reading antes " ) )
2009-03-06 02:24:38 +01:00
m = self . re_Antes . finditer ( hand . handText )
for player in m :
2009-03-11 19:40:17 +01:00
#~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
2009-03-06 02:24:38 +01:00
hand . addAnte ( player . group ( ' PNAME ' ) , player . group ( ' ANTE ' ) )
def readBringIn ( self , hand ) :
m = self . re_BringIn . search ( hand . handText , re . DOTALL )
if m :
2009-03-11 19:40:17 +01:00
#~ logging.debug("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
2009-03-06 02:24:38 +01:00
hand . addBringIn ( m . group ( ' PNAME ' ) , m . group ( ' BRINGIN ' ) )
def readBlinds ( self , hand ) :
2010-02-18 22:12:01 +01:00
liveBlind = True
for a in self . re_PostSB . finditer ( hand . handText ) :
if liveBlind :
hand . addBlind ( a . group ( ' PNAME ' ) , ' small blind ' , a . group ( ' SB ' ) )
liveBlind = False
else :
# Post dead blinds as ante
hand . addBlind ( a . group ( ' PNAME ' ) , ' secondsb ' , a . group ( ' SB ' ) )
2009-03-06 02:24:38 +01:00
for a in self . re_PostBB . finditer ( hand . handText ) :
hand . addBlind ( a . group ( ' PNAME ' ) , ' big blind ' , a . group ( ' BB ' ) )
for a in self . re_PostBoth . finditer ( hand . handText ) :
2009-06-19 08:21:35 +02:00
hand . addBlind ( a . group ( ' PNAME ' ) , ' both ' , a . group ( ' SBBB ' ) )
2009-03-06 02:24:38 +01:00
def readHeroCards ( self , hand ) :
2009-07-13 06:37:51 +02:00
# streets PREFLOP, PREDRAW, and THIRD are special cases beacause
# we need to grab hero's cards
for street in ( ' PREFLOP ' , ' DEAL ' ) :
2009-07-12 22:01:02 +02:00
if street in hand . streets . keys ( ) :
2009-07-13 06:37:51 +02:00
m = self . re_HeroCards . finditer ( hand . streets [ street ] )
for found in m :
# if m == None:
# hand.involved = False
# else:
hand . hero = found . group ( ' PNAME ' )
newcards = found . group ( ' NEWCARDS ' ) . split ( ' ' )
2009-07-12 22:01:02 +02:00
hand . addHoleCards ( street , hand . hero , closed = newcards , shown = False , mucked = False , dealt = True )
2009-07-13 06:37:51 +02:00
for street , text in hand . streets . iteritems ( ) :
2009-07-15 01:26:53 +02:00
if not text or street in ( ' PREFLOP ' , ' DEAL ' ) : continue # already done these
2009-07-13 06:37:51 +02:00
m = self . re_HeroCards . finditer ( hand . streets [ street ] )
for found in m :
player = found . group ( ' PNAME ' )
2009-11-03 20:30:52 +01:00
if found . group ( ' NEWCARDS ' ) is None :
2009-07-13 06:37:51 +02:00
newcards = [ ]
2009-03-14 11:48:34 +01:00
else :
2009-07-13 06:37:51 +02:00
newcards = found . group ( ' NEWCARDS ' ) . split ( ' ' )
2009-11-03 20:30:52 +01:00
if found . group ( ' OLDCARDS ' ) is None :
2009-07-13 06:37:51 +02:00
oldcards = [ ]
2009-03-14 11:48:34 +01:00
else :
2009-07-13 06:37:51 +02:00
oldcards = found . group ( ' OLDCARDS ' ) . split ( ' ' )
2009-03-14 11:48:34 +01:00
2009-07-13 06:37:51 +02:00
if street == ' THIRD ' and len ( newcards ) == 3 : # hero in stud game
hand . hero = player
hand . dealt . add ( player ) # need this for stud??
hand . addHoleCards ( street , player , closed = newcards [ 0 : 2 ] , open = [ newcards [ 2 ] ] , shown = False , mucked = False , dealt = False )
else :
hand . addHoleCards ( street , player , open = newcards , closed = oldcards , shown = False , mucked = False , dealt = False )
2009-03-14 11:48:34 +01:00
2009-03-06 02:24:38 +01:00
def readAction ( self , hand , street ) :
m = self . re_Action . finditer ( hand . streets [ street ] )
for action in m :
2009-07-11 19:44:32 +02:00
acts = action . groupdict ( )
2010-02-14 16:54:19 +01:00
#print "DEBUG: acts: %s" %acts
2009-03-06 02:24:38 +01:00
if action . group ( ' ATYPE ' ) == ' raises ' :
hand . addRaiseBy ( street , action . group ( ' PNAME ' ) , action . group ( ' BET ' ) )
elif action . group ( ' ATYPE ' ) == ' calls ' :
hand . addCall ( street , action . group ( ' PNAME ' ) , action . group ( ' BET ' ) )
elif action . group ( ' ATYPE ' ) == ' bets ' :
hand . addBet ( street , action . group ( ' PNAME ' ) , action . group ( ' BET ' ) )
elif action . group ( ' ATYPE ' ) == ' folds ' :
hand . addFold ( street , action . group ( ' PNAME ' ) )
elif action . group ( ' ATYPE ' ) == ' checks ' :
hand . addCheck ( street , action . group ( ' PNAME ' ) )
2009-03-14 11:48:34 +01:00
elif action . group ( ' ATYPE ' ) == ' discards ' :
2009-07-11 19:44:32 +02:00
hand . addDiscard ( street , action . group ( ' PNAME ' ) , action . group ( ' BET ' ) , action . group ( ' DISCARDED ' ) )
2009-03-14 11:48:34 +01:00
elif action . group ( ' ATYPE ' ) == ' stands pat ' :
hand . addStandsPat ( street , action . group ( ' PNAME ' ) )
2009-03-06 02:24:38 +01:00
else :
2011-03-11 07:08:50 +01:00
print ( _ ( " DEBUG: " ) + _ ( " Unimplemented readAction: ' %s ' ' %s ' " ) % ( action . group ( ' PNAME ' ) , action . group ( ' ATYPE ' ) ) )
2009-03-06 02:24:38 +01:00
def readShowdownActions ( self , hand ) :
2009-07-15 17:48:58 +02:00
# TODO: pick up mucks also??
2009-03-06 02:24:38 +01:00
for shows in self . re_ShowdownAction . finditer ( hand . handText ) :
2009-07-12 22:01:02 +02:00
cards = shows . group ( ' CARDS ' ) . split ( ' ' )
2009-03-06 02:24:38 +01:00
hand . addShownCards ( cards , shows . group ( ' PNAME ' ) )
def readCollectPot ( self , hand ) :
for m in self . re_CollectPot . finditer ( hand . handText ) :
hand . addCollectPot ( player = m . group ( ' PNAME ' ) , pot = m . group ( ' POT ' ) )
def readShownCards ( self , hand ) :
for m in self . re_ShownCards . finditer ( hand . handText ) :
if m . group ( ' CARDS ' ) is not None :
cards = m . group ( ' CARDS ' )
2009-07-04 20:35:20 +02:00
cards = cards . split ( ' ' ) # needs to be a list, not a set--stud needs the order
2009-07-04 00:59:50 +02:00
( shown , mucked ) = ( False , False )
if m . group ( ' SHOWED ' ) == " showed " : shown = True
elif m . group ( ' SHOWED ' ) == " mucked " : mucked = True
2010-09-09 07:19:19 +02:00
#print "DEBUG: hand.addShownCards(%s, %s, %s, %s)" %(cards, m.group('PNAME'), shown, mucked)
2009-07-04 00:59:50 +02:00
hand . addShownCards ( cards = cards , player = m . group ( ' PNAME ' ) , shown = shown , mucked = mucked )
2009-03-06 02:24:38 +01:00
if __name__ == " __main__ " :
parser = OptionParser ( )
2010-08-14 16:27:23 +02:00
parser . add_option ( " -i " , " --input " , dest = " ipath " , help = _ ( " parse input hand history " ) , default = " regression-test-files/stars/horse/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt " )
parser . add_option ( " -o " , " --output " , dest = " opath " , help = _ ( " output translation to " ) , default = " - " )
parser . add_option ( " -f " , " --follow " , dest = " follow " , help = _ ( " follow (tail -f) the input " ) , action = " store_true " , default = False )
2009-11-22 05:34:11 +01:00
#parser.add_option("-q", "--quiet", action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
#parser.add_option("-v", "--verbose", action="store_const", const=logging.INFO, dest="verbosity")
#parser.add_option("--vv", action="store_const", const=logging.DEBUG, dest="verbosity")
2009-03-06 02:24:38 +01:00
( options , args ) = parser . parse_args ( )
e = PokerStars ( in_path = options . ipath , out_path = options . opath , follow = options . follow )