Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

A quandry in Towers of Hanoi

by pmonk4ever (Friar)
on May 14, 2009 at 23:50 UTC ( #764167=perlquestion: print w/ replies, xml ) Need Help??
pmonk4ever has asked for the wisdom of the Perl Monks concerning the following question:

Well, there's this implementation of the Towers of Hanoi that I 'thought' I liked, until on closer inspection I found is falling 4 moves short of a complete resolution.

I put in a $grandTotal variable to record the number of moves, and it consistantly came up 4 short.

So, here is the code:

#!C:\perl\bin use strict; #use warnings; # commented out because it throws a warning in the + middle #use diagnostics; # of execution, about @polea being uninitialized. +?? # Towers of Hanoi # Perl version (5.10.0) my $numdisks = 0; my $count = 0; my $grandTotal = 0; print "Number of disks? "; chomp( $numdisks = <STDIN> ); clear (); my $i = 0; my @polea = ""; my @poleb = ""; my @polec = ""; my $loop = 0; my $string = ""; while ($numdisks > $loop++) { $string = $string ."x"; push (@polea, $string); } print "A\t\t\tB\t\t\tC\n"; for (my $len = 0 ;$len <= $numdisks; $len++) { print "$polea[$len]\t\t\t$poleb[$len]\t\t\t$polec[$len]\n"; } sleep 1; movedisks( $numdisks, 'A', 'B', 'C' ); print "Total: ", $grandTotal, " \n"; # SUB LAND sub clear { if ($^O eq "MSWin32") { system 'cls'; }else{ system 'clear'; } } sub movedisks { my( $num, $from, $to, $aux ) = @_; if( $num == 1 ) { paintdisks ($num, $to, $from); }else{ movedisks( $num-1, $from, $aux, $to ); paintdisks ($num, $to, $from); movedisks( $num-1, $aux, $to, $from ); } } sub paintdisks { my( $numb, $dest, $source) = @_; my $foo = ""; if ($source eq "A") { $foo = $polea[0]; shift @polea; }elsif ($source eq "B") { $foo = $poleb[0]; shift @poleb; }else{ $foo = $polec[0]; shift @polec; } if ($dest eq "A") { unshift @polea, $foo; }elsif ($dest eq "B") { unshift @poleb, $foo; }else{ unshift @polec, $foo; } print "A\t\t\tB\t\t\tC\n"; for (my $len = 0 ;$len <= ($numdisks -1); $len++) { print "$polea[$len]\t\t\t$poleb[$len]\t\t\t$polec[$len]\n"; } $grandTotal ++; sleep 1; # clear (); commented out so I can see the execution! }

And the results:

Results of execution: Number of Disks: 3 A B C x xx xxx A B C x xx xxx A B C xx x xxx A B C xx << here it pushes a + space! xxx x A B C xxx xx x A B C << same here xx x xxx A B C x xxx xx A B C xxx << again here x xx Total: 7 # I'm at a loss # # Result that appears when use warnings & use diagnostics are uncommen +ted # A B C Use of uninitialized value in concatenation (.) or string at towers2.p +l line 29, <STDIN> line 1 (#1) (W uninitialized) An undefined value was used as if it were alread +y defined. It was interpreted as a "" or a 0, but maybe it was a mi +stake. To suppress this warning assign a defined value to your variables. To help you figure out what was undefined, perl will try to tell y +ou the name of the variable (if any) that was undefined. In some cases it + cannot do this, so it also tells you what operation you used the undefine +d value in. Note, however, that perl optimizes your program and the opera +tion displayed in the warning may not necessarily appear literally in y +our program. For example, "that $foo" is usually optimized into "that + " . $foo, and the warning will refer to the concatenation (.) operat +or, even though there is no . in your program. x xx xxx A B C x Use of uninitialized value in concatenation (.) or string at towers2.p +l line 79, <STDIN> line 1 (#1) xx xxx A B C xx x xxx Use of uninitialized value within @polea in concatenation (.) or strin +g at towers2.pl line 79, <STDIN> line 1 (#1) A B C xx xxx x A B C xxx xx x A B C xx x xxx A B C x xxx xx A B C xxx x xx Total: 7

So there are 2 questions I have not been able to figure out: 1) Why is the code pushing spaces? 2) Why does it fall short exactly 4 moves?

The reason I like the implementation is that it made the Tower alive for me, visually!

Therefore, Ladies, Gentlemen & Dragons, I await your musings with humble anticipation.

Update:

Thank you all for responding to my quandry! I have implemented the changes you recommended, and now the compiler is complaining about the following:

