Python coin flip with functions - python

I need to create a python program that will use various functions to simulate flipping a coin 100 times and finding the largest streak of "H"'s out of 10,000 tries. I am stuck on how to finish the def main() function, specifically the counter. I also don't know if my program is calculating the streaks correctly.
def flipCoin() - returns 'H' or 'T' with the same probability as a coin.
def simulate(numFlips) - simulates flipping a coin numFlips(100) times. This function returns a list of length numFlips containing H's and T's.
def countStreak(flips_list) - iterates through the flips list passed to it and counts streaks of 'H's and returns the largest streak it finds. Keep track of the current number of heads and the current largest streak of heads in two separate variables.
As you iterate through the list, keep track of the current number of heads you've seen in a row. If you see a tail, check if the current streak of heads is larger than your current longest streak. If so, save the current streak. Then reset your heads counter.
In the main function, write a testing loop that simulates the process 10000 times.
Keep track of the current largest streak of heads and display this result after the test loop completes.
# import statements
import random
# function defintions
def flip():
coin = random.randint(0, 1)
if coin == 0:
return "H"
else:
return "T"
def simulate(num_flips):
# simulates numFlips coin flips
# returns a list of the flips
numFlips = []
for i in range(100):
numFlips.append(flip())
return numFlips
def countStreak(flips_list):
# iterates through the 'flips' list
# returns number of 'H's
count = 0
maxCount = 0
flips_list = simulate()
for i in flips_list:
if i == "H":
count += 1
if count > maxCount:
maxCount = count
else:
count = 0
return maxCount
def main():
for j in range(10000):
trial = simulate(100)
coinFlip = countStreak(1)
# need something here to track count of streaks for "H"
print("The longest streak of heads was " + str(coinFlip) +".")
if __name__ == "__main__":
main()

So there was a flaw in your code, you were running simulate() function 10000 times. But actually, you had to run it once, but return a list of 10000 items. Also, you need not check the streak every time so the check_streak() need to be out of the loop and we need to pass the result obtained from simulate(10000) into it.
Correct Code:
# import statements
import random
# function defintions
def flip():
coin = random.randint(0, 1) # better option would be to use random.choice()
if coin == 0:
return "H"
else:
return "T"
def simulate(num):
# simulates numFlips coin flips
# returns a list of the flips
numFlips = []
for i in range(num): # this needs to run num times
numFlips.append(flip())
return numFlips
def countStreak(flips_list):
# iterates through the 'flips' list
# returns number of 'H's
count = 0
maxCount = 0
for i in flips_list:
if i == "H":
count += 1
if count > maxCount:
maxCount = count
else:
count = 0
return maxCount
def main():
trial = []
for j in range(10000):
temp2 = simulate(100) # SImulate 10000 coin flips
coinFlip = countStreak(temp2) # Check streak of variable trial
trial.append(coinFlip)
# need something here to track count of streaks for "H"
# print(trial)
print("The longest streak of heads was " + str(max(trial)) +".")
if __name__ == "__main__":
main()
This Part is Optional, For optimisation
Though the logic isn't wrong, you need not make the list 1st and then check streak, you can simply check it together, it will take less time and space.
Also, your logic is correct, but this one would be better:
import random
# function defintions
def flip():
return random.choice(['H', 'T']) # using random.choice()
def simulate(num_flips):
streak = 0
temp = 0
for i in range(num_flips):
if flip() == 'H':
temp+=1 # adding one to temporary streak if it is a heads
else: # this block executes if streak is broken
if temp > streak:
streak = temp
temp = 0
return streak
def main():
trial = []
for i in range(10000):
trial.append(simulate(100))
print("The longest streak of heads was " + str(max(trial)) +".")
if __name__ == "__main__":
main()

Related

Lottery ticket generator

