Merge branch 'master' of git://git.assembla.com/fpdb.git
This commit is contained in:
		
						commit
						51b62392e1
					
				|  | @ -29,8 +29,8 @@ cp -R regression-test fpdb-$1/ | |||
| cp -R utils fpdb-$1/ | ||||
| 
 | ||||
| cd fpdb-$1 | ||||
| zip -r ../../fpdb-1.0_$1.zip * | ||||
| tar -cf - * | bzip2 >> ../../fpdb-1.0_$1.tar.bz2 | ||||
| zip -r releases/fpdb-1.0_$1.zip * | ||||
| tar -cf - * | bzip2 >> releases/fpdb-1.0_$1.tar.bz2 | ||||
| cd .. | ||||
| rm -r fpdb-$1 | ||||
| 
 | ||||
|  |  | |||
|  | @ -312,11 +312,10 @@ The program itself is licensed under AGPLv3, see agpl-3.0.txt</p> | |||
| </TABLE> | ||||
| <p><BR></P> | ||||
| <p><B>Table HandsPlayers</B></P> | ||||
| <p>cardX: can be 1 through 20, one for each card. In holdem only 1-2 of these are used, in omaha 1-4, in stud/razz 1-7, in single draw games 1-10 is used and in badugi 1-16 (4*4) is used.</P> | ||||
| <p>For the draw games: the first 5 (badugi: 4) cards are the initial cards, the next 5 (badugi: 4) are after the first draw. If a player keeps some cards then those cards' spaces are filled with "k", short for "kept".<br> | ||||
| Example 1: If a player gets 2-6 spades for his first five cards and decides to throw away the 4 and then gets a 7 of spades then the first 10 fields of cardXValue would be as follows: 2, 3, 4, 5, 6, k, k, 7, k, k<br> | ||||
| Example 2: If a player gets 2, 3, 5, 8, J of spades for his first five cards and decides to throw away the 2 and the 3 and then gets a Q and K of spades then the first 10 fields of cardXValue would be as follows: 2, 3, 5, 8, J, Q, K, k, k, k<br> | ||||
| Note that it will k in the space of which card was there previously, so in example 2 where the player kept the last 3 cards, the last 3 fields of the first draw (ie. card8-10Value) are replaced with k.</p> | ||||
| <p>cardX: can be 1 through 20, one for each card. In holdem only 1-2 of these are used, in omaha 1-4, in stud/razz 1-7, in single draw 1-10, in tripple draw all 20 and in badugi 1-16 (4*4).</P> | ||||
| <p>For the draw games: the first 5 (badugi: 4) cards are the initial cards, the next 5 (badugi: 4) are after the first draw, etc.<br> | ||||
| Example 1: If a player gets 2-6 spades for his first five cards and decides to throw away the 4 and then gets a 7 of spades then the first 10 fields of cardXValue would be as follows: 2, 3, 4, 5, 6, 2, 3, 5, 6, 7<br> | ||||
| Example 2: If a player gets 2, 3, 5, 8, J of spades for his first five cards and decides to throw away the 2 and the 3 and then gets a Q and K of spades then the first 10 fields of cardXValue would be as follows: 2, 3, 5, 8, J, 5, 8, J, Q, K.</p> | ||||
| <p>I did not separate this into an extra table because I felt the lost space is not sufficiently large. Also the benefit for searching is far less relevant.</P> | ||||
| <TABLE BORDER=1 CELLPADDING=2 CELLSPACING=0> | ||||
| 	<TR VALIGN=TOP> | ||||
|  | @ -370,6 +369,17 @@ Note that it will k in the space of which card was there previously, so in examp | |||
| 		<TD><P>char(1)</P></TD> | ||||
| 		<TD><P>h=hearts, s=spades, d=diamonds, c=clubs, unknown/no card=x</P></TD> | ||||
| 	</TR> | ||||
| 	<TR VALIGN=TOP> | ||||
| 		<TD><P>cardXDiscarded</P></TD> | ||||
| 		<TD><P>boolean</P></TD> | ||||
| 		<TD><P>Whether the card was discarded (this only applies to draw games, X can be 1 through 15 since the final cards can obviously not be discarded).</P></TD> | ||||
| 	</TR> | ||||
| 	<TR VALIGN=TOP> | ||||
| 		<TD><P>DrawnX</P></TD> | ||||
| 		<TD><P>smallint</P></TD> | ||||
| 		<TD><p>X can be 1 through 3.<br> | ||||
| 			This field denotes how many cards the player has drawn on each draw.</P></TD> | ||||
| 	</TR> | ||||
| 	<TR VALIGN=TOP> | ||||
| 		<TD><P>winnings</P></TD> | ||||
| 		<TD><P>int</P></TD> | ||||
|  |  | |||
|  | @ -444,9 +444,9 @@ class Config: | |||
|     def get_import_parameters(self): | ||||
|         imp = {} | ||||
|         try: | ||||
|             imp['callFpdbHud']   = self.callFpdbHud | ||||
|             imp['interval']      = self.interval | ||||
|             imp['hhArchiveBase'] = self.hhArchiveBase | ||||
|             imp['callFpdbHud']   = self.imp.callFpdbHud | ||||
|             imp['interval']      = self.imp.interval | ||||
|             imp['hhArchiveBase'] = self.imp.hhArchiveBase | ||||
|         except: # Default params | ||||
|             imp['callFpdbHud']   = True | ||||
|             imp['interval']      = 10 | ||||
|  | @ -613,9 +613,7 @@ if __name__== "__main__": | |||
|     print "----------- END POPUP WINDOW FORMATS -----------" | ||||
| 
 | ||||
|     print "\n----------- IMPORT -----------" | ||||
|     tmp = c.get_import_parameters() | ||||
|     for param in tmp: | ||||
|         print "    " + str(param) + ": " + str(tmp[param]) | ||||
|     print c.imp | ||||
|     print "----------- END IMPORT -----------" | ||||
| 
 | ||||
|     print "\n----------- TABLE VIEW -----------" | ||||
|  |  | |||
							
								
								
									
										187
									
								
								pyfpdb/EverleafToFpdb.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										187
									
								
								pyfpdb/EverleafToFpdb.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							|  | @ -58,42 +58,46 @@ from HandHistoryConverter import * | |||
| # smaragdar calls [$ 34.50 USD] | ||||
| # ** Dealing Turn ** [ 2d ] | ||||
| # ** Dealing River ** [ 6c ] | ||||
| # dogge shows [ 9h, 9c ]a pair of nines | ||||
| # spicybum shows [ 5d, 6d ]a straight, eight high | ||||
| # harrydebeng does not show cards | ||||
| # smaragdar wins $ 102 USD from main pot with a pair of aces [ ad, ah, qs, 8h, 6c ] | ||||
| 
 | ||||
| 
 | ||||
| class Everleaf(HandHistoryConverter): | ||||
| 	def __init__(self, config, file): | ||||
| 		print "Initialising Everleaf converter class" | ||||
| 		HandHistoryConverter.__init__(self, config, file, "Everleaf") # Call super class init. | ||||
| 		self.sitename = "Everleaf" | ||||
| 		self.setFileType("text") | ||||
| 		self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)') | ||||
| 		self.rexx.setSplitHandRegex('\n\n\n\n') | ||||
| 		self.rexx.setHandInfoRegex('.*#(?P<HID>[0-9]+)\n.*\nBlinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>.*) - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+):(?P<SEC>[0-9]+)\nTable (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)') | ||||
| 		self.rexx.setPlayerInfoRegex('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(  \$ (?P<CASH>[.0-9]+) USD \)') | ||||
| 		self.rexx.setPostSbRegex('.*\n(?P<PNAME>.*): posts small blind \[') | ||||
| 		self.rexx.setPostBbRegex('.*\n(?P<PNAME>.*): posts big blind \[') | ||||
| 		self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<HOLECARDS>.*) \]') | ||||
| 		self.rexx.setActionStepRegex('.*\n(?P<PNAME>.*) (?P<ATYPE>bets|checks|raises|calls|folds)(\s\[\$ (?P<BET>[.\d]+) USD\])?') | ||||
| 		self.rexx.compileRegexes() | ||||
|     def __init__(self, config, file): | ||||
|         print "Initialising Everleaf converter class" | ||||
|         HandHistoryConverter.__init__(self, config, file, sitename="Everleaf") # Call super class init. | ||||
|         self.sitename = "Everleaf" | ||||
|         self.setFileType("text") | ||||
|         self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)') | ||||
|         self.rexx.setSplitHandRegex('\n\n\n\n') | ||||
|         self.rexx.setHandInfoRegex('.*#(?P<HID>[0-9]+)\n.*\nBlinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>.*) - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+):(?P<SEC>[0-9]+)\nTable (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)') | ||||
|         self.rexx.setPlayerInfoRegex('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(  \$ (?P<CASH>[.0-9]+) USD \)') | ||||
|         self.rexx.setPostSbRegex('.*\n(?P<PNAME>.*): posts small blind \[\$? (?P<SB>[.0-9]+)') | ||||
|         self.rexx.setPostBbRegex('.*\n(?P<PNAME>.*): posts big blind \[\$? (?P<BB>[.0-9]+)') | ||||
|         # mct : what about posting small & big blinds simultaneously? | ||||
|         self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<HOLE1>\S\S), (?P<HOLE2>\S\S) \]') | ||||
|         self.rexx.setActionStepRegex('.*\n(?P<PNAME>.*) (?P<ATYPE>bets|checks|raises|calls|folds)(\s\[\$ (?P<BET>[.\d]+) USD\])?') | ||||
|         self.rexx.setShowdownActionRegex('.*\n(?P<PNAME>.*) shows \[ (?P<CARDS>.*) \]') | ||||
|         self.rexx.compileRegexes() | ||||
| 
 | ||||
|         def readSupportedGames(self): | ||||
| 		pass | ||||
|     def readSupportedGames(self): | ||||
|         pass | ||||
| 
 | ||||
|         def determineGameType(self): | ||||
| 		# Cheating with this regex, only support nlhe at the moment | ||||
| 		gametype = ["ring", "hold", "nl"] | ||||
|     def determineGameType(self): | ||||
|         # Cheating with this regex, only support nlhe at the moment | ||||
|         gametype = ["ring", "hold", "nl"] | ||||
| 
 | ||||
| 		m = self.rexx.game_info_re.search(self.obs) | ||||
| 		gametype = gametype + [m.group('SB')] | ||||
| 		gametype = gametype + [m.group('BB')] | ||||
| 		 | ||||
| 		return gametype | ||||
|         m = self.rexx.game_info_re.search(self.obs) | ||||
|         gametype = gametype + [m.group('SB')] | ||||
|         gametype = gametype + [m.group('BB')] | ||||
|          | ||||
|         return gametype | ||||
| 
 | ||||
| 	def readHandInfo(self, hand): | ||||
| 		m =  self.rexx.hand_info_re.search(hand.string) | ||||
| 		hand.handid = m.group('HID') | ||||
| 		hand.tablename = m.group('TABLE') | ||||
|     def readHandInfo(self, hand): | ||||
|         m =  self.rexx.hand_info_re.search(hand.string) | ||||
|         hand.handid = m.group('HID') | ||||
|         hand.tablename = m.group('TABLE') | ||||
| # These work, but the info is already in the Hand class - should be used for tourneys though. | ||||
| #		m.group('SB') | ||||
| #		m.group('BB') | ||||
|  | @ -106,66 +110,87 @@ class Everleaf(HandHistoryConverter): | |||
| # 2008/11/10 3:58:52 ET | ||||
| #TODO: Do conversion from GMT to ET | ||||
| #TODO: Need some date functions to convert to different timezones (Date::Manip for perl rocked for this) | ||||
| 		hand.starttime = "%d/%02d/%02d %d:%02d:%02d ET" %(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), | ||||
| 							  int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC'))) | ||||
| 		hand.buttonpos = int(m.group('BUTTON')) | ||||
|         hand.starttime = "%d/%02d/%02d %d:%02d:%02d ET" %(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), | ||||
|                             int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC'))) | ||||
|         hand.buttonpos = int(m.group('BUTTON')) | ||||
| 
 | ||||
|         def readPlayerStacks(self, hand): | ||||
| 		m = self.rexx.player_info_re.finditer(hand.string) | ||||
| 		players = [] | ||||
|     def readPlayerStacks(self, hand): | ||||
|         m = self.rexx.player_info_re.finditer(hand.string) | ||||
|         players = [] | ||||
| 
 | ||||
| 		for a in m: | ||||
| 			players = players + [[a.group('SEAT'), a.group('PNAME'), a.group('CASH')]] | ||||
|         for a in m: | ||||
|             hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH')) | ||||
| 
 | ||||
| 		hand.players = players | ||||
| 
 | ||||
| 	def markStreets(self, hand): | ||||
| 		# PREFLOP = ** Dealing down cards ** | ||||
| 		m = re.search('(\*\* Dealing down cards \*\*\n)(?P<PREFLOP>.*?\n\*\*)?( Dealing Flop \*\*)?(?P<FLOP>.*?\*\*)?( Dealing Turn \*\*)?(?P<TURN>.*?\*\*)?( Dealing River \*\*)?(?P<RIVER>.*)', hand.string,re.DOTALL) | ||||
|     def markStreets(self, hand): | ||||
|         # PREFLOP = ** Dealing down cards ** | ||||
|         m = re.search('(\*\* Dealing down cards \*\*\n)(?P<PREFLOP>.*?\n\*\*)?( Dealing Flop \*\* \[ (?P<FLOP1>\S\S), (?P<FLOP2>\S\S), (?P<FLOP3>\S\S) \])?(?P<FLOP>.*?\*\*)?( Dealing Turn \*\* \[ (?P<TURN1>\S\S) \])?(?P<TURN>.*?\*\*)?( Dealing River \*\* \[ (?P<RIVER1>\S\S) \])?(?P<RIVER>.*)', hand.string,re.DOTALL) | ||||
| #		for street in m.groupdict(): | ||||
| #			print "DEBUG: Street: %s\tspan: %s" %(street, str(m.span(street))) | ||||
| 		hand.streets = m | ||||
|         hand.streets = m | ||||
| 
 | ||||
|         def readBlinds(self, hand): | ||||
| 		try: | ||||
| 			m = self.rexx.small_blind_re.search(hand.string) | ||||
| 			hand.posted = [m.group('PNAME')] | ||||
| 		except: | ||||
| 			hand.posted = ["FpdbNBP"] | ||||
| 		m = self.rexx.big_blind_re.finditer(hand.string) | ||||
| 		for a in m: | ||||
| 			hand.posted = hand.posted + [a.group('PNAME')] | ||||
|     def readCommunityCards(self, hand): | ||||
|         # currently regex in wrong place pls fix my brain's fried | ||||
|         # what a mess! | ||||
|         re_board = re.compile('\*\* Dealing (?P<STREET>.*) \*\* \[ (?P<CARDS>.*) \]') | ||||
|         m = re_board.finditer(hand.string) | ||||
|         for street in m: | ||||
|             #print street.groups() | ||||
|             re_card = re.compile('(?P<CARD>[0-9tjqka][schd])') # look that's weird, hole cards have a capital rank but board cards are lower case? | ||||
|             cardsmatch = re_card.finditer(street.group('CARDS')) | ||||
|             hand.setCommunityCards(street.group('STREET'), [card.group('CARD') for card in cardsmatch]) | ||||
| 
 | ||||
| 	def readHeroCards(self, hand): | ||||
| 		m = self.rexx.hero_cards_re.search(hand.string) | ||||
| 		if(m == None): | ||||
| 			#Not involved in hand | ||||
| 			hand.involved = False | ||||
| 		else: | ||||
| 			hand.hero = m.group('PNAME') | ||||
| 			hand.holecards = m.group('HOLECARDS') | ||||
| 			hand.holecards = hand.holecards.replace(',','') | ||||
| 			#Must be a better way to do the following tr akqjt AKQJT | ||||
| 			hand.holecards = hand.holecards.replace('a','A') | ||||
| 			hand.holecards = hand.holecards.replace('k','K') | ||||
| 			hand.holecards = hand.holecards.replace('q','Q') | ||||
| 			hand.holecards = hand.holecards.replace('j','J') | ||||
| 			hand.holecards = hand.holecards.replace('t','T') | ||||
|     def readBlinds(self, hand): | ||||
|         try: | ||||
|             m = self.rexx.small_blind_re.search(hand.string) | ||||
|             hand.addBlind(m.group('PNAME'), m.group('SB')) | ||||
|             #hand.posted = [m.group('PNAME')] | ||||
|         except: | ||||
|             hand.addBlind(None, 0) | ||||
|             #hand.posted = ["FpdbNBP"] | ||||
|         m = self.rexx.big_blind_re.finditer(hand.string) | ||||
|         for a in m: | ||||
|             hand.addBlind(a.group('PNAME'), a.group('BB')) | ||||
|             #hand.posted = hand.posted + [a.group('PNAME')] | ||||
| 
 | ||||
|         def readAction(self, hand, street): | ||||
| 		m = self.rexx.action_re.finditer(hand.streets.group(street)) | ||||
| 		hand.actions[street] = [] | ||||
| 		for action in m: | ||||
| 			if action.group('ATYPE') == 'raises' or action.group('ATYPE') == 'calls': | ||||
| 				hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE'), action.group('BET')]] | ||||
| 			else: | ||||
| 				hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE')]] | ||||
| 		print "DEBUG: readAction: %s " %(hand.actions) | ||||
|     def readHeroCards(self, hand): | ||||
|         m = self.rexx.hero_cards_re.search(hand.string) | ||||
|         if(m == None): | ||||
|             #Not involved in hand | ||||
|             hand.involved = False | ||||
|         else: | ||||
|             hand.hero = m.group('PNAME') | ||||
|             hand.addHoleCards([m.group('HOLE1'), m.group('HOLE2')], m.group('PNAME')) | ||||
| 
 | ||||
|     def readAction(self, hand, street): | ||||
|         m = self.rexx.action_re.finditer(hand.streets.group(street)) | ||||
|         hand.actions[street] = [] | ||||
|         for action in m: | ||||
|             if action.group('ATYPE') == 'raises': | ||||
|                 hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') ) | ||||
|             elif action.group('ATYPE') == 'calls': | ||||
|                 hand.addCall( street, action.group('PNAME'), action.group('BET') ) | ||||
|             elif action.group('ATYPE') == 'bets': | ||||
|                 hand.addBet( street, action.group('PNAME'), action.group('BET') ) | ||||
|             else: | ||||
|                 #print "DEBUG: unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),) | ||||
|                 hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE')]] | ||||
| 
 | ||||
| 
 | ||||
|     def readShowdownActions(self, hand): | ||||
|         for shows in self.rexx.showdown_action_re.finditer(hand.string): | ||||
|             print shows.groups() | ||||
|             re_card = re.compile('(?P<CARD>[0-9tjqka][schd])')  # copied from earlier | ||||
|             cards = [card.group('CARD') for card in re_card.finditer(shows.group('CARDS'))] | ||||
|             print cards | ||||
|             hand.addHoleCards(cards, shows.group('PNAME')) | ||||
|              | ||||
| 
 | ||||
|     def getRake(self, hand): | ||||
|         hand.rake = hand.totalpot * Decimal('0.05') # probably not quite right | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
| 	c = Configuration.Config() | ||||
| 	e = Everleaf(c, "regression-test-files/everleaf/Speed_Kuala.txt") | ||||
| 	e.processFile() | ||||
| 	print str(e) | ||||
| 	 | ||||
|     c = Configuration.Config() | ||||
|     e = Everleaf(c, "Speed_Kuala.txt") | ||||
|     e.processFile() | ||||
|     print str(e) | ||||
|      | ||||
|  |  | |||
|  | @ -573,6 +573,27 @@ class FpdbSQLQueries: | |||
|     	elif(self.dbname == 'SQLite'): | ||||
|     		self.query['createHudCacheTable'] = """ """ | ||||
| 
 | ||||
|         if(self.dbname == 'MySQL InnoDB'): | ||||
|             self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)""" | ||||
|         elif(self.dbname == 'PostgreSQL'): | ||||
|             self.query['addTourneyIndex'] = """CREATE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" | ||||
|         elif(self.dbname == 'SQLite'): | ||||
|             self.query['addHandsIndex'] = """ """ | ||||
| 
 | ||||
|         if(self.dbname == 'MySQL InnoDB'): | ||||
|             self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)""" | ||||
|         elif(self.dbname == 'PostgreSQL'): | ||||
|             self.query['addHandsIndex'] = """CREATE INDEX siteHandNo ON Hands (siteHandNo)""" | ||||
|         elif(self.dbname == 'SQLite'): | ||||
|             self.query['addHandsIndex'] = """ """ | ||||
| 
 | ||||
|         if(self.dbname == 'MySQL InnoDB'): | ||||
|             self.query['addPlayersIndex'] = """ALTER TABLE Players ADD INDEX name(name)""" | ||||
|         elif(self.dbname == 'PostgreSQL'): | ||||
|             self.query['addPlayersIndex'] = """CREATE INDEX name ON Players (name)""" | ||||
|         elif(self.dbname == 'SQLite'): | ||||
|             self.query['addPlayersIndex'] = """ """ | ||||
| 
 | ||||
|     	################################ | ||||
|     	# Queries used in GuiGraphViewer | ||||
|     	################################ | ||||
|  | @ -609,6 +630,11 @@ class FpdbSQLQueries: | |||
|     				WHERE Players.name = %s AND HandsPlayers.handId = %s  | ||||
|     				AND Players.siteId = %s AND (tourneysPlayersId IS NULL)""" | ||||
| 
 | ||||
|     	if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL'): | ||||
|     		self.query['getPlayerId'] = """SELECT id from Players where name = %s""" | ||||
|     	elif(self.dbname == 'SQLite'): | ||||
|     		self.query['getPlayerId'] = """SELECT id from Players where name = %s""" | ||||
| 
 | ||||
|     	if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL'): | ||||
|     		self.query['getRingProfitAllHandsPlayerIdSite'] = """ | ||||
|     			SELECT hp.handId, hp.winnings, SUM(ha.amount), hp.winnings - SUM(ha.amount) | ||||
|  | @ -673,13 +699,11 @@ class FpdbSQLQueries: | |||
|                            ,round(100*sum(street2Aggr)/sum(street2Seen)) AS TuAFq | ||||
|                            ,round(100*sum(street3Aggr)/sum(street3Seen)) AS RvAFq | ||||
|                            ,round(100*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr)) | ||||
| 
 | ||||
|                 /(sum(street1Seen)+sum(street2Seen)+sum(street3Seen))) AS PFAFq | ||||
|                      from Gametypes gt | ||||
|                           inner join Sites s on s.Id = gt.siteId | ||||
|                           inner join HudCache hc on hc.gameTypeId = gt.Id | ||||
|                      where gt.limittype = 'nl' | ||||
|                      and   hc.playerId in (3)   # use <player_test> here? | ||||
|                      where hc.playerId in <player_test> | ||||
|                                                 # use <gametype_test> here ? | ||||
|                      group by hc.gametypeId | ||||
|                     ) stats | ||||
|  | @ -692,7 +716,7 @@ class FpdbSQLQueries: | |||
|                           from HandsPlayers hp | ||||
|                           inner join Hands h         ON h.id            = hp.handId | ||||
|                           inner join HandsActions ha ON ha.handPlayerId = hp.id | ||||
|                           where hp.playerId in (3)   # use <player_test> here? | ||||
|                           where hp.playerId in <player_test> | ||||
|                                                      # use <gametype_test> here ? | ||||
|                           and   hp.tourneysPlayersId IS NULL | ||||
|                           group by hp.handId, h.gameTypeId, hp.position, hp.winnings | ||||
|  |  | |||
|  | @ -24,289 +24,300 @@ from time import time | |||
| #import pokereval | ||||
| 
 | ||||
| try: | ||||
| 	import matplotlib | ||||
| 	matplotlib.use('GTK') | ||||
| 	from matplotlib.figure import Figure | ||||
| 	from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas | ||||
| 	from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar | ||||
| 	from numpy import arange, cumsum | ||||
| 	from pylab import * | ||||
|     import matplotlib | ||||
|     matplotlib.use('GTK') | ||||
|     from matplotlib.figure import Figure | ||||
|     from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas | ||||
|     from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar | ||||
|     from numpy import arange, cumsum | ||||
|     from pylab import * | ||||
| except: | ||||
| 	print """Failed to load libs for graphing, graphing will not function. Please in | ||||
|     print """Failed to load libs for graphing, graphing will not function. Please in | ||||
|                  stall numpy and matplotlib if you want to use graphs.""" | ||||
| 	print """This is of no consequence for other parts of the program, e.g. import  | ||||
| 		 and HUD are NOT affected by this problem.""" | ||||
|     print """This is of no consequence for other parts of the program, e.g. import  | ||||
|          and HUD are NOT affected by this problem.""" | ||||
| 
 | ||||
