Merge branch 'master' of git://git.assembla.com/fpdboz
This commit is contained in:
		
						commit
						d292cd18d4
					
				
							
								
								
									
										335
									
								
								pyfpdb/AbsoluteToFpdb.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								pyfpdb/AbsoluteToFpdb.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,335 @@ | ||||||
|  | #!/usr/bin/env python | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # | ||||||
|  | #    Copyright 2008, Carl Gherardi | ||||||
|  | #     | ||||||
|  | #    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 | ||||||
|  | ######################################################################## | ||||||
|  | 
 | ||||||
|  | # TODO: I have no idea if AP has multi-currency options, i just copied the regex out of Everleaf converter for the currency symbols.. weeeeee - Eric | ||||||
|  | import sys | ||||||
|  | import logging | ||||||
|  | from HandHistoryConverter import * | ||||||
|  | 
 | ||||||
|  | # Class for converting Absolute HH format. | ||||||
|  | 
 | ||||||
|  | class Absolute(HandHistoryConverter): | ||||||
|  |      | ||||||
|  |     # Static regexes | ||||||
|  |     re_SplitHands  = re.compile(r"\n\n\n+") | ||||||
|  |     re_TailSplitHands  = re.compile(r"(\n\n\n+)") | ||||||
|  | #Stage #1571362962: Holdem  No Limit $0.02 - 2009-08-05 15:24:06 (ET) | ||||||
|  | #Table: TORONTO AVE (Real Money) Seat #6 is the dealer | ||||||
|  | #Seat 6 - FETS63 ($0.75 in chips) | ||||||
|  | #Board [10s 5d Kh Qh 8c] | ||||||
|  | 
 | ||||||
|  |     re_GameInfo     = re.compile(ur"^Stage #([0-9]+): (?P<GAME>Holdem|)  (?P<LIMIT>No Limit|) (?P<CURRENCY>\$| €|)(?P<BB>[0-9]*[.0-9]+)", re.MULTILINE) | ||||||
|  |     re_HandInfo     = re.compile(ur"^Stage #(?P<HID>[0-9]+): .*(?P<DATETIME>\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d).*\nTable: (?P<TABLE>.*) \(Real Money\)", re.MULTILINE) | ||||||
|  |     re_Button       = re.compile(ur"Seat #(?P<BUTTON>[0-9]) is the ?[dead]* dealer$", re.MULTILINE) # TODO: that's not the right way to match for "dead" dealer is it? | ||||||
|  |     re_PlayerInfo   = re.compile(ur"^Seat (?P<SEAT>[0-9]) - (?P<PNAME>.*) \((?:\$| €|)(?P<CASH>[0-9]*[.0-9]+) in chips\)", re.MULTILINE) | ||||||
|  |     re_Board        = re.compile(ur"\[(?P<CARDS>[^\]]*)\]? *$", re.MULTILINE) | ||||||
|  | #    re_GameInfo    = re.compile(ur"^(Blinds )?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/(?:\$| €)?(?P<BB>[.0-9]+) (?P<LIMIT>NL|PL|) ?(?P<GAME>(Holdem|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.MULTILINE) | ||||||
|  | #    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, debugging=False, index=0): | ||||||
|  |         """\ | ||||||
|  | in_path   (default '-' = sys.stdin) | ||||||
|  | out_path  (default '-' = sys.stdout) | ||||||
|  | follow :  whether to tail -f the input | ||||||
|  | autostart: whether to run the thread (or you can call start() yourself) | ||||||
|  | debugging: if False, pass on partially supported game types. If true, have a go and error...""" | ||||||
|  |         #print "DEBUG: XXXXXXXXXXXXXXX" | ||||||
|  |         HandHistoryConverter.__init__(self, in_path, out_path, sitename="Absolute", follow=follow, index=index) | ||||||
|  |         logging.info("Initialising Absolute converter class") | ||||||
|  |         self.filetype = "text" | ||||||
|  |         self.codepage = "cp1252" | ||||||
|  |         self.siteId   = 3 # Needs to match id entry in Sites database | ||||||
|  |         self.debugging = debugging | ||||||
|  |         if autostart: | ||||||
|  |             self.start() | ||||||
|  |             # otherwise you need to call start yourself. | ||||||
|  | 
 | ||||||
