Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Number Guess

by cryptoquip (Novice)
on Jul 15, 2005 at 00:34 UTC ( [id://475097]=sourcecode: print w/replies, xml ) Need Help??
Category: Fun Stuff
Author/Contact Info cryptoquip jennyjo@gmail.com
Description: This is just a simple little guess-the-number game, and basically my first script after "Hello world." ;-) It works, but I'm sure it could be smoother. Comments welcome.
#Guessing Game
#You only get 10 tries!
#Gives the option of starting over.
#This version should count your turns for you, down from #ten.

TOP:
my $tries = 10;
#This is how many guesses you get.

my $value = int(rand(200));
#This is the number they have to guess: a random integer.

print "Pick a number between 0 and 200.\n";
print "You have ";
print $tries;
print " guesses left.\n";
$tries--;


my $guess = <STDIN>;

until ($tries==0){
    if($guess>$value){
    print "You need to guess a lower number.\n";
    print "Guesses left: ";    
    print $tries;
    print "\n";
    $tries--;
    $guess = <STDIN>;
    }elsif($guess<$value){
    print "You need to guess a higher number.\n";
    print "Guesses left: ";    
    print $tries;
    print "\n";
    $tries--;
    $guess = <STDIN>;
    }else{
    print "You guessed my number in ";
    print (10-$tries);
    print " guesses.  Thanks for playing. \n";
    $tries=0}
}

if ($guess != $value){
    print "Sorry, you ran out of guesses.  My number was ";
    print $value;
    print ". \n"; 
}

print "Play Again? (y/n) \n";

my $again = <STDIN>;

chomp ($again);

if($again eq "y"){
goto TOP;
}else{
print "Goodbye!";
}
Replies are listed 'Best First'.
Re: Number Guess
by Tanktalus (Canon) on Jul 15, 2005 at 02:08 UTC

    I remember doing this game when I was first learning in BASIC. And then the corrolary - you pick the number, the computer guesses it. I learned binary searches that day, without realising it. ;-)

    Comments:

    • use strict; use warnings; Always. Unless you know what you're doing.
    • Formatting. There are two major styles of braces. I'd suggest picking one. Although there can be religious wars on the topic of which one, and I have my preference as well, I'm not going to offer more advice than "just pick one".
    • Indentation. Whitespace is your friend. Make blocks of code easier to follow by lining up the left indent approprately.
    • Next is the use of goto. Although it has some uses, most of them are for advanced users only. As in, only once you've mastered not using goto can you give a reasonable justification for using it. At least, that's my opinion on using goto. In this case, you're using it to somewhat emulate a while loop. So just use a while loop, and people (like me) won't complain. To this end, I'd put the game itself into a "game" subroutine, and then be able to just wrap the call to the game sub in a small while loop.
    • Generally speaking, a single line of output is represented by a single print statement. Exceptions to this, unlike the exceptions to goto, are commonplace, however, so don't take this as a hard-and-fast rule or anything. For example, instead of
      print "Sorry, you ran out of guesses. My number was "; print $value; print ". \n";
      use
      print "Sorry, you ran out of guesses. My number was ", $value, ". +\n";
      Some people will use perl's interpolation to do this as:
      print "Sorry, you ran out of guesses. My number was $value.\n";
      The former may be faster, but in reality the deciding factor should be what you find to be more readable.
    • Comments ... should go before what they're commenting, not after. Code is not a suspense novel - you shouldn't need to wait to see what really is happening. Code should be extremely boring where the plot is revealed before anything happens.
    With all that in mind, here's your code with all of these changes. If you have any questions, don't hesitate to ask.

      Wow, truly the monks are wise and patient. Thanks for the great advice.

      Yes, I had some sense that goto might be a little hacky, but I didn't know how to use subroutines. Obviously, they are the magic answer I needed. Also, I did use strict and use warnings while I was working on this, but after I knew it would work, I didn't bother pasting them in here--why? Who knows; however, I now see the error of my ways.

      Looking at your for loop, I have a question. How does this handle the situation in which the player does successfully guess the answer in under ten tries? Since you have set the loop to run ten times, it looks like it will print "you have x guesses left" and wait for guess input even after you have won the game. I have just run the code and seen that this is not the case, but I can't figure out why. (Also, it looks like the "guesses left" line needs to be removed from the if statements, since you have put it at the top of the for loop. But this is a simple matter.)

      Here is another question: why do I have to chomp $again, but not chomp $guess?

        Question 1: guessing the answer in under 10 tries. The statement you missed is "return". It causes the subroutine to return to whoever called it immediately. All loops that it may be in at that point are automatically exited directly to the caller, bypassing any and all other statements in the subroutine.

        Question 2: chomping. Your $guess is a number. Perl's DWIMery trick with numbers is to treat anything that looks like a number as a number. So if you have a string such as "12afsd4583", perl will treat it as the number 12. e.g.,

        $ perl -e 'print 0+"12afsd4583";print $/' 12
        In your case, the string $guess really is "123\n". Perl sees the "123" part as a number, and then it sees stuff that isn't numeric and cuts it off at that point. So it will do an implicit 'chomp'-like action.

        However, with $again, you're comparing it with the eq operator. Perl can't know, based on string context, whether the \n is important or not, so you have to be explicit. Another way to avoid the chomp is to use a less-precise match, such as a regular expression, e.g., $again =~ /y/i will match anything with a 'y' or a 'Y' in the string, whether it's followed by a carriage return or not.

        BTW - I pointed out the strict comment because while I was rewriting your code (or, rather, mostly just reformatting), I came upon a problem that would have been caught sooner had strict been used. Not a problem in your code, but in an intermediate code between what you had and what I ended up with. ;-) Another advantage of using strict when it's not necessarily needed: adding features and refactoring become easier. Or at least safer. ;-)

      Just for kicks, here's my corrolary, where the computer guesses. It turned out a lot simpler. I'm trying harder to make it pretty, too.
      #The computer will try to guess your number. #Watch out! It knows if you're cheating. use strict; use warnings; sub game{ my $min=0; my $max=200; my $guess; my $response="h"; print "Think of a number between $min and $max, and I will guess wha +t it is. Type h if your number is higher than my guess, and type l i +f it is lower. Type = if I have guessed your number.\n"; while ($response ne "="){ if ((($max-$min)/2)<1){ print "You're not playing fair! I quit.\n"; return; } else{ $guess=int($max-(($max-$min)/2)); print "My guess is ",$guess,".\n"; $response = <STDIN>; chomp($response); if ($response eq "h"){ $min=$guess; } elsif ($response eq "l"){ $max=$guess; } } } } my $again = 'y'; while ($again eq 'y'){ game(); print "That was fun--no really, it was. Play again? (y/n) \n"; $again = <STDIN>; chomp ($again); } print "Goodbye!\n";
