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".
"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.
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.