| import fpdb_import | ||||
| import fpdb_db | ||||
| 
 | ||||
| class GuiGraphViewer (threading.Thread): | ||||
| 	def get_vbox(self): | ||||
| 		"""returns the vbox of this thread""" | ||||
| 		return self.mainHBox | ||||
| 	#end def get_vbox | ||||
| 	 | ||||
| 	def generateGraph(self, widget, data): | ||||
| 		try: self.canvas.destroy() | ||||
| 		except AttributeError: pass | ||||
|     def get_vbox(self): | ||||
|         """returns the vbox of this thread""" | ||||
|         return self.mainHBox | ||||
|     #end def get_vbox | ||||
| 
 | ||||
| 		# Whaich sites are selected? | ||||
| 		# TODO: | ||||
| 		# What hero names for the selected site? | ||||
| 		# TODO: | ||||
|     def generateGraph(self, widget, data): | ||||
|         try: self.canvas.destroy() | ||||
|         except AttributeError: pass | ||||
| 
 | ||||
| 		name = self.heroes[self.sites] | ||||
| 		 | ||||
| 		if self.sites == "PokerStars": | ||||
| 			site=2 | ||||
| 			sitename="PokerStars: " | ||||
| 		elif self.sites=="Full Tilt": | ||||
| 			site=1 | ||||
| 			sitename="Full Tilt: " | ||||
| 		else: | ||||
| 			print "invalid text in site selection in graph, defaulting to PS" | ||||
| 			site=2 | ||||
| 		 | ||||
| 		self.fig = Figure(figsize=(5,4), dpi=100) | ||||
|         # Whaich sites are selected? | ||||
|         # TODO: | ||||
|         # What hero names for the selected site? | ||||
|         # TODO: | ||||
| 
 | ||||
| 		#Set graph properties | ||||
| 		self.ax = self.fig.add_subplot(111) | ||||
|         name = self.heroes[self.sites] | ||||
| 
 | ||||
| 		#Get graph data from DB | ||||
| 		starttime = time() | ||||
| 		line = self.getRingProfitGraph(name, site) | ||||
| 		print "Graph generated in: %s" %(time() - starttime) | ||||
|         if self.sites == "PokerStars": | ||||
|             site=2 | ||||
|             sitename="PokerStars: " | ||||
|         elif self.sites=="Full Tilt": | ||||
|             site=1 | ||||
|             sitename="Full Tilt: " | ||||
|         else: | ||||
|             print "invalid text in site selection in graph, defaulting to PS" | ||||
|             site=2 | ||||
| 
 | ||||
| 		self.ax.set_title("Profit graph for ring games") | ||||
|         self.fig = Figure(figsize=(5,4), dpi=100) | ||||
| 
 | ||||
| 		#Set axis labels and grid overlay properites | ||||
| 		self.ax.set_xlabel("Hands", fontsize = 12) | ||||
| 		self.ax.set_ylabel("$", fontsize = 12) | ||||
| 		self.ax.grid(color='g', linestyle=':', linewidth=0.2) | ||||
| 		text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) | ||||
|         #Set graph properties | ||||
|         self.ax = self.fig.add_subplot(111) | ||||
| 
 | ||||
| 		self.ax.annotate(text, xy=(10, -10), | ||||
|                 xycoords='axes points', | ||||
|                 horizontalalignment='left', verticalalignment='top', | ||||
|                 fontsize=10) | ||||
|         #Get graph data from DB | ||||
|         starttime = time() | ||||
|         line = self.getRingProfitGraph(name, site) | ||||
|         print "Graph generated in: %s" %(time() - starttime) | ||||
| 
 | ||||
|         self.ax.set_title("Profit graph for ring games") | ||||
| 
 | ||||
|         #Set axis labels and grid overlay properites | ||||
|         self.ax.set_xlabel("Hands", fontsize = 12) | ||||
|         self.ax.set_ylabel("$", fontsize = 12) | ||||
|         self.ax.grid(color='g', linestyle=':', linewidth=0.2) | ||||
|         #This line will crash if no hands exist in the query. | ||||
|         text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) | ||||
| 
 | ||||
|         self.ax.annotate(text,  | ||||
|                         xy=(10, -10), | ||||
|                         xycoords='axes points', | ||||
|                         horizontalalignment='left', verticalalignment='top', | ||||
|                         fontsize=10) | ||||
| 
 | ||||
| 
 | ||||
| 		#Draw plot | ||||
| 		self.ax.plot(line,) | ||||
|         #Draw plot | ||||
|         self.ax.plot(line,) | ||||
| 
 | ||||
| 		self.canvas = FigureCanvas(self.fig)  # a gtk.DrawingArea | ||||
| 		self.graphBox.add(self.canvas) | ||||
| 		self.canvas.show() | ||||
| 	#end of def showClicked | ||||
|         self.canvas = FigureCanvas(self.fig)  # a gtk.DrawingArea | ||||
|         self.graphBox.add(self.canvas) | ||||
|         self.canvas.show() | ||||
|     #end of def showClicked | ||||
| 
 | ||||
| 	def getRingProfitGraph(self, name, site): | ||||
| 		self.cursor.execute(self.sql.query['getRingProfitAllHandsPlayerIdSite'], (name, site)) | ||||
| 		#       returns (HandId,Winnings,Costs,Profit) | ||||
|                 winnings = self.db.cursor.fetchall() | ||||
|     def getRingProfitGraph(self, name, site): | ||||
|         self.cursor.execute(self.sql.query['getRingProfitAllHandsPlayerIdSite'], (name, site)) | ||||
|         #returns (HandId,Winnings,Costs,Profit) | ||||
|         winnings = self.db.cursor.fetchall() | ||||
| 
 | ||||
|                 y=map(lambda x:float(x[3]), winnings) | ||||
|                 line = cumsum(y) | ||||
|                 return line/100 | ||||
|         y=map(lambda x:float(x[3]), winnings) | ||||
|         line = cumsum(y) | ||||
|         return line/100 | ||||
|         #end of def getRingProfitGraph | ||||
| 
 | ||||
| 	def createPlayerLine(self, hbox, site, player): | ||||
| 		label = gtk.Label(site +" id:") | ||||
| 		hbox.pack_start(label, False, False, 0) | ||||
| 		label.show() | ||||
|     def createPlayerLine(self, hbox, site, player): | ||||
|         label = gtk.Label(site +" id:") | ||||
|         hbox.pack_start(label, False, False, 0) | ||||
|         label.show() | ||||
| 
 | ||||
| 		pname = gtk.Entry() | ||||
| 		pname.set_text(player) | ||||
| 		pname.set_width_chars(20) | ||||
| 		hbox.pack_start(pname, False, True, 0) | ||||
| 		#TODO: Need to connect a callback here | ||||
| 		pname.connect("changed", self.__set_hero_name, site) | ||||
| 		#TODO: Look at GtkCompletion - to fill out usernames | ||||
| 		pname.show() | ||||
|         pname = gtk.Entry() | ||||
|         pname.set_text(player) | ||||
|         pname.set_width_chars(20) | ||||
|         hbox.pack_start(pname, False, True, 0) | ||||
|         #TODO: Need to connect a callback here | ||||
|         pname.connect("changed", self.__set_hero_name, site) | ||||
|         #TODO: Look at GtkCompletion - to fill out usernames | ||||
|         pname.show() | ||||
| 
 | ||||
| 		self.__set_hero_name(pname, site) | ||||
|         self.__set_hero_name(pname, site) | ||||
| 
 | ||||
| 	def __set_hero_name(self, w, site): | ||||
| 		self.heroes[site] = w.get_text() | ||||
| 		print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site]) | ||||
|     def __set_hero_name(self, w, site): | ||||
|         self.heroes[site] = w.get_text() | ||||
|         print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site]) | ||||
| 
 | ||||
| 	def createSiteLine(self, hbox, site): | ||||
|                 cb = gtk.CheckButton(site) | ||||
| 		cb.connect('clicked', self.__set_site_select, site) | ||||
| 		hbox.pack_start(cb, False, False, 0) | ||||
|                 cb.show() | ||||
|     def createSiteLine(self, hbox, site): | ||||
|         cb = gtk.CheckButton(site) | ||||
|         cb.connect('clicked', self.__set_site_select, site) | ||||
|         hbox.pack_start(cb, False, False, 0) | ||||
|         cb.show() | ||||
| 
 | ||||
| 	def __set_site_select(self, w, site): | ||||
| 		# This doesn't behave as intended - self.site only allows 1 site for the moment. | ||||
| 		self.sites = site | ||||
| 		print "self.sites set to %s" %(self.sites) | ||||
|     def __set_site_select(self, w, site): | ||||
|         # This doesn't behave as intended - self.site only allows 1 site for the moment. | ||||
|         self.sites = site | ||||
|         print "self.sites set to %s" %(self.sites) | ||||
| 
 | ||||
| 	def fillPlayerFrame(self, vbox): | ||||
| 		for site in self.conf.supported_sites.keys(): | ||||
| 			pathHBox = gtk.HBox(False, 0) | ||||
| 			vbox.pack_start(pathHBox, False, True, 0) | ||||
| 			pathHBox.show() | ||||
|     def fillPlayerFrame(self, vbox): | ||||
|         for site in self.conf.supported_sites.keys(): | ||||
|             pathHBox = gtk.HBox(False, 0) | ||||
|             vbox.pack_start(pathHBox, False, True, 0) | ||||
|             pathHBox.show() | ||||
| 
 | ||||
| 			player = self.conf.supported_sites[site].screen_name | ||||
| 			self.createPlayerLine(pathHBox, site, player) | ||||
|             player = self.conf.supported_sites[site].screen_name | ||||
|             self.createPlayerLine(pathHBox, site, player) | ||||
| 
 | ||||
| 	def fillSitesFrame(self, vbox): | ||||
| 		for site in self.conf.supported_sites.keys(): | ||||
|                         hbox = gtk.HBox(False, 0) | ||||
|                         vbox.pack_start(hbox, False, True, 0) | ||||
|                         hbox.show() | ||||
| 			self.createSiteLine(hbox, site) | ||||
|     def fillSitesFrame(self, vbox): | ||||
|         for site in self.conf.supported_sites.keys(): | ||||
|             hbox = gtk.HBox(False, 0) | ||||
|             vbox.pack_start(hbox, False, True, 0) | ||||
|             hbox.show() | ||||
|             self.createSiteLine(hbox, site) | ||||
| 
 | ||||
| 	def fillDateFrame(self, vbox): | ||||
| 		# Hat tip to Mika Bostrom - calendar code comes from PokerStats | ||||
| 		hbox = gtk.HBox() | ||||
| 		vbox.pack_start(hbox, False, True, 0) | ||||
| 		hbox.show() | ||||
|     def fillDateFrame(self, vbox): | ||||
|         # Hat tip to Mika Bostrom - calendar code comes from PokerStats | ||||
|         hbox = gtk.HBox() | ||||
|         vbox.pack_start(hbox, False, True, 0) | ||||
|         hbox.show() | ||||
| 
 | ||||
| 		lbl_start = gtk.Label('From:') | ||||
| 		lbl_start.show() | ||||
|         lbl_start = gtk.Label('From:') | ||||
|         lbl_start.show() | ||||
| 
 | ||||
| 		btn_start = gtk.Button() | ||||
| 		btn_start.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)) | ||||
| 		btn_start.connect('clicked', self.__calendar_dialog, self.start_date) | ||||
| 		btn_start.show() | ||||
|         btn_start = gtk.Button() | ||||
|         btn_start.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)) | ||||
|         btn_start.connect('clicked', self.__calendar_dialog, self.start_date) | ||||
|         btn_start.show() | ||||
| 
 | ||||
| 		hbox.pack_start(lbl_start, expand=False, padding=3) | ||||
| 		hbox.pack_start(btn_start, expand=False, padding=3) | ||||
| 		hbox.pack_start(self.start_date, expand=False, padding=2) | ||||
| 		self.start_date.show() | ||||
|         hbox.pack_start(lbl_start, expand=False, padding=3) | ||||
|         hbox.pack_start(btn_start, expand=False, padding=3) | ||||
|         hbox.pack_start(self.start_date, expand=False, padding=2) | ||||
|         self.start_date.show() | ||||
| 
 | ||||
| 		#New row for end date | ||||
| 		hbox = gtk.HBox() | ||||
| 		vbox.pack_start(hbox, False, True, 0) | ||||
| 		hbox.show() | ||||
|         #New row for end date | ||||
|         hbox = gtk.HBox() | ||||
|         vbox.pack_start(hbox, False, True, 0) | ||||
|         hbox.show() | ||||
| 
 | ||||
| 	        lbl_end = gtk.Label('  To:') | ||||
| 		lbl_end.show() | ||||
| 		btn_end = gtk.Button() | ||||
| 		btn_end.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)) | ||||
| 		btn_end.connect('clicked', self.__calendar_dialog, self.end_date) | ||||
| 		btn_end.show() | ||||
|         lbl_end = gtk.Label('  To:') | ||||
|         lbl_end.show() | ||||
|         btn_end = gtk.Button() | ||||
|         btn_end.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)) | ||||
|         btn_end.connect('clicked', self.__calendar_dialog, self.end_date) | ||||
|         btn_end.show() | ||||
| 
 | ||||
| 		btn_clear = gtk.Button(label=' Clear Dates ') | ||||
| 		btn_clear.connect('clicked', self.__clear_dates) | ||||
| 		btn_clear.show() | ||||
|         btn_clear = gtk.Button(label=' Clear Dates ') | ||||
|         btn_clear.connect('clicked', self.__clear_dates) | ||||
|         btn_clear.show() | ||||
| 
 | ||||
| 		hbox.pack_start(lbl_end, expand=False, padding=3) | ||||
| 		hbox.pack_start(btn_end, expand=False, padding=3) | ||||
| 		hbox.pack_start(self.end_date, expand=False, padding=2) | ||||
| 		self.end_date.show() | ||||
|         hbox.pack_start(lbl_end, expand=False, padding=3) | ||||
|         hbox.pack_start(btn_end, expand=False, padding=3) | ||||
|         hbox.pack_start(self.end_date, expand=False, padding=2) | ||||
|         self.end_date.show() | ||||
| 
 | ||||
| 		hbox.pack_start(btn_clear, expand=False, padding=15) | ||||
|         hbox.pack_start(btn_clear, expand=False, padding=15) | ||||
| 
 | ||||
| 	def __calendar_dialog(self, widget, entry): | ||||
| 		d = gtk.Window(gtk.WINDOW_TOPLEVEL) | ||||
| 		d.set_title('Pick a date') | ||||
|     def __calendar_dialog(self, widget, entry): | ||||
|         d = gtk.Window(gtk.WINDOW_TOPLEVEL) | ||||
|         d.set_title('Pick a date') | ||||
| 
 | ||||
| 		vb = gtk.VBox() | ||||
| 		cal = gtk.Calendar() | ||||
| 		vb.pack_start(cal, expand=False, padding=0) | ||||
|         vb = gtk.VBox() | ||||
|         cal = gtk.Calendar() | ||||
|         vb.pack_start(cal, expand=False, padding=0) | ||||
| 
 | ||||
| 		btn = gtk.Button('Done') | ||||
| 		btn.connect('clicked', self.__get_date, cal, entry, d) | ||||
|         btn = gtk.Button('Done') | ||||
|         btn.connect('clicked', self.__get_date, cal, entry, d) | ||||
| 
 | ||||
| 		vb.pack_start(btn, expand=False, padding=4) | ||||
|         vb.pack_start(btn, expand=False, padding=4) | ||||
| 
 | ||||
| 		d.add(vb) | ||||
| 		d.set_position(gtk.WIN_POS_MOUSE) | ||||
| 		d.show_all() | ||||
|         d.add(vb) | ||||
|         d.set_position(gtk.WIN_POS_MOUSE) | ||||
|         d.show_all() | ||||
| 
 | ||||
| 	def __clear_dates(self, w): | ||||
| 		self.start_date.set_text('') | ||||
| 		self.end_date.set_text('') | ||||
|     def __clear_dates(self, w): | ||||
|         self.start_date.set_text('') | ||||
|         self.end_date.set_text('') | ||||
| 
 | ||||
| 	def __get_dates(self): | ||||
| 		t1 = self.start_date.get_text() | ||||
| 		t2 = self.end_date.get_text() | ||||
| 		return (t1, t2) | ||||
|     def __get_dates(self): | ||||
|         t1 = self.start_date.get_text() | ||||
|         t2 = self.end_date.get_text() | ||||
|         return (t1, t2) | ||||
| 
 | ||||
| 	def __get_date(self, widget, calendar, entry, win): | ||||
|     def __get_date(self, widget, calendar, entry, win): | ||||
| # year and day are correct, month is 0..11 | ||||
| 		(year, month, day) = calendar.get_date() | ||||
| 		month += 1 | ||||
| 		ds = '%04d-%02d-%02d' % (year, month, day) | ||||
| 		entry.set_text(ds) | ||||
| 		win.destroy() | ||||
|         (year, month, day) = calendar.get_date() | ||||
|         month += 1 | ||||
|         ds = '%04d-%02d-%02d' % (year, month, day) | ||||
|         entry.set_text(ds) | ||||
|         win.destroy() | ||||
| 
 | ||||
| 	def __init__(self, db, settings, querylist, config, debug=True): | ||||
| 		"""Constructor for GraphViewer""" | ||||
| 		self.debug=debug | ||||
| 		#print "start of GraphViewer constructor" | ||||
| 		self.db=db | ||||
| 		self.cursor=db.cursor | ||||
| 		self.settings=settings | ||||
| 		self.sql=querylist | ||||
| 		self.conf = config | ||||
|     def exportGraph (self, widget, data): | ||||
|         dia_chooser = gtk.FileChooserDialog(title="Please choose the directory you wish to export to:", | ||||
|                                             action=gtk.FILE_CHOOSER_ACTION_OPEN, | ||||
|                                             buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) | ||||
| 
 | ||||
| 		self.sites = "PokerStars" | ||||
| 		self.heroes = {} | ||||
|         response = dia_chooser.run() | ||||
|         if response == gtk.RESPONSE_OK: | ||||
|             self.exportDir = dia_chooser.get_filename() | ||||
|         elif response == gtk.RESPONSE_CANCEL: | ||||
|             print 'Closed, no graph exported' | ||||
|         dia_chooser.destroy() | ||||
| 
 | ||||
| 		# For use in date ranges. | ||||
| 		self.start_date = gtk.Entry(max=12) | ||||
| 		self.end_date = gtk.Entry(max=12) | ||||
| 		self.start_date.set_property('editable', False) | ||||
| 		self.end_date.set_property('editable', False) | ||||
|     def __init__(self, db, settings, querylist, config, debug=True): | ||||
|         """Constructor for GraphViewer""" | ||||
|         self.debug=debug | ||||
|         #print "start of GraphViewer constructor" | ||||
|         self.db=db | ||||
|         self.cursor=db.cursor | ||||
|         self.settings=settings | ||||
|         self.sql=querylist | ||||
|         self.conf = config | ||||
| 
 | ||||
|         self.sites = "PokerStars" | ||||
|         self.heroes = {} | ||||
| 
 | ||||
|         # For use in date ranges. | ||||
|         self.start_date = gtk.Entry(max=12) | ||||
|         self.end_date = gtk.Entry(max=12) | ||||
|         self.start_date.set_property('editable', False) | ||||
|         self.end_date.set_property('editable', False) | ||||
|          | ||||
| 		self.mainHBox = gtk.HBox(False, 0) | ||||
|                 self.mainHBox.show() | ||||
|         self.mainHBox = gtk.HBox(False, 0) | ||||
|         self.mainHBox.show() | ||||
| 
 | ||||
| 		self.leftPanelBox = gtk.VBox(False, 0) | ||||
|                 self.graphBox = gtk.VBox(False, 0) | ||||
|         self.leftPanelBox = gtk.VBox(False, 0) | ||||
|         self.graphBox = gtk.VBox(False, 0) | ||||
| 
 | ||||
| 		self.hpane = gtk.HPaned() | ||||
| 		self.hpane.pack1(self.leftPanelBox) | ||||
| 		self.hpane.pack2(self.graphBox) | ||||
| 		self.hpane.show() | ||||
|         self.hpane = gtk.HPaned() | ||||
|         self.hpane.pack1(self.leftPanelBox) | ||||
|         self.hpane.pack2(self.graphBox) | ||||
|         self.hpane.show() | ||||
| 
 | ||||
| 		self.mainHBox.add(self.hpane) | ||||
|         self.mainHBox.add(self.hpane) | ||||
| 
 | ||||
| 		playerFrame = gtk.Frame("Hero:") | ||||
|                 playerFrame.set_label_align(0.0, 0.0) | ||||
|                 playerFrame.show() | ||||
|                 vbox = gtk.VBox(False, 0) | ||||
|                 vbox.show() | ||||
|         playerFrame = gtk.Frame("Hero:") | ||||
|         playerFrame.set_label_align(0.0, 0.0) | ||||
|         playerFrame.show() | ||||
|         vbox = gtk.VBox(False, 0) | ||||
|         vbox.show() | ||||
| 
 | ||||
| 		self.fillPlayerFrame(vbox) | ||||
|                 playerFrame.add(vbox) | ||||
|         self.fillPlayerFrame(vbox) | ||||
|         playerFrame.add(vbox) | ||||
| 
 | ||||
|                 sitesFrame = gtk.Frame("Sites:") | ||||
|                 sitesFrame.set_label_align(0.0, 0.0) | ||||
|                 sitesFrame.show() | ||||
|                 vbox = gtk.VBox(False, 0) | ||||
|                 vbox.show() | ||||
|         sitesFrame = gtk.Frame("Sites:") | ||||
|         sitesFrame.set_label_align(0.0, 0.0) | ||||
|         sitesFrame.show() | ||||
|         vbox = gtk.VBox(False, 0) | ||||
|         vbox.show() | ||||
| 
 | ||||
| 		self.fillSitesFrame(vbox) | ||||
|                 sitesFrame.add(vbox) | ||||
|         self.fillSitesFrame(vbox) | ||||
|         sitesFrame.add(vbox) | ||||
| 
 | ||||
|                 dateFrame = gtk.Frame("Date:") | ||||
|                 dateFrame.set_label_align(0.0, 0.0) | ||||
|                 dateFrame.show() | ||||
|                 vbox = gtk.VBox(False, 0) | ||||
|                 vbox.show() | ||||
|         dateFrame = gtk.Frame("Date:") | ||||
|         dateFrame.set_label_align(0.0, 0.0) | ||||
|         dateFrame.show() | ||||
|         vbox = gtk.VBox(False, 0) | ||||
|         vbox.show() | ||||
| 
 | ||||
| 		self.fillDateFrame(vbox) | ||||
|                 dateFrame.add(vbox) | ||||
|         self.fillDateFrame(vbox) | ||||
|         dateFrame.add(vbox) | ||||
| 
 | ||||
|                 graphButton=gtk.Button("Generate Graph") | ||||
|                 graphButton.connect("clicked", self.generateGraph, "cliced data") | ||||
|                 graphButton.show() | ||||
|         graphButton=gtk.Button("Generate Graph") | ||||
|         graphButton.connect("clicked", self.generateGraph, "cliced data") | ||||
|         graphButton.show() | ||||
| 
 | ||||
|                 self.exportButton=gtk.Button("Export to File") | ||||
| #@              self.exportButton.connect("clicked", self.exportGraph, "show clicked") | ||||
|                 self.exportButton.show() | ||||
|         self.exportButton=gtk.Button("Export to File") | ||||
|         self.exportButton.connect("clicked", self.exportGraph, "show clicked") | ||||
|         self.exportButton.show() | ||||
| 
 | ||||
|                 self.leftPanelBox.add(playerFrame) | ||||
|                 self.leftPanelBox.add(sitesFrame) | ||||
|                 self.leftPanelBox.add(dateFrame) | ||||
|                 self.leftPanelBox.add(graphButton) | ||||
|                 self.leftPanelBox.add(self.exportButton) | ||||
|         self.leftPanelBox.add(playerFrame) | ||||
|         self.leftPanelBox.add(sitesFrame) | ||||
|         self.leftPanelBox.add(dateFrame) | ||||
|         self.leftPanelBox.add(graphButton) | ||||
|         self.leftPanelBox.add(self.exportButton) | ||||
| 
 | ||||
|                 self.leftPanelBox.show() | ||||
|                 self.graphBox.show()	 | ||||
| 	 | ||||
| 		#Note: Assumes PokerStars is in the config | ||||
| 	#	self.nameEntry.set_text(self.conf.supported_sites["PokerStars"].screen_name) | ||||
|         self.leftPanelBox.show() | ||||
|         self.graphBox.show() | ||||
|  |  | |||
							
								
								
									
										165
									
								
								pyfpdb/GuiPlayerStats.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								pyfpdb/GuiPlayerStats.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,165 @@ | |||
| #!/usr/bin/python | ||||
| 
 | ||||
| #Copyright 2008 Steffen Jobbagy-Felso | ||||
| #This program is free software: you can redistribute it and/or modify | ||||
| #it under the terms of the GNU Affero General Public License as published by | ||||
| #the Free Software Foundation, version 3 of the License. | ||||
| # | ||||
| #This program is distributed in the hope that it will be useful, | ||||
| #but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| #GNU General Public License for more details. | ||||
| # | ||||
| #You should have received a copy of the GNU Affero General Public License | ||||
| #along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
| #In the "official" distribution you can find the license in | ||||
| #agpl-3.0.txt in the docs folder of the package. | ||||
| 
 | ||||
| import threading | ||||
| import pygtk | ||||
| pygtk.require('2.0') | ||||
| import gtk | ||||
| import os | ||||
|      | ||||
| import fpdb_import | ||||
| import fpdb_db | ||||
| import FpdbSQLQueries | ||||
| 
 | ||||
| class GuiPlayerStats (threading.Thread): | ||||
|     def get_vbox(self): | ||||
|         """returns the vbox of this thread""" | ||||
|         return self.main_hbox | ||||
| 
 | ||||
|     def toggleCallback(self, widget, data=None): | ||||
| #        print "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()]) | ||||
|         self.activesite = data | ||||
|         print "DEBUG: activesite set to %s" %(self.activesite) | ||||
| 
 | ||||
|     def refreshStats(self, widget, data): | ||||
|         try: self.stats_table.destroy() | ||||
|         except AttributeError: pass | ||||
|         self.fillStatsFrame(self.stats_frame) | ||||
| 
 | ||||
|     def fillStatsFrame(self, vbox): | ||||
|         # Get currently active site and grab playerid | ||||
|         tmp = self.sql.query['playerStats'] | ||||
| 
 | ||||
|         result = self.cursor.execute(self.sql.query['getPlayerId'], self.heroes[self.activesite]) | ||||
|         result = self.db.cursor.fetchall() | ||||
|         pid = result[0][0] | ||||
|         tmp = tmp.replace("<player_test>", "(" + str(pid) + ")") | ||||
|         self.cursor.execute(tmp) | ||||
|         result = self.db.cursor.fetchall() | ||||
|         cols = 18 | ||||
|         rows = len(result)+1 # +1 for title row | ||||
|         self.stats_table = gtk.Table(rows, cols, False) | ||||
|         self.stats_table.set_col_spacings(4) | ||||
|         self.stats_table.show() | ||||
|         vbox.add(self.stats_table) | ||||
| 
 | ||||
|         # Create header row | ||||
|         titles = ("GID", "base", "Style", "Site", "$BB", "Hands", "VPIP", "PFR", "saw_f", "sawsd", "wtsdwsf", "wmsd", "FlAFq", "TuAFq", "RvAFq", "PFAFq", "Net($)", "BB/100") | ||||
| 
 | ||||
|         col = 0 | ||||
|         row = 0 | ||||
|         for t in titles: | ||||
|             l = gtk.Label(titles[col]) | ||||
|             l.show() | ||||
|             self.stats_table.attach(l, col, col+1, row, row+1) | ||||
|             col +=1  | ||||
| 
 | ||||
|         for row in range(rows-1): | ||||
|             for col in range(cols): | ||||
|                 if(row%2 == 0): | ||||
|                     bgcolor = "white" | ||||
|                 else: | ||||
|                     bgcolor = "lightgrey" | ||||
|                 eb = gtk.EventBox() | ||||
|                 eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor)) | ||||
|                 l = gtk.Label(result[row-1][col]) | ||||
|                 eb.add(l) | ||||
|                 self.stats_table.attach(eb, col, col+1, row+1, row+2) | ||||
|                 l.show() | ||||
|                 eb.show() | ||||
| 
 | ||||
| 
 | ||||
|     def fillPlayerFrame(self, vbox): | ||||
|         for site in self.conf.supported_sites.keys(): | ||||
|             hbox = gtk.HBox(False, 0) | ||||
|             vbox.pack_start(hbox, False, True, 0) | ||||
|             hbox.show() | ||||
| 
 | ||||
|             player = self.conf.supported_sites[site].screen_name | ||||
|             self.createPlayerLine(hbox, site, player) | ||||
|         hbox = gtk.HBox(False, 0) | ||||
|         button = gtk.Button("Refresh") | ||||
|         button.connect("clicked", self.refreshStats, False) | ||||
|         button.show() | ||||
|         hbox.add(button) | ||||
|         vbox.pack_start(hbox, False, True, 0) | ||||
|         hbox.show() | ||||
| 
 | ||||
|     def createPlayerLine(self, hbox, site, player): | ||||
|         if(self.buttongroup == None): | ||||
|             button = gtk.RadioButton(None, site + " id:") | ||||
|             button.set_active(True) | ||||
|             self.buttongroup = button | ||||
|             self.activesite = site | ||||
|         else: | ||||
|             button = gtk.RadioButton(self.buttongroup, site + " id:") | ||||
|         hbox.pack_start(button, True, True, 0) | ||||
|         button.connect("toggled", self.toggleCallback, site) | ||||
|         button.show() | ||||
| 
 | ||||
|         pname = gtk.Entry() | ||||
|         pname.set_text(player) | ||||
|         pname.set_width_chars(20) | ||||
|         hbox.pack_start(pname, False, True, 0) | ||||
|         pname.connect("changed", self.__set_hero_name, site) | ||||
|         #TODO: Look at GtkCompletion - to fill out usernames | ||||
|         pname.show() | ||||
|         self.__set_hero_name(pname, site) | ||||
| 
 | ||||
|     def __set_hero_name(self, w, site): | ||||
|         self.heroes[site] = w.get_text() | ||||
|         print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site]) | ||||
|      | ||||
|     def __init__(self, db, config, querylist, debug=True): | ||||
|         self.debug=debug | ||||
|         self.db=db | ||||
|         self.cursor=db.cursor | ||||
|         self.conf=config | ||||
| 
 | ||||
|         self.sql = querylist | ||||
| 
 | ||||
|         self.activesite = None | ||||
|         self.buttongroup = None | ||||
| 
 | ||||
|         self.heroes = {} | ||||
|         self.stat_table = None | ||||
|         self.stats_frame = None | ||||
|          | ||||
|         self.main_hbox = gtk.HBox(False, 0) | ||||
|         self.main_hbox.show() | ||||
| 
 | ||||
|         playerFrame = gtk.Frame("Hero:") | ||||
|         playerFrame.set_label_align(0.0, 0.0) | ||||
|         playerFrame.show() | ||||
|         vbox = gtk.VBox(False, 0) | ||||
|         vbox.show() | ||||
| 
 | ||||
|         self.fillPlayerFrame(vbox) | ||||
|         playerFrame.add(vbox) | ||||
| 
 | ||||
|         statsFrame = gtk.Frame("Stats:") | ||||
|         statsFrame.set_label_align(0.0, 0.0) | ||||
|         statsFrame.show() | ||||
|         self.stats_frame = gtk.VBox(False, 0) | ||||
|         self.stats_frame.show() | ||||
| 
 | ||||
|         self.fillStatsFrame(self.stats_frame) | ||||
|         statsFrame.add(self.stats_frame) | ||||
| 
 | ||||
|         self.main_hbox.pack_start(playerFrame) | ||||
|         self.main_hbox.pack_start(statsFrame) | ||||
| 
 | ||||
|  | @ -169,4 +169,3 @@ if __name__== "__main__": | |||
|     main_window.show_all() | ||||
|      | ||||
|     gtk.main() | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,254 +23,492 @@ import traceback | |||
| import os | ||||
| import os.path | ||||
| import xml.dom.minidom | ||||
| from decimal import Decimal | ||||
| import operator | ||||
| from xml.dom.minidom import Node | ||||
| from pokereval import PokerEval | ||||
| 
 | ||||
| class HandHistoryConverter: | ||||
| 	def __init__(self, config, file, sitename): | ||||
| 		print "HandHistory init called" | ||||
| 		self.c         = config | ||||
| 		self.sitename  = sitename | ||||
| 		self.obs       = ""             # One big string | ||||
| 		self.filetype  = "text" | ||||
| 		self.doc       = None     # For XML based HH files | ||||
| 		self.file      = file | ||||
| 		self.hhbase    = self.c.get_import_parameters().get("hhArchiveBase") | ||||
| 		self.hhbase    = os.path.expanduser(self.hhbase) | ||||
| 		self.hhdir     = os.path.join(self.hhbase,sitename) | ||||
| 		self.gametype  = [] | ||||
| #		self.ofile     = os.path.join(self.hhdir,file) | ||||
| 		self.rexx      = FpdbRegex.FpdbRegex() | ||||
|     eval = PokerEval() | ||||
|     def __init__(self, config, file, sitename): | ||||
|         print "HandHistory init called" | ||||
| 
 | ||||
| 	def __str__(self): | ||||
| 		tmp = "HandHistoryConverter: '%s'\n" % (self.sitename) | ||||
| 		tmp = tmp + "\thhbase:     '%s'\n" % (self.hhbase) | ||||
| 		tmp = tmp + "\thhdir:      '%s'\n" % (self.hhdir) | ||||
| 		tmp = tmp + "\tfiletype:   '%s'\n" % (self.filetype) | ||||
| 		tmp = tmp + "\tinfile:     '%s'\n" % (self.file) | ||||
|         self.c         = config | ||||
|         self.sitename  = sitename | ||||
|         self.obs       = ""             # One big string | ||||
|         self.filetype  = "text" | ||||
|         self.doc       = None     # For XML based HH files | ||||
|         self.file      = file | ||||
|         self.hhbase    = self.c.get_import_parameters().get("hhArchiveBase") | ||||
|         self.hhbase    = os.path.expanduser(self.hhbase) | ||||
|         self.hhdir     = os.path.join(self.hhbase,sitename) | ||||
|         self.gametype  = [] | ||||
| #		self.ofile     = os.path.join(self.hhdir,file) | ||||
|         self.rexx      = FpdbRegex.FpdbRegex() | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         tmp = "HandHistoryConverter: '%s'\n" % (self.sitename) | ||||
|         tmp = tmp + "\thhbase:     '%s'\n" % (self.hhbase) | ||||
|         tmp = tmp + "\thhdir:      '%s'\n" % (self.hhdir) | ||||
|         tmp = tmp + "\tfiletype:   '%s'\n" % (self.filetype) | ||||
|         tmp = tmp + "\tinfile:     '%s'\n" % (self.file) | ||||
| #		tmp = tmp + "\toutfile:    '%s'\n" % (self.ofile) | ||||
| #		tmp = tmp + "\tgametype:   '%s'\n" % (self.gametype[0]) | ||||
| #		tmp = tmp + "\tgamebase:   '%s'\n" % (self.gametype[1]) | ||||
| #		tmp = tmp + "\tlimit:      '%s'\n" % (self.gametype[2]) | ||||
| #		tmp = tmp + "\tsb/bb:      '%s/%s'\n" % (self.gametype[3], self.gametype[4]) | ||||
| 		return tmp | ||||
|         return tmp | ||||
| 
 | ||||
| 	def processFile(self): | ||||
| 		if not self.sanityCheck(): | ||||
| 			print "Cowardly refusing to continue after failed sanity check" | ||||
| 			return | ||||
| 		self.readFile(self.file) | ||||
| 		self.gametype = self.determineGameType() | ||||
| 		self.hands = self.splitFileIntoHands() | ||||
| 		for hand in self.hands: | ||||
| 			self.readHandInfo(hand) | ||||
| 			self.readPlayerStacks(hand) | ||||
| 			self.markStreets(hand) | ||||
| 			self.readBlinds(hand) | ||||
| 			self.readHeroCards(hand) | ||||
|     def processFile(self): | ||||
|         if not self.sanityCheck(): | ||||
|             print "Cowardly refusing to continue after failed sanity check" | ||||
|             return | ||||
|         self.readFile(self.file) | ||||
|         self.gametype = self.determineGameType() | ||||
|         self.hands = self.splitFileIntoHands() | ||||
|         for hand in self.hands: | ||||
|             self.readHandInfo(hand) | ||||
|             self.readPlayerStacks(hand) | ||||
|             self.markStreets(hand) | ||||
|             self.readBlinds(hand) | ||||
|             self.readHeroCards(hand) # want to generalise to draw games | ||||
|             self.readCommunityCards(hand) # read community cards | ||||
|             self.readShowdownActions(hand) | ||||
|             # Read action (Note: no guarantee this is in hand order. | ||||
|             for street in hand.streets.groupdict(): | ||||
|                 self.readAction(hand, street) | ||||
| 
 | ||||
| 			# Read action (Note: no guarantee this is in hand order. | ||||
| 			for street in hand.streets.groupdict(): | ||||
| 				self.readAction(hand, street) | ||||
|             # finalise it (total the pot) | ||||
|             hand.totalPot() | ||||
|             self.getRake(hand) | ||||
|              | ||||
|             if(hand.involved == True): | ||||
|                 #self.writeHand("output file", hand) | ||||
|                 hand.printHand() | ||||
|             else: | ||||
|                 pass #Don't write out observed hands | ||||
| 
 | ||||
| 			if(hand.involved == True): | ||||
| 				self.writeHand("output file", hand) | ||||
| 			else: | ||||
| 				pass #Don't write out observed hands | ||||
|     ##### | ||||
|     # These functions are parse actions that may be overridden by the inheriting class | ||||
|     # | ||||
|      | ||||
|     def readSupportedGames(self): abstract | ||||
| 
 | ||||
| 	# Functions to be implemented in the inheriting class | ||||
| 	def readSupportedGames(self): abstract | ||||
|     # should return a list | ||||
|     #   type  base limit | ||||
|     # [ ring, hold, nl   , sb, bb ] | ||||
|     # Valid types specified in docs/tabledesign.html in Gametypes | ||||
|     def determineGameType(self): abstract | ||||
| 
 | ||||
| 	# should return a list | ||||
| 	#   type  base limit | ||||
| 	# [ ring, hold, nl   , sb, bb ] | ||||
| 	# Valid types specified in docs/tabledesign.html in Gametypes | ||||
| 	def determineGameType(self): abstract | ||||
|     # Read any of: | ||||
|     # HID		HandID | ||||
|     # TABLE		Table name | ||||
|     # SB 		small blind | ||||
|     # BB		big blind | ||||
|     # GAMETYPE	gametype | ||||
|     # YEAR MON DAY HR MIN SEC 	datetime | ||||
|     # BUTTON	button seat number | ||||
|     def readHandInfo(self, hand): abstract | ||||
| 
 | ||||
| 	#TODO: Comment | ||||
| 	def readHandInfo(self, hand): abstract | ||||
|     # Needs to return a list of lists in the format | ||||
|     # [['seat#', 'player1name', 'stacksize'] ['seat#', 'player2name', 'stacksize'] [...]] | ||||
|     def readPlayerStacks(self, hand): abstract | ||||
| 
 | ||||
| 	# Needs to return a list of lists in the format | ||||
| 	# [['seat#', 'player1name', 'stacksize'] ['seat#', 'player2name', 'stacksize'] [...]] | ||||
| 	def readPlayerStacks(self, hand): abstract | ||||
|     # Needs to return a MatchObject with group names identifying the streets into the Hand object | ||||
|     # that is, pulls the chunks of preflop, flop, turn and river text into hand.streets MatchObject. | ||||
|     def markStreets(self, hand): abstract | ||||
| 
 | ||||
| 	# Needs to return a MatchObject with group names identifying the streets into the Hand object | ||||
| 	def markStreets(self, hand): abstract | ||||
|     #Needs to return a list in the format | ||||
|     # ['player1name', 'player2name', ...] where player1name is the sb and player2name is bb,  | ||||
|     # addtional players are assumed to post a bb oop | ||||
|     def readBlinds(self, hand): abstract | ||||
|     def readHeroCards(self, hand): abstract | ||||
|     def readAction(self, hand, street): abstract | ||||
|      | ||||
|     # Some sites don't report the rake. This will be called at the end of the hand after the pot total has been calculated | ||||
|     # so that an inheriting class can calculate it for the specific site if need be. | ||||
|     def getRake(self, hand): abstract | ||||
|      | ||||
|     def sanityCheck(self): | ||||
|         sane = True | ||||
|         base_w = False | ||||
|         #Check if hhbase exists and is writable | ||||
|         #Note: Will not try to create the base HH directory | ||||
|         if not (os.access(self.hhbase, os.W_OK) and os.path.isdir(self.hhbase)): | ||||
|             print "HH Sanity Check: Directory hhbase '" + self.hhbase + "' doesn't exist or is not writable" | ||||
|         else: | ||||
|             #Check if hhdir exists and is writable | ||||
|             if not os.path.isdir(self.hhdir): | ||||
|                 # In first pass, dir may not exist. Attempt to create dir | ||||
|                 print "Creating directory: '%s'" % (self.hhdir) | ||||
|                 os.mkdir(self.hhdir) | ||||
|                 sane = True | ||||
|             elif os.access(self.hhdir, os.W_OK): | ||||
|                 sane = True | ||||
|             else: | ||||
|                 print "HH Sanity Check: Directory hhdir '" + self.hhdir + "' or its parent directory are not writable" | ||||
| 
 | ||||
| 	#Needs to return a list in the format | ||||
| 	# ['player1name', 'player2name', ...] where player1name is the sb and player2name is bb,  | ||||
| 	# addtional players are assumed to post a bb oop | ||||
| 	def readBlinds(self, hand): abstract | ||||
| 	def readHeroCards(self, hand): abstract | ||||
| 	def readAction(self, hand, street): abstract | ||||
|         return sane | ||||
| 
 | ||||
| 	def sanityCheck(self): | ||||
| 		sane = False | ||||
| 		base_w = False | ||||
| 		#Check if hhbase exists and is writable | ||||
| 		#Note: Will not try to create the base HH directory | ||||
| 		if not (os.access(self.hhbase, os.W_OK) and os.path.isdir(self.hhbase)): | ||||
| 			print "HH Sanity Check: Directory hhbase '" + self.hhbase + "' doesn't exist or is not writable" | ||||
| 		else: | ||||
| 			#Check if hhdir exists and is writable | ||||
| 			if not os.path.isdir(self.hhdir): | ||||
| 				# In first pass, dir may not exist. Attempt to create dir | ||||
| 				print "Creating directory: '%s'" % (self.hhdir) | ||||
| 				os.mkdir(self.hhdir) | ||||
| 				sane = True | ||||
| 			elif os.access(self.hhdir, os.W_OK): | ||||
| 				sane = True | ||||
| 			else: | ||||
| 				print "HH Sanity Check: Directory hhdir '" + self.hhdir + "' or its parent directory are not writable" | ||||
|     # Functions not necessary to implement in sub class | ||||
|     def setFileType(self, filetype = "text"): | ||||
|         self.filetype = filetype | ||||
| 
 | ||||
| 		return sane | ||||
| 
 | ||||
| 	# Functions not necessary to implement in sub class | ||||
| 	def setFileType(self, filetype = "text"): | ||||
| 		self.filetype = filetype | ||||
| 
 | ||||
| 	def splitFileIntoHands(self): | ||||
| 		hands = [] | ||||
| 		list = self.rexx.split_hand_re.split(self.obs) | ||||
| 		list.pop() #Last entry is empty | ||||
| 		for l in list: | ||||
|     def splitFileIntoHands(self): | ||||
|         hands = [] | ||||
|         list = self.rexx.split_hand_re.split(self.obs) | ||||
|         list.pop() #Last entry is empty | ||||
|         for l in list: | ||||
| #			print "'" + l + "'" | ||||
| 			hands = hands + [Hand(self.sitename, self.gametype, l)] | ||||
| 		return hands | ||||
|             hands = hands + [Hand(self.sitename, self.gametype, l)] | ||||
|         return hands | ||||
| 
 | ||||
| 	def readFile(self, filename): | ||||
| 		"""Read file""" | ||||
| 		print "Reading file: '%s'" %(filename) | ||||
| 		if(self.filetype == "text"): | ||||
| 			infile=open(filename, "rU") | ||||
| 			self.obs = infile.read() | ||||
| 			infile.close() | ||||
| 		elif(self.filetype == "xml"): | ||||
| 			try: | ||||
| 				doc = xml.dom.minidom.parse(filename) | ||||
| 				self.doc = doc | ||||
| 			except: | ||||
| 				traceback.print_exc(file=sys.stderr) | ||||
|     def readFile(self, filename): | ||||
|         """Read file""" | ||||
|         print "Reading file: '%s'" %(filename) | ||||
|         if(self.filetype == "text"): | ||||
|             infile=open(filename, "rU") | ||||
|             self.obs = infile.read() | ||||
|             infile.close() | ||||
|         elif(self.filetype == "xml"): | ||||
|             try: | ||||
|                 doc = xml.dom.minidom.parse(filename) | ||||
|                 self.doc = doc | ||||
|             except: | ||||
|                 traceback.print_exc(file=sys.stderr) | ||||
| 
 | ||||
| 	def writeHand(self, file, hand): | ||||
| 		"""Write out parsed data""" | ||||
| 		print "DEBUG: *************************" | ||||
| 		print "DEBUG: Start of print hand" | ||||
| 		print "DEBUG: *************************" | ||||
|     def writeHand(self, file, hand): | ||||
|         """Write out parsed data""" | ||||
|         print "DEBUG: *************************" | ||||
|         print "DEBUG: Start of print hand" | ||||
|         print "DEBUG: *************************" | ||||
| 
 | ||||
| 		print "%s Game #%s: %s ($%s/$%s) - %s" %(hand.sitename, hand.handid, "XXXXhand.gametype", hand.sb, hand.bb, hand.starttime) | ||||
| 		print "Table '%s' %d-max Seat #%s is the button" %(hand.tablename, hand.maxseats, hand.buttonpos) | ||||
|         print "%s Game #%s: %s ($%s/$%s) - %s" %(hand.sitename, hand.handid, "XXXXhand.gametype", hand.sb, hand.bb, hand.starttime) | ||||
|         print "Table '%s' %d-max Seat #%s is the button" %(hand.tablename, hand.maxseats, hand.buttonpos) | ||||
| 
 | ||||
| 		for player in hand.players: | ||||
| 			print "Seat %s: %s ($%s)" %(player[0], player[1], player[2]) | ||||
|         for player in hand.players: | ||||
|             print "Seat %s: %s ($%s)" %(player[0], player[1], player[2]) | ||||
| 
 | ||||
| 		if(hand.posted[0] == "FpdbNBP"): | ||||
| 			print "No small blind posted" | ||||
| 		else: | ||||
| 			print "%s: posts small blind $%s" %(hand.posted[0], hand.sb) | ||||
|         if(hand.posted[0] == "FpdbNBP"): | ||||
|             print "No small blind posted" | ||||
|         else: | ||||
|             print "%s: posts small blind $%s" %(hand.posted[0], hand.sb) | ||||
| 
 | ||||
| 		#May be more than 1 bb posting | ||||
| 		print "%s: posts big blind $%s" %(hand.posted[1], hand.bb) | ||||
| 		if(len(hand.posted) > 2): | ||||
| 			# Need to loop on all remaining big blinds - lazy | ||||
| 			print "XXXXXXXXX FIXME XXXXXXXX" | ||||
|         #May be more than 1 bb posting | ||||
|         print "%s: posts big blind $%s" %(hand.posted[1], hand.bb) | ||||
|         if(len(hand.posted) > 2): | ||||
|             # Need to loop on all remaining big blinds - lazy | ||||
|             print "XXXXXXXXX FIXME XXXXXXXX" | ||||
| 
 | ||||
| 		print "*** HOLE CARDS ***" | ||||
| 		print "Dealt to %s [%s]" %(hand.hero ,hand.holecards) | ||||
| # | ||||
| ##		ACTION STUFF | ||||
| #		This is no limit only at the moment | ||||
| 		 | ||||
| 		for act in hand.actions['PREFLOP']: | ||||
| 			self.printActionLine(act, 0) | ||||
|         print "*** HOLE CARDS ***" | ||||
|         print "Dealt to %s [%s %s]" %(hand.hero , hand.holecards[0], hand.holecards[1]) | ||||
| 
 | ||||
| 		if 'FLOP' in hand.actions: | ||||
| 			print "*** FLOP *** [%s]" %("XXXXX Flop cards XXXXXX") | ||||
| 			for act in hand.actions['FLOP']: | ||||
| 				self.printActionLine(act, 0) | ||||
|         for act in hand.actions['PREFLOP']: | ||||
|             self.printActionLine(act, 0) | ||||
| 
 | ||||
| 		if 'TURN' in hand.actions: | ||||
| 			print "*** TURN *** [%s] [%s]" %("XXXXX Flop cards XXXXXX", "XXXXX Turn Card XXXXX") | ||||
| 			for act in hand.actions['TURN']: | ||||
| 				self.printActionLine(act, 0) | ||||
|         if 'PREFLOP' in hand.actions: | ||||
|             for act in hand.actions['PREFLOP']: | ||||
|                 print "PF action" | ||||
| 
 | ||||
| 		if 'RIVER' in hand.actions: | ||||
| 			print "*** RIVER *** [%s %s] [%s]" %("XXXXX Flop cards XXXXXX", "XXXXX Turn Card XXXXX", "XXXXX River Card XXXXX") | ||||
| 			for act in hand.actions['RIVER']: | ||||
| 				self.printActionLine(act, 0) | ||||
|         if 'FLOP' in hand.actions: | ||||
|             print "*** FLOP *** [%s %s %s]" %(hand.streets.group("FLOP1"), hand.streets.group("FLOP2"), hand.streets.group("FLOP3")) | ||||
|             for act in hand.actions['FLOP']: | ||||
|                 self.printActionLine(act, 0) | ||||
| 
 | ||||
| 		print "*** SUMMARY ***" | ||||
| 		print "XXXXXXXXXXXX Need sumary info XXXXXXXXXXX" | ||||
| #		print "Total pot $%s | Rake $%s)" %(hand.totalpot  $" + hand.rake) | ||||
| #		print "Board [" + boardcards + "]" | ||||
| # | ||||
| #		SUMMARY STUFF | ||||
|         if 'TURN' in hand.actions: | ||||
|             print "*** TURN *** [%s %s %s] [%s]" %(hand.streets.group("FLOP1"), hand.streets.group("FLOP2"), hand.streets.group("FLOP3"), hand.streets.group("TURN1")) | ||||
|             for act in hand.actions['TURN']: | ||||
|                 self.printActionLine(act, 0) | ||||
| 
 | ||||
|         if 'RIVER' in hand.actions: | ||||
|             print "*** RIVER *** [%s %s %s %s] [%s]" %(hand.streets.group("FLOP1"), hand.streets.group("FLOP2"), hand.streets.group("FLOP3"), hand.streets.group("TURN1"), hand.streets.group("RIVER1")) | ||||
|             for act in hand.actions['RIVER']: | ||||
|                 self.printActionLine(act, 0) | ||||
| 
 | ||||
|         print "*** SUMMARY ***" | ||||
|         print "XXXXXXXXXXXX Need sumary info XXXXXXXXXXX" | ||||
| 
 | ||||
| 
 | ||||
| 	def printActionLine(self, act, pot): | ||||
| 		if act[1] == 'folds' or act[1] == 'checks': | ||||
| 			print "%s: %s" %(act[0], act[1]) | ||||
| 		if act[1] == 'calls': | ||||
| 			print "%s: %s $%s" %(act[0], act[1], act[2]) | ||||
| 		if act[1] == 'raises': | ||||
| 			print "%s: %s $%s to XXXpottotalXXX" %(act[0], act[1], act[2]) | ||||
|     def printActionLine(self, act, pot): | ||||
|         if act[1] == 'folds' or act[1] == 'checks': | ||||
|             print "%s: %s " %(act[0], act[1]) | ||||
|         if act[1] == 'calls': | ||||
|             print "%s: %s $%s" %(act[0], act[1], act[2]) | ||||
|         if act[1] == 'raises': | ||||
|             print "%s: %s $%s to XXXpottotalXXX" %(act[0], act[1], act[2]) | ||||
| 
 | ||||
| 
 | ||||
| #takes a poker float (including , for thousand seperator and converts it to an int | ||||
| 	def float2int (self, string): | ||||
| 		pos=string.find(",") | ||||
| 		if (pos!=-1): #remove , the thousand seperator | ||||
| 			string=string[0:pos]+string[pos+1:] | ||||
|     def float2int (self, string): | ||||
|         pos=string.find(",") | ||||
|         if (pos!=-1): #remove , the thousand seperator | ||||
|             string=string[0:pos]+string[pos+1:] | ||||
| 
 | ||||
| 		pos=string.find(".") | ||||
| 		if (pos!=-1): #remove decimal point | ||||
| 			string=string[0:pos]+string[pos+1:] | ||||
|         pos=string.find(".") | ||||
|         if (pos!=-1): #remove decimal point | ||||
|             string=string[0:pos]+string[pos+1:] | ||||
| 
 | ||||
| 		result = int(string) | ||||
| 		if pos==-1: #no decimal point - was in full dollars - need to multiply with 100 | ||||
| 			result*=100 | ||||
| 		return result | ||||
|         result = int(string) | ||||
|         if pos==-1: #no decimal point - was in full dollars - need to multiply with 100 | ||||
|             result*=100 | ||||
|         return result | ||||
| #end def float2int | ||||
| 
 | ||||
| class Hand: | ||||
| #    def __init__(self, sitename, gametype, sb, bb, string): | ||||
| 
 | ||||
|     UPS = {'a':'A', 't':'T', 'j':'J', 'q':'Q', 'k':'K'} | ||||
|     def __init__(self, sitename, gametype, string): | ||||
| 	self.sitename = sitename | ||||
| 	self.gametype = gametype | ||||
| 	self.string = string | ||||
|         self.sitename = sitename | ||||
|         self.gametype = gametype | ||||
|         self.string = string | ||||
|      | ||||
|         self.streets = None # A MatchObject using a groupnames to identify streets. | ||||
|         self.streetList = ['BLINDS','PREFLOP','FLOP','TURN','RIVER'] # a list of the observed street names in order | ||||
|         self.actions = {} | ||||
|      | ||||
|         self.handid = 0 | ||||
|         self.sb = gametype[3] | ||||
|         self.bb = gametype[4] | ||||
|         self.tablename = "Slartibartfast" | ||||
|         self.maxseats = 10 | ||||
|         self.counted_seats = 0 | ||||
|         self.buttonpos = 0 | ||||
|         self.seating = [] | ||||
|         self.players = [] | ||||
|         self.posted = [] | ||||
|         self.involved = True | ||||
|          | ||||
|         self.hero = "Hiro" | ||||
|         self.holecards = {} # dict from player names to lists of hole cards | ||||
|         self.board = {}     # dict from street names to community cards | ||||
|          | ||||
|         self.action = [] | ||||
|         self.totalpot = None | ||||
|         self.rake = None | ||||
|          | ||||
|         self.bets = {} | ||||
|         self.lastBet = {} | ||||
|         for street in self.streetList: | ||||
|             self.bets[street] = {} | ||||
|             self.lastBet[street] = 0 | ||||
|              | ||||
|     def addPlayer(self, seat, name, chips): | ||||
|         """seat, an int indicating the seat | ||||
|         name, the player name | ||||
|         chips, the chips the player has at the start of the hand""" | ||||
|         #self.players.append(name) | ||||
|         self.players.append([seat, name, chips]) | ||||
|         self.holecards[name] = [] | ||||
|         #self.startChips[name] = chips | ||||
|         #self.endChips[name] = chips | ||||
|         #self.winners[name] = 0 | ||||
|         for street in self.streetList: | ||||
|             self.bets[street][name] = [] | ||||
| 
 | ||||
| 	self.streets = None # A MatchObject using a groupnames to identify streets. | ||||
| 	self.actions = {} | ||||
| 
 | ||||
| 	self.handid = 0 | ||||
| 	self.sb = gametype[3] | ||||
| 	self.bb = gametype[4] | ||||
| 	self.tablename = "Slartibartfast" | ||||
| 	self.maxseats = 10 | ||||
| 	self.counted_seats = 0 | ||||
| 	self.buttonpos = 0 | ||||
| 	self.seating = [] | ||||
| 	self.players = [] | ||||
| 	self.posted = [] | ||||
| 	self.involved = True | ||||
| 	self.hero = "Hiro" | ||||
| 	self.holecards = "Xx Xx" | ||||
| 	self.action = [] | ||||
| 	self.totalpot = 0 | ||||
| 	self.rake = 0 | ||||
|     def addHoleCards(self, cards, player=None): # generalise to add hole cards for a specific seat or player | ||||
|         for c in cards: | ||||
|             self.holecards[player].append(self.card(c)) | ||||
| 
 | ||||
| 
 | ||||
|     def discardHoleCards(self, cards, player=None): | ||||
|         if seat is None: | ||||
|             #raise something | ||||
|             pass | ||||
|         for card in cards: | ||||
|             try: | ||||
|                 self.holecards[player].remove(card) | ||||
|             except ValueError: | ||||
|                 print "tried to discard a card player apparently didn't have" | ||||
| 
 | ||||
|     def setCommunityCards(self, street, cards): | ||||
|         self.board[street] = [self.card(c) for c in cards] | ||||
|         print self.board[street] | ||||
| 
 | ||||
|     def card(self,c): | ||||
|         """upper case the ranks but not suits, 'atjqk' => 'ATJQK'""" | ||||
|         # don't know how to make this 'static' | ||||
|         for k,v in self.UPS.items(): | ||||
|             c = c.replace(k,v) | ||||
|         return c | ||||
| 
 | ||||
|     def addBlind(self, player, amount): | ||||
|         # if player is None, it's a missing small blind. | ||||
|         if player is not None: | ||||
|             self.bets['PREFLOP'][player].append(Decimal(amount)) | ||||
|         self.lastBet['PREFLOP'] = Decimal(amount) | ||||
|         self.posted += [player] | ||||
|          | ||||
| 
 | ||||
|     #def addFold(self, street, player=None): | ||||
|         ## Called when a player folds. | ||||
|         #self.bets[street][player].append(None) | ||||
| 
 | ||||
|     #def addCheck(self, street, player=None): | ||||
|         #self.bets[street][player].append(0) | ||||
| 
 | ||||
|     def addCall(self, street, player=None, amount=None): | ||||
|         # Potentially calculate the amount of the call if not supplied | ||||
|         # corner cases include if player would be all in | ||||
|         if amount is not None: | ||||
|             self.bets[street][player].append(Decimal(amount)) | ||||
|             #self.lastBet[street] = Decimal(amount) | ||||
|             self.actions[street] += [[player, 'calls', amount]] | ||||
|          | ||||
|     def addRaiseTo(self, street, player, amountTo): | ||||
|         # Given only the amount raised to, the amount of the raise can be calculated by | ||||
|         # working out how much this player has already in the pot  | ||||
|         #   (which is the sum of self.bets[street][player]) | ||||
|         # and how much he needs to call to match the previous player  | ||||
|         #   (which is tracked by self.lastBet) | ||||
|         committedThisStreet = reduce(operator.add, self.bets[street][player], 0) | ||||
|         amountToCall = self.lastBet[street] - committedThisStreet | ||||
|         self.lastBet[street] = Decimal(amountTo) | ||||
|         amountBy = Decimal(amountTo) - amountToCall | ||||
|         self.bets[street][player].append(amountBy+amountToCall) | ||||
|         self.actions[street] += [[player, 'raises', amountBy, amountTo]] | ||||
|          | ||||
|     def addBet(self, street, player=None, amount=0): | ||||
|         self.bets[street][name].append(Decimal(amount)) | ||||
|         self.orderedBets[street].append(Decimal(amount)) | ||||
|         self.actions[street] += [[player, 'bets', amount]] | ||||
|          | ||||
|     def totalPot(self): | ||||
|         """If all bets and blinds have been added, totals up the total pot size | ||||
| Known bug: doesn't take into account side pots""" | ||||
|         if self.totalpot is None: | ||||
|             self.totalpot = 0 | ||||
|              | ||||
|             # player names:  | ||||
|             # print [x[1] for x in self.players] | ||||
|             for player in [x[1] for x in self.players]: | ||||
|                 for street in self.streetList: | ||||
|                     #print street, self.bets[street][player] | ||||
|                     self.totalpot += reduce(operator.add, self.bets[street][player], 0) | ||||
|                      | ||||
| 
 | ||||
| 
 | ||||
|     def printHand(self): | ||||
| 	print self.sitename | ||||
| 	print self.gametype | ||||
| 	print self.string | ||||
| 	print self.handid | ||||
| 	print self.sb | ||||
| 	print self.bb | ||||
| 	print self.tablename | ||||
| 	print self.maxseats | ||||
| 	print self.counted_seats | ||||
| 	print self.buttonpos | ||||
| 	print self.seating | ||||
| 	print self.players | ||||
| 	print self.posted | ||||
| 	print self.action | ||||
| 	print self.involved | ||||
| 	print self.hero | ||||
|         # PokerStars format. | ||||
|         print "### DEBUG ###" | ||||
|         print "%s Game #%s: %s ($%s/$%s) - %s" %(self.sitename, self.handid, "XXXXhand.gametype", self.sb, self.bb, self.starttime) | ||||
|         print "Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos) | ||||
|         for player in self.players: | ||||
|             print "Seat %s: %s ($%s)" %(player[0], player[1], player[2]) | ||||
| 
 | ||||
|         if(self.posted[0] is None): | ||||
|             print "No small blind posted" | ||||
|         else: | ||||
|             print "%s: posts small blind $%s" %(self.posted[0], self.sb) | ||||
| 
 | ||||
|         #May be more than 1 bb posting | ||||
|         for a in self.posted[1:]: | ||||
|             print "%s: posts big blind $%s" %(self.posted[1], self.bb) | ||||
|              | ||||
|         # What about big & small blinds? | ||||
| 
 | ||||
|         print "*** HOLE CARDS ***" | ||||
|         print "Dealt to %s [%s %s]" %(self.hero , self.holecards[self.hero][0], self.holecards[self.hero][1]) | ||||
| 
 | ||||
|         if 'PREFLOP' in self.actions: | ||||
|             for act in self.actions['PREFLOP']: | ||||
|                 self.printActionLine(act) | ||||
| 
 | ||||
|         if 'FLOP' in self.actions: | ||||
|             print "*** FLOP *** [%s %s %s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3")) | ||||
|             for act in self.actions['FLOP']: | ||||
|                 self.printActionLine(act) | ||||
| 
 | ||||
|         if 'TURN' in self.actions: | ||||
|             print "*** TURN *** [%s %s %s] [%s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"), self.streets.group("TURN1")) | ||||
|             for act in self.actions['TURN']: | ||||
|                 self.printActionLine(act) | ||||
| 
 | ||||
|         if 'RIVER' in self.actions: | ||||
|             print "*** RIVER *** [%s %s %s %s] [%s]" %(self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"), self.streets.group("TURN1"), self.streets.group("RIVER1")) | ||||
|             for act in self.actions['RIVER']: | ||||
|                 self.printActionLine(act) | ||||
|                  | ||||
|                  | ||||
|         #Some sites don't have a showdown section so we have to figure out if there should be one | ||||
|         # The logic for a showdown is: at the end of river action there are at least two players in the hand | ||||
|         if 'SHOWDOWN' in self.actions: | ||||
|             print "*** SHOW DOWN ***" | ||||
|             print "what do they show" | ||||
|          | ||||
|         print "*** SUMMARY ***" | ||||
|         print "Total pot $%s | Rake $%s)" % (self.totalpot, self.rake) | ||||
|         print "Board [%s %s %s %s %s]" % (self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"), self.streets.group("TURN1"), self.streets.group("RIVER1")) | ||||
|          | ||||
|         #print self.board | ||||
|         for player in self.players: | ||||
|             if self.holecards[player[1]]: # empty list default is false | ||||
|                 hole = self.holecards[player[1]] | ||||
|                 #print self.board.values() | ||||
|                 board = [] | ||||
|                 for s in self.board.values(): | ||||
|                     board += s | ||||
|                 playerhand = self.bestHand('hi', board+hole) | ||||
|                 print "Seat %d: %s showed %s and won/lost with %s" % (player[0], player[1], hole, playerhand) | ||||
|             else: | ||||
|                 print "Seat %d: %s mucked or folded" % (player[0], player[1]) | ||||
| 
 | ||||
| 
 | ||||
|     def printActionLine(self, act): | ||||
|         if act[1] == 'folds' or act[1] == 'checks': | ||||
|             print "%s: %s " %(act[0], act[1]) | ||||
|         if act[1] == 'calls': | ||||
|             print "%s: %s $%s" %(act[0], act[1], act[2]) | ||||
|         if act[1] == 'raises': | ||||
|             print "%s: %s $%s to $%s" %(act[0], act[1], act[2], act[3]) | ||||
| 
 | ||||
|     # going to use pokereval to figure out hands | ||||
|     # these functions are copied from pokergame.py | ||||
|     # im thinking perhaps its best to use all the functionality of pokergame instead | ||||
|     # of reinventing the wheel | ||||
|     def bestHand(self, side, cards): | ||||
|         #if self.variant == "omaha" or self.variant == "omaha8": | ||||
|         #hand = self.serial2player[serial].hand.tolist(True) | ||||
|         #board = self.board.tolist(True) | ||||
|         #else: | ||||
|         #hand = hand.tolist(True) + board.tolist(True) | ||||
|         #board = [] | ||||
|         print cards | ||||
|         return HandHistoryConverter.eval.best('hi', cards, []) | ||||
| 
 | ||||
|     def bestHandValue(self, side, serial): | ||||
|         (value, cards) = self.bestHand(side, serial) | ||||
|         return value | ||||
| 
 | ||||
| 
 | ||||
|     def readableHandValueLong(self, side, value, cards): | ||||
|         cards = self.eval.card2string(cards) | ||||
|         if value == "NoPair": | ||||
|             if side == "low": | ||||
|                 if cards[0][0] == '5': | ||||
|                     return _("The wheel") | ||||
|                 else: | ||||
|                     return join(map(lambda card: card[0], cards), ", ") | ||||
|             else: | ||||
|                 return _("High card %(card)s") % { 'card' : _(letter2name[cards[0][0]]) } | ||||
|         elif value == "OnePair": | ||||
|             return _("A pair of %(card)s") % { 'card' : _(letter2names[cards[0][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[2][0]]) } | ||||
|         elif value == "TwoPair": | ||||
|             return _("Two pairs %(card1)s and %(card2)s") % { 'card1' : _(letter2names[cards[0][0]]), 'card2' : _(letter2names[cards[2][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[4][0]]) } | ||||
|         elif value == "Trips": | ||||
|             return _("Three of a kind %(card)s") % { 'card' : _(letter2names[cards[0][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[3][0]]) } | ||||
|         elif value == "Straight": | ||||
|             return _("Straight %(card1)s to %(card2)s") % { 'card1' : _(letter2name[cards[0][0]]), 'card2' : _(letter2name[cards[4][0]]) } | ||||
|         elif value == "Flush": | ||||
|             return _("Flush %(card)s high") % { 'card' : _(letter2name[cards[0][0]]) } | ||||
|         elif value == "FlHouse": | ||||
|             return _("%(card1)ss full of %(card2)ss") % { 'card1' : _(letter2name[cards[0][0]]), 'card2' : _(letter2name[cards[3][0]]) } | ||||
|         elif value == "Quads": | ||||
|             return _("Four of a kind %(card)s") % { 'card' : _(letter2names[cards[0][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[4][0]]) } | ||||
|         elif value == "StFlush": | ||||
|             if letter2name[cards[0][0]] == 'Ace': | ||||
|                 return _("Royal flush") | ||||
|             else: | ||||
|                 return _("Straight flush %(card)s high") % { 'card' : _(letter2name[cards[0][0]]) } | ||||
|         return value | ||||
							
								
								
									
										3
									
								
								pyfpdb/Mucked.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										3
									
								
								pyfpdb/Mucked.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							|  | @ -170,6 +170,7 @@ class Stud_cards: | |||
|         for r in range(0, self.rows): | ||||
|             self.grid_contents[( 0, r)] = gtk.Label("%d" % (r + 1)) | ||||
|             self.grid_contents[( 1, r)] = gtk.Label("player %d" % (r + 1)) | ||||
|             self.grid_contents[( 1, r)].set_property("width-chars", 12) | ||||
|             self.grid_contents[( 4, r)] = gtk.Label("-") | ||||
|             self.grid_contents[( 9, r)] = gtk.Label("-") | ||||
|             self.grid_contents[( 2, r)] = self.eb[( 0, r)] | ||||
|  | @ -289,7 +290,7 @@ class Stud_cards: | |||
| 
 | ||||
|     def clear(self): | ||||
|         for r in range(0, self.rows): | ||||
|             self.grid_contents[(1, r)].set_text("        ") | ||||
|             self.grid_contents[(1, r)].set_text("             ") | ||||
|             for c in range(0, 7): | ||||
|                 self.seen_cards[(c, r)].set_from_pixbuf(self.card_images[('B', 'S')]) | ||||
|                 self.eb[(c, r)].set_tooltip_text('') | ||||
|  |  | |||
|  | @ -35,72 +35,72 @@ import unittest | |||
| 
 | ||||
| class TestSequenceFunctions(unittest.TestCase): | ||||
| 
 | ||||
| 	def setUp(self): | ||||
| 		"""Configure MySQL settings/database and establish connection""" | ||||
| 		self.c = Configuration.Config() | ||||
| 		self.mysql_settings={ 'db-host':"localhost",  | ||||
| 					'db-backend':2,  | ||||
| 					'db-databaseName':"fpdbtest",  | ||||
| 					'db-user':"fpdb",  | ||||
| 					'db-password':"fpdb"} | ||||
| 		self.mysql_db = fpdb_db.fpdb_db() | ||||
| 		self.mysql_db.connect(self.mysql_settings['db-backend'], self.mysql_settings['db-host'], | ||||
| 					self.mysql_settings['db-databaseName'], self.mysql_settings['db-user'], | ||||
| 					self.mysql_settings['db-password']) | ||||
| 		self.mysqldict = FpdbSQLQueries.FpdbSQLQueries('MySQL InnoDB') | ||||
| 		self.mysqlimporter = fpdb_import.Importer(self, self.mysql_settings, self.c) | ||||
| 		self.mysqlimporter.setCallHud(False) | ||||
|     def setUp(self): | ||||
|         """Configure MySQL settings/database and establish connection""" | ||||
|         self.c = Configuration.Config() | ||||
|         self.mysql_settings={ 'db-host':"localhost",  | ||||
|                     'db-backend':2,  | ||||
|                     'db-databaseName':"fpdbtest",  | ||||
|                     'db-user':"fpdb",  | ||||
|                     'db-password':"fpdb"} | ||||
|         self.mysql_db = fpdb_db.fpdb_db() | ||||
|         self.mysql_db.connect(self.mysql_settings['db-backend'], self.mysql_settings['db-host'], | ||||
|                     self.mysql_settings['db-databaseName'], self.mysql_settings['db-user'], | ||||
|                     self.mysql_settings['db-password']) | ||||
|         self.mysqldict = FpdbSQLQueries.FpdbSQLQueries('MySQL InnoDB') | ||||
|         self.mysqlimporter = fpdb_import.Importer(self, self.mysql_settings, self.c) | ||||
|         self.mysqlimporter.setCallHud(False) | ||||
| 
 | ||||
| #		"""Configure Postgres settings/database and establish connection""" | ||||
| #		self.pg_settings={ 'db-host':"localhost", 'db-backend':3, 'db-databaseName':"fpdbtest", 'db-user':"fpdb", 'db-password':"fpdb"} | ||||
| #		self.pg_db = fpdb_db.fpdb_db() | ||||
| #		self.pg_db.connect(self.pg_settings['db-backend'], self.pg_settings['db-host'], | ||||
| #					self.pg_settings['db-databaseName'], self.pg_settings['db-user'], | ||||
| #					self.pg_settings['db-password']) | ||||
| #		self.pgdict = FpdbSQLQueries.FpdbSQLQueries('PostgreSQL') | ||||
| #        """Configure Postgres settings/database and establish connection""" | ||||
| #        self.pg_settings={ 'db-host':"localhost", 'db-backend':3, 'db-databaseName':"fpdbtest", 'db-user':"fpdb", 'db-password':"fpdb"} | ||||
| #        self.pg_db = fpdb_db.fpdb_db() | ||||
| #        self.pg_db.connect(self.pg_settings['db-backend'], self.pg_settings['db-host'], | ||||
| #                    self.pg_settings['db-databaseName'], self.pg_settings['db-user'], | ||||
| #                    self.pg_settings['db-password']) | ||||
| #        self.pgdict = FpdbSQLQueries.FpdbSQLQueries('PostgreSQL') | ||||
| 
 | ||||
| 
 | ||||
| 	def testDatabaseConnection(self): | ||||
| 		"""Test all supported DBs""" | ||||
| 		self.result = self.mysql_db.cursor.execute(self.mysqldict.query['list_tables']) | ||||
| 		self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result)) | ||||
|     def testDatabaseConnection(self): | ||||
|         """Test all supported DBs""" | ||||
|         self.result = self.mysql_db.cursor.execute(self.mysqldict.query['list_tables']) | ||||
|         self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result)) | ||||
| 
 | ||||
| #		self.result = self.pg_db.cursor.execute(self.pgdict.query['list_tables']) | ||||
| #		self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result)) | ||||
| #        self.result = self.pg_db.cursor.execute(self.pgdict.query['list_tables']) | ||||
| #        self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result)) | ||||
| 
 | ||||
| 	def testMySQLRecreateTables(self): | ||||
| 		"""Test droping then recreating fpdb table schema""" | ||||
| 		self.mysql_db.recreate_tables() | ||||
| 		self.result = self.mysql_db.cursor.execute("SHOW TABLES") | ||||
| 		self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result)) | ||||
|     def testMySQLRecreateTables(self): | ||||
|         """Test droping then recreating fpdb table schema""" | ||||
|         self.mysql_db.recreate_tables() | ||||
|         self.result = self.mysql_db.cursor.execute("SHOW TABLES") | ||||
|         self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result)) | ||||
| 
 | ||||
| 	def testPokerStarsHHDate(self): | ||||
| 		latest = "PokerStars Game #21969660557:  Hold'em No Limit ($0.50/$1.00) - 2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET]" | ||||
| 		previous = "PokerStars Game #21969660557:  Hold'em No Limit ($0.50/$1.00) - 2008/08/17 - 01:14:43 (ET)" | ||||
| 		older1 = "PokerStars Game #21969660557:  Hold'em No Limit ($0.50/$1.00) - 2008/09/07 06:23:14 ET" | ||||
|     def testPokerStarsHHDate(self): | ||||
|         latest = "PokerStars Game #21969660557:  Hold'em No Limit ($0.50/$1.00) - 2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET]" | ||||
|         previous = "PokerStars Game #21969660557:  Hold'em No Limit ($0.50/$1.00) - 2008/08/17 - 01:14:43 (ET)" | ||||
|         older1 = "PokerStars Game #21969660557:  Hold'em No Limit ($0.50/$1.00) - 2008/09/07 06:23:14 ET" | ||||
| 
 | ||||
| 		result = fpdb_simple.parseHandStartTime(older1, "ps") | ||||
| 		self.failUnless(result==datetime.datetime(2008,9,7,11,23,14), | ||||
| 						"Date incorrect, expected: 2008-09-07 11:23:14 got: " + str(result)) | ||||
| 		result = fpdb_simple.parseHandStartTime(latest, "ps") | ||||
| 		self.failUnless(result==datetime.datetime(2008,11,12,15,00,48),  | ||||
| 						"Date incorrect, expected: 2008-11-12 15:00:48 got: " + str(result)) | ||||
| 		result = fpdb_simple.parseHandStartTime(previous, "ps") | ||||
| 		self.failUnless(result==datetime.datetime(2008,8,17,6,14,43), | ||||
| 						"Date incorrect, expected: 2008-08-17 01:14:43 got: " + str(result)) | ||||
|         result = fpdb_simple.parseHandStartTime(older1, "ps") | ||||
|         self.failUnless(result==datetime.datetime(2008,9,7,11,23,14), | ||||
|                         "Date incorrect, expected: 2008-09-07 11:23:14 got: " + str(result)) | ||||
|         result = fpdb_simple.parseHandStartTime(latest, "ps") | ||||
|         self.failUnless(result==datetime.datetime(2008,11,12,15,00,48),  | ||||
|                         "Date incorrect, expected: 2008-11-12 15:00:48 got: " + str(result)) | ||||
|         result = fpdb_simple.parseHandStartTime(previous, "ps") | ||||
|         self.failUnless(result==datetime.datetime(2008,8,17,6,14,43), | ||||
|                         "Date incorrect, expected: 2008-08-17 01:14:43 got: " + str(result)) | ||||
| 
 | ||||
| 	def testImportHandHistoryFiles(self): | ||||
| 		"""Test import of single HH file""" | ||||
| 		self.mysqlimporter.addImportFile("regression-test-files/hand-histories/ps-lhe-ring-3hands.txt") | ||||
| 		self.mysqlimporter.runImport() | ||||
| 		self.mysqlimporter.addImportDirectory("regression-test-files/hand-histories") | ||||
| 		self.mysqlimporter.runImport() | ||||
|     def testImportHandHistoryFiles(self): | ||||
|         """Test import of single HH file""" | ||||
|         self.mysqlimporter.addImportFile("regression-test-files/hand-histories/ps-lhe-ring-3hands.txt") | ||||
|         self.mysqlimporter.runImport() | ||||
|         self.mysqlimporter.addImportDirectory("regression-test-files/hand-histories") | ||||
|         self.mysqlimporter.runImport() | ||||
| 
 | ||||
| #	def testPostgresSQLRecreateTables(self): | ||||
| #		"""Test droping then recreating fpdb table schema""" | ||||
| #		self.pg_db.recreate_tables() | ||||
| #		self.result = self.pg_db.cursor.execute(self.pgdict.query['list_tables']) | ||||
| #		self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result)) | ||||
| #    def testPostgresSQLRecreateTables(self): | ||||
| #        """Test droping then recreating fpdb table schema""" | ||||
| #        self.pg_db.recreate_tables() | ||||
| #        self.result = self.pg_db.cursor.execute(self.pgdict.query['list_tables']) | ||||
| #        self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result)) | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|         unittest.main() | ||||
|  |  | |||
|  | @ -229,12 +229,11 @@ class Sql: | |||
|                         sum(street3CheckCallRaiseDone)   AS ccr_3, | ||||
|                         sum(street4CheckCallRaiseChance) AS ccr_opp_4, | ||||
|                         sum(street4CheckCallRaiseDone)   AS ccr_4 | ||||
|                     FROM HudCache, Hands | ||||
|                     WHERE HudCache.PlayerId in  | ||||
|                         (SELECT PlayerId FROM HandsPlayers  | ||||
|                         WHERE handId = %s) | ||||
|                     AND   Hands.id = %s | ||||
|                     AND   Hands.gametypeId = HudCache.gametypeId | ||||
|                     FROM Hands | ||||
|                          INNER JOIN HandsPlayers ON (HandsPlayers.handId = %s) | ||||
|                          INNER JOIN HudCache ON (    HudCache.PlayerId = HandsPlayers.PlayerId+0 | ||||
|                                                  AND HudCache.gametypeId+0 = Hands.gametypeId+0) | ||||
|                     WHERE Hands.id = %s | ||||
|                     GROUP BY HudCache.PlayerId | ||||
|                 """ | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										110
									
								
								pyfpdb/Stats.py
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								pyfpdb/Stats.py
									
									
									
									
									
								
							|  | @ -71,6 +71,7 @@ def do_stat(stat_dict, player = 24, stat = 'vpip'): | |||
| #    functions that return individual stats | ||||
| 
 | ||||
| def playername(stat_dict, player): | ||||
|     """    Player Name.""" | ||||
|     return (stat_dict[player]['screen_name'], | ||||
|             stat_dict[player]['screen_name'], | ||||
|             stat_dict[player]['screen_name'], | ||||
|  | @ -98,6 +99,26 @@ def vpip(stat_dict, player): | |||
|                     'Voluntarily Put In Pot %' | ||||
|                     ) | ||||
| 
 | ||||
| def vpip_0(stat_dict, player): | ||||
|     """    Voluntarily put $ in the pot (no decimals).""" | ||||
|     stat = 0.0 | ||||
|     try: | ||||
|         stat = float(stat_dict[player]['vpip'])/float(stat_dict[player]['n']) | ||||
|         return (stat,  | ||||
|                 '%2.0f'      % (100*stat) + '%',  | ||||
|                 'v=%2.0f'    % (100*stat) + '%',  | ||||
|                 'vpip=%2.0f' % (100*stat) + '%',  | ||||
|                 '(%d/%d)'    % (stat_dict[player]['vpip'], stat_dict[player]['n']), | ||||
|                 'vpip' | ||||
|                 ) | ||||
|     except: return (stat,  | ||||
|                     '%2.0f'      % (0) + '%',  | ||||
|                     'w=%2.0f'    % (0) + '%',  | ||||
|                     'wtsd=%2.0f' % (0) + '%',  | ||||
|                     '(%d/%d)'    % (0, 0), | ||||
|                     'wtsd' | ||||
|                     ) | ||||
| 
 | ||||
| def pfr(stat_dict, player): | ||||
|     """    Preflop (3rd street) raise.""" | ||||
|     stat = 0.0 | ||||
|  | @ -119,6 +140,27 @@ def pfr(stat_dict, player): | |||
|                 'Pre-Flop Raise %' | ||||
|                 ) | ||||
| 
 | ||||
| def pfr_0(stat_dict, player): | ||||
|     """    Preflop (3rd street) raise (no decimals).""" | ||||
|     stat = 0.0 | ||||
|     try: | ||||
|         stat = float(stat_dict[player]['pfr'])/float(stat_dict[player]['n']) | ||||
|         return (stat,  | ||||
|                 '%2.0f'      % (100*stat) + '%',  | ||||
|                 'p=%2.0f'    % (100*stat) + '%',  | ||||
|                 'pfr=%2.0f'  % (100*stat) + '%',  | ||||
|                 '(%d/%d)'    % (stat_dict[player]['pfr'], stat_dict[player]['n']), | ||||
|                 'pfr' | ||||
|                 ) | ||||
|     except:  | ||||
|         return (stat,  | ||||
|                 '%2.0f'      % (0) + '%',  | ||||
|                 'p=%2.0f'    % (0) + '%',  | ||||
|                 'pfr=%2.0f' % (0) + '%',  | ||||
|                 '(%d/%d)'    % (0, 0), | ||||
|                 'pfr' | ||||
|                 ) | ||||
| 
 | ||||
| def wtsd(stat_dict, player): | ||||
|     """    Went to SD when saw flop/4th.""" | ||||
|     stat = 0.0 | ||||
|  | @ -149,7 +191,7 @@ def wmsd(stat_dict, player): | |||
|                 '%3.1f'      % (100*stat) + '%',  | ||||
|                 'w=%3.1f'    % (100*stat) + '%',  | ||||
|                 'wmsd=%3.1f' % (100*stat) + '%',  | ||||
|                 '(%f5.0/%d)'    % (stat_dict[player]['wmsd'], stat_dict[player]['sd']), | ||||
|                 '(%5.1f/%d)'    % (float(stat_dict[player]['wmsd']), stat_dict[player]['sd']), | ||||
|                 '% won money at showdown' | ||||
|                 ) | ||||
|     except: | ||||
|  | @ -412,6 +454,61 @@ def a_freq_4(stat_dict, player): | |||
|                 '(%d/%d)'      % (0, 0), | ||||
|                 'Aggression Freq 7th' | ||||
|                 ) | ||||
| 
 | ||||
| def a_freq_123(stat_dict, player): | ||||
|     """    Post-Flop aggression frequency.""" | ||||
|     stat = 0.0 | ||||
|     try: | ||||
|         stat = float(  stat_dict[player]['aggr_1'] + stat_dict[player]['aggr_2'] + stat_dict[player]['aggr_3'] | ||||
|                     ) / float(  stat_dict[player]['saw_1'] + stat_dict[player]['saw_2'] + stat_dict[player]['saw_3']); | ||||
|         return (stat, | ||||
|                 '%3.1f'             % (100*stat) + '%',  | ||||
|                 'afq=%3.1f'         % (100*stat) + '%',  | ||||
|                 'postf_aggfq=%3.1f' % (100*stat) + '%',  | ||||
|                 '(%d/%d)'           % (  stat_dict[player]['aggr_1'] | ||||
|                                        + stat_dict[player]['aggr_2'] | ||||
|                                        + stat_dict[player]['aggr_3'] | ||||
|                                       ,  stat_dict[player]['saw_1'] | ||||
|                                        + stat_dict[player]['saw_2'] | ||||
|                                        + stat_dict[player]['saw_3'] | ||||
|                                       ), | ||||
|                 'Post-Flop Aggression Freq' | ||||
|                 ) | ||||
|     except: | ||||
|         return (stat, | ||||
|                 '%2.0f'        % (0) + '%',  | ||||
|                 'a3=%2.0f'     % (0) + '%',  | ||||
|                 'a_fq_3=%2.0f' % (0) + '%',  | ||||
|                 '(%d/%d)'      % (0, 0), | ||||
|                 'Post-Flop Aggression Freq' | ||||
|                 ) | ||||
| 
 | ||||
| def a_freq_123_0(stat_dict, player): | ||||
|     """    Post-Flop aggression frequency (no decimals).""" | ||||
|     stat = 0.0 | ||||
|     try: | ||||
|         stat = float(  stat_dict[player]['aggr_1'] + stat_dict[player]['aggr_2'] + stat_dict[player]['aggr_3']) / float(  stat_dict[player]['saw_1'] + stat_dict[player]['saw_2'] + stat_dict[player]['saw_3']); | ||||
|         return (stat, | ||||
|                 '%2.0f'             % (100*stat) + '%',  | ||||
|                 'afq=%2.0f'         % (100*stat) + '%',  | ||||
|                 'postf_aggfq=%2.0f' % (100*stat) + '%',  | ||||
|                 '(%d/%d)'           % (  stat_dict[player]['aggr_1'] | ||||
|                                        + stat_dict[player]['aggr_2'] | ||||
|                                        + stat_dict[player]['aggr_3'] | ||||
|                                       ,  stat_dict[player]['saw_1'] | ||||
|                                        + stat_dict[player]['saw_2'] | ||||
|                                        + stat_dict[player]['saw_3'] | ||||
|                                       ), | ||||
|                 'Post-Flop Aggression Freq' | ||||
|                 ) | ||||
|     except: | ||||
|         return (stat, | ||||
|                 '%2.0f'        % (0) + '%',  | ||||
|                 'a3=%2.0f'     % (0) + '%',  | ||||
|                 'a_fq_3=%2.0f' % (0) + '%',  | ||||
|                 '(%d/%d)'      % (0, 0), | ||||
|                 'Post-Flop Aggression Freq' | ||||
|                 ) | ||||
|      | ||||
| def cb_1(stat_dict, player): | ||||
|     """    Flop continuation bet.""" | ||||
|  | @ -589,7 +686,9 @@ if __name__== "__main__": | |||
|      | ||||
|     for player in stat_dict.keys(): | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'vpip')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'vpip_0')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'pfr')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'pfr_0')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'wtsd')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'saw_f')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'n')  | ||||
|  | @ -604,6 +703,8 @@ if __name__== "__main__": | |||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_2')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_3')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_4')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_123')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_123_0')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_1')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_2')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_3')  | ||||
|  | @ -611,7 +712,8 @@ if __name__== "__main__": | |||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_1')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_2')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_3')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_4')  | ||||
|         print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_4') | ||||
|         print "\n"  | ||||
| 
 | ||||
|     print "\n\nLegal stats:" | ||||
|     for attr in dir(): | ||||
|  | @ -619,8 +721,8 @@ if __name__== "__main__": | |||
|         if attr in ("Configuration", "Database", "GInitiallyUnowned", "gtk", "pygtk", | ||||
|                     "player", "c", "db_connection", "do_stat", "do_tip", "stat_dict", | ||||
|                     "h"): continue | ||||
|         print attr, eval("%s.__doc__" % (attr)) | ||||
|         print "%-14s %s" % (attr, eval("%s.__doc__" % (attr))) | ||||
| #        print "            <pu_stat pu_stat_name = \"%s\"> </pu_stat>" % (attr) | ||||
| 
 | ||||
|     db_connection.close | ||||
|     db_connection.close_connection | ||||
| 
 | ||||
|  |  | |||
|  | @ -37,6 +37,7 @@ import gtk | |||
| import fpdb_db | ||||
| import fpdb_simple | ||||
| import GuiBulkImport | ||||
| import GuiPlayerStats | ||||
| import GuiTableViewer | ||||
| import GuiAutoImport | ||||
| import GuiGraphViewer | ||||
|  | @ -117,12 +118,12 @@ class fpdb: | |||
| 	 | ||||
| 	def dia_create_del_database(self, widget, data): | ||||
| 		print "todo: implement dia_create_del_database" | ||||
| 		obtain_global_lock() | ||||
| 		self.obtain_global_lock() | ||||
| 	#end def dia_create_del_database | ||||
| 	 | ||||
| 	def dia_create_del_user(self, widget, data): | ||||
| 		print "todo: implement dia_create_del_user" | ||||
| 		obtain_global_lock() | ||||
| 		self.obtain_global_lock() | ||||
| 	#end def dia_create_del_user | ||||
| 	 | ||||
| 	def dia_database_stats(self, widget, data): | ||||
|  | @ -132,17 +133,17 @@ class fpdb: | |||
| 	 | ||||
| 	def dia_delete_db_parts(self, widget, data): | ||||
| 		print "todo: implement dia_delete_db_parts" | ||||
| 		obtain_global_lock() | ||||
| 		self.obtain_global_lock() | ||||
| 	#end def dia_delete_db_parts | ||||
| 	 | ||||
| 	def dia_edit_profile(self, widget=None, data=None, create_default=False, path=None): | ||||
| 		print "todo: implement dia_edit_profile" | ||||
| 		obtain_global_lock() | ||||
| 		self.obtain_global_lock() | ||||
| 	#end def dia_edit_profile | ||||
| 
 | ||||
| 	def dia_export_db(self, widget, data): | ||||
| 		print "todo: implement dia_export_db" | ||||
| 		obtain_global_lock() | ||||
| 		self.obtain_global_lock() | ||||
| 	#end def dia_export_db | ||||
| 	 | ||||
| 	def dia_get_db_root_credentials(self): | ||||
|  | @ -167,7 +168,7 @@ class fpdb: | |||
| 	 | ||||
| 	def dia_import_db(self, widget, data): | ||||
| 		print "todo: implement dia_import_db" | ||||
| 		obtain_global_lock() | ||||
| 		self.obtain_global_lock() | ||||
| 	#end def dia_import_db | ||||
| 	 | ||||
| 	def dia_licensing(self, widget, data): | ||||
|  | @ -263,7 +264,11 @@ class fpdb: | |||
| 		 | ||||
| 		self.db = fpdb_db.fpdb_db() | ||||
| 		#print "end of fpdb.load_profile, databaseName:",self.settings['db-databaseName'] | ||||
| 		self.db.connect(self.settings['db-backend'], self.settings['db-host'], self.settings['db-databaseName'], self.settings['db-user'], self.settings['db-password']) | ||||
| 		self.db.connect(self.settings['db-backend'], | ||||
|             self.settings['db-host'], | ||||
|             self.settings['db-databaseName'], | ||||
|             self.settings['db-user'],  | ||||
|             self.settings['db-password']) | ||||
| 		if self.db.wrongDbVersion: | ||||
| 			diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) | ||||
| 
 | ||||
|  | @ -283,7 +288,7 @@ class fpdb: | |||
| 			diaDbVersionWarning.destroy() | ||||
| 
 | ||||
| 		# Database connected to successfully, load queries to pass on to other classes | ||||
|                 self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name()) | ||||
| 		self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name()) | ||||
| 	#end def load_profile | ||||
| 	 | ||||
| 	def not_implemented(self): | ||||
|  | @ -326,6 +331,13 @@ class fpdb: | |||
| 		self.add_and_display_tab(bulk_tab, "Bulk Import") | ||||
| 	#end def tab_bulk_import | ||||
| 
 | ||||
| 	def tab_player_stats(self, widget, data): | ||||
| 		new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.db, self.config, self.querydict) | ||||
| 		self.threads.append(new_ps_thread) | ||||
| 		ps_tab=new_ps_thread.get_vbox() | ||||
| 		self.add_and_display_tab(ps_tab, "Player Stats") | ||||
| 
 | ||||
| 
 | ||||
| 	def tab_main_help(self, widget, data): | ||||
| 		"""Displays a tab with the main fpdb help screen""" | ||||
| 		#print "start of tab_main_help" | ||||
|  | @ -384,7 +396,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") | |||
| 				("/Viewers/_Graphs", "<control>G", self.tabGraphViewer, 0, None ), | ||||
| 				("/Viewers/Hand _Replayer (todo)", None, self.not_implemented, 0, None ), | ||||
| 				("/Viewers/Player _Details (todo)", None, self.not_implemented, 0, None ), | ||||
| 				("/Viewers/_Player Stats (tabulated view) (todo)", None, self.not_implemented, 0, None ), | ||||
| 				("/Viewers/_Player Stats (tabulated view)", None, self.tab_player_stats, 0, None ), | ||||
| 				("/Viewers/Starting _Hands (todo)", None, self.not_implemented, 0, None ), | ||||
| 				("/Viewers/_Session Replayer (todo)", None, self.not_implemented, 0, None ), | ||||
| 				("/Viewers/Poker_table Viewer (mostly obselete)", "<control>T", self.tab_table_viewer, 0, None ), | ||||
|  |  | |||
							
								
								
									
										292
									
								
								pyfpdb/fpdb_db.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										292
									
								
								pyfpdb/fpdb_db.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							|  | @ -21,153 +21,171 @@ import fpdb_simple | |||
| import FpdbSQLQueries | ||||
| 
 | ||||
| class fpdb_db: | ||||
| 	def __init__(self): | ||||
| 		"""Simple constructor, doesnt really do anything""" | ||||
| 		self.db=None | ||||
| 		self.cursor=None | ||||
| 		self.sql = {} | ||||
| 		self.MYSQL_INNODB=2 | ||||
| 		self.PGSQL=3 | ||||
| 		self.SQLITE=4 | ||||
| 	#end def __init__ | ||||
| 	 | ||||
| 	def connect(self, backend, host, database, user, password): | ||||
| 		"""Connects a database with the given parameters""" | ||||
| 		self.backend=backend | ||||
| 		self.host=host | ||||
| 		self.database=database | ||||
| 		self.user=user | ||||
| 		self.password=password | ||||
| 		if backend==self.MYSQL_INNODB: | ||||
| 			import MySQLdb | ||||
| 			self.db=MySQLdb.connect(host = host, user = user, passwd = password, db = database) | ||||
| 		elif backend==self.PGSQL: | ||||
| 			import psycopg2 | ||||
| 			self.db = psycopg2.connect(host = host, user = user, password = password, database = database) | ||||
| 		else: | ||||
| 			raise fpdb_simple.FpdbError("unrecognised database backend:"+backend) | ||||
| 		self.cursor=self.db.cursor() | ||||
| 		self.cursor.execute('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED') | ||||
| 		# Set up query dictionary as early in the connection process as we can. | ||||
|                 self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name()) | ||||
| 		self.wrongDbVersion=False | ||||
| 		try: | ||||
| 			self.cursor.execute("SELECT * FROM Settings") | ||||
| 			settings=self.cursor.fetchone() | ||||
| 			if settings[0]!=118: | ||||
| 				print "outdated or too new database version - please recreate tables" | ||||
| 				self.wrongDbVersion=True | ||||
| 		except:# _mysql_exceptions.ProgrammingError: | ||||
| 			print "failed to read settings table - please recreate tables" | ||||
| 			self.wrongDbVersion=True | ||||
| 	#end def connect | ||||
|     def __init__(self): | ||||
|         """Simple constructor, doesnt really do anything""" | ||||
|         self.db=None | ||||
|         self.cursor=None | ||||
|         self.sql = {} | ||||
|         self.MYSQL_INNODB=2 | ||||
|         self.PGSQL=3 | ||||
|         self.SQLITE=4 | ||||
|     #end def __init__ | ||||
|      | ||||
|     def connect(self, backend=None, host=None, database=None, | ||||
|                 user=None, password=None): | ||||
|         """Connects a database with the given parameters""" | ||||
|         if backend is None: | ||||
|             raise FpdbError('Database backend not defined') | ||||
|         self.backend=backend | ||||
|         self.host=host | ||||
|         self.user=user | ||||
|         self.password=password | ||||
|         self.database=database | ||||
|         if backend==self.MYSQL_INNODB: | ||||
|             import MySQLdb | ||||
|             self.db=MySQLdb.connect(host = host, user = user, passwd = password, db = database) | ||||
|         elif backend==self.PGSQL: | ||||
|             import psycopg2 | ||||
|             # If DB connection is made over TCP, then the variables | ||||
|             # host, user and password are required | ||||
|             print "host=%s user=%s pass=%s." % (host, user, password) | ||||
|             if self.host and self.user and self.password: | ||||
|                 self.db = psycopg2.connect(host = host, | ||||
|                         user = user,  | ||||
|                         password = password,  | ||||
|                         database = database) | ||||
|             # For local domain-socket connections, only DB name is | ||||
|             # needed, and everything else is in fact undefined and/or | ||||
|             # flat out wrong | ||||
|             else: | ||||
|                 self.db = psycopg2.connect(database = database) | ||||
|         else: | ||||
|             raise fpdb_simple.FpdbError("unrecognised database backend:"+backend) | ||||
|         self.cursor=self.db.cursor() | ||||
|         self.cursor.execute('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED') | ||||
|         # Set up query dictionary as early in the connection process as we can. | ||||
|         self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name()) | ||||
|         self.wrongDbVersion=False | ||||
|         try: | ||||
|             self.cursor.execute("SELECT * FROM Settings") | ||||
|             settings=self.cursor.fetchone() | ||||
|             if settings[0]!=118: | ||||
|                 print "outdated or too new database version - please recreate tables" | ||||
|                 self.wrongDbVersion=True | ||||
|         except:# _mysql_exceptions.ProgrammingError: | ||||
|             print "failed to read settings table - please recreate tables" | ||||
|             self.wrongDbVersion=True | ||||
|     #end def connect | ||||
| 
 | ||||
| 	def disconnect(self, due_to_error=False): | ||||
| 		"""Disconnects the DB""" | ||||
| 		if due_to_error: | ||||
| 			self.db.rollback() | ||||
| 		else: | ||||
| 			self.db.commit() | ||||
| 		self.cursor.close() | ||||
| 		self.db.close() | ||||
| 	#end def disconnect | ||||
| 	 | ||||
| 	def reconnect(self, due_to_error=False): | ||||
| 		"""Reconnects the DB""" | ||||
| 		#print "started fpdb_db.reconnect" | ||||
| 		self.disconnect(due_to_error) | ||||
| 		self.connect(self.backend, self.host, self.database, self.user, self.password) | ||||
|     def disconnect(self, due_to_error=False): | ||||
|         """Disconnects the DB""" | ||||
|         if due_to_error: | ||||
|             self.db.rollback() | ||||
|         else: | ||||
|             self.db.commit() | ||||
|         self.cursor.close() | ||||
|         self.db.close() | ||||
|     #end def disconnect | ||||
|      | ||||
|     def reconnect(self, due_to_error=False): | ||||
|         """Reconnects the DB""" | ||||
|         #print "started fpdb_db.reconnect" | ||||
|         self.disconnect(due_to_error) | ||||
|         self.connect(self.backend, self.host, self.database, self.user, self.password) | ||||
| 
 | ||||
| 	def create_tables(self): | ||||
| 		#todo: should detect and fail gracefully if tables already exist. | ||||
| 		self.cursor.execute(self.sql.query['createSettingsTable']) | ||||
|                 self.cursor.execute(self.sql.query['createSitesTable']) | ||||
|                 self.cursor.execute(self.sql.query['createGametypesTable']) | ||||
|                 self.cursor.execute(self.sql.query['createPlayersTable']) | ||||
|                 self.cursor.execute(self.sql.query['createAutoratesTable']) | ||||
|                 self.cursor.execute(self.sql.query['createHandsTable']) | ||||
|                 self.cursor.execute(self.sql.query['createBoardCardsTable']) | ||||
|                 self.cursor.execute(self.sql.query['createTourneyTypesTable']) | ||||
|                 self.cursor.execute(self.sql.query['createTourneysTable']) | ||||
|                 self.cursor.execute(self.sql.query['createTourneysPlayersTable']) | ||||
|                 self.cursor.execute(self.sql.query['createHandsPlayersTable']) | ||||
|                 self.cursor.execute(self.sql.query['createHandsActionsTable']) | ||||
|                 self.cursor.execute(self.sql.query['createHudCacheTable']) | ||||
| 		self.fillDefaultData() | ||||
|                 self.db.commit() | ||||
|     def create_tables(self): | ||||
|         #todo: should detect and fail gracefully if tables already exist. | ||||
|         self.cursor.execute(self.sql.query['createSettingsTable']) | ||||
|         self.cursor.execute(self.sql.query['createSitesTable']) | ||||
|         self.cursor.execute(self.sql.query['createGametypesTable']) | ||||
|         self.cursor.execute(self.sql.query['createPlayersTable']) | ||||
|         self.cursor.execute(self.sql.query['createAutoratesTable']) | ||||
|         self.cursor.execute(self.sql.query['createHandsTable']) | ||||
|         self.cursor.execute(self.sql.query['createBoardCardsTable']) | ||||
|         self.cursor.execute(self.sql.query['createTourneyTypesTable']) | ||||
|         self.cursor.execute(self.sql.query['createTourneysTable']) | ||||
|         self.cursor.execute(self.sql.query['createTourneysPlayersTable']) | ||||
|         self.cursor.execute(self.sql.query['createHandsPlayersTable']) | ||||
|         self.cursor.execute(self.sql.query['createHandsActionsTable']) | ||||
|         self.cursor.execute(self.sql.query['createHudCacheTable']) | ||||
|         self.cursor.execute(self.sql.query['addTourneyIndex']) | ||||
|         self.cursor.execute(self.sql.query['addHandsIndex']) | ||||
|         self.cursor.execute(self.sql.query['addPlayersIndex']) | ||||
|         self.fillDefaultData() | ||||
|         self.db.commit() | ||||
| #end def disconnect | ||||
| 	 | ||||
| 	def drop_tables(self): | ||||
| 		"""Drops the fpdb tables from the current db""" | ||||
|      | ||||
|     def drop_tables(self): | ||||
|         """Drops the fpdb tables from the current db""" | ||||
| 
 | ||||
| 		if(self.get_backend_name() == 'MySQL InnoDB'): | ||||
| 			#Databases with FOREIGN KEY support need this switched of before you can drop tables | ||||
|                 	self.drop_referencial_integrity() | ||||
|         if(self.get_backend_name() == 'MySQL InnoDB'): | ||||
|             #Databases with FOREIGN KEY support need this switched of before you can drop tables | ||||
|             self.drop_referencial_integrity() | ||||
| 
 | ||||
| 			# Query the DB to see what tables exist | ||||
| 			self.cursor.execute(self.sql.query['list_tables']) | ||||
| 	                for table in self.cursor: | ||||
|                 	        self.cursor.execute(self.sql.query['drop_table'] + table[0]) | ||||
| 		elif(self.get_backend_name() == 'PostgreSQL'): | ||||
| 			self.db.commit()# I have no idea why this makes the query work--REB 07OCT2008 | ||||
| 			self.cursor.execute(self.sql.query['list_tables']) | ||||
| 			tables = self.cursor.fetchall() | ||||
| 	                for table in tables: | ||||
|                 	        self.cursor.execute(self.sql.query['drop_table'] + table[0] + ' cascade')  | ||||
| 		elif(self.get_backend_name() == 'SQLite'): | ||||
| 			#todo: sqlite version here | ||||
| 			print "Empty function here" | ||||
|             # Query the DB to see what tables exist | ||||
|             self.cursor.execute(self.sql.query['list_tables']) | ||||
|             for table in self.cursor: | ||||
|                 self.cursor.execute(self.sql.query['drop_table'] + table[0]) | ||||
|         elif(self.get_backend_name() == 'PostgreSQL'): | ||||
|             self.db.commit()# I have no idea why this makes the query work--REB 07OCT2008 | ||||
|             self.cursor.execute(self.sql.query['list_tables']) | ||||
|             tables = self.cursor.fetchall() | ||||
|             for table in tables: | ||||
|                 self.cursor.execute(self.sql.query['drop_table'] + table[0] + ' cascade')  | ||||
|         elif(self.get_backend_name() == 'SQLite'): | ||||
|             #todo: sqlite version here | ||||
|             print "Empty function here" | ||||
| 
 | ||||
|                 self.db.commit() | ||||
| 	#end def drop_tables | ||||
|             self.db.commit() | ||||
|     #end def drop_tables | ||||
| 
 | ||||
| 	def drop_referencial_integrity(self): | ||||
| 		"""Update all tables to remove foreign keys""" | ||||
|     def drop_referencial_integrity(self): | ||||
|         """Update all tables to remove foreign keys""" | ||||
| 
 | ||||
| 		self.cursor.execute(self.sql.query['list_tables']) | ||||
| 		result = self.cursor.fetchall() | ||||
|         self.cursor.execute(self.sql.query['list_tables']) | ||||
|         result = self.cursor.fetchall() | ||||
| 
 | ||||
| 		for i in range(len(result)): | ||||
| 			self.cursor.execute("SHOW CREATE TABLE " + result[i][0]) | ||||
| 			inner = self.cursor.fetchall() | ||||
|         for i in range(len(result)): | ||||
|             self.cursor.execute("SHOW CREATE TABLE " + result[i][0]) | ||||
|             inner = self.cursor.fetchall() | ||||
| 
 | ||||
| 			for j in range(len(inner)): | ||||
| 			# result[i][0] - Table name | ||||
| 			# result[i][1] - CREATE TABLE parameters | ||||
| 			#Searching for CONSTRAINT `tablename_ibfk_1` | ||||
| 				for m in re.finditer('(ibfk_[0-9]+)', inner[j][1]): | ||||
| 					key = "`" + inner[j][0] + "_" + m.group() + "`" | ||||
| 					self.cursor.execute("ALTER TABLE " + inner[j][0] + " DROP FOREIGN KEY " + key) | ||||
|             for j in range(len(inner)): | ||||
|             # result[i][0] - Table name | ||||
|             # result[i][1] - CREATE TABLE parameters | ||||
|             #Searching for CONSTRAINT `tablename_ibfk_1` | ||||
|                 for m in re.finditer('(ibfk_[0-9]+)', inner[j][1]): | ||||
|                     key = "`" + inner[j][0] + "_" + m.group() + "`" | ||||
|                     self.cursor.execute("ALTER TABLE " + inner[j][0] + " DROP FOREIGN KEY " + key) | ||||
|                 self.db.commit() | ||||
|         #end drop_referencial_inegrity | ||||
| 	 | ||||
| 	def get_backend_name(self): | ||||
| 		"""Returns the name of the currently used backend""" | ||||
| 		if self.backend==2: | ||||
| 			return "MySQL InnoDB" | ||||
| 		elif self.backend==3: | ||||
| 			return "PostgreSQL" | ||||
| 		else: | ||||
| 			raise fpdb_simple.FpdbError("invalid backend") | ||||
| 	#end def get_backend_name | ||||
| 	 | ||||
| 	def get_db_info(self): | ||||
| 		return (self.host, self.database, self.user, self.password) | ||||
| 	#end def get_db_info | ||||
| 	 | ||||
| 	def fillDefaultData(self): | ||||
| 		self.cursor.execute("INSERT INTO Settings VALUES (118);") | ||||
| 		self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'Full Tilt Poker', 'USD');") | ||||
| 		self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'PokerStars', 'USD');") | ||||
| 		self.cursor.execute("INSERT INTO TourneyTypes VALUES (DEFAULT, 1, 0, 0, 0, False);") | ||||
| 	#end def fillDefaultData | ||||
| 	 | ||||
| 	def recreate_tables(self): | ||||
| 		"""(Re-)creates the tables of the current DB""" | ||||
| 		 | ||||
| 		self.drop_tables() | ||||
| 		self.create_tables() | ||||
| 		self.db.commit() | ||||
| 		print "Finished recreating tables" | ||||
| 	#end def recreate_tables | ||||
|      | ||||
|     def get_backend_name(self): | ||||
|         """Returns the name of the currently used backend""" | ||||
|         if self.backend==2: | ||||
|             return "MySQL InnoDB" | ||||
|         elif self.backend==3: | ||||
|             return "PostgreSQL" | ||||
|         else: | ||||
|             raise fpdb_simple.FpdbError("invalid backend") | ||||
|     #end def get_backend_name | ||||
|      | ||||
|     def get_db_info(self): | ||||
|         return (self.host, self.database, self.user, self.password) | ||||
|     #end def get_db_info | ||||
|      | ||||
|     def fillDefaultData(self): | ||||
|         self.cursor.execute("INSERT INTO Settings VALUES (118);") | ||||
|         self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'Full Tilt Poker', 'USD');") | ||||
|         self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'PokerStars', 'USD');") | ||||
|         self.cursor.execute("INSERT INTO TourneyTypes VALUES (DEFAULT, 1, 0, 0, 0, False);") | ||||
|     #end def fillDefaultData | ||||
|      | ||||
|     def recreate_tables(self): | ||||
|         """(Re-)creates the tables of the current DB""" | ||||
|          | ||||
|         self.drop_tables() | ||||
|         self.create_tables() | ||||
|         self.db.commit() | ||||
|         print "Finished recreating tables" | ||||
|     #end def recreate_tables | ||||
| #end class fpdb_db | ||||
|  |  | |||
							
								
								
									
										508
									
								
								pyfpdb/fpdb_import.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										508
									
								
								pyfpdb/fpdb_import.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							|  | @ -20,16 +20,16 @@ | |||
| import sys | ||||
| 
 | ||||
| try: | ||||
| 	import MySQLdb | ||||
| 	mysqlLibFound=True | ||||
|     import MySQLdb | ||||
|     mysqlLibFound=True | ||||
| except: | ||||
| 	pass | ||||
| 	 | ||||
|     pass | ||||
|      | ||||
| try: | ||||
| 	import psycopg2 | ||||
| 	pgsqlLibFound=True | ||||
|     import psycopg2 | ||||
|     pgsqlLibFound=True | ||||
| except: | ||||
| 	pass | ||||
|     pass | ||||
| 
 | ||||
| import traceback | ||||
| import math | ||||
|  | @ -42,274 +42,282 @@ from time import time | |||
| 
 | ||||
| class Importer: | ||||
| 
 | ||||
| 	def __init__(self, caller, settings, config): | ||||
| 		"""Constructor""" | ||||
| 		self.settings=settings | ||||
| 		self.caller=caller | ||||
| 		self.config = config | ||||
| 		self.db = None | ||||
| 		self.cursor = None | ||||
| 		self.filelist = {} | ||||
| 		self.dirlist = {} | ||||
| 		self.monitor = False | ||||
| 		self.updated = {}		#Time last import was run {file:mtime} | ||||
| 		self.lines = None | ||||
| 		self.faobs = None		#File as one big string | ||||
| 		self.pos_in_file = {} # dict to remember how far we have read in the file | ||||
| 		#Set defaults | ||||
| 		self.callHud = self.config.get_import_parameters().get("callFpdbHud") | ||||
| 		if not self.settings.has_key('minPrint'): | ||||
| 			self.settings['minPrint'] = 30 | ||||
| 		self.dbConnect() | ||||
|     def __init__(self, caller, settings, config): | ||||
|         """Constructor""" | ||||
|         self.settings=settings | ||||
|         self.caller=caller | ||||
|         self.config = config | ||||
|         self.db = None | ||||
|         self.cursor = None | ||||
|         self.filelist = {} | ||||
|         self.dirlist = {} | ||||
|         self.monitor = False | ||||
|         self.updated = {}       #Time last import was run {file:mtime} | ||||
|         self.lines = None | ||||
|         self.faobs = None       #File as one big string | ||||
|         self.pos_in_file = {} # dict to remember how far we have read in the file | ||||
|         #Set defaults | ||||
|         self.callHud = self.config.get_import_parameters().get("callFpdbHud") | ||||
|         if not self.settings.has_key('minPrint'): | ||||
|             self.settings['minPrint'] = 30 | ||||
|         self.dbConnect() | ||||
| 
 | ||||
| 	def dbConnect(self): | ||||
| 		#connect to DB | ||||
| 		if self.settings['db-backend'] == 2: | ||||
| 			if not mysqlLibFound: | ||||
| 				raise fpdb_simple.FpdbError("interface library MySQLdb not found but MySQL selected as backend - please install the library or change the config file") | ||||
| 			self.db = MySQLdb.connect(self.settings['db-host'], self.settings['db-user'], | ||||
| 							self.settings['db-password'], self.settings['db-databaseName']) | ||||
| 		elif self.settings['db-backend'] == 3: | ||||
| 			if not pgsqlLibFound: | ||||
| 				raise fpdb_simple.FpdbError("interface library psycopg2 not found but PostgreSQL selected as backend - please install the library or change the config file") | ||||
| 			print self.settings | ||||
| 			self.db = psycopg2.connect(host = self.settings['db-host'], | ||||
| 									   user = self.settings['db-user'], | ||||
| 									   password = self.settings['db-password'], | ||||
| 									   database = self.settings['db-databaseName']) | ||||
| 		elif self.settings['db-backend'] == 4: | ||||
| 			pass | ||||
| 		else: | ||||
| 			pass | ||||
| 		self.cursor = self.db.cursor() | ||||
|     # XXX: Why is this here, when fpdb_db.connect() already does the | ||||
|     # same? | ||||
|     def dbConnect(self): | ||||
|         #connect to DB | ||||
|         if self.settings['db-backend'] == 2: | ||||
|             if not mysqlLibFound: | ||||
|                 raise fpdb_simple.FpdbError("interface library MySQLdb not found but MySQL selected as backend - please install the library or change the config file") | ||||
|             self.db = MySQLdb.connect(self.settings['db-host'], self.settings['db-user'], | ||||
|                             self.settings['db-password'], self.settings['db-databaseName']) | ||||
|         elif self.settings['db-backend'] == 3: | ||||
|             if not pgsqlLibFound: | ||||
|                 raise fpdb_simple.FpdbError("interface library psycopg2 not found but PostgreSQL selected as backend - please install the library or change the config file") | ||||
|             print self.settings | ||||
|             if self.settings.has_key('db-host') and \ | ||||
|                         self.settings.has_key('db-user'): | ||||
|                 self.db = psycopg2.connect(host = self.settings['db-host'], | ||||
|                                        user = self.settings['db-user'], | ||||
|                                        password = self.settings['db-password'], | ||||
|                                        database = self.settings['db-databaseName']) | ||||
|             else: | ||||
|                 dbname = self.settings['db-databaseName'] | ||||
|                 self.db = psycopg2.connect(database = dbname) | ||||
|         elif self.settings['db-backend'] == 4: | ||||
|             pass | ||||
|         else: | ||||
|             pass | ||||
|         self.cursor = self.db.cursor() | ||||
| 
 | ||||
| 	#Set functions | ||||
| 	def setCallHud(self, value): | ||||
| 		self.callHud = value | ||||
|     #Set functions | ||||
|     def setCallHud(self, value): | ||||
|         self.callHud = value | ||||
| 
 | ||||
| 	def setMinPrint(self, value): | ||||
| 		self.settings['minPrint'] = int(value) | ||||
|     def setMinPrint(self, value): | ||||
|         self.settings['minPrint'] = int(value) | ||||
| 
 | ||||
| 	def setHandCount(self, value): | ||||
| 		self.settings['handCount'] = int(value) | ||||
|     def setHandCount(self, value): | ||||
|         self.settings['handCount'] = int(value) | ||||
| 
 | ||||
| 	def setQuiet(self, value): | ||||
| 		self.settings['quiet'] = value | ||||
|     def setQuiet(self, value): | ||||
|         self.settings['quiet'] = value | ||||
| 
 | ||||
| 	def setFailOnError(self, value): | ||||
| 		self.settings['failOnError'] = value | ||||
|     def setFailOnError(self, value): | ||||
|         self.settings['failOnError'] = value | ||||
| 
 | ||||
| #	def setWatchTime(self): | ||||
| #		self.updated = time() | ||||
| #   def setWatchTime(self): | ||||
| #       self.updated = time() | ||||
| 
 | ||||
| 	def clearFileList(self): | ||||
| 		self.filelist = {} | ||||
|     def clearFileList(self): | ||||
|         self.filelist = {} | ||||
| 
 | ||||
| 	#Add an individual file to filelist | ||||
| 	def addImportFile(self, filename, site = "default", filter = "passthrough"): | ||||
| 		#TODO: test it is a valid file | ||||
| 		self.filelist[filename] = [site] + [filter] | ||||
|     #Add an individual file to filelist | ||||
|     def addImportFile(self, filename, site = "default", filter = "passthrough"): | ||||
|         #TODO: test it is a valid file | ||||
|         self.filelist[filename] = [site] + [filter] | ||||
| 
 | ||||
| 	#Add a directory of files to filelist | ||||
| 	#Only one import directory per site supported. | ||||
| 	#dirlist is a hash of lists: | ||||
| 	#dirlist{ 'PokerStars' => ["/path/to/import/", "filtername"] } | ||||
| 	def addImportDirectory(self,dir,monitor = False, site = "default", filter = "passthrough"): | ||||
| 		if os.path.isdir(dir): | ||||
| 			if monitor == True: | ||||
| 				self.monitor = True | ||||
| 				self.dirlist[site] = [dir] + [filter] | ||||
|     #Add a directory of files to filelist | ||||
|     #Only one import directory per site supported. | ||||
|     #dirlist is a hash of lists: | ||||
|     #dirlist{ 'PokerStars' => ["/path/to/import/", "filtername"] } | ||||
|     def addImportDirectory(self,dir,monitor = False, site = "default", filter = "passthrough"): | ||||
|         if os.path.isdir(dir): | ||||
|             if monitor == True: | ||||
|                 self.monitor = True | ||||
|                 self.dirlist[site] = [dir] + [filter] | ||||
| 
 | ||||
| 			for file in os.listdir(dir): | ||||
| 				self.addImportFile(os.path.join(dir, file), site, filter) | ||||
| 		else: | ||||
| 			print "Warning: Attempted to add: '" + str(dir) + "' as an import directory" | ||||
|             for file in os.listdir(dir): | ||||
|                 self.addImportFile(os.path.join(dir, file), site, filter) | ||||
|         else: | ||||
|             print "Warning: Attempted to add: '" + str(dir) + "' as an import directory" | ||||
| 
 | ||||
| 	#Run full import on filelist | ||||
| 	def runImport(self): | ||||
| 		for file in self.filelist: | ||||
| 			self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) | ||||
|     #Run full import on filelist | ||||
|     def runImport(self): | ||||
|         for file in self.filelist: | ||||
|             self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) | ||||
| 
 | ||||
| 	#Run import on updated files, then store latest update time. | ||||
| 	def runUpdated(self): | ||||
| 		#Check for new files in directory | ||||
| 		#todo: make efficient - always checks for new file, should be able to use mtime of directory | ||||
| 		# ^^ May not work on windows | ||||
| 		for site in self.dirlist: | ||||
| 			self.addImportDirectory(self.dirlist[site][0], False, site, self.dirlist[site][1]) | ||||
|     #Run import on updated files, then store latest update time. | ||||
|     def runUpdated(self): | ||||
|         #Check for new files in directory | ||||
|         #todo: make efficient - always checks for new file, should be able to use mtime of directory | ||||
|         # ^^ May not work on windows | ||||
|         for site in self.dirlist: | ||||
|             self.addImportDirectory(self.dirlist[site][0], False, site, self.dirlist[site][1]) | ||||
| 
 | ||||
| 		for file in self.filelist: | ||||
| 			stat_info = os.stat(file) | ||||
| 			try:  | ||||
| 				lastupdate = self.updated[file] | ||||
| 				if stat_info.st_mtime > lastupdate: | ||||
| 					self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) | ||||
| 					self.updated[file] = time() | ||||
| 			except: | ||||
| 				self.updated[file] = time() | ||||
| 				# This codepath only runs first time the file is found, if modified in the last | ||||
| 				# minute run an immediate import. | ||||
| 				if (time() - stat_info.st_mtime) < 60: | ||||
| 					self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) | ||||
|         for file in self.filelist: | ||||
|             stat_info = os.stat(file) | ||||
|             try:  | ||||
|                 lastupdate = self.updated[file] | ||||
|                 if stat_info.st_mtime > lastupdate: | ||||
|                     self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) | ||||
|                     self.updated[file] = time() | ||||
|             except: | ||||
|                 self.updated[file] = time() | ||||
|                 # This codepath only runs first time the file is found, if modified in the last | ||||
|                 # minute run an immediate import. | ||||
|                 if (time() - stat_info.st_mtime) < 60: | ||||
|                     self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) | ||||
| 
 | ||||
| 	# This is now an internal function that should not be called directly. | ||||
| 	def import_file_dict(self, file, site, filter): | ||||
| 		if(filter == "passthrough"): | ||||
| 			self.import_fpdb_file(file, site) | ||||
| 		else: | ||||
| 			#Load filter, and run filtered file though main importer | ||||
| 			self.import_fpdb_file(file, site) | ||||
|     # This is now an internal function that should not be called directly. | ||||
|     def import_file_dict(self, file, site, filter): | ||||
|         if(filter == "passthrough"): | ||||
|             self.import_fpdb_file(file, site) | ||||
|         else: | ||||
|             #Load filter, and run filtered file though main importer | ||||
|             self.import_fpdb_file(file, site) | ||||
| 
 | ||||
| 
 | ||||
| 	def import_fpdb_file(self, file, site): | ||||
| 		starttime = time() | ||||
| 		last_read_hand=0 | ||||
| 		loc = 0 | ||||
| 		if (file=="stdin"): | ||||
| 			inputFile=sys.stdin | ||||
| 		else: | ||||
| 			inputFile=open(file, "rU") | ||||
| 			try: loc = self.pos_in_file[file] | ||||
| 			except: pass | ||||
|     def import_fpdb_file(self, file, site): | ||||
|         starttime = time() | ||||
|         last_read_hand=0 | ||||
|         loc = 0 | ||||
|         if (file=="stdin"): | ||||
|             inputFile=sys.stdin | ||||
|         else: | ||||
|             inputFile=open(file, "rU") | ||||
|             try: loc = self.pos_in_file[file] | ||||
|             except: pass | ||||
| 
 | ||||
| 		# Read input file into class and close file | ||||
| 		inputFile.seek(loc) | ||||
| 		self.lines=fpdb_simple.removeTrailingEOL(inputFile.readlines()) | ||||
| 		self.pos_in_file[file] = inputFile.tell() | ||||
| 		inputFile.close() | ||||
|         # Read input file into class and close file | ||||
|         inputFile.seek(loc) | ||||
|         self.lines=fpdb_simple.removeTrailingEOL(inputFile.readlines()) | ||||
|         self.pos_in_file[file] = inputFile.tell() | ||||
|         inputFile.close() | ||||
| 
 | ||||
| 		try: # sometimes we seem to be getting an empty self.lines, in which case, we just want to return. | ||||
| 			firstline = self.lines[0] | ||||
| 		except: | ||||
| #			print "import_fpdb_file", file, site, self.lines, "\n" | ||||
| 			return | ||||
|         try: # sometimes we seem to be getting an empty self.lines, in which case, we just want to return. | ||||
|             firstline = self.lines[0] | ||||
|         except: | ||||
| #           print "import_fpdb_file", file, site, self.lines, "\n" | ||||
|             return | ||||
| 
 | ||||
| 		if firstline.find("Tournament Summary")!=-1: | ||||
| 			print "TODO: implement importing tournament summaries" | ||||
| 			#self.faobs = readfile(inputFile) | ||||
| 			#self.parseTourneyHistory() | ||||
| 			return 0 | ||||
| 		 | ||||
| 		site=fpdb_simple.recogniseSite(firstline) | ||||
| 		category=fpdb_simple.recogniseCategory(firstline) | ||||
|         if firstline.find("Tournament Summary")!=-1: | ||||
|             print "TODO: implement importing tournament summaries" | ||||
|             #self.faobs = readfile(inputFile) | ||||
|             #self.parseTourneyHistory() | ||||
|             return 0 | ||||
|          | ||||
|         site=fpdb_simple.recogniseSite(firstline) | ||||
|         category=fpdb_simple.recogniseCategory(firstline) | ||||
| 
 | ||||
| 		startpos=0 | ||||
| 		stored=0 #counter | ||||
| 		duplicates=0 #counter | ||||
| 		partial=0 #counter | ||||
| 		errors=0 #counter | ||||
|         startpos=0 | ||||
|         stored=0 #counter | ||||
|         duplicates=0 #counter | ||||
|         partial=0 #counter | ||||
|         errors=0 #counter | ||||
| 
 | ||||
| 		for i in range (len(self.lines)): #main loop, iterates through the lines of a file and calls the appropriate parser method | ||||
| 			if (len(self.lines[i])<2): | ||||
| 				endpos=i | ||||
| 				hand=self.lines[startpos:endpos] | ||||
| 		 | ||||
| 				if (len(hand[0])<2): | ||||
| 					hand=hand[1:] | ||||
| 		 | ||||
| 				cancelled=False | ||||
| 				damaged=False | ||||
| 				if (site=="ftp"): | ||||
| 					for i in range (len(hand)): | ||||
| 						if (hand[i].endswith(" has been canceled")): #this is their typo. this is a typo, right? | ||||
| 							cancelled=True | ||||
| 						 | ||||
| 						seat1=hand[i].find("Seat ") #todo: make this recover by skipping this line | ||||
| 						if (seat1!=-1): | ||||
| 							if (hand[i].find("Seat ", seat1+3)!=-1): | ||||
| 								damaged=True | ||||
| 				 | ||||
| 				if (len(hand)<3): | ||||
| 					pass | ||||
| 					#todo: the above 2 lines are kind of a dirty hack, the mentioned circumstances should be handled elsewhere but that doesnt work with DOS/Win EOL. actually this doesnt work. | ||||
| 				elif (hand[0].endswith(" (partial)")): #partial hand - do nothing | ||||
| 					partial+=1 | ||||
| 				elif (hand[1].find("Seat")==-1 and hand[2].find("Seat")==-1 and hand[3].find("Seat")==-1):#todo: should this be or instead of and? | ||||
| 					partial+=1 | ||||
| 				elif (cancelled or damaged): | ||||
| 					partial+=1 | ||||
| 				else: #normal processing | ||||
| 					isTourney=fpdb_simple.isTourney(hand[0]) | ||||
| 					if not isTourney: | ||||
| 						fpdb_simple.filterAnteBlindFold(site,hand) | ||||
| 					hand=fpdb_simple.filterCrap(site, hand, isTourney) | ||||
| 					self.hand=hand | ||||
| 					 | ||||
| 					try: | ||||
| 						handsId=fpdb_parse_logic.mainParser(self.db, self.cursor, site, category, hand) | ||||
| 						self.db.commit() | ||||
| 						 | ||||
| 						stored+=1 | ||||
| 						self.db.commit() | ||||
| 						if self.callHud: | ||||
| 							#print "call to HUD here. handsId:",handsId | ||||
| 							#pipe the Hands.id out to the HUD | ||||
| 							self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) | ||||
| 					except fpdb_simple.DuplicateError: | ||||
| 						duplicates+=1 | ||||
| 					except (ValueError), fe: | ||||
| 						errors+=1 | ||||
| 						self.printEmailErrorMessage(errors, file, hand) | ||||
| 				 | ||||
| 						if (self.settings['failOnError']): | ||||
| 							self.db.commit() #dont remove this, in case hand processing was cancelled. | ||||
| 							raise | ||||
| 					except (fpdb_simple.FpdbError), fe: | ||||
| 						errors+=1 | ||||
| 						self.printEmailErrorMessage(errors, file, hand) | ||||
|         for i in range (len(self.lines)): #main loop, iterates through the lines of a file and calls the appropriate parser method | ||||
|             if (len(self.lines[i])<2): | ||||
|                 endpos=i | ||||
|                 hand=self.lines[startpos:endpos] | ||||
|          | ||||
|                 if (len(hand[0])<2): | ||||
|                     hand=hand[1:] | ||||
|          | ||||
|                 cancelled=False | ||||
|                 damaged=False | ||||
|                 if (site=="ftp"): | ||||
|                     for i in range (len(hand)): | ||||
|                         if (hand[i].endswith(" has been canceled")): #this is their typo. this is a typo, right? | ||||
|                             cancelled=True | ||||
|                          | ||||
|                         seat1=hand[i].find("Seat ") #todo: make this recover by skipping this line | ||||
|                         if (seat1!=-1): | ||||
|                             if (hand[i].find("Seat ", seat1+3)!=-1): | ||||
|                                 damaged=True | ||||
|                  | ||||
|                 if (len(hand)<3): | ||||
|                     pass | ||||
|                     #todo: the above 2 lines are kind of a dirty hack, the mentioned circumstances should be handled elsewhere but that doesnt work with DOS/Win EOL. actually this doesnt work. | ||||
|                 elif (hand[0].endswith(" (partial)")): #partial hand - do nothing | ||||
|                     partial+=1 | ||||
|                 elif (hand[1].find("Seat")==-1 and hand[2].find("Seat")==-1 and hand[3].find("Seat")==-1):#todo: should this be or instead of and? | ||||
|                     partial+=1 | ||||
|                 elif (cancelled or damaged): | ||||
|                     partial+=1 | ||||
|                 else: #normal processing | ||||
|                     isTourney=fpdb_simple.isTourney(hand[0]) | ||||
|                     if not isTourney: | ||||
|                         fpdb_simple.filterAnteBlindFold(site,hand) | ||||
|                     hand=fpdb_simple.filterCrap(site, hand, isTourney) | ||||
|                     self.hand=hand | ||||
|                      | ||||
|                     try: | ||||
|                         handsId=fpdb_parse_logic.mainParser(self.settings['db-backend'], self.db | ||||
|                                                            ,self.cursor, site, category, hand) | ||||
|                         self.db.commit() | ||||
|                          | ||||
|                         stored+=1 | ||||
|                         self.db.commit() | ||||
|                         if self.callHud: | ||||
|                             #print "call to HUD here. handsId:",handsId | ||||
|                             #pipe the Hands.id out to the HUD | ||||
|                             self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) | ||||
|                     except fpdb_simple.DuplicateError: | ||||
|                         duplicates+=1 | ||||
|                     except (ValueError), fe: | ||||
|                         errors+=1 | ||||
|                         self.printEmailErrorMessage(errors, file, hand) | ||||
|                  | ||||
|                         if (self.settings['failOnError']): | ||||
|                             self.db.commit() #dont remove this, in case hand processing was cancelled. | ||||
|                             raise | ||||
|                     except (fpdb_simple.FpdbError), fe: | ||||
|                         errors+=1 | ||||
|                         self.printEmailErrorMessage(errors, file, hand) | ||||
| 
 | ||||
| 						#fe.printStackTrace() #todo: get stacktrace | ||||
| 						self.db.rollback() | ||||
| 						 | ||||
| 						if (self.settings['failOnError']): | ||||
| 							self.db.commit() #dont remove this, in case hand processing was cancelled. | ||||
| 							raise | ||||
| 					if (self.settings['minPrint']!=0): | ||||
| 						if ((stored+duplicates+partial+errors)%self.settings['minPrint']==0): | ||||
| 							print "stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors | ||||
| 			 | ||||
| 					if (self.settings['handCount']!=0): | ||||
| 						if ((stored+duplicates+partial+errors)>=self.settings['handCount']): | ||||
| 							if (not self.settings['quiet']): | ||||
| 								print "quitting due to reaching the amount of hands to be imported" | ||||
| 								print "Total stored:", stored, "duplicates:", duplicates, "partial/damaged:", partial, "errors:", errors, " time:", (time() - starttime) | ||||
| 							sys.exit(0) | ||||
| 				startpos=endpos | ||||
| 		print "Total stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors, " time:", (time() - starttime) | ||||
| 		 | ||||
| 		if stored==0: | ||||
| 			if duplicates>0: | ||||
| 				for line_no in range(len(self.lines)): | ||||
| 					if self.lines[line_no].find("Game #")!=-1: | ||||
| 						final_game_line=self.lines[line_no] | ||||
| 				handsId=fpdb_simple.parseSiteHandNo(final_game_line) | ||||
| 			else: | ||||
| 				print "failed to read a single hand from file:", inputFile | ||||
| 				handsId=0 | ||||
| 			#todo: this will cause return of an unstored hand number if the last hand was error or partial | ||||
| 		self.db.commit() | ||||
| 		self.handsId=handsId | ||||
| 		return handsId | ||||
|                         #fe.printStackTrace() #todo: get stacktrace | ||||
|                         self.db.rollback() | ||||
|                          | ||||
|                         if (self.settings['failOnError']): | ||||
|                             self.db.commit() #dont remove this, in case hand processing was cancelled. | ||||
|                             raise | ||||
|                     if (self.settings['minPrint']!=0): | ||||
|                         if ((stored+duplicates+partial+errors)%self.settings['minPrint']==0): | ||||
|                             print "stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors | ||||
|              | ||||
|                     if (self.settings['handCount']!=0): | ||||
|                         if ((stored+duplicates+partial+errors)>=self.settings['handCount']): | ||||
|                             if (not self.settings['quiet']): | ||||
|                                 print "quitting due to reaching the amount of hands to be imported" | ||||
|                                 print "Total stored:", stored, "duplicates:", duplicates, "partial/damaged:", partial, "errors:", errors, " time:", (time() - starttime) | ||||
|                             sys.exit(0) | ||||
|                 startpos=endpos | ||||
|         print "Total stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors, " time:", (time() - starttime) | ||||
|          | ||||
|         if stored==0: | ||||
|             if duplicates>0: | ||||
|                 for line_no in range(len(self.lines)): | ||||
|                     if self.lines[line_no].find("Game #")!=-1: | ||||
|                         final_game_line=self.lines[line_no] | ||||
|                 handsId=fpdb_simple.parseSiteHandNo(final_game_line) | ||||
|             else: | ||||
|                 print "failed to read a single hand from file:", inputFile | ||||
|                 handsId=0 | ||||
|             #todo: this will cause return of an unstored hand number if the last hand was error or partial | ||||
|         self.db.commit() | ||||
|         self.handsId=handsId | ||||
|         return handsId | ||||
| #end def import_file_dict | ||||
| 
 | ||||
| 	def parseTourneyHistory(self): | ||||
| 		print "Tourney history parser stub" | ||||
| 		#Find tournament boundaries. | ||||
| 		#print self.foabs | ||||
| 		 | ||||
|     def parseTourneyHistory(self): | ||||
|         print "Tourney history parser stub" | ||||
|         #Find tournament boundaries. | ||||
|         #print self.foabs | ||||
|          | ||||
| 
 | ||||
| 	def printEmailErrorMessage(self, errors, filename, line): | ||||
| 		traceback.print_exc(file=sys.stderr) | ||||
| 		print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it." | ||||
| 		print "Filename:", filename | ||||
| 		print "Here is the first line so you can identify it. Please mention that the error was a ValueError:" | ||||
| 		print self.hand[0] | ||||
| 		print "Hand logged to hand-errors.txt" | ||||
| 		logfile = open('hand-errors.txt', 'a') | ||||
| 		for s in self.hand: | ||||
| 			logfile.write(str(s) + "\n") | ||||
| 		logfile.write("\n") | ||||
| 		logfile.close() | ||||
|     def printEmailErrorMessage(self, errors, filename, line): | ||||
|         traceback.print_exc(file=sys.stderr) | ||||
|         print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it." | ||||
|         print "Filename:", filename | ||||
|         print "Here is the first line so you can identify it. Please mention that the error was a ValueError:" | ||||
|         print self.hand[0] | ||||
|         print "Hand logged to hand-errors.txt" | ||||
|         logfile = open('hand-errors.txt', 'a') | ||||
|         for s in self.hand: | ||||
|             logfile.write(str(s) + "\n") | ||||
|         logfile.write("\n") | ||||
|         logfile.close() | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
| 	print "CLI for fpdb_import is now available as CliFpdb.py" | ||||
|     print "CLI for fpdb_import is now available as CliFpdb.py" | ||||
|  |  | |||
|  | @ -21,146 +21,171 @@ import fpdb_simple | |||
| import fpdb_save_to_db | ||||
| 
 | ||||
| #parses a holdem hand | ||||
| def mainParser(db, cursor, site, category, hand): | ||||
| 	if (category=="holdem" or category=="omahahi" or category=="omahahilo"): | ||||
| 		base="hold" | ||||
| 	else: | ||||
| 		base="stud" | ||||
| 	#part 0: create the empty arrays | ||||
| 	lineTypes=[] #char, valid values: header, name, cards, action, win, rake, ignore | ||||
| 	lineStreets=[] #char, valid values: (predeal, preflop, flop, turn, river) | ||||
| def mainParser(backend, db, cursor, site, category, hand): | ||||
|     if (category=="holdem" or category=="omahahi" or category=="omahahilo"): | ||||
|         base="hold" | ||||
|     else: | ||||
|         base="stud" | ||||
|     #part 0: create the empty arrays | ||||
|     lineTypes=[] #char, valid values: header, name, cards, action, win, rake, ignore | ||||
|     lineStreets=[] #char, valid values: (predeal, preflop, flop, turn, river) | ||||
| 
 | ||||
| 	cardValues, cardSuits, boardValues, boardSuits, antes, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo, seatLines, winnings, rakes=[],[],[],[],[],[],[],[],[],[],[],[],[] | ||||
|     cardValues, cardSuits, boardValues, boardSuits, antes, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo, seatLines, winnings, rakes=[],[],[],[],[],[],[],[],[],[],[],[],[] | ||||
| 
 | ||||
| 	#part 1: read hand no and check for duplicate | ||||
| 	siteHandNo=fpdb_simple.parseSiteHandNo(hand[0]) | ||||
| 	handStartTime=fpdb_simple.parseHandStartTime(hand[0], site) | ||||
| 	siteID=fpdb_simple.recogniseSiteID(cursor, site) | ||||
| 	#print "parse logic, siteID:",siteID,"site:",site | ||||
| 	 | ||||
| 	isTourney=fpdb_simple.isTourney(hand[0]) | ||||
| 	smallBlindLine=0 | ||||
| 	for i in range(len(hand)): | ||||
| 		if hand[i].find("posts small blind")!=-1 or hand[i].find("posts the small blind")!=-1: | ||||
| 			if hand[i][-2:] == "$0": | ||||
| 				continue | ||||
| 			smallBlindLine=i | ||||
| 			#print "found small blind line:",smallBlindLine | ||||
| 			break | ||||
| 	#print "small blind line:",smallBlindLine | ||||
| 	gametypeID=fpdb_simple.recogniseGametypeID(cursor, hand[0], hand[smallBlindLine], siteID, category, isTourney) | ||||
| 	if isTourney: | ||||
| 		if site!="ps": | ||||
| 			raise fpdb_simple.FpdbError("tourneys are only supported on PS right now") | ||||
| 		siteTourneyNo=fpdb_simple.parseTourneyNo(hand[0]) | ||||
| 		buyin=fpdb_simple.parseBuyin(hand[0]) | ||||
| 		fee=fpdb_simple.parseFee(hand[0]) | ||||
| 		entries=-1 #todo: parse this | ||||
| 		prizepool=-1 #todo: parse this | ||||
| 		knockout=0 | ||||
| 		tourneyStartTime=handStartTime #todo: read tourney start time | ||||
| 		rebuyOrAddon=fpdb_simple.isRebuyOrAddon(hand[0]) | ||||
|     #part 1: read hand no and check for duplicate | ||||
|     siteHandNo=fpdb_simple.parseSiteHandNo(hand[0]) | ||||
|     handStartTime=fpdb_simple.parseHandStartTime(hand[0], site) | ||||
|     siteID=fpdb_simple.recogniseSiteID(cursor, site) | ||||
|     #print "parse logic, siteID:",siteID,"site:",site | ||||
|      | ||||
|     isTourney=fpdb_simple.isTourney(hand[0]) | ||||
|     smallBlindLine=0 | ||||
|     for i in range(len(hand)): | ||||
|         if hand[i].find("posts small blind")!=-1 or hand[i].find("posts the small blind")!=-1: | ||||
|             if hand[i][-2:] == "$0": | ||||
|                 continue | ||||
|             smallBlindLine=i | ||||
|             #print "found small blind line:",smallBlindLine | ||||
|             break | ||||
|     #print "small blind line:",smallBlindLine | ||||
|     gametypeID=fpdb_simple.recogniseGametypeID(backend, db, cursor, hand[0], hand[smallBlindLine], siteID, category, isTourney) | ||||
|     if isTourney: | ||||
|         if site!="ps": | ||||
|             raise fpdb_simple.FpdbError("tourneys are only supported on PS right now") | ||||
|         siteTourneyNo=fpdb_simple.parseTourneyNo(hand[0]) | ||||
|         buyin=fpdb_simple.parseBuyin(hand[0]) | ||||
|         fee=fpdb_simple.parseFee(hand[0]) | ||||
|         entries=-1 #todo: parse this | ||||
|         prizepool=-1 #todo: parse this | ||||
|         knockout=0 | ||||
|         tourneyStartTime=handStartTime #todo: read tourney start time | ||||
|         rebuyOrAddon=fpdb_simple.isRebuyOrAddon(hand[0]) | ||||
| 
 | ||||
| 		tourneyTypeId=fpdb_simple.recogniseTourneyTypeId(cursor, siteID, buyin, fee, knockout, rebuyOrAddon)		 | ||||
| 	fpdb_simple.isAlreadyInDB(cursor, gametypeID, siteHandNo) | ||||
| 	 | ||||
| 	#part 2: classify lines by type (e.g. cards, action, win, sectionchange) and street | ||||
| 	fpdb_simple.classifyLines(hand, category, lineTypes, lineStreets) | ||||
| 		 | ||||
| 	#part 3: read basic player info	 | ||||
| 	#3a read player names, startcashes | ||||
| 	for i in range (len(hand)): #todo: use maxseats+1 here. | ||||
| 		if (lineTypes[i]=="name"): | ||||
| 			seatLines.append(hand[i]) | ||||
| 	names=fpdb_simple.parseNames(seatLines) | ||||
| 	playerIDs = fpdb_simple.recognisePlayerIDs(cursor, names, siteID) | ||||
| 	tmp=fpdb_simple.parseCashesAndSeatNos(seatLines, site) | ||||
| 	startCashes=tmp['startCashes'] | ||||
| 	seatNos=tmp['seatNos'] | ||||
| 	 | ||||
| 	fpdb_simple.createArrays(category, len(names), cardValues, cardSuits, antes, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo) | ||||
| 	 | ||||
| 	#3b read positions | ||||
| 	if base=="hold": | ||||
| 		positions = fpdb_simple.parsePositions (hand, names) | ||||
| 	 | ||||
| 	#part 4: take appropriate action for each line based on linetype | ||||
| 	for i in range(len(hand)): | ||||
| 		if (lineTypes[i]=="cards"): | ||||
| 			fpdb_simple.parseCardLine (site, category, lineStreets[i], hand[i], names, cardValues, cardSuits, boardValues, boardSuits) | ||||
| 			#if category=="studhilo": | ||||
| 			#	print "hand[i]:", hand[i] | ||||
| 			#	print "cardValues:", cardValues | ||||
| 			#	print "cardSuits:", cardSuits | ||||
| 		elif (lineTypes[i]=="action"): | ||||
| 			fpdb_simple.parseActionLine (site, base, isTourney, hand[i], lineStreets[i], playerIDs, names, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo) | ||||
| 		elif (lineTypes[i]=="win"): | ||||
| 			fpdb_simple.parseWinLine (hand[i], site, names, winnings, isTourney) | ||||
| 		elif (lineTypes[i]=="rake"): | ||||
| 			if isTourney: | ||||
| 				totalRake=0 | ||||
| 			else: | ||||
| 				totalRake=fpdb_simple.parseRake(hand[i]) | ||||
| 			fpdb_simple.splitRake(winnings, rakes, totalRake) | ||||
| 		elif (lineTypes[i]=="header" or lineTypes[i]=="rake" or lineTypes[i]=="name" or lineTypes[i]=="ignore"): | ||||
| 			pass | ||||
| 		elif (lineTypes[i]=="ante"): | ||||
| 			fpdb_simple.parseAnteLine(hand[i], site, isTourney, names, antes) | ||||
| 		elif (lineTypes[i]=="table"): | ||||
| 			tableResult=fpdb_simple.parseTableLine(site, base, hand[i]) | ||||
| 		else: | ||||
| 			raise fpdb_simple.FpdbError("unrecognised lineType:"+lineTypes[i]) | ||||
| 	if site=="ftp": | ||||
| 		tableResult=fpdb_simple.parseTableLine(site, base, hand[0]) | ||||
| 	maxSeats=tableResult['maxSeats'] | ||||
| 	tableName=tableResult['tableName'] | ||||
| 	#print "before part5, antes:", antes | ||||
| 	 | ||||
| 	#part 5: final preparations, then call fpdb_save_to_db.* with | ||||
| 	#		 the arrays as they are - that file will fill them. | ||||
| 	fpdb_simple.convertCardValues(cardValues) | ||||
| 	if base=="hold": | ||||
| 		fpdb_simple.convertCardValuesBoard(boardValues) | ||||
| 		fpdb_simple.convertBlindBet(actionTypes, actionAmounts) | ||||
| 		fpdb_simple.checkPositions(positions) | ||||
| 		 | ||||
| 	cursor.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, )) | ||||
| 	limit_type=cursor.fetchone()[0] | ||||
| 	fpdb_simple.convert3B4B(site, category, limit_type, actionTypes, actionAmounts) | ||||
| 	 | ||||
| 	totalWinnings=0 | ||||
| 	for i in range(len(winnings)): | ||||
| 		totalWinnings+=winnings[i] | ||||
| 	 | ||||
| 	if base=="hold": | ||||
| 		hudImportData=fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes, allIns, actionTypeByNo, winnings, totalWinnings, positions) | ||||
| 	else: | ||||
| 		hudImportData=fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes, allIns, actionTypeByNo, winnings, totalWinnings, None) | ||||
| 	 | ||||
| 	if isTourney: | ||||
| 		ranks=[] | ||||
| 		for i in range (len(names)): | ||||
| 			ranks.append(0) | ||||
| 		payin_amounts=fpdb_simple.calcPayin(len(names), buyin, fee) | ||||
| 		 | ||||
| 		if base=="hold": | ||||
| 			result = fpdb_save_to_db.tourney_holdem_omaha(cursor, base, category, siteTourneyNo, buyin, fee, knockout, entries, prizepool, tourneyStartTime, payin_amounts, ranks, tourneyTypeId, siteID, | ||||
| 					siteHandNo, gametypeID, handStartTime, names, playerIDs, startCashes, positions, cardValues, cardSuits, boardValues, boardSuits, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, hudImportData, maxSeats, tableName, seatNos) | ||||
| 		elif base=="stud": | ||||
| 			result = fpdb_save_to_db.tourney_stud(cursor, base, category, siteTourneyNo, buyin, fee, knockout, entries, prizepool, tourneyStartTime, payin_amounts, ranks, tourneyTypeId, siteID, | ||||
| 					siteHandNo, gametypeID, handStartTime, names, playerIDs, startCashes, antes, cardValues, cardSuits, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, hudImportData, maxSeats, tableName, seatNos) | ||||
| 		else: | ||||
| 			raise fpdb_simple.FpdbError ("unrecognised category") | ||||
| 	else: | ||||
| 		if base=="hold": | ||||
| 			result = fpdb_save_to_db.ring_holdem_omaha(cursor, base, category, siteHandNo, gametypeID, handStartTime, names, playerIDs, startCashes, positions, cardValues, cardSuits, boardValues, boardSuits, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, hudImportData, maxSeats, tableName, seatNos) | ||||
| 		elif base=="stud": | ||||
| 			result = fpdb_save_to_db.ring_stud(cursor, base, category, siteHandNo, gametypeID,  | ||||
| 					handStartTime, names, playerIDs, startCashes, antes, cardValues,  | ||||
| 					cardSuits, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, hudImportData, maxSeats, tableName, seatNos) | ||||
| 		else: | ||||
| 			raise fpdb_simple.FpdbError ("unrecognised category") | ||||
| 		db.commit() | ||||
| 	return result | ||||
|         tourneyTypeId=fpdb_simple.recogniseTourneyTypeId(cursor, siteID, buyin, fee, knockout, rebuyOrAddon)         | ||||
|     fpdb_simple.isAlreadyInDB(cursor, gametypeID, siteHandNo) | ||||
|      | ||||
|     #part 2: classify lines by type (e.g. cards, action, win, sectionchange) and street | ||||
|     fpdb_simple.classifyLines(hand, category, lineTypes, lineStreets) | ||||
|          | ||||
|     #part 3: read basic player info     | ||||
|     #3a read player names, startcashes | ||||
|     for i in range (len(hand)): #todo: use maxseats+1 here. | ||||
|         if (lineTypes[i]=="name"): | ||||
|             seatLines.append(hand[i]) | ||||
|     names=fpdb_simple.parseNames(seatLines) | ||||
|     playerIDs = fpdb_simple.recognisePlayerIDs(cursor, names, siteID) | ||||
|     tmp=fpdb_simple.parseCashesAndSeatNos(seatLines, site) | ||||
|     startCashes=tmp['startCashes'] | ||||
|     seatNos=tmp['seatNos'] | ||||
|      | ||||
|     fpdb_simple.createArrays(category, len(names), cardValues, cardSuits, antes, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo) | ||||
|      | ||||
|     #3b read positions | ||||
|     if base=="hold": | ||||
|         positions = fpdb_simple.parsePositions (hand, names) | ||||
|      | ||||
|     #part 4: take appropriate action for each line based on linetype | ||||
|     for i in range(len(hand)): | ||||
|         if (lineTypes[i]=="cards"): | ||||
|             fpdb_simple.parseCardLine (site, category, lineStreets[i], hand[i], names, cardValues, cardSuits, boardValues, boardSuits) | ||||
|             #if category=="studhilo": | ||||
|             #    print "hand[i]:", hand[i] | ||||
|             #    print "cardValues:", cardValues | ||||
|             #    print "cardSuits:", cardSuits | ||||
|         elif (lineTypes[i]=="action"): | ||||
|             fpdb_simple.parseActionLine (site, base, isTourney, hand[i], lineStreets[i], playerIDs, names, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo) | ||||
|         elif (lineTypes[i]=="win"): | ||||
|             fpdb_simple.parseWinLine (hand[i], site, names, winnings, isTourney) | ||||
|         elif (lineTypes[i]=="rake"): | ||||
|             if isTourney: | ||||
|                 totalRake=0 | ||||
|             else: | ||||
|                 totalRake=fpdb_simple.parseRake(hand[i]) | ||||
|             fpdb_simple.splitRake(winnings, rakes, totalRake) | ||||
|         elif (lineTypes[i]=="header" or lineTypes[i]=="rake" or lineTypes[i]=="name" or lineTypes[i]=="ignore"): | ||||
|             pass | ||||
|         elif (lineTypes[i]=="ante"): | ||||
|             fpdb_simple.parseAnteLine(hand[i], site, isTourney, names, antes) | ||||
|         elif (lineTypes[i]=="table"): | ||||
|             tableResult=fpdb_simple.parseTableLine(site, base, hand[i]) | ||||
|         else: | ||||
|             raise fpdb_simple.FpdbError("unrecognised lineType:"+lineTypes[i]) | ||||
|     if site=="ftp": | ||||
|         tableResult=fpdb_simple.parseTableLine(site, base, hand[0]) | ||||
|     maxSeats=tableResult['maxSeats'] | ||||
|     tableName=tableResult['tableName'] | ||||
|     #print "before part5, antes:", antes | ||||
|      | ||||
|     #part 5: final preparations, then call fpdb_save_to_db.* with | ||||
|     #         the arrays as they are - that file will fill them. | ||||
|     fpdb_simple.convertCardValues(cardValues) | ||||
|     if base=="hold": | ||||
|         fpdb_simple.convertCardValuesBoard(boardValues) | ||||
|         fpdb_simple.convertBlindBet(actionTypes, actionAmounts) | ||||
|         fpdb_simple.checkPositions(positions) | ||||
|          | ||||
|     cursor.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, )) | ||||
|     limit_type=cursor.fetchone()[0] | ||||
|     fpdb_simple.convert3B4B(site, category, limit_type, actionTypes, actionAmounts) | ||||
|      | ||||
|     totalWinnings=0 | ||||
|     for i in range(len(winnings)): | ||||
|         totalWinnings+=winnings[i] | ||||
|      | ||||
|     if base=="hold": | ||||
|         hudImportData=fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes | ||||
|                                      , allIns, actionTypeByNo, winnings, totalWinnings, positions | ||||
|                                      , actionTypes, actionAmounts) | ||||
|     else: | ||||
|         hudImportData=fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes | ||||
|                                      , allIns, actionTypeByNo, winnings, totalWinnings, None | ||||
|                                      , actionTypes, actionAmounts) | ||||
|      | ||||
|     if isTourney: | ||||
|         ranks=[] | ||||
|         for i in range (len(names)): | ||||
|             ranks.append(0) | ||||
|         payin_amounts=fpdb_simple.calcPayin(len(names), buyin, fee) | ||||
|          | ||||
|         if base=="hold": | ||||
|             result = fpdb_save_to_db.tourney_holdem_omaha( | ||||
|                                        backend, db, cursor, base, category, siteTourneyNo, buyin | ||||
|                                      , fee, knockout, entries, prizepool, tourneyStartTime | ||||
|                                      , payin_amounts, ranks, tourneyTypeId, siteID, siteHandNo | ||||
|                                      , gametypeID, handStartTime, names, playerIDs, startCashes | ||||
|                                      , positions, cardValues, cardSuits, boardValues, boardSuits | ||||
|                                      , winnings, rakes, actionTypes, allIns, actionAmounts | ||||
|                                      , actionNos, hudImportData, maxSeats, tableName, seatNos) | ||||
|         elif base=="stud": | ||||
|             result = fpdb_save_to_db.tourney_stud( | ||||
|                                        backend, db, cursor, base, category, siteTourneyNo | ||||
|                                      , buyin, fee, knockout, entries, prizepool, tourneyStartTime | ||||
|                                      , payin_amounts, ranks, tourneyTypeId, siteID, siteHandNo | ||||
|                                      , gametypeID, handStartTime, names, playerIDs, startCashes | ||||
|                                      , antes, cardValues, cardSuits, winnings, rakes, actionTypes | ||||
|                                      , allIns, actionAmounts, actionNos, hudImportData, maxSeats | ||||
|                                      , tableName, seatNos) | ||||
|         else: | ||||
|             raise fpdb_simple.FpdbError ("unrecognised category") | ||||
|     else: | ||||
|         if base=="hold": | ||||
|             result = fpdb_save_to_db.ring_holdem_omaha( | ||||
|                                        backend, db, cursor, base, category, siteHandNo | ||||
|                                      , gametypeID, handStartTime, names, playerIDs | ||||
|                                      , startCashes, positions, cardValues, cardSuits | ||||
|                                      , boardValues, boardSuits, winnings, rakes | ||||
|                                      , actionTypes, allIns, actionAmounts, actionNos | ||||
|                                      , hudImportData, maxSeats, tableName, seatNos) | ||||
|         elif base=="stud": | ||||
|             result = fpdb_save_to_db.ring_stud( | ||||
|                                        backend, db, cursor, base, category, siteHandNo, gametypeID | ||||
|                                      , handStartTime, names, playerIDs, startCashes, antes | ||||
|                                      , cardValues, cardSuits, winnings, rakes, actionTypes, allIns | ||||
|                                      , actionAmounts, actionNos, hudImportData, maxSeats, tableName | ||||
|                                      , seatNos) | ||||
|         else: | ||||
|             raise fpdb_simple.FpdbError ("unrecognised category") | ||||
|         db.commit() | ||||
|     return result | ||||
| #end def mainParser | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,77 +18,110 @@ | |||
| #This file contains methods to store hands into the db. decides to move this | ||||
| #into a seperate file since its ugly, fairly long and just generally in the way. | ||||
| 
 | ||||
| from time import time | ||||
| 
 | ||||
| import fpdb_simple | ||||
| 
 | ||||
| #stores a stud/razz hand into the database | ||||
| def ring_stud(cursor, base, category, site_hand_no, gametype_id, hand_start_time, names, player_ids, start_cashes, antes, card_values, card_suits, winnings, rakes, action_types, allIns, action_amounts, actionNos, hudImportData, maxSeats, tableName, seatNos): | ||||
| 	fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) | ||||
| 	 | ||||
| 	hands_id=fpdb_simple.storeHands(cursor, site_hand_no, gametype_id, hand_start_time, names, tableName, maxSeats) | ||||
| 	 | ||||
| 	#print "before calling store_hands_players_stud, antes:", antes | ||||
| 	hands_players_ids=fpdb_simple.store_hands_players_stud(cursor, hands_id, player_ids,  | ||||
| 				start_cashes, antes, card_values, card_suits, winnings, rakes, seatNos) | ||||
| 	 | ||||
| 	fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData) | ||||
| 	 | ||||
| 	fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) | ||||
| 	return hands_id | ||||
| def ring_stud(backend, db, cursor, base, category, site_hand_no, gametype_id, hand_start_time | ||||
|              ,names, player_ids, start_cashes, antes, card_values, card_suits, winnings, rakes | ||||
|              ,action_types, allIns, action_amounts, actionNos, hudImportData, maxSeats, tableName | ||||
|              ,seatNos): | ||||
|     fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) | ||||
|      | ||||
|     hands_id=fpdb_simple.storeHands(backend, db, cursor, site_hand_no, gametype_id | ||||
|                                    ,hand_start_time, names, tableName, maxSeats) | ||||
|      | ||||
|     #print "before calling store_hands_players_stud, antes:", antes | ||||
|     hands_players_ids=fpdb_simple.store_hands_players_stud(backend, db, cursor, hands_id, player_ids | ||||
|                                                           ,start_cashes, antes, card_values | ||||
|                                                           ,card_suits, winnings, rakes, seatNos) | ||||
|      | ||||
|     fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData) | ||||
|      | ||||
|     fpdb_simple.storeActions(cursor, hands_players_ids, action_types | ||||
|                             ,allIns, action_amounts, actionNos) | ||||
|     return hands_id | ||||
| #end def ring_stud | ||||
| 
 | ||||
| def ring_holdem_omaha(cursor, base, category, site_hand_no, gametype_id, hand_start_time, names, player_ids, start_cashes, positions, card_values, card_suits, board_values, board_suits, winnings, rakes, action_types, allIns, action_amounts, actionNos, hudImportData, maxSeats, tableName, seatNos): | ||||
| 	"""stores a holdem/omaha hand into the database""" | ||||
| 	fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) | ||||
| 	fpdb_simple.fill_board_cards(board_values, board_suits) | ||||
| def ring_holdem_omaha(backend, db, cursor, base, category, site_hand_no, gametype_id | ||||
|                      ,hand_start_time, names, player_ids, start_cashes, positions, card_values | ||||
|                      ,card_suits, board_values, board_suits, winnings, rakes, action_types, allIns | ||||
|                      ,action_amounts, actionNos, hudImportData, maxSeats, tableName, seatNos): | ||||
|     """stores a holdem/omaha hand into the database""" | ||||
|     t0 = time() | ||||
|     fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) | ||||
|     t1 = time() | ||||
|     fpdb_simple.fill_board_cards(board_values, board_suits) | ||||
|     t2 = time() | ||||
| 
 | ||||
| 	hands_id=fpdb_simple.storeHands(cursor, site_hand_no, gametype_id, hand_start_time, names, tableName, maxSeats) | ||||
| 	 | ||||
| 	hands_players_ids=fpdb_simple.store_hands_players_holdem_omaha(cursor, category, hands_id, player_ids, start_cashes, positions, card_values, card_suits, winnings, rakes, seatNos) | ||||
| 				 | ||||
| 	fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData) | ||||
| 	 | ||||
| 	fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits) | ||||
| 	 | ||||
| 	fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) | ||||
| 	return hands_id | ||||
|     hands_id=fpdb_simple.storeHands(backend, db, cursor, site_hand_no, gametype_id | ||||
|                                    ,hand_start_time, names, tableName, maxSeats) | ||||
|     t3 = time() | ||||
|     hands_players_ids=fpdb_simple.store_hands_players_holdem_omaha( | ||||
|                                backend, db, cursor, category, hands_id, player_ids, start_cashes | ||||
|                              , positions, card_values, card_suits, winnings, rakes, seatNos) | ||||
|     t4 = time()             | ||||
|     fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData) | ||||
|     t5 = time() | ||||
|     fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits) | ||||
|     t6 = time() | ||||
|     fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) | ||||
|     t7 = time() | ||||
|     print "cards=%4.3f board=%4.3f hands=%4.3f plyrs=%4.3f hudcache=%4.3f board=%4.3f actions=%4.3f" \ | ||||
|     % (t1-t0, t2-t1, t3-t2, t4-t3, t5-t4, t6-t5, t7-t6) | ||||
|     return hands_id | ||||
| #end def ring_holdem_omaha | ||||
| 
 | ||||
| def tourney_holdem_omaha(cursor, base, category, siteTourneyNo, buyin, fee, knockout, entries, prizepool, tourney_start, payin_amounts, ranks, tourneyTypeId, siteId, #end of tourney specific params | ||||
| 			site_hand_no, gametype_id, hand_start_time, names, player_ids, start_cashes, positions, card_values, card_suits, board_values, board_suits, winnings, rakes, action_types, allIns, action_amounts, actionNos, hudImportData, maxSeats, tableName, seatNos): | ||||
| 	"""stores a tourney holdem/omaha hand into the database""" | ||||
| 	fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) | ||||
| 	fpdb_simple.fill_board_cards(board_values, board_suits) | ||||
| 	 | ||||
| 	tourney_id=fpdb_simple.store_tourneys(cursor, tourneyTypeId, siteTourneyNo, entries, prizepool, tourney_start) | ||||
| 	tourneys_players_ids=fpdb_simple.store_tourneys_players(cursor, tourney_id, player_ids, payin_amounts, ranks, winnings) | ||||
| 	 | ||||
| 	hands_id=fpdb_simple.storeHands(cursor, site_hand_no, gametype_id, hand_start_time, names, tableName, maxSeats) | ||||
| 	 | ||||
| 	hands_players_ids=fpdb_simple.store_hands_players_holdem_omaha_tourney(cursor, category, hands_id, player_ids, start_cashes, positions, card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids) | ||||
| 	 | ||||
| 	fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData) | ||||
| 	 | ||||
| 	fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits) | ||||
| 	 | ||||
| 	fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) | ||||
| 	return hands_id | ||||
| def tourney_holdem_omaha(backend, db, cursor, base, category, siteTourneyNo, buyin, fee, knockout | ||||
|                         ,entries, prizepool, tourney_start, payin_amounts, ranks, tourneyTypeId | ||||
|                         ,siteId #end of tourney specific params | ||||
|                         ,site_hand_no, gametype_id, hand_start_time, names, player_ids | ||||
|                         ,start_cashes, positions, card_values, card_suits, board_values | ||||
|                         ,board_suits, winnings, rakes, action_types, allIns, action_amounts | ||||
|                         ,actionNos, hudImportData, maxSeats, tableName, seatNos): | ||||
|     """stores a tourney holdem/omaha hand into the database""" | ||||
|     fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) | ||||
|     fpdb_simple.fill_board_cards(board_values, board_suits) | ||||
|      | ||||
|     tourney_id=fpdb_simple.store_tourneys(cursor, tourneyTypeId, siteTourneyNo, entries, prizepool, tourney_start) | ||||
|     tourneys_players_ids=fpdb_simple.store_tourneys_players(cursor, tourney_id, player_ids, payin_amounts, ranks, winnings) | ||||
|      | ||||
|     hands_id=fpdb_simple.storeHands(backend, db, cursor, site_hand_no, gametype_id | ||||
|                                    ,hand_start_time, names, tableName, maxSeats) | ||||
|      | ||||
|     hands_players_ids=fpdb_simple.store_hands_players_holdem_omaha_tourney( | ||||
|                       backend, db, cursor, category, hands_id, player_ids, start_cashes, positions | ||||
|                     , card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids) | ||||
|      | ||||
|     fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData) | ||||
|      | ||||
|     fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits) | ||||
|      | ||||
|     fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) | ||||
|     return hands_id | ||||
| #end def tourney_holdem_omaha | ||||
| 
 | ||||
| def tourney_stud(cursor, base, category, siteTourneyNo, buyin, fee, knockout, entries, prizepool, tourneyStartTime, payin_amounts, ranks, tourneyTypeId, siteId, | ||||
| 					siteHandNo, gametypeId, handStartTime, names, playerIds, startCashes, antes, cardValues, cardSuits, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, hudImportData, maxSeats, tableName, seatNos): | ||||
| def tourney_stud(backend, db, cursor, base, category, siteTourneyNo, buyin, fee, knockout, entries | ||||
|                 ,prizepool, tourneyStartTime, payin_amounts, ranks, tourneyTypeId, siteId | ||||
|                 ,siteHandNo, gametypeId, handStartTime, names, playerIds, startCashes, antes | ||||
|                 ,cardValues, cardSuits, winnings, rakes, actionTypes, allIns, actionAmounts | ||||
|                 ,actionNos, hudImportData, maxSeats, tableName, seatNos): | ||||
| #stores a tourney stud/razz hand into the database | ||||
| 	fpdb_simple.fillCardArrays(len(names), base, category, cardValues, cardSuits) | ||||
| 	 | ||||
| 	tourney_id=fpdb_simple.store_tourneys(cursor, tourneyTypeId, siteTourneyNo, entries, prizepool, tourneyStartTime) | ||||
| 	 | ||||
| 	tourneys_players_ids=fpdb_simple.store_tourneys_players(cursor, tourney_id, playerIds, payin_amounts, ranks, winnings) | ||||
| 	 | ||||
| 	hands_id=fpdb_simple.storeHands(cursor, siteHandNo, gametypeId, handStartTime, names, tableName, maxSeats) | ||||
| 	 | ||||
| 	hands_players_ids=fpdb_simple.store_hands_players_stud_tourney(cursor, hands_id, playerIds, startCashes, antes, cardValues, cardSuits, winnings, rakes, seatNos, tourneys_players_ids) | ||||
| 	 | ||||
| 	fpdb_simple.storeHudCache(cursor, base, category, gametypeId, playerIds, hudImportData) | ||||
| 	 | ||||
| 	fpdb_simple.storeActions(cursor, hands_players_ids, actionTypes, allIns, actionAmounts, actionNos) | ||||
| 	return hands_id | ||||
|     fpdb_simple.fillCardArrays(len(names), base, category, cardValues, cardSuits) | ||||
|      | ||||
|     tourney_id=fpdb_simple.store_tourneys(cursor, tourneyTypeId, siteTourneyNo, entries, prizepool, tourneyStartTime) | ||||
|      | ||||
|     tourneys_players_ids=fpdb_simple.store_tourneys_players(cursor, tourney_id, playerIds, payin_amounts, ranks, winnings) | ||||
|      | ||||
|     hands_id=fpdb_simple.storeHands(backend, db, cursor, siteHandNo, gametypeId, handStartTime, names, tableName, maxSeats) | ||||
|      | ||||
|     hands_players_ids=fpdb_simple.store_hands_players_stud_tourney(backend, db, cursor, hands_id | ||||
|                                              , playerIds, startCashes, antes, cardValues, cardSuits | ||||
|                                              , winnings, rakes, seatNos, tourneys_players_ids) | ||||
|      | ||||
|     fpdb_simple.storeHudCache(cursor, base, category, gametypeId, playerIds, hudImportData) | ||||
|      | ||||
|     fpdb_simple.storeActions(cursor, hands_players_ids, actionTypes, allIns, actionAmounts, actionNos) | ||||
|     return hands_id | ||||
| #end def tourney_stud | ||||
|  |  | |||
							
								
								
									
										4377
									
								
								pyfpdb/fpdb_simple.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										4377
									
								
								pyfpdb/fpdb_simple.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										27
									
								
								pyfpdb/upd_indexes.sql
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										27
									
								
								pyfpdb/upd_indexes.sql
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,27 @@ | |||
| 
 | ||||
| # script to update indexes on mysql (+other?) database | ||||
| 
 | ||||
| select '1. Dropping indexes' as ' '; | ||||
| select 'Can''t drop messages indicate index already gone' as ' '; | ||||
| 
 | ||||
| ALTER TABLE `fpdb`.`Settings` DROP INDEX `id`; | ||||
| ALTER TABLE `fpdb`.`Sites` DROP INDEX `id`; | ||||
| ALTER TABLE `fpdb`.`Gametypes` DROP INDEX `id`; | ||||
| ALTER TABLE `fpdb`.`Players` DROP INDEX `id`; | ||||
| ALTER TABLE `fpdb`.`Autorates` DROP INDEX `id`; | ||||
| ALTER TABLE `fpdb`.`Hands` DROP INDEX `id`; | ||||
| ALTER TABLE `fpdb`.`BoardCards` DROP INDEX `id`; | ||||
| ALTER TABLE `fpdb`.`TourneyTypes` DROP INDEX `id`; | ||||
| ALTER TABLE `fpdb`.`Tourneys` DROP INDEX `id`; | ||||
| ALTER TABLE `fpdb`.`TourneysPlayers` DROP INDEX `id`; | ||||
| ALTER TABLE `fpdb`.`HandsPlayers` DROP INDEX `id`; | ||||
| ALTER TABLE `fpdb`.`HandsActions` DROP INDEX `id`; | ||||
| ALTER TABLE `fpdb`.`HudCache` DROP INDEX `id`; | ||||
| 
 | ||||
| select '2. Adding extra indexes on useful fields' as ' '; | ||||
| select 'Duplicate key name messages indicate new indexes already there' as ' ';  | ||||
| 
 | ||||
| ALTER TABLE `fpdb`.`tourneys` ADD INDEX `siteTourneyNo`(`siteTourneyNo`); | ||||
| ALTER TABLE `fpdb`.`hands` ADD INDEX `siteHandNo`(`siteHandNo`); | ||||
| ALTER TABLE `fpdb`.`players` ADD INDEX `name`(`name`); | ||||
| 
 | ||||
							
								
								
									
										0
									
								
								readme.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								readme.txt
									
									
									
									
									
										Normal file
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user