Roulette: The House Always Wins (Python Simulation)
By: Alejandro Colocho
Tags: Monte Carlo Simulation, Python, Data Science, Data Analysis

Photo by: Kay

The other day, I fell prey to the YouTube algorithm. I began watching videos about cars, then I ended up watching videos about roulette strategies to maximize profit. You win this round YouTube. Anyway, I don’t feel that there are any strategies, after all, the house always wins. However, I couldn’t settle by just knowing that the house always wins. Today, we’ll build a roulette game in python, we’ll perform a monte carlo simulation, and we will conduct an experiment to see how fast we can become millionaires (don’t quit your job just yet).

Background

Before we start writing code, we need to understand how roulette works. Roulette is a game in which a ball is spun around a roulette that is spinning too. The ball has 38 different places to land. You can win in the following way:

Guess the color of the number.

Guess the number.

Guess if the number is even or odd.

Guess what area the winning number is located. For example, if it’s in the first 1/3 of numbers, second 1/3, etc.

How hard can it be right? Extremely hard. Why? Because odds will always be stacked against you. For example:

You can try to guess the color of the number. Black or red. However, there is a third color that the casino will not let you choose, on 2 extra numbers 0 and 00, which is green. No matter if you pick red or black, you will only win around 47% of the time.

You can try to guess if the number will be even or odd. 50/50 right? Nope, 0 and 00 don’t count as even or odd. You lose your wager.

What about guessing the zone? It should be easier, right? Nope, you still have 2/3 of the board against you. What about if you bet on all thirds available? Congrats! You won, but you still haven’t made money. Why? Each third pays 2 to 1. If you place a $10 bet on all thirds, you are likely to win $20, but you will lose $20. Unless it lands on 0 or 00, then you lost all $30.

Okay, but if you bet on a single number? The payout should be substantial, right? You’re right. It pays 35 to 1, but you will only guess the number about 2.6% of the time.

Now that I discouraged you enough, let’s build the game.

Building Roulette

Before we get started, I must disclose that this game doesn’t replicate roulette in real life perfectly. For example, you cannot place bets on more than one space, and it uses a random algorithm. The random algorithm part is important because it means that it’s not truly random. Someone designed the package to act random. However, if you crack the algorithm you can potentially predict correctly what number comes next.

Anyway, we will start with building the board. In this case, we will use a dictionary to list all spots with their assigned color.

roulette = {'00':'g',0:'g',1:'r',2:'b',3:'r',4:'b',5:'r',6:'b',7:'r',

8:'b',9:'r',10:'b',11:'b',12:'r',13:'b',14:'r',15:'b',16:'r',

17:'b',18:'r',19:'r',20:'b',21:'r',22:'b',23:'r',24:'b',25:'r',

26:'b',27:'r',28:'b',29:'b',30:'r',31:'b',32:'r',33:'b',34:'r',

35:'b',36:'r'}

As you can see, we pass 00 as a string because python does not support 00 as a number. This will not be an issue because when we use the get() method, it will not care if it’s a number or a string. Next, we will create a dictionary with possible bets as keys and what they mean.

bets = {'first_dozen':range(1,13),'second_dozen':range(13,25),'third_dozen':range(25,37),

'red':'r','black':'b','even':'even','odd':'odd',

'first_column':[1,4,7,10,13,16,19,22,25,28,31,34],

'second_column':[2,5,8,11,14,17,20,23,26,29,32,35],

'third_column':[x*3 for x in range(1,13)],

'high':range(19,37),'low':range(1,19),

'single_num':list(roulette.keys())}

For example, if we use the first_dozen key, then we are betting on number 1–12. Remember, the range function creates a range up to the number before that it was told to stop at. The numbers in columns were assigned that way because the board consists of 36 numbers arranged in 3 columns by 12. High and low just means the first half of the numbers 1–36. Now, we need to get some payouts. We achieve this by using a dictionary. The payouts we used are the same ones a well-known casino uses.

bets_payout = {'dozen':2,'color':1,'even_odd':1,'column':2,'high_low':1,'single_num':35}

Great! We have everything we need to start adding the logic to the game. We need three functions.

To spin the roulette. Check if we have a winning bet. Calculate our payout.

def spin_roulette():

number = choice(list(roulette.keys()))

color = roulette.get(number)

return number, color



def calculate_payout(bet_amount,payout):

bet_payout = bets_payout.get(payout)

return bet_amount * bet_payout



def check_win(bet_amount,bet,test,num,color):

if bet in 'even odd':

if (num == 0) or (num == '00'):

return 0



if ((num%2) == 0) and (bet=='even'):

return calculate_payout(bet_amount,'even_odd')

elif ((num%2) == 1) and (bet=='odd'):

return calculate_payout(bet_amount,'even_odd')

else:

return 0



elif bet in 'black red':

if color == test:

return calculate_payout(bet_amount,'color')

else:

return 0



elif 'column' in bet:

if num in test:

