Merge branch 'master' of git://git.assembla.com/free_poker_tools
This commit is contained in:
		
						commit
						49022fcf83
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							|  | @ -1,2 +0,0 @@ | ||||||
| *.pyc |  | ||||||
| *~ |  | ||||||
|  | @ -27,6 +27,12 @@ from HandHistoryConverter import * | ||||||
| 
 | 
 | ||||||
| class Absolute(HandHistoryConverter): | class Absolute(HandHistoryConverter): | ||||||
| 
 | 
 | ||||||
|  |     # Class Variables | ||||||
|  |     sitename = "Absolute" | ||||||
|  |     filetype = "text" | ||||||
|  |     codepage = "cp1252" | ||||||
|  |     siteid   = 8 | ||||||
|  |      | ||||||
|     # Static regexes |     # Static regexes | ||||||
|     re_SplitHands  = re.compile(r"\n\n\n+") |     re_SplitHands  = re.compile(r"\n\n\n+") | ||||||
|     re_TailSplitHands  = re.compile(r"(\n\n\n+)") |     re_TailSplitHands  = re.compile(r"(\n\n\n+)") | ||||||
|  | @ -48,24 +54,6 @@ class Absolute(HandHistoryConverter): | ||||||
| #    re_Board       = re.compile(ur"\[ (?P<CARDS>.+) \]") | #    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   = 8 # 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): |     def compilePlayerRegexs(self, hand): | ||||||
|         players = set([player[1] for player in hand.players]) |         players = set([player[1] for player in hand.players]) | ||||||
|         if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' |         if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' | ||||||
|  |  | ||||||
|  | @ -26,6 +26,11 @@ from HandHistoryConverter import * | ||||||
| 
 | 
 | ||||||
| class Betfair(HandHistoryConverter): | class Betfair(HandHistoryConverter): | ||||||
| 
 | 
 | ||||||
|  |     sitename = 'Betfair' | ||||||
|  |     filetype = "text" | ||||||
|  |     codepage = "cp1252" | ||||||
|  |     siteId   = 7 # Needs to match id entry in Sites database | ||||||
|  | 
 | ||||||
|     # Static regexes |     # Static regexes | ||||||
|     re_GameInfo      = re.compile("^(?P<LIMIT>NL|PL|) (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAME>(Texas Hold\'em|Omaha Hi|Razz))", re.MULTILINE) |     re_GameInfo      = re.compile("^(?P<LIMIT>NL|PL|) (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAME>(Texas Hold\'em|Omaha Hi|Razz))", re.MULTILINE) | ||||||
|     re_SplitHands    = re.compile(r'\n\n+') |     re_SplitHands    = re.compile(r'\n\n+') | ||||||
|  | @ -34,19 +39,6 @@ class Betfair(HandHistoryConverter): | ||||||
|     re_PlayerInfo    = re.compile("Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*)\s\(\s(\$(?P<CASH>[.0-9]+)) \)") |     re_PlayerInfo    = re.compile("Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*)\s\(\s(\$(?P<CASH>[.0-9]+)) \)") | ||||||
|     re_Board         = re.compile(ur"\[ (?P<CARDS>.+) \]") |     re_Board         = re.compile(ur"\[ (?P<CARDS>.+) \]") | ||||||
| 
 | 
 | ||||||
|     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="Betfair", follow=follow, index) # Call super class init. |  | ||||||
|         logging.info("Initialising Betfair converter class") |  | ||||||
|         self.filetype = "text" |  | ||||||
|         self.codepage = "cp1252" |  | ||||||
|         self.siteId   = 7 # Needs to match id entry in Sites database |  | ||||||
|         if autostart: |  | ||||||
|             self.start() |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
|     def compilePlayerRegexs(self,  hand): |     def compilePlayerRegexs(self,  hand): | ||||||
|         players = set([player[1] for player in hand.players]) |         players = set([player[1] for player in hand.players]) | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| #!/usr/bin/env python | #!/usr/bin/env python | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
| """Configuration.py | """Configuration.py | ||||||
| 
 | 
 | ||||||
| Handles HUD configuration files. | Handles HUD configuration files. | ||||||
|  | @ -73,11 +74,17 @@ class Layout: | ||||||
| 
 | 
 | ||||||
| class Site: | class Site: | ||||||
|     def __init__(self, node): |     def __init__(self, node): | ||||||
|  |         def normalizePath(path): | ||||||
|  |             "Normalized existing pathes" | ||||||
|  |             if os.path.exists(path): | ||||||
|  |                 return os.path.abspath(path) | ||||||
|  |             return path | ||||||
|  |          | ||||||
|         self.site_name    = node.getAttribute("site_name") |         self.site_name    = node.getAttribute("site_name") | ||||||
|         self.table_finder = node.getAttribute("table_finder") |         self.table_finder = node.getAttribute("table_finder") | ||||||
|         self.screen_name  = node.getAttribute("screen_name") |         self.screen_name  = node.getAttribute("screen_name") | ||||||
|         self.site_path    = node.getAttribute("site_path") |         self.site_path    = normalizePath(node.getAttribute("site_path")) | ||||||
|         self.HH_path      = node.getAttribute("HH_path") |         self.HH_path      = normalizePath(node.getAttribute("HH_path")) | ||||||
|         self.decoder      = node.getAttribute("decoder") |         self.decoder      = node.getAttribute("decoder") | ||||||
|         self.hudopacity   = node.getAttribute("hudopacity") |         self.hudopacity   = node.getAttribute("hudopacity") | ||||||
|         self.hudbgcolor   = node.getAttribute("bgcolor") |         self.hudbgcolor   = node.getAttribute("bgcolor") | ||||||
|  | @ -92,6 +99,8 @@ class Site: | ||||||
|         self.ypad         = node.getAttribute("ypad") |         self.ypad         = node.getAttribute("ypad") | ||||||
|         self.layout       = {} |         self.layout       = {} | ||||||
|              |              | ||||||
|  |         print self.site_name, self.HH_path | ||||||
|  | 
 | ||||||
|         for layout_node in node.getElementsByTagName('layout'): |         for layout_node in node.getElementsByTagName('layout'): | ||||||
|             lo = Layout(layout_node) |             lo = Layout(layout_node) | ||||||
|             self.layout[lo.max] = lo |             self.layout[lo.max] = lo | ||||||
|  | @ -543,6 +552,13 @@ class Config: | ||||||
|             if db_type   != None: self.supported_databases[db_name].dp_type   = db_type |             if db_type   != None: self.supported_databases[db_name].dp_type   = db_type | ||||||
|         return |         return | ||||||
|      |      | ||||||
|  |     def getDefaultSite(self): | ||||||
|  |         "Returns first enabled site or None" | ||||||
|  |         for site_name,site in self.supported_sites.iteritems(): | ||||||
|  |             if site.enabled: | ||||||
|  |                 return site_name | ||||||
|  |         return None | ||||||
|  | 
 | ||||||
|     def get_tv_parameters(self): |     def get_tv_parameters(self): | ||||||
|         tv = {} |         tv = {} | ||||||
|         try:    tv['combinedStealFold'] = self.tv.combinedStealFold |         try:    tv['combinedStealFold'] = self.tv.combinedStealFold | ||||||
|  | @ -573,14 +589,15 @@ class Config: | ||||||
|         except:  imp['fastStoreHudCache'] = True |         except:  imp['fastStoreHudCache'] = True | ||||||
|         return imp |         return imp | ||||||
| 
 | 
 | ||||||
|     def get_default_paths(self, site = "PokerStars"): |     def get_default_paths(self, site = None): | ||||||
|  |         if site is None: site = self.getDefaultSite() | ||||||
|         paths = {} |         paths = {} | ||||||
|         try: |         try: | ||||||
|             paths['hud-defaultPath']        = os.path.expanduser(self.supported_sites[site].HH_path) |             path = os.path.expanduser(self.supported_sites[site].HH_path) | ||||||
|             paths['bulkImport-defaultPath'] = os.path.expanduser(self.supported_sites[site].HH_path) |             assert(os.path.isdir(path) or os.path.isfile(path)) # maybe it should try another site? | ||||||
|  |             paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = path | ||||||
|         except: |         except: | ||||||
|             paths['hud-defaultPath']        = "default" |             paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = "default" | ||||||
|             paths['bulkImport-defaultPath'] = "default" |  | ||||||
|         return paths |         return paths | ||||||
|      |      | ||||||
|     def get_frames(self, site = "PokerStars"): |     def get_frames(self, site = "PokerStars"): | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ import sys | ||||||
| import traceback | import traceback | ||||||
| from datetime import datetime, date, time, timedelta | from datetime import datetime, date, time, timedelta | ||||||
| from time import time, strftime, sleep | from time import time, strftime, sleep | ||||||
|  | from decimal import Decimal | ||||||
| import string | import string | ||||||
| import re | import re | ||||||
| import logging | import logging | ||||||
|  | @ -1020,6 +1021,22 @@ class Database: | ||||||
|             print "Error during fdb.lock_for_insert:", str(sys.exc_value) |             print "Error during fdb.lock_for_insert:", str(sys.exc_value) | ||||||
|     #end def lock_for_insert |     #end def lock_for_insert | ||||||
| 
 | 
 | ||||||
|  |     def getGameTypeId(self, siteid, game): | ||||||
|  |         c = self.get_cursor() | ||||||
|  |         #FIXME: Fixed for NL at the moment | ||||||
|  |         c.execute(self.sql.query['getGametypeNL'], (siteid, game['type'], game['category'], game['limitType'],  | ||||||
|  |                         int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100))) | ||||||
|  |         tmp = c.fetchone() | ||||||
|  |         if (tmp == None): | ||||||
|  |             hilo = "h" | ||||||
|  |             if game['category'] in ['studhilo', 'omahahilo']: | ||||||
|  |                 hilo = "s" | ||||||
|  |             elif game['category'] in ['razz','27_3draw','badugi']: | ||||||
|  |                 hilo = "l" | ||||||
|  |             tmp  = self.insertGameTypes( (siteid, game['type'], game['base'], game['category'], game['limitType'], hilo, | ||||||
|  |                                     int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100), 0, 0) ) | ||||||
|  |         return tmp[0] | ||||||
|  | 
 | ||||||
