http://www.perlmonks.org?node_id=775760

## Intro

My young son has me playing the Chutes and Ladders board game with him. While fun for him, this simple game of chance provides little stimulation (for an adult) after the first few spins of the dial. So, being a geek, I coded up some Perl to dump out how many spins it takes to win a game, how often a player climbs a specific ladder, etc. You know -- absolute crucial knowledge for parents.

Now, I'll be able to impress with nuggets such as: "You'll most likely win in 22 moves! But, don't bet on it because that only happens 2.5% of the time".

## Obvious Stats

Observations based on 1 million games:
Metric Number of spins
Mean 39.6
Median 33
Mode 22
Minimum 7
Maximum Infinite?
10% 15
90% 73

"10%" means that only about 10% of games will end in 15 moves or less. Similarly, "90%" means that 90% of games will end in 73 moves or less.

The maximum number of moves seems to be infinite. In a sample of 1 million games, the maximum number of moves was 399; after 2 million, it was 437. Maybe there's an asymptote, I don't know. In any case, I think it is practically impossible to be that unlucky. Update: Refer to esper's reply below for more details.

## The Code

This program merely dumps out raw data. Statistical analysis software sold separately. Batteries not included.

```=head1 NAME

Options:
-help           verbose help
-moves          verbose display of all moves
-games  int     number of games

Generate statistics for the "Chutes and Ladders" game by running a
user-specified number of games.  All metrics are for the winning playe
+r
on a standard 10x10 square game board.  All moves are for a single pla
+yer.

=over 4

=item moves

Use the C<-moves> option to display all individual moves for each game
+.

=item games

By default, one game is played.  To run more games, use the C<-games>
+option.

=item help

Show verbose usage information.

=back

Run 1000 games and dump the stats to an output file for further proces
+sing:

=cut

use strict;
use warnings FATAL => 'all';
#use diagnostics;
use Data::Dumper;
use Getopt::Long;
use Pod::Usage;

my \$games;
my \$verbose = 0;

my %special = (
#  Start
1  => {end =>  38, action => 'up ladder'},
4  => {end =>  14, action => 'up ladder'},
9  => {end =>  31, action => 'up ladder'},
21  => {end =>  42, action => 'up ladder'},
28  => {end =>  84, action => 'up ladder'},
36  => {end =>  44, action => 'up ladder'},
51  => {end =>  67, action => 'up ladder'},
71  => {end =>  91, action => 'up ladder'},
80  => {end => 100, action => 'up ladder'},
# Chutes
#  Start
16  => {end =>   6, action => 'down chute'},
48  => {end =>  26, action => 'down chute'},
49  => {end =>  11, action => 'down chute'},
56  => {end =>  53, action => 'down chute'},
62  => {end =>  19, action => 'down chute'},
64  => {end =>  60, action => 'down chute'},
87  => {end =>  24, action => 'down chute'},
93  => {end =>  73, action => 'down chute'},
95  => {end =>  75, action => 'down chute'},
98  => {end =>  78, action => 'down chute'}
);

parse_args();

for my \$i (1 .. \$games) {
game(\$i);
}

sub game {
my \$game = shift;
my %counts;
my \$mvcnt = 0;
my \$pos   = 0;
while (\$pos != 100) {
\$mvcnt++;
my \$spin = int(rand(6)) + 1;    # random spin (1-6)
my \$tmp  = \$pos + \$spin;
my \$msg  = sprintf 'mvcnt=%4d, spin=%1d, start=%2d, ', \$mvcnt,
+\$spin, \$pos;
\$counts{spin}{\$spin}++;
\$counts{move} = \$mvcnt;
my \$action;
if (\$tmp > 100) {
\$action = 'stay';
\$counts{stay}++
}
elsif (exists \$special{\$tmp}) {
\$pos    = \$special{\$tmp}{end};
\$action = \$special{\$tmp}{action};
\$counts{\$action}{\$tmp}++
}
else {
\$pos    = \$tmp;
}
\$msg .= sprintf 'end=%3d', \$pos;
print "\$msg (\$action)\n" if \$verbose;
}
print Dumper(\%counts);
# These may simplify parsing the output:
#for (keys %{\$counts{spin}}) {print "spin\$_ = \$counts{spin}{\$_}\n"}
#for (keys %{\$counts{'down chute'}}) {print "chute\$_  = \$counts{'do
+wn chute'}{\$_}\n"}
print "Game = \$game , Moves = \$mvcnt\n";
}

sub parse_args {
my \$help;
GetOptions(
'moves'   => \\$verbose,
'games=i' => \\$games,
'help'    => \\$help
) or pod2usage();

\$help and pod2usage(-verbose => 2);

\$games = 1 unless \$games;

@ARGV and pod2usage(-msg => "Error: unexpected args: @ARGV", -verbo
+se => 1);
}

Update July 1, 2009: Removed unused \$full variable in parse_args sub. Refer to wrinkles' node below.

## Other observations

• During the average game, the winner will climb 3.4 ladders and slide down 4.3 chutes.
• Not all ladders are created equal. It is more than three times as likely to climb ladder36 (most popular) than ladder1 (least).
• Nor are all chutes created equal. chute48 (most popular) is used three times as often as chute62 (least).
• Only 37% of games include staying put after a spin.
• Winning the game in the minimum number of moves (7) happens very rarely -- 1597 out of 1 million, or about 0.16%

Miscellaneous game characteristics:

• 100 squares
• 10 chutes
• A spin results in a random number between 1 and 6
• It is not possible to climb ladder1 or ladder80 more than once in a game. There are no such limits on the other ladders or any of the chutes.

## Typical Histogram

Here is a sample histogram of the number of moves for 1 million games:

```Number of samples in population: 1000000
Value range: 7 - 399
Mean value: 39
Median value: 33

< 7:      0
7 - 46: 698863
46 - 85: 238740
85 - 124:  49545
124 - 163:  10267
163 - 202:   2029
202 - 241:    436
241 - 280:     97
280 - 319:     17
319 - 358:      5
358 - 397:      0
>= 397:      1