return calculate_payout(bet_amount,'column')

else:

return 0



elif 'dozen' in bet:

if num in test:

return calculate_payout(bet_amount,'dozen')

else:

return 0



elif bet in 'high low':

if num in test:

return calculate_payout(bet_amount,'high_low')

else:

return 0



else:

if num == test:

return calculate_payout(bet_amount,'single_num')

else:

return 0

bonus, how would you make this program better? Leave a comment.

Everything is pretty straight forward with all three functions. The only thing I have to add is that I used the random package to “randomize” the number selected from the roulette.

Monte Carlo Simulation

We will look at the percentage of player wins, player winning amount, and house winning amount:

Betting always on even. Expecting to converge to (18/38) wins.

Betting always on 00. Expecting to converge to (1/38) wins.

Betting on the opposite color that shows up. (Example, if red shows up this round, then we will bet black next round) Expecting to converge to (18/38) wins.

Some of the rules we will follow:

We will bet 15 units every time.

We will run 10,000 trials

First, we’ll create a function to spin our roulette and determine if we win.

def custom_feeling_lucky(bet_amount,bet,test=False):

if test == False:

test = bets.get(bet)

num,color = spin_roulette()

return check_win(bet_amount,bet,test,num,color), color

Now, we’ll build our simulations:

Bet always on even.

win_lose_even = []

for i in range(0,10000):

win,color = custom_feeling_lucky(15,'even')

win_lose_even.append(win)



even_wins = [x for x in win_lose_even if x > 0]

player_winning_amount_even = np.sum(win_lose_even)

house_winning_amount_even = np.sum([15 for x in win_lose_even if x == 0])



print("Win Percentage: {}".format(len(even_wins)/len(win_lose_even)))

print("Player Win Amount: {}".format(player_winning_amount_even))

print("House Win Amount: {}".format(house_winning_amount_even))

Results

Win Percentage: 0.4723

Player Win Amount: 70845

House Win Amount: 79155

Bet always on 00.

win_lose_00 = []

for i in range(0,10000):

win,color = custom_feeling_lucky(15,'single_num','00')

win_lose_00.append(win)



wins_00 = [x for x in win_lose_00 if x > 0]

player_winning_amount_00 = np.sum(win_lose_00)

house_winning_amount_00 = np.sum([15 for x in win_lose_00 if x == 0])



print("Win Percentage: {}".format(len(wins_00)/len(win_lose_00)))

print("Player Win Amount: {}".format(player_winning_amount_00))

print("House Win Amount: {}".format(house_winning_amount_00))

Results

Win Percentage: 0.0242

Player Win Amount: 127050

House Win Amount: 146370

Betting on the opposite color that shows up.

win_lose_opposite = []

bet_color = 'red'

for i in range(0,10000):

win,color = custom_feeling_lucky(15,bet_color)

win_lose_opposite.append(win)



if color == 'r':

bet_color = 'black'

elif color == 'b':

bet_color = 'red'

else:

bet_color = choice(['black','red'])



wins_opposite = [x for x in win_lose_opposite if x > 0]

player_winning_amount_opposite = np.sum(win_lose_opposite)

house_winning_amount_opposite = np.sum([15 for x in win_lose_opposite if x == 0])



print("Win Percentage: {}".format(len(wins_opposite)/len(win_lose_opposite)))

print("Player Win Amount: {}".format(player_winning_amount_opposite))

print("House Win Amount: {}".format(house_winning_amount_opposite))

Results

Win Percentage: 0.4733

Player Win Amount: 70995

House Win Amount: 79005

As you can see, the winning percentage converged to what it was expected. For every simulation, you can see that we did win some money, but the house won even more. The house always wins. When I was doing my research for this article, I came across a popular casino that had the following words in their website: “Luck isn’t with you. Luck isn’t against. Luck doesn’t care.” I guess that would be true if the game wasn’t stacked against you.

Becoming a Millionaire

I decided that we would run this experiment by betting only on red. Why? This is the bet that you have more chances on winning, but not more than the house of course. We’re interested in finding out how many trials it would take us to reach a million dollars and how much money we spent to reach it.

trials = 0

money_spent = 0

money_made = 0



while money_made < 1000000:

win,color = custom_feeling_lucky(15,'red')

trials += 1

money_spent += 15

money_made += win



print('Trials: {}'.format(trials))

print('Money Spent: {}'.format(money_spent))

print('Money Made: {}'.format(money_made))

Results

Trials: 141076

Money Spent: 2116140

Money Made: 1000005

Looks like we need to spend $2 million to win $1 million, and we need to spin the roulette about 141,000 times. It doesn’t look like this is such a good deal for us.

The Wrap Up

It’s obvious that the house always wins, but let’s get passed that. This project was a fun experiment that touched on statistics, programming, and analysis. If you’re a veteran programmer, I think that you should still practice easy projects like this. Going back to the basics is always a must. If you’re a newbie programmer, projects like this will push you to get better.