Poker winning hands probability tester

TrustyTony 0 Tallied Votes 577 Views Share

Here is code which I wrote to experiment how hard it is to get Royal Flush in Poker.

import random
from itertools import islice

suitcode={'heart':'H','diamonds':'D','spade':'S','club':'C'}
valuecode={14:'A',13:'K',12:'Q',11:'J'}
for i in range(2,11):
    valuecode[i] = str(i)
    
def dealer(deck):
    while deck:
        yield deck.pop()

def gethand(dealer):
    return sorted(islice(dealer,5))

def isflush(cards):
    return all(suit==firstsuit
               for value,suit in cards
               for _,firstsuit in (cards[0],)
               )

def isstraight(cards):
    if all(a==b for a,b in zip(range(2,6)+[14],[x for x,_ in cards])):
##        print 'Small ace',cards #straight 1..5
        return True
    else:
        return all(nextvalue==thisvalue+1
               for (thisvalue,_),(nextvalue,_) in zip(cards[:-1],cards[1:]))

def cardcode(value,suit):
    return suitcode[suit]+valuecode[value]

def codedhand(cards):
    return ','.join(cardcode(*card) for card in cards)
    
if __name__== '__main__':
    wins = games = 0
    handstyle=''

    multiples={frozenset([1,3]):'Triple',frozenset([1,2]):'Two pairs', frozenset([1,4]):'Four same',
               frozenset([2,3]):'Full house'}
    while 'Royal' not in handstyle: # and wins < 1000:
        ## cards with ace as more high value 14
        deck=[(value+2,suit)
              for suit in ('heart','diamonds','spade','club')
              for value in range(13)]
        random.shuffle(deck)

        getcards=dealer(deck)

        while len(deck)>=10 and 'Royal' not in handstyle:
            games+=1
            playerhand, dealerhand = gethand(getcards), gethand(getcards)

            for cards in (dealerhand,playerhand):
                if len(set(x for x,_ in cards))<4: ## 3 or 4 same, two pairs or full house
                    wins+=1
                    values=list(x for x,_ in cards)
                    counts={}
                    for value in set(values):
                        counts[value]=values.count(value)
                    handstyle = multiples[frozenset(counts.values())]
                    print handstyle,':',codedhand(cards)
                    
                if isflush(cards) or isstraight(cards):
                    wins+=1
                    if isflush(cards) and isstraight(cards):
                        handstyle = 'Royal Flush' if cards[-1][0]==14 else 'Straight Flush'
                        print '***'+handstyle+'***'
                    else:                                              
                        handstyle = 'Straight ' if isstraight(cards) else 'Flush'
                    print handstyle,':',codedhand(cards)
            
                    
    raw_input("\n\n%i wins in %i games" % (wins,games))
TrustyTony 888 pyMod Team Colleague Featured Poster

Bug in Royal Flush detection because of Ace as 1 straight is sorted wrong. Change the main routine for loop to:

for cards in (dealerhand,playerhand):
                if len(set(x for x,_ in cards)) < 4: ## 3 or 4 same, two pairs or full house
                    wins+=1
                    values=list(x for x,_ in cards)
                    counts={}
                    for value in set(values):
                        counts[value]=values.count(value)
                    handstyle = multiples[frozenset(counts.values())]
                    
                elif isflush(cards) or isstraight(cards):
                    wins+=1
                    if isflush(cards) and isstraight(cards):
                        handstyle = 'Royal Flush' if cards[0][0]==10 else 'Straight Flush'
                        print '***'+handstyle+'***'
                    else:                                              
                        handstyle = 'Straight' if isstraight(cards) else 'Flush'
                else: # at most one pair -> pass printing
                    continue

                print handstyle,':',codedhand(cards)

to correct the problem.

If you want to recognize one pair hands add to dictionary:

frozenset([1,1,1,2]):'One pair'

and include hands with 4 different values.

TrustyTony 888 pyMod Team Colleague Featured Poster

This my old hashing is not sufficient in identifying all valuable hands in game, so I got shamed of this old code and did some cleaning of the mess, with more complete statistics:

import random
from itertools import islice

suitcode={'heart':'H','diamonds':'D','spade':'S','club':'C'}
valuecode={14:'A',13:'K',12:'Q',11:'J'}
for i in range(2,11):
    valuecode[i] = str(i)
    
def dealer(deck):
    while deck:
        yield deck.pop()

def gethands(dealer):
    while dealer:
        cards = sorted(islice(dealer,5))
        if len(cards) == 5:
            yield cards
        else:
            break

def isflush(cards):
    return all(suit==firstsuit
               for value,suit in cards
               for _,firstsuit in (cards[0],)
               )

def isstraight(cards):
    # check also case 2,3,4,5,14 -> 1,2,3,4,5
    return (all(a==b for a,b in zip(range(2,6)+[14],
                                    [x for x,_ in cards])
                ) or
            # normal case
            all(nextvalue==thisvalue+1
                for (thisvalue,_),(nextvalue,_) in zip(cards[:-1],cards[1:]))
            )

def cardcode(value,suit):
    return suitcode[suit]+valuecode[value]

def codedhand(cards):
    return ','.join(cardcode(*card) for card in cards)