|  |     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 | ||||||
|  |             player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")" | ||||||
|  |             logging.debug("player_re: "+ player_re) | ||||||
|  |             #(?P<CURRENCY>\$| €|)(?P<BB>[0-9]*[.0-9]+) | ||||||
|  |             self.re_PostSB          = re.compile(ur"^%s - Posts small blind (?:\$| €|)(?P<SB>[0-9]*[.0-9]+)" % player_re, re.MULTILINE) | ||||||
|  |             self.re_PostBB          = re.compile(ur"^%s - Posts big blind (?:\$| €|)(?P<BB>[0-9]*[.0-9]+)" % player_re, re.MULTILINE) | ||||||
|  |             # TODO: Absolute posting when coming in new: %s - Posts $0.02 .. should that be a new Post line? where do we need to add support for that? *confused* | ||||||
|  |             self.re_PostBoth        = re.compile(ur"^%s - Posts dead (?:\$| €|)(?P<SBBB>[0-9]*[.0-9]+)" % player_re, re.MULTILINE) | ||||||
|  |             self.re_Action          = re.compile(ur"^%s - (?P<ATYPE>Bets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P<BET>[0-9]*[.0-9]+)?" % player_re, re.MULTILINE) | ||||||
|  |             print "^%s - (?P<ATYPE>Bets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P<BET>[0-9]*[.0-9]+)?" % player_re | ||||||
|  |             self.re_ShowdownAction  = re.compile(ur"^%s - Shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE) | ||||||
|  |             self.re_CollectPot      = re.compile(ur"^Seat [0-9]: %s(?: \(dealer\)| \(big blind\)| \(small blind\)|) (?:won|collected) Total \((?:\$| €|)(?P<POT>[0-9]*[.0-9]+)\)" % player_re, re.MULTILINE) | ||||||
|  |             #self.re_PostSB          = re.compile(ur"^%s: posts small blind \[(?:\$| €|) (?P<SB>[.0-9]+)" % player_re, re.MULTILINE) | ||||||
|  |             #self.re_PostBB          = re.compile(ur"^%s: posts big blind \[(?:\$| €|) (?P<BB>[.0-9]+)" % player_re, re.MULTILINE) | ||||||
|  |             #self.re_PostBoth        = re.compile(ur"^%s: posts both blinds \[(?:\$| €|) (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE) | ||||||
|  |             #self.re_Antes           = re.compile(ur"^%s: posts ante \[(?:\$| €|) (?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE) | ||||||
|  |             #self.re_BringIn         = re.compile(ur"^%s posts bring-in (?:\$| €|)(?P<BRINGIN>[.0-9]+)\." % player_re, re.MULTILINE) | ||||||
|  |             self.re_HeroCards       = re.compile(ur"^Dealt to %s \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE) | ||||||
|  |             #self.re_Action          = re.compile(ur"^%s(?P<ATYPE>: bets| checks| raises| calls| folds)(\s\[(?:\$| €|) (?P<BET>[.\d]+) (USD|EUR|)\])?" % player_re, re.MULTILINE) | ||||||
|  |             #self.re_Action          = re.compile(ur"^%s(?P<ATYPE>: bets| checks| raises| calls| folds| complete to)(\s\[?(?:\$| €|) ?(?P<BET>\d+\.?\d*)\.?\s?(USD|EUR|)\]?)?" % player_re, re.MULTILINE) | ||||||
|  |             #self.re_ShowdownAction  = re.compile(ur"^%s shows \[ (?P<CARDS>.*) \]" % player_re, re.MULTILINE) | ||||||
|  |             #self.re_CollectPot      = re.compile(ur"^%s wins (?:\$| €|) (?P<POT>[.\d]+) (USD|EUR|chips)(.*?\[ (?P<CARDS>.*?) \])?" % player_re, re.MULTILINE) | ||||||
|  |             #self.re_SitsOut         = re.compile(ur"^%s sits out" % player_re, re.MULTILINE) | ||||||
|  | 
 | ||||||
|  |     def readSupportedGames(self): | ||||||
|  |         return [["ring", "hold", "nl"], | ||||||
|  |                 ["ring", "hold", "pl"], | ||||||
|  |                 ["ring", "hold", "fl"], | ||||||
|  |                 ["ring", "studhi", "fl"], | ||||||
|  |                 ["ring", "omahahi", "pl"] | ||||||
|  |                ] | ||||||
|  | 
 | ||||||
|  |     def determineGameType(self, handText): | ||||||
|  |         """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 """ | ||||||
|  |         info = {'type':'ring'} | ||||||
|  |          | ||||||
|  |         m = self.re_GameInfo.search(handText) | ||||||
|  |         if not m: | ||||||
|  |             return None | ||||||
|  |          | ||||||
|  |         mg = m.groupdict() | ||||||
|  |          | ||||||
|  |         # translations from captured groups to our info strings | ||||||
|  |         limits = { 'No Limit':'nl', 'PL':'pl', '':'fl' } | ||||||
|  |         games = {              # base, category | ||||||
|  |                   "Holdem" : ('hold','holdem'),  | ||||||
|  |                     'Omaha' : ('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'] | ||||||
|  |         else: | ||||||
|  |             info['sb'] = str(float(mg['BB']) * 0.5) # TODO: Apparently AP doesn't provide small blind info!? must search to see if it's posted, I guess | ||||||
|  |         if 'BB' in mg: | ||||||
|  |             info['bb'] = mg['BB'] | ||||||
|  |         if 'CURRENCY' in mg: | ||||||
|  |             info['currency'] = currencies[mg['CURRENCY']] | ||||||
|  |             if info['currency'] == 'T$': | ||||||
|  |                 info['type'] = 'tour' | ||||||
|  |         # NB: SB, BB must be interpreted as blinds or bets depending on limit type. | ||||||
|  |          | ||||||
|  |         return info | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def readHandInfo(self, hand): | ||||||
|  |         m = self.re_HandInfo.search(hand.handText) | ||||||
|  |         if(m == None): | ||||||
|  |             logging.info("Didn't match re_HandInfo") | ||||||
|  |             logging.info(hand.handText) | ||||||
|  |             return None | ||||||
|  |         logging.debug("HID %s, Table %s" % (m.group('HID'),  m.group('TABLE'))) | ||||||
|  |         hand.handid =  m.group('HID') | ||||||
|  |         hand.tablename = m.group('TABLE') | ||||||
|  |         hand.maxseats = 6     # assume 6-max unless we have proof it's a larger/smaller game, since absolute doesn't give seat max info | ||||||
|  | 
 | ||||||
|  |         hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%Y-%m-%d %H:%M:%S") | ||||||
|  |         return | ||||||
|  | 
 | ||||||
|  |     def readPlayerStacks(self, hand): | ||||||
|  |         m = self.re_PlayerInfo.finditer(hand.handText) | ||||||
|  |         for a in m: | ||||||
|  |             seatnum = int(a.group('SEAT')) | ||||||
|  |             hand.addPlayer(seatnum, a.group('PNAME'), a.group('CASH')) | ||||||
|  |             if seatnum > 6: | ||||||
|  |                 hand.maxseats = 10 # absolute does 2/4/6/8/10 games  | ||||||
|  |                 # TODO: implement lookup list by table-name to determine maxes, then fall back to 6 default/10 here, if there's no entry in the list? | ||||||
|  |              | ||||||
|  |          | ||||||
|  |     def markStreets(self, hand): | ||||||
|  |         # PREFLOP = ** Dealing down cards ** | ||||||
|  |         # 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.handText,re.DOTALL) | ||||||
|  |         if hand.gametype['base'] == 'hold': | ||||||
|  |             m = re.search(r"\*\*\* POCKET CARDS \*\*\*(?P<PREFLOP>.+(?=\*\*\* FLOP \*\*\*)|.+)" | ||||||
|  |                     r"(\*\*\* FLOP \*\*\*(?P<FLOP>.+(?=\*\*\* TURN \*\*\*)|.+))?" | ||||||
|  |                     r"(\*\*\* TURN \*\*\*(?P<TURN>.+(?=\*\*\* RIVER \*\*\*)|.+))?" | ||||||
|  |                     r"(\*\*\* RIVER \*\*\*(?P<RIVER>.+))?", hand.handText, re.DOTALL) | ||||||
|  |              | ||||||
|  |         elif hand.gametype['base'] == 'stud': # TODO: Not implemented yet | ||||||
|  |             m =     re.search(r"(?P<ANTES>.+(?=\*\* Dealing down cards \*\*)|.+)" | ||||||
|  |                            r"(\*\* Dealing down cards \*\*(?P<THIRD>.+(?=\*\*\*\* dealing 4th street \*\*\*\*)|.+))?" | ||||||
|  |                            r"(\*\*\*\* dealing 4th street \*\*\*\*(?P<FOURTH>.+(?=\*\*\*\* dealing 5th street \*\*\*\*)|.+))?" | ||||||
|  |                            r"(\*\*\*\* dealing 5th street \*\*\*\*(?P<FIFTH>.+(?=\*\*\*\* dealing 6th street \*\*\*\*)|.+))?" | ||||||
|  |                            r"(\*\*\*\* dealing 6th street \*\*\*\*(?P<SIXTH>.+(?=\*\*\*\* dealing river \*\*\*\*)|.+))?" | ||||||
|  |                            r"(\*\*\*\* dealing river \*\*\*\*(?P<SEVENTH>.+))?", hand.handText,re.DOTALL) | ||||||
|  |         hand.addStreets(m) | ||||||
|  | 
 | ||||||
|  |     def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand | ||||||
|  |         # If this has been called, street is a street which gets dealt community cards by type hand | ||||||
|  |         # but it might be worth checking somehow. | ||||||
|  | #        if street in ('FLOP','TURN','RIVER'):   # a list of streets which get dealt community cards (i.e. all but PREFLOP) | ||||||
|  |         logging.debug("readCommunityCards (%s)" % street) | ||||||
|  |         m = self.re_Board.search(hand.streets[street]) | ||||||
|  |         cards = m.group('CARDS') | ||||||
|  |         cards = [validCard(card) for card in cards.split(' ')] | ||||||
|  |         hand.setCommunityCards(street=street, cards=cards) | ||||||
|  | 
 | ||||||
|  |     def readAntes(self, hand): | ||||||
|  |         logging.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("Player bringing in: %s for %s" %(m.group('PNAME'),  m.group('BRINGIN')))         | ||||||
|  |             hand.addBringIn(m.group('PNAME'),  m.group('BRINGIN')) | ||||||
|  |         else: | ||||||
|  |             logging.warning("No bringin found.") | ||||||
|  | 
 | ||||||
|  |     def readBlinds(self, hand): | ||||||
|  |         m = self.re_PostSB.search(hand.handText) | ||||||
|  |         if m is not None: | ||||||
|  |             hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) | ||||||
|  |         else: | ||||||
|  |             logging.debug("No small blind") | ||||||
|  |             hand.addBlind(None, None, None) | ||||||
|  |         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): | ||||||
|  |             hand.addBlind(a.group('PNAME'), 'both', a.group('SBBB')) | ||||||
|  | 
 | ||||||
|  |     def readButton(self, hand): | ||||||
|  |         hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON')) | ||||||
|  | 
 | ||||||
|  |     def readHeroCards(self, hand): | ||||||
|  |         m = self.re_HeroCards.search(hand.handText) | ||||||
|  |         if m: | ||||||
|  |             hand.hero = m.group('PNAME') | ||||||
|  |             # "2c, qh" -> ["2c","qc"] | ||||||
|  |             # Also works with Omaha hands. | ||||||
|  |             cards = m.group('CARDS') | ||||||
|  |             cards = [validCard(card) for card in cards.split(' ')] | ||||||
|  | #            hand.addHoleCards(cards, m.group('PNAME')) | ||||||
|  |             hand.addHoleCards('PREFLOP', hand.hero, closed=cards, shown=False, mucked=False, dealt=True) | ||||||
|  | 
 | ||||||
|  |         else: | ||||||
|  |             #Not involved in hand | ||||||
|  |             hand.involved = False | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def readStudPlayerCards(self, hand, street): | ||||||
|  |         # lol. see Plymouth.txt | ||||||
|  |         logging.warning("Absolute readStudPlayerCards is only a stub.") | ||||||
|  |         #~ if street in ('THIRD', 'FOURTH',  'FIFTH',  'SIXTH'): | ||||||
|  |             #~ hand.addPlayerCards(player = player.group('PNAME'), street = street,  closed = [],  open = []) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def readAction(self, hand, street): | ||||||
|  |         logging.debug("readAction (%s)" % street) | ||||||
|  |         m = self.re_Action.finditer(hand.streets[street]) | ||||||
|  |         for action in m: | ||||||
|  |             logging.debug("%s %s" % (action.group('ATYPE'), action.groupdict())) | ||||||
|  |             if action.group('ATYPE') == 'Raises ' or action.group('ATYPE') == 'All-In(Raise) ': | ||||||
|  |                 hand.addCallandRaise( 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 ' or action.group('ATYPE') == 'All-In ': | ||||||
|  |                 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')) | ||||||
|  |             elif action.group('ATYPE') == ' complete to': # TODO: not supported yet ? | ||||||
|  |                 hand.addComplete( street, action.group('PNAME'), action.group('BET')) | ||||||
|  |             else: | ||||||
|  |                 logging.debug("Unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def readShowdownActions(self, hand): | ||||||
|  |         """Reads lines where holecards are reported in a showdown""" | ||||||
|  |         logging.debug("readShowdownActions") | ||||||
|  |         for shows in self.re_ShowdownAction.finditer(hand.handText): | ||||||
|  |             cards = shows.group('CARDS') | ||||||
|  |             cards = [validCard(card) for card in cards.split(' ')] | ||||||
|  |             logging.debug("readShowdownActions %s %s" %(cards, shows.group('PNAME'))) | ||||||
|  |             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): | ||||||
|  |         """Reads lines where hole & board cards are mixed to form a hand (summary lines)""" | ||||||
|  |         for m in self.re_CollectPot.finditer(hand.handText): | ||||||
|  |             try: | ||||||
|  |                 if m.group('CARDS') is not None: | ||||||
|  |                     cards = m.group('CARDS') | ||||||
|  |                     cards = [validCard(card) for card in cards.split(' ')] | ||||||
|  |                     player = m.group('PNAME') | ||||||
|  |                     logging.debug("readShownCards %s cards=%s" % (player, cards)) | ||||||
|  |     #                hand.addShownCards(cards=None, player=m.group('PNAME'), holeandboard=cards) | ||||||
|  |                     hand.addShownCards(cards=cards, player=m.group('PNAME')) | ||||||
|  |             except IndexError: | ||||||
|  |                 pass # there's no "PLAYER - Mucks" at AP that I can see | ||||||
|  | 
 | ||||||
|  | def validCard(card): | ||||||
|  |     card = card.strip() | ||||||
|  |     if card == '10s': card = 'Ts' | ||||||
|  |     if card == '10h': card = 'Th' | ||||||
|  |     if card == '10d': card = 'Td' | ||||||
|  |     if card == '10c': card = 'Tc' | ||||||
|  |     return card | ||||||
|  | 
 | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     parser = OptionParser() | ||||||
|  |     parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="-") | ||||||
|  |     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) | ||||||
|  |     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") | ||||||
|  | 
 | ||||||