|     def getSqlPlayerIDs(self, pnames, siteid): |     def getSqlPlayerIDs(self, pnames, siteid): | ||||||
|         result = {} |         result = {} | ||||||
|         if(self.pcache == None): |         if(self.pcache == None): | ||||||
|  | @ -1127,15 +1144,22 @@ class Database: | ||||||
|             sitehandno, |             sitehandno, | ||||||
|             handstart,  |             handstart,  | ||||||
|             importtime, |             importtime, | ||||||
|  |             seats, | ||||||
|             maxseats, |             maxseats, | ||||||
|             boardcard1,  |             boardcard1,  | ||||||
|             boardcard2,  |             boardcard2,  | ||||||
|             boardcard3,  |             boardcard3,  | ||||||
|             boardcard4,  |             boardcard4,  | ||||||
|             boardcard5 |             boardcard5, | ||||||
|  |             street1Pot, | ||||||
|  |             street2Pot, | ||||||
|  |             street3Pot, | ||||||
|  |             street4Pot, | ||||||
|  |             showdownPot | ||||||
|              )  |              )  | ||||||
|              VALUES  |              VALUES  | ||||||
|               (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""" |               (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, | ||||||
|  |                %s, %s, %s, %s, %s, %s, %s)""" | ||||||
| #---            texture, | #---            texture, | ||||||
| #--            playersVpi, | #--            playersVpi, | ||||||
| #--            playersAtStreet1,  | #--            playersAtStreet1,  | ||||||
|  | @ -1148,27 +1172,25 @@ class Database: | ||||||
| #--            street2Raises, | #--            street2Raises, | ||||||
| #--            street3Raises, | #--            street3Raises, | ||||||
| #--            street4Raises, | #--            street4Raises, | ||||||
| #--            street1Pot, |  | ||||||
| #--            street2Pot, |  | ||||||
| #--            street3Pot, |  | ||||||
| #--            street4Pot, |  | ||||||
| #--            showdownPot |  | ||||||
| #--            seats,  | #--            seats,  | ||||||
| 
 | 
 | ||||||
|         q = q.replace('%s', self.sql.query['placeholder']) |         q = q.replace('%s', self.sql.query['placeholder']) | ||||||
|  |         print "DEBUG: p: %s" %p | ||||||
|  |         print "DEBUG: gtid: %s" % p['gameTypeId'] | ||||||
|         self.cursor.execute(q, ( |         self.cursor.execute(q, ( | ||||||
|                 p['tableName'],  |                 p['tableName'],  | ||||||
|  |                 p['gameTypeId'],  | ||||||
|                 p['siteHandNo'],  |                 p['siteHandNo'],  | ||||||
|                 p['gametypeid'],  |  | ||||||
|                 p['handStart'],  |                 p['handStart'],  | ||||||
|                 datetime.today(), #importtime |                 datetime.today(), #importtime | ||||||
| #                len(p['names']), #seats | #                len(p['names']), #seats | ||||||
|                 p['maxSeats'], |                 p['maxSeats'], | ||||||
|  |                 p['seats'], | ||||||
|                 p['boardcard1'],  |                 p['boardcard1'],  | ||||||
|                 p['boardcard2'],  |                 p['boardcard2'],  | ||||||
|                 p['boardcard3'],  |                 p['boardcard3'],  | ||||||
|                 p['boardcard4'],  |                 p['boardcard4'],  | ||||||
|                 p['boardcard5']) |                 p['boardcard5'], | ||||||
| #                hudCache['playersVpi'],  | #                hudCache['playersVpi'],  | ||||||
| #                hudCache['playersAtStreet1'],  | #                hudCache['playersAtStreet1'],  | ||||||
| #                hudCache['playersAtStreet2'], | #                hudCache['playersAtStreet2'], | ||||||
|  | @ -1180,12 +1202,12 @@ class Database: | ||||||
| #                hudCache['street2Raises'], | #                hudCache['street2Raises'], | ||||||
| #                hudCache['street3Raises'],  | #                hudCache['street3Raises'],  | ||||||
| #                hudCache['street4Raises'],  | #                hudCache['street4Raises'],  | ||||||
| #                hudCache['street1Pot'], |                 p['street1Pot'], | ||||||
| #                hudCache['street2Pot'],  |                 p['street2Pot'], | ||||||
| #                hudCache['street3Pot'], |                 p['street3Pot'], | ||||||
| #                hudCache['street4Pot'], |                 p['street4Pot'], | ||||||
| #                hudCache['showdownPot'] |                 p['showdownPot'] | ||||||
|         ) |         )) | ||||||
|         #return getLastInsertId(backend, conn, cursor) |         #return getLastInsertId(backend, conn, cursor) | ||||||
|     # def storeHand |     # def storeHand | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -26,6 +26,11 @@ from HandHistoryConverter import * | ||||||
| 
 | 
 | ||||||
| class Everleaf(HandHistoryConverter): | class Everleaf(HandHistoryConverter): | ||||||
|      |      | ||||||
|  |     sitename = 'Everleaf' | ||||||
|  |     filetype = "text" | ||||||
|  |     codepage = "cp1252" | ||||||
|  |     siteId   = 3 # Needs to match id entry in Sites database | ||||||
|  | 
 | ||||||
|     # Static regexes |     # Static regexes | ||||||
|     re_SplitHands  = re.compile(r"\n\n\n+") |     re_SplitHands  = re.compile(r"\n\n\n+") | ||||||
|     re_TailSplitHands  = re.compile(r"(\n\n\n+)") |     re_TailSplitHands  = re.compile(r"(\n\n\n+)") | ||||||
|  | @ -37,24 +42,6 @@ class Everleaf(HandHistoryConverter): | ||||||
|     re_Board       = re.compile(ur"\[ (?P<CARDS>.+) \]") |     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="Everleaf", follow=follow, index=index) |  | ||||||
|         logging.info("Initialising Everleaf 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): |     def compilePlayerRegexs(self, hand): | ||||||
|         players = set([player[1] for player in hand.players]) |         players = set([player[1] for player in hand.players]) | ||||||
|         if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' |         if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' | ||||||
|  |  | ||||||
|  | @ -1 +1,4 @@ | ||||||
| class FpdbParseError(Exception): pass | class FpdbParseError(Exception):  | ||||||
|  |     def __init__(self,hid=None): | ||||||
|  |         self.hid = hid | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | @ -27,8 +27,14 @@ from HandHistoryConverter import * | ||||||
| 
 | 
 | ||||||
| class Fulltilt(HandHistoryConverter): | class Fulltilt(HandHistoryConverter): | ||||||
|      |      | ||||||
|  |     sitename = "Fulltilt" | ||||||
|  |     filetype = "text" | ||||||
|  |     codepage = "cp1252" | ||||||
|  |     siteId   = 1 # Needs to match id entry in Sites database | ||||||
|  | 
 | ||||||
|     # Static regexes |     # Static regexes | ||||||
|     re_GameInfo     = re.compile('''(?:(?P<TOURNAMENT>.+)\s\((?P<TOURNO>\d+)\),\s)? |     re_GameInfo     = re.compile('''.*\#(?P<HID>[0-9]+):\s | ||||||
|  |                                     (?:(?P<TOURNAMENT>.+)\s\((?P<TOURNO>\d+)\),\s)? | ||||||
|                                     .+ |                                     .+ | ||||||
|                                     -\s(?P<CURRENCY>\$|)? |                                     -\s(?P<CURRENCY>\$|)? | ||||||
|                                     (?P<SB>[.0-9]+)/ |                                     (?P<SB>[.0-9]+)/ | ||||||
|  | @ -39,7 +45,7 @@ class Fulltilt(HandHistoryConverter): | ||||||
|                                  ''', re.VERBOSE) |                                  ''', re.VERBOSE) | ||||||
|     re_SplitHands   = re.compile(r"\n\n+") |     re_SplitHands   = re.compile(r"\n\n+") | ||||||
|     re_TailSplitHands   = re.compile(r"(\n\n+)") |     re_TailSplitHands   = re.compile(r"(\n\n+)") | ||||||
|     re_HandInfo     = re.compile('''.*\#(?P<HID>[0-9]+):\s |     re_HandInfo     = re.compile(r'''.*\#(?P<HID>[0-9]+):\s | ||||||
|                                     (?:(?P<TOURNAMENT>.+)\s\((?P<TOURNO>\d+)\),\s)? |                                     (?:(?P<TOURNAMENT>.+)\s\((?P<TOURNO>\d+)\),\s)? | ||||||
|                                     Table\s |                                     Table\s | ||||||
|                                     (?P<PLAY>Play\sChip\s|PC)? |                                     (?P<PLAY>Play\sChip\s|PC)? | ||||||
|  | @ -47,8 +53,9 @@ class Fulltilt(HandHistoryConverter): | ||||||
|                                     (\((?P<TABLEATTRIBUTES>.+)\)\s)?-\s |                                     (\((?P<TABLEATTRIBUTES>.+)\)\s)?-\s | ||||||
|                                     \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\s(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s |                                     \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\s(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s | ||||||
|                                     (?P<GAMETYPE>[a-zA-Z\/\'\s]+)\s-\s |                                     (?P<GAMETYPE>[a-zA-Z\/\'\s]+)\s-\s | ||||||
|                                     (?P<DATETIME>.*) |                                     (?P<DATETIME>.*?)\n | ||||||
|                                  ''', re.VERBOSE) |                                     (?:.*?\n(?P<CANCELLED>Hand\s\#(?P=HID)\shas\sbeen\scanceled))? | ||||||
|  |                                  ''', re.VERBOSE|re.DOTALL) | ||||||
|     re_Button       = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE) |     re_Button       = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE) | ||||||
|     re_PlayerInfo   = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$?(?P<CASH>[,.0-9]+)\)$', re.MULTILINE) |     re_PlayerInfo   = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$?(?P<CASH>[,.0-9]+)\)$', re.MULTILINE) | ||||||
|     re_Board        = re.compile(r"\[(?P<CARDS>.+)\]") |     re_Board        = re.compile(r"\[(?P<CARDS>.+)\]") | ||||||
|  | @ -60,20 +67,6 @@ class Fulltilt(HandHistoryConverter): | ||||||
| 
 | 
 | ||||||
|     mixes = { 'HORSE': 'horse', '7-Game': '7game', 'HOSE': 'hose', 'HA': 'ha'} |     mixes = { 'HORSE': 'horse', '7-Game': '7game', 'HOSE': 'hose', 'HA': 'ha'} | ||||||
| 
 | 
 | ||||||
|     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="Fulltilt", follow=follow, index=index) |  | ||||||
|         logging.info("Initialising Fulltilt converter class") |  | ||||||
|         self.filetype = "text" |  | ||||||
|         self.codepage = "cp1252" |  | ||||||
|         self.siteId   = 1 # Needs to match id entry in Sites database |  | ||||||
|         if autostart: |  | ||||||
|             self.start() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     def compilePlayerRegexs(self,  hand): |     def compilePlayerRegexs(self,  hand): | ||||||
|         players = set([player[1] for player in hand.players]) |         players = set([player[1] for player in hand.players]) | ||||||
|         if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' |         if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' | ||||||
|  | @ -118,7 +111,7 @@ follow :  whether to tail -f the input""" | ||||||
|         if not m:  |         if not m:  | ||||||
|             return None |             return None | ||||||
|         mg = m.groupdict() |         mg = m.groupdict() | ||||||
| 
 |         print mg | ||||||
|         # translations from captured groups to our info strings |         # translations from captured groups to our info strings | ||||||
|         limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' } |         limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' } | ||||||
|         games = {              # base, category |         games = {              # base, category | ||||||
|  | @ -140,7 +133,7 @@ follow :  whether to tail -f the input""" | ||||||
|         if mg['TOURNO'] == None:  info['type'] = "ring" |         if mg['TOURNO'] == None:  info['type'] = "ring" | ||||||
|         else:                     info['type'] = "tour" |         else:                     info['type'] = "tour" | ||||||
|         # NB: SB, BB must be interpreted as blinds or bets depending on limit type. |         # NB: SB, BB must be interpreted as blinds or bets depending on limit type. | ||||||
|         if info['type'] == "tour": return None # importer is screwed on tournies, pass on those hands so we don't interrupt other autoimporting | #        if info['type'] == "tour": return None # importer is screwed on tournies, pass on those hands so we don't interrupt other autoimporting | ||||||
|         return info |         return info | ||||||
| 
 | 
 | ||||||
|     #Following function is a hack, we should be dealing with this in readFile (i think correct codepage....) |     #Following function is a hack, we should be dealing with this in readFile (i think correct codepage....) | ||||||
|  | @ -158,11 +151,11 @@ follow :  whether to tail -f the input""" | ||||||
|         self.obs = self.obs.replace('\r\n', '\n') |         self.obs = self.obs.replace('\r\n', '\n') | ||||||
|         if self.obs == "" or self.obs == None: |         if self.obs == "" or self.obs == None: | ||||||
|             logging.info("Read no hands.") |             logging.info("Read no hands.") | ||||||
|             return |             return [] | ||||||
|         return re.split(self.re_SplitHands,  self.obs) |         return re.split(self.re_SplitHands,  self.obs) | ||||||
| 
 | 
 | ||||||
|     def readHandInfo(self, hand): |     def readHandInfo(self, hand): | ||||||
|         m =  self.re_HandInfo.search(hand.handText,re.DOTALL) |         m =  self.re_HandInfo.search(hand.handText) | ||||||
|         if(m == None): |         if(m == None): | ||||||
|             logging.info("Didn't match re_HandInfo") |             logging.info("Didn't match re_HandInfo") | ||||||
|             logging.info(hand.handText) |             logging.info(hand.handText) | ||||||
|  | @ -170,6 +163,10 @@ follow :  whether to tail -f the input""" | ||||||
|         hand.handid = m.group('HID') |         hand.handid = m.group('HID') | ||||||
|         hand.tablename = m.group('TABLE') |         hand.tablename = m.group('TABLE') | ||||||
|         hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%H:%M:%S ET - %Y/%m/%d") |         hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%H:%M:%S ET - %Y/%m/%d") | ||||||
|  | 
 | ||||||
|  |         if m.group("CANCELLED"): | ||||||
|  |             raise FpdbParseError(hid=m.group('HID')) | ||||||
|  | 
 | ||||||
|         if m.group('TABLEATTRIBUTES'): |         if m.group('TABLEATTRIBUTES'): | ||||||
|             m2 = self.re_Max.search(m.group('TABLEATTRIBUTES')) |             m2 = self.re_Max.search(m.group('TABLEATTRIBUTES')) | ||||||
|             if m2: hand.maxseats = int(m2.group('MAX')) |             if m2: hand.maxseats = int(m2.group('MAX')) | ||||||
|  | @ -369,7 +366,4 @@ if __name__ == "__main__": | ||||||
| 
 | 
 | ||||||
|     (options, args) = parser.parse_args() |     (options, args) = parser.parse_args() | ||||||
| 
 | 
 | ||||||
|     LOG_FILENAME = './logging.out' |  | ||||||
|     logging.basicConfig(filename=LOG_FILENAME,level=options.verbosity) |  | ||||||
| 
 |  | ||||||
|     e = Fulltilt(in_path = options.ipath, out_path = options.opath, follow = options.follow) |     e = Fulltilt(in_path = options.ipath, out_path = options.opath, follow = options.follow) | ||||||
|  |  | ||||||
|  | @ -252,10 +252,10 @@ | ||||||
| 
 | 
 | ||||||
| 	    <site enabled="False" | 	    <site enabled="False" | ||||||
| 	          site_name="PartyPoker" | 	          site_name="PartyPoker" | ||||||
| 	          table_finder="PartyPoker.exe" | 	          table_finder="PartyGaming.exe" | ||||||
| 	          screen_name="YOUR SCREEN NAME HERE" | 	          screen_name="YOUR SCREEN NAME HERE" | ||||||
| 	          site_path="" | 	          site_path="C:/Program Files/PartyGaming/PartyPoker" | ||||||
| 	          HH_path="" | 	          HH_path="C:/Program Files/PartyGaming/PartyPoker/HandHistory/YOUR SCREEN NAME HERE/" | ||||||
| 	          decoder="everleaf_decode_table" | 	          decoder="everleaf_decode_table" | ||||||
|               converter="PartyPokerToFpdb" |               converter="PartyPokerToFpdb" | ||||||
| 	          supported_games="holdem"> | 	          supported_games="holdem"> | ||||||
|  |  | ||||||
							
								
								
									
										134
									
								
								pyfpdb/Hand.py
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								pyfpdb/Hand.py
									
									
									
									
									
								
							|  | @ -32,6 +32,8 @@ import pprint | ||||||
| import DerivedStats | import DerivedStats | ||||||
| import Card | import Card | ||||||
| 
 | 
 | ||||||
|  | log = logging.getLogger("parser") | ||||||
|  | 
 | ||||||
| class Hand(object): | class Hand(object): | ||||||
| 
 | 
 | ||||||
| ###############################################################3 | ###############################################################3 | ||||||
|  | @ -162,7 +164,7 @@ shown   whether they were revealed at showdown | ||||||
| mucked  whether they were mucked at showdown | mucked  whether they were mucked at showdown | ||||||
| dealt   whether they were seen in a 'dealt to' line | dealt   whether they were seen in a 'dealt to' line | ||||||
| """ | """ | ||||||
| #        logging.debug("addHoleCards %s %s" % (open + closed, player)) | #        log.debug("addHoleCards %s %s" % (open + closed, player)) | ||||||
|         try: |         try: | ||||||
|             self.checkPlayerExists(player) |             self.checkPlayerExists(player) | ||||||
|         except FpdbParseError, e: |         except FpdbParseError, e: | ||||||
|  | @ -187,21 +189,7 @@ db: a connected fpdb_db object""" | ||||||
|         sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId) |         sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId) | ||||||
| 
 | 
 | ||||||
|         #Gametypes |         #Gametypes | ||||||
| 
 |         gtid = db.getGameTypeId(self.siteId, self.gametype) | ||||||
|         print "DEBUG: self.gametype %s" % self.gametype |  | ||||||
|         #Nice way to discover if the game is already listed in the db? |  | ||||||
|         #Also this is using an old method from fpdb_simple - should probably conform to the rest of the inserts |  | ||||||
| 
 |  | ||||||
|         hilo = "h" |  | ||||||
|         if self.gametype['category'] in ['studhilo', 'omahahilo']: |  | ||||||
|             hilo = "s" |  | ||||||
|         elif self.gametype['category'] in ['razz','27_3draw','badugi']: |  | ||||||
|             hilo = "l" |  | ||||||
|         #FIXME - the two zeros are small_bet and big_bet for limit |  | ||||||
|         gtid = db.insertGameTypes( (self.siteId, self.gametype['type'], self.gametype['base'],  |  | ||||||
|                                     self.gametype['category'], self.gametype['limitType'], hilo, |  | ||||||
|                                     self.gametype['sb'], self.gametype['bb'], 0, 0) ) |  | ||||||
|          |  | ||||||
| 
 | 
 | ||||||
|         # HudCache data to come from DerivedStats class |         # HudCache data to come from DerivedStats class | ||||||
|         # HandsActions - all actions for all players for all streets - self.actions |         # HandsActions - all actions for all players for all streets - self.actions | ||||||
|  | @ -210,14 +198,11 @@ db: a connected fpdb_db object""" | ||||||
|         hh = {} |         hh = {} | ||||||
|         hh['siteHandNo'] =  self.handid |         hh['siteHandNo'] =  self.handid | ||||||
|         hh['handStart'] = self.starttime |         hh['handStart'] = self.starttime | ||||||
|  |         hh['gameTypeId'] = gtid | ||||||
|         # seats TINYINT NOT NULL, |         # seats TINYINT NOT NULL, | ||||||
|         hh['tableName'] = self.tablename |         hh['tableName'] = self.tablename | ||||||
|         hh['maxSeats'] = self.maxseats |         hh['maxSeats'] = self.maxseats | ||||||
|              # boardcard1 smallint,  /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */ |         hh['seats'] = len(sqlids) | ||||||
|              # boardcard2 smallint, |  | ||||||
|              # boardcard3 smallint, |  | ||||||
|              # boardcard4 smallint, |  | ||||||
|              # boardcard5 smallint, |  | ||||||
|         # Flop turn and river may all be empty - add (likely) too many elements and trim with range |         # Flop turn and river may all be empty - add (likely) too many elements and trim with range | ||||||
|         boardcards = self.board['FLOP'] + self.board['TURN'] + self.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] |         boardcards = self.board['FLOP'] + self.board['TURN'] + self.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] | ||||||
|         cards = [Card.encodeCard(c) for c in boardcards[0:5]] |         cards = [Card.encodeCard(c) for c in boardcards[0:5]] | ||||||
|  | @ -227,7 +212,6 @@ db: a connected fpdb_db object""" | ||||||
|         hh['boardcard4'] = cards[3] |         hh['boardcard4'] = cards[3] | ||||||
|         hh['boardcard5'] = cards[4] |         hh['boardcard5'] = cards[4] | ||||||
| 
 | 
 | ||||||
|         print hh |  | ||||||
|              # texture smallint, |              # texture smallint, | ||||||
|              # playersVpi SMALLINT NOT NULL,         /* num of players vpi */ |              # playersVpi SMALLINT NOT NULL,         /* num of players vpi */ | ||||||
|                 # Needs to be recorded |                 # Needs to be recorded | ||||||
|  | @ -251,17 +235,14 @@ db: a connected fpdb_db object""" | ||||||
|                 # Needs to be recorded |                 # Needs to be recorded | ||||||
|              # street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */ |              # street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */ | ||||||
|                 # Needs to be recorded |                 # Needs to be recorded | ||||||
|              # street1Pot INT,                  /* pot size at flop/street4 */ | 
 | ||||||