I'm trying to create a lottery ticket generator. Lottery tickets in Norway can have 10 rows that you bet on. They contain each 7 numbers. The numbers you can choose from is 1-34. In total i can choose 70 numbers within this range of numbers, but i want every number to be picked two times(68) and two can be picked three times(total of 70 numbers). My program will only give me nine rows of numbers and i can't figure out what I'm doing wrong.
import random as r
# picks random number
def pickNumber():
number = r.randint(1, 34)
return number
# checks if number is in the list
def checkList(lst, number):
if not number in lst:
return True
return False
# checks the amount a number has occured
def checkNumber(lst, number):
my_set = None
if lst[number - 1] == 1:
return False
else:
lst[number - 1] += 1
my_set = set(lst)
if len(my_set) == 1:
for i in range(len(lst)):
lst[i] = 0
return True
# Run program
def main():
occured = []
for i in range(34):
occured.append(0)
ticket = []
counter = 1
while True:
row = []
while True:
number = pickNumber()
if checkList(row, number):
if checkNumber(occured, number):
row.append(number)
if len(row) >= 7:
break
ticket.append(row)
counter += 1
if counter == 10:
break
for i in range(len(ticket)):
print(ticket[i])
main()
(moving comment to answer)
Start with counter = 0. You check for 10 before processing the tenth row.

Counting Heads and Tails in a coin flip program

For my assignment, I have to use Functions within Python to simulate a coin flip. I managed to get the coin flip to showcase heads and tales for the amount the user has inputted. However, for the next portion, I have to get the program to read how many times Heads and Tails appeared. The error I am getting is
'NameError: name 'heads' is not defined'.
import random
def main():
tosses = int(input("Please enter the amount of coin tosses:"))
coin(tosses)
count = 0
heads = 0
tails = 0
def coin(tosses):
for toss in range(tosses):
if random.randint(1, 2) == 1:
print('Heads')
heads += 1
count += 1
else:
print('Tails')
heads += 1
count += 1
print (heads)
print (tails)
main()
Problem
heads was defined out of the scope of the function coin.
Solution
Try defining the variables inside the function, then returning them. Note: the same had to be done with main.
import random
def main():
tosses = int(input("Please enter the amount of coin tosses:"))
coin(tosses)
heads, tails, count = coin(tosses)
return heads, tails
def coin(tosses):
count = 0
heads = 0
tails = 0
for toss in range(tosses):
if random.randint(1, 2) == 1:
print('Heads')
heads += 1
count += 1
else:
print('Tails')
tails += 1 # note you had this say heads before
count += 1
return heads, tails, count
heads, tails = main()
print(heads)
print(tails)
More on why this problem occurred
When you use def and create a new function, all of the variables in that function are accessible just to that function.
What was happening to you, is that you were trying to update the heads variable with heads += 1, but the function literally didn't know what the variable you were referring to is! (That variable was defined in main, and is only accessible from within the main function.)

monte carlo of a preexisting program

The python code in diceGame.py (below) contains a python implementation of the dice game we discussed in class. Assume we run the code N times and estimate the probability of a certain event A, P r{A}, based on the number of times A occurs divided by N. We then repeat this process M times collecting the probabilities pi, i = 1, . . . , M. Under the assumption that both dices are fair, modify the main routine of diceGame.py using N = 10, 100, 1000 and M = 100 for the following probabilities:
The probability of winning the game at the first dice roll.
The probability of winning the game if the first roll gives a 4.
The probability of winning the game.
The probability of a game to require more than 5 dice rolls.
I know that all of these answers can easily be supplied through the code itself. My problem is that I have no idea how to edit the python code to give these desired outputs.
Here is the code:
# ===============================
# IMPORTS RANDOM NUMBER GENERATOR
# ===============================
import random
# ================================================================
# GENERATES RANDOMLY THE SUM OF TWO INTEGERS IN THE [1,6] INTERVAL
# ================================================================
def rollDices():
return int(random.randint(1,6) + random.randint(1,6))
# ================================================
# RETURN THE OUTCOME STRING GIVEN AN INTEGER STATE
# ================================================
def getOutcome(outcome):
if(outcome == 0):
result = "Lost at first roll."
elif(outcome == 1):
result = "Won at first roll."
elif(outcome == 2):
result = "Won on [4,5,6,8,9,10]"
elif(outcome == 3):
result = "Lost on [4,5,6,8,9,10]"
return result
# ==============
# PLAYS THE GAME
# ==============
def playGame():
# Define Variables
gameFinished = False
wonGame = False
totRolls = 0
while (not(gameFinished)):
# ROLL DICES
totScore = rollDices()
totRolls += 1;
# GAME IS LOST
if(totScore in [2,3,12]):
gameFinished = True
wonGame = False
return 0,wonGame,totRolls,totScore
# GAME IS WON
if(totScore in [7,11]):
gameFinished = True
wonGame = True
return 1,wonGame,totRolls,totScore
# JUST CONTINUE PLAYING
if(totScore in [4,5,6,8,9,10]):
# REPEAT UNTIL YOU FIND THE SCORE AGAIN OR 7
newScore = 0
while((newScore != totScore)and(newScore != 7)):
newScore = rollDices()
totRolls += 1;
# CHECK IF YOU WIN OR LOOSE
if(newScore == totScore):
gameFinished = True
wonGame = True
return 2,wonGame,totRolls,totScore
if(newScore == 7):
gameFinished = True
wonGame = False
return 3,wonGame,totRolls,totScore
# ============
# MAIN PROGRAM
# ============
if __name__ == "__main__":
intVal,wonGame,numRolls,lastScore = playGame()
print("Outcome: %s" % (getOutcome(intVal)))
if(wonGame):
print("You have won the game.")
else:
print("You have lost the game.")
print("Total rolls needed for this game: %d" % (numRolls))
print("Last outcome: %d" % (lastScore))
New main function as I attempt the problem:
if __name__ == "__main__":
m = 100
n = 10
FRwins = 0
for i in range(m):
for j in range(n):
intVal,wonGame,numRolls,lastScore = playGame()
if getOutcome(intVal) == 1:
FRwins += 1
FRwins = FRwins/float(n)
print(FRwins)
Currently this programme is playing the game once. If you look at the final 10 lines of code, that is what you want to adjust in order to do this. The important line is this:
intVal,wonGame,numRolls,lastScore = playGame()
It is only being called once, so you only get one result out of it. Since you need to do a Monte Carlo simulation (i.e. playing over and over again and tracking the probabilities), you just need to replay this line lots of times, and keep track of the results each time.
From there, you will need to set up some for loops, such as:
for i in range(m):
and keep track of results from each simulation. Since you are working with m and n, you will need nested loops surrounding your playGame(). Then you just need to tally the results as you go, and divide by the total attempts to get your probabilities.
Hopefully this is helpful. Feel free to ask further questions - I'm trying to keep it general enough that I'm not actually writing the code for what seems to be your homework!

