Skip to content

Instantly share code, notes, and snippets.

@thejevans
Created November 13, 2018 13:26
Show Gist options
  • Save thejevans/581d46c2446434f1b4ffc545a9d3acbc to your computer and use it in GitHub Desktop.
Save thejevans/581d46c2446434f1b4ffc545a9d3acbc to your computer and use it in GitHub Desktop.
#!/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