|  |     (options, args) = parser.parse_args() | ||||||
|  | 
 | ||||||
|  |     LOG_FILENAME = './logging.out' | ||||||
|  |     logging.basicConfig(filename=LOG_FILENAME,level=options.verbosity) | ||||||
|  | 
 | ||||||
|  |     e = Absolute(in_path = options.ipath, out_path = options.opath, follow = options.follow, autostart=True, debugging=True) | ||||||
|  | 
 | ||||||
|  | @ -957,6 +957,11 @@ class Database: | ||||||
|         c.execute("INSERT INTO Sites (name,currency) VALUES ('PokerStars', 'USD')") |         c.execute("INSERT INTO Sites (name,currency) VALUES ('PokerStars', 'USD')") | ||||||
|         c.execute("INSERT INTO Sites (name,currency) VALUES ('Everleaf', 'USD')") |         c.execute("INSERT INTO Sites (name,currency) VALUES ('Everleaf', 'USD')") | ||||||
|         c.execute("INSERT INTO Sites (name,currency) VALUES ('Win2day', 'USD')") |         c.execute("INSERT INTO Sites (name,currency) VALUES ('Win2day', 'USD')") | ||||||
|  |         c.execute("INSERT INTO Sites (name,currency) VALUES ('OnGame', 'USD')") | ||||||
|  |         c.execute("INSERT INTO Sites (name,currency) VALUES ('UltimateBet', 'USD')") | ||||||
|  |         c.execute("INSERT INTO Sites (name,currency) VALUES ('Betfair', 'USD')") | ||||||
|  |         c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')") | ||||||
|  |         c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')") | ||||||
|         if self.backend == self.SQLITE: |         if self.backend == self.SQLITE: | ||||||
|             c.execute("INSERT INTO TourneyTypes VALUES (NULL, 1, 0, 0, 0, 0);") |             c.execute("INSERT INTO TourneyTypes VALUES (NULL, 1, 0, 0, 0, 0);") | ||||||
|         else: |         else: | ||||||
|  |  | ||||||
|  | @ -81,7 +81,7 @@ class GuiPlayerStats (threading.Thread): | ||||||
|                        , ["hand",       False, "Hand",     0.0, "%s"]   # true not allowed for this line |                        , ["hand",       False, "Hand",     0.0, "%s"]   # true not allowed for this line | ||||||
|                        , ["plposition", False, "Posn",     1.0, "%s"]   # true not allowed for this line (set in code) |                        , ["plposition", False, "Posn",     1.0, "%s"]   # true not allowed for this line (set in code) | ||||||
|                        , ["n",          True,  "Hds",      1.0, "%d"] |                        , ["n",          True,  "Hds",      1.0, "%d"] | ||||||
|                        , ["avgseats",   True,  "Seats",    1.0, "%3.1f"] |                        , ["avgseats",   False,  "Seats",    1.0, "%3.1f"] | ||||||
|                        , ["vpip",       True,  "VPIP",     1.0, "%3.1f"] |                        , ["vpip",       True,  "VPIP",     1.0, "%3.1f"] | ||||||
|                        , ["pfr",        True,  "PFR",      1.0, "%3.1f"] |                        , ["pfr",        True,  "PFR",      1.0, "%3.1f"] | ||||||
|                        , ["pf3",        True,  "PF3",      1.0, "%3.1f"] |                        , ["pf3",        True,  "PF3",      1.0, "%3.1f"] | ||||||
|  |  | ||||||
|  | @ -203,6 +203,96 @@ | ||||||
| 	        	<location seat="9" x="70" y="53">  </location> | 	        	<location seat="9" x="70" y="53">  </location> | ||||||
| 	        </layout> | 	        </layout> | ||||||
| 	    </site> | 	    </site> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	    <site enabled="False" | ||||||
|  | 	          site_name="Absolute" | ||||||
|  | 	          table_finder="AbsolutePoker.exe" | ||||||
|  | 	          screen_name="YOUR SCREEN NAME HERE" | ||||||
|  | 	          site_path="" | ||||||
|  | 	          HH_path="" | ||||||
|  | 	          decoder="everleaf_decode_table" | ||||||
|  |               converter="AbsoluteToFpdb" | ||||||
|  | 	          supported_games="holdem"> | ||||||
|  | 	        <layout fav_seat="0" height="547" max="8" width="794"> | ||||||
|  | 	        	<location seat="1" x="640" y="64">  </location> | ||||||
|  | 	        	<location seat="2" x="650" y="230"> </location> | ||||||
|  | 	        	<location seat="3" x="650" y="385"> </location> | ||||||
|  | 	        	<location seat="4" x="588" y="425"> </location> | ||||||
|  | 	        	<location seat="5" x="92" y="425"> </location> | ||||||
|  | 	        	<location seat="6" x="0" y="373"> </location> | ||||||
|  | 	        	<location seat="7" x="0" y="223"> </location> | ||||||
|  | 	        	<location seat="8" x="25" y="50">  </location> | ||||||
|  | 	        </layout> | ||||||
|  | 	        <layout fav_seat="0" height="547" max="6" width="794"> | ||||||
|  | 	        	<location seat="1" x="640" y="58"> </location> | ||||||
|  | 	        	<location seat="2" x="654" y="288"> </location> | ||||||
|  | 	        	<location seat="3" x="615" y="424"> </location> | ||||||
|  | 	        	<location seat="4" x="70" y="421"> </location> | ||||||
|  | 	        	<location seat="5" x="0" y="280"> </location> | ||||||
|  | 	        	<location seat="6" x="70" y="58"> </location> | ||||||
|  | 	        </layout> | ||||||
|  | 	        <layout fav_seat="0" height="547" max="2" width="794"> | ||||||
|  | 	        	<location seat="1" x="651" y="288"> </location> | ||||||
|  | 	        	<location seat="2" x="10"  y="288"> </location> | ||||||
|  | 	        </layout> | ||||||
|  | 	        <layout fav_seat="0" height="547" max="9" width="794"> | ||||||
|  | 	        	<location seat="1" x="634" y="38">  </location> | ||||||
|  | 	        	<location seat="2" x="667" y="184"> </location> | ||||||
|  | 	        	<location seat="3" x="667" y="321"> </location> | ||||||
|  | 	        	<location seat="4" x="667" y="445"> </location> | ||||||
|  | 	        	<location seat="5" x="337" y="459"> </location> | ||||||
|  | 	        	<location seat="6" x="0" y="400"> </location> | ||||||
|  | 	        	<location seat="7" x="0" y="322"> </location> | ||||||
|  | 	        	<location seat="8" x="0" y="181">  </location> | ||||||
|  | 	        	<location seat="9" x="70" y="53">  </location> | ||||||
|  | 	        </layout> | ||||||
|  | 	    </site> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	    <site enabled="False" | ||||||
|  | 	          site_name="PartyPoker" | ||||||
|  | 	          table_finder="PartyPoker.exe" | ||||||
|  | 	          screen_name="YOUR SCREEN NAME HERE" | ||||||
|  | 	          site_path="" | ||||||
|  | 	          HH_path="" | ||||||
|  | 	          decoder="everleaf_decode_table" | ||||||
|  |               converter="PartyPokerToFpdb" | ||||||
|  | 	          supported_games="holdem"> | ||||||
|  | 	        <layout fav_seat="0" height="547" max="8" width="794"> | ||||||
|  | 	        	<location seat="1" x="640" y="64">  </location> | ||||||
|  | 	        	<location seat="2" x="650" y="230"> </location> | ||||||
|  | 	        	<location seat="3" x="650" y="385"> </location> | ||||||
|  | 	        	<location seat="4" x="588" y="425"> </location> | ||||||
|  | 	        	<location seat="5" x="92" y="425"> </location> | ||||||
|  | 	        	<location seat="6" x="0" y="373"> </location> | ||||||
|  | 	        	<location seat="7" x="0" y="223"> </location> | ||||||
|  | 	        	<location seat="8" x="25" y="50">  </location> | ||||||
|  | 	        </layout> | ||||||
|  | 	        <layout fav_seat="0" height="547" max="6" width="794"> | ||||||
|  | 	        	<location seat="1" x="640" y="58"> </location> | ||||||
|  | 	        	<location seat="2" x="654" y="288"> </location> | ||||||
|  | 	        	<location seat="3" x="615" y="424"> </location> | ||||||
|  | 	        	<location seat="4" x="70" y="421"> </location> | ||||||
|  | 	        	<location seat="5" x="0" y="280"> </location> | ||||||
|  | 	        	<location seat="6" x="70" y="58"> </location> | ||||||
|  | 	        </layout> | ||||||
|  | 	        <layout fav_seat="0" height="547" max="2" width="794"> | ||||||
|  | 	        	<location seat="1" x="651" y="288"> </location> | ||||||
|  | 	        	<location seat="2" x="10"  y="288"> </location> | ||||||
|  | 	        </layout> | ||||||
|  | 	        <layout fav_seat="0" height="547" max="9" width="794"> | ||||||
|  | 	        	<location seat="1" x="634" y="38">  </location> | ||||||
|  | 	        	<location seat="2" x="667" y="184"> </location> | ||||||
|  | 	        	<location seat="3" x="667" y="321"> </location> | ||||||
|  | 	        	<location seat="4" x="667" y="445"> </location> | ||||||
|  | 	        	<location seat="5" x="337" y="459"> </location> | ||||||
|  | 	        	<location seat="6" x="0" y="400"> </location> | ||||||
|  | 	        	<location seat="7" x="0" y="322"> </location> | ||||||
|  | 	        	<location seat="8" x="0" y="181">  </location> | ||||||
|  | 	        	<location seat="9" x="70" y="53">  </location> | ||||||
|  | 	        </layout> | ||||||
|  | 	    </site> | ||||||
|     </supported_sites> |     </supported_sites> | ||||||
| 
 | 
 | ||||||
