2

I'm trying to use random numbers to access an item in a list, and then once that item has been called it should not be called again. ex: list = [1,2,3,4,5] - I want to be able to pull out each item at random until all have been pulled - without any repeating.

below is the actual code in which I tried - and failed - to implement this.

from random import *
def make_hand():
    cards = ["AC", "AS", "AD", "AH", "2C", "2S", "2D", "2H", "3C", "3S",      "3D", "3H", "4C", "4S", "4D", "4H", "5C",
             "5S", "5D", "5H", "6C", "6S", "6D", "6H", "7C", "7S", "7D", "7H", "8C", "8S", "8D", "8H", "9C", "9S",
             "9D", "9H", "10C", "10S", "10D", "10H", "JC", "JS", "JD", "JH", "QC", "QS", "QD", "QH", "KC", "KS", "KD",
             "KH"] # list of all cards in a deck. c = clubs, s = spades, d = diamonds, h = hearts
    used_cards = [] # list to check that no card is ever used twice.
    rn = randint(0, 51) # method of picking a random card
    used_cards.append(rn) # adds picked card to list of used cards
    rn2 = randint(0, 51)
    while rn2 in used_cards: #  checks if card has been used, and if so changes value
        rn2 = randint(0, 51)
    used_cards.append(rn2)
    rn3 = randint(0, 51)
    while rn3 in used_cards:
        rn3 = randint(0, 51)
    used_cards.append(rn3)
    rn4 = randint(0, 51)
    while rn4 in used_cards:
        rn4 = randint(0, 51)
    used_cards.append(rn4)
    rn5 = randint(0, 51)
    while rn5 in used_cards:
        rn5 = randint(0, 51)
    used_cards.append(rn5)
    return cards[rn], cards[rn2], cards[rn3], cards[rn4], cards[rn5]


def test_make_hand():
    num = 50
    while num > 0:
        assert make_hand()[0] != make_hand()[1] != make_hand()[2] != make_hand()[3] != make_hand()[4]
        num -= 1
    return True

EDIT: after all the feed back from you guys it's much prettier and more functional now!

from random import *

cards = ["AC", "AS", "AD", "AH", "2C", "2S", "2D", "2H", "3C", "3S",      "3D", "3H", "4C", "4S", "4D", "4H", "5C",
             "5S", "5D", "5H", "6C", "6S", "6D", "6H", "7C", "7S", "7D", "7H", "8C", "8S", "8D", "8H", "9C", "9S",
             "9D", "9H", "10C", "10S", "10D", "10H", "JC", "JS", "JD", "JH", "QC", "QS", "QD", "QH", "KC", "KS", "KD",
             "KH"] # list of all cards in a deck. c = clubs, s = spades, d = diamonds, h = hearts


def make_hand(num):
    while num > 0:
        shuffle(cards)
        hand = [cards[x] for x in range(5)]
        for x in hand:
            if x in cards:
                cards.remove(x)
        print(len(cards))
        print(hand)
        num -= 1
vinnie
  • 93
  • 1
  • 1
  • 4
  • Shuffle your array of cards first, then take first N elements – Ja͢ck Apr 02 '15 at 22:46
  • There's no need to do the [Solved] thing, remember that SO is not a forum. It would be better to upvote, comment on, and/accept an answer (if it helped you) instead. Or you can post your own answer if you found a solution different from the ones already posted. – Paul Richter Apr 03 '15 at 00:08

5 Answers5

2
assert make_hand()[0] != make_hand()[1] != make_hand()[2] != make_hand()[3] != make_hand()[4]

It looks like you're generating 5 different hands rather than just generating a single hand and comparing the cards within it. There is no guarantee that on 5 different calls to this make_hand method that each hand has fully unique cards. It looks like there's only a guarantee that cards within a single hand will be random.

If you want every hand to have unique cards, you would need to move the cards and used_cards array out into global scope.

Edit: I might also suggest a more efficient approach, in that you simply shuffle the array, and pull off the top 5 cards of that shuffled array to make your randomized hand. Take a look here for more details on that approach.

Shuffling a list of objects in python

Community
  • 1
  • 1
Morgan
  • 1,765
  • 2
  • 19
  • 26
1

Every instance of make_hand() in your assert calls make_hand a new time. Remember, every single time you write somefunction() your function is invoked anew.

Instead, store the return value of the function in a tuple so it can be retrieved, like so:

def test_make_hand():
    num = 50
    while num > 0:
        hand = make_hand()
        assert hand[0]!=hand[1]!=hand[2]!=hand[3]!=hand[4]
        num-=1
    return True

On a totally unrelated note, I would strongly suggest you improve code reuse in your make_hand function by using a loop.

Nick Bailey
  • 3,078
  • 2
  • 11
  • 13
1

I'm not versed in python, so I can't write the code, but it would be much more efficient to just remove the card from the deck array after it's been used. That way you won't need to keep track of used cards or check for them to draw a new one.

Also, your assertion test is flawed. make_hand() creates a completely new hand every time, with a new deck of cards. Comparing those values is meaningless.

Along the same line... If you are trying to make several hands from the same deck, you will need to track the cards in the deck outside of the make_hand() method.

posit labs
  • 8,951
  • 4
  • 36
  • 66
1

Besides the issue of generating several hands, you should take a look at the random.sample function:

import random
def make_hand():
    cards = ["AC", "AS", "AD", "AH", "2C", "2S", "2D", "2H", "3C", "3S", "3D", "3H", "4C", "4S", "4D", "4H", "5C",
             "5S", "5D", "5H", "6C", "6S", "6D", "6H", "7C", "7S", "7D", "7H", "8C", "8S", "8D", "8H", "9C", "9S",
             "9D", "9H", "10C", "10S", "10D", "10H", "JC", "JS", "JD", "JH", "QC", "QS", "QD", "QH", "KC", "KS", "KD",
             "KH"] # list of all cards in a deck. c = clubs, s = spades, d = diamonds, h = hearts
    return random.sample(cards, 5)
Francis Colas
  • 3,459
  • 2
  • 26
  • 31
0

Since your picking cards from a deck of cards I would change your approce by moveing your cards from your cards array to a hand list, then you will know wich cards have been used(same as the cards hand)

from random import *
cards = ["AC", "AS", "AD", "AH", "2C", "2S", "2D", "2H", "3C", "3S","3D","3H", "4C", "4S", "4D", "4H", "5C","5S", "5D", "5H", "6C", "6S", "6D","6H", "7C", "7S", "7D", "7H", "8C", "8S", "8D", "8H", "9C", "9S","9D", "9H", "10C", "10S", "10D", "10H", "JC", "JS", "JD", "JH", "QC", "QS", "QD", "QH", "KC", "KS", "KD","KH"]
def make_hand():
    hand = [] # list of picked cards
    for i in range(0,4) #picks 5 cards
        hand.append(cards.pop(randint(0, len(cards)-1)))
    return hand

In this for loop that is run 5 times(0 to 4) we choose a random integer from 0 to the size of the cards list -1. This is since len returns the size of cards(1 indexed) and we are using it as an list index(0-indexed. We then use pop on that random chosen index, which removes the item in the list and returns it, so then we add that returned item in the hand.

Bjerke
  • 156
  • 2
  • 11