Add preliminary Badugi support

Done to flesh out what DrawHand will look like
This commit is contained in:
Worros 2009-03-14 19:48:34 +09:00
parent d389706e85
commit 04b43e3b95
2 changed files with 226 additions and 59 deletions

View File

@ -58,9 +58,9 @@ class Hand:
self.actions[street] = [] self.actions[street] = []
self.board[street] = [] self.board[street] = []
# Collections indexed by player names # Collections indexed by player names
self.holecards = {} # dict from player names to dicts by street ... of tuples ... of holecards self.holecards = {} # dict from player names to dicts by street ... of tuples ... of holecards
self.discards = {} # dict from player names to dicts by street ... of tuples ... of discarded holecards
self.stacks = {} self.stacks = {}
self.collected = [] #list of ? self.collected = [] #list of ?
self.collectees = {} # dict from player names to amounts collected (?) self.collectees = {} # dict from player names to amounts collected (?)
@ -89,10 +89,12 @@ If a player has None chips he won't be added."""
self.players.append([seat, name, chips]) self.players.append([seat, name, chips])
self.stacks[name] = Decimal(chips) self.stacks[name] = Decimal(chips)
self.holecards[name] = [] self.holecards[name] = []
self.discards[name] = []
self.pot.addPlayer(name) self.pot.addPlayer(name)
for street in self.streetList: for street in self.streetList:
self.bets[street][name] = [] self.bets[street][name] = []
self.holecards[name] = {} # dict from street names. self.holecards[name] = {} # dict from street names.
self.discards[name] = {} # dict from street names.
def addStreets(self, match): def addStreets(self, match):
@ -246,6 +248,20 @@ Add a raise on [street] by [player] to [amountTo]
self.lastBet[street] = Decimal(amount) self.lastBet[street] = Decimal(amount)
self.pot.addMoney(player, Decimal(amount)) self.pot.addMoney(player, Decimal(amount))
def addDiscard(self, street, player, num, cards):
self.checkPlayerExists(player)
if cards:
act = (player, 'discards', num, cards)
self.discardDrawHoleCards(cards, player, street)
else:
act = (player, 'discards', num)
self.actions[street].append(act)
def addStandsPat(self, street, player):
self.checkPlayerExists(player)
act = (player, 'stands pat')
self.actions[street].append(act)
def addFold(self, street, player): def addFold(self, street, player):
logging.debug("%s %s folds" % (street, player)) logging.debug("%s %s folds" % (street, player))
@ -303,7 +319,7 @@ Map the tuple self.gametype onto the pokerstars string describing it
"fivedraw" : "5 Card Draw", "fivedraw" : "5 Card Draw",
"27_1draw" : "FIXME", "27_1draw" : "FIXME",
"27_3draw" : "Triple Draw 2-7 Lowball", "27_3draw" : "Triple Draw 2-7 Lowball",
"badugi" : "FIXME" "badugi" : "Badugi"
} }
ls = {"nl" : "No Limit", ls = {"nl" : "No Limit",
"pl" : "Pot Limit", "pl" : "Pot Limit",
@ -346,12 +362,18 @@ Map the tuple self.gametype onto the pokerstars string describing it
print >>fh, _("%s: posts small & big blinds $%s" %(act[0], act[3])) print >>fh, _("%s: posts small & big blinds $%s" %(act[0], act[3]))
elif act[1] == 'bringin': elif act[1] == 'bringin':
print >>fh, _("%s: brings in for $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else '')) print >>fh, _("%s: brings in for $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else ''))
elif act[1] == 'discards':
print >>fh, _("%s: discards %s %s%s" %(act[0], act[2], 'card' if act[2] == 1 else 'cards' , " [" + " ".join(self.discards[act[0]]['DRAWONE']) + "]" if self.hero == act[0] else ''))
elif act[1] == 'stands pat':
print >>fh, _("%s: stands pat" %(act[0]))
class HoldemOmahaHand(Hand): class HoldemOmahaHand(Hand):
def __init__(self, hhc, sitename, gametype, handText): def __init__(self, hhc, sitename, gametype, handText):
if gametype['base'] != 'hold': if gametype['base'] != 'hold':
pass # or indeed don't pass and complain instead pass # or indeed don't pass and complain instead
logging.debug("HoldemOmahaHand") logging.debug("HoldemOmahaHand")
self.streetList = ['BLINDSANTES', 'PREFLOP','FLOP','TURN','RIVER'] # a list of the observed street names in order self.streetList = ['BLINDSANTES', 'DEAL', 'PREFLOP','FLOP','TURN','RIVER'] # a list of the observed street names in order
self.communityStreets = ['FLOP', 'TURN', 'RIVER'] self.communityStreets = ['FLOP', 'TURN', 'RIVER']
self.actionStreets = ['PREFLOP','FLOP','TURN','RIVER'] self.actionStreets = ['PREFLOP','FLOP','TURN','RIVER']
Hand.__init__(self, sitename, gametype, handText) Hand.__init__(self, sitename, gametype, handText)
@ -508,16 +530,167 @@ class DrawHand(Hand):
def __init__(self, hhc, sitename, gametype, handText): def __init__(self, hhc, sitename, gametype, handText):
if gametype['base'] != 'draw': if gametype['base'] != 'draw':
pass # or indeed don't pass and complain instead pass # or indeed don't pass and complain instead
self.streetList = ['BLINDSANTES', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE']
self.holeStreets = ['DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE']
self.actionStreets = ['PREDEAL', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE']
Hand.__init__(self, sitename, gametype, handText)
self.sb = gametype['sb']
self.bb = gametype['bb']
# Populate the draw hand.
hhc.readHandInfo(self)
hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(self)
hhc.markStreets(self)
hhc.readBlinds(self)
hhc.readButton(self)
hhc.readShowdownActions(self)
# Read actions in street order
for street in self.streetList:
if self.streets[street]:
# hhc.readCommunityCards(self, street)
hhc.readDrawCards(self, street)
hhc.readAction(self, street)
hhc.readCollectPot(self)
hhc.readShownCards(self)
self.totalPot() # finalise it (total the pot)
hhc.getRake(self)
def discardHoleCards(self, cards, player):
# Draw games (at least Badugi has blinds - override default Holdem addBlind
def addBlind(self, player, blindtype, amount):
# if player is None, it's a missing small blind.
# 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 call of 1 sb and a raise to 1 bb
#
logging.debug("addBlind: %s posts %s, %s" % (player, blindtype, amount))
if player is not None:
self.bets['DEAL'][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['BLINDSANTES'].append(act)
self.pot.addMoney(player, Decimal(amount))
if blindtype == 'big blind':
self.lastBet['DEAL'] = Decimal(amount)
elif blindtype == 'both':
# extra small blind is 'dead'
self.lastBet['DEAL'] = Decimal(self.bb)
self.posted = self.posted + [[player,blindtype]]
#print "DEBUG: self.posted: %s" %(self.posted)
def addDrawHoleCards(self, newcards, oldcards, player, street, shown=False):
"""\
Assigns observed holecards to a player.
cards list of card bigrams e.g. ['2h','Jc']
player (string) name of player
"""
try: try:
self.checkPlayerExists(player) self.checkPlayerExists(player)
for card in cards: # if shown and len(cardset) > 0:
self.holecards[player].remove(card) # self.shown.add(player)
self.holecards[player][street] = (newcards,oldcards)
except FpdbParseError, e: except FpdbParseError, e:
pass print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
except ValueError:
print "[ERROR] discardHoleCard tried to discard a card %s didn't have" % (player,) def discardDrawHoleCards(self, cards, player, street):
logging.debug("discardDrawHoleCards '%s' '%s' '%s'" % (cards, player, street))
self.discards[player][street] = set([cards])
def addShownCards(self, cards, player, holeandboard=None):
"""\
For when a player shows cards for any reason (for showdown or out of choice).
Card ranks will be uppercased
"""
logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard))
# if cards is not None:
# self.shown.add(player)
# self.addHoleCards(cards,player)
# elif holeandboard is not None:
# holeandboard = set([self.card(c) for c in holeandboard])
# board = set([c for s in self.board.values() for c in s])
# self.addHoleCards(holeandboard.difference(board),player,shown=True)
def writeHand(self, fh=sys.__stdout__):
# PokerStars format.
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))
players_who_act_ondeal = set(([x[0] for x in self.actions['DEAL']]+[x[0] for x in self.actions['BLINDSANTES']]))
for player in [x for x in self.players if x[1] in players_who_act_ondeal]:
#Only print stacks of players who do something on deal
print >>fh, _("Seat %s: %s ($%s)" %(player[0], player[1], player[2]))
if 'BLINDSANTES' in self.actions:
for act in self.actions['BLINDSANTES']:
print >>fh, _("%s: %s %s $%s" %(act[0], act[1], act[2], act[3]))
if 'DEAL' in self.actions:
print >>fh, _("*** DEALING HANDS ***")
for player in [x[1] for x in self.players if x[1] in players_who_act_ondeal]:
if 'DEAL' in self.holecards[player]:
(nc,oc) = self.holecards[player]['DEAL']
print >>fh, _("Dealt to %s: [%s]") % (player, " ".join(nc))
for act in self.actions['DEAL']:
self.printActionLine(act, fh)
if 'DRAWONE' in self.actions:
print >>fh, _("*** FIRST DRAW ***")
for act in self.actions['DRAWONE']:
self.printActionLine(act, fh)
if act[0] == self.hero and act[1] == 'discards':
(nc,oc) = self.holecards[act[0]]['DRAWONE']
dc = self.discards[act[0]]['DRAWONE']
kc = oc - dc
print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc)))
if 'DRAWTWO' in self.actions:
print >>fh, _("*** SECOND DRAW ***")
for act in self.actions['DRAWTWO']:
self.printActionLine(act, fh)
if act[0] == self.hero and act[1] == 'discards':
(nc,oc) = self.holecards[act[0]]['DRAWTWO']
dc = self.discards[act[0]]['DRAWTWO']
kc = oc - dc
print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc)))
if 'DRAWTHREE' in self.actions:
print >>fh, _("*** THIRD DRAW ***")
for act in self.actions['DRAWTHREE']:
self.printActionLine(act, fh)
if act[0] == self.hero and act[1] == 'discards':
(nc,oc) = self.holecards[act[0]]['DRAWTHREE']
dc = self.discards[act[0]]['DRAWTHREE']
kc = oc - dc
print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc)))
if 'SHOWDOWN' in self.actions:
print >>fh, _("*** SHOW DOWN ***")
#TODO: Complete SHOWDOWN
# Current PS format has the lines:
# Uncalled bet ($111.25) returned to s0rrow
# s0rrow collected $5.15 from side pot
# stervels: shows [Ks Qs] (two pair, Kings and Queens)
# stervels collected $45.35 from main pot
# Immediately before the summary.
# The current importer uses those lines for importing winning rather than the summary
for name in self.pot.returned:
print >>fh, _("Uncalled bet ($%s) returned to %s" %(self.pot.returned[name],name))
for entry in self.collected:
print >>fh, _("%s collected $%s from x pot" %(entry[0], entry[1]))
print >>fh, _("*** SUMMARY ***")
print >>fh, "%s | Rake $%.2f" % (self.pot, self.rake)
print >>fh, "\n\n"
class StudHand(Hand): class StudHand(Hand):
def __init__(self, hhc, sitename, gametype, handText): def __init__(self, hhc, sitename, gametype, handText):