|     <supported_games> |     <supported_games> | ||||||
|  | @ -337,6 +427,8 @@ | ||||||
|         <hhc site="Full Tilt Poker" converter="FulltiltToFpdb"/> |         <hhc site="Full Tilt Poker" converter="FulltiltToFpdb"/> | ||||||
|         <hhc site="Everleaf" converter="EverleafToFpdb"/> |         <hhc site="Everleaf" converter="EverleafToFpdb"/> | ||||||
|         <hhc site="Win2day" converter="Win2dayToFpdb"/> |         <hhc site="Win2day" converter="Win2dayToFpdb"/> | ||||||
|  |         <hhc site="Absolute" converter="AbsoluteToFpdb"/> | ||||||
|  |         <hhc site="PartyPoker" converter="PartyPokerToFpdb"/> | ||||||
|     </hhcs> |     </hhcs> | ||||||
| 
 | 
 | ||||||
|     <supported_databases> |     <supported_databases> | ||||||
|  |  | ||||||
|  | @ -40,7 +40,7 @@ class Hand(object): | ||||||
|     LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'} |     LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'} | ||||||
|     SYMBOL = {'USD': '$', 'EUR': u'$', 'T$': '', 'play': ''} |     SYMBOL = {'USD': '$', 'EUR': u'$', 'T$': '', 'play': ''} | ||||||
|     MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose'  : 'HOSE', 'ha': 'HA'} |     MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose'  : 'HOSE', 'ha': 'HA'} | ||||||
|     SITEIDS = {'Fulltilt':1, 'PokerStars':2, 'Everleaf':3, 'Win2day':4, 'OnGame':5, 'UltimateBet':6, 'Betfair':7} |     SITEIDS = {'Fulltilt':1, 'PokerStars':2, 'Everleaf':3, 'Win2day':4, 'OnGame':5, 'UltimateBet':6, 'Betfair':7, 'Absolute':8, 'PartyPoker':9 } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def __init__(self, sitename, gametype, handText, builtFrom = "HHC"): |     def __init__(self, sitename, gametype, handText, builtFrom = "HHC"): | ||||||
|  |  | ||||||
							
								
								
									
										521
									
								
								pyfpdb/PartyPokerToFpdb.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										521
									
								
								pyfpdb/PartyPokerToFpdb.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,521 @@ | ||||||
|  | #!/usr/bin/env python | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | # | ||||||
|  | #    Copyright 2009, Grigorij Indigirkin | ||||||
|  | #     | ||||||
|  | #    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 | ||||||
|  | ######################################################################## | ||||||
|  | 
 | ||||||
|  | import sys | ||||||
|  | from collections import defaultdict | ||||||
|  | 
 | ||||||
|  | from HandHistoryConverter import * | ||||||
|  | 
 | ||||||
|  | # PartyPoker HH Format | ||||||
|  | 
 | ||||||
|  | class PartyPoker(HandHistoryConverter): | ||||||
|  |     class ParsingException(Exception): | ||||||
|  |         "Usage: raise ParsingException(<msg>[, hh=<hh>])" | ||||||
|  |         def __init__(self, *args, **kwargs): | ||||||
|  |             if len(args)==0: args=[''] + list(args) | ||||||
|  |             msg, args = args[0], args[1:] | ||||||
|  |             if 'hh' in kwargs: | ||||||
|  |                 msg += self.wrapHh(kwargs['hh']) | ||||||
|  |                 del kwargs['hh'] | ||||||
|  |             return Exception.__init__(self, msg, *args, **kwargs) | ||||||
|  |         def wrapHh(self, hh): | ||||||
|  |             return ("\n\nHand history attached below:\n" | ||||||
|  |                     "%(DELIMETER)s\n%(HH)s\n%(DELIMETER)s") % \ | ||||||
|  |                     {'DELIMETER': '#'*50, 'HH': hh} | ||||||
|  |                      | ||||||
|  | ############################################################ | ||||||
|  | #    Class Variables | ||||||
|  | 
 | ||||||
|  |     sym = {'USD': "\$", } | ||||||
|  | 
 | ||||||
|  |     # Static regexes | ||||||
|  |     # $5 USD NL Texas Hold'em - Saturday, July 25, 07:53:52 EDT 2009 | ||||||
|  |     # NL Texas Hold'em $1 USD Buy-in Trny:45685440 Level:8  Blinds-Antes(600/1 200 -50) - Sunday, May 17, 11:25:07 MSKS 2009 | ||||||
|  |     re_GameInfoRing     = re.compile(""" | ||||||
|  |             (?P<CURRENCY>\$|)\s*(?P<RINGLIMIT>\d+)\s*(?:USD)?\s* | ||||||
|  |             (?P<LIMIT>(NL))\s+ | ||||||
|  |             (?P<GAME>(Texas\ Hold\'em)) | ||||||
|  |             \s*\-\s* | ||||||
|  |             (?P<DATETIME>.+) | ||||||
|  |             """, re.VERBOSE) | ||||||
|  |     re_GameInfoTrny     = re.compile(""" | ||||||
|  |             (?P<LIMIT>(NL))\s+ | ||||||
|  |             (?P<GAME>(Texas\ Hold\'em))\s+ | ||||||
|  |             (?P<BUYIN>\$?[.0-9]+)\s*(?P<BUYIN_CURRENCY>USD)?\s*Buy-in\s+ | ||||||
|  |             Trny:\s?(?P<TOURNO>\d+)\s+ | ||||||
|  |             Level:\s*(?P<LEVEL>\d+)\s+ | ||||||
|  |             Blinds(?:-Antes)?\( | ||||||
|  |                 (?P<SB>[.0-9 ]+)\s* | ||||||
|  |                 /(?P<BB>[.0-9 ]+) | ||||||
|  |                 (?:\s*-\s*(?P<ANTE>[.0-9 ]+)\$?)? | ||||||
|  |             \) | ||||||
|  |             \s*\-\s* | ||||||
|  |             (?P<DATETIME>.+) | ||||||
|  |             """, re.VERBOSE) | ||||||
|  |     re_Hid          = re.compile("^Game \#(?P<HID>\d+) starts.") | ||||||
|  |     #re_GameInfo     = re.compile(""" | ||||||
|  |           #PartyPoker\sGame\s\#(?P<HID>[0-9]+):\s+ | ||||||
|  |           #(Tournament\s\#                # open paren of tournament info | ||||||
|  |           #(?P<TOURNO>\d+),\s | ||||||
|  |           #(?P<BUYIN>[%(LS)s\+\d\.]+      # here's how I plan to use LS | ||||||
|  |           #\s?(?P<TOUR_ISO>%(LEGAL_ISO)s)? | ||||||
|  |           #)\s)?                          # close paren of tournament info | ||||||
|  |           #(?P<MIXED>HORSE|8\-Game|HOSE)?\s?\(? | ||||||
|  |           #(?P<GAME>Hold\'em|Razz|7\sCard\sStud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi|Triple\sDraw\s2\-7\sLowball)\s | ||||||
|  |           #(?P<LIMIT>No\sLimit|Limit|Pot\sLimit)\)?,?\s | ||||||
|  |           #(-\sLevel\s(?P<LEVEL>[IVXLC]+)\s)? | ||||||
|  |           #\(?                            # open paren of the stakes | ||||||
|  |           #(?P<CURRENCY>%(LS)s|)? | ||||||
|  |           #(?P<SB>[.0-9]+)/(%(LS)s)? | ||||||
|  |           #(?P<BB>[.0-9]+) | ||||||
|  |           #\s?(?P<ISO>%(LEGAL_ISO)s)? | ||||||
|  |           #\)\s-\s                        # close paren of the stakes | ||||||
|  |           #(?P<DATETIME>.*$)""" % substitutions, | ||||||
|  |           #re.MULTILINE|re.VERBOSE) | ||||||
|  | 
 | ||||||
|  |     re_PlayerInfo   = re.compile(""" | ||||||
|  |           Seat\s(?P<SEAT>\d+):\s | ||||||
|  |           (?P<PNAME>.*)\s | ||||||
|  |           \(\s*\$?(?P<CASH>[0-9,.]+)\s*(?:USD|)\s*\) | ||||||
|  |           """ ,  | ||||||
|  |           re.VERBOSE) | ||||||
|  |     #re_PlayerInfo   = re.compile(""" | ||||||
|  |           #^Seat\s(?P<SEAT>[0-9]+):\s | ||||||
|  |           #(?P<PNAME>.*)\s | ||||||
|  |           #\((%(LS)s)?(?P<CASH>[.0-9]+)\sin\schips\)""" % substitutions,  | ||||||
|  |           #re.MULTILINE|re.VERBOSE) | ||||||
|  | 
 | ||||||
|  |     re_HandInfo     = re.compile(""" | ||||||
|  |             ^Table\s+ | ||||||
|  |             (?P<TTYPE>[a-zA-Z0-9 ]+)\s+ | ||||||
|  |             (?: \#|\(|)(?P<TABLE>\d+)\)?\s+ | ||||||
|  |             (?:[^ ]+\s+\#(?P<MTTTABLE>\d+).+)? # table number for mtt | ||||||
|  |             \((?P<PLAY>Real|Play)\s+Money\)\s+ # FIXME: check if play money is correct | ||||||
|  |             Seat\s+(?P<BUTTON>\d+)\sis\sthe\sbutton | ||||||
|  |             """,  | ||||||
|  |           re.MULTILINE|re.VERBOSE) | ||||||
|  |     #re_HandInfo     = re.compile(""" | ||||||
|  |           #^Table\s\'(?P<TABLE>[-\ a-zA-Z\d]+)\'\s | ||||||
|  |           #((?P<MAX>\d+)-max\s)? | ||||||
|  |           #(?P<PLAY>\(Play\sMoney\)\s)? | ||||||
|  |           #(Seat\s\#(?P<BUTTON>\d+)\sis\sthe\sbutton)?""",  | ||||||
|  |           #re.MULTILINE|re.VERBOSE) | ||||||
|  | 
 | ||||||
