This is a fun evening exploration to teach myself how to code Python by asking the question "What does the distribution of games of Chutes & Ladders look like by number of spins to win?"

If you're new to Jupyter or Python you might find this interesting.

There's quite a long tail distribution - if you get very unlucky, the game might last well over 200 spins, but if you're super lucky you could get it in 7. :)

In [33]:
# We'll be lazy and code both chutes and ladders as "portals",
# first specifying the square FROM which the portal will go and
# then the square TO which the portal will take you. This allows
# both forward and backward movement. This set of coded portals
# maps the Chutes & Ladders game.

portals = {
1  : 38,
4  : 14,
9  : 31,
16 : 6,
21 : 42,
28 : 84,
36 : 44,
47 : 26,
49 : 11,
56 : 53,
51 : 67,
62 : 19,
64 : 60,
71 : 91,
80 : 100,
87 : 24,
93 : 73,
96 : 75,
98 : 78,
}

# Plays a game of Chutes & Ladders, returns # spins to win
# If printGame is true, will print details of the game.
import random
def playGame(printGame):
currentSquare = 0
spins = 0
while True:
spin = random.randint(1,6)
spins = spins + 1
if printGame: print "you spun a", spin
if currentSquare + spin > 100:
if printGame: print "oh no, you can't go past 100"
else:
currentSquare += spin
if printGame: print "after roll you landed on", currentSquare
portalDest = portals.get(currentSquare)
if portalDest is not None:
if printGame:
if portalDest < currentSquare: print "oh no, a chute to", portalDest
if portalDest > currentSquare: print "oh yay, a ladder to", portalDest
currentSquare = portalDest
if currentSquare == 100:
break
if printGame: print "you won in", spins, "spins!"
return spins

playGame(True)

you spun a 4
after roll you landed on 4
oh yay, a ladder to 14
you spun a 6
after roll you landed on 20
you spun a 5
after roll you landed on 25
you spun a 1
after roll you landed on 26
you spun a 2
after roll you landed on 28
oh yay, a ladder to 84
you spun a 6
after roll you landed on 90
you spun a 6
after roll you landed on 96
oh no, a chute to 75
you spun a 1
after roll you landed on 76
you spun a 3
after roll you landed on 79
you spun a 6
after roll you landed on 85
you spun a 4
after roll you landed on 89
you spun a 5
after roll you landed on 94
you spun a 3
after roll you landed on 97
you spun a 5
oh no,  you can't go past 100
you spun a 1
after roll you landed on 98
oh no, a chute to 78
you spun a 1
after roll you landed on 79
you spun a 2
after roll you landed on 81
you spun a 2
after roll you landed on 83
you spun a 2
after roll you landed on 85
you spun a 5
after roll you landed on 90
you spun a 3
after roll you landed on 93
oh no, a chute to 73
you spun a 4
after roll you landed on 77
you spun a 1
after roll you landed on 78
you spun a 3
after roll you landed on 81
you spun a 4
after roll you landed on 85
you spun a 5
after roll you landed on 90
you spun a 5
after roll you landed on 95
you spun a 5
after roll you landed on 100
you won in 28 spins!

Out[33]:
28
In [34]:
# Now we're going to play a whole bunch of games to get a distribution.
print "Playing games..."
gameOutcomes = [playGame(False) for game in range(100000)]
print "100,000 games completed."

Playing games...
100,000 games completed.

In [35]:
print "Fastest game is in", min(gameOutcomes), "spins."
print "Slowest game is in", max(gameOutcomes), "spins."

Fastest game is in 7 spins.
Slowest game is in 317 spins.

In [21]:
%matplotlib inline
import numpy as np
import pandas as pd
from scipy import stats, integrate
import matplotlib.pyplot as plt
import seaborn as sns

print "Median game takes", int(np.median(gameOutcomes)), "spins."
print "95th %ile game takes", int(np.percentile(gameOutcomes, 95)), "spins."
sns.distplot(gameOutcomes, axlabel="spins to win", hist_kws={"histtype":"step", "alpha":1, "color":"g" })

Median game takes 33 spins.
95th %ile game takes 89 spins.

Out[21]:
<matplotlib.axes.AxesSubplot at 0x1113e2390>