|                 # Needs to be recorded |         #print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" %  self.getStreetTotals() | ||||||
|              # street2Pot INT,                  /* pot size at turn/street5 */ |         #FIXME: Pot size still in decimal, needs to be converted to cents | ||||||
|                 # Needs to be recorded |         (hh['street1Pot'], hh['street2Pot'], hh['street3Pot'], hh['street4Pot'], hh['showdownPot']) = self.getStreetTotals() | ||||||
|              # street3Pot INT,                  /* pot size at river/street6 */ | 
 | ||||||
|                 # Needs to be recorded |  | ||||||
|              # street4Pot INT,                  /* pot size at sd/street7 */ |  | ||||||
|                 # Needs to be recorded |  | ||||||
|              # showdownPot INT,                 /* pot size at sd/street7 */ |  | ||||||
|              # comment TEXT, |              # comment TEXT, | ||||||
|              # commentTs DATETIME |              # commentTs DATETIME | ||||||
|  |         #print hh | ||||||
|         handid = db.storeHand(hh) |         handid = db.storeHand(hh) | ||||||
|         # HandsPlayers - ? ... Do we fix winnings? |         # HandsPlayers - ? ... Do we fix winnings? | ||||||
|         # Tourneys ? |         # Tourneys ? | ||||||
|  | @ -282,7 +263,7 @@ seat    (int) indicating the seat | ||||||
| name    (string) player name | name    (string) player name | ||||||
| chips   (string) the chips the player has at the start of the hand (can be None) | chips   (string) the chips the player has at the start of the hand (can be None) | ||||||
| If a player has None chips he won't be added.""" | If a player has None chips he won't be added.""" | ||||||
|         logging.debug("addPlayer: %s %s (%s)" % (seat, name, chips)) |         log.debug("addPlayer: %s %s (%s)" % (seat, name, chips)) | ||||||
|         if chips is not None: |         if chips is not None: | ||||||
|             chips = re.sub(u',', u'', chips) #some sites have commas |             chips = re.sub(u',', u'', chips) #some sites have commas | ||||||
|             self.players.append([seat, name, chips]) |             self.players.append([seat, name, chips]) | ||||||
|  | @ -298,9 +279,9 @@ If a player has None chips he won't be added.""" | ||||||
|         # go through m and initialise actions to empty list for each street. |         # go through m and initialise actions to empty list for each street. | ||||||
|         if match: |         if match: | ||||||
|             self.streets.update(match.groupdict()) |             self.streets.update(match.groupdict()) | ||||||
|             logging.debug("markStreets:\n"+ str(self.streets)) |             log.debug("markStreets:\n"+ str(self.streets)) | ||||||
|         else: |         else: | ||||||
|             logging.error("markstreets didn't match") |             log.error("markstreets didn't match") | ||||||
| 
 | 
 | ||||||
|     def checkPlayerExists(self,player): |     def checkPlayerExists(self,player): | ||||||
|         if player not in [p[1] for p in self.players]: |         if player not in [p[1] for p in self.players]: | ||||||
|  | @ -310,7 +291,7 @@ If a player has None chips he won't be added.""" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def setCommunityCards(self, street, cards): |     def setCommunityCards(self, street, cards): | ||||||
|         logging.debug("setCommunityCards %s %s" %(street,  cards)) |         log.debug("setCommunityCards %s %s" %(street,  cards)) | ||||||
|         self.board[street] = [self.card(c) for c in cards] |         self.board[street] = [self.card(c) for c in cards] | ||||||
| #        print "DEBUG: self.board: %s" % self.board | #        print "DEBUG: self.board: %s" % self.board | ||||||
| 
 | 
 | ||||||
|  | @ -321,7 +302,7 @@ If a player has None chips he won't be added.""" | ||||||
|         return c |         return c | ||||||
| 
 | 
 | ||||||
|     def addAnte(self, player, ante): |     def addAnte(self, player, ante): | ||||||
|         logging.debug("%s %s antes %s" % ('ANTES', player, ante)) |         log.debug("%s %s antes %s" % ('ANTES', player, ante)) | ||||||
|         if player is not None: |         if player is not None: | ||||||
|             ante = re.sub(u',', u'', ante) #some sites have commas |             ante = re.sub(u',', u'', ante) #some sites have commas | ||||||
|             self.bets['ANTES'][player].append(Decimal(ante)) |             self.bets['ANTES'][player].append(Decimal(ante)) | ||||||
|  | @ -340,7 +321,7 @@ If a player has None chips he won't be added.""" | ||||||
|         #   - this is a call of 1 sb and a raise to 1 bb |         #   - this is a call of 1 sb and a raise to 1 bb | ||||||
|         # |         # | ||||||
| 
 | 
 | ||||||
|         logging.debug("addBlind: %s posts %s, %s" % (player, blindtype, amount)) |         log.debug("addBlind: %s posts %s, %s" % (player, blindtype, amount)) | ||||||
|         if player is not None: |         if player is not None: | ||||||
|             amount = re.sub(u',', u'', amount) #some sites have commas |             amount = re.sub(u',', u'', amount) #some sites have commas | ||||||
|             self.bets['PREFLOP'][player].append(Decimal(amount)) |             self.bets['PREFLOP'][player].append(Decimal(amount)) | ||||||
|  | @ -362,7 +343,7 @@ If a player has None chips he won't be added.""" | ||||||
|     def addCall(self, street, player=None, amount=None): |     def addCall(self, street, player=None, amount=None): | ||||||
|         if amount: |         if amount: | ||||||
|             amount = re.sub(u',', u'', amount) #some sites have commas |             amount = re.sub(u',', u'', amount) #some sites have commas | ||||||
|         logging.debug("%s %s calls %s" %(street, player, amount)) |         log.debug("%s %s calls %s" %(street, player, amount)) | ||||||
|         # Potentially calculate the amount of the call if not supplied |         # Potentially calculate the amount of the call if not supplied | ||||||
|         # corner cases include if player would be all in |         # corner cases include if player would be all in | ||||||
|         if amount is not None: |         if amount is not None: | ||||||
|  | @ -432,7 +413,7 @@ Add a raise on [street] by [player] to [amountTo] | ||||||
|         self._addRaise(street, player, C, Rb, Rt) |         self._addRaise(street, player, C, Rb, Rt) | ||||||
| 
 | 
 | ||||||
|     def _addRaise(self, street, player, C, Rb, Rt): |     def _addRaise(self, street, player, C, Rb, Rt): | ||||||
|         logging.debug("%s %s raise %s" %(street, player, Rt)) |         log.debug("%s %s raise %s" %(street, player, Rt)) | ||||||
|         self.bets[street][player].append(C + Rb) |         self.bets[street][player].append(C + Rb) | ||||||
|         self.stacks[player] -= (C + Rb) |         self.stacks[player] -= (C + Rb) | ||||||
|         act = (player, 'raises', Rb, Rt, C, self.stacks[player]==0) |         act = (player, 'raises', Rb, Rt, C, self.stacks[player]==0) | ||||||
|  | @ -443,7 +424,7 @@ Add a raise on [street] by [player] to [amountTo] | ||||||
|          |          | ||||||
|          |          | ||||||
|     def addBet(self, street, player, amount): |     def addBet(self, street, player, amount): | ||||||
|         logging.debug("%s %s bets %s" %(street, player, amount)) |         log.debug("%s %s bets %s" %(street, player, amount)) | ||||||
|         amount = re.sub(u',', u'', amount) #some sites have commas |         amount = re.sub(u',', u'', amount) #some sites have commas | ||||||
|         self.checkPlayerExists(player) |         self.checkPlayerExists(player) | ||||||
|         self.bets[street][player].append(Decimal(amount)) |         self.bets[street][player].append(Decimal(amount)) | ||||||
|  | @ -462,7 +443,7 @@ Add a raise on [street] by [player] to [amountTo] | ||||||
|          |          | ||||||
| 
 | 
 | ||||||
|     def addFold(self, street, player): |     def addFold(self, street, player): | ||||||
|         logging.debug("%s %s folds" % (street, player)) |         log.debug("%s %s folds" % (street, player)) | ||||||
|         self.checkPlayerExists(player) |         self.checkPlayerExists(player) | ||||||
|         self.folded.add(player) |         self.folded.add(player) | ||||||
|         self.pot.addFold(player) |         self.pot.addFold(player) | ||||||
|  | @ -477,7 +458,7 @@ Add a raise on [street] by [player] to [amountTo] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def addCollectPot(self,player, pot): |     def addCollectPot(self,player, pot): | ||||||
|         logging.debug("%s collected %s" % (player, pot)) |         log.debug("%s collected %s" % (player, pot)) | ||||||
|         self.checkPlayerExists(player) |         self.checkPlayerExists(player) | ||||||
|         self.collected = self.collected + [[player, pot]] |         self.collected = self.collected + [[player, pot]] | ||||||
|         if player not in self.collectees: |         if player not in self.collectees: | ||||||
|  | @ -491,7 +472,7 @@ Add a raise on [street] by [player] to [amountTo] | ||||||
| For when a player shows cards for any reason (for showdown or out of choice). | For when a player shows cards for any reason (for showdown or out of choice). | ||||||
| Card ranks will be uppercased | Card ranks will be uppercased | ||||||
| """ | """ | ||||||
|         logging.debug("addShownCards %s hole=%s all=%s" % (player, cards,  holeandboard)) |         log.debug("addShownCards %s hole=%s all=%s" % (player, cards,  holeandboard)) | ||||||
|         if cards is not None: |         if cards is not None: | ||||||
|             self.addHoleCards(cards,player,shown, mucked) |             self.addHoleCards(cards,player,shown, mucked) | ||||||
|         elif holeandboard is not None: |         elif holeandboard is not None: | ||||||
|  | @ -499,7 +480,6 @@ Card ranks will be uppercased | ||||||
|             board = set([c for s in self.board.values() for c in s]) |             board = set([c for s in self.board.values() for c in s]) | ||||||
|             self.addHoleCards(holeandboard.difference(board),player,shown, mucked) |             self.addHoleCards(holeandboard.difference(board),player,shown, mucked) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     def totalPot(self): |     def totalPot(self): | ||||||
|         """If all bets and blinds have been added, totals up the total pot size""" |         """If all bets and blinds have been added, totals up the total pot size""" | ||||||
|          |          | ||||||
|  | @ -541,7 +521,7 @@ Map the tuple self.gametype onto the pokerstars string describing it | ||||||
|               "cp"  : "Cap Pot Limit" |               "cp"  : "Cap Pot Limit" | ||||||
|              } |              } | ||||||
| 
 | 
 | ||||||
|         logging.debug("gametype: %s" %(self.gametype)) |         log.debug("gametype: %s" %(self.gametype)) | ||||||
|         retstring = "%s %s" %(gs[self.gametype['category']], ls[self.gametype['limitType']]) |         retstring = "%s %s" %(gs[self.gametype['category']], ls[self.gametype['limitType']]) | ||||||
|         return retstring |         return retstring | ||||||
| 
 | 
 | ||||||
|  | @ -583,6 +563,9 @@ Map the tuple self.gametype onto the pokerstars string describing it | ||||||
|         """Return a string of the stakes of the current hand.""" |         """Return a string of the stakes of the current hand.""" | ||||||
|         return "%s%s/%s%s" % (self.sym, self.sb, self.sym, self.bb) |         return "%s%s/%s%s" % (self.sym, self.sb, self.sym, self.bb) | ||||||
| 
 | 
 | ||||||
|  |     def getStreetTotals(self): | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|     def writeGameLine(self): |     def writeGameLine(self): | ||||||
|         """Return the first HH line for the current hand.""" |         """Return the first HH line for the current hand.""" | ||||||
|         gs = "PokerStars Game #%s: " % self.handid |         gs = "PokerStars Game #%s: " % self.handid | ||||||
|  | @ -620,7 +603,7 @@ class HoldemOmahaHand(Hand): | ||||||
|     def __init__(self, hhc, sitename, gametype, handText, builtFrom = "HHC", handid=None): |     def __init__(self, hhc, sitename, gametype, handText, builtFrom = "HHC", handid=None): | ||||||
|         if gametype['base'] != 'hold': |         if gametype['base'] != 'hold': | ||||||
|             pass # or indeed don't pass and complain instead |             pass # or indeed don't pass and complain instead | ||||||
|         logging.debug("HoldemOmahaHand") |         log.debug("HoldemOmahaHand") | ||||||
|         self.allStreets = ['BLINDSANTES', 'PREFLOP','FLOP','TURN','RIVER'] |         self.allStreets = ['BLINDSANTES', 'PREFLOP','FLOP','TURN','RIVER'] | ||||||
|         self.holeStreets = ['PREFLOP'] |         self.holeStreets = ['PREFLOP'] | ||||||
|         self.communityStreets = ['FLOP', 'TURN', 'RIVER'] |         self.communityStreets = ['FLOP', 'TURN', 'RIVER'] | ||||||
|  | @ -648,6 +631,7 @@ class HoldemOmahaHand(Hand): | ||||||
|             for street in self.actionStreets: |             for street in self.actionStreets: | ||||||
|                 if self.streets[street]: |                 if self.streets[street]: | ||||||
|                     hhc.readAction(self, street) |                     hhc.readAction(self, street) | ||||||
|  |                     self.pot.markTotal(street) | ||||||
|             hhc.readCollectPot(self) |             hhc.readCollectPot(self) | ||||||
|             hhc.readShownCards(self) |             hhc.readShownCards(self) | ||||||
|             self.totalPot() # finalise it (total the pot) |             self.totalPot() # finalise it (total the pot) | ||||||
|  | @ -659,9 +643,9 @@ class HoldemOmahaHand(Hand): | ||||||
|             if handid is not None: |             if handid is not None: | ||||||
|                 self.select(handid) # Will need a handId |                 self.select(handid) # Will need a handId | ||||||
|             else: |             else: | ||||||
|                 logging.warning("HoldemOmahaHand.__init__:Can't assemble hand from db without a handid") |                 log.warning("HoldemOmahaHand.__init__:Can't assemble hand from db without a handid") | ||||||
|         else: |         else: | ||||||
|             logging.warning("HoldemOmahaHand.__init__:Neither HHC nor DB+handid provided") |             log.warning("HoldemOmahaHand.__init__:Neither HHC nor DB+handid provided") | ||||||
|             pass |             pass | ||||||
|                  |                  | ||||||
| 
 | 
 | ||||||
