Calculating an average in "Rock, Paper, Scissors" - python

Last night I was thinking to my self about the probability of getting the same outcome in "Rock, Paper, Scissors" 10 times in a row. I worked out how to do that and completed that task but then I wanted to challenge myself a bit, so I wanted to adapt the program so it ran the initial program a number of times (10,000) and then outputted the average result, which I hoped would be close to the probability of getting the same 10 times in a row. Please note that I am not taking into account tactics, just that both players randomly pick either r, p, or s.
def rps():
num=0 # num is the number of times i want the programme to run while roll<10:
total=0 # this should be close to 3^10 * 10000, its the result of all the tries added together
while num <10001:
tries=0 # this is how many times the programme has tried to get p1=p2
roll=0 # this is the amount of times it has counted p1=p2 (it gets re-set everytime it reaches 10)
import random
while roll <10:
p1=random.randint(1,3)
p2=random.randint(1,3)
if p1==p2:
roll=roll+1
else:
tries=tries + 1
roll=0
num=num+1
if roll==10:
total=total+roll
roll=0
if num==10000:
print (num)
print (total/num)
rps()

There are quite a few problems with the program, for once, there isn't any use for the second for loop, I get that you are using the second for loop to reset the counter if the number of consecutive rolls reaches 10, but you are already doing that here
if roll==10:
total=total+roll
roll=0
by setting roll=0, you are resetting it.
also, the last if condition adds to the complexity,
if num==10000:
print (num)
print (total/num)
instead of this, you can just print the average outside the loop like this
if roll==10:
total=total+roll
roll=0
print (total/10000) #this being outside the while loop
one more thing, you are incrementing num only when roll1 != roll2, this adds to the number of times the loop has to run
This is how the program came out after the changes
import random
def rps():
num=0 #num is the number of times i want the programme to run while roll<10:
total=0 #this should be close to 3^10 * 10000, its the result of all the tries added together
roll = 0
while num <10001:
tries=0 #this is how many times the programme has tried to get p1=p2
p1=random.randint(1,3)
p2=random.randint(1,3)
if p1==p2:
roll = roll+1
else:
tries = tries + 1
roll = 0
if roll==10:
print(roll)
total += roll
roll=0
num = num + 1
print (total/10000)
print(tries)
rps()
The answer coming out was 0,I guess it was highly unlikely that you get 10 in a row.

Some self-explanatory code (so you can also learn to write clean code):
import random
def get_10_outcomes():
return [
(random.randint(1, 3), random.randint(1, 3))
]
def have_we_got_10_in_a_row():
return (
len(set(get_10_outcomes()))
== 1
)
def how_many_10_in_a_row_in_10000():
return len(list(filter(
None,
[have_we_got_10_in_a_row() for _ in range(10000)]
)))
def get_chance_of_10_in_a_row():
return how_many_10_in_a_row_in_10000() / 10000
chance = get_chance_of_10_in_a_row()
print('{:.3%}'.format(chance))

Related

Im a little stuck in a dice rolling program in python, am very new to python and very confused