View File

@ -23,49 +23,6 @@ from HandHistoryConverter import *
# PokerStars HH Format # PokerStars HH Format
#PokerStars Game #20461877044: Hold'em No Limit ($1/$2) - 2008/09/16 18:58:01 ET
#Table 'Gianfar IV' 6-max Seat #1 is the button
#Seat 1: ZeKGB ($224 in chips)
#Seat 2: quimboavida ($107.75 in chips)
#Seat 3: tropical100 ($190 in chips)
#Seat 4: jackhama33 ($54.95 in chips)
#Seat 5: Olubanu ($196 in chips)
#Seat 6: LSgambler ($205.35 in chips)
#quimboavida: posts small blind $1
#tropical100: posts big blind $2
#*** HOLE CARDS ***
#jackhama33: folds
#Olubanu: folds
#LSgambler: folds
#ZeKGB: folds
#quimboavida: calls $1
#tropical100: raises $5 to $7
#quimboavida: calls $5
#*** FLOP *** [3d Qs Kd]
#quimboavida: bets $10
#tropical100: calls $10
#*** TURN *** [3d Qs Kd] [Ah]
#quimboavida: checks
#tropical100: checks
#*** RIVER *** [3d Qs Kd Ah] [7c]
#quimboavida: bets $30
#tropical100: folds
#quimboavida collected $32.35 from pot
#*** SUMMARY ***
#Total pot $34 | Rake $1.65
#Board [3d Qs Kd Ah 7c]
#Seat 1: ZeKGB (button) folded before Flop (didn't bet)
#Seat 2: quimboavida (small blind) collected ($32.35)
#Seat 3: tropical100 (big blind) folded on the River
#Seat 4: jackhama33 folded before Flop (didn't bet)
#Seat 5: Olubanu folded before Flop (didn't bet)
#Seat 6: LSgambler folded before Flop (didn't bet)
#PokerStars Game #25381215423: HORSE (Razz Limit, $0.10/$0.20) - 2009/02/26 15:20:19 ET
#Table 'Natalie V' 8-max
class PokerStars(HandHistoryConverter): class PokerStars(HandHistoryConverter):
# Static regexes # Static regexes
@ -103,7 +60,7 @@ follow : whether to tail -f the input"""
self.re_BringIn = re.compile(r"^%s: brings[- ]in( low|) for \$?(?P<BRINGIN>[.0-9]+)" % player_re, re.MULTILINE) self.re_BringIn = re.compile(r"^%s: brings[- ]in( low|) 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_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<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % player_re, re.MULTILINE) self.re_HeroCards = re.compile(r"^Dealt to %s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % player_re, re.MULTILINE)
self.re_Action = re.compile(r"^%s:(?P<ATYPE> bets| checks| raises| calls| folds)( \$(?P<BET>[.\d]+))?( to \$(?P<BETTO>[.\d]+))?" % player_re, re.MULTILINE) self.re_Action = re.compile(r"^%s:(?P<ATYPE> bets| checks| raises| calls| folds| discards| stands pat)( \$(?P<BET>[.\d]+))?( to \$(?P<BETTO>[.\d]+))?( (?P<NODISCARDED>\d) cards?( \[(?P<DISCARDED>.+?)\])?)?" % player_re, re.MULTILINE)
self.re_ShowdownAction = re.compile(r"^%s: shows \[(?P<CARDS>.*)\]" % 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) 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)
self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE) self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE)
@ -111,7 +68,13 @@ follow : whether to tail -f the input"""
def readSupportedGames(self): def readSupportedGames(self):
return [] return [["ring", "hold", "nl"],
["ring", "hold", "pl"],
["ring", "hold", "fl"],
["ring", "stud", "fl"],
["ring", "draw", "fl"],
["ring", "omaha", "pl"]
]
def determineGameType(self, handText): def determineGameType(self, handText):
info = {'type':'ring'} info = {'type':'ring'}
@ -200,6 +163,12 @@ follow : whether to tail -f the input"""
r"(\*\*\* 5th STREET \*\*\*(?P<FIFTH>.+(?=\*\*\* 6th STREET \*\*\*)|.+))?" r"(\*\*\* 5th STREET \*\*\*(?P<FIFTH>.+(?=\*\*\* 6th STREET \*\*\*)|.+))?"
r"(\*\*\* 6th STREET \*\*\*(?P<SIXTH>.+(?=\*\*\* RIVER \*\*\*)|.+))?" r"(\*\*\* 6th STREET \*\*\*(?P<SIXTH>.+(?=\*\*\* RIVER \*\*\*)|.+))?"
r"(\*\*\* RIVER \*\*\*(?P<SEVENTH>.+))?", hand.handText,re.DOTALL) r"(\*\*\* RIVER \*\*\*(?P<SEVENTH>.+))?", hand.handText,re.DOTALL)
elif hand.gametype['base'] in ("draw"):
m = re.search(r"(?P<PREDEAL>.+(?=\*\*\* DEALING HANDS \*\*\*)|.+)"
r"(\*\*\* DEALING HANDS \*\*\*(?P<DEAL>.+(?=\*\*\* FIRST DRAW \*\*\*)|.+))?"
r"(\*\*\* FIRST DRAW \*\*\*(?P<DRAWONE>.+(?=\*\*\* SECOND DRAW \*\*\*)|.+))?"
r"(\*\*\* SECOND DRAW \*\*\*(?P<DRAWTWO>.+(?=\*\*\* THIRD DRAW \*\*\*)|.+))?"
r"(\*\*\* THIRD DRAW \*\*\*(?P<DRAWTHREE>.+))?", hand.handText,re.DOTALL)
hand.addStreets(m) hand.addStreets(m)
def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand
@ -245,6 +214,27 @@ follow : whether to tail -f the input"""
cards = set(cards.split(' ')) cards = set(cards.split(' '))
hand.addHoleCards(cards, m.group('PNAME')) hand.addHoleCards(cards, m.group('PNAME'))
def readDrawCards(self, hand, street):
logging.debug("readDrawCards")
m = self.re_HeroCards.finditer(hand.streets[street])
if m == None:
hand.involved = False
else:
for player in m:
hand.hero = player.group('PNAME') # Only really need to do this once
newcards = player.group('NEWCARDS')
oldcards = player.group('OLDCARDS')
if newcards == None:
newcards = set()
else:
newcards = set(newcards.split(' '))
if oldcards == None:
oldcards = set()
else:
oldcards = set(oldcards.split(' '))
hand.addDrawHoleCards(newcards, oldcards, player.group('PNAME'), street)
def readStudPlayerCards(self, hand, street): def readStudPlayerCards(self, hand, street):
# See comments of reference implementation in FullTiltToFpdb.py # See comments of reference implementation in FullTiltToFpdb.py
logging.debug("readStudPlayerCards") logging.debug("readStudPlayerCards")
@ -293,8 +283,12 @@ follow : whether to tail -f the input"""
hand.addFold( street, action.group('PNAME')) hand.addFold( street, action.group('PNAME'))
elif action.group('ATYPE') == ' checks': elif action.group('ATYPE') == ' checks':
hand.addCheck( street, action.group('PNAME')) hand.addCheck( street, action.group('PNAME'))
elif action.group('ATYPE') == ' discards':
hand.addDiscard(street, action.group('PNAME'), action.group('NODISCARDED'), action.group('DISCARDED'))
elif action.group('ATYPE') == ' stands pat':
hand.addStandsPat( street, action.group('PNAME'))
else: else:
print "DEBUG: unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),) print "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),)
def readShowdownActions(self, hand): def readShowdownActions(self, hand):