|  | @ -672,6 +656,18 @@ class HoldemOmahaHand(Hand): | ||||||
|         else: |         else: | ||||||
|             self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt) |             self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt) | ||||||
| 
 | 
 | ||||||
|  |     def getStreetTotals(self): | ||||||
|  |         # street1Pot INT,                  /* pot size at flop/street4 */ | ||||||
|  |         # street2Pot INT,                  /* pot size at turn/street5 */ | ||||||
|  |         # street3Pot INT,                  /* pot size at river/street6 */ | ||||||
|  |         # street4Pot INT,                  /* pot size at sd/street7 */ | ||||||
|  |         # showdownPot INT,                 /* pot size at sd/street7 */ | ||||||
|  |         tmp1 = self.pot.getTotalAtStreet('FLOP') | ||||||
|  |         tmp2 = self.pot.getTotalAtStreet('TURN') | ||||||
|  |         tmp3 = self.pot.getTotalAtStreet('RIVER') | ||||||
|  |         tmp4 = 0 | ||||||
|  |         tmp5 = 0 | ||||||
|  |         return (tmp1,tmp2,tmp3,tmp4,tmp5) | ||||||
| 
 | 
 | ||||||
|     def writeHTMLHand(self, fh=sys.__stdout__): |     def writeHTMLHand(self, fh=sys.__stdout__): | ||||||
|         from nevow import tags as T |         from nevow import tags as T | ||||||
|  | @ -773,7 +769,7 @@ class HoldemOmahaHand(Hand): | ||||||
|         super(HoldemOmahaHand, self).writeHand(fh) |         super(HoldemOmahaHand, self).writeHand(fh) | ||||||
| 
 | 
 | ||||||
|         players_who_act_preflop = set(([x[0] for x in self.actions['PREFLOP']]+[x[0] for x in self.actions['BLINDSANTES']])) |         players_who_act_preflop = set(([x[0] for x in self.actions['PREFLOP']]+[x[0] for x in self.actions['BLINDSANTES']])) | ||||||
|         logging.debug(self.actions['PREFLOP']) |         log.debug(self.actions['PREFLOP']) | ||||||
|         for player in [x for x in self.players if x[1] in players_who_act_preflop]: |         for player in [x for x in self.players if x[1] in players_who_act_preflop]: | ||||||
|             #Only print stacks of players who do something preflop |             #Only print stacks of players who do something preflop | ||||||
|             print >>fh, ("Seat %s: %s ($%s in chips) " %(player[0], player[1], player[2])) |             print >>fh, ("Seat %s: %s ($%s in chips) " %(player[0], player[1], player[2])) | ||||||
|  | @ -896,6 +892,7 @@ class DrawHand(Hand): | ||||||
|             for street in self.streetList: |             for street in self.streetList: | ||||||
|                 if self.streets[street]: |                 if self.streets[street]: | ||||||
|                     hhc.readAction(self, street) |                     hhc.readAction(self, street) | ||||||
|  |                     self.pot.markTotal(street) | ||||||
|             hhc.readCollectPot(self) |             hhc.readCollectPot(self) | ||||||
|             hhc.readShownCards(self) |             hhc.readShownCards(self) | ||||||
|             self.totalPot() # finalise it (total the pot) |             self.totalPot() # finalise it (total the pot) | ||||||
|  | @ -916,7 +913,7 @@ class DrawHand(Hand): | ||||||
|         #   - this is a call of 1 sb and a raise to 1 bb |         #   - this is a call of 1 sb and a raise to 1 bb | ||||||
|         #  |         #  | ||||||
|          |          | ||||||
|         logging.debug("addBlind: %s posts %s, %s" % (player, blindtype, amount)) |         log.debug("addBlind: %s posts %s, %s" % (player, blindtype, amount)) | ||||||
|         if player is not None: |         if player is not None: | ||||||
|             self.bets['DEAL'][player].append(Decimal(amount)) |             self.bets['DEAL'][player].append(Decimal(amount)) | ||||||
|             self.stacks[player] -= Decimal(amount) |             self.stacks[player] -= Decimal(amount) | ||||||
|  | @ -943,7 +940,7 @@ class DrawHand(Hand): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def discardDrawHoleCards(self, cards, player, street): |     def discardDrawHoleCards(self, cards, player, street): | ||||||
|         logging.debug("discardDrawHoleCards '%s' '%s' '%s'" % (cards, player, street)) |         log.debug("discardDrawHoleCards '%s' '%s' '%s'" % (cards, player, street)) | ||||||
|         self.discards[street][player] = set([cards]) |         self.discards[street][player] = set([cards]) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -956,6 +953,14 @@ class DrawHand(Hand): | ||||||
|             act = (player, 'discards', num) |             act = (player, 'discards', num) | ||||||
|         self.actions[street].append(act) |         self.actions[street].append(act) | ||||||
| 
 | 
 | ||||||
|  |     def getStreetTotals(self): | ||||||
|  |         # street1Pot INT,                  /* pot size at flop/street4 */ | ||||||
|  |         # street2Pot INT,                  /* pot size at turn/street5 */ | ||||||
|  |         # street3Pot INT,                  /* pot size at river/street6 */ | ||||||
|  |         # street4Pot INT,                  /* pot size at sd/street7 */ | ||||||
|  |         # showdownPot INT,                 /* pot size at sd/street7 */ | ||||||
|  |         return (0,0,0,0,0) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     def writeHand(self, fh=sys.__stdout__): |     def writeHand(self, fh=sys.__stdout__): | ||||||
|         # PokerStars format. |         # PokerStars format. | ||||||
|  | @ -1061,9 +1066,9 @@ class StudHand(Hand): | ||||||
|             for street in self.actionStreets: |             for street in self.actionStreets: | ||||||
|                 if street == 'ANTES': continue # OMG--sometime someone folds in the ante round |                 if street == 'ANTES': continue # OMG--sometime someone folds in the ante round | ||||||
|                 if self.streets[street]: |                 if self.streets[street]: | ||||||
|                     logging.debug(street) |                     log.debug(street + self.streets[street]) | ||||||
|                     logging.debug(self.streets[street]) |  | ||||||
|                     hhc.readAction(self, street) |                     hhc.readAction(self, street) | ||||||
|  |                     self.pot.markTotal(street) | ||||||
|             hhc.readCollectPot(self) |             hhc.readCollectPot(self) | ||||||
|             hhc.readShownCards(self) # not done yet |             hhc.readShownCards(self) # not done yet | ||||||
|             self.totalPot() # finalise it (total the pot) |             self.totalPot() # finalise it (total the pot) | ||||||
|  | @ -1094,7 +1099,7 @@ street  (string) the street name (in streetList) | ||||||
| open  list of card bigrams e.g. ['2h','Jc'], dealt face up | open  list of card bigrams e.g. ['2h','Jc'], dealt face up | ||||||
| closed    likewise, but known only to player | closed    likewise, but known only to player | ||||||
| """ | """ | ||||||
|         logging.debug("addPlayerCards %s, o%s x%s" % (player,  open, closed)) |         log.debug("addPlayerCards %s, o%s x%s" % (player,  open, closed)) | ||||||
|         try: |         try: | ||||||
|             self.checkPlayerExists(player) |             self.checkPlayerExists(player) | ||||||
|             self.holecards[street][player] = (open, closed) |             self.holecards[street][player] = (open, closed) | ||||||
|  | @ -1108,7 +1113,7 @@ closed    likewise, but known only to player | ||||||
|         """\ |         """\ | ||||||
| Add a complete on [street] by [player] to [amountTo] | Add a complete on [street] by [player] to [amountTo] | ||||||
| """ | """ | ||||||
|         logging.debug("%s %s completes %s" % (street, player, amountTo)) |         log.debug("%s %s completes %s" % (street, player, amountTo)) | ||||||
|         amountTo = re.sub(u',', u'', amountTo) #some sites have commas |         amountTo = re.sub(u',', u'', amountTo) #some sites have commas | ||||||
|         self.checkPlayerExists(player) |         self.checkPlayerExists(player) | ||||||
|         Bp = self.lastBet['THIRD'] |         Bp = self.lastBet['THIRD'] | ||||||
|  | @ -1126,7 +1131,7 @@ Add a complete on [street] by [player] to [amountTo] | ||||||
|          |          | ||||||
|     def addBringIn(self, player, bringin): |     def addBringIn(self, player, bringin): | ||||||
|         if player is not None: |         if player is not None: | ||||||
|             logging.debug("Bringin: %s, %s" % (player , bringin)) |             log.debug("Bringin: %s, %s" % (player , bringin)) | ||||||
|             self.bets['THIRD'][player].append(Decimal(bringin)) |             self.bets['THIRD'][player].append(Decimal(bringin)) | ||||||
|             self.stacks[player] -= Decimal(bringin) |             self.stacks[player] -= Decimal(bringin) | ||||||
|             act = (player, 'bringin', bringin, self.stacks[player]==0) |             act = (player, 'bringin', bringin, self.stacks[player]==0) | ||||||
|  | @ -1134,6 +1139,14 @@ Add a complete on [street] by [player] to [amountTo] | ||||||
|             self.lastBet['THIRD'] = Decimal(bringin) |             self.lastBet['THIRD'] = Decimal(bringin) | ||||||
|             self.pot.addMoney(player, Decimal(bringin)) |             self.pot.addMoney(player, Decimal(bringin)) | ||||||
| 
 | 
 | ||||||
|  |     def getStreetTotals(self): | ||||||
|  |         # street1Pot INT,                  /* pot size at flop/street4 */ | ||||||
|  |         # street2Pot INT,                  /* pot size at turn/street5 */ | ||||||
|  |         # street3Pot INT,                  /* pot size at river/street6 */ | ||||||
|  |         # street4Pot INT,                  /* pot size at sd/street7 */ | ||||||
|  |         # showdownPot INT,                 /* pot size at sd/street7 */ | ||||||
|  |         return (0,0,0,0,0) | ||||||
|  | 
 | ||||||
|      |      | ||||||
|     def writeHand(self, fh=sys.__stdout__): |     def writeHand(self, fh=sys.__stdout__): | ||||||
|         # PokerStars format. |         # PokerStars format. | ||||||
|  | @ -1294,6 +1307,7 @@ class Pot(object): | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.contenders   = set() |         self.contenders   = set() | ||||||
|         self.committed    = {} |         self.committed    = {} | ||||||
|  |         self.streettotals = {} | ||||||
|         self.total        = None |         self.total        = None | ||||||
|         self.returned     = {} |         self.returned     = {} | ||||||
|         self.sym          = u'$' # this is the default currency symbol |         self.sym          = u'$' # this is the default currency symbol | ||||||
|  | @ -1313,6 +1327,14 @@ class Pot(object): | ||||||
|         self.contenders.add(player) |         self.contenders.add(player) | ||||||
|         self.committed[player] += amount |         self.committed[player] += amount | ||||||
| 
 | 
 | ||||||
|  |     def markTotal(self, street): | ||||||
|  |         self.streettotals[street] = sum(self.committed.values()) | ||||||
|  | 
 | ||||||
|  |     def getTotalAtStreet(self, street): | ||||||
|  |         if street in self.streettotals: | ||||||
|  |             return self.streettotals[street] | ||||||
|  |         return 0 | ||||||
|  | 
 | ||||||
|     def end(self): |     def end(self): | ||||||
|         self.total = sum(self.committed.values()) |         self.total = sum(self.committed.values()) | ||||||
|          |          | ||||||
|  |  | ||||||
|  | @ -20,7 +20,6 @@ import Hand | ||||||
| import re | import re | ||||||
| import sys | import sys | ||||||
| import traceback | import traceback | ||||||
| import logging |  | ||||||
| from optparse import OptionParser | from optparse import OptionParser | ||||||
| import os | import os | ||||||
| import os.path | import os.path | ||||||
|  | @ -31,19 +30,37 @@ import operator | ||||||
| from xml.dom.minidom import Node | from xml.dom.minidom import Node | ||||||
| import time | import time | ||||||
| import datetime | import datetime | ||||||
|  | from Exceptions import FpdbParseError | ||||||
| 
 | 
 | ||||||
| import gettext | import gettext | ||||||
| gettext.install('fpdb') | gettext.install('fpdb') | ||||||
| 
 | 
 | ||||||
|  | import logging, logging.config | ||||||
|  | logging.config.fileConfig("logging.conf") | ||||||
|  | log = logging.getLogger("parser") | ||||||
|  | 
 | ||||||
| class HandHistoryConverter(): | class HandHistoryConverter(): | ||||||
| 
 | 
 | ||||||
|     READ_CHUNK_SIZE = 10000 # bytes to read at a time from file (in tail mode) |     READ_CHUNK_SIZE = 10000 # bytes to read at a time from file in tail mode | ||||||
|     def __init__(self, in_path = '-', out_path = '-', sitename = None, follow=False, index=0): | 
 | ||||||
|         logging.info("HandHistory init") |     # filetype can be "text" or "xml" | ||||||
|  |     # so far always "text" | ||||||
|  |     # subclass HHC_xml for xml parsing | ||||||
|  |     filetype = "text" | ||||||
|  | 
 | ||||||
|  |     # codepage indicates the encoding of the text file. | ||||||
|  |     # cp1252 is a safe default | ||||||
|  |     # "utf_8" is more likely if there are funny characters | ||||||
|  |     codepage = "cp1252" | ||||||
|  | 
 | ||||||
|  |     def __init__(self, in_path = '-', out_path = '-', follow=False, index=0, autostart=True): | ||||||
|  |         """\ | ||||||
|  | in_path   (default '-' = sys.stdin) | ||||||
|  | out_path  (default '-' = sys.stdout) | ||||||
|  | follow :  whether to tail -f the input""" | ||||||
|  | 
 | ||||||
|  |         log.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) ) | ||||||
|          |          | ||||||
|         # default filetype and codepage. Subclasses should set these properly. |  | ||||||
|         self.filetype  = "text" |  | ||||||
|         self.codepage  = "utf8" |  | ||||||
|         self.index     = 0 |         self.index     = 0 | ||||||
| 
 | 
 | ||||||