Printing first n Happy Numbers - Python

I am writing a piece of code in python that checks whether a given number is happy or not, that is taking the number and adding the sum of their squares is 1 which is a happy number or ending up with a never ending loop which defines a unhappy number.
After that, I want to list the first n Happy Numbers. I got the checking for happy numbers down albeit sloppily, I just can't seem to figure out the listing part.
def adder(num):
total=0
if len(str(num))>1: #check if given number is double digit or not
tens = int(str(num)[0]) # splitting the digits
ones = int(str(num)[1])
total = (tens**2)+(ones**2) # summing up the squares
#print (total)
return total
else: # if the given number is a single digit
total = (num**2)
#print (total)
return total
#adder(9)
def happynumber(num, counter):
N = adder (num) # storing the sum in a variable
#print ("value of n is {}".format(N))
if N == 1: #checks if the sum is 1
# print ("In just {} tries we found that {} is a happy number.".format(counter, number))
print (number)
else: # if the sum isn't 1, racalls the happynumber function
counter += 1 # keeps track of number of tries so that we don't end up in an infinite loop
if counter < 11: # setting the limit for number of tries
#print (counter)
happynumber (N, counter)
else:
#print ("it took us {} tries and found that the number {} is not a happy number".format(counter, number))
return False
counter = 0
for i in range(0,100): # listing all the happy numbers between 0 and 100
number = i
happynumber (number, counter)
Additionally, I would like it if you guys would review my writing style and give some pointers.
The problem, I am not able to list the first n numbers however way I try.
I tried using counter in the loop but to no avail.
If your main problem is that you want to have all your happy numbers in a list, you can easily address this by defining a list outside the recursion loop.
def happynumber(num, counter):
N = adder(num)
if N == 1:
happyhappy.append(number) #new happy number into list
else:
...continue with your code
#-------main script-------------
happyhappy = [] #create a list to store your happy numbers
counter = 0
for i in range(100):
number = i
happynumber(number, counter)
print(happyhappy) #and retrieve the list
Having said that there is an inefficiency in your adder() function. It calculates only up to two digits. Even worse, it has to perform the square operation for each digit from scratch, which is very time consuming.
A better way is to pre-calculate the squares and store them in a dictionary:
square_dic = {str(i): i ** 2 for i in range(10)} #create a dictionary of squares
def adder(num):
s = str(num) #make the number into an iterable string
x = [square_dic[i] for i in s] #look up the square of each digit
return sum(x) #and calculate the sum of squares
Thanks to list comprehensions in Python we can make it even snappier
square_dic = {str(i): i ** 2 for i in range(10)}
def adder(num): #does exactly, what the other function did
return sum(square_dic[i] for i in str(num))
So first off, you shouldn't have to pass your counter variable since it is a global variable. I'd also probably declare it up above your methods just to make sure there are no issues.
Your next issue is you never reset your counter variable. So the first time the program runs into a number that is not-happy after 10 attempts it proceeds to return false for every single number that is not happy after the first attempt. Try adding in counter = 0 before your return False line in the if counter < 11/else block
Here is an example with very small change to your current code. I add another input for the happynumber function, that is your list that you want to store the happy numbers.
I am sure this is not the most efficient way, but it shows how you can update your code.
The code :
def happynumber(num, counter, the_list):
N = adder(num);
print ("value of n is {}".format(N));
if counter == 0: #THIS IS ADDED
the_list.append(num); #THIS IS ADDED
if N == 1:
print ("In just {} tries we found that {} is a happy number.".format(counter, number))
print (num);
else:
counter += 1
if counter < 11:
print (counter)
happynumber(N, counter, the_list)
else:
print ("it took us {} tries and found that the number {} is not a happy number".format(counter, number))
the_list.pop(); #THIS IS ADDED
return False
counter = 0;
happynumber_list = []; #THIS IS ADDED
for i in range(0,100):
number = i
happynumber (number, counter, happynumber_list)
In the first attempt, the number will be stored to the list...but if the number was found not a happy number.. then that number will be pop out of the list.
Here is the result :
[1, 7, 10, 13, 19, 23, 28, 31, 32, 44, 49, 59, 68, 70, 79, 82, 86, 91, 94, 95, 97]
Is this okay?
You could use memoization to make the use of a counter unnecessary. I would also use a generator (yield) so only the number of results are produced that you ask for. Then you don't have to specify a range (0, 100), but can just specify that you want the first 25 happy numbers (or whatever is needed).
Here is how that would look:
import itertools
def sum_digit_squares(num):
return sum(int(i)*int(i) for i in str(num))
def happynumbers():
memo = { 1: True }
for i in itertools.count(): # forever (as long as getting from this iterator)
result = None # Will become either True (happy) or False (not happy)
visited = set()
j = i
while result is None:
if j in memo: # Did we make the calculation for this one before?
result = memo[j]
elif j in visited:
result = False # endless loop detected
else:
visited.add(j)
j = sum_digit_squares(j)
for j in visited:
memo[j] = result
if result:
yield i
print (list(itertools.islice(happynumbers(), 0, 25))) # Produce first 25 happy numbers

