13 Replies - 768 Views - Last Post: 01 January 2015 - 07:16 PM Rate Topic: -----

#1 The Chief  Icon User is offline

  • D.I.C Head

Reputation: 4
  • View blog
  • Posts: 123
  • Joined: 12-November 14

Quicker way than lots of if statements?

Posted 26 December 2014 - 09:48 AM

I am writing a little program that selects a card at random based on a 52 deck and I want to count the number of times each type of card is pulled.

import random

count = 0
aceOfDiamonds = 0
kingOfDiamonds = 0
queenOfDiamonds = 0
jackOfDiamonds = 0
tenOfDiamonds = 0
nineOfDiamonds = 0
eightOfDiamonds = 0
sevenOfDiamonds = 0
sixOfDiamonds = 0
fiveOfDiamonds = 0
fourOfDiamonds = 0
threeOfDiamonds = 0
twoOfDiamonds = 0
card = ['Ace','King','Queen','Jack','Ten','Nine','Eight',
        'Seven','Six','Five','Four','Three','Two']
face = ['Hearts','Spades','Clubs','Diamonds']

while count < 1000000:
    rCard = random.choice(card)
    rFace = random.choice(face)
    if(rCard == 'Ace' and rFace == 'Diamonds'):
        aceOfDiamonds+=1
    elif(rCard == 'King' and rFace == 'Diamonds'):
        kingOfDiamonds+=1
    elif(rCard == 'Queen' and rFace == 'Diamonds'):
        queenOfDiamonds+=1
    elif(rCard == 'Jack' and rFace == 'Diamonds'):
        jackOfDiamonds+=1
    elif(rCard == 'Ten' and rFace == 'Diamonds'):
        tenOfDiamonds+=1
    elif(rCard == 'Nine' and rFace == 'Diamonds'):
        nineOfDiamonds+=1
    elif(rCard == 'Eight' and rFace == 'Diamonds'):
        eightOfDiamonds+=1
    elif(rCard == 'Seven' and rFace == 'Diamonds'):
        sevenOfDiamonds+=1
    elif(rCard == 'Six' and rFace == 'Diamonds'):
        sixOfDiamonds+=1
    elif(rCard == 'Five' and rFace == 'Diamonds'):
        fiveOfDiamonds+=1
    elif(rCard == 'Four' and rFace == 'Diamonds'):
        fourOfDiamonds+=1
    elif(rCard == 'Three' and rFace == 'Diamonds'):
        threeOfDiamonds+=1
    elif(rCard == 'Two' and rFace == 'Diamonds'):
        twoOfDiamonds+=1
    count+=1
print("Ace of Diamonds appeared",aceOfDiamonds,"times")
print("King of Diamonds appeared",kingOfDiamonds,"times")
print("Queen of Diamonds appeared",queenOfDiamonds,"times")
print("Jack of Diamonds appeared",jackOfDiamonds,"times")
print("Ten of Diamonds appeared",tenOfDiamonds,"times")
print("Nine of Diamonds appeared",nineOfDiamonds,"times")
print("Eight of Diamonds appeared",eightOfDiamonds,"times")
print("Seven of Diamonds appeared",sevenOfDiamonds,"times")
print("Six of Diamonds appeared",sixOfDiamonds,"times")
print("Five of Diamonds appeared",fiveOfDiamonds,"times")
print("Four of Diamonds appeared",fourOfDiamonds,"times")
print("Three of Diamonds appeared",threeOfDiamonds,"times")
print("Two of Diamonds appeared",twoOfDiamonds,"times")



I've tested this and so far it seems random enough, on a 1million run the each type of ace appears about 15 - 20 times. As you can clearly see though this method is utterly ridiculous and I'm embarrassed to even post it here but was wondering if someone could show me a nice way to tie this together.

Once I include the other 3 faces the program is going to be massive. I've not yet been taught anything like this and I simply expanded on a smaller exercise. Would be nice if I could get the full program going without 50 if statements though.

Thanks

Is This A Good Question/Topic? 0
  • +

Replies To: Quicker way than lots of if statements?

#2 jon.kiparsky  Icon User is online

  • Chinga la migra
  • member icon


Reputation: 10681
  • View blog
  • Posts: 18,293
  • Joined: 19-March 11