This is what the instructions are telling me to do...
main – This function is the main routine. It should do the following:
Ask the user how many dice they want to roll. If the user enters a number less than 1 or greater than 10, the program should continue to ask the user for a valid number between 1 and 10. Remember you can use a while loop to do input validation.
Once the program has a valid number from the user, it should use that number as an argument when calling the roll_dice function.
roll_dice – This function has one parameter, num_dice, which is the number of dice to roll.
Since the program will be displaying the total of the dice, start by initializing a variable to 0 which will keep a running total.
Use a for loop to roll each die the number of times specified.
Use the randint function from the random module to get a random digit between 1 and 6 inclusive.
Print the number of the loop iteration and the die value as indicated in the Sample Output.
Make sure to update the running total INSIDE the for loop.
After the for loop is complete, print the total value of all the dice that were rolled.
And this is the code I have so far:
import random
def main():
num_dice = int(input('How many dice do you want to roll?'))
while num_dice < 1 or num_dice > 10:
print('Enter a number between 1 and 10.')
num_dice = (input('How many dice do you want to roll?'))
roll_dice(num_dice)
def roll_dice(num_dice):
rolls = 0
for i in range(num_dice):
print(f'Roll #', rolls, random.randint(1, 6))
rolls+=1
main()
There's a few improvements:
you typically don't want to repeat code, so it would be better to only have the input statement in there once (that would have also avoided the mistake you made on the second one);
you are asked to return a sum total of rolls, but also to print each roll; you can either compute it before printing, or print the assigned value directly (with a walrus operator :=)
once you have the total, you'll need to do something with it, like print it.
Something like:
import random
def main():
# you can loop 'forever' and then break out under the right condition
while True:
# you'd forgotten one of the int()
num_dice = int(input('How many dice do you want to roll?'))
if num_dice < 1 or num_dice > 10:
print('Enter a number between 1 and 10.')
else:
break
result = roll_dice(num_dice)
print(f'The total for {num_dice} rolls was {result}.')
def roll_dice(num_dice):
rolls = 0
for i in range(1, num_dice + 1):
# you printed rolls, but you want i, starting at 1
# roll := something, causes roll to be assigned, but also returns the value
print(f'Roll #{i} = {(roll := random.randint(1, 6))}')
rolls += roll
return rolls
main()
(Edit: I noticed that you were already using an f-string in roll_dice, so you may as well make actual use of it)
I like #Blckknght's suggestion for another nice use of the walrus operator in a shorter version of main():
def main():
# you can loop 'forever' and then break out under the right condition
while (n := int(input('How many dice do you want to roll?'))) < 1 or n > 10:
print('Enter a number between 1 and 10.')
result = roll_dice(n)
print(f'The total for {n} rolls was {result}.')
Beware though: if someone asks you to explain your code, you better know what's going on here:
due to short-circuit evaluation, the first part of the or in the while is executed first, and the second part is only executed if the first part is False; that's why you can use the := in the first part and know that num_dice will have been updated for the second part;
the walrus operator assigns the righthand value, but also returns it, so it can be compared to 1
def main():
num_dice = int(input('How many dice do you want to roll?'))
while num_dice < 1 or num_dice > 10:
print('Enter a number between 1 and 10.')
num_dice = (input('How many dice do you want to roll?'))
roll_dice(num_dice)
def roll_dice(num_dice):
rolls = 0
for i in range(num_dice):
print(f'Roll #', rolls, random.randint(1, 6))
out_ran_num = random.randint(1, 6)
rolls+=out_ran_num
return rolls
main()
Please check indentation
First, we want to keep asking the user how many dice they want to roll until they give a valid input, we can do that with a while loop like so:
valid_integer = False
# While the user hasn't given a valid integer
while valid_integer == False:
# Note: this will crash if the user does not input a number
num_dice = int(input('How many dice do you want to roll?'))
# Checking if the input is valid
if num_dice < 1 or num_dice > 10:
print("Please enter a number between 1 and 10")
# Because we did not change the variable valid_integer, it will loop again
else:
valid_integer = True
print(roll_dice(num_dice))
Now we need to create the roll_dice function, it needs to take one parameter (the number of dice to roll) and return a integer (the total of the dice rolls)
import random
# num_dice: int is known as type hinting, it is used to indicate the type of a value
def roll_dice(num_dice: int):
total = 0
for i in range(num_dice):
roll = random.randint(1, 6)
total += roll
return total
Now we can put the code together! We need to put the loop in a function main() and call it. Don't forget your imports!
import random
def main():
valid_integer = False
# While the user hasn't given a valid integer
while valid_integer == False:
# Note: this will crash if the user does not input a number
num_dice = int(input('How many dice do you want to roll?'))
# Checking if the input is valid
if num_dice < 1 or num_dice > 10:
print("Please enter a number between 1 and 10")
# Because we did not change the variable valid_integer, it will loop again
else:
valid_integer = True
print(roll_dice(num_dice))
# num_dice: int is known as type hinting, it is used to indicate the type of a value
def roll_dice(num_dice: int):
total = 0
for i in range(num_dice):
roll = random.randint(1, 6)
total += roll
return total
if __name__ == "__main__":
main()
more info on if __name__ == "__main__" What does if __name__ == "__main__": do?
In main function in while loop there should int for taking input and should use roll_dice function outside while loop. there should be return word to get total as shown in figure
In roll_dies function there should should be rolls+=random.randint(1,6) and also
return rolls outside for loop