|  |     re_SplitHands   = re.compile('\x00+') | ||||||
|  |     re_TailSplitHands   = re.compile('(\x00+)') | ||||||
|  |     lineSplitter    = '\n' | ||||||
|  |     re_Button       = re.compile('Seat (?P<BUTTON>\d+) is the button', re.MULTILINE) | ||||||
|  |     re_Board        = re.compile(r"\[(?P<CARDS>.+)\]") | ||||||
|  |     re_NoSmallBlind = re.compile('^There is no Small Blind in this hand as the Big Blind of the previous hand left the table') | ||||||
|  | #        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]+)')     | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, index=0): | ||||||
|  |         """\ | ||||||
|  | in_path   (default '-' = sys.stdin) | ||||||
|  | out_path  (default '-' = sys.stdout) | ||||||
|  | follow :  whether to tail -f the input""" | ||||||
|  |         HandHistoryConverter.__init__(self, in_path, out_path, sitename="PartyPoker", follow=follow, index=index) | ||||||
|  |         logging.info("Initialising PartyPoker converter class") | ||||||
|  |         self.filetype = "text" | ||||||
|  |         self.codepage = "cp1252" # FIXME: wtf? | ||||||
|  |         self.siteId   = 9 # Needs to match id entry in Sites database | ||||||
|  |         self._gameType = None # cached reg-parse result | ||||||
|  |         if autostart:  | ||||||
|  |             self.start() | ||||||
|  | 
 | ||||||
|  |     def allHandsAsList(self): | ||||||
|  |         list = HandHistoryConverter.allHandsAsList(self) | ||||||
|  |         return filter(lambda text: len(text.strip()), list) | ||||||
|  | 
 | ||||||
|  |     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. | ||||||
|  | # TODO: should probably rename re_HeroCards and corresponding method, | ||||||
|  | #    since they are used to find all cards on lines starting with "Dealt to:" | ||||||
|  | #    They still identify the hero. | ||||||
|  |             self.compiledPlayers = players | ||||||
|  |             player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")" | ||||||
|  |             subst = {'PLYR': player_re, 'CUR_SYM': hand.SYMBOL[hand.gametype['currency']], | ||||||
|  |                 'CUR': hand.gametype['currency'] if hand.gametype['currency']!='T$' else ''} | ||||||
|  |             logging.debug("player_re: " + subst['PLYR']) | ||||||
|  |             logging.debug("CUR_SYM: " + subst['CUR_SYM']) | ||||||
|  |             logging.debug("CUR: " + subst['CUR']) | ||||||
|  |             self.re_PostSB = re.compile( | ||||||
|  |                 r"^%(PLYR)s posts small blind \[%(CUR_SYM)s(?P<SB>[.0-9]+) ?%(CUR)s\]\." %  subst,  | ||||||
|  |                 re.MULTILINE) | ||||||
|  |             self.re_PostBB = re.compile( | ||||||
|  |                 r"^%(PLYR)s posts big blind \[%(CUR_SYM)s(?P<BB>[.0-9]+) ?%(CUR)s\]\." %  subst,  | ||||||
|  |                 re.MULTILINE) | ||||||
|  |             self.re_Antes = re.compile( | ||||||
|  |                 r"^%(PLYR)s posts ante \[%(CUR_SYM)s(?P<ANTE>[.0-9]+) ?%(CUR)s\]\." %  subst, | ||||||
|  |                 re.MULTILINE) | ||||||
|  |             #self.re_BringIn = re.compile( | ||||||
|  |                 #r"^%(PLYR)s: brings[- ]in( low|) for %(CUR)s(?P<BRINGIN>[.0-9]+)" % subst, | ||||||
|  |                 #re.MULTILINE) | ||||||
|  |             #self.re_PostBoth = re.compile( | ||||||
|  |                 #r"^%(PLYR)s: posts small \& big blinds \[%(CUR)s (?P<SBBB>[.0-9]+)" %  subst, | ||||||
|  |                 #re.MULTILINE) | ||||||
|  |             self.re_HeroCards = re.compile( | ||||||
|  |                 r"^Dealt to %(PLYR)s \[\s*(?P<NEWCARDS>.+)\s*\]" % subst, | ||||||
|  |                 re.MULTILINE) | ||||||
|  |             self.re_Action = re.compile(r""" | ||||||
|  |                 ^%(PLYR)s\s+(?P<ATYPE>bets|checks|raises|calls|folds|is\sall-In) | ||||||
|  |                 (?:\s+\[%(CUR_SYM)s(?P<BET>[.,\d]+)\s*%(CUR)s\])? | ||||||
|  |                 """ %  subst,  | ||||||
|  |                 re.MULTILINE|re.VERBOSE) | ||||||
|  |             self.re_ShownCards = re.compile( | ||||||
|  |                 r"^%s (?P<SHOWED>(?:doesn\'t )?shows?) "  %  player_re +  | ||||||
|  |                 r"\[ *(?P<CARDS>.+) *\](?P<COMBINATION>.+)\.",  | ||||||
|  |                 re.MULTILINE) | ||||||
|  |             self.re_CollectPot = re.compile( | ||||||
|  |                 r""""^%(PLYR)s \s+ wins \s+ | ||||||
|  |                 %(CUR_SYM)s(?P<POT>[.\d]+)\s*%(CUR)s""" %  subst,  | ||||||
|  |                 re.MULTILINE|re.VERBOSE) | ||||||
|  |             #self.re_sitsOut    = re.compile("^%s sits out" %  player_re, re.MULTILINE) | ||||||
|  |             #self.re_ShownCards = re.compile( | ||||||
|  |                 #"^Seat (?P<SEAT>[0-9]+): %s (\(.*\) )? | ||||||
|  |                 #(?P<SHOWED>showed|mucked) \[(?P<CARDS>.*)\].*" %  player_re,  | ||||||
|  |                 #re.MULTILINE) | ||||||
|  | 
 | ||||||
|  |     def readSupportedGames(self): | ||||||
|  |         return [["ring", "hold", "nl"], | ||||||
|  |                 #["ring", "hold", "pl"], | ||||||
|  |                 #["ring", "hold", "fl"], | ||||||
|  | 
 | ||||||
|  |                 ["tour", "hold", "nl"], | ||||||
|  |                 #["tour", "hold", "pl"], | ||||||
|  |                 #["tour", "hold", "fl"], | ||||||
|  |                ] | ||||||
|  | 
 | ||||||
|  |     def _getGameType(self, handText): | ||||||
|  |         if self._gameType is None: | ||||||
|  |             # let's determine whether hand is trny | ||||||
|  |             # and whether 5-th line contains head line | ||||||
|  |             headLine = handText.split(self.lineSplitter)[4] | ||||||
|  |             #print headLine | ||||||
|  |             #sys.exit(1) | ||||||
|  |             for headLineContainer in headLine, handText: | ||||||
|  |                 for regexp in self.re_GameInfoTrny, self.re_GameInfoRing: | ||||||
|  |                     m = regexp.search(headLineContainer) | ||||||
|  |                     if m is not None: | ||||||
|  |                         self._gameType = m | ||||||
|  |                         return self._gameType | ||||||
|  |         return self._gameType | ||||||
|  |      | ||||||
|  |     def determineGameType(self, handText): | ||||||
|  | #    inspect the handText and return the gametype dict | ||||||
|  | #    gametype dict is: | ||||||
|  | #    {'limitType': xxx, 'base': xxx, 'category': xxx} | ||||||
|  | 
 | ||||||
|  |         print self.ParsingException().wrapHh( handText ) | ||||||
|  |          | ||||||
|  |         info = {} | ||||||
|  |         m = self._getGameType(handText) | ||||||
|  |         if m is None: | ||||||
|  |             return None | ||||||
|  |          | ||||||
|  | 
 | ||||||
|  |         mg = m.groupdict() | ||||||
|  |         # translations from captured groups to fpdb info strings | ||||||
|  |         limits = { 'NL':'nl',  | ||||||
|  | #            'Pot Limit':'pl', 'Limit':'fl'  | ||||||
|  |             } | ||||||
|  |         games = {                          # base, category | ||||||
|  |                          "Texas Hold'em" : ('hold','holdem'),  | ||||||
|  |                                 #'Omaha' : ('hold','omahahi'), | ||||||
|  |                } | ||||||
|  |         currencies = { '$':'USD', '':'T$' } | ||||||
|  | 
 | ||||||