Re: Quicker way than lots of if statements?

Posted 26 December 2014 - 10:01 AM

First of all, you want to get away from having a separate variable for each card. What you're dealing with here is a deck of cards, not this card and that card and, hey, here's another card, and so forth. If there's a collective noun for a thing, if the thing can be conceived of as a group, it's probably a collection of some sort, and thinking of it that way will probably make your program work better.

So if you think of a deck as a list of 52, then you can think of the card's value as ranging from 0..12, and its suit ranging from 0..3. Let's say aces are counted low (ace=0, king=12) and suits run heart, spade, club, diamond. This is completely arbitrary, just for concreteness. Now we can say that the ace of hearts is deck[0], and the ace of spades is deck[13] - it always seemed like a bad luck card to me - and in general for a card whose index is i card's value is given as i % 13 and suit is i /13, and the card's index i = suit * 13 + value. So for example the seven of diamonds is indexed as 3 * 13 + 7 = 39 +7 = 46. Checking, we get 46 /13 = 3, 46 % 13 = 7, so it works.

Okay, now it's possible to answer your question in a reasonable way - but maybe you can already see where this goes? See if this answers your question, if not I'll write some more.
Was This Post Helpful? 1
  • +
  • -

#3 The Chief  Icon User is offline

  • D.I.C Head

Reputation: 4
  • View blog
  • Posts: 123
  • Joined: 12-November 14

Re: Quicker way than lots of if statements?

Posted 26 December 2014 - 10:06 AM

Thanks, I'll have a go at re-writing the program with your advice, I think I know how to do it although I still don't see a way around the if statements as I need to perform a check on each card.

if it's x count+=1
if it's y count+=1

etc?
Was This Post Helpful? 0
  • +
  • -

#4 jon.kiparsky  Icon User is online

  • Chinga la migra
  • member icon


Reputation: 10681
  • View blog
  • Posts: 18,293
  • Joined: 19-March 11

Re: Quicker way than lots of if statements?

Posted 26 December 2014 - 10:14 AM

Since it's going into an array, you can just do

deck[index] +=1


Was This Post Helpful? 1
  • +
  • -

#5 The Chief  Icon User is offline

  • D.I.C Head

Reputation: 4
  • View blog
  • Posts: 123
  • Joined: 12-November 14

Re: Quicker way than lots of if statements?

Posted 28 December 2014 - 09:05 AM

I've been trying to have a go at doing this but I'm totally lost. Could you give me a little more on what to do?

So I'm keeping this the same

import random
count = 0
rCard = 0
rFace = 0

card = ['Ace','King','Queen','Jack','Ten','Nine','Eight',
        'Seven','Six','Five','Four','Three','Two']
face = ['Hearts','Spades','Clubs','Diamonds']




but then adding something like

while count < 1000000:
    for i in range(0,12)[card]:
        for j in range(0,3)[face]:
            rCard[i]+=1
            rFace[j]+=1
            count+=1
print(rCard[i],"of",rFace[j], "appeared",count,"times")



but quite frankly I don't even know the syntax so can you point me in the right direction? Thanks
Was This Post Helpful? 0
  • +
  • -

#6 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 6979
  • View blog
  • Posts: 14,600
  • Joined: 16-October 07

Re: Quicker way than lots of if statements?

Posted 28 December 2014 - 09:28 AM

What the hell is up with those for loops?

As you are clearly totally lost, maybe this will get your started:
>>> import random
>>> # create an list of counts for all 52 of our cards
... counts = [ 0 for x in range(52) ]
>>> counts
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> # loop for sample size, say 10000
>>> for x in range(10000): 
...     # use random.randint to pick a value from 0..51
...     # increment count in that position by 1
...     counts[random.randint(0,51)] += 1
... 
>>> counts
[195, 186, 219, 208, 210, 193, 200, 161, 233, 190, 203, 185, 232, 202, 200, 213, 199, 194, 159, 216, 164, 192, 188, 186, 202, 208, 193, 178, 181, 189, 225, 178, 181, 178, 195, 171, 192, 181, 194, 190, 179, 165, 177, 187, 205, 179, 191, 202, 190, 191, 178, 192]
>>> # There, now you have a random distribution across all 52 cards
... # pick this positions you wish to show
... # you'll want a function
... def getCardName(n): # where n is 0..51



