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

Well, I finally managed to make a script with no help from others! It is a silly "Guess the Random Number" game with no use except the experience of making it. If anyone wants to advise me of better ways to do the things I did, please feel free to respond!
The real reason for the post is that I can't understand why the subroutine was doing something. The second line of the sub is now my $numb=$_[0]; and works fine, but when it was $numb=@_; it always had 1 as the value no matter what was passed. Why was that so? What was happening?
TIA
jg
#!/usr/local/bin/perl -w use strict; srand; print "I have a number between 1 and 19.\nTry to guess it.\n"; my $number=int(rand(20)); guess_routine($number); sub guess_routine { my @guesses; my $numb=$_[0]; print "Guess?\n"; my $in=<STDIN>; chomp ($in); print "You said $in is the number.\n"; while ($in != $numb){ if ($in > $numb) { print "Too high! "; }else{ print "Too low! "; } push (@guesses, $in); @guesses = sort{$a <=> $b} @guesses; print "\nSo far you've guessed @guesses."; print "\nWhat is your guess?\n"; $in=<STDIN>; chomp ($in); } print "\nYes, $numb is the number!\n"; print "So you want another go?\n"; chomp(my $answer=<STDIN>); if ($answer =~/^y/i){ @guesses=""; print "\nI have a new number between 1 and 19.\nTry to guess i +t.\n"; $number=int(rand(20)); guess_routine($number); }else{ print "\nOK, bugger off then!\n"; exit 0; } }
_____________________________________________________
Ain't no time to hate! Barely time to wait! ~RH

Replies are listed 'Best First'.
Re: Reading an array with a single value (My 2nd completed script!)
by Masem (Monsignor) on Oct 01, 2001 at 17:58 UTC
    $numb=@_;, since the left hand side is a scalar, automatically looks to the scalar invokation of the right-hand side, which when it is an array, will be the size of that array. Which is why you got '1' back.

    $numb=$_[0] returns the scalar in the 1st position of the @_ array, which is what you wanted.

    You could have also done ($numb)=@_;, which , since the LHS is now an array, does an array evaluation of the RHS, and thus would set $numb to the first scalar in @_.

    -----------------------------------------------------
    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
    It's not what you know, but knowing how to find it if you don't know that's important

Re: Reading an array with a single value (My 2nd completed script!)
by Maclir (Curate) on Oct 01, 2001 at 18:05 UTC
    An alternative to the
    if ($in > $numb) { print "Too high! "; }else{ print "Too low! "; }
    construct is to use the trinary operator:
    print 'Too ', ($in > $numb) ? 'high!' : 'low!';
Re: Reading an array with a single value (My 2nd completed script!)
by higle (Chaplain) on Oct 01, 2001 at 17:59 UTC
    Whenever you assign a complete array to a scalar variable, e.g. my $foo = @baz; , the variable $foo will get the length or size of the array.

    Essentially, your scalar was getting the number of arguments passed to your subroutine.

    higle
