Merge branch 'master' of git://git.assembla.com/fpdboz
This commit is contained in:
commit
b80dc2fb38
|
@ -68,7 +68,7 @@ class Everleaf(HandHistoryConverter):
|
||||||
print "Initialising Everleaf converter class"
|
print "Initialising Everleaf converter class"
|
||||||
HandHistoryConverter.__init__(self, config, file, sitename="Everleaf") # Call super class init.
|
HandHistoryConverter.__init__(self, config, file, sitename="Everleaf") # Call super class init.
|
||||||
self.sitename = "Everleaf"
|
self.sitename = "Everleaf"
|
||||||
self.setFileType("text")
|
self.setFileType("text", "cp1252")
|
||||||
self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)')
|
self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)')
|
||||||
self.rexx.setSplitHandRegex('\n\n+')
|
self.rexx.setSplitHandRegex('\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.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]+)')
|
||||||
|
@ -79,7 +79,7 @@ class Everleaf(HandHistoryConverter):
|
||||||
self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<HOLE1>\S\S), (?P<HOLE2>\S\S) \]')
|
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.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.setShowdownActionRegex('.*\n(?P<PNAME>.*) shows \[ (?P<CARDS>.*) \]')
|
||||||
self.rexx.setCollectPotRegex('.*\n(?P<PNAME>.*) wins \$ (?P<POT>[.\d]+) USD.*')
|
self.rexx.setCollectPotRegex('.*\n(?P<PNAME>.*) wins \$ (?P<POT>[.\d]+) USD(.*\[ (?P<HAND>.*) \])?')
|
||||||
self.rexx.compileRegexes()
|
self.rexx.compileRegexes()
|
||||||
|
|
||||||
def readSupportedGames(self):
|
def readSupportedGames(self):
|
||||||
|
@ -118,9 +118,7 @@ class Everleaf(HandHistoryConverter):
|
||||||
def readPlayerStacks(self, hand):
|
def readPlayerStacks(self, hand):
|
||||||
m = self.rexx.player_info_re.finditer(hand.string)
|
m = self.rexx.player_info_re.finditer(hand.string)
|
||||||
players = []
|
players = []
|
||||||
#print "\nReading stacks - players seen:"
|
|
||||||
for a in m:
|
for a in m:
|
||||||
#print a.group('PNAME')
|
|
||||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
||||||
|
|
||||||
def markStreets(self, hand):
|
def markStreets(self, hand):
|
||||||
|
@ -132,28 +130,11 @@ class Everleaf(HandHistoryConverter):
|
||||||
r"(\*\* Dealing Flop \*\* \[ \S\S, \S\S, \S\S \](?P<FLOP>.+(?=\*\* Dealing Turn \*\*)|.+))?"
|
r"(\*\* Dealing Flop \*\* \[ \S\S, \S\S, \S\S \](?P<FLOP>.+(?=\*\* Dealing Turn \*\*)|.+))?"
|
||||||
r"(\*\* Dealing Turn \*\* \[ \S\S \](?P<TURN>.+(?=\*\* Dealing River \*\*)|.+))?"
|
r"(\*\* Dealing Turn \*\* \[ \S\S \](?P<TURN>.+(?=\*\* Dealing River \*\*)|.+))?"
|
||||||
r"(\*\* Dealing River \*\* \[ \S\S \](?P<RIVER>.+))?", hand.string,re.DOTALL)
|
r"(\*\* Dealing River \*\* \[ \S\S \](?P<RIVER>.+))?", hand.string,re.DOTALL)
|
||||||
# that wasn't easy.
|
|
||||||
|
|
||||||
|
|
||||||
#m1 = re.search(r'(\*\* Dealing down cards \*\*)?(?P<PREFLOP>.*?\n\*\*)',hand.string,re.DOTALL)
|
|
||||||
#m2 = re.search(r'(\*\* Dealing Flop \*\*)?(?P<FLOP>.*\n\*\*)',hand.string,re.DOTALL)
|
|
||||||
#print hand.string
|
|
||||||
#print "m groups:\n",m.groupdict()
|
|
||||||
#print "m1 groups:\n",m1.groupdict()
|
|
||||||
#print "m2 groups:\n",m2.groupdict()
|
|
||||||
#(\*\* 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
|
||||||
#sys.exit()
|
|
||||||
|
|
||||||
def readCommunityCards(self, hand):
|
def readCommunityCards(self, hand):
|
||||||
# currently regex in wrong place pls fix my brain's fried
|
# currently regex in wrong place pls fix my brain's fried
|
||||||
# what a mess!
|
|
||||||
re_board = re.compile('\*\* Dealing (?P<STREET>.*) \*\* \[ (?P<CARDS>.*) \]')
|
re_board = re.compile('\*\* Dealing (?P<STREET>.*) \*\* \[ (?P<CARDS>.*) \]')
|
||||||
m = re_board.finditer(hand.string)
|
m = re_board.finditer(hand.string)
|
||||||
for street in m:
|
for street in m:
|
||||||
|
@ -209,11 +190,15 @@ class Everleaf(HandHistoryConverter):
|
||||||
re_card = re.compile('(?P<CARD>[0-9tjqka][schd])') # copied from earlier
|
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'))]
|
cards = [card.group('CARD') for card in re_card.finditer(shows.group('CARDS'))]
|
||||||
print cards
|
print cards
|
||||||
hand.addHoleCards(cards, shows.group('PNAME'))
|
hand.addShownCards(cards, shows.group('PNAME'))
|
||||||
|
|
||||||
def readCollectPot(self,hand):
|
def readCollectPot(self,hand):
|
||||||
m = self.rexx.collect_pot_re.search(hand.string)
|
m = self.rexx.collect_pot_re.search(hand.string)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
|
if m.group('HAND') is not None:
|
||||||
|
re_card = re.compile('(?P<CARD>[0-9tjqka][schd])') # copied from earlier
|
||||||
|
cards = set([hand.card(card.group('CARD')) for card in re_card.finditer(m.group('HAND'))])
|
||||||
|
hand.addShownCards(cards=None, player=m.group('PNAME'), holeandboard=cards)
|
||||||
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
|
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
|
||||||
else:
|
else:
|
||||||
print "WARNING: Unusual, no one collected; can happen if it's folded to big blind with a dead small blind."
|
print "WARNING: Unusual, no one collected; can happen if it's folded to big blind with a dead small blind."
|
||||||
|
@ -223,7 +208,7 @@ class Everleaf(HandHistoryConverter):
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
c = Configuration.Config()
|
c = Configuration.Config()
|
||||||
e = Everleaf(c, "Speed_Kuala_full.txt")
|
e = Everleaf(c, "regression-test-files/everleaf/Speed_Kuala_full.txt")
|
||||||
e.processFile()
|
e.processFile()
|
||||||
print str(e)
|
print str(e)
|
||||||
|
|
||||||
|
|
404
pyfpdb/Hand.py
Normal file
404
pyfpdb/Hand.py
Normal file
|
@ -0,0 +1,404 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
#Copyright 2008 Carl Gherardi
|
||||||
|
#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 Configuration
|
||||||
|
import FpdbRegex
|
||||||
|
import Hand
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import xml.dom.minidom
|
||||||
|
import codecs
|
||||||
|
from decimal import Decimal
|
||||||
|
import operator
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
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.streetList = ['BLINDS','PREFLOP','FLOP','TURN','RIVER'] # a list of the observed street names in order
|
||||||
|
|
||||||
|
self.handid = 0
|
||||||
|
self.sb = gametype[3]
|
||||||
|
self.bb = gametype[4]
|
||||||
|
self.tablename = "Slartibartfast"
|
||||||
|
self.hero = "Hiro"
|
||||||
|
self.maxseats = 10
|
||||||
|
self.counted_seats = 0
|
||||||
|
self.buttonpos = 0
|
||||||
|
self.seating = []
|
||||||
|
self.players = []
|
||||||
|
self.posted = []
|
||||||
|
self.involved = True
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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 = {}
|
||||||
|
|
||||||
|
# dict from player names to amounts collected
|
||||||
|
self.collected = {}
|
||||||
|
|
||||||
|
# Sets of players
|
||||||
|
self.shown = set()
|
||||||
|
self.folded = set()
|
||||||
|
|
||||||
|
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):
|
||||||
|
"""\
|
||||||
|
Adds a player to the hand, and initialises data structures indexed by player.
|
||||||
|
seat (int) indicating the seat
|
||||||
|
name (string) player name
|
||||||
|
chips (string) the chips the player has at the start of the hand (can be None)
|
||||||
|
If a player has None chips he won't be added."""
|
||||||
|
if chips is not None:
|
||||||
|
self.players.append([seat, name, chips])
|
||||||
|
self.holecards[name] = []
|
||||||
|
for street in self.streetList:
|
||||||
|
self.bets[street][name] = []
|
||||||
|
|
||||||
|
|
||||||
|
def addHoleCards(self, cards, player):
|
||||||
|
"""\
|
||||||
|
Assigns observed holecards to a player.
|
||||||
|
cards list of card bigrams e.g. ['2h','jc']
|
||||||
|
player (string) name of player
|
||||||
|
hand
|
||||||
|
Note, will automatically uppercase the rank letter.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.checkPlayerExists(player)
|
||||||
|
self.holecards[player] = set([self.card(c) for c in cards])
|
||||||
|
except FpdbParseError, e:
|
||||||
|
print "Tried to add holecards for unknown player: %s" % (player,)
|
||||||
|
|
||||||
|
def addShownCards(self, cards, player, holeandboard=None):
|
||||||
|
"""\
|
||||||
|
For when a player shows cards for any reason (for showdown or out of choice).
|
||||||
|
"""
|
||||||
|
if cards is not None:
|
||||||
|
self.shown.add(player)
|
||||||
|
self.addHoleCards(cards,player)
|
||||||
|
elif holeandboard is not None:
|
||||||
|
board = set([c for s in self.board.values() for c in s])
|
||||||
|
#print board
|
||||||
|
#print holeandboard
|
||||||
|
#print holeandboard.difference(board)
|
||||||
|
self.addHoleCards(holeandboard.difference(board),player)
|
||||||
|
|
||||||
|
|
||||||
|
def checkPlayerExists(self,player):
|
||||||
|
if player not in [p[1] for p in self.players]:
|
||||||
|
raise FpdbParseError
|
||||||
|
|
||||||
|
def discardHoleCards(self, cards, player):
|
||||||
|
try:
|
||||||
|
self.checkPlayerExists(player)
|
||||||
|
for card in cards:
|
||||||
|
self.holecards[player].remove(card)
|
||||||
|
except FpdbParseError, e:
|
||||||
|
pass
|
||||||
|
except ValueError:
|
||||||
|
print "tried to discard a card %s didn't have" % (player,)
|
||||||
|
|
||||||
|
def setCommunityCards(self, street, cards):
|
||||||
|
self.board[street] = [self.card(c) for c in cards]
|
||||||
|
|
||||||
|
def card(self,c):
|
||||||
|
"""upper case the ranks but not suits, 'atjqk' => 'ATJQK'"""
|
||||||
|
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 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):
|
||||||
|
"""\
|
||||||
|
Add a raise on [street] by [player] to [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)
|
||||||
|
self.checkPlayerExists(player)
|
||||||
|
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, amount):
|
||||||
|
self.checkPlayerExists(player)
|
||||||
|
self.bets[street][player].append(Decimal(amount))
|
||||||
|
self.actions[street] += [[player, 'bets', amount]]
|
||||||
|
|
||||||
|
def addFold(self, street, player):
|
||||||
|
self.checkPlayerExists(player)
|
||||||
|
self.folded.add(player)
|
||||||
|
self.actions[street] += [[player, 'folds']]
|
||||||
|
|
||||||
|
def addCheck(self, street, player):
|
||||||
|
self.checkPlayerExists(player)
|
||||||
|
self.actions[street] += [[player, 'checks']]
|
||||||
|
|
||||||
|
def addCollectPot(self,player, pot):
|
||||||
|
self.checkPlayerExists(player)
|
||||||
|
if player not in self.collected:
|
||||||
|
self.collected[player] = pot
|
||||||
|
else:
|
||||||
|
# possibly lines like "p collected $ from pot" appear during the showdown
|
||||||
|
# but they are usually unique in the summary, so it's best to try to get them from there.
|
||||||
|
print "%s collected pot more than once; avoidable by reading winnings only from summary lines?"
|
||||||
|
|
||||||
|
|
||||||
|
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 getGameTypeAsString(self):
|
||||||
|
"""\
|
||||||
|
Map the tuple self.gametype onto the pokerstars string describing it
|
||||||
|
"""
|
||||||
|
# currently it appears to be something like ["ring", "hold", "nl", sb, bb]:
|
||||||
|
gs = {"hold" : "Hold'em",
|
||||||
|
"omahahi" : "FIXME",
|
||||||
|
"omahahilo" : "FIXME",
|
||||||
|
"razz" : "Razz",
|
||||||
|
"studhi" : "FIXME",
|
||||||
|
"studhilo" : "FIXME",
|
||||||
|
"fivedraw" : "5 Card Draw",
|
||||||
|
"27_1draw" : "FIXME",
|
||||||
|
"27_3draw" : "Triple Draw 2-7 Lowball",
|
||||||
|
"badugi" : "FIXME"
|
||||||
|
}
|
||||||
|
ls = {"nl" : "No Limit",
|
||||||
|
"pl" : "Pot Limit",
|
||||||
|
"fl" : "Limit",
|
||||||
|
"cn" : "Cap No Limit",
|
||||||
|
"cp" : "Cap Pot Limit"
|
||||||
|
}
|
||||||
|
|
||||||
|
string = "%s %s" %(gs[self.gametype[1]], ls[self.gametype[2]])
|
||||||
|
|
||||||
|
return string
|
||||||
|
|
||||||
|
def printHand(self):
|
||||||
|
# PokerStars format.
|
||||||
|
print "\n### Pseudo stars format ###"
|
||||||
|
print "%s Game #%s: %s ($%s/$%s) - %s" %(self.sitename, self.handid, self.getGameTypeAsString(), 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 ***"
|
||||||
|
if self.involved:
|
||||||
|
print "Dealt to %s [%s]" %(self.hero , " ".join(self.holecards[self.hero]))
|
||||||
|
|
||||||
|
if 'PREFLOP' in self.actions:
|
||||||
|
for act in self.actions['PREFLOP']:
|
||||||
|
self.printActionLine(act)
|
||||||
|
|
||||||
|
if 'FLOP' in self.actions:
|
||||||
|
print "*** FLOP *** [%s]" %( " ".join(self.board['Flop']))
|
||||||
|
for act in self.actions['FLOP']:
|
||||||
|
self.printActionLine(act)
|
||||||
|
|
||||||
|
if 'TURN' in self.actions:
|
||||||
|
print "*** TURN *** [%s] [%s]" %( " ".join(self.board['Flop']), " ".join(self.board['Turn']))
|
||||||
|
for act in self.actions['TURN']:
|
||||||
|
self.printActionLine(act)
|
||||||
|
|
||||||
|
if 'RIVER' in self.actions:
|
||||||
|
print "*** RIVER *** [%s] [%s]" %(" ".join(self.board['Flop']+self.board['Turn']), " ".join(self.board['River']) )
|
||||||
|
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
|
||||||
|
# we probably don't need a showdown section in pseudo stars format for our filtering purposes
|
||||||
|
if 'SHOWDOWN' in self.actions:
|
||||||
|
print "*** SHOW DOWN ***"
|
||||||
|
print "what do they show"
|
||||||
|
|
||||||
|
print "*** SUMMARY ***"
|
||||||
|
print "Total pot $%s | Rake $%.2f)" % (self.totalpot, self.rake) # TODO side pots
|
||||||
|
board = []
|
||||||
|
for s in self.board.values():
|
||||||
|
board += s
|
||||||
|
if board: # sometimes hand ends preflop without a board
|
||||||
|
print "Board [%s]" % (" ".join(board))
|
||||||
|
|
||||||
|
|
||||||
|
for player in self.players:
|
||||||
|
seatnum = player[0]
|
||||||
|
name = player[1]
|
||||||
|
if name in self.collected and self.holecards[name]:
|
||||||
|
print "Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards[name]), self.collected[name])
|
||||||
|
elif name in self.collected:
|
||||||
|
print "Seat %d: %s collected ($%s)" % (seatnum, name, self.collected[name])
|
||||||
|
elif player[1] in self.shown:
|
||||||
|
print "Seat %d: %s showed [%s]" % (seatnum, name, " ".join(self.holecards[name]))
|
||||||
|
elif player[1] in self.folded:
|
||||||
|
print "Seat %d: %s folded" % (seatnum, name)
|
||||||
|
else:
|
||||||
|
print "Seat %d: %s mucked" % (seatnum, name)
|
||||||
|
|
||||||
|
print
|
||||||
|
# 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 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] == 'bets':
|
||||||
|
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 at some point.
|
||||||
|
# these functions are copied from pokergame.py
|
||||||
|
def bestHand(self, side, cards):
|
||||||
|
return HandHistoryConverter.eval.best('hi', cards, [])
|
||||||
|
|
||||||
|
# from pokergame.py
|
||||||
|
def bestHandValue(self, side, serial):
|
||||||
|
(value, cards) = self.bestHand(side, serial)
|
||||||
|
return value
|
||||||
|
|
||||||
|
# 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
|
|
@ -17,17 +17,19 @@
|
||||||
|
|
||||||
import Configuration
|
import Configuration
|
||||||
import FpdbRegex
|
import FpdbRegex
|
||||||
|
import Hand
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
|
import codecs
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
import operator
|
import operator
|
||||||
from xml.dom.minidom import Node
|
from xml.dom.minidom import Node
|
||||||
from pokereval import PokerEval
|
from pokereval import PokerEval
|
||||||
|
from time import time
|
||||||
#from pokerengine.pokercards import *
|
#from pokerengine.pokercards import *
|
||||||
# provides letter2name{}, letter2names{}, visible_card(), not_visible_card(), is_visible(), card_value(), class PokerCards
|
# provides letter2name{}, letter2names{}, visible_card(), not_visible_card(), is_visible(), card_value(), class PokerCards
|
||||||
# but it's probably not installed so here are the ones we may want:
|
# but it's probably not installed so here are the ones we may want:
|
||||||
|
@ -67,11 +69,11 @@ class HandHistoryConverter:
|
||||||
eval = PokerEval()
|
eval = PokerEval()
|
||||||
def __init__(self, config, file, sitename):
|
def __init__(self, config, file, sitename):
|
||||||
print "HandHistory init called"
|
print "HandHistory init called"
|
||||||
|
|
||||||
self.c = config
|
self.c = config
|
||||||
self.sitename = sitename
|
self.sitename = sitename
|
||||||
self.obs = "" # One big string
|
self.obs = "" # One big string
|
||||||
self.filetype = "text"
|
self.filetype = "text"
|
||||||
|
self.codepage = "utf8"
|
||||||
self.doc = None # For XML based HH files
|
self.doc = None # For XML based HH files
|
||||||
self.file = file
|
self.file = file
|
||||||
self.hhbase = self.c.get_import_parameters().get("hhArchiveBase")
|
self.hhbase = self.c.get_import_parameters().get("hhArchiveBase")
|
||||||
|
@ -95,6 +97,7 @@ class HandHistoryConverter:
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
def processFile(self):
|
def processFile(self):
|
||||||
|
starttime = time()
|
||||||
if not self.sanityCheck():
|
if not self.sanityCheck():
|
||||||
print "Cowardly refusing to continue after failed sanity check"
|
print "Cowardly refusing to continue after failed sanity check"
|
||||||
return
|
return
|
||||||
|
@ -128,6 +131,9 @@ class HandHistoryConverter:
|
||||||
#else:
|
#else:
|
||||||
#pass #Don't write out observed hands
|
#pass #Don't write out observed hands
|
||||||
|
|
||||||
|
endtime = time()
|
||||||
|
print "Processed %d hands in %d seconds" % (len(self.hands), endtime-starttime)
|
||||||
|
|
||||||
#####
|
#####
|
||||||
# These functions are parse actions that may be overridden by the inheriting class
|
# These functions are parse actions that may be overridden by the inheriting class
|
||||||
#
|
#
|
||||||
|
@ -192,8 +198,9 @@ class HandHistoryConverter:
|
||||||
return sane
|
return sane
|
||||||
|
|
||||||
# Functions not necessary to implement in sub class
|
# Functions not necessary to implement in sub class
|
||||||
def setFileType(self, filetype = "text"):
|
def setFileType(self, filetype = "text", codepage='utf8'):
|
||||||
self.filetype = filetype
|
self.filetype = filetype
|
||||||
|
self.codepage = codepage
|
||||||
|
|
||||||
def splitFileIntoHands(self):
|
def splitFileIntoHands(self):
|
||||||
hands = []
|
hands = []
|
||||||
|
@ -202,14 +209,14 @@ class HandHistoryConverter:
|
||||||
list.pop() #Last entry is empty
|
list.pop() #Last entry is empty
|
||||||
for l in list:
|
for l in list:
|
||||||
# print "'" + l + "'"
|
# print "'" + l + "'"
|
||||||
hands = hands + [Hand(self.sitename, self.gametype, l)]
|
hands = hands + [Hand.Hand(self.sitename, self.gametype, l)]
|
||||||
return hands
|
return hands
|
||||||
|
|
||||||
def readFile(self, filename):
|
def readFile(self, filename):
|
||||||
"""Read file"""
|
"""Read file"""
|
||||||
print "Reading file: '%s'" %(filename)
|
print "Reading file: '%s'" %(filename)
|
||||||
if(self.filetype == "text"):
|
if(self.filetype == "text"):
|
||||||
infile=open(filename, "rU")
|
infile=codecs.open(filename, "rU", self.codepage)
|
||||||
self.obs = infile.read()
|
self.obs = infile.read()
|
||||||
infile.close()
|
infile.close()
|
||||||
elif(self.filetype == "xml"):
|
elif(self.filetype == "xml"):
|
||||||
|
@ -235,300 +242,3 @@ class HandHistoryConverter:
|
||||||
result*=100
|
result*=100
|
||||||
return result
|
return result
|
||||||
#end def float2int
|
#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.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.collected = {} # dict from player names to amounts collected
|
|
||||||
|
|
||||||
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 (can be None)"""
|
|
||||||
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] = []
|
|
||||||
|
|
||||||
|
|
||||||
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][player].append(Decimal(amount))
|
|
||||||
#self.orderedBets[street].append(Decimal(amount))
|
|
||||||
self.actions[street] += [[player, 'bets', amount]]
|
|
||||||
|
|
||||||
def addFold(self, street, player):
|
|
||||||
self.actions[street] += [[player, 'folds']]
|
|
||||||
|
|
||||||
def addCheck(self, street, player):
|
|
||||||
self.actions[street] += [[player, 'checks']]
|
|
||||||
|
|
||||||
def addCollectPot(self,player, pot):
|
|
||||||
if player not in self.collected:
|
|
||||||
self.collected[player] = pot
|
|
||||||
else:
|
|
||||||
# possibly lines like "p collected $ from pot" appear during the showdown
|
|
||||||
# but they are usually unique in the summary.
|
|
||||||
print "%s collected pot more than once; avoidable by reading winnings only from summary lines?"
|
|
||||||
|
|
||||||
|
|
||||||
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):
|
|
||||||
# PokerStars format.
|
|
||||||
print "\n### Pseudo stars format ###"
|
|
||||||
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 ***"
|
|
||||||
if self.involved:
|
|
||||||
print "Dealt to %s [%s]" %(self.hero , " ".join(self.holecards[self.hero]))
|
|
||||||
|
|
||||||
if 'PREFLOP' in self.actions:
|
|
||||||
for act in self.actions['PREFLOP']:
|
|
||||||
self.printActionLine(act)
|
|
||||||
|
|
||||||
if 'FLOP' in self.actions:
|
|
||||||
print "*** FLOP *** [%s]" %( " ".join(self.board['Flop']))
|
|
||||||
for act in self.actions['FLOP']:
|
|
||||||
self.printActionLine(act)
|
|
||||||
|
|
||||||
if 'TURN' in self.actions:
|
|
||||||
print "*** TURN *** [%s] [%s]" %( " ".join(self.board['Flop']), " ".join(self.board['Turn']))
|
|
||||||
for act in self.actions['TURN']:
|
|
||||||
self.printActionLine(act)
|
|
||||||
|
|
||||||
if 'RIVER' in self.actions:
|
|
||||||
print "*** RIVER *** [%s] [%s]" %(" ".join(self.board['Flop']+self.board['Turn']), " ".join(self.board['River']) )
|
|
||||||
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 $%.2f)" % (self.totalpot, self.rake) # TODO side pots
|
|
||||||
board = []
|
|
||||||
for s in self.board.values():
|
|
||||||
board += s
|
|
||||||
if board: # sometimes hand ends preflop without a board
|
|
||||||
print "Board [%s]" % (" ".join(board))
|
|
||||||
|
|
||||||
#print self.board
|
|
||||||
for player in self.players:
|
|
||||||
seatnum = player[0]
|
|
||||||
name = player[1]
|
|
||||||
if name in self.collected and self.holecards[name]:
|
|
||||||
# TODO: (bug) hero cards will always be 'shown' because they are known to us. Better to explicitly flag those who 'show' their cards.
|
|
||||||
print "Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards[name]), self.collected[name])
|
|
||||||
elif name in self.collected:
|
|
||||||
print "Seat %d: %s collected ($%s)" % (seatnum, name, self.collected[name])
|
|
||||||
elif self.holecards[player[1]]:
|
|
||||||
print "Seat %d: %s showed [%s]" % (seatnum, name, " ".join(self.holecards[name]))
|
|
||||||
else:
|
|
||||||
print "Seat %d: %s folded or mucked" % (seatnum, name)
|
|
||||||
|
|
||||||
print
|
|
||||||
# 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 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] == 'bets':
|
|
||||||
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 at some point.
|
|
||||||
# these functions are copied from pokergame.py
|
|
||||||
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, [])
|
|
||||||
|
|
||||||
# from pokergame.py
|
|
||||||
def bestHandValue(self, side, serial):
|
|
||||||
(value, cards) = self.bestHand(side, serial)
|
|
||||||
return value
|
|
||||||
|
|
||||||
# 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
|
|
|
@ -227,7 +227,7 @@ class Hud:
|
||||||
game_params = config.get_game_parameters(self.poker_game)
|
game_params = config.get_game_parameters(self.poker_game)
|
||||||
if not game_params['aux'] == "":
|
if not game_params['aux'] == "":
|
||||||
aux_params = config.get_aux_parameters(game_params['aux'])
|
aux_params = config.get_aux_parameters(game_params['aux'])
|
||||||
self.aux_windows.append(eval("%s.%s(gtk.Window(), self, config, 'fpdb')" % (aux_params['module'], aux_params['class'])))
|
self.aux_windows.append(eval("%s.%s(gtk.Window(), config, 'fpdb')" % (aux_params['module'], aux_params['class'])))
|
||||||
|
|
||||||
# gobject.timeout_add(500, self.update_table_position)
|
# gobject.timeout_add(500, self.update_table_position)
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import fpdb_db
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
import fpdb_simple
|
import fpdb_simple
|
||||||
import FpdbSQLQueries
|
import FpdbSQLQueries
|
||||||
|
import Tables
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
@ -89,6 +90,11 @@ class TestSequenceFunctions(unittest.TestCase):
|
||||||
self.failUnless(result==datetime.datetime(2008,8,17,6,14,43),
|
self.failUnless(result==datetime.datetime(2008,8,17,6,14,43),
|
||||||
"Date incorrect, expected: 2008-08-17 01:14:43 got: " + str(result))
|
"Date incorrect, expected: 2008-08-17 01:14:43 got: " + str(result))
|
||||||
|
|
||||||
|
def testTableDetection(self):
|
||||||
|
result = Tables.clean_title("French (deep)")
|
||||||
|
self.failUnless(result == "French", "French (deep) parsed incorrectly. Expected 'French' got: " + str(result))
|
||||||
|
# result = ("French (deep) - $0.25/$0.50 - No Limit Hold'em - Logged In As xxxx")
|
||||||
|
|
||||||
def testImportHandHistoryFiles(self):
|
def testImportHandHistoryFiles(self):
|
||||||
"""Test import of single HH file"""
|
"""Test import of single HH file"""
|
||||||
self.mysqlimporter.addImportFile("regression-test-files/hand-histories/ps-lhe-ring-3hands.txt")
|
self.mysqlimporter.addImportFile("regression-test-files/hand-histories/ps-lhe-ring-3hands.txt")
|
||||||
|
|
|
@ -59,7 +59,11 @@ class Importer:
|
||||||
#Set defaults
|
#Set defaults
|
||||||
self.callHud = self.config.get_import_parameters().get("callFpdbHud")
|
self.callHud = self.config.get_import_parameters().get("callFpdbHud")
|
||||||
if not self.settings.has_key('minPrint'):
|
if not self.settings.has_key('minPrint'):
|
||||||
|
#TODO: Is this value in the xml file?
|
||||||
self.settings['minPrint'] = 30
|
self.settings['minPrint'] = 30
|
||||||
|
if not self.settings.has_key('handCount'):
|
||||||
|
#TODO: Is this value in the xml file?
|
||||||
|
self.settings['handCount'] = 0
|
||||||
self.dbConnect()
|
self.dbConnect()
|
||||||
|
|
||||||
# XXX: Why is this here, when fpdb_db.connect() already does the
|
# XXX: Why is this here, when fpdb_db.connect() already does the
|
||||||
|
|
BIN
pyfpdb/psnlheparser-mct.tgz
Normal file
BIN
pyfpdb/psnlheparser-mct.tgz
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user