How do I fix my (supposedly while-loop or if-statement) dice-simulator in Python so it prints the amount of tries its taken before landing on a 6?

So, I'm a little stuck on a coding assignment of mine – I'm supposed to write a code in Python simulating the throw of a dice, in which the program randomizes numbers between 1-6 until it "lands" on the number 6; the program is furthermore supposed to count the number of tries it has "thrown the dice" before "landing" on a 6, and print out print("It took", n, "tries to get a six.") in which n = the number of tries it has thrown the dice before landing on a 6.
This is what I've come up with thus far:
import random
dice = random.randint(1,6)
n = 0
while dice == 6:
n = n + 1
print("It took", n, "tries to get a 6.")
break
But, alas, it only prints out "It took 1 try to get a 6." in the result window and shows blank in the result window whenever the "dice" doesn't land on a 6. I guess what my question is, is: how do I get it to count all the tries before landing on a 6, and subsequently print the said amount of tries in combination with the statement print("It took", n, "amount of tries to get a 6.")?
The usual pattern for repeating an action an unknown number of times is to use a while True loop, and then break out of the loop when the exit condition is satisfied.
rolls = 0
while True:
die = random.randint(1, 6)
rolls += 1
if die == 6:
break
print("It took", rolls, "tries to get a 6.")
You need to write your break command into an if-statement.
In your current code it breaks within the first iteration.
As this is an assigment i dont want to tell you everything.
But that while loop condition won't get you there.
Try writing a blank while loop with a break-condition, think about it.

Calculating the number of rolls of a dice in python

So I'm a beginner programmer and I'm trying to calculate the number of rolls it would take for two dice to add up to the sum of 11. This is the code I tried, but every time I run this, it gives me the output 'None'. What am I doing wrong here?
from random import randint
def die_roll1():
return(randint(1, 6))
def die_roll2():
return(randint(1,6))
def roll_sum():
sum = die_roll1() + die_roll2()
count = 2
if sum == 11:
return(count)
else:
count +=2
roll_sum()
print("The number of rolls are: ", roll_sum())
You are not returning the result of roll_sum() in the else block. However, consider using a while loop instead, as recursion for simpler cases is generally unpythonic:
import random
tries = 1
while True:
a, b = random.randint(1, 6), random.randint(1, 6)
if a + b == 11:
winning = [a, b]
break
tries += 1
Output:
22
[5, 6]
Technically, you simply need to return the count after the else portion. If you roll two non-11s, then the result is never passed recursively through all function calls, so it gets lost in limbo and returns None.
However, your code would never produce a number other than 4 in this case because you reset the count variable to 2 every time you roll an 11.
This can be fixed by making your count variable global (outside the function), and then incrementing it inside the function. This can also be fixed by declaring the variable outside of a while loop.
Iterative programs are nearly always more readable than recursive ones, and your program for this problem should definitely be iterative. The other answers give you an iterative solution.
But as nobody has shown you exactly how to correct your own (recursive) program, I'll do that. I think there are a few things you can learn which will help you (and other beginners) in the long run.
Here's the corrected code.
from random import randint
def die_roll():
return(randint(1, 6))
def roll_sum(count):
sum = die_roll() + die_roll()
if sum == 11:
return(count)
else:
count += 2
return roll_sum(count)
# Call roll_sum with 2 as your initial count
roll_sum(2)
Explanation
When your if statement block has a return statement, your else block should ALWAYS have a return statement too (and so should any elif blocks). If Python doesn't find an explicit return statement (this is what happens in your original program), it returns a special object called None.
So you need to make sure that every possible flow through your function leads to a return statement. Preceding your recursive call in your else block fixes this problem.
Initializing count = 2 inside your roll_sum function results in 2 being assigned to count every single time that the function is (recursively) called. This is obviously not what you want. Instead, you can add a function argument called count, which will solve this problem.
In your initial call of roll_sum, you will have to pass the initial value of count.
There is no need of having 2 functions which do exactly the same thing -- die_roll1 and die_roll2. A function is only supposed to encapsulate a functionality. You can instead just call the same function twice. If you want to make it explicit that you have 2 separate dice rolls, you can just add 2 variables.
roll1 = die_roll()
roll2 = die_roll()
sum = roll1 + roll2
All the best!
Here are several simple solutions to calculate the number of times each sum occurs in the rolling of two dice. To answer your specific problem, you would simply need to use the 'Specific Solution' in place of the 'General Solution' below.
dice1 = [1,2,3,4,5,6]
dice2 = [1,2,3,4,5,6]
totals = []
for num in dice1:
for roll in dice2:
sumz = str(num+roll)
if [sumz, 0] not in totals:
temp = [sumz, 0]
totals.append(temp)
for item in totals:
for num in dice1:
for roll in dice2:
# General Solution - sum of all roles
sumz2 = str(num+roll)
if sumz2 == item[0]:
item[1] += 1
# Specific Solution - only count number of 11's rolled
if sumz2 == '11':
if item[0] == '11':
item[1] += 1
print(totals)
# Using a dictionary to count
totals = {}
for num in dice1:
for roll in dice2:
sumz = str(num+roll)
if sumz not in totals:
totals[sumz] = 1
else:
totals[sumz] += 1
print(totals)
# using collections
from collections import Counter
# temp list to hold all sumz, including multiple entries of same value
temp = []
for num in dice1:
for roll in dice2:
temp.append(num+roll)
# unsorted dictionary of key value pairs
d = Counter(temp)
list_sorted_by_key = []
for i in sorted (d):
temp2 = (i, d[i])
list_sorted_by_key.append(temp2)
print(list_sorted_by_key)

