Created
November 13, 2018 13:26
-
-
Save thejevans/581d46c2446434f1b4ffc545a9d3acbc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
""" | |
@author: Emily Blick | |
@collaborators: | |
@hours_spent: | |
""" | |
import random | |
import numpy as np | |
import matplotlib.pyplot as plt | |
import time | |
### Part 1 ### | |
def simple_roulette(choices, pockets): | |
real = random.choice(pockets) | |
guess = random.choice(choices) | |
if real == guess: | |
return True | |
else: | |
return False | |
""" | |
Simulates a roulette wheel with `choices` choices available to the player and | |
`pockets` possible pockets on the wheel. Assumes player placed a bet on any single | |
number (a "straight up" bet). | |
:param list choices: a list of choices (e.g. ['1', '2', '3'] if there are 3 pockets - roulette has 36) | |
:param list pockets: a list of pockets on the roulette wheel. For European roulette the user | |
should pass choices + ['0'] while for American roulette the user should pass | |
choices + ['0', '00'] | |
:return: Returns True if a random choice from `choices` wins (matches a random choice from | |
pockets) - this assumes the player placed a "straight up" bet on a single pocket, | |
otherwise returns False | |
:rtype: bool | |
""" | |
raise NotImplementedError | |
def play_roulette(num_spins, choices, pockets): | |
payout = 35 | |
winnings = 0 | |
bet = 1 | |
for _ in range(num_spins): | |
outcome = simple_roulette(choices,pockets) | |
if outcome == True: | |
winnings += payout | |
else: | |
winnings -= bet | |
return winnings/num_spins | |
""" | |
Plays `num_spins` games of roulette. Calls `simple_roulette` internally with appropriate | |
values of `choices` and `pockets`. Assumes player places a bet of 1 on every spin, if | |
they win the spin (as determined by `simple_roulette`) their winnings are incremented by | |
the payout (defined as the number of choice s minus 1), otherwise they lose their bet. | |
:param int num_spins: Number of spins to simulate | |
:param list choices: a list of choices (e.g. ['1', '2', '3'] if there are 3 pockets) | |
:param list pockets: a list of pockets on the roulette wheel. For European roulette this | |
will be equal to choices + ['0'] while for American roulette this will be equal to | |
choices + ['0', '00'] | |
:return: Expected value of a bet of 1 (e.g. if 0, means that on average player gets their | |
bet back, a positive value means the player makes money on average, and a negative number | |
means the player loses money on average) | |
""" | |
raise NotImplementedError | |
### Part 2 ### | |
def test_roulette(roulette_func): | |
for num_spins in [1000, 10000, 100000, 1000000, 10000000]: | |
fair = roulette_func(num_spins, range(1,37),range(1,37)) | |
print(fair) | |
european = roulette_func(num_spins, range(1,37), range(1,38)) | |
print(european) | |
american = roulette_func(num_spins,range(1,37),range(1,39)) | |
print(american) | |
return | |
""" | |
Accepts a roulette function (i.e. either play_roulette or play_roulette_numpy), and uses it | |
to simulate fair, European, and American roulette games for some number of spins and prints | |
the estimate of the expected value. This function iterates through a number of spins, | |
[1000, 10000, 100000, 1000000, 10000000], printing the estimated value of the expected value | |
for fair, American, and European roulette after each of these number of spins. Note that each | |
set of trials for each of these numbers of spins is independent of the last (so you can simply | |
call roulette_func for each of the number of spins - no need to make use of the results from | |
the previous / lower number of spins). | |
:param roulette_func: The function to use to estimate the expected value of a gambler's bet (should | |
accept the number of spins, a list of available choices, and a list of available pockets). | |
""" | |
raise NotImplementedError | |
### Part 3 ### | |
def play_roulette_numpy(num_spins, choices, pockets): | |
payout = 35 | |
choicesnum = np.random.choice(choices,num_spins) | |
pocketsnum = np.random.choice(pockets,num_spins) | |
luckywins = (choicesnum == pocketsnum) | |
number_winnings = np.sum(np.array(luckywins)) | |
newbet = ((num_spins-number_winnings)*-1) + (payout*number_winnings) | |
result = newbet/num_spins | |
return result | |
""" | |
Uses numpy's random.choice module and vector math internally to simulate the expected value of | |
a bet of 1 over num_spins trials (WITHOUT using iteration). Should only require a few lines | |
of code (~3-4) to solve in a way which is clearly readable. Self contained / does not need to | |
call an external function like we did earlier (with play_roulette calling simple_roulette). | |
:param int num_spins: Number of spins to simulate | |
:param list choices: a list of choices (e.g. ['1', '2', '3'] if there are 3 pockets) | |
:param list pockets: a list of pockets on the roulette wheel. For European roulette the user | |
should pass choices + ['0'] while for American roulette the user should pass | |
choices + ['0', '00'] | |
:return: Expected value of a bet of 1 (e.g. if 0, means that on average player gets their | |
bet back, a positive value means the player makes money on average, and a negative number | |
means the player loses money on average) | |
""" | |
raise NotImplementedError | |
### Part 4 ### | |
def plot_american_roulette(num_spins_max): | |
estimate = [] | |
expected = 0 | |
for spins in range(1,num_spins_max+1): | |
result = 35 if simple_roulette(range(1,37),range(1,39)) else -1 | |
expected += result | |
estimate.append(expected/spins) | |
x = list(range(1,num_spins_max+1)) | |
plt.axhline((36/38)-1, color = 'orange') | |
plt.plot(x, estimate) | |
plt.ylim(-.1, .1) | |
plt.title('Expected return as a function of the number of spins for American roulette') | |
plt.xlabel('Number of spins') | |
plt.ylabel('Expected return') | |
plt.show() | |
return | |
""" | |
This is a little different from the previous functions since we want to plot the | |
expected value vs. the number of spins. Internally this function uses simple_roulette | |
and builds a list by appending the currently estimated expected value after each spin up | |
to `num_spins_max`, then plots this vs. number of spins. y limits are forced to be between | |
-.1 and .1 to avoid extreme values hiding what's going on. | |
:param int num_spins_max: How many times to spin | |
:return: Nothing | |
:rtype: None | |
""" | |
raise NotImplementedError | |
if __name__ == '__main__': | |
print('Testing using standard Python iteration') | |
start = time.clock() | |
test_roulette(play_roulette) | |
print('Testing took {} seconds\n'.format(time.clock() - start)) | |
print('Testing using Numpy') | |
start = time.clock() | |
test_roulette(play_roulette_numpy) | |
print('Testing took {} seconds\n'.format(time.clock() - start)) | |
print('Generating plot of expected value estimate over 1,000,000 spins') | |
plot_american_roulette(1000000) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment