Condition in FOR loop in Python - python

I'm making a simple lottery simulator. I have two mutually exclusive command line flags, so either the program performs amount of draws the user specifies or until you hit the Jackpot.
for i in range(args.draws):
perform lottery draws here
How to modify the for loop in a way that if args.draws is not given it should
run until jackpot is hit. I am now defaulting the args.draws to a very high number
so in almost all the cases the Jackpot is hit and then break the loop, but is there
better way to do this
Here is the whole code. It is not pretty Im just learning Python
import random
import argparse
def oneoutof(occurance, times):
if occurance == 0:return 0
return float(times)/float(occurance)
if __name__ == '__main__':
LOTTERY_NUMBERS = [i + 1 for i in range(39)]
WIN_LIST =[0,0,0,0]
six_plus_one = 0
parser = argparse.ArgumentParser(description="[Lottery]\n"
"Example: python3 lottery.py ")
group = parser.add_mutually_exclusive_group()
group.add_argument("-s","--seven",action="store_true",
help="Stop when you hit 7 right")
group.add_argument("-d","--draws",type=int,default=1000000,
help="Stop after number of draws")
parser.add_argument("-n","--numbers", nargs=7, type = int,choices=range(1, 40),
help="Lottery numbers, if not given will be randomly selected")
args = parser.parse_args()
if args.numbers ==None:
print('You did not give lottery numbers so following numbers are randomly selected')
picked_numbers = set(random.sample(LOTTERY_NUMBERS, 7))
print(*picked_numbers)
print('Number of lottery draws is {:,}'.format(args.draws))
else:
picked_numbers = set(args.numbers)
print('Number of lottery draws is {:,}'.format(args.draws))
for i in range(args.draws):
lotto_numbers = set(random.sample(LOTTERY_NUMBERS, 7))
remaining_nbrs = set(LOTTERY_NUMBERS).difference(lotto_numbers)
extra_nmbs = set(random.sample(remaining_nbrs, 3))
correct_numbers = lotto_numbers&picked_numbers
correct_extranmbs = extra_nmbs&picked_numbers
if len(correct_numbers) > 3 and not (len(correct_numbers) == 6 and correct_extranmbs):
index = len(correct_numbers) - 4
WIN_LIST[index] = WIN_LIST[index] + 1
if len(correct_numbers) == 7 and args.seven:
print("You hit JACKPOT {} round".format(i))
break
elif len(correct_numbers) == 6 and correct_extranmbs:
six_plus_one=six_plus_one+1
print('4 correct %i times, one out of %g\n'
'5 correct %i times, one out of %g\n'
'6 correct %i times, one out of %g\n'
'6+1 correct %i times, one out of %f\n'
'7 correct %i times, one out of %f\n'
%(WIN_LIST[0],oneoutof(WIN_LIST[0], args.draws),
WIN_LIST[1],oneoutof(WIN_LIST[1], args.draws),
WIN_LIST[2],oneoutof(WIN_LIST[2], args.draws),
six_plus_one,float(args.draws)/float(six_plus_one) if six_plus_one else 0,
WIN_LIST[3],oneoutof(WIN_LIST[3], args.draws)))

