Python Forum
I am getting an incorrect average, and not sure why? What's wrong with my code?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
I am getting an incorrect average, and not sure why? What's wrong with my code?
#1
The question asks to Write a program called test4.py that plays the following card game:

The game starts with certain initial amount of dollars.

At each round of the game, instead of flipping a coin, the player shuffles a deck and draws 6 cards. If the drawn hand contains at least one ace, the player gains a dollar, otherwise they lose a dollar.

The game runs until the player either runs out of money or doubles their initial amount.

To test the game, given the initial amount, run it 1000 times to determine how many rounds does the game last on average.

Provide a user with an interface to enter the initial bankroll. For each entered number, the program should respond with the average duration of the game for that initial bankroll.

If code is correct it should run the program:

Output:
Enter initial amount: 10 Average number of rounds: 46.582 Enter initial amount: 20 Average number of rounds: 97.506 Enter initial amount: 30 Average number of rounds: 148.09 Enter initial amount: 40 Average number of rounds: 194.648 Enter initial amount: 50 Average number of rounds: 245.692 Enter initial amount: 60 Average number of rounds: 290.576 Enter initial amount: 70 Average number of rounds: 335.528 Enter initial amount: 80 Average number of rounds: 391.966 Enter initial amount: 90 Average number of rounds: 433.812 Enter initial amount: 100 Average number of rounds: 487.258
This is my code (but the numbers are incorrect(average):

import random


faceValues = ['ace', '2', '3', '4', '5', '6',
              '7', '8', '9', '10', 'jack',
              'queen', 'king']

suits = ['clubs', 'diamonds', 'hearts',
         'spades']


import random

def shuffledDeck():
    deck = []
    for faceValue in faceValues:
        for suit in suits:
            deck.append(faceValue + ' of ' + suit)
    random.shuffle(deck)
    return deck

def faceValueOf(card):
    return card.split()[0]

def suitOf(card):
    return card.split()[2]


import random

def oneGame(initial):
  countFlips = 0
  bankroll = initial
  while 0 < bankroll < 2*initial:
    
    d=shuffledDeck()
    numberOfAces=0
    for number in range(6):
        countFlips+=1
        for currentHand in d:
            if faceValueOf(currentHand)=='ace':
              bankroll +=1
            else:
              bankroll -= 1
  return countFlips 
                
                 
                  
                       


def experiment(initials, repetitions):
  for initial in initials:
    print('Enter Initial bankroll:', initial)
    totalFlips = 0
    for number in range(repetitions):
      totalFlips += oneGame(initial)
    print('Average number of rounds:', totalFlips/repetitions)
    print()
experiment([10,20,30,40,50,60,70,80,90,100],1000)
Reply
#2
This is my code:
import random


faceValues = ['ace', '2', '3', '4', '5', '6',
'7', '8', '9', '10', 'jack',
'queen', 'king']

suits = ['clubs', 'diamonds', 'hearts',
'spades']


import random

def shuffledDeck():
deck = []
for faceValue in faceValues:
for suit in suits:
deck.append(faceValue + ' of ' + suit)
random.shuffle(deck)
return deck

def faceValueOf(card):
return card.split()[0]

def suitOf(card):
return card.split()[2]


import random

def oneGame(initial):
countFlips = 0
bankroll = initial
while 0 < bankroll < 2*initial:

d=shuffledDeck()
numberOfAces=0
for number in range(6):
countFlips+=1
for currentHand in d:
if faceValueOf(currentHand)=='ace':
bankroll +=1
else:
bankroll -= 1
return countFlips




def experiment(initials, repetitions):
for initial in initials:
print('Enter Initial bankroll:', initial)
totalFlips = 0
for number in range(repetitions):
totalFlips += oneGame(initial)
print('Average number of rounds:', totalFlips/repetitions)
print()
experiment([10,20,30,40,50,60,70,80,90,100],1000)

The error is that it is not giving me the correct average number :(
If written correctly It should run:

Enter initial amount: 10
Average number of rounds: 46.582
Enter initial amount: 20
Average number of rounds: 97.506
Enter initial amount: 30
Average number of rounds: 148.09
Enter initial amount: 40
Average number of rounds: 194.648
Enter initial amount: 50
Average number of rounds: 245.692
Enter initial amount: 60
Average number of rounds: 290.576
Enter initial amount: 70
Average number of rounds: 335.528
Enter initial amount: 80
Average number of rounds: 391.966
Enter initial amount: 90
Average number of rounds: 433.812
Enter initial amount: 100
Average number of rounds: 487.258

The assignment was to Write a program called test4.py that plays the following card game:
The game starts with certain initial amount of dollars.
At each round of the game, instead of flipping a coin, the player shuffles a deck and draws 6 cards. If the drawn hand contains at least one ace, the player gains a dollar, otherwise they lose a dollar.
The game runs until the player either runs out of money or doubles their initial amount.
To test the game, given the initial amount, run it 1000 times to determine how many rounds does the game last on average.
Provide a user with an interface to enter the initial bankroll. For each entered number, the program should respond with the average duration of the game for that initial bankroll.
Reply
#3
You have an error in oneGame. The rules are supposed to be that you win 1 if your hand contains an ace, otherwise you lose 1. Your logic is, well it is hard to say exactly what your logic is doing, but you never win, you lose very quickly, and you count to 6 instead of counting how long it takes to win or lose. This part is the problem. I think you were planning on counting aces, but that idea got lost somewhere.
        numberOfAces=0
        for number in range(6):
            countFlips+=1
            for currentHand in d:
                if d == 1:
                    bankroll +=1
                else:
                    bankroll -= 1
Are you required to make a regular deck of cards? To learn the statistics of the game it would easier and faster if you design the deck to fit the experiment. The code below makes it easy to count aces by assigning aces a value of 1 and all other cards a value of 0. If the sum of a hand > 0 you know you have an ace.
deck = [1,0,0,0,0,0,0,0,0,0,0,0,0]*4

def hand():
    if sum(random.sample(deck, k=6)) > 0:
        return 1;
    return -1

def game(start):
    count = 0
    bank = start
    while 0 < bank < start * 2:
        bank += hand()
        count += 1
    return count;
If you want to stay with using a deck with Aces and Queens you can still speed things up asking if 'Ace' is
Reply
#4
Don't double post.
Reply
#5
(Nov-18-2020, 05:45 AM)deanhystad Wrote: Don't double post.

Sorry I didn't mean to. It was my first time on the website and I got confused. I was even confused about how to post a thread.
Okay this is my code(idk how to set it up on the thread the way you did (I'm sorry :( ). Below my code is instructions to fix my code provided from my professor. Can you help me fix the code per his instruction? copy/paste, fix the send to me bc I'm still new and I get lost going through line to fix. Thankk you in advance!!!!

import random


faceValues = ['ace', '2', '3', '4', '5', '6',
'7', '8', '9', '10', 'jack',
'queen', 'king']

suits = ['clubs', 'diamonds', 'hearts',
'spades']


import random

def shuffledDeck():
deck = []
for faceValue in faceValues:
for suit in suits:
deck.append(faceValue + ' of ' + suit)
random.shuffle(deck)
return deck

def faceValueOf(card):
return card.split()[0]

def suitOf(card):
return card.split()[2]



import random
def oneGame(initial):
countFlips = 0
bankroll = initial
while 0 < bankroll < 2*initial:
start=0
d=shuffledDeck()
for number in range(6):
countFlips+=1
for currentHand in d:
if faceValueOf(currentHand)=='ace':
start += 1
if start >= 1:
bankroll += 1
else:
bankroll -= 1
return countFlips

def experiment(initials, repetitions):
for initial in initials:
print('Enter Initial bankroll:', initial)
totalFlips = 0
for number in range(repetitions):
totalFlips += oneGame(initial)
print('Average number of rounds:', totalFlips/repetitions)
print()
experiment([10, 20, 30,40,50,60,70,80,90,100], 1000)


Professor instruction :

The last line of your program automatically uses the initial amounts shown in the test instructions. However, that's not what the test instructions say to do, which is to provide a user with an interface to enter the initial bankroll. To fix this, you will need to replace that line with a loop that repeatedly prompts the user for the initial bankroll and then passes it to the experiment function. (You can then remove line 50 since it won't be needed.)
- The purpose of countFlips is to keep track of each time your program draws a hand. However, since line 38 is inside the for loop on the line above it, it increases countFlips 6 times instead of just once. You can fix this by moving that line outside (before or after) that loop.
- Line 39 goes through all 52 cards in the deck, which is not correct. To fix, you can replace that line with currentHand = d[number], which makes your program draw a card (make sure it is indented so that it is inside the for loop on line 37).
Reply
#6
Please wrap code in Python tags so it retains proper indentation.

This code plays the card game and calculates the average number of hands for any starting bank.
import random

deck = 'A234567890JQK'*4

def play(start, hand=6, replay=1):
    count = 0
    for _ in range(replay):
        bank = start
        while 0 < bank < start*2:
            if 'A' in random.sample(deck, hand):
                bank += 1
            else:
                bank -= 1
            count += 1
    return count

while True:
    start = int(input('Enter inital amount: '))
    print('Average number of rounds:', play(start, replay=1000)/1000)
This is my deck of cards
deck = 'A234567890JQK'*4
I also made a version where this was my deck of cards
deck = '[1,0,0,0,0,0,0,0,0,0,0,0,0]'*4
Either work fine. The important thing is to have something that accurately represents the attributes that are important for the purpose of this experiment. The deck should have 4 aces and 48 other cards. The aces can be a 1 and other cards 0, or the aces can be A and the other cards not A. There is no reason to make the deck any fancier than it has to be for the purposes of the experiment.

This is a hand.
if 'A' in random.sample(deck, hand):
    bank += 1
else:
    bank -= 1
There is no reason to count how many aces appear in the hand. The rules of the game are you get paid $1 if there are any aces and you lose $1 if there are no aces. When I used 0's and 1's I used the sum() function to determine if there are any aces. With the letters I look for the letter 'A'. This code is sufficient for playing a single hand, and there is no reason to make the code more complicated than it has to be.

This is a game.
bank = start
while 0 < bank < start*2:
    if 'A' in random.sample(deck, hand):
        bank += 1
    else:
        bank -= 1
    count += 1
The rules of the game say you continue to play hands until you either lose all your money or you double your money. It doesn't matter if you win or loose. The important part here is keeping track of how many hands it takes to win or lose.

For my purposes I don't want to play a single game. I want to play 1000 games. I could write a function to play a hand, and a function to play a game, and a function to calculate the average of 1000 games, but the more functions I use the slower the code. To allow for playing more than one game I wrapped the game inside a loop.
def play(start, hand=6, replay=1):
    count = 0
    for _ in range(replay):
        bank = start
        while 0 < bank < start*2:
            if 'A' in random.sample(deck, hand):
                bank += 1
            else:
                bank -= 1
            count += 1
    return count
And finally, this code lets me enter the starting bank and prints the average number of hands.
while True:
    start = int(input('Enter inital amount: '))
    print('Average number of rounds:', play(start, replay=1000)/1000)
The program will calculate averages for as long as I input integer strings. To quit I can type Ctrl+c or just enter without a number.
Reply
#7
The avg number is a bit off still so. This is an example of the running code.

Example of running the program:
Enter initial amount: 10
Average number of rounds: 46.582

Enter initial amount: 20
Average number of rounds: 97.506

Enter initial amount: 30
Average number of rounds: 148.09

Enter initial amount: 40
Average number of rounds: 194.648

Enter initial amount: 50
Average number of rounds: 245.692

Enter initial amount: 60
Average number of rounds: 290.576

Enter initial amount: 70
Average number of rounds: 335.528

Enter initial amount: 80
Average number of rounds: 391.966

Enter initial amount: 90
Average number of rounds: 433.812

Enter initial amount: 100
Average number of rounds: 487.258


Write a program called test4.py that plays the following card game:

The game starts with certain initial amount of dollars.

At each round of the game, instead of flipping a coin, the player shuffles a deck and draws 6 cards. If the drawn hand contains at least one ace, the player gains a dollar, otherwise they lose a dollar.

The game runs until the player either runs out of money or doubles their initial amount.

To test the game, given the initial amount, run it 1000 times to determine how many rounds does the game last on average.

Provide a user with an interface to enter the initial bankroll. For each entered number, the program should respond with the average duration of the game for that initial bankroll.
Reply
#8
Your big error is in oneGame()
def oneGame(initial):
    countFlips = 0
    bankroll = initial
    while 0 < bankroll < 2*initial:
        # This is where you error was.  You did multiple
        # adds and subtracts for each hand.  There should
        # only be 1 ad or subtract
        for card in shuffledDeck[0:6]:  # Look at top six cards
            if 'ace' in card:
                bankroll += 1
                break # Stop after find first ace
        else: 
            bankroll -= 1 # Only do this if for loop completes              
        countFlips += 1
    return countFlips
Your code added a dollar for each ace and subtracted a dollar for each non-ace. If you drew 4 aces you would add $2, but if you drew no aces you lost $6. In the code above we break out of the for loop after finding the first ace. The "else" statement is only executed when there are no aces in the hand.

The for/else is a bit confusing. I don't think any other programming language has this logic construct. You might find the code easier to understand if the "hand" logic is broken out into it's own function.
def hand():
    for card in shuffledDeck[0:6]:  # Look at top 6 cards
        if 'ace' in card:
            return 1  # Return 1 if we find an ace
    return -1  # Return -1 if no ace found          

def oneGame(initial):
    countFlips = 0
    bankroll = initial
    while 0 < bankroll < 2*initial:
        bankroll += hand()
        countFlips += 1
    return countFlips
Reply
#9
I think the averages in your last post look fine. 1000 hands is a pretty small sample size for this game as the number of hands required to win or lose varies greatly. I modified my program slightly to collect the counts and do a little statistical analysis and plotting.
import random
import statistics
import collections
import matplotlib.pyplot as plt
 
deck = 'A234567890JQK'*4
hand = 6
 
def play(start):
    count = 0
    bank = start
    while 0 < bank < start*2:
        if 'A' in random.sample(deck, hand):
            bank += 1
        else:
            bank -= 1
        count += 1
    return count

while True:
    start = int(input('Enter inital amount: '))
    counts = [play(start) for _ in range(1000)]
    unique_counts = collections.Counter(counts)
    print('Mean =', statistics.mean(counts))
    print('Median =', statistics.median(counts))
    print('Number of different counts =', len(unique_counts))
    print('Count range =', min(counts), 'to', max(counts))
    mode = statistics.mode(counts)
    print('Mode =', mode, 'Count =', unique_counts[mode])
    print('Standard Deviation =', statistics.stdev(counts))
    plt.bar(unique_counts.keys(), unique_counts.values())
    plt.show()
Output:
Enter inital amount: 100 Mean = 484.818 Median = 474.0 Number of different counts = 222 Count range = 238 to 952 Mode = 454 Count = 15 Standard Deviation = 103.47417929987066 Enter inital amount: 100 Enter inital amount: 100 Mean = 492.046 Median = 480.0 Number of different counts = 227 Count range = 250 to 934 Mode = 466 Count = 15 Standard Deviation = 102.92227591186895
Running two tests the average count changed from 484 to 492. Such variation is not surprising when you see the number of hands required to win or lose a game ranges from the low 200's to over 1000 upon occasion. When I increased the sample size from 1000 to 10,000 I also noticed some interesting clumping in the plots. The kind of non-uniform distribution that raises hell with statistical analysis.

What I found really interesting is how bad this game is. You never win. I modified the code to count wins and losses and I never win. I guess this makes sense considering you only have a 38% chance of winning any given hand and you need to win a lot of hands to double your money. The odds are not in your favor.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  im not sure what ive done wrong code doesnt run dgizzly 3 1,378 Nov-16-2022, 03:02 AM
Last Post: deanhystad
  what is wrong with my code 53535 4 1,558 Apr-07-2022, 11:37 AM
Last Post: 53535
  What's wrong with my code? NeedHelpPython 4 2,233 Oct-22-2021, 07:59 PM
Last Post: Yoriz
  Help with my code due 11:59 pm, can you tell me where I went wrong and help fix it? shirleylam852 1 2,677 Dec-09-2020, 06:37 AM
Last Post: stranac
  Something is Wrong with my code susmith552 4 3,047 Nov-28-2019, 02:16 AM
Last Post: susmith552
  What is wrong with my code? Than999 1 2,388 Nov-10-2019, 08:59 PM
Last Post: ichabod801
  Wrong output on my code. JTNA 2 7,920 Apr-04-2019, 01:55 PM
Last Post: JTNA
  Return giving incorrect value Calingaladha 5 3,361 Oct-24-2018, 09:53 PM
Last Post: LeSchakal
  Why is this code wrong? Lemmy 4 5,185 Apr-05-2018, 03:46 PM
Last Post: Lemmy
  What's wrong with my code and visuals for python? beginnercoder04 2 2,825 Mar-17-2018, 01:06 AM
Last Post: beginnercoder04

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020