|  |         for expectedField in ['LIMIT', 'GAME']: | ||||||
|  |             if mg[expectedField] is None: | ||||||
|  |                 raise self.ParsingException( | ||||||
|  |                     "Cannot fetch field '%s'" % expectedField, | ||||||
|  |                     hh = handText) | ||||||
|  |         try: | ||||||
|  |             info['limitType'] = limits[mg['LIMIT']] | ||||||
|  |         except: | ||||||
|  |             raise self.ParsingException( | ||||||
|  |                 "Unknown limit '%s'" % mg['LIMIT'], | ||||||
|  |                 hh = handText) | ||||||
|  | 
 | ||||||
|  |         try: | ||||||
|  |             (info['base'], info['category']) = games[mg['GAME']] | ||||||
|  |         except: | ||||||
|  |             raise self.ParsingException( | ||||||
|  |                 "Unknown game type '%s'" % mg['GAME'], | ||||||
|  |                 hh = handText) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         if 'TOURNO' in mg: | ||||||
|  |             info['type'] = 'tour' | ||||||
|  |         else: | ||||||
|  |             info['type'] = 'ring' | ||||||
|  |          | ||||||
|  |         if info['type'] == 'ring': | ||||||
|  |             info['sb'], info['bb'] = ringBlinds(mg['RINGLIMIT']) | ||||||
|  |             # FIXME: there are only $ and play money availible for cash | ||||||
|  |             info['currency'] = currencies(mg['CURRENCY']) | ||||||
|  |         else: | ||||||
|  |             info['sb'] = renderTrnyMoney(mg['SB']) | ||||||
|  |             info['bb'] = renderTrnyMoney(mg['BB']) | ||||||
|  |             info['currency'] = 'T$' | ||||||
|  |              | ||||||
|  | 
 | ||||||
|  |         # NB: SB, BB must be interpreted as blinds or bets depending on limit type. | ||||||
|  |         return info | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def readHandInfo(self, hand): | ||||||
|  |         info = {} | ||||||
|  |         m = self.re_HandInfo.search(hand.handText,re.DOTALL) | ||||||
|  |         if m: | ||||||
|  |             info.update(m.groupdict()) | ||||||
|  |         else: | ||||||
|  |             raise self.ParsingException("Cannot read Handinfo for current hand", hh=hand.handText) | ||||||
|  |         m = self._getGameType(hand.handText) | ||||||
|  |         if m: info.update(m.groupdict()) | ||||||
|  |         m = self.re_Hid.search(hand.handText) | ||||||
|  |         if m: info.update(m.groupdict()) | ||||||
|  | 
 | ||||||
|  |         # FIXME: it's a hack cause party doesn't supply hand.maxseats info | ||||||
|  |         #hand.maxseats = '9' | ||||||
|  |         hand.mixed = None | ||||||
|  |          | ||||||
|  |         # TODO : I rather like the idea of just having this dict as hand.info | ||||||
|  |         logging.debug("readHandInfo: %s" % info) | ||||||
|  |         for key in info: | ||||||
|  |             if key == 'DATETIME': | ||||||
|  |                 #Saturday, July 25, 07:53:52 EDT 2009 | ||||||
|  |                 #Thursday, July 30, 21:40:41 MSKS 2009 | ||||||
|  |                 m2 = re.search("\w+, (?P<M>\w+) (?P<D>\d+), (?P<H>\d+):(?P<MIN>\d+):(?P<S>\d+) (?P<TZ>[A-Z]+) (?P<Y>\d+)", info[key]) | ||||||
|  |                 # we cant use '%B' due to locale problems | ||||||
|  |                 months = ['January', 'February', 'March', 'April','May', 'June', | ||||||
|  |                     'July','August','September','October','November','December'] | ||||||
|  |                 month = months.index(m2.group('M')) + 1 | ||||||
|  |                 datetimestr = "%s/%s/%s %s:%s:%s" % (m2.group('Y'), month,m2.group('D'),m2.group('H'),m2.group('MIN'),m2.group('S')) | ||||||
|  |                 hand.starttime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") | ||||||
|  |                 #tzShift = defaultdict(lambda:0, {'EDT': -5, 'EST': -6, 'MSKS': 3}) | ||||||
|  |                 #hand.starttime -= datetime.timedelta(hours=tzShift[m2.group('TZ')]) | ||||||
|  |                    | ||||||
|  |             if key == 'HID': | ||||||
|  |                 hand.handid = info[key] | ||||||
|  |             if key == 'TABLE': | ||||||
|  |                 hand.tablename = info[key] | ||||||
|  |             if key == 'BUTTON': | ||||||
|  |                 hand.buttonpos = info[key] | ||||||
|  |             if key == 'TOURNO': | ||||||
|  |                 hand.tourNo = info[key] | ||||||
|  |             if key == 'BUYIN': | ||||||
|  |                 #FIXME: it's dirty hack T_T | ||||||
|  |                 cur = info[key][0] if info[key][0] not in '0123456789' else '' | ||||||
|  |                 hand.buyin = info[key] + '+%s0' % cur | ||||||
|  |             if key == 'LEVEL': | ||||||
|  |                 hand.level = info[key] | ||||||
|  |             if key == 'PLAY' and info['PLAY'] != 'Real': | ||||||
|  |                 # TODO: play money wasn't tested | ||||||
|  | #                hand.currency = 'play' # overrides previously set value | ||||||
|  |                 hand.gametype['currency'] = 'play' | ||||||
|  | 
 | ||||||
|  |     def readButton(self, hand): | ||||||
|  |         m = self.re_Button.search(hand.handText) | ||||||
|  |         if m: | ||||||
|  |             hand.buttonpos = int(m.group('BUTTON')) | ||||||
|  |         else: | ||||||
|  |             logging.info('readButton: not found') | ||||||
|  | 
 | ||||||
|  |     def readPlayerStacks(self, hand): | ||||||
|  |         logging.debug("readPlayerStacks") | ||||||
|  |         m = self.re_PlayerInfo.finditer(hand.handText) | ||||||
|  |         players = [] | ||||||
|  |         for a in m: | ||||||
|  |             hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), | ||||||
|  |                            renderTrnyMoney(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. | ||||||
|  |         assert hand.gametype['base'] == "hold", \ | ||||||
|  |             "wtf! There're no %s games on party" % hand.gametype['base'] | ||||||
|  |         m =  re.search( | ||||||
|  |             r"\*{2} Dealing down cards \*{2}" | ||||||
|  |             r"(?P<PREFLOP>.+?)" | ||||||
|  |             r"(?:\*{2} Dealing Flop \*{2} (?P<FLOP>\[ \S\S, \S\S, \S\S \].+?))?" | ||||||
|  |             r"(?:\*{2} Dealing Turn \*{2} (?P<TURN>\[ \S\S \].+?))?" | ||||||
|  |             r"(?:\*{2} Dealing River \*{2} (?P<RIVER>\[ \S\S \].+?))?$" | ||||||
|  |             , hand.handText,re.DOTALL) | ||||||
|  |         hand.addStreets(m) | ||||||
|  | 
 | ||||||
|  |     def readCommunityCards(self, hand, street):  | ||||||
|  |         if street in ('FLOP','TURN','RIVER'):    | ||||||
|  |             m = self.re_Board.search(hand.streets[street]) | ||||||
|  |             hand.setCommunityCards(street, renderCards(m.group('CARDS'))) | ||||||
|  | 
 | ||||||
|  |     def readAntes(self, hand): | ||||||
|  |         logging.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 readBlinds(self, hand): | ||||||
|  |         noSmallBlind = bool(self.re_NoSmallBlind.search(hand.handText)) | ||||||
|  |         if hand.gametype['type'] == 'ring': | ||||||
|  |             try: | ||||||
|  |                 assert noSmallBlind==False | ||||||
|  |                 m = self.re_PostSB.search(hand.handText) | ||||||
|  |                 hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) | ||||||
|  |             except: # no small blind | ||||||
|  |                 hand.addBlind(None, None, None) | ||||||
|  |                | ||||||
|  |             for a in self.re_PostBB.finditer(hand.handText): | ||||||
|  |                 hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) | ||||||
|  |         else:  | ||||||
|  |             # party doesn't track blinds for tournaments | ||||||
|  |             # so there're some cra^Wcaclulations | ||||||
|  |             if hand.buttonpos == 0: | ||||||
|  |                 self.readButton(hand) | ||||||
|  |             # NOTE: code below depends on Hand's implementation | ||||||
|  |             # playersMap - dict {seat: (pname,stack)} | ||||||
|  |             playersMap = dict([(f[0], f[1:3]) for f in hand.players])  | ||||||
|  |             maxSeat = max(playersMap) | ||||||
|  |              | ||||||
|  |             def findFirstNonEmptySeat(startSeat): | ||||||
|  |                 while startSeat not in playersMap: | ||||||
|  |                     if startSeat >= maxSeat:  | ||||||
|  |                         startSeat = 0 | ||||||
|  |                     startSeat += 1 | ||||||
|  |                 return startSeat | ||||||
|  |             smartMin = lambda A,B: A if float(A) <= float(B) else B | ||||||
|  |              | ||||||
|  |             if noSmallBlind: | ||||||
|  |                 hand.addBlind(None, None, None) | ||||||
|  |             else: | ||||||
|  |                 smallBlindSeat = findFirstNonEmptySeat(int(hand.buttonpos) + 1) | ||||||
|  |                 blind = smartMin(hand.sb, playersMap[smallBlindSeat][1]) | ||||||
|  |                 hand.addBlind(playersMap[smallBlindSeat][0], 'small blind', blind) | ||||||
|  |                      | ||||||
|  |             bigBlindSeat = findFirstNonEmptySeat(smallBlindSeat + 1) | ||||||
|  |             blind = smartMin(hand.bb, playersMap[bigBlindSeat][1]) | ||||||
|  |             hand.addBlind(playersMap[bigBlindSeat][0], 'small blind', blind) | ||||||
|  |              | ||||||
|  |                  | ||||||
|  | 
 | ||||||
