diff --git a/pyfpdb/Card.py b/pyfpdb/Card.py
index 287a0f6a..8639fd35 100755
--- a/pyfpdb/Card.py
+++ b/pyfpdb/Card.py
@@ -16,6 +16,25 @@
#agpl-3.0.txt in the docs folder of the package.
+# From fpdb_simple
+card_map = { "0": 0, "2": 2, "3" : 3, "4" : 4, "5" : 5, "6" : 6, "7" : 7, "8" : 8,
+ "9" : 9, "T" : 10, "J" : 11, "Q" : 12, "K" : 13, "A" : 14}
+
+# FIXME: the following is a workaround until switching to newimport.
+# This should be moved into DerivedStats
+# I'd also like to change HandsPlayers.startCards to a different datatype
+# so we can 'trivially' add different start card classifications
+
+def calcStartCards(hand, player):
+ if hand.gametype['category'] == 'holdem':
+ hcs = hand.join_holecards(player, asList=True)
+ #print "DEBUG: hcs: %s" % hcs
+ value1 = card_map[hcs[0][0]]
+ value2 = card_map[hcs[1][0]]
+ return twoStartCards(value1, hcs[0][1], value2, hcs[1][1])
+ else:
+ # FIXME: Only do startCards value for holdem at the moment
+ return 0
def twoStartCards(value1, suit1, value2, suit2):
@@ -127,4 +146,4 @@ if __name__ == '__main__':
(i, valueSuitFromCard(i), i+13, valueSuitFromCard(i+13), i+26, valueSuitFromCard(i+26), i+39, valueSuitFromCard(i+39))
print
- print encodeCard('7c')
\ No newline at end of file
+ print encodeCard('7c')
diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py
index d14ee1d8..4330020b 100755
--- a/pyfpdb/Configuration.py
+++ b/pyfpdb/Configuration.py
@@ -284,6 +284,10 @@ class Game:
stat.hudprefix = stat_node.getAttribute("hudprefix")
stat.hudsuffix = stat_node.getAttribute("hudsuffix")
stat.hudcolor = stat_node.getAttribute("hudcolor")
+ stat.stat_loth = stat_node.getAttribute("stat_loth")
+ stat.stat_hith = stat_node.getAttribute("stat_hith")
+ stat.stat_locolor = stat_node.getAttribute("stat_locolor")
+ stat.stat_hicolor = stat_node.getAttribute("stat_hicolor")
self.stats[stat.stat_name] = stat
diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py
index dbd655a3..f96b6af7 100644
--- a/pyfpdb/DerivedStats.py
+++ b/pyfpdb/DerivedStats.py
@@ -47,19 +47,12 @@ class DerivedStats():
self.handsplayers[player[1]]['wonWhenSeenStreet1'] = 0.0
self.handsplayers[player[1]]['sawShowdown'] = False
self.handsplayers[player[1]]['wonAtSD'] = 0.0
- for i in range(5):
- self.handsplayers[player[1]]['street%dCalls' % i] = 0
- self.handsplayers[player[1]]['street%dBets' % i] = 0
- for i in range(1,5):
- self.handsplayers[player[1]]['street%dCBChance' %i] = False
- self.handsplayers[player[1]]['street%dCBDone' %i] = False
-
- #FIXME - Everything below this point is incomplete.
+ self.handsplayers[player[1]]['startCards'] = 0
self.handsplayers[player[1]]['position'] = 2
- self.handsplayers[player[1]]['tourneyTypeId'] = 1
- self.handsplayers[player[1]]['startCards'] = 0
self.handsplayers[player[1]]['street0_3BChance'] = False
self.handsplayers[player[1]]['street0_3BDone'] = False
+ self.handsplayers[player[1]]['street0_4BChance'] = False
+ self.handsplayers[player[1]]['street0_4BDone'] = False
self.handsplayers[player[1]]['stealAttemptChance'] = False
self.handsplayers[player[1]]['stealAttempted'] = False
self.handsplayers[player[1]]['foldBbToStealChance'] = False
@@ -67,13 +60,22 @@ class DerivedStats():
self.handsplayers[player[1]]['foldSbToStealChance'] = False
self.handsplayers[player[1]]['foldedSbToSteal'] = False
self.handsplayers[player[1]]['foldedBbToSteal'] = False
+ for i in range(5):
+ self.handsplayers[player[1]]['street%dCalls' % i] = 0
+ self.handsplayers[player[1]]['street%dBets' % i] = 0
+ for i in range(1,5):
+ self.handsplayers[player[1]]['street%dCBChance' %i] = False
+ self.handsplayers[player[1]]['street%dCBDone' %i] = False
+ self.handsplayers[player[1]]['street%dCheckCallRaiseChance' %i] = False
+ self.handsplayers[player[1]]['street%dCheckCallRaiseDone' %i] = False
+
+ #FIXME - Everything below this point is incomplete.
+ self.handsplayers[player[1]]['tourneyTypeId'] = 1
for i in range(1,5):
self.handsplayers[player[1]]['otherRaisedStreet%d' %i] = False
self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False
self.handsplayers[player[1]]['foldToStreet%dCBChance' %i] = False
self.handsplayers[player[1]]['foldToStreet%dCBDone' %i] = False
- self.handsplayers[player[1]]['street%dCheckCallRaiseChance' %i] = False
- self.handsplayers[player[1]]['street%dCheckCallRaiseDone' %i] = False
self.assembleHands(self.hand)
self.assembleHandsPlayers(self.hand)
@@ -172,33 +174,46 @@ class DerivedStats():
# self.handsplayers[player[1]]['card%s' % i] = Card.encodeCard(card)
for i, card in enumerate(hcs[:7]):
self.handsplayers[player[1]]['card%s' % (i+1)] = Card.encodeCard(card)
+ self.handsplayers[player[1]]['startCards'] = Card.calcStartCards(hand, player[1])
-
- # position,
- #Stud 3rd street card test
- # denny501: brings in for $0.02
- # s0rrow: calls $0.02
- # TomSludge: folds
- # Soroka69: calls $0.02
- # rdiezchang: calls $0.02 (Seat 8)
- # u.pressure: folds (Seat 1)
- # 123smoothie: calls $0.02
- # gashpor: calls $0.02
-
+ self.setPositions(hand)
+ self.calcCheckCallRaise(hand)
+ self.calc34BetStreet0(hand)
+ self.calcSteals(hand)
# Additional stats
# 3betSB, 3betBB
# Squeeze, Ratchet?
- def getPosition(hand, seat):
- """Returns position value like 'B', 'S', 0, 1, ..."""
- # Flop/Draw games with blinds
- # Need a better system???
- # -2 BB - B (all)
- # -1 SB - S (all)
- # 0 Button
- # 1 Cutoff
- # 2 Hijack
+ def setPositions(self, hand):
+ """Sets the position for each player in HandsPlayers
+ any blinds are negative values, and the last person to act on the
+ first betting round is 0
+ NOTE: HU, both values are negative for non-stud games
+ NOTE2: I've never seen a HU stud match"""
+ # The position calculation must be done differently for Stud and other games as
+ # Stud the 'blind' acts first - in all other games they act last.
+ #
+ #This function is going to get it wrong when there in situations where there
+ # is no small blind. I can live with that.
+ positions = [7, 6, 5, 4, 3, 2, 1, 0, 'S', 'B']
+ actions = hand.actions[hand.holeStreets[0]]
+ players = self.pfbao(actions)
+ seats = len(players)
+ map = []
+ if hand.gametype['base'] == 'stud':
+ # Could posibly change this to be either -2 or -1 depending if they complete or bring-in
+ # First player to act is -1, last player is 0 for 6 players it should look like:
+ # ['S', 4, 3, 2, 1, 0]
+ map = positions[-seats-1:-1] # Copy required positions from postions array anding in -1
+ map = map[-1:] + map[0:-1] # and move the -1 to the start of that array
+ else:
+ # For 6 players is should look like:
+ # [3, 2, 1, 0, 'S', 'B']
+ map = positions[-seats:] # Copy required positions from array ending in -2
+
+ for i, player in enumerate(players):
+ self.handsplayers[player]['position'] = map[i]
def assembleHudCache(self, hand):
pass
@@ -262,13 +277,59 @@ class DerivedStats():
for (i, street) in enumerate(hand.actionStreets[1:]):
self.hands['street%dRaises' % i] = len(filter( lambda action: action[1] in ('raises','bets'), hand.actions[street]))
- def calcCBets(self, hand):
- # Continuation Bet chance, action:
- # Had the last bet (initiative) on previous street, got called, close street action
- # Then no bets before the player with initiatives first action on current street
- # ie. if player on street-1 had initiative
- # and no donkbets occurred
+ def calcSteals(self, hand):
+ """Fills stealAttempt(Chance|ed, fold(Bb|Sb)ToSteal(Chance|)
+ Steal attemp - open raise on positions 2 1 0 S - i.e. MP3, CO, BU, SB
+ Fold to steal - folding blind after steal attemp wo any other callers or raisers
+ """
+ steal_attemp = False
+ steal_positions = ('2', '1', '0', 'S')
+ if hand.gametype['base'] == 'stud':
+ steal_positions = ('2', '1', '0')
+ for action in hand.actions[hand.actionStreets[1]]:
+ pname, act = action[0], action[1]
+ #print action[0], hp.position, steal_attemp, act
+ if self.handsplayers[pname]['position'] == 'B':
+ #NOTE: Stud games will never hit this section
+ self.handsplayers[pname]['foldBbToStealChance'] = steal_attemp
+ self.handsplayers[pname]['foldBbToSteal'] = self.handsplayers[pname]['foldBbToStealChance'] and act == 'folds'
+ break
+ elif self.handsplayers[pname]['position'] == 'S':
+ self.handsplayers[pname]['foldSbToStealChance'] = steal_attemp
+ self.handsplayers[pname]['foldSbToSteal'] = self.handsplayers[pname]['foldSbToStealChance'] and act == 'folds'
+
+ if steal_attemp and act != 'folds':
+ break
+
+ if self.handsplayers[pname]['position'] in steal_positions and not steal_attemp:
+ self.handsplayers[pname]['stealAttemptChance'] = True
+ if act in ('bets', 'raises'):
+ self.handsplayers[pname]['stealAttempted'] = True
+ steal_attemp = True
+
+ def calc34BetStreet0(self, hand):
+ """Fills street0_(3|4)B(Chance|Done), other(3|4)BStreet0"""
+ bet_level = 1 # bet_level after 3-bet is equal to 3
+ for action in hand.actions[hand.actionStreets[1]]:
+ # FIXME: fill other(3|4)BStreet0 - i have no idea what does it mean
+ pname, aggr = action[0], action[1] in ('raises', 'bets')
+ self.handsplayers[pname]['street0_3BChance'] = bet_level == 2
+ self.handsplayers[pname]['street0_4BChance'] = bet_level == 3
+ self.handsplayers[pname]['street0_3BDone'] = aggr and (self.handsplayers[pname]['street0_3BChance'])
+ self.handsplayers[pname]['street0_4BDone'] = aggr and (self.handsplayers[pname]['street0_4BChance'])
+ if aggr:
+ bet_level += 1
+
+
+ def calcCBets(self, hand):
+ """Fill streetXCBChance, streetXCBDone, foldToStreetXCBDone, foldToStreetXCBChance
+
+ Continuation Bet chance, action:
+ Had the last bet (initiative) on previous street, got called, close street action
+ Then no bets before the player with initiatives first action on current street
+ ie. if player on street-1 had initiative and no donkbets occurred
+ """
# XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
# came there
#for i, street in enumerate(hand.actionStreets[2:], start=1):
@@ -280,6 +341,28 @@ class DerivedStats():
if chance == True:
self.handsplayers[name]['street%dCBDone' % (i+1)] = self.betStreet(hand.actionStreets[i+2], name)
+ def calcCheckCallRaise(self, hand):
+ """Fill streetXCheckCallRaiseChance, streetXCheckCallRaiseDone
+
+ streetXCheckCallRaiseChance = got raise/bet after check
+ streetXCheckCallRaiseDone = checked. got raise/bet. didn't fold
+
+ CG: CheckCall would be a much better name for this.
+ """
+ for i, street in enumerate(hand.actionStreets[2:], start=1):
+ actions = hand.actions[hand.actionStreets[i]]
+ checkers = set()
+ initial_raiser = None
+ for action in actions:
+ pname, act = action[0], action[1]
+ if act in ('bets', 'raises') and initial_raiser is None:
+ initial_raiser = pname
+ elif act == 'checks' and initial_raiser is None:
+ checkers.add(pname)
+ elif initial_raiser is not None and pname in checkers:
+ self.handsplayers[pname]['street%dCheckCallRaiseChance' % i] = True
+ self.handsplayers[pname]['street%dCheckCallRaiseDone' % i] = act!='folds'
+
def seen(self, hand, i):
pas = set()
for act in hand.actions[hand.actionStreets[i+1]]:
@@ -293,11 +376,13 @@ class DerivedStats():
def aggr(self, hand, i):
aggrers = set()
- for act in hand.actions[hand.actionStreets[i]]:
- if act[1] in ('completes', 'raises'):
+ # Growl - actionStreets contains 'BLINDSANTES', which isn't actually an action street
+ for act in hand.actions[hand.actionStreets[i+1]]:
+ if act[1] in ('completes', 'bets', 'raises'):
aggrers.add(act[0])
for player in hand.players:
+ #print "DEBUG: actionStreet[%s]: %s" %(hand.actionStreets[i+1], i)
if player[1] in aggrers:
self.handsplayers[player[1]]['street%sAggr' % i] = True
else:
@@ -333,6 +418,44 @@ class DerivedStats():
players.add(action[0])
return players
+ def pfbao(self, actions, f=None, l=None, unique=True):
+ """Helper method. Returns set of PlayersFilteredByActionsOrdered
+
+ f - forbidden actions
+ l - limited to actions
+ """
+ # Note, this is an adaptation of function 5 from:
+ # http://www.peterbe.com/plog/uniqifiers-benchmark
+ seen = {}
+ players = []
+ for action in actions:
+ if l is not None and action[1] not in l: continue
+ if f is not None and action[1] in f: continue
+ if action[0] in seen and unique: continue
+ seen[action[0]] = 1
+ players.append(action[0])
+ return players
+
+ def firstsBetOrRaiser(self, actions):
+ """Returns player name that placed the first bet or raise.
+
+ None if there were no bets or raises on that street
+ """
+ for act in actions:
+ if act[1] in ('bets', 'raises'):
+ return act[0]
+ return None
+
+ def lastBetOrRaiser(self, street):
+ """Returns player name that placed the last bet or raise for that street.
+ None if there were no bets or raises on that street"""
+ lastbet = None
+ for act in self.hand.actions[street]:
+ if act[1] in ('bets', 'raises'):
+ lastbet = act[0]
+ return lastbet
+
+
def noBetsBefore(self, street, player):
"""Returns true if there were no bets before the specified players turn, false otherwise"""
betOrRaise = False
@@ -355,12 +478,3 @@ class DerivedStats():
break
return betOrRaise
-
- def lastBetOrRaiser(self, street):
- """Returns player name that placed the last bet or raise for that street.
- None if there were no bets or raises on that street"""
- lastbet = None
- for act in self.hand.actions[street]:
- if act[1] in ('bets', 'raises'):
- lastbet = act[0]
- return lastbet
diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example
index b1ebd761..3acfd812 100644
--- a/pyfpdb/HUD_config.xml.example
+++ b/pyfpdb/HUD_config.xml.example
@@ -448,59 +448,61 @@ Left-Drag to Move"
-
-
-
-
-
+
+
+
+
-
-
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py
index a18797df..1ea0d203 100644
--- a/pyfpdb/HandHistoryConverter.py
+++ b/pyfpdb/HandHistoryConverter.py
@@ -512,7 +512,7 @@ or None if we fail to get the info """
def getTableTitleRe(type, table_name=None, tournament = None, table_number=None):
"Returns string to search in windows titles"
if type=="tour":
- return "%s.+Table\s%s" % (tournament, table_number)
+ return "%s.+Table.+%s" % (tournament, table_number)
else:
return table_name
diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py
index b61c17aa..1a27b682 100644
--- a/pyfpdb/Hud.py
+++ b/pyfpdb/Hud.py
@@ -606,6 +606,7 @@ class Hud:
if self.update_table_position() == False: # we got killed by finding our table was gone
return
+ self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
for s in self.stat_dict:
try:
statd = self.stat_dict[s]
@@ -629,8 +630,17 @@ class Hud:
window = self.stat_windows[statd['seat']]
if this_stat.hudcolor != "":
- self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.hudcolor))
+ else:
+ window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
+
+ if this_stat.stat_loth != "":
+ if number[0] < (float(this_stat.stat_loth)/100):
+ window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.stat_locolor))
+
+ if this_stat.stat_hith != "":
+ if number[0] > (float(this_stat.stat_hith)/100):
+ window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.stat_hicolor))
window.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?
diff --git a/pyfpdb/PartyPokerToFpdb.py b/pyfpdb/PartyPokerToFpdb.py
index ba597881..269b26a6 100755
--- a/pyfpdb/PartyPokerToFpdb.py
+++ b/pyfpdb/PartyPokerToFpdb.py
@@ -78,11 +78,12 @@ class PartyPoker(HandHistoryConverter):
re_HandInfo = re.compile("""
^Table\s+
- (?P[^#()]+)\s+ # Regular, Speed, etc
- (?P\(|\#| ) # \# means sng, ( - mtt, nothing - cash game
- (?P\d+) \)? \s+ # it's global unique id for this table
- (?:Table\s+\#(?P\d+).+)? # table num for mtt tournaments
- \((?PReal|Play)\s+Money\)\s*
+ (?P[a-zA-Z0-9 ]+)\s+
+ (?: \#|\(|)(?P
\d+)\)?\s+
+ (?:[^ ]+\s+\#(?P\d+).+)? # table number for mtt
+ (\(No\sDP\)\s)?
+ \((?PReal|Play)\s+Money\)\s+ # FIXME: check if play money is correct
+ Seat\s+(?P