Python while loop restarting code from the beginning

Need help adding a while loop to my code to start it from the beginning again after the user agrees to it. Every time I add it at the end of the code it skips it when I run it and I'm not sure how to do it at all. Any help is welcomed. Thank you!
print('Welcome to the Dice Game')
print(" ")
print('This program will simulate rolling a dice and will track the frequency each value is rolled.')
print(" ")
print('After rolling the dice, the program will output a summary table for the session.')
print(" ")
raw_input("Press Enter to continue...")
# function to roll the dice and get a value
def roll_dice():
r=random.randint(1,6)
return r
#to track the number of times rolled the dice
rolled=0
# to track the number of remaining turns
remaining=10000
# list to store the results
result=[]
# to track the number of sessions
sessions=0
while True:
#incrementing the session variable
sessions+=1
#getting the number of turns from the user
n=int(input("How many times would you like to roll the dice? "))
#checking the number of turns greater than remaining turns or not
if n > remaining:
print('You have only remaining',remaining)
continue
#rolling the dice according to the value of n
if rolled <= 10000 and n <= remaining :
for i in range(n):
result.append(roll_dice())
#updating the remaining turns and rolled variables
remaining=remaining-n
rolled=rolled+n
#printing the results and session variable
if rolled==10000:
print('---------------')
for i in range(len(result)):
print('|{:7d} | {:d} |'.format( i+1,result[i]))
print('---------------')
print('Rolled 10000 times in %d sessions' % sessions)
sys.exit(0)
Your rolled, remaining, result and sessions variables persist on the next iteration of the while loop. You need to redefine the variables on each iteration of the loop, because you're checking against the remaining variable to check if the user's turn is over. So instead of:
def roll_dice():
# ...
rolled = 0
remaining = 10000
result = []
sessions = 0
while True:
# ...
you need:
def roll_dice():
# ...
while True:
rolled = 0
remaining = 10000
result = []
sessions = 0
# ...
I see many unnecessary variables and comparisons in your code, a cleaner code usually results less bugs and better readability.
I suggest something like this:
def do_dice_game(rounds=1000):
sessions = 0
rolls = []
while rounds > 0:
sessions += 1
user_input = rounds + 1
while user_input > rounds:
user_input = int(raw_input("..."))
rolls += [random.randint(1, 6) for i in range(user_input)]
rounds -= user_input
# print something
def do_games():
to_continue = True
while to_continue:
do_dice_game()
to_continue = raw_input("...") == "continue"
Also, according to your code, numbers of each session has no effect on the final "rolled" result. You can always just record the number of sessions and then roll 1000 random numbers at the end.