Hope this helps.
Was This Post Helpful? 1
  • +
  • -

#7 The Chief  Icon User is offline

  • D.I.C Head

Reputation: 4
  • View blog
  • Posts: 123
  • Joined: 12-November 14

Re: Quicker way than lots of if statements?

Posted 28 December 2014 - 09:32 AM

I'll come back to this a little in a few days when I progress a little more. I think it's a bit out of my depth. I'll post my attempt then
Was This Post Helpful? 0
  • +
  • -

#8 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 6979
  • View blog
  • Posts: 14,600
  • Joined: 16-October 07

Re: Quicker way than lots of if statements?

Posted 29 December 2014 - 06:29 AM

Ok, a quick basic example:
>>> # filling a list with zeros 
...
>>> [ 0 for x in range(2) ]
[0, 0]
>>> [ 0 ] * 2 # this is a wonky kind of syntax, but good to know
[0, 0]
>>> xs = [ 0 ] * 2 # so
>>> xs
[0, 0]
>>> # now, let's make a function
... 
>>> import random
>>> def toss():
...     result = random.randint(0,1)
...     print result
...     return result
... 
>>> xs[toss()] += 1
1
>>> xs[toss()] += 1
0
>>> xs[toss()] += 1
1
>>> xs
[1, 2]
>>> # see we've tallied those three tosses?
>>> # time for some more, so I'll take the print out of toss
>>> def toss(): return random.randint(0,1)
... 
>>> for x in range(97):
...     xs[toss()] += 1
... 
>>> xs
[59, 41]
>>> # want some user feedback?  How about another list?
... names = ['heads','tails']
... for i in range(len(names)):
...     print i, ": You tossed", xs[i], names[i]
... 
0 : You tossed 59 heads
1 : You tossed 41 tails
>>> 



There are 52 unique cards in a deck, so you essentially do the same thing, translating card numbers to names. Note that if your random is functioning optimally, the distribution converges on equality. This becomes clear the more trails you do.

e.g.
>>> for x in range(1000000):
...     xs[toss()] += 1
... 
>>> xs
[500308, 499792]
>>> 



Hope this helps.
Was This Post Helpful? 0
  • +
  • -

#9 CurlyJoe  Icon User is offline

  • D.I.C Head

Reputation: 22
  • View blog
  • Posts: 95
  • Joined: 19-September 13

Re: Quicker way than lots of if statements?

Posted 29 December 2014 - 06:21 PM

When a program contains many if statements, they can usually be replace with a dictionary.
import random
import pprint

card = ['Ace','King','Queen','Jack','Ten','Nine','Eight',
        'Seven','Six','Five','Four','Three','Two']
face = ['Hearts','Spades','Clubs','Diamonds']
 
cards_dict = {}
for count in range(1000):
    rCard = random.choice(card)
    rFace = random.choice(face)
    key = rCard+rFace
    if key in cards_dict:
        cards_dict[key] += 1
    else:
        cards_dict[key] = 1
pprint.pprint(cards_dict) 

Was This Post Helpful? 0
  • +
  • -

#10 jon.kiparsky  Icon User is online

  • Chinga la migra
  • member icon


Reputation: 10681
  • View blog
  • Posts: 18,293
  • Joined: 19-March 11

Re: Quicker way than lots of if statements?

Posted 29 December 2014 - 08:23 PM

Yes, you can do that, but what is the advantage of using 'TwoHearts' as a key, rather than a simple integer index? I don't see what this buys you over using a simple list.
Was This Post Helpful? 0
  • +
  • -

#11 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 6979
  • View blog
  • Posts: 14,600
  • Joined: 16-October 07

Re: Quicker way than lots of if statements?

Posted 30 December 2014 - 05:35 AM

I didn't want to do this, but given the dictionary solution...

Ok, you have two sets, face and suit. You essentially want all combinations of those sets, face * suit. You'll often see a nested loop for this, two values stored, etc. However, you really only need a single value to represent each combination. Think of it like this:
0 Ace of Hearts
...
12 Two of Hearts
13 Ace of Spades
25 Two of Spades
26 Ace of Clubs