python - infinite coin flip that stops when number of heads = number of tails

I'm new to python and I'm trying to create a coinflip loop which will keep flipping and counting the number of flips until the number of heads = the number of tails, where it will stop and print the total number of flips it took to reach that. I'm trying to get the results in order to work on my maths coursework, but I cannot seem to figure out how to get it to stop or print the results, and when I do it prints 0. Here is the code I have so far:
import random
heads = 1
tails = sum(random.choice(['head', 'tail']) == 'tail'
count = 0
while True:
coinresult = random.randint(1, 2) if heads == tails:
break
print("The number of flips was {count}".format(count = heads + tails))
not sure what is going on with your indentation but try this:
import random
heads = 0 #initialize the count variables
tails = 0
while True:
coinresult = random.randint(1, 2) #flip coin
if coinresult == 1: #if result = 1 then increment heads counter
heads += 1
elif coinresult == 2: #if result = 2 then increment tails counter
tails += 1
if heads == tails: #check if counts are equal and break loop if they are
break
print("The number of flips was {count}".format(count = heads + tails))
import itertools as it
import random
def flips():
while True:
yield (random.getrandbits(1)<<1) - 1
def cumsum(seq):
s = 0
for i in seq:
s += i
yield s
def length(seq):
n = 0
for _ in seq:
n += 1
return n
print("The number of flips was {}".format(length(it.takewhile((0L).__cmp__, cumsum(flips())))))
I think this will be a nice implementation
import random
s = 0
iteration = 0
while True:
coin = random.sample([-1,1], 1)[0]
s = s + coin
iteration = iteration + 1
if s == 0:
break
print(iteration)

Categories