Merge branch 'master' into monkeyfutz

Everleaf converts hands
Moved process hand logic into the hand subclass that knows what it
wants, it calls back to the hhc (which knows about the format) to populate itself

Conflicts:

	pyfpdb/EverleafToFpdb.py
	pyfpdb/Hand.py
	pyfpdb/HandHistoryConverter.py
This commit is contained in:
Matt Turnbull 2009-03-01 23:22:47 +00:00
commit 5c26bb028d
13 changed files with 396 additions and 374 deletions

View File

@ -62,6 +62,7 @@ class Site:
self.aux_window = node.getAttribute("aux_window")
self.font = node.getAttribute("font")
self.font_size = node.getAttribute("font_size")
self.use_frames = node.getAttribute("use_frames")
self.layout = {}
for layout_node in node.getElementsByTagName('layout'):
@ -465,6 +466,9 @@ class Config:
paths['hud-defaultPath'] = "default"
paths['bulkImport-defaultPath'] = "default"
return paths
def get_frames(self, site = "PokerStars"):
return self.supported_sites[site].use_frames == "True"
def get_default_colors(self, site = "PokerStars"):
colors = {}

View File

@ -116,31 +116,30 @@ class Database:
row = c.fetchone()
return row[0]
# def get_cards(self, hand):
# this version is for the PTrackSv2 db
# c = self.connection.cursor()
# c.execute(self.sql.query['get_cards'], hand)
# colnames = [desc[0] for desc in c.description]
# cards = {}
# for row in c.fetchall():
# s_dict = {}
# for name, val in zip(colnames, row):
# s_dict[name] = val
# cards[s_dict['seat_number']] = s_dict
# return (cards)
def get_cards(self, hand):
# this version is for the fpdb db
"""Get and return the cards for each player in the hand."""
cards = {} # dict of cards, the key is the seat number example: {1: 'AcQd9hTs5d'}
c = self.connection.cursor()
c.execute(self.sql.query['get_cards'], hand)
colnames = [desc[0] for desc in c.description]
cards = {}
for row in c.fetchall():
s_dict = {}
for name, val in zip(colnames, row):
s_dict[name] = val
cards[s_dict['seat_number']] = s_dict
return (cards)
cards[s_dict['seat_number']] = (self.convert_cards(s_dict))
return cards
def convert_cards(self, d):
ranks = ('', '', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
cards = ""
for i in range(1, 8):
if d['card' + str(i) + 'Value'] == None:
break
elif d['card' + str(i) + 'Value'] == 0:
cards += "xx"
else:
cards += ranks[d['card' + str(i) + 'Value']] + d['card' +str(i) + 'Suit']
return cards
def get_action_from_hand(self, hand_no):
action = [ [], [], [], [], [] ]
@ -214,6 +213,7 @@ if __name__=="__main__":
for p in stat_dict.keys():
print p, " ", stat_dict[p]
print "cards =", db_connection.get_cards(73525)
db_connection.close_connection
print "press enter to continue"

View File

@ -40,23 +40,26 @@ class Everleaf(HandHistoryConverter):
in_path (default '-' = sys.stdin)
out_path (default '-' = sys.stdout)
follow : whether to tail -f the input"""
super(Everleaf, self).__init__(in_path, out_path, sitename="Everleaf", follow=follow) # Call super class init.
HandHistoryConverter.__init__(self, in_path, out_path, sitename="Everleaf", follow=follow)
logging.info("Initialising Everleaf converter class")
self.filetype = "text"
self.codepage = "cp1252"
self.start()
def compilePlayerRegexs(self):
player_re = "(?P<PNAME>" + "|".join(map(re.escape, self.players)) + ")"
logging.debug("player_re: "+ player_re)
self.re_PostSB = re.compile(r"^%s: posts small blind \[\$? (?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBB = re.compile(r"^%s: posts big blind \[\$? (?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBoth = re.compile(r"^%s: posts both blinds \[\$? (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_HeroCards = re.compile(r"^Dealt to %s \[ (?P<CARDS>.*) \]" % player_re, re.MULTILINE)
self.re_Action = re.compile(r"^%s(?P<ATYPE>: bets| checks| raises| calls| folds)(\s\[\$ (?P<BET>[.\d]+) (USD|EUR)\])?" % player_re, re.MULTILINE)
self.re_ShowdownAction = re.compile(r"^%s shows \[ (?P<CARDS>.*) \]" % player_re, re.MULTILINE)
self.re_CollectPot = re.compile(r"^%s wins \$ (?P<POT>[.\d]+) (USD|EUR)(.*?\[ (?P<CARDS>.*?) \])?" % player_re, re.MULTILINE)
self.re_SitsOut = re.compile(r"^%s sits out" % player_re, re.MULTILINE)
def compilePlayerRegexs(self, players):
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
# we need to recompile the player regexs.
self.compiledPlayers = players
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
logging.debug("player_re: "+ player_re)
self.re_PostSB = re.compile(r"^%s: posts small blind \[\$? (?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBB = re.compile(r"^%s: posts big blind \[\$? (?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBoth = re.compile(r"^%s: posts both blinds \[\$? (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_HeroCards = re.compile(r"^Dealt to %s \[ (?P<CARDS>.*) \]" % player_re, re.MULTILINE)
self.re_Action = re.compile(r"^%s(?P<ATYPE>: bets| checks| raises| calls| folds)(\s\[\$ (?P<BET>[.\d]+) (USD|EUR)\])?" % player_re, re.MULTILINE)
self.re_ShowdownAction = re.compile(r"^%s shows \[ (?P<CARDS>.*) \]" % player_re, re.MULTILINE)
self.re_CollectPot = re.compile(r"^%s wins \$ (?P<POT>[.\d]+) (USD|EUR)(.*?\[ (?P<CARDS>.*?) \])?" % player_re, re.MULTILINE)
self.re_SitsOut = re.compile(r"^%s sits out" % player_re, re.MULTILINE)
def readSupportedGames(self):
return [["ring", "hold", "nl"],
@ -69,6 +72,13 @@ follow : whether to tail -f the input"""
# Blinds $0.50/$1 PL Omaha - 2008/12/07 - 21:59:48
# Blinds $0.05/$0.10 NL Hold'em - 2009/02/21 - 11:21:57
# $0.25/$0.50 7 Card Stud - 2008/12/05 - 21:43:59
# Tourney:
# Everleaf Gaming Game #75065769
# ***** Hand history for game #75065769 *****
# Blinds 10/20 NL Hold'em - 2009/02/25 - 17:30:32
# Table 2
structure = "" # nl, pl, cn, cp, fl
game = ""
@ -95,84 +105,89 @@ follow : whether to tail -f the input"""
return gametype
def readHandInfo(self, hand):
m = self.re_HandInfo.search(hand.string)
m = self.re_HandInfo.search(hand.handText)
if(m == None):
logging.info("Didn't match re_HandInfo")
logging.info(hand.handtext)
return None
logging.debug("HID %s" % m.group('HID'))
logging.debug("HID %s, Table %s" % (m.group('HID'), m.group('TABLE')))
hand.handid = m.group('HID')
hand.tablename = m.group('TABLE')
hand.maxseats = 6 # assume 6-max unless we have proof it's a larger/smaller game, since everleaf doesn't give seat max info
# Believe Everleaf time is GMT/UTC, no transation necessary
# Stars format (Nov 10 2008): 2008/11/07 12:38:49 CET [2008/11/07 7:38:49 ET]
# or : 2008/11/07 12:38:49 ET
# Not getting it in my HH files yet, so using
# 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)
# Believe Everleaf time is GMT/UTC, no transation necessary
# Stars format (Nov 10 2008): 2008/11/07 12:38:49 CET [2008/11/07 7:38:49 ET]
# or : 2008/11/07 12:38:49 ET
# Not getting it in my HH files yet, so using
# 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 = time.strptime(m.group('DATETIME'), "%Y/%m/%d - %H:%M:%S")
return
#return({'HID': m.group('HID'), 'table':m.group('TABLE'), 'max_seats':6})
def readPlayerStacks(self, hand):
m = self.re_PlayerInfo.finditer(hand.string)
m = self.re_PlayerInfo.finditer(hand.handText)
for a in m:
seatnum = int(a.group('SEAT'))
hand.addPlayer(seatnum, a.group('PNAME'), a.group('CASH'))
if seatnum > 6:
hand.max_seats = 10 # everleaf currently does 2/6/10 games, so if seats > 6 are in use, it must be 10-max.
hand.maxseats = 10 # everleaf currently does 2/6/10 games, so if seats > 6 are in use, it must be 10-max.
# TODO: implement lookup list by table-name to determine maxes, then fall back to 6 default/10 here, if there's no entry in the list?
def markStreets(self, hand):
# PREFLOP = ** Dealing down cards **
# This re fails if, say, river is missing; then we don't get the ** that starts the river.
#m = re.search('(\*\* Dealing down cards \*\*\n)(?P<PREFLOP>.*?\n\*\*)?( Dealing Flop \*\* \[ (?P<FLOP1>\S\S), (?P<FLOP2>\S\S), (?P<FLOP3>\S\S) \])?(?P<FLOP>.*?\*\*)?( Dealing Turn \*\* \[ (?P<TURN1>\S\S) \])?(?P<TURN>.*?\*\*)?( Dealing River \*\* \[ (?P<RIVER1>\S\S) \])?(?P<RIVER>.*)', hand.string,re.DOTALL)
#m = re.search('(\*\* Dealing down cards \*\*\n)(?P<PREFLOP>.*?\n\*\*)?( Dealing Flop \*\* \[ (?P<FLOP1>\S\S), (?P<FLOP2>\S\S), (?P<FLOP3>\S\S) \])?(?P<FLOP>.*?\*\*)?( Dealing Turn \*\* \[ (?P<TURN1>\S\S) \])?(?P<TURN>.*?\*\*)?( Dealing River \*\* \[ (?P<RIVER1>\S\S) \])?(?P<RIVER>.*)', hand.handText,re.DOTALL)
m = re.search(r"\*\* Dealing down cards \*\*(?P<PREFLOP>.+(?=\*\* Dealing Flop \*\*)|.+)"
r"(\*\* Dealing Flop \*\*(?P<FLOP> \[ \S\S, \S\S, \S\S \].+(?=\*\* Dealing Turn \*\*)|.+))?"
r"(\*\* Dealing Turn \*\*(?P<TURN> \[ \S\S \].+(?=\*\* Dealing River \*\*)|.+))?"
r"(\*\* Dealing River \*\*(?P<RIVER> \[ \S\S \].+))?", hand.string,re.DOTALL)
r"(\*\* Dealing River \*\*(?P<RIVER> \[ \S\S \].+))?", hand.handText,re.DOTALL)
hand.addStreets(m)
def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand
if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
m = self.re_Board.search(hand.streets.group(street))
hand.setCommunityCards(street, m.group('CARDS').split(', '))
# If this has been called, street is a street which gets dealt community cards by type hand
# but it might be worth checking somehow.
# if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
m = self.re_Board.search(hand.streets[street])
cards = m.group('CARDS')
cards = [card.strip() for card in cards.split(',')]
hand.setCommunityCards(street, cards)
def readBlinds(self, hand):
m = self.re_PostSB.search(hand.string)
m = self.re_PostSB.search(hand.handText)
if m is not None:
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
else:
logging.debug("No small blind")
hand.addBlind(None, None, None)
for a in self.re_PostBB.finditer(hand.string):
for a in self.re_PostBB.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
for a in self.re_PostBoth.finditer(hand.string):
for a in self.re_PostBoth.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'both', a.group('SBBB'))
def readButton(self, hand):
hand.buttonpos = int(self.re_Button.search(hand.string).group('BUTTON'))
hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON'))
def readHeroCards(self, hand):
m = self.re_HeroCards.search(hand.string)
if(m == None):
#Not involved in hand
hand.involved = False
else:
m = self.re_HeroCards.search(hand.handText)
if m:
hand.hero = m.group('PNAME')
# "2c, qh" -> set(["2c","qc"])
# "2c, qh" -> ["2c","qc"]
# Also works with Omaha hands.
cards = m.group('CARDS')
cards = set(cards.split(', '))
cards = [card.strip() for card in cards.split(',')]
hand.addHoleCards(cards, m.group('PNAME'))
else:
#Not involved in hand
hand.involved = False
def readAction(self, hand, street):
m = self.re_Action.finditer(hand.streets.group(street))
m = self.re_Action.finditer(hand.streets[street])
for action in m:
if action.group('ATYPE') == ' raises':
hand.addCallandRaise( street, action.group('PNAME'), action.group('BET') )
@ -189,20 +204,22 @@ follow : whether to tail -f the input"""
def readShowdownActions(self, hand):
for shows in self.re_ShowdownAction.finditer(hand.string):
"""Reads lines where holecards are reported in a showdown"""
for shows in self.re_ShowdownAction.finditer(hand.handText):
cards = shows.group('CARDS')
cards = set(cards.split(', '))
cards = cards.split(', ')
hand.addShownCards(cards, shows.group('PNAME'))
def readCollectPot(self,hand):
for m in self.re_CollectPot.finditer(hand.string):
for m in self.re_CollectPot.finditer(hand.handText):
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
def readShownCards(self,hand):
for m in self.re_CollectPot.finditer(hand.string):
"""Reads lines where hole & board cards are mixed to form a hand (summary lines)"""
for m in self.re_CollectPot.finditer(hand.handText):
if m.group('CARDS') is not None:
cards = m.group('CARDS')
cards = set(cards.split(', '))
cards = cards.split(', ')
hand.addShownCards(cards=None, player=m.group('PNAME'), holeandboard=cards)

View File

@ -28,7 +28,7 @@ class FullTilt(HandHistoryConverter):
re_GameInfo = re.compile('- \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (Ante \$(?P<ANTE>[.0-9]+) )?- (?P<LTYPE>(No|Pot)? )?Limit (?P<GAME>(Hold\'em|Omaha|Razz))')
re_SplitHands = re.compile(r"\n\n+")
re_HandInfo = re.compile('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[- a-zA-Z]+) (\((?P<TABLEATTRIBUTES>.+)\) )?- \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (Ante \$(?P<ANTE>[.0-9]+) )?- (?P<GAMETYPE>[a-zA-Z\' ]+) - (?P<DATETIME>.*)')
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)')
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$(?P<CASH>[.0-9]+)\)\n')
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
@ -43,9 +43,10 @@ class FullTilt(HandHistoryConverter):
print "DEBUG player_re: " + player_re
self.re_PostSB = re.compile(r"^%s posts the small blind of \$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBB = re.compile(r"^%s posts (the big blind of )?\$?(?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_Antes = re.compile(r"^%s antes \$?(?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE)
self.re_BringIn = re.compile(r"^%s brings in for \$?(?P<BRINGIN>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBoth = re.compile(r"^%s posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_HeroCards = re.compile(r"^Dealt to %s \[(?P<CARDS>.*)\]( \[(?P<NEWCARD>.*)\])?" % player_re, re.MULTILINE)
self.re_HeroCards = re.compile(r"^Dealt to %s \[(?P<CARDS>[AKQJT0-9hcsd ]+)\]( \[(?P<NEWCARD>[AKQJT0-9hcsd ]+)\])?" % player_re, re.MULTILINE)
self.re_Action = re.compile(r"^%s(?P<ATYPE> bets| checks| raises to| calls| folds)(\s\$(?P<BET>[.\d]+))?" % player_re, re.MULTILINE)
self.re_ShowdownAction = re.compile(r"^%s shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
self.re_CollectPot = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$(?P<POT>[.\d]+)\)(, mucked| with.*)" % player_re, re.MULTILINE)
@ -155,13 +156,17 @@ class FullTilt(HandHistoryConverter):
def readAntes(self, hand):
print "DEBUG: reading antes"
print "DEBUG: FIXME reading antes"
m = self.re_Antes.finditer(hand.string)
for player in m:
print "DEBUG: hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE'))
hand.addAnte(player.group('PNAME'), player.group('ANTE'))
def readBringIn(self, hand):
print "DEBUG: reading bring in"
# print hand.string
m = self.re_BringIn.search(hand.string,re.DOTALL)
print "DEBUG: Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN'))
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
def readButton(self, hand):
hand.buttonpos = int(self.re_Button.search(hand.string).group('BUTTON'))
@ -183,16 +188,15 @@ class FullTilt(HandHistoryConverter):
#Used for stud hands - borrows the HeroCards regex for now.
m = self.re_HeroCards.finditer(hand.streets.group(street))
print "DEBUG: razz/stud readPlayerCards"
print "DEBUG: STREET: %s", street
print hand.streets.group(street)
for player in m:
print player.groups()
#hand.hero = m.group('PNAME')
# "2c, qh" -> set(["2c","qc"])
# Also works with Omaha hands.
cards = player.group('CARDS')
print "DEBUG: PNAME: %s CARDS: %s" %(player.group('PNAME'), player.group('CARDS'))
if player.group('NEWCARD') != None:
print cards
cards = cards + " " + player.group('NEWCARD')
cards = set(cards.split(' '))
# hand.addHoleCards(cards, m.group('PNAME'))
hand.addPlayerCards(cards, player.group('PNAME'))
def readAction(self, hand, street):
m = self.re_Action.finditer(hand.streets.group(street))

View File

@ -35,6 +35,20 @@ import Configuration
class GuiBulkImport():
def import_dir(self):
"""imports a directory, non-recursive. todo: move this to fpdb_import so CLI can use it"""
self.path = self.inputFile
self.importer.addImportDirectory(self.path)
self.importer.setCallHud(False)
starttime = time()
if not self.importer.settings['threads'] > 1:
(stored, dups, partial, errs, ttime) = self.importer.runImport()
print 'GuiBulkImport.import_dir done: Stored: %d Duplicates: %d Partial: %d Errors: %d in %s seconds - %d/sec'\
% (stored, dups, partial, errs, ttime, stored / ttime)
else:
self.importer.RunImportThreaded()
def load_clicked(self, widget, data=None):
# get the dir to import from the chooser
self.inputFile = self.chooser.get_filename()
@ -66,6 +80,7 @@ class GuiBulkImport():
self.lab_info.set_text("Import finished")
def get_vbox(self):
"""returns the vbox of this thread"""
return self.vbox
def __init__(self, db, settings, config):

View File

@ -29,6 +29,11 @@ Main for FreePokerTools HUD.
# Standard Library modules
import sys
# redirect the stderr
errorfile = open('HUD-error.txt', 'w', 0)
sys.stderr = errorfile
import os
import thread
import time
@ -72,7 +77,7 @@ class HUD_main(object):
def destroy(*args): # call back for terminating the main eventloop
gtk.main_quit()
def create_HUD(self, new_hand_id, table, table_name, max, poker_game, is_tournament, stat_dict):
def create_HUD(self, new_hand_id, table, table_name, max, poker_game, is_tournament, stat_dict, cards):
def idle_func():
@ -82,20 +87,21 @@ class HUD_main(object):
self.vb.add(newlabel)
newlabel.show()
self.hud_dict[table_name] = Hud.Hud(self, table, max, poker_game, self.config, self.db_connection)
self.hud_dict[table_name].tablehudlabel = newlabel
self.hud_dict[table_name].create(new_hand_id, self.config, stat_dict)
self.hud_dict[table_name].create(new_hand_id, self.config, stat_dict, cards)
for m in self.hud_dict[table_name].aux_windows:
m.update_data(new_hand_id, self.db_connection)
m.update_gui(new_hand_id)
self.hud_dict[table_name].update(new_hand_id, self.config, stat_dict)
self.hud_dict[table_name].update(new_hand_id, self.config)
self.hud_dict[table_name].reposition_windows()
return False
finally:
gtk.gdk.threads_leave()
self.hud_dict[table_name] = Hud.Hud(self, table, max, poker_game, self.config, self.db_connection)
gobject.idle_add(idle_func)
def update_HUD(self, new_hand_id, table_name, config, stat_dict):
def update_HUD(self, new_hand_id, table_name, config):
"""Update a HUD gui from inside the non-gui read_stdin thread."""
# This is written so that only 1 thread can touch the gui--mainly
# for compatibility with Windows. This method dispatches the
@ -103,7 +109,7 @@ class HUD_main(object):
def idle_func():
gtk.gdk.threads_enter()
try:
self.hud_dict[table_name].update(new_hand_id, config, stat_dict)
self.hud_dict[table_name].update(new_hand_id, config)
for m in self.hud_dict[table_name].aux_windows:
m.update_gui(new_hand_id)
return False
@ -145,6 +151,7 @@ class HUD_main(object):
try:
(table_name, max, poker_game) = self.db_connection.get_table_name(new_hand_id)
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id)
cards = self.db_connection.get_cards(new_hand_id)
except:
print "skipping ", new_hand_id
sys.stderr.write("Database error in hand %d. Skipping.\n" % int(new_hand_id))
@ -163,9 +170,11 @@ class HUD_main(object):
# Update an existing HUD
if temp_key in self.hud_dict:
self.hud_dict[temp_key].stat_dict = stat_dict
self.hud_dict[temp_key].cards = cards
for aw in self.hud_dict[temp_key].aux_windows:
aw.update_data(new_hand_id, self.db_connection)
self.update_HUD(new_hand_id, temp_key, self.config, stat_dict)
self.update_HUD(new_hand_id, temp_key, self.config)
# Or create a new HUD
else:
@ -175,11 +184,12 @@ class HUD_main(object):
tablewindow = Tables.discover_table_by_name(self.config, table_name)
if tablewindow == None:
# If no client window is found on the screen, complain and continue
if is_tournament:
table_name = tour_number + " " + tab_number
sys.stderr.write("table name "+table_name+" not found, skipping.\n")
else:
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, is_tournament, stat_dict)
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, is_tournament, stat_dict, cards)
if __name__== "__main__":
sys.stderr.write("HUD_main starting\n")

View File

@ -15,38 +15,25 @@
#In the "official" distribution you can find the license in
#agpl-3.0.txt in the docs folder of the package.
import Hand
import re
import sys
import traceback
import logging
import os
import os.path
import xml.dom.minidom
import codecs
from decimal import Decimal
import operator
import time
from copy import deepcopy
from Exceptions import *
class Hand:
# def __init__(self, sitename, gametype, sb, bb, string):
UPS = {'a':'A', 't':'T', 'j':'J', 'q':'Q', 'k':'K', 'S':'s', 'C':'c', 'H':'h', 'D':'d'}
def __init__(self, sitename, gametype, handtext):
def __init__(self, sitename, gametype, handText):
self.sitename = sitename
self.gametype = gametype
self.string = handtext
if gametype[1] == "hold" or self.gametype[1] == "omaha":
self.streetList = ['PREFLOP','FLOP','TURN','RIVER'] # a list of the observed street names in order
elif self.gametype[1] == "razz" or self.gametype[1] == "stud" or self.gametype[1] == "stud8":
self.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order
self.handText = handText
self.handid = 0
self.sb = gametype[3]
self.bb = gametype[4]
self.tablename = "Slartibartfast"
self.hero = "Hiro"
self.maxseats = 10
@ -56,38 +43,26 @@ class Hand:
self.players = []
self.posted = []
self.involved = True
self.pot = Pot()
#
# Collections indexed by street names
#
# A MatchObject using a groupnames to identify streets.
# filled by markStreets()
self.streets = None
# dict from street names to lists of tuples, such as
# [['mct','bets','$10'],['mika','folds'],['carlg','raises','$20']]
# actually they're clearly lists but they probably should be tuples.
self.actions = {}
# dict from street names to community cards
self.board = {}
#
# Collections indexed by player names
#
# dict from player names to lists of hole cards
self.holecards = {}
# Collections indexed by street names
self.bets = {}
self.lastBet = {}
self.streets = {}
self.actions = {} # [['mct','bets','$10'],['mika','folds'],['carlg','raises','$20']]
for street in self.streetList:
self.streets[street] = "" # portions of the handText, filled by markStreets()
self.bets[street] = {}
self.lastBet[street] = 0
self.actions[street] = []
self.stacks = {}
self.board = {} # dict from street names to community cards
# dict from player names to amounts collected
self.collected = []
self.collectees = {}
# Collections indexed by player names
self.holecards = {} # dict from player names to lists of hole cards
self.stacks = {}
self.collected = [] #list of ?
self.collectees = {} # dict from player names to amounts collected (?)
# Sets of players
self.shown = set()
@ -99,11 +74,7 @@ class Hand:
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):
"""\
@ -115,7 +86,7 @@ If a player has None chips he won't be added."""
if chips is not None:
self.players.append([seat, name, chips])
self.stacks[name] = Decimal(chips)
self.holecards[name] = set()
self.holecards[name] = []
self.pot.addPlayer(name)
for street in self.streetList:
self.bets[street][name] = []
@ -124,21 +95,34 @@ If a player has None chips he won't be added."""
def addStreets(self, match):
# go through m and initialise actions to empty list for each street.
if match is not None:
self.streets = match
for street in match.groupdict():
if match.group(street) is not None:
self.actions[street] = []
self.streets.update(match.groupdict())
logging.debug(self.streets)
else:
logging.error("markstreets didn't match")
def addHoleCards(self, cards, player):
"""\
Assigns observed holecards to a player.
cards set of card bigrams e.g. set(['2h','Jc'])
cards list of card bigrams e.g. ['2h','Jc']
player (string) name of player
"""
#print "DEBUG: addHoleCards", cards,player
try:
self.checkPlayerExists(player)
cards = set([self.card(c) for c in cards])
self.holecards[player].extend(cards)
except FpdbParseError, e:
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
def addPlayerCards(self, cards, player):
"""\
Assigns observed cards to a player.
cards list of card bigrams e.g. ['2h','Jc']
player (string) name of player
Should probably be merged with addHoleCards
"""
logging.debug("addPlayerCards %s, %s" % ( cards,player))
try:
self.checkPlayerExists(player)
cards = set([self.card(c) for c in cards])
@ -185,25 +169,31 @@ Card ranks will be uppercased
c = c.replace(k,v)
return c
def addAnte(self, player, ante):
if player is not None:
self.bets['ANTES'][player].append(Decimal(ante))
self.stacks[player] -= Decimal(ante)
act = (player, 'posts', "ante", ante, self.stacks[player]==0)
self.actions['ANTES'].append(act)
self.pot.addMoney(player, Decimal(ante))
def addBlind(self, player, blindtype, amount):
# if player is None, it's a missing small blind.
# TODO:
# The situation we need to cover are:
# Player in small blind posts
# - this is a bet of 1 sb, as yet uncalled.
# Player in the big blind posts
# - this is a bet of 1 bb and is the new uncalled
# - this is a call of 1 sb and a raise to 1 bb
#
# If a player posts a big & small blind
# - FIXME: We dont record this for later printing yet
#print "DEBUG addBlind: %s posts %s, %s" % (player, blindtype, amount)
logging.debug("addBlind: %s posts %s, %s" % (player, blindtype, amount))
if player is not None:
self.bets['PREFLOP'][player].append(Decimal(amount))
self.stacks[player] -= Decimal(amount)
#print "DEBUG %s posts, stack %s" % (player, self.stacks[player])
act = (player, 'posts', blindtype, amount, self.stacks[player]==0)
self.actions['PREFLOP'].append(act)
self.actions['BLINDSANTES'].append(act)
self.pot.addMoney(player, Decimal(amount))
if blindtype == 'big blind':
self.lastBet['PREFLOP'] = Decimal(amount)
@ -214,6 +204,8 @@ Card ranks will be uppercased
#print "DEBUG: self.posted: %s" %(self.posted)
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
@ -365,22 +357,69 @@ Map the tuple self.gametype onto the pokerstars string describing it
"cp" : "Cap Pot Limit"
}
logging.debug("DEBUG: self.gametype: %s" %(self.gametype))
string = "%s %s" %(gs[self.gametype[1]], ls[self.gametype[2]])
logging.debug("gametype: %s" %(self.gametype))
retstring = "%s %s" %(gs[self.gametype[1]], ls[self.gametype[2]])
return string
return retstring
def writeHand(self, fh=sys.__stdout__):
if self.gametype[1] == "hold" or self.gametype[1] == "omaha":
self.writeHoldemHand(fh)
else:
self.writeStudHand(fh)
print >>fh, "Override me"
def printHand(self):
self.writeHand(sys.stdout)
def writeHoldemHand(self, fh=sys.__stdout__):
def printActionLine(self, act, fh):
if act[1] == 'folds':
print >>fh, _("%s: folds " %(act[0]))
elif act[1] == 'checks':
print >>fh, _("%s: checks " %(act[0]))
elif act[1] == 'calls':
print >>fh, _("%s: calls $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else ''))
elif act[1] == 'bets':
print >>fh, _("%s: bets $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else ''))
elif act[1] == 'raises':
print >>fh, _("%s: raises $%s to $%s%s" %(act[0], act[2], act[3], ' and is all-in' if act[5] else ''))
elif act[1] == 'posts':
if(act[2] == "small blind"):
print >>fh, _("%s: posts small blind $%s" %(act[0], act[3]))
elif(act[2] == "big blind"):
print >>fh, _("%s: posts big blind $%s" %(act[0], act[3]))
elif(act[2] == "both"):
print >>fh, _("%s: posts small & big blinds $%s" %(act[0], act[3]))
class HoldemOmahaHand(Hand):
def __init__(self, hhc, sitename, gametype, handText):
if gametype[1] not in ["hold","omaha"]:
pass # or indeed don't pass and complain instead
self.streetList = ['BLINDSANTES', 'PREFLOP','FLOP','TURN','RIVER'] # a list of the observed street names in order
self.communityStreets = ['FLOP', 'TURN', 'RIVER']
self.actionStreets = ['PREFLOP','FLOP','TURN','RIVER']
Hand.__init__(self, sitename, gametype, handText)
self.sb = gametype[3]
self.bb = gametype[4]
hhc.readHandInfo(self)
hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(players = set([player[1] for player in self.players]))
hhc.markStreets(self)
hhc.readBlinds(self)
hhc.readButton(self)
hhc.readHeroCards(self)
hhc.readShowdownActions(self)
# Read actions in street order
for street in self.communityStreets:
if self.streets[street]:
hhc.readCommunityCards(self, street)
for street in self.actionStreets:
if self.streets[street]:
hhc.readAction(self, street)
hhc.readCollectPot(self)
hhc.readShownCards(self)
self.totalPot() # finalise it (total the pot)
hhc.getRake(self)
def writeHand(self, fh=sys.__stdout__):
# PokerStars format.
#print "\n### Pseudo stars format ###"
#print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %(self.sitename, self.handid, self.getGameTypeAsString(), self.sb, self.bb, self.starttime))
print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d - %H:%M:%S (ET)', self.starttime)))
print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos))
@ -390,35 +429,29 @@ Map the tuple self.gametype onto the pokerstars string describing it
#Only print stacks of players who do something preflop
print >>fh, _("Seat %s: %s ($%s)" %(player[0], player[1], player[2]))
#May be more than 1 bb posting
for a in self.posted:
if(a[1] == "small blind"):
print >>fh, _("%s: posts small blind $%s" %(a[0], self.sb))
if(a[1] == "big blind"):
print >>fh, _("%s: posts big blind $%s" %(a[0], self.bb))
if(a[1] == "both"):
print >>fh, _("%s: posts small & big blinds $%.2f" %(a[0], (Decimal(self.sb) + Decimal(self.bb))))
if self.actions['BLINDSANTES']:
for act in self.actions['BLINDSANTES']:
self.printActionLine(act, fh)
print >>fh, _("*** HOLE CARDS ***")
if self.involved:
print >>fh, _("Dealt to %s [%s]" %(self.hero , " ".join(self.holecards[self.hero])))
if 'PREFLOP' in self.actions:
if self.actions['PREFLOP']:
for act in self.actions['PREFLOP']:
self.printActionLine(act, fh)
if 'FLOP' in self.actions:
if self.actions['FLOP']:
print >>fh, _("*** FLOP *** [%s]" %( " ".join(self.board['FLOP'])))
for act in self.actions['FLOP']:
self.printActionLine(act, fh)
if 'TURN' in self.actions:
if self.actions['TURN']:
print >>fh, _("*** TURN *** [%s] [%s]" %( " ".join(self.board['FLOP']), " ".join(self.board['TURN'])))
for act in self.actions['TURN']:
self.printActionLine(act, fh)
if 'RIVER' in self.actions:
if self.actions['RIVER']:
print >>fh, _("*** RIVER *** [%s] [%s]" %(" ".join(self.board['FLOP']+self.board['TURN']), " ".join(self.board['RIVER']) ))
for act in self.actions['RIVER']:
self.printActionLine(act, fh)
@ -429,7 +462,7 @@ Map the tuple self.gametype onto the pokerstars string describing it
# we probably don't need a showdown section in pseudo stars format for our filtering purposes
if 'SHOWDOWN' in self.actions:
print >>fh, _("*** SHOW DOWN ***")
#TODO: Complete SHOWDOWN
#TODO: Complete SHOWDOWN
# Current PS format has the lines:
# Uncalled bet ($111.25) returned to s0rrow
@ -467,26 +500,45 @@ Map the tuple self.gametype onto the pokerstars string describing it
print >>fh, _("Seat %d: %s mucked" % (seatnum, name))
print >>fh, "\n\n"
# TODO:
# logic for side pots
# logic for which players get to showdown
# I'm just not sure we need to do this so heavily.. and if we do, it's probably better to use pokerlib
#if self.holecards[player[1]]: # empty list default is false
#hole = self.holecards[player[1]]
##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)
#print "Seat %d: %s showed %s" % (player[0], player[1], hole)
#else:
#print "Seat %d: %s mucked or folded" % (player[0], player[1])
class StudHand(Hand):
def __init__(self, hhc, sitename, gametype, handText):
if gametype[1] not in ["razz","stud","stud8"]:
pass # or indeed don't pass and complain instead
self.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order
Hand.__init__(self, sitename, gametype, handText)
hhc.readHandInfo(self)
hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(players = set([player[1] for player in self.players]))
hhc.markStreets(self)
hhc.readAntes(self)
hhc.readBringIn(self)
hhc.readShowdownActions(self)
# Read actions in street order
for street in self.streetList:
if self.streets[street]:
logging.debug(street)
logging.debug(hand.streets[street])
hhc.readPlayerCards(self, street)
hhc.readAction(self, street)
hhc.readCollectPot(self)
hhc.readShownCards(self)
self.totalPot() # finalise it (total the pot)
hhc.getRake(self)
def addBringIn(self, player, ante):
if player is not None:
self.bets['THIRD'][player].append(Decimal(ante))
self.stacks[player] -= Decimal(ante)
act = (player, 'bringin', "bringin", ante, self.stacks[player]==0)
self.actions['THIRD'].append(act)
self.pot.addMoney(player, Decimal(ante))
def writeStudHand(self, fh=sys.__stdout__):
# PokerStars format.
#print "\n### Pseudo stars format ###"
#print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %(self.sitename, self.handid, self.getGameTypeAsString(), self.sb, self.bb, self.starttime))
print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d - %H:%M:%S (ET)', self.starttime)))
print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos))
@ -496,10 +548,16 @@ Map the tuple self.gametype onto the pokerstars string describing it
#Only print stacks of players who do something preflop
print >>fh, _("Seat %s: %s ($%s)" %(player[0], player[1], player[2]))
if 'ANTES' in self.actions:
for act in self.actions['ANTES']:
print >>fh, _("%s: posts the ante $%s" %(act[0], act[3]))
if 'THIRD' in self.actions:
print >>fh, _("*** 3RD STREET ***")
for player in [x for x in self.players if x[1] in players_who_post_antes]:
print >>fh, _("Dealt to ")
for act in self.actions['THIRD']:
#FIXME: Need some logic here for bringin vs completes
self.printActionLine(act, fh)
if 'FOURTH' in self.actions:
@ -527,7 +585,7 @@ Map the tuple self.gametype onto the pokerstars string describing it
# we probably don't need a showdown section in pseudo stars format for our filtering purposes
if 'SHOWDOWN' in self.actions:
print >>fh, _("*** SHOW DOWN ***")
# print >>fh, "DEBUG: what do they show"
# TODO: print showdown lines.
# Current PS format has the lines:
# Uncalled bet ($111.25) returned to s0rrow
@ -566,78 +624,11 @@ Map the tuple self.gametype onto the pokerstars string describing it
print >>fh, _("Seat %d: %s mucked" % (seatnum, name))
print >>fh, "\n\n"
# TODO:
# logic for side pots
# logic for which players get to showdown
# I'm just not sure we need to do this so heavily.. and if we do, it's probably better to use pokerlib
#if self.holecards[player[1]]: # empty list default is false
#hole = self.holecards[player[1]]
##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)
#print "Seat %d: %s showed %s" % (player[0], player[1], hole)
#else:
#print "Seat %d: %s mucked or folded" % (player[0], player[1])
def printHand(self):
self.writeHand(sys.stdout)
def printActionLine(self, act, fh):
if act[1] == 'folds':
print >>fh, _("%s: folds " %(act[0]))
elif act[1] == 'checks':
print >>fh, _("%s: checks " %(act[0]))
if act[1] == 'calls':
print >>fh, _("%s: calls $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else ''))
if act[1] == 'bets':
print >>fh, _("%s: bets $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else ''))
if act[1] == 'raises':
print >>fh, _("%s: raises $%s to $%s%s" %(act[0], act[2], act[3], ' and is all-in' if act[5] else ''))
# going to use pokereval to figure out hands at some point.
# these functions are copied from pokergame.py
def bestHand(self, side, cards):
return HandHistoryConverter.eval.best('hi', cards, [])
# from pokergame.py
# got rid of the _ for internationalisation
def readableHandValueLong(self, side, value, 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
class FpdbParseError(Exception): pass
class Pot(object):
@ -711,4 +702,3 @@ class Pot(object):
return _("too many pots.. no small blind and walk in bb?. self.pots: %s" %(self.pots))
# I don't know stars format for a walk in the bb when sb doesn't post.
# The thing to do here is raise a Hand error like fpdb import does and file it into errors.txt

View File

@ -72,13 +72,10 @@ letter2names = {
import gettext
gettext.install('myapplication')
class HandHistoryConverter(threading.Thread):
# eval = PokerEval()
def __init__(self, in_path = '-', out_path = '-', sitename = None, follow=False):
super(HandHistoryConverter, self).__init__()
threading.Thread.__init__(self)
logging.info("HandHistory init called")
# default filetype and codepage. Subclasses should set these properly.
@ -94,7 +91,7 @@ class HandHistoryConverter(threading.Thread):
self.out_fh = open(self.out_path, 'a')
self.sitename = sitename
self.follow = follow
self.players = set()
self.compiledPlayers = set()
self.maxseats = 10
def __str__(self):
@ -145,45 +142,11 @@ class HandHistoryConverter(threading.Thread):
gametype = self.determineGameType(handtext)
if gametype is None:
return
hand = Hand.Hand(self.sitename, gametype, handtext)
self.readHandInfo(hand)
self.readPlayerStacks(hand)
playersThisHand = set([player[1] for player in hand.players])
if playersThisHand <= self.players: # x <= y means 'x is subset of y'
# we're ok; the regex should already cover them all.
pass
else:
# we need to recompile the player regexs.
self.players = playersThisHand
self.compilePlayerRegexs()
self.markStreets(hand)
# Different calls if stud or holdem like
if gametype[1] == "hold" or gametype[1] == "omaha":
self.readBlinds(hand)
self.readButton(hand)
self.readHeroCards(hand) # want to generalise to draw games
elif gametype[1] == "razz" or gametype[1] == "stud" or gametype[1] == "stud8":
self.readAntes(hand)
self.readBringIn(hand)
self.readShowdownActions(hand)
# Read actions in street order
for street in hand.streetList: # go through them in order
#logging.debug(street)
if hand.streets.group(street) is not None:
if gametype[1] == "hold" or gametype[1] == "omaha":
self.readCommunityCards(hand, street) # read community cards
elif gametype[1] == "razz" or gametype[1] == "stud" or gametype[1] == "stud8":
self.readPlayerCards(hand, street)
self.readAction(hand, street)
self.readCollectPot(hand)
self.readShownCards(hand)
hand.totalPot() # finalise it (total the pot)
self.getRake(hand)
if gametype[1] in ("hold", "omaha"):
hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handtext)
elif gametype[1] in ("razz","stud","stud8"):
hand = Hand.StudHand(self, self.sitename, gametype, handtext)
hand.writeHand(self.out_fh)
@ -207,7 +170,7 @@ class HandHistoryConverter(threading.Thread):
self.hands = self.splitFileIntoHands()
outfile = open(self.ofile, 'w')
for hand in self.hands:
#print "\nDEBUG: Input:\n"+hand.string
#print "\nDEBUG: Input:\n"+hand.handText
self.readHandInfo(hand)
self.readPlayerStacks(hand)
@ -263,8 +226,7 @@ class HandHistoryConverter(threading.Thread):
outfile.close()
endtime = time.time()
print "Processed %d hands in %.3f seconds" % (len(self.hands), endtime - starttime)
#####
# These functions are parse actions that may be overridden by the inheriting class
# This function should return a list of lists looking like:
# return [["ring", "hold", "nl"], ["tour", "hold", "nl"]]
@ -279,13 +241,13 @@ class HandHistoryConverter(threading.Thread):
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
# 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
# Needs to return a list of lists in the format
@ -355,7 +317,7 @@ class HandHistoryConverter(threading.Thread):
list = self.re_SplitHands.split(self.obs)
list.pop() #Last entry is empty
for l in list:
# print "'" + l + "'"
# print "'" + l + "'"
hands = hands + [Hand.Hand(self.sitename, self.gametype, l)]
return hands

View File

@ -48,6 +48,8 @@ import HUD_main
class Hud:
def __init__(self, parent, table, max, poker_game, config, db_connection):
# __init__ is (now) intended to be called from the stdin thread, so it
# cannot touch the gui
self.parent = parent
self.table = table
self.config = config
@ -57,26 +59,28 @@ class Hud:
self.deleted = False
self.stacked = True
self.site = table.site
self.colors = config.get_default_colors(self.table.site)
self.mw_created = False
self.stat_windows = {}
self.stat_windows = {}
self.popup_windows = {}
self.aux_windows = []
self.aux_windows = []
(font, font_size) = config.get_default_font(self.table.site)
self.colors = config.get_default_colors(self.table.site)
if font == None:
font = "Sans"
if font_size == None:
font_size = "8"
self.font = pango.FontDescription(font + " " + font_size)
self.font = pango.FontDescription(font + " " + font_size)
# do we need to add some sort of condition here for dealing with a request for a font that doesn't exist?
def create_mw(self):
# Set up a main window for this this instance of the HUD
self.main_window = gtk.Window()
self.main_window.set_gravity(gtk.gdk.GRAVITY_STATIC)
self.main_window.set_title(table.name + " FPDBHUD")
self.main_window.set_title(self.table.name + " FPDBHUD")
self.main_window.destroyhandler = self.main_window.connect("destroy", self.kill_hud)
self.main_window.set_decorated(False)
self.main_window.set_opacity(self.colors["hudopacity"])
@ -123,6 +127,7 @@ class Hud:
self.ebox.connect_object("button-press-event", self.on_button_press, self.menu)
self.main_window.show_all()
self.mw_created = True
# TODO: fold all uses of this type of 'topify' code into a single function, if the differences between the versions don't
# create adverse effects?
@ -228,13 +233,17 @@ class Hud:
return self.stat_dict[key]['seat']
sys.stderr.write("Error finding actual seat.\n")
def create(self, hand, config, stat_dict):
def create(self, hand, config, stat_dict, cards):
# update this hud, to the stats and players as of "hand"
# hand is the hand id of the most recent hand played at this table
#
# this method also manages the creating and destruction of stat
# windows via calls to the Stat_Window class
if not self.mw_created:
self.create_mw()
self.stat_dict = stat_dict
self.cards = cards
sys.stderr.write("------------------------------------------------------------\nCreating hud from hand %s\n" % hand)
adj = self.adj_seats(hand, config)
sys.stderr.write("adj = %s\n" % adj)
@ -274,37 +283,35 @@ class Hud:
if os.name == "nt":
gobject.timeout_add(500, self.update_table_position)
def update(self, hand, config, stat_dict):
def update(self, hand, config):
self.hand = hand # this is the last hand, so it is available later
self.stat_dict = stat_dict # so this is available for popups, etc
self.update_table_position()
self.stat_dict = stat_dict
for s in stat_dict:
for s in self.stat_dict:
try:
self.stat_windows[stat_dict[s]['seat']].player_id = stat_dict[s]['player_id']
self.stat_windows[self.stat_dict[s]['seat']].player_id = self.stat_dict[s]['player_id']
except: # omg, we have more seats than stat windows .. damn poker sites with incorrect max seating info .. let's force 10 here
self.max = 10
self.create(hand, config)
self.stat_windows[stat_dict[s]['seat']].player_id = stat_dict[s]['player_id']
self.create(hand, config, self.stat_dict, self.cards)
self.stat_windows[self.stat_dict[s]['seat']].player_id = self.stat_dict[s]['player_id']
for r in range(0, config.supported_games[self.poker_game].rows):
for c in range(0, config.supported_games[self.poker_game].cols):
this_stat = config.supported_games[self.poker_game].stats[self.stats[r][c]]
number = Stats.do_stat(stat_dict, player = stat_dict[s]['player_id'], stat = self.stats[r][c])
number = Stats.do_stat(self.stat_dict, player = self.stat_dict[s]['player_id'], stat = self.stats[r][c])
statstring = this_stat.hudprefix + str(number[1]) + this_stat.hudsuffix
if this_stat.hudcolor != "":
self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
self.stat_windows[stat_dict[s]['seat']].label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.hudcolor))
self.stat_windows[stat_dict[s]['seat']].label[r][c].set_text(statstring)
self.stat_windows[self.stat_dict[s]['seat']].label[r][c].set_text(statstring)
if statstring != "xxx": # is there a way to tell if this particular stat window is visible already, or no?
self.stat_windows[stat_dict[s]['seat']].window.show_all()
self.stat_windows[self.stat_dict[s]['seat']].window.show_all()
# self.reposition_windows()
tip = stat_dict[s]['screen_name'] + "\n" + number[5] + "\n" + \
tip = self.stat_dict[s]['screen_name'] + "\n" + number[5] + "\n" + \
number[3] + ", " + number[4]
Stats.do_tip(self.stat_windows[stat_dict[s]['seat']].e_box[r][c], tip)
Stats.do_tip(self.stat_windows[self.stat_dict[s]['seat']].e_box[r][c], tip)
def topify_window(self, window):
"""Set the specified gtk window to stayontop in MS Windows."""
@ -365,6 +372,7 @@ class Stat_Window:
self.y = y + table.y # x and y are the location relative to table.x & y
self.player_id = player_id # looks like this isn't used ;)
self.sb_click = 0 # used to figure out button clicks
self.useframes = parent.config.get_frames(parent.site)
self.window = gtk.Window()
self.window.set_decorated(0)
@ -382,23 +390,28 @@ class Stat_Window:
self.frame = []
self.label = []
for r in range(self.game.rows):
self.frame.append([])
if self.useframes:
self.frame.append([])
self.e_box.append([])
self.label.append([])
for c in range(self.game.cols):
self.frame[r].append( gtk.Frame() )
if self.useframes:
self.frame[r].append( gtk.Frame() )
self.e_box[r].append( gtk.EventBox() )
self.e_box[r][c].modify_bg(gtk.STATE_NORMAL, parent.backgroundcolor)
self.e_box[r][c].modify_fg(gtk.STATE_NORMAL, parent.foregroundcolor)
Stats.do_tip(self.e_box[r][c], 'stuff')
# self.grid.attach(self.e_box[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0)
self.grid.attach(self.frame[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0)
self.frame[r][c].add(self.e_box[r][c])
if self.useframes:
self.grid.attach(self.frame[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0)
self.frame[r][c].add(self.e_box[r][c])
else:
self.grid.attach(self.e_box[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0)
self.label[r].append( gtk.Label('xxx') )
self.frame[r][c].modify_bg(gtk.STATE_NORMAL, parent.backgroundcolor)
if self.useframes:
self.frame[r][c].modify_bg(gtk.STATE_NORMAL, parent.backgroundcolor)
self.label[r][c].modify_bg(gtk.STATE_NORMAL, parent.backgroundcolor)
self.label[r][c].modify_fg(gtk.STATE_NORMAL, parent.foregroundcolor)

View File

@ -154,7 +154,7 @@ class Stud_list:
winners = winners + player
pot_dec = "%.2f" % (float(pot)/100)
hero_cards = self.get_hero_cards(self.parent.hero, self.parent.mucked_cards.cards)
hero_cards = self.get_hero_cards(self.parent.hero, self.parent.hud.cards)
self.info_row = ((new_hand_id, hero_cards, pot_dec, winners), )
def get_hero_cards(self, hero, cards):
@ -163,11 +163,10 @@ class Stud_list:
if hero == '':
return "xxxxxx"
else:
for k in cards.keys():
if cards[k]['screen_name'] == hero:
return trans[cards[k]['card1Value']] + cards[k]['card1Suit'] \
+ trans[cards[k]['card2Value']] + cards[k]['card2Suit'] \
+ trans[cards[k]['card3Value']] + cards[k]['card3Suit']
# find the hero's seat from the stat_dict
for stat in self.parent.hud.stat_dict.itervalues():
if stat['screen_name'] == hero:
return self.parent.hud.cards[stat['seat']][0:6]
return "xxxxxx"
def update_gui(self, new_hand_id):
@ -225,25 +224,7 @@ class Stud_cards:
self.container.add(self.grid)
def translate_cards(self, old_cards):
ranks = ('', '', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
for c in old_cards.keys():
for i in range(1, 8):
rank = 'card' + str(i) + 'Value'
suit = 'card' + str(i) + 'Suit'
key = 'hole_card_' + str(i)
if old_cards[c][rank] == 0:
old_cards[c][key] = 'xx'
else:
old_cards[c][key] = ranks[old_cards[c][rank]] + old_cards[c][suit]
return old_cards
def update_data(self, new_hand_id, db_connection):
# db_connection = Database.Database(self.config, 'fpdb', '')
cards = db_connection.get_cards(new_hand_id)
self.cards = self.translate_cards(cards)
self.tips = []
action = db_connection.get_action_from_hand(new_hand_id)
for street in action:
@ -261,13 +242,13 @@ class Stud_cards:
def update_gui(self, new_hand_id):
self.clear()
for c in self.cards.keys():
self.grid_contents[(1, self.cards[c]['seat_number'] - 1)].set_text(self.cards[c]['screen_name'])
for i in ((0, 'hole_card_1'), (1, 'hole_card_2'), (2, 'hole_card_3'), (3, 'hole_card_4'),
(4, 'hole_card_5'), (5, 'hole_card_6'), (6, 'hole_card_7')):
if not self.cards[c][i[1]] == "xx":
self.seen_cards[(i[0], self.cards[c]['seat_number'] - 1)]. \
set_from_pixbuf(self.card_images[self.split_cards(self.cards[c][i[1]])])
for c, cards in self.parent.hud.cards.iteritems():
self.grid_contents[(1, c - 1)].set_text(self.get_screen_name(c))
for i in ((0, cards[0:2]), (1, cards[2:4]), (2, cards[4:6]), (3, cards[6:8]),
(4, cards[8:10]), (5, cards[10:12]), (6, cards[12:14])):
if not i[1] == "xx":
self.seen_cards[(i[0], c - 1)]. \
set_from_pixbuf(self.card_images[self.split_cards(i[1])])
## action in tool tips for 3rd street cards
for c in (0, 1, 2):
for r in range(0, self.rows):
@ -279,6 +260,13 @@ class Stud_cards:
for r in range(0, self.rows):
self.eb[(round_to_col[round], r)].set_tooltip_text(self.tips[round])
def get_screen_name(self, seat_no):
"""Gets and returns the screen name from stat_dict, given seat number."""
for k in self.parent.hud.stat_dict.keys():
if self.parent.hud.stat_dict[k]['seat'] == seat_no:
return self.parent.hud.stat_dict[k]['screen_name']
return "No Name"
def split_cards(self, card):
return (card[0], card[1].upper())

View File

@ -70,6 +70,13 @@ def do_stat(stat_dict, player = 24, stat = 'vpip'):
###########################################
# functions that return individual stats
def totalprofit(stat_dict, player):
""" Total Profit."""
if stat_dict[player]['net'] != 0:
stat = float(stat_dict[player]['net']) / 100
return (stat, '$%.2f' % stat, 'tp=$%.2f' % stat, 'totalprofit=$%.2f' % stat, str(stat), 'Total Profit')
return ('0', '$0.00', 'tp=0', 'totalprofit=0', '0', 'Total Profit')
def playername(stat_dict, player):
""" Player Name."""
return (stat_dict[player]['screen_name'],

View File

@ -390,9 +390,9 @@ if __name__=="__main__":
print discover_table_by_name(c, "Ringe")
# print discover_tournament_table(c, "118942908", "3")
# tables = discover(c)
# for t in tables.keys():
# print tables[t]
tables = discover(c)
for t in tables.keys():
print tables[t]
print "press enter to continue"
sys.stdin.readline()

View File

@ -61,6 +61,7 @@ class Importer:
self.filelist = {}
self.dirlist = {}
self.addToDirList = {}
self.removeFromFileList = {} # to remove deleted files
self.monitor = False
self.updated = {} #Time last import was run {file:mtime}
self.lines = None
@ -209,8 +210,13 @@ class Importer:
for dir in self.addToDirList:
self.addImportDirectory(dir, True, self.addToDirList[dir][0], self.addToDirList[dir][1])
for file in self.removeFromFileList:
if file in self.filelist:
del self.filelist[file]
self.addToDirList = {}
self.removeFromFileList = {}
# This is now an internal function that should not be called directly.
def import_file_dict(self, file, site, filter):
@ -266,9 +272,15 @@ class Importer:
if (file=="stdin"):
inputFile=sys.stdin
else:
inputFile=open(file, "rU")
try: loc = self.pos_in_file[file]
except: pass
if os.path.exists(file):
inputFile = open(file, "rU")
else:
self.removeFromFileList[file] = True
return (0, 0, 0, 1, 0)
try:
loc = self.pos_in_file[file]
except:
pass
# Read input file into class and close file
inputFile.seek(loc)