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 B<chutes_n_ladders> - Stats for "Chutes and Ladders" game =head1 SYNOPSIS chutes_n_ladders [options] Options: -help verbose help -moves verbose display of all moves -games int number of games =head1 DESCRIPTION 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. =head1 OPTIONS =over 4 =item moves Use the C<-moves> option to display all individual moves for each game +. chutes_n_ladders -moves =item games By default, one game is played. To run more games, use the C<-games> +option. chutes_n_ladders -games 500 =item help Show verbose usage information. =back =head1 EXAMPLES Run 1000 games and dump the stats to an output file for further proces +sing: chutes_n_ladders -g 1000 > out.txt =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 = ( # Ladders # 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; $action = 'advance'; $counts{advance}++ } $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{'up ladder' }}) {print "ladder$_ = $counts{'up + ladder' }{$_}\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
  • 9 ladders
  • 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

What fascinating statistics can you dial up?

Replies are listed 'Best First'.
Re: Dial up some obscure stats for the Chutes and Ladders game
by Limbic~Region (Chancellor) on Jun 29, 2009 at 20:21 UTC
    toolic,
    You are not nearly geeky enough. This all assumes that you have a "fair" dial, that age and strength don't have a bearing on the outcome and that the behavior is uniform over time (wear and tear don't affect the results).

    Now if you were to do this MythBuster's style:

    1. Calculate the average force by applied by yourself and then your child
    2. Set up a robot that could apply that force in alternating spins
    3. Set up a web cam to snap pictures at regular intervals
    4. Write software to intepret the picture to both determine which number is landed on and when to trigger the robot (dial is not spinning)
    5. Let it run over a prolonged period of time
    6. Provide us all with the results and tell us if we can expect the same with our games at home

    This is way cool by the way!

    Cheers - L~R

      You are not nearly geeky enough.
      My wife would disagree. But, my son is young enough that he doesn't realize his father is one yet. I wonder how many years I have left before it dawns on him.
      This all assumes that you have a "fair" dial
      Don't get me started on the dial! The width of the line separating the numbers is comparable to the width of the arrow-head. This ambiguity forces far too many re-spins (that's harder to simulate with Perl :). Additionally, this ambiguity is a function of the person spinning the dial. My son claims he must re-spin when it is close and the number does not suit his needs!
        My son claims he must re-spin when it is close and the number does not suit his needs!

        Which you clearly agree with... meaning you are first Dad and only second geek. You may be in luck: your son may never discover you are a geek. You'll merely be his hero (at least until some long off Saturday night when you absolutely positively refuse to hand over the car keys - but that will be only temporary).

        Pretty cool to have a Dad serve up an entire post of obscure stats in honor of his son - I imagine in the next installment, you'll start hand-crafting computer games for him :-) There are many ways to love a child - all of them count.

        Best, beth

        The width of the line separating the numbers is comparable to the width of the arrow-head. This ambiguity forces far too many re-spins (that's harder to simulate with Perl :).

        Oh come on! (Width of line * number of lines) / ( 2 * pi * radius of arrow ) gives you a probability that a spin will land on a line. What's so hard about that? (I believe the width of the arrow point is irrelevant, or at least ignorable.)

        Additionally, this ambiguity is a function of the person spinning the dial. My son claims he must re-spin when it is close and the number does not suit his needs!

        So a per-player weighting factor needs to be applied to the above-mentioned probability. I will grant that assigning a "direction" to the weighting factor, based on the relative merits of two adjacent values on the dial, makes for a more challenging decision process.

        I know... there's a certain degree of general fatigue induced by parenting young children, and this tends to limit the amount of time and effort that can be expended on purely geek pursuits. Been there, done that.

        Maybe that's why we use a die. The chances of not hitting one of the 6 faces is too remote to worry about. You would have to account for die being thrown across room and under the sofa.

      you forgot the part where they rig the game with explosives just to blow something up :-)

Re: Dial up some obscure stats for the Chutes and Ladders game
by dsheroh (Monsignor) on Jun 30, 2009 at 10:09 UTC
    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.

    The maximum number of moves is infinite, provided sufficiently poor luck.

    Proof: Starting on square 6, it is possible to spin an infinite sequence of fives, causing you to slide down the 16 -> 6 chute an infinite number of times and resulting in an infinite number of moves.

    There are also several other infinite loops possible, due to the various chutes and the multiple sequences of spins that can take you from the bottom of any given chute to its top, but the 6-11-16 loop is the simplest to lay out.

    (Disclaimer: I do not have a copy of the board readily available, so I have inferred the board topology from the posted source code. If there is no 16 -> 6 chute, or if there is a chute/ladder on 11, the specific example used will not work, but the general principle remains.)

      Thanks for the clear explanation. I updated the OP with a link to your reply.
      I do not have a copy of the board readily available
      The wiki link in the OP includes a photograph of the board.

      Update: The wiki photo differs slightly from my game board at home (and the code posted in the OP): the wiki board has a chute that starts on square 47 and ends on 26; the chute in the code is 48-26.

Re: Dial up some obscure stats for the Chutes and Ladders game
by wol (Hermit) on Jul 02, 2009 at 10:49 UTC
    An avenue for investigation...

    If a player were to keep rolling the same number, where would they wind up?

    As the board is a finite size, there's only two possible kinds of answer, they'd wind up going round in circles, or they'd get to the end and (as this is a game for one) win.

    For example, if a player keeps rolling 1, then they'd get into a loop involving ladder 28=>84 and snake/chute 87=>24. (Caution: calculated using head, not Perl.)

    So what are the results for rolling only 2s .. 6s? Is it possible to win the game? Which number results in the most convoluted loop? Which number carries on longest before it gets into a loop.

    Grr - damn this paid employment lark! I have to stop before I can actually try any of this stuff out!

    --
    use JAPH;
    print JAPH::asString();

      Thanks for the ideas.

      You reminded me that I wanted to do some more analysis. While you are interested in infinity, I am still obsessed with ending the game in the minimum number of spins (7).

      In another sample of 1 million games, 1509 ended in 7 spins. Of those games, there were 421 unique sequences of 7 spins. Some sequences only occurred once (38 out of 421). Other sequences occurred multiple times, up to a maximum of 10 times.

      These 2 sequences occurred 10 times each: 4->3->6->5->6->5->5 1->4->4->5->5->4->4
Re: Dial up some obscure stats for the Chutes and Ladders game
by JavaFan (Canon) on Jul 04, 2009 at 00:44 UTC
    It is not possible to climb ladder1 or ladder80 more than once in a game.
    According to the wikipedia article you quote, a player who rolls 3 sixes in a row starts all over again. Which makes it possible to use ladder1 more than once.
    What fascinating statistics can you dial up?
    The same article says that a player rolls again after rolling a six. Which means you can finish in less than 7 turns. Perhaps you should make a histogram on turns as well.

    But the most important statistics is missing. The entire game is almost without decisions (except that you are allowed to skip a roll when rolling 6, and aren't forced to climb a ladder). Which leaves one big decision: do you go first, or second? Obviously, going first increases the chance of winning, but by how much? Said it differently, if you play chutes and ladders (2 player game), the loser paying the winner 1 USD, how much would you pay to go first?

      The wikipedia article indeed does mention those facts. But, it also mentions that there are other variants of the game. The version of the game I have at home has no such restrictions. This Perl code is based on the game manufactured by Hasbro (formerly Milton Bradley) in the United States in 1999. Your post has prompted me to do a little more web searching to find a site more specific to this version, including the rules. I apologize for the confusion.

      That being said, the variant you pointed out is slightly more complex, and hence, would make for more interesting analysis.

        In case of the simple rules, you can't get to the square 100 before the 7th turn:
        #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; my %special = ( ... ); # copy from the OP my %reachable = ( 0 => undef ); my $turn = 0; while (not exists $reachable{100}) { my %next; for my $square (keys %reachable) { for my $spin (1 .. 6) { my $target = $square + $spin; next if $target > 100; undef $next{$target}; undef $next{ $special{$target}{end} } if $special{$target} +; } } undef @reachable{ keys %next }; say ++$turn, ': ', join ' ', sort { $a <=> $b } keys %reachable; } say "$turn";
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Dial up some obscure stats for the Chutes and Ladders game
by Anonymous Monk on Feb 22, 2015 at 01:45 UTC
    What is the probability of running a game that uses no ladders or no chutes? I just played a game with my daughter in which I hit the initial ladder and then went chute/ladder free the rest of the way. At the same time, she did not hit a ladder until square 51 and a chute until she did so at square 98. Those were her only special squares.
      What is the probability of running a game that uses no ladders or no chutes?
      Winning games which use 0 ladders and 0 chutes: 1178 out of 1 million, or about 0.12%, which is rarer than winning the game in the minimum number of moves.
Re: Dial up some obscure stats for the Chutes and Ladders game
by wrinkles (Pilgrim) on Jul 01, 2009 at 10:11 UTC
    What is $full used for?
      Nothing. It is an unused variable. I was probably using it at one time, but forgot to remove it. As has been discussed many times here at the Monastery, there is no simple way to identify unused variables which have been declared with my.

      It is harmless, but I will update the code in the OP to remove the variable. Thanks for the good catch.