|  |     def readHeroCards(self, hand): | ||||||
|  | #    streets PREFLOP, PREDRAW, and THIRD are special cases beacause | ||||||
|  | #    we need to grab hero's cards | ||||||
|  |         for street in ('PREFLOP',): | ||||||
|  |             if street in hand.streets.keys(): | ||||||
|  |                 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 = renderCards(found.group('NEWCARDS')) | ||||||
|  |                     hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def readAction(self, hand, street): | ||||||
|  |         m = self.re_Action.finditer(hand.streets[street]) | ||||||
|  |         for action in m: | ||||||
|  |             acts = action.groupdict() | ||||||
|  |             if action.group('ATYPE') in ('raises','is all-In'): | ||||||
|  |                 #print action.groupdict() | ||||||
|  |                 #sys.exit(1) | ||||||
|  |                 hand.addRaiseBy( street, action.group('PNAME'), action.group('BET') ) | ||||||
|  |             elif action.group('ATYPE') == 'calls': | ||||||
|  |                 hand.addCall( street, action.group('PNAME'), action.group('BET') ) | ||||||
|  |                 #print action.groupdict() | ||||||
|  |                 #sys.exit(1) | ||||||
|  |             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')) | ||||||
|  |             else: | ||||||
|  |                 print "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def readShowdownActions(self, hand): | ||||||
|  |         # all action in readShownCards | ||||||
|  |         pass | ||||||
|  | ## TODO: pick up mucks also?? | ||||||
|  |         #for shows in self.re_ShowdownAction.finditer(hand.handText):             | ||||||
|  |             #cards = shows.group('CARDS').split(' ') | ||||||
|  |             #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 = renderCards(m.group('CARDS')) | ||||||
|  | 
 | ||||||
|  |                 (shown, mucked) = (False, False) | ||||||
|  |                 if m.group('SHOWED') == "show": shown = True | ||||||
|  |                 else: mucked = True | ||||||
|  | 
 | ||||||
|  |                 hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked) | ||||||
|  |                  | ||||||
|  | def ringBlinds(ringLimit): | ||||||
|  |     "Returns blinds for current limit" | ||||||
|  |     ringLimit = float(ringLimit) | ||||||
|  |     if ringLimit == 5.: ringLimit = 4. | ||||||
|  |     return ('%.2f' % (ringLimit/200.), '%.2f' % (ringLimit/100.)  ) | ||||||
|  | 
 | ||||||
|  | def renderTrnyMoney(money): | ||||||
|  |     "renders 'numbers' like '1 200' and '2,000'" | ||||||
|  |     return money.replace(' ', '').replace(',', '') | ||||||
|  | 
 | ||||||
|  | def renderCards(string): | ||||||
|  |     "splits strings like ' Js, 4d '" | ||||||
|  |     cards = string.strip().split(' ') | ||||||
|  |     return filter(len, map(lambda x: x.strip(' ,'), cards)) | ||||||
|  |      | ||||||
|  | 
 | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     parser = OptionParser() | ||||||
|  |     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) | ||||||
|  |     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") | ||||||
|  | 
 | ||||||
|  |     (options, args) = parser.parse_args() | ||||||
|  | 
 | ||||||
|  |     #LOG_FILENAME = './logging.out' | ||||||
|  |     logging.basicConfig(level=options.verbosity) | ||||||
|  | 
 | ||||||
|  |     e = PartyPoker(in_path = options.ipath, out_path = options.opath, follow = options.follow) | ||||||
|  | @ -132,6 +132,9 @@ class Importer: | ||||||
| #       self.updated = time() | #       self.updated = time() | ||||||
| 
 | 
 | ||||||
|     def clearFileList(self): |     def clearFileList(self): | ||||||
|  |         self.updatedsize = {} | ||||||
|  |         self.updatetime = {} | ||||||
|  |         self.pos_in_file = {} | ||||||
|         self.filelist = {} |         self.filelist = {} | ||||||
| 
 | 
 | ||||||
|     def closeDBs(self): |     def closeDBs(self): | ||||||
|  | @ -199,7 +202,7 @@ class Importer: | ||||||
|         print "Started at", start, "--", len(self.filelist), "files to import.", self.settings['dropIndexes'] |         print "Started at", start, "--", len(self.filelist), "files to import.", self.settings['dropIndexes'] | ||||||
|         if self.settings['dropIndexes'] == 'auto': |         if self.settings['dropIndexes'] == 'auto': | ||||||
|             self.settings['dropIndexes'] = self.calculate_auto2(self.database, 12.0, 500.0) |             self.settings['dropIndexes'] = self.calculate_auto2(self.database, 12.0, 500.0) | ||||||
|         if self.settings['dropHudCache'] == 'auto': |         if 'dropHudCache' in self.settings and self.settings['dropHudCache'] == 'auto': | ||||||
|             self.settings['dropHudCache'] = self.calculate_auto2(self.database, 25.0, 500.0)    # returns "drop"/"don't drop" |             self.settings['dropHudCache'] = self.calculate_auto2(self.database, 25.0, 500.0)    # returns "drop"/"don't drop" | ||||||
| 
 | 
 | ||||||
|         if self.settings['dropIndexes'] == 'drop': |         if self.settings['dropIndexes'] == 'drop': | ||||||
|  | @ -241,7 +244,7 @@ class Importer: | ||||||
|             self.database.afterBulkImport() |             self.database.afterBulkImport() | ||||||
|         else: |         else: | ||||||
|             print "No need to rebuild indexes." |             print "No need to rebuild indexes." | ||||||
|         if self.settings['dropHudCache'] == 'drop': |         if 'dropHudCache' in self.settings and self.settings['dropHudCache'] == 'drop': | ||||||
|             self.database.rebuild_hudcache() |             self.database.rebuild_hudcache() | ||||||
|         else: |         else: | ||||||
|             print "No need to rebuild hudcache." |             print "No need to rebuild hudcache." | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user