Re: Number Guess
by Pied (Monk) on Jul 15, 2005 at 06:46 UTC
    Here's how I rewrote your code, with some explanations. This is like to make your code look more perlish, though this is how *I* 'd see your code (with heavy comments).
    Should I code it myself, it would be different again...

    #!c:\perl\bin\perl.exe -w # -w means "warn me if I do anything that i may not want to do (ie: ma +ke a typo in a var name)" use strict; #Because God wants it my $guess; #declare it somewhere like here seems nice TOP: my $tries = 10; my $value = int(rand(200)); print "Pick a number between 0 and 200.\nYou have ",$tries--," guesses + left.\n"; #Do it in one line. #the $tries-- prints $tries and then, decrements it. while ($tries>0 and defined ($guess=<STDIN>)){ #since you reread $guess each time, why not write it just once? #then until became a while, so I inversed the $tries test too. #defined is used because the <STDIN> can be undefined... #put the $tries test first, so that it doesn't ask for input when yo +u're over next if $guess!~m/^\d+\n$/; #this might be a bit ugly right now #just learn this as "it is an integer followed by a carriage return" + #And then, read about regexps if($guess>$value){ print "You need to guess a lower number.\nGuesses left: ",$tries-- +,"\n"; next; # jump again to the while loop NOW #same hacks as above. } if($guess<$value){ print "You need to guess a higher number.\nGuesses left: ",$tries- +-,"\n"; next; #same hacks as above. } #beeing here means we didn't jumped before (the "next"'s were not ca +lled print "You guessed my number in ",(10-$tries)," guesses. Thanks for +playing.\n"; $tries=0; } print "Sorry, you ran out of guesses. My number was $value\n" if ($gu +ess != $value); #Since the test is a "simple" if (this) then {just that} #you can write just that if (this); #looks like English. Easy to read. print "Play Again? (y/n) \n"; chomp(my $again = <STDIN>); #chomp ($again); goto TOP if($again =~m/y/i);#I don't like goto, but that's your code. #=~ means check this var #m/foo/ means "does it contain the word foo" #i means case insensitive #once again, the if can be written easier #else not needed! print "Goodbye!";

    Once again, this is how *I* would see *your* code
    Read some nodes, read some tuts and docs, learn the idioms, and then you'll write your perlish perl code.

    P!
      Thanks for the comments--this looks elegant and useful. I'll take your advice and do more reading. :-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://475097]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (4)
As of 2024-04-25 13:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found