monte carlo of a preexisting program - python

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!

Related

Python coin flip with functions

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

This little function to rotate a coin isn't working

I'm doing a little program. This program works as follows:
1- U put how many coins do u want to have
2- U put all of them 'heads'
3- From the second coin, you start to flip the coins that the index a multiple of 2, when u finish you go back to the start and start again, but this time you'll start from the third coin and flip all that the index is multiple of 3, and continue like that, restart from the fourth coin and flip the multiples of 4 and continue until the end...
Example: 4 coins-->
heads, heads,heads,heads
1° time:
heads,talls,heads,talls,
2° time:
heads,talls,talls,talls,
3° time:
heads, talls,talls,heads.
I think this code is almost reaching it, but this function I built doesn't do the job of flipping the coin and change the 'mode' on the 'moedas' list
Vocab: Heads-cara / Talls - coroa /Coin(s)- moeda(s) /To flip - Virar (portuguese)
I'll apreciate any help to change some error on the rest of the code too.
def Virar(moeda):
if moeda == 'cara':
moeda = 'coroa'
if moeda == 'coroa':
moeda = 'cara'
return moeda
qtde_moedas = int(input('How much coins do u want?'))
moedas=[]
while (len(moedas))<qtde_moedas:
moedas.append('cara')
for divisor in range(2,len(moedas)):
for index_num in range(len(moedas)):
if (index_num+1)%divisor==0:
moedas[index_num] = Virar(moedas[index_num])
else:
pass
Say you pass 'cara' to your function Virar; first it changes moeda to 'coroa', because it was 'cara'. And then, it checks whether moeda is 'coroa', which is True now, so it turns it back to 'cara'! So Viara never flips the coin as you wish. Instead, try using elif or else:
def Virar(moeda):
if moeda == 'cara':
moeda = 'coroa'
else:
moeda = 'cara'
return moeda
A shorter version, if you are interested, would be the following:
def virar(moeda):
return 'coroa' if moeda == 'cara' else 'cara'
qtde_moedas = int(input("How many coins do you want? "))
moedas = ['cara'] * qtde_moedas
for divisor in range(2, qtde_moedas + 1):
for i in range(divisor - 1, qtde_moedas, divisor):
moedas[i] = virar(moedas[i])
print(moedas)

Generating 5 unique numbers for a Powerball simulator

I wrote this from pseudo-code provided during class, and I've got most of it figured out. Only issue I'm running into is it's returning duplicate numbers for the first 5 'balls' and I can't at all figure out why. One of the lines in the pseudo-code I wasn't sure about was: "if that number is not in the main number sequence". I coded it like this:
if number != mainNumbers:
which could be the issue, but I'm not sure how else to code that.
from random import *
def drawing():
balls=0
mainNumbers=[]
while balls < 5:
number=randint(1,69)
if number != mainNumbers:
mainNumbers.append(number)
balls = balls + 1
mainNumbers.sort()
pBall=randint(1,26)
return mainNumbers, pBall
def main():
print("This program simulates a user defined number of Powerball drawings\n")
runs = int(input("What's the total number of drawings? "))
print()
count = 1
while count <= runs:
balls, pBall = drawing()
print("Drawing: {0} - The numbers are: {1} and the Powerball is: {2}".format(count, balls, pBall))
count = count + 1
main()

Dice Game Simulation