C:\Perl\working>perl towers2.pl Not enough arguments for map at towers2.pl line 32, near """)" Global symbol "$polea" requires explicit package name at towers2.pl li +ne 32. Global symbol "$poleb" requires explicit package name at towers2.pl li +ne 32. Global symbol "$polec" requires explicit package name at towers2.pl li +ne 32. Global symbol "$polea" requires explicit package name at towers2.pl li +ne 84. Global symbol "$poleb" requires explicit package name at towers2.pl li +ne 84. Global symbol "$polec" requires explicit package name at towers2.pl li +ne 84. Execution of towers2.pl aborted due to compilation errors (#1) (F) The function requires more arguments than you specified. Uncaught exception from user code: Not enough arguments for map at towers2.pl line 32, near """)" Global symbol "$polea" requires explicit package name at towers2.pl li +ne 32. Global symbol "$poleb" requires explicit package name at towers2.pl li +ne 32. Global symbol "$polec" requires explicit package name at towers2.pl li +ne 32. Global symbol "$polea" requires explicit package name at towers2.pl li +ne 84. Global symbol "$poleb" requires explicit package name at towers2.pl li +ne 84. Global symbol "$polec" requires explicit package name at towers2.pl li +ne 84. Execution of towers2.pl aborted due to compilation errors. at towers2.pl line 91

Here is Line 32 and surrounding code:

my $i = 0; #my @polea; #This was conflicting with the map initialization below my @poleb; my @polec; my $loop = 0; my $string = ""; #while ($numdisks > $loop++) { # $string = $string ."x"; # push (@polea, $string); #} my @polea = map 'x' x $_, 1 .. $numdisks; print "A\t\t\tB\t\t\tC\n"; for (my $len = 0 ;$len <= $numdisks; $len++) { # print "$polea[$len]\t\t\t$poleb[$len]\t\t\t$polec[$len]\n"; 32 print join "\t\t\t", map ($_->[$len] || ""), \$polea, \$poleb, \$p +olec; print "\n"; }

However, if I comment out lines 32 & 84, and use the origonal print statement, the script executes the moves correctly, and they are 7, without the spaces. Yes I still get the uninitialized warnings, which was why I initalized them to "" in the first place.

Another Update

After more study in the perldoc, I now have the following:

print join "\t\t\t", map {[$_]->[$len] || ""} \my $polea, \my $pol +eb, \my $polec; print "\n";

Which gives me the following results:

A B C x SCALAR(0x183ce7c) SCALAR(0x183ceac) SCALAR(0x183cecc) xx xxx xxxx xxxxx Total Moves: 31

Intriguing, no?

Sincerely,

ki6jux

"No trees were harmed in the creation of this node. However, a rather large number of electrons were somewhat inconvenienced."

Comment on A quandry in Towers of Hanoi
Select or Download Code
Re: A quandry in Towers of Hanoi
by jwkrahn (Monsignor) on May 15, 2009 at 00:06 UTC
    my @polea = ""; my @poleb = ""; my @polec = "";

    You are assigning an empty string to the first element of your arrays.   Just declare your arrays like this:

    my @polea; my @poleb; my @polec;
Re: A quandry in Towers of Hanoi
by tilly (Archbishop) on May 15, 2009 at 00:15 UTC
    Your bug is that you are initializing your arrays with:
    my @polea = ""; my @poleb = ""; my @polec = "";
    which means that they have invisible 0-width entries on top of each stack. Get rid of those and your bug goes away.

    Incidentally if you change the way you print slightly, you can turn warnings back on:

    for (my $len = 0 ;$len <= $numdisks; $len++) { print join "\t\t\t", map {$_->[$len] || ""} \@polea, \@poleb, \@po +lec; print "\n"; }
    (You have to change this in two locations.)
      Hi, tilly, thank you for your suggestion on the print statement, however, as you can see in my update, something's wrong. I looked up the 'map' function, but perldoc was not very helpful.

      ki6jux

      "No trees were harmed in the creation of this node. However, a rather large number of electrons were somewhat inconvenienced."

        I said \@polea to create a reference to your array while you said \$polea which creates a reference to a non-existent scalar. Hence the problem.

        Implement the print statement as I actually wrote it and the program will run correctly. Also see references quick reference if references are confusing you.

Re: A quandry in Towers of Hanoi
by jwkrahn (Monsignor) on May 15, 2009 at 00:24 UTC
    while ($numdisks > $loop++) { $string = $string ."x"; push (@polea, $string); }

    That could be written more simply as:

    my @polea = map 'x' x $_, 1 .. $numdisks;
      Hello jwkrahn,

      Thank you for your suggestion, it worked perfectly!

      ki6jux

      "No trees were harmed in the creation of this node. However, a rather large number of electrons were somewhat inconvenienced."

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://764167]
Approved by planetscape
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (13)
As of 2014-12-26 17:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (173 votes), past polls