|         self.in_path = in_path |         self.in_path = in_path | ||||||
|  | @ -60,52 +77,70 @@ class HandHistoryConverter(): | ||||||
|             # TODO: out_path should be sanity checked. |             # TODO: out_path should be sanity checked. | ||||||
|             out_dir = os.path.dirname(self.out_path) |             out_dir = os.path.dirname(self.out_path) | ||||||
|             if not os.path.isdir(out_dir) and out_dir != '': |             if not os.path.isdir(out_dir) and out_dir != '': | ||||||
|                 logging.info("Creatin directory '%s'" % out_dir) |                 log.info("Creating directory '%s'" % out_dir) | ||||||
|                 os.makedirs(out_dir) |                 os.makedirs(out_dir) | ||||||
|  |             try: | ||||||
|                 self.out_fh = codecs.open(self.out_path, 'w', 'cp1252') |                 self.out_fh = codecs.open(self.out_path, 'w', 'cp1252') | ||||||
|  |                 log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh)) | ||||||
|  |             except: | ||||||
|  |                 log.error("out_path %s couldn't be opened" % (self.out_path)) | ||||||
| 
 | 
 | ||||||
|         self.sitename  = sitename |  | ||||||
|         self.follow = follow |         self.follow = follow | ||||||
|         self.compiledPlayers   = set() |         self.compiledPlayers   = set() | ||||||
|         self.maxseats  = 10 |         self.maxseats  = 10 | ||||||
| 
 | 
 | ||||||
|  |         if autostart: | ||||||
|  |             self.start() | ||||||
|  | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return """ |         return """ | ||||||
| HandHistoryConverter: '%(sitename)s' | HandHistoryConverter: '%(sitename)s' | ||||||
|     filetype:   '%(filetype)s' |     filetype    '%(filetype)s' | ||||||
|     in_path:    '%(in_path)s' |     in_path     '%(in_path)s' | ||||||
|     out_path:   '%(out_path)s' |     out_path    '%(out_path)s' | ||||||
|     """ % { 'sitename':self.sitename, 'filetype':self.filetype, 'in_path':self.in_path, 'out_path':self.out_path } |     follow      '%(follow)s' | ||||||
|  |     """ %  locals()  | ||||||
| 
 | 
 | ||||||
|     def start(self): |     def start(self): | ||||||
|         """process a hand at a time from the input specified by in_path. |         """Process a hand at a time from the input specified by in_path. | ||||||
| If in follow mode, wait for more data to turn up. | If in follow mode, wait for more data to turn up. | ||||||
| Otherwise, finish at eof. | Otherwise, finish at EOF. | ||||||
| 
 | 
 | ||||||
| """ | """ | ||||||
|         starttime = time.time() |         starttime = time.time() | ||||||
|         if not self.sanityCheck(): |         if not self.sanityCheck(): | ||||||
|             print "Cowardly refusing to continue after failed sanity check" |             log.warning("Failed sanity check") | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         if self.follow: |         try: | ||||||
|             numHands = 0 |             numHands = 0 | ||||||
|  |             numErrors = 0 | ||||||
|  |             if self.follow: | ||||||
|  |                 log.info("Tailing '%s'" % self.in_path) | ||||||
|                 for handText in self.tailHands(): |                 for handText in self.tailHands(): | ||||||
|                 numHands+=1 |                     try: | ||||||
|                         self.processHand(handText) |                         self.processHand(handText) | ||||||
|  |                         numHands+=1 | ||||||
|  |                     except FpdbParseError, e: | ||||||
|  |                         numErrors+=1 | ||||||
|  |                         log.warning("Failed to convert hand %s" % e.hid) | ||||||
|  |                         log.debug(handText) | ||||||
|             else: |             else: | ||||||
|                 handsList = self.allHandsAsList() |                 handsList = self.allHandsAsList() | ||||||
|             logging.info("Parsing %d hands" % len(handsList)) |                 log.info("Parsing %d hands" % len(handsList)) | ||||||
|             nBadHangs = 0 |  | ||||||
|                 for handText in handsList: |                 for handText in handsList: | ||||||
|                     try: |                     try: | ||||||
|                         self.processedHands.append(self.processHand(handText)) |                         self.processedHands.append(self.processHand(handText)) | ||||||
|                 except Exception, e: # TODO: it's better to replace it with s-t like HhcEception |                     except FpdbParseError, e: | ||||||
|                     nBadHangs += 1 |                         numErrors+=1 | ||||||
|                     logging.error("Caught exception while parsing hand: %s" % str(e)) |                         log.warning("Failed to convert hand %s" % e.hid) | ||||||
|             numHands =  len(handsList) - nBadHangs |                         log.debug(handText) | ||||||
|  |                 numHands = len(handsList) | ||||||
|             endtime = time.time() |             endtime = time.time() | ||||||
|         print "read %d hands in %.3f seconds" % (numHands, endtime - starttime) |             log.info("Read %d hands (%d failed) in %.3f seconds" % (numHands, numErrors, endtime - starttime)) | ||||||
|  |         except IOError, ioe: | ||||||
|  |             log.exception("Error converting '%s'" % self.in_path) | ||||||
|  |         finally: | ||||||
|             if self.out_fh != sys.stdout: |             if self.out_fh != sys.stdout: | ||||||
|                 self.out_fh.close() |                 self.out_fh.close() | ||||||
| 
 | 
 | ||||||
|  | @ -134,7 +169,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py. | ||||||
|                     time.sleep(interval) |                     time.sleep(interval) | ||||||
|                     fd.seek(where) |                     fd.seek(where) | ||||||
|                 else: |                 else: | ||||||
|                     logging.debug("%s changed inode numbers from %d to %d" % (self.in_path, fd_results[1], st_results[1])) |                     log.debug("%s changed inode numbers from %d to %d" % (self.in_path, fd_results[1], st_results[1])) | ||||||
|                     fd = codecs.open(self.in_path, 'r', self.codepage) |                     fd = codecs.open(self.in_path, 'r', self.codepage) | ||||||
|                     fd.seek(where) |                     fd.seek(where) | ||||||
|             else: |             else: | ||||||
|  | @ -179,13 +214,13 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py. | ||||||
|         self.obs = self.obs.strip() |         self.obs = self.obs.strip() | ||||||
|         self.obs = self.obs.replace('\r\n', '\n') |         self.obs = self.obs.replace('\r\n', '\n') | ||||||
|         if self.obs == "" or self.obs == None: |         if self.obs == "" or self.obs == None: | ||||||
|             logging.info("Read no hands.") |             log.info("Read no hands.") | ||||||
|             return |             return [] | ||||||
|         return re.split(self.re_SplitHands,  self.obs) |         return re.split(self.re_SplitHands,  self.obs) | ||||||
|          |          | ||||||
|     def processHand(self, handText): |     def processHand(self, handText): | ||||||
|         gametype = self.determineGameType(handText) |         gametype = self.determineGameType(handText) | ||||||
|         logging.debug("gametype %s" % gametype) |         log.debug("gametype %s" % gametype) | ||||||
|         hand = None |         hand = None | ||||||
|         if gametype is None:  |         if gametype is None:  | ||||||
|             l = None |             l = None | ||||||
|  | @ -200,14 +235,14 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py. | ||||||
|             l = [type] + [base] + [limit] |             l = [type] + [base] + [limit] | ||||||
|         if l in self.readSupportedGames(): |         if l in self.readSupportedGames(): | ||||||
|             if gametype['base'] == 'hold': |             if gametype['base'] == 'hold': | ||||||
|                 logging.debug("hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handtext)") |                 log.debug("hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handtext)") | ||||||
|                 hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handText) |                 hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handText) | ||||||
|             elif gametype['base'] == 'stud': |             elif gametype['base'] == 'stud': | ||||||
|                 hand = Hand.StudHand(self, self.sitename, gametype, handText) |                 hand = Hand.StudHand(self, self.sitename, gametype, handText) | ||||||
|             elif gametype['base'] == 'draw': |             elif gametype['base'] == 'draw': | ||||||
|                 hand = Hand.DrawHand(self, self.sitename, gametype, handText) |                 hand = Hand.DrawHand(self, self.sitename, gametype, handText) | ||||||
|         else: |         else: | ||||||
|             logging.info("Unsupported game type: %s" % gametype) |             log.info("Unsupported game type: %s" % gametype) | ||||||
| 
 | 
 | ||||||
|         if hand: |         if hand: | ||||||
| #    uncomment these to calculate some stats | #    uncomment these to calculate some stats | ||||||
|  | @ -216,7 +251,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py. | ||||||
|             hand.writeHand(self.out_fh) |             hand.writeHand(self.out_fh) | ||||||
|             return hand |             return hand | ||||||
|         else: |         else: | ||||||
|             logging.info("Unsupported game type: %s" % gametype) |             log.info("Unsupported game type: %s" % gametype) | ||||||
|             # TODO: pity we don't know the HID at this stage. Log the entire hand? |             # TODO: pity we don't know the HID at this stage. Log the entire hand? | ||||||
|             # From the log we can deduce that it is the hand after the one before :) |             # From the log we can deduce that it is the hand after the one before :) | ||||||
| 
 | 
 | ||||||
