(disk): (peg from) -> (peg to)
####
$ ./hanoi.pl 3 3
1: A -> B
2: A -> C
1: B -> C
3: A -> B
1: C -> A
2: C -> B
1: A -> B
##
##
#! /usr/bin/perl -w
use strict;
use Getopt::Long;
use Pod::Usage;
GetOptions(
'pegs=i' => \ my $peg_count,
'disks=i' => \ my $disk_count,
'program=s' => \ my $program,
'verbose' => \ my $verbose,
'prompt' => \ my $prompt,
'help' => \ my $help,
) or pod2usage(2);
pod2usage(1) if $help;
$verbose ||= $prompt;
$peg_count ||= 3;
$disk_count ||= 4;
$program ||= "./hanoi.pl";
my @pegs;
my %disks;
my $peg = 'A';
for (1..$peg_count) {
push @pegs, $peg;
$disks{$peg} = [];
$peg++;
}
$disks{A} = [reverse 1..$disk_count];
open (PIPE, "$program $peg_count $disk_count |")
or die "Cannot run '$program': $!";
my $move = 0;
while () {
chomp;
$move++;
print "Move $move: $_\n" if $verbose;
die "Move $move: Invalid input '$_'\n"
unless (/(\d+):\s*(\w+)\s*->\s*(\w+)/);
my $disk = $1;
my $from = $2;
my $to = $3;
die "Peg '$from' not found on move $move\n"
unless exists $disks{$from};
my $pile_from = $disks{$from};
die "Disk $disk is not on top of peg '$from' at move $move\n"
unless $pile_from->[-1] == $disk;
die "Peg '$to' not found on move $move\n"
unless exists $disks{$to};
my $pile_to = $disks{$to};
if (@$pile_to) {
my $top = $pile_to->[-1];
die "Disk $disk cannot go on top of disk $top at move $move\n"
unless $disk < $top;
}
pop @$pile_from;
if ($verbose) {
foreach my $peg (@pegs) {
print join " ", "$peg ", @{$disks{$peg}};
print " -" if $peg eq $from;
print " +$disk" if $peg eq $to;
print "\n";
}
if ($prompt) {
;
}
else {
print "\n";
}
}
push @$pile_to, $disk;
}
my @with_disks = grep {@{ $disks{$_} }} @pegs;
if (1 == @with_disks and $with_disks[0] eq 'B') {
print "Solved in $move moves\n";
}
else {
die "Not solved after $move moves\n";
}
__END__
=head1 NAME
hanoi-driver.pl
=head1 SYNPOSIS
hanoi-driver.pl [opts]
=head1 OPTIONS
-h --help Print help and exit
--pegs INT How many pegs to have. Default 3.
--disks INT How many disks to have. Default 4.
--program STR What test program to run. Default ./hanoi.pl.
-v --verbose Keep a running commentary up about each step
--prompt Wait for STDIN on each step. Implies verbose.
=head1 DESCRIPTION
Test driver for programs that solve the hanoi puzzle. It will
execute the program, study the output, die if any impossible
moves get made or the puzzle is not solved properly, and then
report how many steps it took.
If you set verbose mode it will show the game being played.
=head1 EXAMPLES
This will execute "./hanoi.pl 3 4" and expect to see a
solution to the hanoi puzzle with 3 pegs and 4 disks.
./hanoi-driver.pl
This will execute "./hanoi.pl 3 4" and expect to see a
solution to the hanoi puzzle with 3 pegs and 4 disks.
The output will play the solution out.
This will execute "./another_program" and expect to see a
solution to the hanoi puzzle with 5 pegs and 15 disks.
./hanoi-driver.pl --program=./another_program --pegs=5 --disks=15
=head1 AUTHOR
Ben Tilly (tilly on perlmonks)