=head1 NAME B - 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 player on a standard 10x10 square game board. All moves are for a single player. =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 processing: 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{'down 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", -verbose => 1); }