Plankton has asked for the wisdom of the Perl Monks concerning the following question:

Friends,

I am trying to automate my Tam's Chinese Peg Game. I can't seem to figure out what I am doing wrong here. I keep getting ...
 Can't call method "hasPeg" on unblessed reference at boardTree.pm line 40.
... errors. And I don't understand why.

Line 40 is this ...
if ( $jumper->hasPeg() ) {
... line of the sub makeLinks.
Please excuse me if this seems like too much code to post. But here is the entire boardTree.pm package.
package boardTree; use lib('.'); use board; use hole; use warnings; use diagnostics; use Data::Dumper; use strict; use Exporter; use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = (); @EXPORT_OK = qw( &new ); %EXPORT_TAGS = ( DEFAULT => [qw ( &new )] ); # # new - boardTree constructor # sub new { my ($pkg, $board, $index, $level, $links ) = @_; my $obj = bless { board => $board, index => defined( $index ) ? $index : 0, level => defined( $level ) ? $level : 0, links => defined( $links ) ? $links : [] }, $pkg; return $obj; } sub makeLinks { my $obj = shift; my $nextLevel = $obj->{'level'} + 1; print "nextLevel => $nextLevel\n"; for my $jumper ( $obj->{'board'}->getHoles() ) { print __FILE__ . " $jumper\n"; if ( $jumper->hasPeg() ) { for my $jumpy ( $jumper->getLinks() ) { my $rc = $jumpy->jumpingOver( $jumper->getIndex() ); if ( $rc > -1 ) { my @nholes = (); for ($obj->{'board'}->getHoles()) { my %newHole = %$_; push ( @nholes, \%newHole ); } $nholes[$jumpy->getIndex()]->{'peg'} = 'white'; $nholes[$jumper->getIndex()]->{'peg'} = 'white'; $nholes[$rc]->{'peg'} = 'black'; my $newBoard = new board( \@nholes, $nextLevel ); push( @{$obj->{'links'}}, new boardTree ( $newBoard, $obj->{'index'} + 1, $nextLevel, [] )); $obj->{'links'}[$obj->getNumLinks()-1]->makeLinks( +); } } } } } # # returns the links attribute # sub getLinks { my $obj = shift; return @{$obj->{'links'}}; } sub getNumLinks { my $obj = shift; return $#{@{$obj->{'links'}}} + 1; } # # print out the object # sub dumpPretty { my $obj = shift; print __FILE__ . "[" . __LINE__ . "] level => " . $obj->{'level'} +. ":\n"; $obj->{'board'}->dumpPretty(); print "\tno links = " . $obj->getNumLinks() . "\n"; for my $l ( $obj->getLinks() ) { $l->dumpPretty(); } }
I suspect I am not following the explantion of cloning of an array in Copying an Array of Hashes. I attempt to make a copy of a boards holes on these lines ...
my @nholes = (); for ($obj->{'board'}->getHoles()) { my %newHole = %$_; push ( @nholes, \%newHole ); } $nholes[$jumpy->getIndex()]->{'peg'} = 'white'; $nholes[$jumper->getIndex()]->{'peg'} = 'white'; $nholes[$rc]->{'peg'} = 'black'; my $newBoard = new board( \@nholes, $nextLevel );
... It seems to that @nholes is not getting into the $newBoard object correctly. Here is the output I am getting.

$ ./testBoardTree.pl 
Can't call method "hasPeg" on unblessed reference at boardTree.pm line 40 (#1)
    (F) A method call must know in what package it's supposed to run.  It
    ordinarily finds this out from the object reference you supply, but you
    didn't supply an object reference in this case.  A reference isn't an
    object reference until it has been blessed.  See perlobj.
    
Uncaught exception from user code:
        Can't call method "hasPeg" on unblessed reference at boardTree.pm line 40.
        boardTree::makeLinks('boardTree=HASH(0x193b930)') called at boardTree.pm line 60
        boardTree::makeLinks('boardTree=HASH(0x198c240)') called at ./testBoardTree.pl line 46
nextLevel => 2
boardTree.pm hole=HASH(0x19504ac)
boardTree.pm hole=HASH(0x195b27c)
boardTree.pm hole=HASH(0x1958a98)
boardTree.pm hole=HASH(0x1975a70)
boardTree.pm hole=HASH(0x1975c38)
boardTree.pm hole=HASH(0x193bc9c)
boardTree.pm hole=HASH(0x194d804)
boardTree.pm hole=HASH(0x198718c)
boardTree.pm hole=HASH(0x19833ac)
boardTree.pm hole=HASH(0x193aeb0)
boardTree.pm hole=HASH(0x196ceb8)
boardTree.pm hole=HASH(0x198724c)
nextLevel => 3
boardTree.pm HASH(0x193b4bc)
What do you think I am doing wrong? Note that for some reason at nextLevel => 3 hashes don't seem to be recognized as holes. I think this happens at the 1st level of recursion.

Plankton: 1% Evil, 99% Hot Gas.

Replies are listed 'Best First'.
Re: Can't call method "foo" on unblessed reference
by Roy Johnson (Monsignor) on Jun 16, 2004 at 17:43 UTC
    What does getHoles return? An array of objects?

    We're not really tightening our belts, it just feels that way because we're getting fatter.
      Yes getHoles returns an array of holes. At least I had hoped. Here's a shortened version of the board.pm where getHoles is defined.
      package board; ... use lib('.'); use hole; # # new - board constructor # # holes ) is an ref to a array of hole objects # This is not typically passed in to the # constructor. The constructor will build # the holes attribute $holes is not passed. # # level ) is also not typically used. # sub new { my ($pkg, $holes, $level) = @_; unless ( $holes ) { # # create the holes # ... } my $obj = bless { holes => $holes, # ref to array of holes level => defined( $level ) ? $level : 0 }, $pkg; return $obj; } sub getHoles { my $obj = shift; return wantarray ? @{$obj->{'holes'}} : $obj->{'holes'}; ... 1; }
      If you don't mind could you please take a look at Tam's Chinese Peg Game. That's should explain some of the why's and how's of data structures I am mangling. :)

      Plankton: 1% Evil, 99% Hot Gas.
        Within the code that you omitted:
        unless ( $holes ) { # # create the holes # ... }
        you call holes::new and insert it into @$holes? Is it possible for $obj->{'holes'} to return a reference to undef?

        Nothing else suggests itself at the moment.


        We're not really tightening our belts, it just feels that way because we're getting fatter.
Re: Can't call method "foo" on unblessed reference
by davidj (Priest) on Jun 16, 2004 at 17:49 UTC
    I believe your syntax for initializing your class is incorrect in sub new
    Try the following in its place

    sub new { my $class = shift; my $self = { }; bless($self, $class); $self->init(@_); return $self; } sub init { my $self = shift; my ($board, $index, $level, $links ) = @_; $self->{board} = $board; $self->{index} = defined( $index ) ? $index : 0; $self->{level} = defined( $level ) ? $level : 0; $self->{links} = defined( $links ) ? $links : []; }

    UPDATE
    my apologies for this post. I was not aware that the syntax used to init an object as used here was valid. I have always initted my objects in the way I provided. Many sorrows for the confusion.

    davidj
      I believe your syntax for initializing your class is incorrect in sub new
      Why? Its practically identical to what you wrote.
Re: Can't call method "foo" on unblessed reference
by halley (Prior) on Jun 16, 2004 at 19:02 UTC
    use Data::Dumper; print Dumper $jumper;
    Also, getting used to using the debugger will really help.

    --
    [ e d @ h a l l e y . c c ]