def newdeck():
    ## cards with ace as more high value 14 == 12 + 2
    deck = [(value+2,suit)
              for suit in ('heart','diamonds','spade','club')
              for value in range(13)]
    random.shuffle(deck)
    return deck

if __name__== '__main__':
    hands = 0
    wins = {}
    handstyle=''

    multiples={frozenset((3,(1,1,3))):'Triple',
               frozenset((3,(1,2,2))):'Two pairs',
               frozenset((2,(1,4))):'Four same',
               frozenset((2,(2,3))):'Full house',
               frozenset((4,(1,1,1,2))):'One pair'
               }
    totalhands = 0
    while 'Royal Flush' not in wins: # and sum(wins[key] for key in wins) < 10000:
        deck = newdeck()
        cards_generator = dealer(deck)

        for hands,cards in enumerate(gethands(cards_generator)):
            if 'Royal' in handstyle:
               break

            if isflush(cards) or isstraight(cards):
                if isflush(cards) and isstraight(cards):
                    handstyle = 'Royal Flush' if cards[0][0]==10 else 'Straight Flush'
                    print '***' + handstyle + '***'
                else:                                              
                    handstyle = 'Straight' if isstraight(cards) else 'Flush'
                wins[handstyle] = wins[handstyle]+1 if handstyle in wins else 1
            else:
                values = [x for x,_ in cards]
                count_of_values = tuple(sorted(values.count(x) for x in set(values)))
                signature = frozenset((len(count_of_values), count_of_values))
                if signature in multiples: # and not 4 in signature:  
                    wins[multiples[signature]] = (wins[multiples[signature]]+1
                                                  if multiples[signature] in wins
                                                  else 1)
                    handstyle = multiples[signature]
                else:
                    continue

##                print "%10s:%20s" % (handstyle,codedhand(cards))
            
        totalhands += hands
            
     
    raw_input("%i wins in %i hands:\n%s\nPush enter to finish! " %
              (sum(wins[key] for key in wins), totalhands, wins))
TrustyTony 888 pyMod Team Colleague Featured Poster

Frozenset is unnecessary as I use tuple instead of tuple, then also separate length is unnecessary and separate signature

import random
from itertools import islice

suitcode={'heart':'H','diamonds':'D','spade':'S','club':'C'}
valuecode={14:'A',13:'K',12:'Q',11:'J'}
for i in range(2,11):
    valuecode[i] = str(i)
    
def dealer(deck):
    while deck:
        yield deck.pop()

def gethands(dealer):
    while dealer:
        cards = sorted(islice(dealer,5))
        if len(cards) == 5:
            yield cards
        else:
            break

def isflush(cards):
    return all(suit==firstsuit
               for value,suit in cards
               for _,firstsuit in (cards[0],)
               )

def isstraight(cards):
    # check also case 2,3,4,5,14 -> 1,2,3,4,5
    return (all(a==b for a,b in zip(range(2,6)+[14],
                                    [x for x,_ in cards])
                ) or
            # normal case
            all(nextvalue==thisvalue+1
                for (thisvalue,_),(nextvalue,_) in zip(cards[:-1],cards[1:]))
            )

def cardcode(value,suit):
    return suitcode[suit]+valuecode[value]

def codedhand(cards):
    return ','.join(cardcode(*card) for card in cards)

def newdeck():
    ## cards with ace as more high value 14 == 12 + 2
    deck = [(value+2,suit)
              for suit in ('heart','diamonds','spade','club')
              for value in range(13)]
    random.shuffle(deck)
    return deck

if __name__== '__main__':
    hands = 0
    wins = {}
    handstyle=''

    multiples={(1,1,3) : 'Triple',
               (1,2,2) : 'Two pairs',
               (1,4) : 'Four same',
               (2,3) : 'Full house',
               (1,1,1,2) : 'One pair'
               }
    totalhands = 0
    while sum(wins[key] for key in wins) < 100000: # 'Royal Flush' not in wins: 
        deck = newdeck()
        cards_generator = dealer(deck)

        for hands,cards in enumerate(gethands(cards_generator)):
            if 'Royal' in handstyle:
               break

            if isflush(cards) or isstraight(cards):
                if isflush(cards) and isstraight(cards):
                    handstyle = 'Royal Flush' if cards[0][0]==10 else 'Straight Flush'
                    print '***' + handstyle + '***'
                else:                                              
                    handstyle = 'Straight' if isstraight(cards) else 'Flush'
                wins[handstyle] = wins[handstyle]+1 if handstyle in wins else 1
                print "%10s:%20s" % (handstyle,codedhand(cards))
            else:
                values = [x for x,_ in cards]
                count_of_values = tuple(sorted(values.count(x) for x in set(values)))
                if count_of_values in multiples:
                    # and len(count_of_values) < 4: # do not consider simple pairs
                    wins[multiples[count_of_values]] = (wins[multiples[count_of_values]]+1
                                                  if multiples[count_of_values] in wins
                                                  else 1)
                    handstyle = multiples[count_of_values]
                else:
                    continue

            
        totalhands += hands
            
     
    raw_input("%i wins in %i hands:\n%s\nPush enter to finish! " %
              (sum(wins[key] for key in wins), totalhands, wins))
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.