Search code examples
pythonsimulationpoker

calling function multiple times with new results


I wanted to create a poker simulation that creates a certain number of 5-card poker hands, to see how many times hands I need to play till I get the royal flush...

I wrote a function that generates 5 cards but when i run the function multiple times it won't work --> i get 5*x cards instead of multiple hands with each 5 cards

import random

d = []
h = []

def cards():

    l1 = ["Herz", "Karo", "Pik", "Kreuz"]
    l2 = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
    for i in range(10):
        d.append([])
    for k in range(10):
        d[k].append(l1[random.randint(0, (len(l1) - 1))])
        d[k].append(l2[random.randint(0, (len(l2) - 1))])
    for a in d:
        if a not in h:
            h.append(a)
            if len(h) == 5:
                break
        else:
            continue
    return h

for i in range(2):
    print(cards())

When I run the code, I get the following:

[['Karo', 8], ['Herz', 5], ['Pik', 13], ['Herz', 12], ['Karo', 3]]

[['Karo', 8, 'Karo', 5], ['Herz', 5, 'Karo', 6], ['Pik', 13, 'Herz', 4], ['Herz', 12, 'Herz', 5], ['Karo', 3, 'Pik', 3], ['Karo', 8, 'Kreuz', 3], ['Karo', 9, 'Kreuz', 3], ['Pik', 13, 'Herz', 10], ['Pik', 6, 'Karo', 11], ['Karo', 2, 'Pik', 13], []]


Solution

  • Your code currently has global lists that it keeps appending to. This is almost certainly not what you want.

    I would suggest creating a deck of cards, and sampling them without replacement to get a hand of five. You can get up to 10 such hands from a deck of 52 cards. A better way might be to create the deck and shuffle it, picking off 5 cards at a time until it contains fewer than 5 cards.

    In either case, you could then pass each hand through a function that tests if it is a flush or whatever else you want.

    All the tools you will need for this (until you use numpy), are in the itertools and random modules.

    First create a global deck. There is no need to do this multiple times because it will slow you down to no purpose. The deck of cards won't change, only their order will:

    rank = [str(x) for x in range(2, 11)] + list('JQKA')
    suit = list('♠♥♦♣')
    deck = list(''.join(card) for card in itertools.product(rank, suit))
    

    Now you can use this deck to generate from 1 to 10 hands at a time with no repeating cards between them. The key is that shuffling the deck is done in place. You don't have to regenerate the deck every time:

    def make_hands(cards=5, hands=None):
        if hands is None:
            hands = len(deck) // cards
        if cards * hands > len(deck):
            raise ValueError('you ask for too much')
        if cards < 1 or hands < 1:
            raise ValueError('you ask for too little')
        random.shuffle(deck)
        result = [deck[cards * i:cards * i + cards] for i in range(hands)]
    

    You can change the desired number of cards per hand and hands per deck with this function. Let's say that you also have a function to check if a hand is a flush or not called isflush. You could apply it like this:

    def how_many():
        shuffles = 0
        hands = 0
        while True:
            shuffles += 1
            cards = make_hands()
            for hand in cards:
                hands += 1
                if isflush(hand):
                    return shuttles, hands
    
    shuffles, hands = how_many()
    print(f'It took {hands} hands with {shuffles} reshuffles to find a flush')