So, we start with Hearts, count to the number of faces(13), then start over with the next suit. Same as above with more data.
   n % 13  n // 13
 n face    suit     name
 0    0       0     Ace of Hearts
12   12       0     Two of Hearts
13    0       1     Ace of Spades
14    1       1     King of Spades
25   12       1     Two of Spades
26    0       2     Ace of Clubs



Now, with some code:
face = ['Ace','King','Queen','Jack','Ten','Nine','Eight',
        'Seven','Six','Five','Four','Three','Two']
suit = ['Hearts','Spades','Clubs','Diamonds']

faceCount = len(face)
cardsCount = len(suit) * faceCount # all possible combinations

# show all cards
for i in range(cardsCount):
    # note, we break our single int up into two ints, face and suit
    faceNum, suitNum = (i % faceCount), (i // faceCount)
    # with that, we compose a name
    cardName = face[faceNum] + " of " + suit[suitNum]
    # print count with cardName
    print i, faceNum, suitNum, cardName



The counting solution is actually just three mores lines. You should be able to worry it out from what's already been given.
Was This Post Helpful? 0
  • +
  • -

#12 CurlyJoe  Icon User is offline

  • D.I.C Head

Reputation: 22
  • View blog
  • Posts: 95
  • Joined: 19-September 13

Re: Quicker way than lots of if statements?

Posted 30 December 2014 - 11:11 AM

View Postjon.kiparsky, on 29 December 2014 - 08:23 PM, said:

Yes, you can do that, but what is the advantage of using 'TwoHearts' as a key, rather than a simple integer index? I don't see what this buys you over using a simple list.

No one here said anything about a dictionary buying you anything over a simple list so perhaps you are arguing with someone in a different thread and posted here by mistake. The first sentence of the above post says

Quote

When a program contains many if statements, they can usually be replaced with a dictionary
and an example was given to show one way of doing that.
Was This Post Helpful? 0
  • +
  • -

#13 jon.kiparsky  Icon User is online

  • Chinga la migra
  • member icon


Reputation: 10681
  • View blog
  • Posts: 18,293
  • Joined: 19-March 11

Re: Quicker way than lots of if statements?

Posted 30 December 2014 - 12:06 PM

View PostCurlyJoe, on 30 December 2014 - 01:11 PM, said:

]No one here said anything about a dictionary buying you anything over a simple list so perhaps you are arguing with someone in a different thread and posted here by mistake.


I'm not arguing with anyone, I'm just curious about what the advantages of this method might be over the simpler method already described. I agree with you that dictionaries are often a good way to get around complicated hard-coded decision logic, but in this case you're constructing a compound key which is hard to parse efficiently, in comparison to an integer-indexed representation, which converts trivially to and from the human-readable Value-Suit naming system. If you're going to use value and suit names in your underlying representation, it would seem more effective, to me, to do it in terms of a Card class. There might be some advantages to that. I just don't see the advantage of a dict with a constructed key as you describe, and I'm curious if there are any.
Was This Post Helpful? 0
  • +
  • -

#14 pythonuser007  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 51
  • Joined: 25-January 14

Re: Quicker way than lots of if statements?

Posted 01 January 2015 - 07:16 PM

You may want to look at this.

from random import randint
from random import shuffle

suits = ['Hearts','Diamonds','Spades','Clubs']
face = ['2','3','4','5','6','7','8','9','10','Jack','Queen','King','Ace']

def make_deck():
    deck = []
    for item in range(0,4):
        for value in range(0,13):
            deck.append([value, item, 0])
    return deck



def get_random_card(deck):
    card = randint(0, 51)
    return card

def shuffle_deck(deck):
    shuffle(deck)
    shuffle(deck)
    shuffle(deck)
    return deck


def print_card(card):
    string = face[card[0]] + " of " + suits[card[1]]
    return string

def tally_randomly_chosen_card(card, tally):
    tally[card][2] += 1
    return tally


tally = make_deck()
cards = make_deck()
shuffle(cards)

times = int(raw_input("Enter how many times you want to pick a random card: "))
for x in range(0, times):
    card = get_random_card(cards)
    tally = tally_randomly_chosen_card(card, tally)

for card in tally:
    part = print_card(card)
    print "\t",part," was selected ",card[2]," times."



Was This Post Helpful? 0
  • +
  • -

Page 1 of 1