|  | @ -342,26 +377,23 @@ or None if we fail to get the info """ | ||||||
|         return hands |         return hands | ||||||
| 
 | 
 | ||||||
|     def readFile(self): |     def readFile(self): | ||||||
|         """open in_path according to self.codepage""" |         """Open in_path according to self.codepage. Exceptions caught further up""" | ||||||
|          |          | ||||||
|         if(self.filetype == "text"): |         if(self.filetype == "text"): | ||||||
|             if self.in_path == '-': |             if self.in_path == '-': | ||||||
|                 # read from stdin |                 # read from stdin | ||||||
|                 logging.debug("Reading stdin with %s" % self.codepage) # is this necessary? or possible? or what? |                 log.debug("Reading stdin with %s" % self.codepage) # is this necessary? or possible? or what? | ||||||
|                 in_fh = codecs.getreader('cp1252')(sys.stdin) |                 in_fh = codecs.getreader('cp1252')(sys.stdin) | ||||||
|             else: |             else: | ||||||
|                 logging.debug("Opening %s with %s" % (self.in_path, self.codepage)) |  | ||||||
|                 in_fh = codecs.open(self.in_path, 'r', self.codepage) |                 in_fh = codecs.open(self.in_path, 'r', self.codepage) | ||||||
|                 in_fh.seek(self.index) |                 in_fh.seek(self.index) | ||||||
|  |                 log.debug("Opened in_path: '%s' with %s" % (self.in_path, self.codepage)) | ||||||
|                 self.obs = in_fh.read() |                 self.obs = in_fh.read() | ||||||
|                 self.index = in_fh.tell() |                 self.index = in_fh.tell() | ||||||
|                 in_fh.close() |                 in_fh.close() | ||||||
|         elif(self.filetype == "xml"): |         elif(self.filetype == "xml"): | ||||||
|             try: |  | ||||||
|             doc = xml.dom.minidom.parse(filename) |             doc = xml.dom.minidom.parse(filename) | ||||||
|             self.doc = doc |             self.doc = doc | ||||||
|             except: |  | ||||||
|                 traceback.print_exc(file=sys.stderr) |  | ||||||
| 
 | 
 | ||||||
|     def guessMaxSeats(self, hand): |     def guessMaxSeats(self, hand): | ||||||
|         """Return a guess at max_seats when not specified in HH.""" |         """Return a guess at max_seats when not specified in HH.""" | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| #!/usr/bin/env python | #!/usr/bin/env python | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
| """Hud.py | """Hud.py | ||||||
| 
 | 
 | ||||||
| Create and manage the hud overlays. | Create and manage the hud overlays. | ||||||
|  | @ -96,6 +97,8 @@ class Hud: | ||||||
|                     continue |                     continue | ||||||
|                 self.aux_windows.append(my_import(self, config, aux_params)) |                 self.aux_windows.append(my_import(self, config, aux_params)) | ||||||
|          |          | ||||||
|  |         self.creation_attrs = None | ||||||
|  | 
 | ||||||
|     def create_mw(self): |     def create_mw(self): | ||||||
| 
 | 
 | ||||||
| #	Set up a main window for this this instance of the HUD | #	Set up a main window for this this instance of the HUD | ||||||
|  | @ -146,6 +149,21 @@ class Hud: | ||||||
|         self.item4.connect("activate", self.debug_stat_windows) |         self.item4.connect("activate", self.debug_stat_windows) | ||||||
|         self.item4.show() |         self.item4.show() | ||||||
|          |          | ||||||
|  |         self.item5 = gtk.MenuItem('Set max seats') | ||||||
|  |         self.menu.append(self.item5) | ||||||
|  |         self.item5.show() | ||||||
|  |         self.maxSeatsMenu = gtk.Menu() | ||||||
|  |         self.item5.set_submenu(self.maxSeatsMenu) | ||||||
|  |         for i in range(2, 11, 1): | ||||||
|  |             item = gtk.MenuItem('%d-max' % i) | ||||||
|  |             item.ms = i | ||||||
|  |             self.maxSeatsMenu.append(item) | ||||||
|  |             item.connect("activate", self.change_max_seats) | ||||||
|  |             item.show() | ||||||
|  |             setattr(self, 'maxSeatsMenuItem%d' % (i-1), item)  | ||||||
|  |          | ||||||
|  |              | ||||||
|  |          | ||||||
|         self.ebox.connect_object("button-press-event", self.on_button_press, self.menu) |         self.ebox.connect_object("button-press-event", self.on_button_press, self.menu) | ||||||
| 
 | 
 | ||||||
|         self.main_window.show_all() |         self.main_window.show_all() | ||||||
|  | @ -163,6 +181,18 @@ class Hud: | ||||||
|              |              | ||||||
|         self.update_table_position() |         self.update_table_position() | ||||||
|             |             | ||||||
|  |     def change_max_seats(self, widget): | ||||||
|  |         if self.max != widget.ms: | ||||||
|  |             print 'change_max_seats', widget.ms | ||||||
|  |             self.max = widget.ms | ||||||
|  |             try: | ||||||
|  |                 self.kill() | ||||||
|  |                 self.create(*self.creation_attrs) | ||||||
|  |                 self.update(self.hand, self.config) | ||||||
|  |             except Exception, e: | ||||||
|  |                 print "Expcetion:",str(e) | ||||||
|  |                 pass | ||||||
|  |          | ||||||
|     def update_table_position(self): |     def update_table_position(self): | ||||||
|         if os.name == 'nt': |         if os.name == 'nt': | ||||||
|             if not win32gui.IsWindow(self.table.number): |             if not win32gui.IsWindow(self.table.number): | ||||||
|  | @ -270,6 +300,8 @@ class Hud: | ||||||
| # | # | ||||||
| #    this method also manages the creating and destruction of stat | #    this method also manages the creating and destruction of stat | ||||||
| #    windows via calls to the Stat_Window class | #    windows via calls to the Stat_Window class | ||||||
|  |         self.creation_attrs = hand, config, stat_dict, cards  | ||||||
|  | 
 | ||||||
|         self.hand = hand   |         self.hand = hand   | ||||||
|         if not self.mw_created: |         if not self.mw_created: | ||||||
|             self.create_mw() |             self.create_mw() | ||||||
|  |  | ||||||
							
								
								
									
										257
									
								
								pyfpdb/PartyPokerToFpdb.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										257
									
								
								pyfpdb/PartyPokerToFpdb.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							|  | @ -21,43 +21,48 @@ | ||||||
| import sys | import sys | ||||||
| from collections import defaultdict | from collections import defaultdict | ||||||
| 
 | 
 | ||||||
|  | from Exceptions import FpdbParseError | ||||||
| from HandHistoryConverter import * | from HandHistoryConverter import * | ||||||
| 
 | 
 | ||||||
| # PartyPoker HH Format | # PartyPoker HH Format | ||||||
| 
 | 
 | ||||||
| class PartyPoker(HandHistoryConverter): | class PartyPokerParseError(FpdbParseError): | ||||||
|     class ParsingException(Exception): |     "Usage: raise PartyPokerParseError(<msg>[, hh=<hh>][, hid=<hid>])" | ||||||
|         "Usage: raise ParsingException(<msg>[, hh=<hh>])" |     def __init__(self, msg='', hh=None, hid=None): | ||||||
|         def __init__(self, *args, **kwargs): |         if hh is not None: | ||||||
|             if len(args)==0: args=[''] + list(args) |             msg += "\n\nHand history attached below:\n" + self.wrapHh(hh) | ||||||
|             msg, args = args[0], args[1:] |         return super(PartyPokerParseError, self).__init__(hid=hid) | ||||||
|             if 'hh' in kwargs: |         #return super(PartyPokerParseError, self).__init__(msg, hid=hid) | ||||||
|                 msg += self.wrapHh(kwargs['hh']) |  | ||||||
|                 del kwargs['hh'] |  | ||||||
|             return Exception.__init__(self, msg, *args, **kwargs) |  | ||||||
|     def wrapHh(self, hh): |     def wrapHh(self, hh): | ||||||
|             return ("\n\nHand history attached below:\n" |         return ("%(DELIMETER)s\n%(HH)s\n%(DELIMETER)s") % \ | ||||||
|                     "%(DELIMETER)s\n%(HH)s\n%(DELIMETER)s") % \ |  | ||||||
|                 {'DELIMETER': '#'*50, 'HH': hh} |                 {'DELIMETER': '#'*50, 'HH': hh} | ||||||
| 
 | 
 | ||||||
|  | class PartyPoker(HandHistoryConverter): | ||||||
|  | 
 | ||||||
| ############################################################ | ############################################################ | ||||||
| #    Class Variables | #    Class Variables | ||||||
| 
 | 
 | ||||||
|  |     sitename = "PartyPoker" | ||||||
|  |     codepage = "cp1252" | ||||||
|  |     siteId = 9 # TODO: automate; it's a class variable so shouldn't hit DB too often | ||||||
|  |     filetype = "text" # "text" or "xml". I propose we subclass HHC to HHC_Text and HHC_XML. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     sym = {'USD': "\$", } |     sym = {'USD': "\$", } | ||||||
| 
 | 
 | ||||||
|     # Static regexes |     # Static regexes | ||||||
|     # $5 USD NL Texas Hold'em - Saturday, July 25, 07:53:52 EDT 2009 |     # $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 |     # 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(""" |     re_GameInfoRing     = re.compile(""" | ||||||
|             (?P<CURRENCY>\$|)\s*(?P<RINGLIMIT>\d+)\s*(?:USD)?\s* |             (?P<CURRENCY>\$|)\s*(?P<RINGLIMIT>[0-9,]+)\s*(?:USD)?\s* | ||||||
|             (?P<LIMIT>(NL))\s+ |             (?P<LIMIT>(NL|PL|))\s+ | ||||||
|             (?P<GAME>(Texas\ Hold\'em)) |             (?P<GAME>(Texas\ Hold\'em|Omaha)) | ||||||
|             \s*\-\s* |             \s*\-\s* | ||||||
|             (?P<DATETIME>.+) |             (?P<DATETIME>.+) | ||||||
|             """, re.VERBOSE) |             """, re.VERBOSE) | ||||||
|     re_GameInfoTrny     = re.compile(""" |     re_GameInfoTrny     = re.compile(""" | ||||||
|             (?P<LIMIT>(NL))\s+ |             (?P<LIMIT>(NL|PL|))\s+ | ||||||
|             (?P<GAME>(Texas\ Hold\'em))\s+ |             (?P<GAME>(Texas\ Hold\'em|Omaha))\s+ | ||||||
|             (?P<BUYIN>\$?[.0-9]+)\s*(?P<BUYIN_CURRENCY>USD)?\s*Buy-in\s+ |             (?P<BUYIN>\$?[.0-9]+)\s*(?P<BUYIN_CURRENCY>USD)?\s*Buy-in\s+ | ||||||
|             Trny:\s?(?P<TOURNO>\d+)\s+ |             Trny:\s?(?P<TOURNO>\d+)\s+ | ||||||
|             Level:\s*(?P<LEVEL>\d+)\s+ |             Level:\s*(?P<LEVEL>\d+)\s+ | ||||||
|  | @ -88,52 +93,58 @@ class PartyPoker(HandHistoryConverter): | ||||||
|             """, |             """, | ||||||
|           re.MULTILINE|re.VERBOSE) |           re.MULTILINE|re.VERBOSE) | ||||||
| 
 | 
 | ||||||
|  |     re_TotalPlayers = re.compile("^Total\s+number\s+of\s+players\s*:\s*(?P<MAXSEATS>\d+)", re.MULTILINE) | ||||||
|     re_SplitHands   = re.compile('\x00+') |     re_SplitHands   = re.compile('\x00+') | ||||||
|     re_TailSplitHands   = re.compile('(\x00+)') |     re_TailSplitHands   = re.compile('(\x00+)') | ||||||
|     lineSplitter    = '\n' |     lineSplitter    = '\n' | ||||||
|     re_Button       = re.compile('Seat (?P<BUTTON>\d+) is the button', re.MULTILINE) |     re_Button       = re.compile('Seat (?P<BUTTON>\d+) is the button', re.MULTILINE) | ||||||
|     re_Board        = re.compile(r"\[(?P<CARDS>.+)\]") |     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') |     re_NoSmallBlind = re.compile( | ||||||
|  |                     '^There is no Small Blind in this hand as the Big Blind ' | ||||||
|  |                     'of the previous hand left the table', re.MULTILINE) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     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): |     def allHandsAsList(self): | ||||||
|         list = HandHistoryConverter.allHandsAsList(self) |         list = HandHistoryConverter.allHandsAsList(self) | ||||||
|  |         if list is None: | ||||||
|  |             return [] | ||||||
|         return filter(lambda text: len(text.strip()), list) |         return filter(lambda text: len(text.strip()), list) | ||||||
| 
 | 
 | ||||||
|  |     def guessMaxSeats(self, hand): | ||||||
|  |         """Return a guess at max_seats when not specified in HH.""" | ||||||
|  |         mo = self.maxOccSeat(hand) | ||||||
|  | 
 | ||||||
|  |         if mo == 10: return mo | ||||||
|  |         if mo == 2: return 2 | ||||||
|  |         if mo <= 6: return 6 | ||||||
|  |         # there are 9-max tables for cash and 10-max for tournaments | ||||||
|  |         return 9 if hand.gametype['type']=='ring' else 10 | ||||||
|  | 
 | ||||||
|     def compilePlayerRegexs(self,  hand): |     def compilePlayerRegexs(self,  hand): | ||||||
|         players = set([player[1] for player in hand.players]) |         players = set([player[1] for player in hand.players]) | ||||||
|         if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' |         if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' | ||||||
|  | 
 | ||||||
|             self.compiledPlayers = players |             self.compiledPlayers = players | ||||||
|             player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")" |             player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")" | ||||||
|             subst = {'PLYR': player_re, 'CUR_SYM': hand.SYMBOL[hand.gametype['currency']], |             subst = {'PLYR': player_re, 'CUR_SYM': hand.SYMBOL[hand.gametype['currency']], | ||||||
|                 'CUR': hand.gametype['currency'] if hand.gametype['currency']!='T$' else ''} |                 'CUR': hand.gametype['currency'] if hand.gametype['currency']!='T$' else ''} | ||||||
|             for key in ('CUR_SYM', 'CUR'): |             for key in ('CUR_SYM', 'CUR'): | ||||||
|                 subst[key] = re.escape(subst[key]) |                 subst[key] = re.escape(subst[key]) | ||||||
|             logging.debug("player_re: " + subst['PLYR']) |             log.debug("player_re: '%s'" % subst['PLYR']) | ||||||
|             logging.debug("CUR_SYM: " + subst['CUR_SYM']) |             log.debug("CUR_SYM: '%s'" % subst['CUR_SYM']) | ||||||
|             logging.debug("CUR: " + subst['CUR']) |             log.debug("CUR: '%s'" % subst['CUR']) | ||||||
|             self.re_PostSB = re.compile( |             self.re_PostSB = re.compile( | ||||||
|                 r"^%(PLYR)s posts small blind \[%(CUR_SYM)s(?P<SB>[.0-9]+) ?%(CUR)s\]\." %  subst, |                 r"^%(PLYR)s posts small blind \[%(CUR_SYM)s(?P<SB>[.0-9]+) ?%(CUR)s\]\." %  subst, | ||||||
|                 re.MULTILINE) |                 re.MULTILINE) | ||||||
|             self.re_PostBB = re.compile( |             self.re_PostBB = re.compile( | ||||||
|                 r"^%(PLYR)s posts big blind \[%(CUR_SYM)s(?P<BB>[.0-9]+) ?%(CUR)s\]\." %  subst, |                 r"^%(PLYR)s posts big blind \[%(CUR_SYM)s(?P<BB>[.0-9]+) ?%(CUR)s\]\." %  subst, | ||||||
|                 re.MULTILINE) |                 re.MULTILINE) | ||||||
|  |             # NOTE: comma is used as a fraction part delimeter in re below | ||||||
|  |             self.re_PostDead = re.compile( | ||||||
|  |                 r"^%(PLYR)s posts big blind \+ dead \[(?P<BBNDEAD>[.,0-9]+) ?%(CUR_SYM)s\]\." %  subst, | ||||||
|  |                 re.MULTILINE) | ||||||
|             self.re_Antes = re.compile( |             self.re_Antes = re.compile( | ||||||
|                 r"^%(PLYR)s posts ante \[%(CUR_SYM)s(?P<ANTE>[.0-9]+) ?%(CUR)s\]\." %  subst, |                 r"^%(PLYR)s posts ante \[%(CUR_SYM)s(?P<ANTE>[.0-9]+) ?%(CUR)s\]" %  subst, | ||||||
|                 re.MULTILINE) |                 re.MULTILINE) | ||||||
|             self.re_HeroCards = re.compile( |             self.re_HeroCards = re.compile( | ||||||
|                 r"^Dealt to %(PLYR)s \[\s*(?P<NEWCARDS>.+)\s*\]" % subst, |                 r"^Dealt to %(PLYR)s \[\s*(?P<NEWCARDS>.+)\s*\]" % subst, | ||||||
|  | @ -148,21 +159,23 @@ follow :  whether to tail -f the input""" | ||||||
|                 r"\[ *(?P<CARDS>.+) *\](?P<COMBINATION>.+)\.", |                 r"\[ *(?P<CARDS>.+) *\](?P<COMBINATION>.+)\.", | ||||||
|                 re.MULTILINE) |                 re.MULTILINE) | ||||||
|             self.re_CollectPot = re.compile( |             self.re_CollectPot = re.compile( | ||||||
|                 r""""^%(PLYR)s \s+ wins \s+ |                 r"""^%(PLYR)s \s+ wins \s+ | ||||||
|                 %(CUR_SYM)s(?P<POT>[.\d]+)\s*%(CUR)s""" %  subst,  |                 %(CUR_SYM)s(?P<POT>[.,\d]+)\s*%(CUR)s""" %  subst, | ||||||
|                 re.MULTILINE|re.VERBOSE) |                 re.MULTILINE|re.VERBOSE) | ||||||
| 
 | 
 | ||||||
|     def readSupportedGames(self): |     def readSupportedGames(self): | ||||||
|         return [["ring", "hold", "nl"], |         return [["ring", "hold", "nl"], | ||||||
|                 #["ring", "hold", "pl"], |                 ["ring", "hold", "pl"], | ||||||
|                 #["ring", "hold", "fl"], |                 ["ring", "hold", "fl"], | ||||||
| 
 | 
 | ||||||
|                 ["tour", "hold", "nl"], |                 ["tour", "hold", "nl"], | ||||||
|                 #["tour", "hold", "pl"], |                 ["tour", "hold", "pl"], | ||||||
|                 #["tour", "hold", "fl"], |                 ["tour", "hold", "fl"], | ||||||
|                ] |                ] | ||||||
| 
 | 
 | ||||||
|     def _getGameType(self, handText): |     def _getGameType(self, handText): | ||||||
|  |         if not hasattr(self, '_gameType'): | ||||||
|  |             self._gameType = None | ||||||
|         if self._gameType is None: |         if self._gameType is None: | ||||||
|             # let's determine whether hand is trny |             # let's determine whether hand is trny | ||||||
|             # and whether 5-th line contains head line |             # and whether 5-th line contains head line | ||||||
|  | @ -181,7 +194,7 @@ follow :  whether to tail -f the input""" | ||||||
|         gametype dict is: |         gametype dict is: | ||||||
|         {'limitType': xxx, 'base': xxx, 'category': xxx}""" |         {'limitType': xxx, 'base': xxx, 'category': xxx}""" | ||||||
| 
 | 
 | ||||||
|         logging.debug(self.ParsingException().wrapHh( handText )) |         log.debug(PartyPokerParseError().wrapHh( handText )) | ||||||
| 
 | 
 | ||||||
|         info = {} |         info = {} | ||||||
|         m = self._getGameType(handText) |         m = self._getGameType(handText) | ||||||
|  | @ -190,31 +203,29 @@ follow :  whether to tail -f the input""" | ||||||
| 
 | 
 | ||||||
|         mg = m.groupdict() |         mg = m.groupdict() | ||||||
|         # translations from captured groups to fpdb info strings |         # translations from captured groups to fpdb info strings | ||||||
|         limits = { 'NL':'nl',  |         limits = { 'NL':'nl', 'PL':'pl', '':'fl' } | ||||||
| #            'Pot Limit':'pl', 'Limit':'fl'  |  | ||||||
|             } |  | ||||||
|         games = {                          # base, category |         games = {                          # base, category | ||||||
|                          "Texas Hold'em" : ('hold','holdem'), |                          "Texas Hold'em" : ('hold','holdem'), | ||||||
|                                 #'Omaha' : ('hold','omahahi'), |                                 'Omaha' : ('hold','omahahi'), | ||||||
|                } |                } | ||||||
|         currencies = { '$':'USD', '':'T$' } |         currencies = { '$':'USD', '':'T$' } | ||||||
| 
 | 
 | ||||||
|         for expectedField in ['LIMIT', 'GAME']: |         for expectedField in ['LIMIT', 'GAME']: | ||||||
|             if mg[expectedField] is None: |             if mg[expectedField] is None: | ||||||
|                 raise self.ParsingException( |                 raise PartyPokerParseError( | ||||||
|                     "Cannot fetch field '%s'" % expectedField, |                     "Cannot fetch field '%s'" % expectedField, | ||||||
|                     hh = handText) |                     hh = handText) | ||||||
|         try: |         try: | ||||||
|             info['limitType'] = limits[mg['LIMIT']] |             info['limitType'] = limits[mg['LIMIT'].strip()] | ||||||
|         except: |         except: | ||||||
|             raise self.ParsingException( |             raise PartyPokerParseError( | ||||||
|                 "Unknown limit '%s'" % mg['LIMIT'], |                 "Unknown limit '%s'" % mg['LIMIT'], | ||||||
|                 hh = handText) |                 hh = handText) | ||||||
| 
 | 
 | ||||||