Produce a function that receives the die value and the total number of rolls and prints a single line of the histogram based on the values passed

"You will need to call the function once per possible die value."
I'm a programming noob and have spent about seven hours trying to figure this out.
My code is just a conglomeration of ideas and hopes that I'm headed in the right direction. I desperately need help and want to understand this stuff. I've scoured the message boards for my specific issue in vain. Please assist...
I realize my code is spitting out the result for every possible roll. When I need a program that I.E. when someone chooses to roll 50 times and designates 2 as the die value they desire to single out. The histogram would display how many times 2 was randomly rolled out of 50 rolls as asterisks on a single line of histogram.
My code thus far:
import random
def dice_sum(rolls):
results = 0
dice_sum = 0
for i in range(0, rolls):
results = random.randint(1, 6)
print("Die %d rolled %d." % (i+1, results))
dice_sum += results
print("Total of %d dice rolls is: %d" % (rolls, dice_sum))
return dice_sum
def hist_gram():
hist_gram='*'
dievalue= int(input('Which specific value between 1 and 6 are you requesting? [enter a #]'))
# get user input
rolls = int(input('How many times would you like to roll the 6 sided die? [enter a #]'))
dievalue= int(input('Which specific value between 1 and 6 are you requesting? [enter a #]'))
# pass input values to function and print result
result = dice_sum(rolls=rolls)
print(result)
You're making a mountain out of a molehill. Slow down and think about the problem. They want you to do an action a bunch of times. Then based on what each result is, do something with that information.
We can use a for loop to do the actions many times, as you've used. Then we can check the result using a simple if statement. You're trying to do the processing after the fact and it's making your life more difficult than it needs to be.
Our solution becomes very simple:
import random
def dice_count(rolls, reqValue):
count = 0
for i in range(0, rolls):
if roll_the_dice() == reqValue:
count = count + 1
#Every time we encounter the value, we count up by one
#That's it! return count.
#Apparently we want a 'single line of a histogram',
# which is kind of a pointless histogram, don't you think?
#Turns out you can multiply against strings.
return count*'*'
def roll_the_dice():
#Apparently we need to call the function more than once? Confusing instruction.
return random.randint(1,6)
And now for the input:
You can use a try..catch block to deal with bad input. If someone inputs something that's not a number, the int conversion will create a ValueError. Instead of crashing, we can decide what happens when a ValueError is raised. If an error occurs, just start over - and keep trying until the user gets it right.
def main():
doInput()
def doInput():
rolls = 0
side = 0
#set up the variables, so we can access them outside the try..catch block
try:
rolls = int(raw_input("How many times should the die be rolled? "))
except ValueError:
print "That's not a valid number. Try again!"
doInput()
try:
side = int(raw_input("Which side?"))
if side < 1 or side > 6:
print "That's not a valid side of a die! Try again!"
do_input()
except ValueError:
print "That's not a valid number. Try again!"
do_input()
dice_count(rolls, side)
You'll want to store the result of each die role somehow, rather than just adding up the sum of your roles. This will also extend your function to be able to look at the results of all 50 results if you want, or just one roll at a time.
There are a few data structures you could use, but I'd recommend a dictionary because it's the most intuitive when dealing with storing values associated with events. For example:
from collections import defaultdict
import random
def dice_sum(rolls):
results = defaultdict(int)
for i in xrange(rolls):
this_roll = random.randint(1,6)
results[this_roll] += 1
return results
Running dice_sum(50):
>>> results = dice_sum(5)
>>> results[1]
11
>>> results[2]
5
>>> results[3]
6
>>> results[4]
13
>>> results[5]
8
>>> results[6]
7
Getting a histogram for a single line has been explained, so if you want the whole thing:
def histogram(results):
hist = ""
for i in xrange(1,7):
bar = '#' * results[i]
hist += '{}: {}\n'.format(i,bar)
return hist
Running it:
>>> print histogram(results)
1: ###########
2: #####
3: ######
4: #############
5: ########
6: #######

Categories

Resources