I have this question for an assignment:
Your friend has devised a game with two players. The two players,
called A and B, take turns rolling an ordinary six-sided die, with A being
the first to roll.
The first player who rolls a six wins the game.
You and your friend do not agree about what the probability of A winning
the game is, and you therefore decide to simulate the game with a
computer.
Thus: write a Python program that performs 10 trials, each consisting of
10000 games, and for each trial prints the fraction of the games won by
player A.
This is the code I've gotten so far, it's just returning a number in and around 1667 every time. I'm mainly wondering how to differentiate between A or B winning the game.
Any help would be appreciated!
EDITED CODE
import random
def rollDie():
return random.choice([1,2,3,4,5,6])
def roll_first():
if random.choice([0,1]) == 0:
return 'A'
else:
return 'B'
def rollSim():
while True:
turn = roll_first()
numTrials = 10
numThrows = 10000
totalThrows = numTrials*numThrows
game_on = True
winsA = 0
winsB = 0
while game_on:
for n in range(numTrials):
games = 0
for i in range(numThrows):
throw = rollDie()
if turn == 'A':
if throw == 6:
winsA += 1
games += 1
break
else:
turn = 'B'
else:
if throw == 6:
winsB += 1
games += 1
break
else:
turn = 'A'
return winsA/totalThrows
The best way to achieve a clean code would be to separate in functions each one of the tasks in hand, meaning:
1. Run a play -> For each dice rolling
2. Run a game -> Alternation of plays between A and B, until the first one gets a 6 on the dice (here considering that if A gets a 6, B doesn't even need to play, as A won)
3. Run a trial -> Consisting of a specific number of plays
4. Run the main program -> Consisting of playing all the number of trials required
So, below, is one of the possible solutions (here you see that my play function already returns the result, meaning if the player won or not):
import random
def play():
won = True
keepPlaying = False
rollDice = random.choice([1,2,3,4,5,6])
if rollDice == 6:
return won
return keepPlaying
def run_game(winsA, winsB):
while True:
playA = play()
playB = play()
if playA:
winsA += 1
return winsA, winsB
elif playB:
winsB += 1
return winsA, winsB
def run_trial(numGames):
winsA = 0
winsB = 0
for i in range(numGames):
wins = run_game(winsA, winsB)
winsA = wins[0]
winsB = wins[1]
print("winsA:", winsA, "| winsB:", winsB, "| Fraction of A wins:", "{} %".format(winsA / ( winsA + winsB ) * 100))
numTrials = 10
numGames = 10000
for i in range(numTrials):
run_trial(numGames)
You really only need to count wins for player A. Since you play 10000 games per trial, if you know the number of games that A won, you know the other games must have been won by B, and A+B=10000.
You seem to decide randomly who has the first turn, but the task states that it should always be player A taking the first turn.
You can use a boolean isPlayerA to know whose turn it is. Start with isPlayerA = True and then toggle it with isPlayerA = not isPlayerA.
Here is how you could code it:
import random
def rollDie():
return random.choice([1,2,3,4,5,6])
def winFraction(): # Perform one trial of 10000 games and return fraction of wins for A
winsA = 0 # only count wins for A
for numTrow in range(10000):
isPlayerA = True # Player A always takes the first turn
throw = rollDie()
while throw != 6: # While the game is not over yet:
isPlayerA = not isPlayerA # Switch to the other player
throw = rollDie()
if isPlayerA:
winsA += 1 # Only count the wins for player A
return winsA/10000.0 # This is the fraction: we know the number of played games
def sim():
for trial in range(10): # Perform 10 trials
print(winFraction()) # Print the result of the trial
sim() # Start the simulation

Random number generator, how to get random numbers that are not the same

I am making a random number generator but I do not want the numbers over again. so for example
[1,2,3,4] is perfect -
[1,1,2,4] is not what I want because a number recurring.
I have looked on here and no one has the answer to the problem I am searching for, in my logic this should work but I do not know what I am doing wrong.
I am new to python and I saw a couple questions like mine but none with the same problem
import random, timeit
random_num = random.randint(1,10)
cont_randomized_num = random.randint(1,10)
tries = 0
start = timeit.default_timer()
num_guess = 0
stored_numbers = []
while cont_randomized_num != random_num:
if cont_randomized_num == stored_numbers:
cont_randomized_num = random.randint(1,10)
elif cont_randomized_num != stored_numbers:
print(num_guess)
stored_numbers.append(cont_randomized_num)
print(stored_numbers)
cont_randomized_num = random.randint(1,10)
tries +=1
print()
print()
stop = timeit.default_timer()
print(random_num)
print('Number of tries:',tries)
print('Time elapsed:',stop)
input('press ENTER to end')
I guess I did not make myself clear enough.
I want to generate a random number = ANSWER
I want a second number generated to try and match the ANSWER, if it is not the ANSWER then STORE it somewhere. If the second generated number is generated a second time and it is the same as the first time it was generated I want it to skip and generate a new one. Keep this going until the second generated number is equal to the first number generated.
I have figured it out (finally) here is the code that is not over complicated and have nothing to do with any answer or critique given! This is what I have been asking for this entire time.
import random
import timeit
start = timeit.default_timer()
stored_numbers = []
cont_random = random.randint(1,10)
random_num = random.randint(1,10)
times_guessed = 0
while random_num not in stored_numbers:
if cont_random in stored_numbers:
cont_random = random.randint(1, 10)
elif cont_random not in stored_numbers:
print(cont_random)
stored_numbers.append(cont_random)
cont_random = random.randint(1, 10)
times_guessed += 1
print('Answer has been guessed!')
print('Stored numbers',stored_numbers)
print()
print()
stop = timeit.default_timer()
print('Time elapsed:',stop)
print('Times guessed -', times_guessed)
print('The random number:',random_num)
input('Press ENTER to exit')
Use random.sample() instead of populating the list one by one (see docs):
Return a k length list of unique elements chosen from the population sequence. Used for random sampling without replacement.
random.sample(range(10), 5)
>>>> [5, 9, 1, 6, 3]
random.sample() needs to be fed a list (or any iterable, really) to choose a subset from. Here, I gave it a list of the first 10 numbers starting from 0.
Here is my solution, you can add more functionality to it if you want by adding more code in the loop.
import random, timeit
def main():
tries = 0
NUMBER_OF_RANDOMS = 4
stored_numbers = []
start = timeit.default_timer()
while len(stored_numbers) != NUMBER_OF_RANDOMS:
current = random.randint(1,10)
tries += 1
if current not in stored_numbers:
stored_numbers.append(current)
stop = timeit.default_timer() - start
print 'Number of tries:', tries
print 'Time elapsed:', stop
print stored_numbers
if __name__ == '__main__':
main()
Does this do what you were wanting? I believe you do unnecessarily complicated code.

Categories