|         try: |         try: | ||||||
|             (info['base'], info['category']) = games[mg['GAME']] |             (info['base'], info['category']) = games[mg['GAME']] | ||||||
|         except: |         except: | ||||||
|             raise self.ParsingException( |             raise PartyPokerParseError( | ||||||
|                 "Unknown game type '%s'" % mg['GAME'], |                 "Unknown game type '%s'" % mg['GAME'], | ||||||
|                 hh = handText) |                 hh = handText) | ||||||
| 
 | 
 | ||||||
|  | @ -227,10 +238,11 @@ follow :  whether to tail -f the input""" | ||||||
|         if info['type'] == 'ring': |         if info['type'] == 'ring': | ||||||
|             info['sb'], info['bb'] = ringBlinds(mg['RINGLIMIT']) |             info['sb'], info['bb'] = ringBlinds(mg['RINGLIMIT']) | ||||||
|             # FIXME: there are only $ and play money availible for cash |             # FIXME: there are only $ and play money availible for cash | ||||||
|  |             # to be honest, party doesn't save play money hh | ||||||
|             info['currency'] = currencies[mg['CURRENCY']] |             info['currency'] = currencies[mg['CURRENCY']] | ||||||
|         else: |         else: | ||||||
|             info['sb'] = renderTrnyMoney(mg['SB']) |             info['sb'] = clearMoneyString(mg['SB']) | ||||||
|             info['bb'] = renderTrnyMoney(mg['BB']) |             info['bb'] = clearMoneyString(mg['BB']) | ||||||
|             info['currency'] = 'T$' |             info['currency'] = 'T$' | ||||||
| 
 | 
 | ||||||
|         # NB: SB, BB must be interpreted as blinds or bets depending on limit type. |         # NB: SB, BB must be interpreted as blinds or bets depending on limit type. | ||||||
|  | @ -239,21 +251,48 @@ follow :  whether to tail -f the input""" | ||||||
| 
 | 
 | ||||||
|     def readHandInfo(self, hand): |     def readHandInfo(self, hand): | ||||||
|         info = {} |         info = {} | ||||||
|         m = self.re_HandInfo.search(hand.handText,re.DOTALL) |         try: | ||||||
|         if m: |             info.update(self.re_Hid.search(hand.handText).groupdict()) | ||||||
|             info.update(m.groupdict()) |         except: | ||||||
|         else: |             raise PartyPokerParseError("Cannot read HID for current hand", hh=hand.handText) | ||||||
|             raise self.ParsingException("Cannot read Handinfo for current hand", hh=hand.handText) | 
 | ||||||
|         m = self._getGameType(hand.handText) |         try: | ||||||
|         if m: info.update(m.groupdict()) |             info.update(self.re_HandInfo.search(hand.handText,re.DOTALL).groupdict()) | ||||||
|         m = self.re_Hid.search(hand.handText) |         except: | ||||||
|  |             raise PartyPokerParseError("Cannot read Handinfo for current hand", | ||||||
|  |             hh=hand.handText, hid = info['HID']) | ||||||
|  | 
 | ||||||
|  |         try: | ||||||
|  |             info.update(self._getGameType(hand.handText).groupdict()) | ||||||
|  |         except: | ||||||
|  |             raise PartyPokerParseError("Cannot read GameType for current hand", | ||||||
|  |             hh=hand.handText, hid = info['HID']) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         m = self.re_TotalPlayers.search(hand.handText) | ||||||
|         if m: info.update(m.groupdict()) |         if m: info.update(m.groupdict()) | ||||||
| 
 | 
 | ||||||
|         # FIXME: it's a hack cause party doesn't supply hand.maxseats info |  | ||||||
|         #hand.maxseats = ??? |  | ||||||
|         hand.mixed = None |  | ||||||
| 
 | 
 | ||||||
|         logging.debug("readHandInfo: %s" % info) |         # FIXME: it's dirty hack | ||||||
|  |         # party doesnt subtract uncalled money from commited money | ||||||
|  |         # so hand.totalPot calculation has to be redefined | ||||||
|  |         from Hand import Pot, HoldemOmahaHand | ||||||
|  |         def getNewTotalPot(origTotalPot): | ||||||
|  |             def totalPot(self): | ||||||
|  |                 if self.totalpot is None: | ||||||
|  |                     self.pot.end() | ||||||
|  |                     self.totalpot = self.pot.total | ||||||
|  |                 for i,v in enumerate(self.collected): | ||||||
|  |                     if v[0] in self.pot.returned: | ||||||
|  |                         self.collected[i][1] = Decimal(v[1]) - self.pot.returned[v[0]] | ||||||
|  |                 return origTotalPot() | ||||||
|  |             return totalPot | ||||||
|  |         instancemethod = type(hand.totalPot) | ||||||
|  |         hand.totalPot = instancemethod(getNewTotalPot(hand.totalPot), hand, HoldemOmahaHand) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         log.debug("readHandInfo: %s" % info) | ||||||
|         for key in info: |         for key in info: | ||||||
|             if key == 'DATETIME': |             if key == 'DATETIME': | ||||||
|                 #Saturday, July 25, 07:53:52 EDT 2009 |                 #Saturday, July 25, 07:53:52 EDT 2009 | ||||||
|  | @ -278,14 +317,14 @@ follow :  whether to tail -f the input""" | ||||||
|             if key == 'TOURNO': |             if key == 'TOURNO': | ||||||
|                 hand.tourNo = info[key] |                 hand.tourNo = info[key] | ||||||
|             if key == 'BUYIN': |             if key == 'BUYIN': | ||||||
|                 #FIXME: it's dirty hack T_T |                 # FIXME: it's dirty hack T_T | ||||||
|  |                 # code below assumes that rake is equal to zero | ||||||
|                 cur = info[key][0] if info[key][0] not in '0123456789' else '' |                 cur = info[key][0] if info[key][0] not in '0123456789' else '' | ||||||
|                 hand.buyin = info[key] + '+%s0' % cur |                 hand.buyin = info[key] + '+%s0' % cur | ||||||
|             if key == 'LEVEL': |             if key == 'LEVEL': | ||||||
|                 hand.level = info[key] |                 hand.level = info[key] | ||||||
|             if key == 'PLAY' and info['PLAY'] != 'Real': |             if key == 'PLAY' and info['PLAY'] != 'Real': | ||||||
|                 # TODO: play money wasn't tested |                 # if realy there's no play money hh on party | ||||||
| #                hand.currency = 'play' # overrides previously set value |  | ||||||
|                 hand.gametype['currency'] = 'play' |                 hand.gametype['currency'] = 'play' | ||||||
| 
 | 
 | ||||||
|     def readButton(self, hand): |     def readButton(self, hand): | ||||||
|  | @ -293,21 +332,17 @@ follow :  whether to tail -f the input""" | ||||||
|         if m: |         if m: | ||||||
|             hand.buttonpos = int(m.group('BUTTON')) |             hand.buttonpos = int(m.group('BUTTON')) | ||||||
|         else: |         else: | ||||||
|             logging.info('readButton: not found') |             log.info('readButton: not found') | ||||||
| 
 | 
 | ||||||
|     def readPlayerStacks(self, hand): |     def readPlayerStacks(self, hand): | ||||||
|         logging.debug("readPlayerStacks") |         log.debug("readPlayerStacks") | ||||||
|         m = self.re_PlayerInfo.finditer(hand.handText) |         m = self.re_PlayerInfo.finditer(hand.handText) | ||||||
|         players = [] |         players = [] | ||||||
|         for a in m: |         for a in m: | ||||||
|             hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), |             hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), | ||||||
|                            renderTrnyMoney(a.group('CASH'))) |                            clearMoneyString(a.group('CASH'))) | ||||||
| 
 | 
 | ||||||
|     def markStreets(self, hand): |     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( |         m =  re.search( | ||||||
|             r"\*{2} Dealing down cards \*{2}" |             r"\*{2} Dealing down cards \*{2}" | ||||||
|             r"(?P<PREFLOP>.+?)" |             r"(?P<PREFLOP>.+?)" | ||||||
|  | @ -323,16 +358,11 @@ follow :  whether to tail -f the input""" | ||||||
|             hand.setCommunityCards(street, renderCards(m.group('CARDS'))) |             hand.setCommunityCards(street, renderCards(m.group('CARDS'))) | ||||||
| 
 | 
 | ||||||
|     def readAntes(self, hand): |     def readAntes(self, hand): | ||||||
|         logging.debug("reading antes") |         log.debug("reading antes") | ||||||
|         m = self.re_Antes.finditer(hand.handText) |         m = self.re_Antes.finditer(hand.handText) | ||||||
|         for player in m: |         for player in m: | ||||||
|             hand.addAnte(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: |  | ||||||
|             hand.addBringIn(m.group('PNAME'),  m.group('BRINGIN')) |  | ||||||
|          |  | ||||||
|     def readBlinds(self, hand): |     def readBlinds(self, hand): | ||||||
|         noSmallBlind = bool(self.re_NoSmallBlind.search(hand.handText)) |         noSmallBlind = bool(self.re_NoSmallBlind.search(hand.handText)) | ||||||
|         if hand.gametype['type'] == 'ring': |         if hand.gametype['type'] == 'ring': | ||||||
|  | @ -345,6 +375,10 @@ follow :  whether to tail -f the input""" | ||||||
| 
 | 
 | ||||||
|             for a in self.re_PostBB.finditer(hand.handText): |             for a in self.re_PostBB.finditer(hand.handText): | ||||||
|                 hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) |                 hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) | ||||||
|  | 
 | ||||||
|  |             deadFilter = lambda s: s.replace(',', '.') | ||||||
|  |             for a in self.re_PostDead.finditer(hand.handText): | ||||||
|  |                 hand.addBlind(a.group('PNAME'), 'both', deadFilter(a.group('BBNDEAD'))) | ||||||
|         else: |         else: | ||||||
|             # party doesn't track blinds for tournaments |             # party doesn't track blinds for tournaments | ||||||
|             # so there're some cra^Wcaclulations |             # so there're some cra^Wcaclulations | ||||||
|  | @ -365,6 +399,7 @@ follow :  whether to tail -f the input""" | ||||||
| 
 | 
 | ||||||
|             if noSmallBlind: |             if noSmallBlind: | ||||||
|                 hand.addBlind(None, None, None) |                 hand.addBlind(None, None, None) | ||||||
|  |                 smallBlindSeat = int(hand.buttonpos) | ||||||
|             else: |             else: | ||||||
|                 smallBlindSeat = findFirstNonEmptySeat(int(hand.buttonpos) + 1) |                 smallBlindSeat = findFirstNonEmptySeat(int(hand.buttonpos) + 1) | ||||||
|                 blind = smartMin(hand.sb, playersMap[smallBlindSeat][1]) |                 blind = smartMin(hand.sb, playersMap[smallBlindSeat][1]) | ||||||
|  | @ -372,7 +407,7 @@ follow :  whether to tail -f the input""" | ||||||
| 
 | 
 | ||||||
|             bigBlindSeat = findFirstNonEmptySeat(smallBlindSeat + 1) |             bigBlindSeat = findFirstNonEmptySeat(smallBlindSeat + 1) | ||||||
|             blind = smartMin(hand.bb, playersMap[bigBlindSeat][1]) |             blind = smartMin(hand.bb, playersMap[bigBlindSeat][1]) | ||||||
|             hand.addBlind(playersMap[bigBlindSeat][0], 'small blind', blind) |             hand.addBlind(playersMap[bigBlindSeat][0], 'big blind', blind) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -391,18 +426,39 @@ follow :  whether to tail -f the input""" | ||||||
|         m = self.re_Action.finditer(hand.streets[street]) |         m = self.re_Action.finditer(hand.streets[street]) | ||||||
|         for action in m: |         for action in m: | ||||||
|             acts = action.groupdict() |             acts = action.groupdict() | ||||||
|             if action.group('ATYPE') in ('raises','is all-In'): |             playerName = action.group('PNAME') | ||||||
|                 hand.addRaiseBy( street, action.group('PNAME'), action.group('BET') ) |             amount = clearMoneyString(action.group('BET')) if action.group('BET') else None | ||||||
|             elif action.group('ATYPE') == 'calls': |             actionType = action.group('ATYPE') | ||||||
|                 hand.addCall( street, action.group('PNAME'), action.group('BET') ) | 
 | ||||||
|             elif action.group('ATYPE') == 'bets': |             if actionType == 'is all-In': | ||||||
|                 hand.addBet( street, action.group('PNAME'), action.group('BET') ) |                 # party's allin can mean either raise or bet or call | ||||||
|             elif action.group('ATYPE') == 'folds': |                 Bp = hand.lastBet[street] | ||||||
|                 hand.addFold( street, action.group('PNAME')) |                 if Bp == 0: | ||||||
|             elif action.group('ATYPE') == 'checks': |                     actionType = 'bets' | ||||||
|                 hand.addCheck( street, action.group('PNAME')) |                 elif Bp < Decimal(amount): | ||||||
|  |                     actionType = 'raises' | ||||||
|                 else: |                 else: | ||||||
|                 print "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),) |                     actionType = 'calls' | ||||||
|  | 
 | ||||||
|  |             if actionType == 'raises': | ||||||
|  |                 if street == 'PREFLOP' and \ | ||||||
|  |                     playerName in [item[0] for item in hand.actions['BLINDSANTES'] if item[2]!='ante']: | ||||||
|  |                     # preflop raise from blind | ||||||
|  |                     hand.addRaiseBy( street, playerName, amount ) | ||||||
|  |                 else: | ||||||
|  |                     hand.addCallandRaise( street, playerName, amount ) | ||||||
|  |             elif actionType == 'calls': | ||||||
|  |                 hand.addCall( street, playerName, amount ) | ||||||
|  |             elif actionType == 'bets': | ||||||
|  |                 hand.addBet( street, playerName, amount ) | ||||||
|  |             elif actionType == 'folds': | ||||||
|  |                 hand.addFold( street, playerName ) | ||||||
|  |             elif actionType == 'checks': | ||||||
|  |                 hand.addCheck( street, playerName ) | ||||||
|  |             else: | ||||||
|  |                 raise PartyPokerParseError( | ||||||
|  |                     "Unimplemented readAction: '%s' '%s'" % (playerName,actionType,), | ||||||
|  |                     hid = hand.hid, hh = hand.handText ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def readShowdownActions(self, hand): |     def readShowdownActions(self, hand): | ||||||
|  | @ -411,7 +467,7 @@ follow :  whether to tail -f the input""" | ||||||
| 
 | 
 | ||||||
|     def readCollectPot(self,hand): |     def readCollectPot(self,hand): | ||||||
|         for m in self.re_CollectPot.finditer(hand.handText): |         for m in self.re_CollectPot.finditer(hand.handText): | ||||||
|             hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT')) |             hand.addCollectPot(player=m.group('PNAME'),pot=clearMoneyString(m.group('POT'))) | ||||||
| 
 | 
 | ||||||