Re: Reading an array with a single value (My 2nd completed script!)
by demerphq (Chancellor) on Oct 01, 2001 at 21:17 UTC
    Well jerrygarciuh,

    Other people have explained your problem with getting parameters, but I will revisit it for a moment. You need to take the time to grok list and scalar context. It is obvious to me from your code that you dont quite get this idea and its very important that you do. BTW this isnt a disrespect, context in this regard is a perl peculiarity, and it usually takes a while to really understand it. But it is one of the main things that make perl as rich and expressive a language as it is, and accordingly absolutely must be learned.

    Ok so on to the code. Ive read the posts that have been provided, suaveants is quite good, but both he and you overlooked a crucial issue, that is that if someone were to play your game over and over and over eventually your program would eat up all of the memory on your computer and crash. (Actually thats a lie, perl would first warn about deep recursion and then, I think :), terminate it before it affected overall system performance.)

    Basically your code calls itself. For no reason. This is bad. Recursion should only be used when there is a predetermined point where the routine will no longer recurse. In your code there is no such condition. It is up to the user when to stop the recursion, which could mean never. To be honest at your level of programming, again no disrespect, but you shouldn't be doing recursion at all. Recursion is a tricky subject with many subtleties, until you have mastered a lot of other stuff, especially iteration first.

    So here is suaveants edited version of your code, fixed to remove the recursion

    #!/usr/local/bin/perl use strict; use warnings; srand; # moved subroutine calls to _after_ their declarations, not necessary, + but a good # habit that can avoid nasty bugs in more complicated scenarios. # this also means that input being an auxilliary sub to guess_routine +needs to go # before it sub input { my $arrayref=shift; print "\nSo far you've guessed @$arrayref." if $arrayref; print "\nWhat is your guess?\n"; my $in=<STDIN>; chomp ($in); $in } sub guess_routine { my $done=0; until ($done) { my @guesses; print "I have a number from 0 to 19 inclusive.\nTry to guess i +t.\n"; my $numb=int(rand(20)); my $in = input(); while ($in != $numb){ print($in > $numb ? 'Too high! ' : 'Too low! '); # moved to trinary operator, just shrinks up # code, if else isn't bad @guesses = sort{$a <=> $b} (@guesses,$in); # you were pushing onto the array, then sorting # simply sorting array and value together shoule # be more efficient $in = input(\@guesses); # created a subroutine for # this, since you had similar code in two places. } print "\nYes, $numb is the number!\n"; print "So you want another go?\n"; my $answer=<STDIN>; # no chomp, you check /^y/ chomp unecessar +y if ($answer !~/^y/i){ print "\nOK, bugger off then!\n"; $done=1; } } } guess_routine(); #moved the print and rand into the routine # that way you don't have the code duplicated when user # says y for new game...
    Incidentally I've also fixed a couple of other minor points in the code. One would be that you are not producing a number 'between 1 and 19' but rather a number from 0 to 19 inclusive. Or 0<=$num<=19. The other would be that exit 0 is unnecessary in this situation (actually it was necessary because you were using recursion, which is an indication that you were doing something wrong.) Now when the user decides not to play another game the subroutine terminates and then so does the script.

    Now a minor point jerrygarciuh but you _really_ aught to sit down and go through either perlman:perltoot or perlman:perlboot. While these are both ultimately aimed at object oriented perl, they are excellent perl tutorials in general. If you sit down and work through these two documents you will learn 10000 times more than you will by asking questions here. Dont get me wrong, I've watched your progress here and im not trying to discourage you, but working through the tutorials will lead you to answer many of your own questions which is a much better way to learn. Of course I and many of the other monks will be happy as always to help you out with any questions that these tutorial might raise.

    Yves
    --
    You are not ready to use symrefs unless you already know why they are bad. -- tadmc (CLPM)

Re: Reading an array with a single value (My 2nd completed script!)
by suaveant (Parson) on Oct 01, 2001 at 18:22 UTC
    ok... Here is my edit...
    #!/usr/local/bin/perl -w use strict; srand; guess_routine(); #moved the print and rand into the routine # that way you don't have the code duplicated when user # says y for new game... sub guess_routine { my @guesses; print "I have a number between 1 and 19.\nTry to guess it.\n"; my $numb=int(rand(20)); my $in = input(); while ($in != $numb){ print($in > $numb ? 'Too high! ' : 'Too low! '); # moved to trinary operator, just shrinks up # code, if else isn't bad @guesses = sort{$a <=> $b} (@guesses,$in); # you were pushing onto the array, then sorting # simply sorting array and value together shoule # be more efficient $in = input(\@guesses); # created a subroutine for # this, since you had similar code in two places. } print "\nYes, $numb is the number!\n"; print "So you want another go?\n"; my $answer=<STDIN>; # no chomp, you check /^y/ chomp unecessary if ($answer =~/^y/i){ guess_routine(); } else { print "\nOK, bugger off then!\n"; exit 0; } } sub input { my $in; print "\nSo far you've guessed @{$_[0]}." if $_[0]; print "\nWhat is your guess?\n"; $in=<STDIN>; chomp ($in); $in }

                    - Ant
                    - Some of my best work - Fish Dinner

Re: Reading an array with a single value (My 2nd completed script!)
by cricket (Acolyte) on Oct 01, 2001 at 20:46 UTC
    also, you use this nice short-ification:
    chomp(my $answer=<STDIN>);
    in one place, but not in others. so (using suaveant's good suggestion for an additional subroutine to handle a repeated task), it would look like:
    chomp ( $in=<STDIN> );
    since most of the time when you get user input you're going to want to remove the newline, i like doing it all on one line.