We need an import at the top of the file:
from itertools import count, islice
Then we can edit some of your code...
Firstly, set the default value of args.draws to be None - we can use this as "no limit".
group.add_argument("-d","--draws", type=int, default=None, help="Stop after number of draws")
Then, we adjust your print to take into account that None can't be formatted as a integer so we replace it with the largest possible number float('inf') which will successfully still display as inf when printed with the {:,} formatting, so:
print('Number of lottery draws is {:,}'.format(args.draws or float('inf')))
Then, instead of looping over a range, we loop over an infinite sequence, but cap it to n many elements, which is either an integer or is None (which means don't apply a limit to that sequence):
for i in islice(count(1), args.draws):
# ...

You can use a while loop instead.
if(args.draws.length!=0)
for i in range(args.draws):
perform lottery draws here
else
while(!jackpotHit)
perform lottery draws here

I would use itertools.count:
from itertools import count
draws = range(args.draw) if args.draw is not None else count()
for i in draws:
perform lottery draws here

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

Trying to create lottery program in python but getting "FINISHED"

I am trying to create a lottery loop which stops when random generated numbers match the winner ones. But I'm getting this after some time.
---------- FINISHED ----------
exit code: -1073741571 status: 1
import sys
import random
sys.setrecursionlimit(1500000)
lotteryWinner = []
lotteryRandom = []
for i in range(6):
number = random.randint(1,50)
while number in lotteryWinner:
number = random.randint(1,50)
lotteryWinner.append(number)
lotteryWinner.sort()
print(lotteryWinner)
def main():
if len(lotteryRandom)>5:
lotteryRandom.clear()
for i in range(6):
number = random.randint(1,50)
while number in lotteryRandom:
number = random.randint(1,50)
lotteryRandom.append(number)
lotteryRandom.sort()
print(lotteryRandom)
if lotteryWinner != lotteryRandom:
main()
if lotteryWinner == lotteryRandom:
print('You win')
main()
The exit code you receive occurs to indicate that the program indeed did recurse till the provided limit, however reaches the maximum number of recursions. Often it is also necessary to provide the threadinglimit. But since the program is based on random number generation, it might just work some time when a matching list is indeed found. However, it is important to understand how small a probability you are dealing with. You are trying to match 5 random numbers in the two lists which includes:
You want to generate the exact same 5 numbers.(from 1 to 50, where the chaces of picking 1 number is 1/50 and the probability of picking 5 numbers is (1/5)^5)
You want them in the same order in the list. (sorting them as you have done is a good choice)
To make the chances better, one of the multiple things you could do is
import sys
import random
sys.setrecursionlimit(1500000)
lotteryWinner = []
lotteryRandom = []
for i in range(6):
number = random.randint(1,10)
lotteryWinner.append(number)
lotteryWinner.sort()
print(lotteryWinner)
def main():
number = random.randint(1,10)
if number not in lotteryWinner:
main()
else:
print('You win')
main()
Output:
[3, 4, 6, 9, 10, 10]
You win
To improve the chances, the range for random integer generation has been reduced and the program only checks if the generated number is in the initial list of generated numbers. You could increase the range for random number generation to make winning more rare.

Calculating an average in "Rock, Paper, Scissors"

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))

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: #######

Python: Average number of drawings (Randomly generated numbers)

I'm very new to Python and I hope for some help or guides by asking here.
Here's the problem:
Write a program that estimates the average number of drawings it takes before the user’s numbers are picked in a lottery that consists of correctly picking six different numbers that are between 1 and 10. To do this, run a loop 1000 times that randomly generates a set of user numbers and simulates drawings until the user’s numbers are drawn. Find the average number of drawings needed over the 1000 times the loop runs.
I tried to create something (below), but I just can't think of how to get those average number. Also it seems the loop is not good. Any help or solution? thank you in advance.
from random import randint
from random import choice #???
userlist = []
for y in range(6):
user = input("Enter your entry no.{} lotto number: ".format(y+1))
userlist.append(user)
x = 0
randomlotterylist = []
while not x>1000:
lottery = []
for i in range (6):
lot.append(randint(1,10))
randomlotterylist.append(lottery)
x = x + 1
#Next.. ????
First, you want to know your theoretical average number of drawings, that's (1/10)^6 assuming no repetition allowed. Therefore on average every 1,000,000 tries you'd hit the correct number. That is only if the order matters but I assume in your case the order does not matter, so def your average is less than that...
from random import randint
def number_of_tries_before_hitting_jackpot(user_number):
n_tries = 0
while True:
random_number = set([randint(1,10) for i in range(1,7)])
if user_number == random_number:
return n_tries
else:
n_tries+=1
def ask_user_his_number():
userlist = []
for y in range(6):
user = input("Enter your entry no.{} lotto number: ".format(y+1))
userlist.append(user)
return set(userlist)
n_tries_list = []
for x in range(1,1001):
user_number = ask_user_his_number()
print user_number
tmp = number_of_tries_before_hitting_jackpot(user_number)
print tmp
n_tries_list.append(tmp)
avg_number_drawings = reduce(lambda x, y: x + y, n_tries_list) / len(n_tries_list)
print avg_number_drawings
This code is not what I'd do in the sense that the user needs to input its 6 numbers 1,000 times (v annoying for the user). You could change the ask_user_his_number function to a function that just randomly selects a set of 6 numbers.
by using random module, for loop, list in short without defining fuction.
from random import *
user_num=[]
count=0
for i in range(6):
random_num=randint(1,10)
user_num+=[random_num]
user_num.sort()
for j in range(1000):
picked=[]
for k in range(6):
pick_num=randint(1,10)
picked+=[pick_num]
picked.sort()
if picked==user_num:
count+=1
print("the avg darwing is: ",count, count/1000)

Categories

Resources