|     def readShownCards(self,hand): |     def readShownCards(self,hand): | ||||||
|         for m in self.re_ShownCards.finditer(hand.handText): |         for m in self.re_ShownCards.finditer(hand.handText): | ||||||
|  | @ -425,17 +481,17 @@ follow :  whether to tail -f the input""" | ||||||
|                 hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked) |                 hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked) | ||||||
| 
 | 
 | ||||||
| def ringBlinds(ringLimit): | def ringBlinds(ringLimit): | ||||||
|     "Returns blinds for current limit" |     "Returns blinds for current limit in cash games" | ||||||
|     ringLimit = float(ringLimit) |     ringLimit = float(clearMoneyString(ringLimit)) | ||||||
|     if ringLimit == 5.: ringLimit = 4. |     if ringLimit == 5.: ringLimit = 4. | ||||||
|     return ('%.2f' % (ringLimit/200.), '%.2f' % (ringLimit/100.)  ) |     return ('%.2f' % (ringLimit/200.), '%.2f' % (ringLimit/100.)  ) | ||||||
| 
 | 
 | ||||||
| def renderTrnyMoney(money): | def clearMoneyString(money): | ||||||
|     "renders 'numbers' like '1 200' and '2,000'" |     "Renders 'numbers' like '1 200' and '2,000'" | ||||||
|     return money.replace(' ', '').replace(',', '') |     return money.replace(' ', '').replace(',', '') | ||||||
| 
 | 
 | ||||||
| def renderCards(string): | def renderCards(string): | ||||||
|     "splits strings like ' Js, 4d '" |     "Splits strings like ' Js, 4d '" | ||||||
|     cards = string.strip().split(' ') |     cards = string.strip().split(' ') | ||||||
|     return filter(len, map(lambda x: x.strip(' ,'), cards)) |     return filter(len, map(lambda x: x.strip(' ,'), cards)) | ||||||
| 
 | 
 | ||||||
|  | @ -454,7 +510,4 @@ if __name__ == "__main__": | ||||||
| 
 | 
 | ||||||
|     (options, args) = parser.parse_args() |     (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) |     e = PartyPoker(in_path = options.ipath, out_path = options.opath, follow = options.follow) | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ | ||||||
| ######################################################################## | ######################################################################## | ||||||
| 
 | 
 | ||||||
| # TODO: straighten out discards for draw games | # TODO: straighten out discards for draw games | ||||||
|  | 
 | ||||||
| import sys | import sys | ||||||
| from HandHistoryConverter import * | from HandHistoryConverter import * | ||||||
| 
 | 
 | ||||||
|  | @ -26,8 +27,12 @@ from HandHistoryConverter import * | ||||||
| 
 | 
 | ||||||
| class PokerStars(HandHistoryConverter): | class PokerStars(HandHistoryConverter): | ||||||
| 
 | 
 | ||||||
| ############################################################ |     # Class Variables | ||||||
| #    Class Variables | 
 | ||||||
|  |     sitename = "PokerStars" | ||||||
|  |     filetype = "text" | ||||||
|  |     codepage = "cp1252" | ||||||
|  |     siteId   = 2 # Needs to match id entry in Sites database | ||||||
| 
 | 
 | ||||||
|     mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} # Legal mixed games |     mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} # Legal mixed games | ||||||
|     sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "\x80", "GBP": "\xa3"}         # ADD Euro, Sterling, etc HERE |     sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "\x80", "GBP": "\xa3"}         # ADD Euro, Sterling, etc HERE | ||||||
|  | @ -77,20 +82,6 @@ class PokerStars(HandHistoryConverter): | ||||||
| #        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]+)')     | #        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="PokerStars", follow=follow, index=index) |  | ||||||
|         logging.info("Initialising PokerStars converter class") |  | ||||||
|         self.filetype = "text" |  | ||||||
|         self.codepage = "cp1252" |  | ||||||
|         self.siteId   = 2 # Needs to match id entry in Sites database |  | ||||||
|         if autostart: |  | ||||||
|             self.start() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     def compilePlayerRegexs(self,  hand): |     def compilePlayerRegexs(self,  hand): | ||||||
|         players = set([player[1] for player in hand.players]) |         players = set([player[1] for player in hand.players]) | ||||||
|         if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' |         if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' | ||||||
|  | @ -388,7 +379,4 @@ if __name__ == "__main__": | ||||||
| 
 | 
 | ||||||
|     (options, args) = parser.parse_args() |     (options, args) = parser.parse_args() | ||||||
| 
 | 
 | ||||||
|     LOG_FILENAME = './logging.out' |  | ||||||
|     logging.basicConfig(filename=LOG_FILENAME,level=options.verbosity) |  | ||||||
| 
 |  | ||||||
|     e = PokerStars(in_path = options.ipath, out_path = options.opath, follow = options.follow) |     e = PokerStars(in_path = options.ipath, out_path = options.opath, follow = options.follow) | ||||||
|  |  | ||||||
|  | @ -230,11 +230,20 @@ def discover_nt_by_name(c, tablename): | ||||||
|     """Finds poker client window with the given table name.""" |     """Finds poker client window with the given table name.""" | ||||||
|     titles = {} |     titles = {} | ||||||
|     win32gui.EnumWindows(win_enum_handler, titles) |     win32gui.EnumWindows(win_enum_handler, titles) | ||||||
|  |      | ||||||
|  |     def getDefaultEncoding(): | ||||||
|  |         # FIXME: if somebody know better place fot this function - move it | ||||||
|  |         # FIXME: it's better to use GetCPInfo for windows http://msdn.microsoft.com/en-us/library/dd318078(VS.85).aspx | ||||||
|  |         # but i have no idea, how to call it | ||||||
|  |         import locale | ||||||
|  |         return locale.getpreferredencoding() | ||||||
|  |          | ||||||
|     for hwnd in titles: |     for hwnd in titles: | ||||||
|         #print "Tables.py: tablename =", tablename, "title =", titles[hwnd] |         #print "Tables.py: tablename =", tablename, "title =", titles[hwnd] | ||||||
|         try: |         try: | ||||||
|  |             # maybe it's better to make global titles[hwnd] decoding? | ||||||
|             # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html |             # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html | ||||||
|             if not tablename.lower() in titles[hwnd].lower(): continue |             if not tablename.lower() in titles[hwnd].decode(getDefaultEncoding()).lower(): continue | ||||||
|         except: |         except: | ||||||
|             continue |             continue | ||||||
|         if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window |         if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window | ||||||
|  |  | ||||||
|  | @ -26,6 +26,11 @@ from HandHistoryConverter import * | ||||||
| 
 | 
 | ||||||
| class Win2day(HandHistoryConverter): | class Win2day(HandHistoryConverter): | ||||||
| 
 | 
 | ||||||
|  |     sitename = "Win2day" | ||||||
|  |     filetype = "text" | ||||||
|  |     codepage = "cp1252" | ||||||
|  |     siteID   = 4 | ||||||
|  | 
 | ||||||
|     # Static regexes |     # Static regexes | ||||||
|     #<HISTORY ID="102271403" SESSION="session31237702.xml" TABLE="Innsbruck 3" GAME="GAME_THM" GAMETYPE="GAMETYPE_REAL" GAMEKIND="GAMEKIND_CASH" TABLECURRENCY="EUR" LIMIT="NL" STAKES="0.25/0.50" DATE="1246909773" WIN="0.00" LOSS="0.50"> |     #<HISTORY ID="102271403" SESSION="session31237702.xml" TABLE="Innsbruck 3" GAME="GAME_THM" GAMETYPE="GAMETYPE_REAL" GAMEKIND="GAMEKIND_CASH" TABLECURRENCY="EUR" LIMIT="NL" STAKES="0.25/0.50" DATE="1246909773" WIN="0.00" LOSS="0.50"> | ||||||
|      |      | ||||||
|  | @ -39,15 +44,6 @@ class Win2day(HandHistoryConverter): | ||||||
|     re_Card        = re.compile('^<CARD LINK="(?P<CARD>[0-9]+)"></CARD>', re.MULTILINE) |     re_Card        = re.compile('^<CARD LINK="(?P<CARD>[0-9]+)"></CARD>', re.MULTILINE) | ||||||
|     re_BoardLast    = re.compile('^<CARD LINK="(?P<CARD>[0-9]+)"></CARD></ACTION>', re.MULTILINE) |     re_BoardLast    = re.compile('^<CARD LINK="(?P<CARD>[0-9]+)"></CARD></ACTION>', re.MULTILINE) | ||||||
|      |      | ||||||
|     def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, index=0): |  | ||||||
|         HandHistoryConverter.__init__(self, in_path, out_path, sitename="Win2day", follow=follow, index=index) |  | ||||||
|         logging.info("Initialising Win2day converter class") |  | ||||||
|         self.filetype = "text" |  | ||||||
|         self.codepage = "cp1252" |  | ||||||
|         self.sideID   = 4 |  | ||||||
|         if autostart: |  | ||||||
|             self.start() |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
|     def compilePlayerRegexs(self,  hand): |     def compilePlayerRegexs(self,  hand): | ||||||
|         players = set([player[1] for player in hand.players]) |         players = set([player[1] for player in hand.players]) | ||||||
|  | @ -65,7 +61,7 @@ class Win2day(HandHistoryConverter): | ||||||
|             self.re_PostBoth         = re.compile(r'^<ACTION TYPE="HAND_BLINDS" PLAYER="%s" KIND="HAND_AB" VALUE="(?P<SBBB>[.0-9]+)"></ACTION>' %  player_re, re.MULTILINE) |             self.re_PostBoth         = re.compile(r'^<ACTION TYPE="HAND_BLINDS" PLAYER="%s" KIND="HAND_AB" VALUE="(?P<SBBB>[.0-9]+)"></ACTION>' %  player_re, re.MULTILINE) | ||||||
|      |      | ||||||
|             #r'<ACTION TYPE="HAND_DEAL" PLAYER="%s">\n<CARD LINK="(?P<CARD1>[0-9]+)"></CARD>\n<CARD LINK="(?P<CARD2>[0-9]+)"></CARD></ACTION>' |             #r'<ACTION TYPE="HAND_DEAL" PLAYER="%s">\n<CARD LINK="(?P<CARD1>[0-9]+)"></CARD>\n<CARD LINK="(?P<CARD2>[0-9]+)"></CARD></ACTION>' | ||||||
|             self.re_HeroCards        = re.compile(r'<ACTION TYPE="HAND_DEAL" PLAYER="%s">\n(?P<CARDS><CARD LINK="[0-9]+"></CARD>\n<CARD LINK="[0-9]"></CARD>)</ACTION>' % player_re, re.MULTILINE) |             self.re_HeroCards        = re.compile(r'<ACTION TYPE="HAND_DEAL" PLAYER="%s">\n(?P<CARDS><CARD LINK="[0-9]+"></CARD>\n<CARD LINK="[0-9]+"></CARD>)</ACTION>' % player_re, re.MULTILINE) | ||||||
|              |              | ||||||
|             #'^<ACTION TYPE="(?P<ATYPE>[_A-Z]+)" PLAYER="%s"( VALUE="(?P<BET>[.0-9]+)")?></ACTION>' |             #'^<ACTION TYPE="(?P<ATYPE>[_A-Z]+)" PLAYER="%s"( VALUE="(?P<BET>[.0-9]+)")?></ACTION>' | ||||||
|             self.re_Action           = re.compile(r'^<ACTION TYPE="(?P<ATYPE>[_A-Z]+)" PLAYER="%s"( VALUE="(?P<BET>[.0-9]+)")?></ACTION>' %  player_re, re.MULTILINE) |             self.re_Action           = re.compile(r'^<ACTION TYPE="(?P<ATYPE>[_A-Z]+)" PLAYER="%s"( VALUE="(?P<BET>[.0-9]+)")?></ACTION>' %  player_re, re.MULTILINE) | ||||||
|  |  | ||||||
							
								
								
									
										40
									
								
								pyfpdb/logging.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								pyfpdb/logging.conf
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | ||||||
|  | [loggers] | ||||||
|  | keys=root,parser | ||||||
|  | 
 | ||||||
|  | [handlers] | ||||||
|  | keys=consoleHandler,fileHandler | ||||||
|  | 
 | ||||||
|  | [formatters] | ||||||
|  | keys=fileFormatter,stderrFormatter | ||||||
|  | 
 | ||||||
|  | [logger_root] | ||||||
|  | level=INFO | ||||||
|  | handlers=consoleHandler,fileHandler | ||||||
|  | 
 | ||||||
|  | [logger_parser] | ||||||
|  | level=INFO | ||||||
|  | # set to NOTSET or DEBUG to see everything the parser does | ||||||
|  | handlers=consoleHandler,fileHandler | ||||||
|  | qualname=parser | ||||||
|  | propagate=0 | ||||||
|  | 
 | ||||||
|  | [handler_consoleHandler] | ||||||
|  | class=StreamHandler | ||||||
|  | level=INFO | ||||||
|  | formatter=stderrFormatter | ||||||
|  | args=(sys.stderr,) | ||||||
|  | 
 | ||||||
|  | [handler_fileHandler] | ||||||
|  | class=FileHandler | ||||||
|  | level=INFO | ||||||
|  | formatter=fileFormatter | ||||||
|  | args=('logging.out', 'a') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | [formatter_fileFormatter] | ||||||
|  | format=%(asctime)s - %(name)-12s %(levelname)-8s %(message)s | ||||||
|  | datefmt= | ||||||
|  | 
 | ||||||
|  | [formatter_stderrFormatter] | ||||||
|  | format=%(name)-12s: %(levelname)-8s %(message)s | ||||||
|  | datefmt= | ||||||
|  | @ -5,6 +5,11 @@ import py | ||||||
| # regression-test-files/fulltilt/nlhe/NLHE-6max-1.txt | # regression-test-files/fulltilt/nlhe/NLHE-6max-1.txt | ||||||
| #   Sorrowful: start: $8.85 end: $14.70 total: $5.85  | #   Sorrowful: start: $8.85 end: $14.70 total: $5.85  | ||||||
|    |    | ||||||
|  | # 'Canceled' hand | ||||||
|  | # regression-test-files/fulltilt/lh/Marlin.txt | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def checkGameInfo(hhc, header, info): | def checkGameInfo(hhc, header, info): | ||||||
|     assert hhc.determineGameType(header) == info |     assert hhc.determineGameType(header) == info | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ text = "" | ||||||
| 
 | 
 | ||||||
| hhc = PokerStarsToFpdb.PokerStars(autostart=False) | hhc = PokerStarsToFpdb.PokerStars(autostart=False) | ||||||
| 
 | 
 | ||||||
| h = HoldemOmahaHand(None, "ASite", gametype, text, builtFrom = "Test") | h = HoldemOmahaHand(None, "PokerStars", gametype, text, builtFrom = "Test") | ||||||
| h.addPlayer("1", "s0rrow", "100000") | h.addPlayer("1", "s0rrow", "100000") | ||||||
| 
 | 
 | ||||||
| hhc.compilePlayerRegexs(h) | hhc.compilePlayerRegexs(h) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user