From 4f44eff3daa9a2285757da6389fac55cc55018ff Mon Sep 17 00:00:00 2001 From: Matt Turnbull Date: Mon, 8 Dec 2008 06:23:50 +0000 Subject: [PATCH] getting somewhere, very messy, using pokereval, not sure if this is right direction, comments please --- pyfpdb/EverleafToFpdb.py | 30 ++++++-- pyfpdb/HandHistoryConverter.py | 133 +++++++++++++++++++++++++++------ 2 files changed, 135 insertions(+), 28 deletions(-) diff --git a/pyfpdb/EverleafToFpdb.py b/pyfpdb/EverleafToFpdb.py index d60211b6..1a1196c5 100755 --- a/pyfpdb/EverleafToFpdb.py +++ b/pyfpdb/EverleafToFpdb.py @@ -66,7 +66,7 @@ from HandHistoryConverter import * class Everleaf(HandHistoryConverter): def __init__(self, config, file): print "Initialising Everleaf converter class" - HandHistoryConverter.__init__(self, config, file, "Everleaf") # Call super class init. + HandHistoryConverter.__init__(self, config, file, sitename="Everleaf") # Call super class init. self.sitename = "Everleaf" self.setFileType("text") self.rexx.setGameInfoRegex('.*Blinds \$?(?P[.0-9]+)/\$?(?P[.0-9]+)') @@ -78,6 +78,7 @@ class Everleaf(HandHistoryConverter): # mct : what about posting small & big blinds simultaneously? self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P.*)\s\[ (?P\S\S), (?P\S\S) \]') self.rexx.setActionStepRegex('.*\n(?P.*) (?Pbets|checks|raises|calls|folds)(\s\[\$ (?P[.\d]+) USD\])?') + self.rexx.setShowdownActionRegex('.*\n(?P.*) shows \[ (?P.*) \]') self.rexx.compileRegexes() def readSupportedGames(self): @@ -118,8 +119,7 @@ class Everleaf(HandHistoryConverter): players = [] for a in m: - hand.addPlayer(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): # PREFLOP = ** Dealing down cards ** @@ -128,6 +128,17 @@ class Everleaf(HandHistoryConverter): # print "DEBUG: Street: %s\tspan: %s" %(street, str(m.span(street))) hand.streets = m + def readCommunityCards(self, hand): + # currently regex in wrong place pls fix my brain's fried + # what a mess! + re_board = re.compile('\*\* Dealing (?P.*) \*\* \[ (?P.*) \]') + m = re_board.finditer(hand.string) + for street in m: + #print street.groups() + re_card = re.compile('(?P[0-9tjqka][schd])') # look that's weird, hole cards have a capital rank but board cards are lower case? + cardsmatch = re_card.finditer(street.group('CARDS')) + hand.setCommunityCards(street.group('STREET'), [card.group('CARD') for card in cardsmatch]) + def readBlinds(self, hand): try: m = self.rexx.small_blind_re.search(hand.string) @@ -148,7 +159,7 @@ class Everleaf(HandHistoryConverter): hand.involved = False else: hand.hero = m.group('PNAME') - hand.addHoleCards(m.group('HOLE1'), m.group('HOLE2')) + hand.addHoleCards([m.group('HOLE1'), m.group('HOLE2')], m.group('PNAME')) def readAction(self, hand, street): m = self.rexx.action_re.finditer(hand.streets.group(street)) @@ -161,10 +172,19 @@ class Everleaf(HandHistoryConverter): elif action.group('ATYPE') == 'bets': hand.addBet( street, action.group('PNAME'), action.group('BET') ) else: - print "DEBUG: unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),) + #print "DEBUG: unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),) hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE')]] + def readShowdownActions(self, hand): + for shows in self.rexx.showdown_action_re.finditer(hand.string): + print shows.groups() + re_card = re.compile('(?P[0-9tjqka][schd])') # copied from earlier + cards = [card.group('CARD') for card in re_card.finditer(shows.group('CARDS'))] + print cards + hand.addHoleCards(cards, shows.group('PNAME')) + + def getRake(self, hand): hand.rake = hand.totalpot * Decimal('0.05') # probably not quite right diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 71bc0b25..06a59064 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -26,10 +26,13 @@ import xml.dom.minidom from decimal import Decimal import operator from xml.dom.minidom import Node +from pokereval import PokerEval class HandHistoryConverter: + eval = PokerEval() def __init__(self, config, file, sitename): print "HandHistory init called" + self.c = config self.sitename = sitename self.obs = "" # One big string @@ -68,8 +71,9 @@ class HandHistoryConverter: self.readPlayerStacks(hand) self.markStreets(hand) self.readBlinds(hand) - self.readHeroCards(hand) - + self.readHeroCards(hand) # want to generalise to draw games + self.readCommunityCards(hand) # read community cards + self.readShowdownActions(hand) # Read action (Note: no guarantee this is in hand order. for street in hand.streets.groupdict(): self.readAction(hand, street) @@ -198,10 +202,7 @@ class HandHistoryConverter: print "*** HOLE CARDS ***" print "Dealt to %s [%s %s]" %(hand.hero , hand.holecards[0], hand.holecards[1]) -# -## ACTION STUFF -# This is no limit only at the moment - + for act in hand.actions['PREFLOP']: self.printActionLine(act, 0) @@ -226,10 +227,6 @@ class HandHistoryConverter: print "*** SUMMARY ***" print "XXXXXXXXXXXX Need sumary info XXXXXXXXXXX" -# print "Total pot $%s | Rake $%s)" %(hand.totalpot $" + hand.rake) -# print "Board [" + boardcards + "]" -# -# SUMMARY STUFF def printActionLine(self, act, pot): @@ -239,7 +236,7 @@ class HandHistoryConverter: print "%s: %s $%s" %(act[0], act[1], act[2]) if act[1] == 'raises': print "%s: %s $%s to XXXpottotalXXX" %(act[0], act[1], act[2]) - + #takes a poker float (including , for thousand seperator and converts it to an int def float2int (self, string): @@ -261,13 +258,13 @@ class Hand: # def __init__(self, sitename, gametype, sb, bb, string): UPS = {'a':'A', 't':'T', 'j':'J', 'q':'Q', 'k':'K'} - STREETS = ['BLINDS','PREFLOP','FLOP','TURN','RIVER'] 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 @@ -281,15 +278,18 @@ class Hand: self.players = [] self.posted = [] self.involved = True + self.hero = "Hiro" - self.holecards = "Xx Xx" + self.holecards = {} # dict from player names to lists of hole cards + self.board = {} # dict from street names to community cards + self.action = [] self.totalpot = None self.rake = None self.bets = {} self.lastBet = {} - for street in self.STREETS: + for street in self.streetList: self.bets[street] = {} self.lastBet[street] = 0 @@ -299,20 +299,36 @@ class Hand: chips, the chips the player has at the start of the hand""" #self.players.append(name) self.players.append([seat, name, chips]) + self.holecards[name] = [] #self.startChips[name] = chips #self.endChips[name] = chips #self.winners[name] = 0 - for street in self.STREETS: + for street in self.streetList: self.bets[street][name] = [] - def addHoleCards(self,h1,h2,seat=None): # generalise to add hole cards for a specific seat or player - self.holecards = [self.card(h1), self.card(h2)] + 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' + # don't know how to make this 'static' for k,v in self.UPS.items(): c = c.replace(k,v) return c @@ -325,6 +341,13 @@ class Hand: 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 @@ -352,15 +375,16 @@ class Hand: self.actions[street] += [[player, 'bets', amount]] def totalPot(self): - + """If all bets and blinds have been added, totals up the total pot size +Known bug: doesn't take into account side pots""" if self.totalpot is None: self.totalpot = 0 # player names: # print [x[1] for x in self.players] for player in [x[1] for x in self.players]: - for street in self.STREETS: - print street, self.bets[street][player] + for street in self.streetList: + #print street, self.bets[street][player] self.totalpot += reduce(operator.add, self.bets[street][player], 0) @@ -385,7 +409,7 @@ class Hand: # What about big & small blinds? print "*** HOLE CARDS ***" - print "Dealt to %s [%s %s]" %(self.hero , self.holecards[0], self.holecards[1]) + print "Dealt to %s [%s %s]" %(self.hero , self.holecards[self.hero][0], self.holecards[self.hero][1]) if 'PREFLOP' in self.actions: for act in self.actions['PREFLOP']: @@ -416,6 +440,19 @@ class Hand: print "*** SUMMARY ***" print "Total pot $%s | Rake $%s)" % (self.totalpot, self.rake) print "Board [%s %s %s %s %s]" % (self.streets.group("FLOP1"), self.streets.group("FLOP2"), self.streets.group("FLOP3"), self.streets.group("TURN1"), self.streets.group("RIVER1")) + + #print self.board + for player in self.players: + if self.holecards[player[1]]: # empty list default is false + hole = self.holecards[player[1]] + #print self.board.values() + board = [] + for s in self.board.values(): + board += s + playerhand = self.bestHand('hi', board+hole) + print "Seat %d: %s showed %s and won/lost with %s" % (player[0], player[1], hole, playerhand) + else: + print "Seat %d: %s mucked or folded" % (player[0], player[1]) def printActionLine(self, act): @@ -424,4 +461,54 @@ class Hand: if act[1] == 'calls': print "%s: %s $%s" %(act[0], act[1], act[2]) if act[1] == 'raises': - print "%s: %s $%s to $%s" %(act[0], act[1], act[2], act[3]) \ No newline at end of file + print "%s: %s $%s to $%s" %(act[0], act[1], act[2], act[3]) + + # going to use pokereval to figure out hands + # these functions are copied from pokergame.py + # im thinking perhaps its best to use all the functionality of pokergame instead + # of reinventing the wheel + def bestHand(self, side, cards): + #if self.variant == "omaha" or self.variant == "omaha8": + #hand = self.serial2player[serial].hand.tolist(True) + #board = self.board.tolist(True) + #else: + #hand = hand.tolist(True) + board.tolist(True) + #board = [] + print cards + return HandHistoryConverter.eval.best('hi', cards, []) + + def bestHandValue(self, side, serial): + (value, cards) = self.bestHand(side, serial) + return value + + + def readableHandValueLong(self, side, value, cards): + cards = self.eval.card2string(cards) + if value == "NoPair": + if side == "low": + if cards[0][0] == '5': + return _("The wheel") + else: + return join(map(lambda card: card[0], cards), ", ") + else: + return _("High card %(card)s") % { 'card' : _(letter2name[cards[0][0]]) } + elif value == "OnePair": + return _("A pair of %(card)s") % { 'card' : _(letter2names[cards[0][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[2][0]]) } + elif value == "TwoPair": + return _("Two pairs %(card1)s and %(card2)s") % { 'card1' : _(letter2names[cards[0][0]]), 'card2' : _(letter2names[cards[2][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[4][0]]) } + elif value == "Trips": + return _("Three of a kind %(card)s") % { 'card' : _(letter2names[cards[0][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[3][0]]) } + elif value == "Straight": + return _("Straight %(card1)s to %(card2)s") % { 'card1' : _(letter2name[cards[0][0]]), 'card2' : _(letter2name[cards[4][0]]) } + elif value == "Flush": + return _("Flush %(card)s high") % { 'card' : _(letter2name[cards[0][0]]) } + elif value == "FlHouse": + return _("%(card1)ss full of %(card2)ss") % { 'card1' : _(letter2name[cards[0][0]]), 'card2' : _(letter2name[cards[3][0]]) } + elif value == "Quads": + return _("Four of a kind %(card)s") % { 'card' : _(letter2names[cards[0][0]]) } + _(", %(card)s kicker") % { 'card' : _(letter2name[cards[4][0]]) } + elif value == "StFlush": + if letter2name[cards[0][0]] == 'Ace': + return _("Royal flush") + else: + return _("Straight flush %(card)s high") % { 'card' : _(letter2name[cards[0][0]]) } + return value \ No newline at end of file