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)
Related
Hey so im pretty new to programming in general and I was having a crack at a question I found for the collatz function,
The code I wrote after some trial and error is as follows:
def collatz(number):
if number % 2 == 0:
number = number//2
print(number)
return number
elif number%2 != 0:
number = 3*number + 1
print(number)
return number
n = int(input("plz enter the number:"))
while n != 1:
n = collatz(n)
Output:
plz enter the number:3
10
5
16
8
4
2
1
This code works but im not sure how the variable values are being alloted, cuz after running this program I can see that in the shell "number = 3" but "n = 1", why is this the case? Shouldnt "number" also equal to 1? Because I am returning the value of number within the function?
Also just to clear my concepts, at the initial moment when I input n = 3, at that moment n = number = 3, then does this returned value of "number" automatically become the new value of n, when i call it in the while loop?
Just wanted to check cuz im a little weak when it comes to doing stuff that needs to pass parameters.
edit:
Why is this case diff then what was just answered?
def testfile(number):
number = number -1
print(number)
return number
n = int(input("enter:"))
while n != 2:
n = testfile(n)
Output:
enter:5
4
3
2
When the input is given as n = 5, then why does number = 3 instead of 5 as was just explained below?
Here's how your program works.
You ask for a number and store it in variable n.
You open a loop which continues until n is 1
Every time the loop repeats, you're calling your function and passing a COPY of n. If you add one to the copy inside the function, your original n will not change.
The COPY is called number. You perform your little tricks with number, output it to the screen, and here's the confusing part: you return a copy of number right back to your loop. And where does it go? It goes right back to n. This overwrites whatever was in n previously.
The aim is to create a percentage attendace calculator based on a given list of names. I was able to loop the input questions with the names in the list. However my issues lie with the following if condition which should output a 1 for each input question if the answer is y for each person in the list or a 0 if the answer n for any person in the list. The number outputs should then be added in order to obtain a precentage. Please help.
continueLooping=True
students=["Annie", "Brian", "Clare", "Danny", "Ellen"]
i=0
while i<len(students):
askuser=input(f"Is {students[i]} present?[y/n]")
i=i+1
if askuser == "y":
one = 1
print("1")
else:
one = -1
print("-1")
while one<len(students):
if askuser == "y":
one = 1
one=one+1
else:
one = -1
one=one+1
percentage=(one)/len(students)
print(percentage)
Your second inner while loop will terminate only if the first answer is "y".
What you should be aiming to do is count the number of "y" answers you receive in the outer while loop.
As such:
students=["Annie", "Brian", "Clare", "Danny", "Ellen"]
i=0
studentsPresentCount = 0
while i<len(students):
askuser=input(f"Is {students[i]} present?[y/n]")
i=i+1
if askuser == "y":
studentsPresentCount += 1
percentage = studentsPresentCount/len(students)
print(percentage)
Note you can use the syntactic sugar 'i += 1' instead of 'i = i + 1'.
In trying to stay as close to your code as possible, the code below works for what you describe.
There are three main corrections to the code:
You have an inner while loop that isn't necessary. On each pass of the outer while loop, you can ask about each student, output the desired attendance, and adjust the attendance score. There's no need for a second loop inside.
You keep changing the value of "one", rather than incrementing or decrementing. You can set one to 0 outside the loop (as you do with your counter i), and adjust it inside the loop.
You probably don't want non-attendance to be -1, but rather have it as zero. Imagine a scenario with 3 attendees and 2 non-attendees. Your scoring would end up with 1+1+1-1-1, for an attendance score of 1 - when in fact the attendance score is 3.
There's also no need for the "continueLooping" variable at the outset.
Last point, if you want percent, you can multiply the percentage value by 100 (as it is, it returns the decimal value).
The working code, with these corrections, is:
students=["Annie", "Brian", "Clare", "Danny", "Ellen"]
i=0
one = 0
while i<len(students):
askuser=input(f"Is {students[i]} present?[y/n]")
i=i+1
if askuser == "y":
one += 1
print("1")
else:
print("0")
percentage=(one)/len(students)
print(percentage)
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))
Note - Go down to the edits if you want the more recent code, look here if you want to see the original question. I have made edits to the code, however, so mistakes in this code block may be outdated.
As a self-taught Python 3 programmer, I have been working on a way to simplify radical expressions. The one part of the program that does not work, however, is the square factorization. I have a function that detects square numbers, which works fine. The function that does not work is the following-
def sqfactorslist(num):
factors = []
counter = num // 2 + 1
while counter > 0:
if counter == 1:
factors.append(num) #if no square ints other than 1 square into num, append and finish.
while is_square(counter) == True and counter != 1: #If counter is a valid square integer, append it's square and subtract it from num.
if (counter ** 2) >= num:
factors.append(counter ** 2)
num -= counter ** 2
else: #Else, continue with a program.
break
if counter > 0:
counter -= 1 #If counter more than 0, subtract 1 from it
else:
break #If number is equal to or less than 0, break
return factors #If the input is 32, this should return 16 and 2.
It doesn't return anything other than an infinite loop. Anyone know whats wrong?
Edit 1 -- I have changed the program so that it runs, but now I have a stranger issue: If I input a square number as num, for example 16, I get a number larger than the input, e.x. 81, in the return list. I get no returned elements for a non-square number.
To make it run, I indented the first if statement after the end of the second while loop.
Edit 2 -- I have changed the program again, but I come up with another issue similar to the one above. After eliminating another mistake, where I squared numbers already shown to be square, found in the second while loop, the program now has a new problem - If I use a non-square integer, it returns an empty list, and if I use a square integer, like 16, it gives me an infinite loop. Current code shown below --
def findsqfactors(num):
factors = []
counter = num // 2 + 1
while counter > 0:
if counter == 1:
factors.append(num) #If no square ints other than 1 square into num, append then finish.
while is_square(counter) == True and counter != 1: #
if counter >= num:
factors.append(counter)
num -= counter
else:
break
if counter > 0:
counter -= 1
else:
break
return factors
"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: #######