Category: Fun Stuff
Author/Contact Info sulfericacid sulfericacid@qwest.net
Description: Generates a random (or semi-random) number based on user's inputted $max. Object of game is to guess the number before your chances run out (default set at 5). Games completed, won and lost are stored into a database and presented to the user after each game.

# Small bug fixed: Thanks Enlil!
# Indents fixed: PerlTidy saved the day

From this script I learned: naked blocks (which are a total life saver), the easier way to increment database variables and furthered my experience with regex (as scary as that is).
#!/usr/bin/perl -W

use strict;
use warnings;
use POSIX;
use Fcntl;
use SDBM_File;

my %dbm;
my $test = "game.dbm";
my $win  = 0;
my ( $total, $wonpercent, $lostpercent );

tie( %dbm, 'SDBM_File', $test, O_CREAT | O_RDWR, 0644 )
  || die "Died tying database\nReason: $!";

unless ( exists $dbm{win} )  { $dbm{win}  = 0 }
unless ( exists $dbm{lost} ) { $dbm{lost} = 0 }

# max = maximum number to randomize
# tries = # of tries not to exceed $allowed
# allowed = max number of tries allowed

my $tries = 0;
my $guess;
my $allowed = 5;

print "What's the highest number you want to try?\n";
chomp( my $max = <STDIN> );
my $answer = int( rand($max) ) + 1;

while ( $tries < $allowed ) {

    print "  Your guess:  ";
    chomp( $guess = <STDIN> );
    $tries++;

    if ( $guess eq $answer ) {
        last;
    }
    elsif ( $guess > $answer ) {
        print "                 $guess is too high!\n";
    }
    elsif ( $guess < $answer ) {
        print "                 $guess is too low!\n";
    }
}

if ( $guess eq $answer ) {
    print "\nYou got it right!\n";
    print "It only took you $tries tries!\n";

    $dbm{won}++;
    $dbm{total}++;    # for stats
}
else {
    print "\n You lose!  You're only allowed $allowed guesses :(\n";
    print "Answer was: $answer\n";

    $dbm{lost}++;
    $dbm{total}++;    # for stats

}

print "-----------------------------------------\n";

print "Total games played: $dbm{total}\n";
$wonpercent  = ( $dbm{won} / $dbm{total} ) * 100;
$lostpercent = ( $dbm{lost} / $dbm{total} ) * 100;

print "Games won: $dbm{won}\n";
print "Games lost: $dbm{lost}\n";

printf( "Percent won: %.0f\n",  $wonpercent );
printf( "Percent lost: %.0f\n", $lostpercent );

print "-----------------------------------------\n";
Replies are listed 'Best First'.
Re: Guess A Number
by jasonk (Parson) on Mar 17, 2003 at 15:06 UTC

    Other than the fact that your indenting style is very hard to read, the only problem I can see with your code (which won't actually hurt this script, but may cause you problems in the future if you keep doing it) is that 'eq' is a string comparison operator, if you want a numeric comparison you should be using '=='.


    We're not surrounded, we're in a target-rich environment!
      I appologize for the indending, people have been telling me lately it makes it all look funny and harder to read. I can't figure out the best way to indent anything so I'm stuck with what I got for the time being, sorry. == and eq always confused me and since it didn't show up as an error with the script I thought it was a lucky guess. On the next script update I'll change everything

      Thanks

      "Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

      sulfericacid
        Typical indenting styles indent a specified amount within every control structure. The specified amount is usually one of 2, 3, and 4 spaces. People also vary on the placement of braces.

        Whatever you do, the key is to pick a style and then be consistent. Mixing and matching and random indentation makes your code much harder to work with.

        If you are too lazy to pick a style, you can just download perltidy, run it on your scripts, and then accept the way that it does things.

        Hi sulfericacid
        If you use appropriate code-editor it will indent for you automatically as you type. I use emacs, and it works very well. Besides indenting there are lots of other features in emacs, like auto-typing , hiding certain code while developing, auto-ftp etc..

        example for indentation from your code:

        while ($tries < $allowed) { print " Your guess: "; chomp($guess = <STDIN>); $tries++; if ($guess eq $answer) { last; } elsif ($guess > $answer) { print " $guess is too high!\n"; } elsif ($guess < $answer) { print " $guess is too low!\n"; } }

        If you like to use emacs visit:http://www.gnu.org/software/emacs/. It's worth investment of time.

        One more point, make your code little modular. That would increase the readability also.

        artist

Re: Guess A Number
by parv (Parson) on Mar 17, 2003 at 18:00 UTC

    If a number is guessed right on the 1st try, that would be try number 1, not 0. Right? In that case, number of tries in the output should reflect reality...

    ... if ($guess == $answer) { printf "\nYou got it right!\nIt took you only %u tries.\n" , ++$tries; ...

    Personally, i don't like the fact that $dbm{total}++ happens at two different places. You could move it out of the if..else structure (before or after).

    At the end, there are just way too many print statements. What do you think of replacing them w/ "here document"?

    Since you are saving the percentages in variables and lost percentage w/ won percentage make 100, you could just subtract one from 100 to calculate the other instead of doing the same calculation twice. If you were not temporarily storing the percentages, then you would have to calculate the two percentages individually.

Re: Guess A Number
by MrYoya (Monk) on Mar 17, 2003 at 19:00 UTC
    This program looks like a good exercise to learn on. I noticed that at the beginning of the program you initialize $dbm{win} and later use $dbm{won}, resulting in an uninitialized value warning.

    Another idea for improvement is to put the input in a loop and only exit the loop upon receiving the proper input. This is one way:

    my $max; chomp($max = <STDIN>) while(not defined $max && $max =~ m/^[0-9]+$/); my $answer = int(rand($max))+1;
      All these little programs are made for learning, and something like this is fun to play with so it's killing two birds with one stone, lol. Thanks for the correction of $dbm{won}, that was changed.

      "Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

      sulfericacid
Re: Guess A Number
by parv (Parson) on Mar 17, 2003 at 22:47 UTC

    A side note (since the expected range of randam number is missing or i have missed it)...

    my $answer = int(rand($max)) + 1;

    ...$answer lies in [1,$max], and w/ this...

    my $answer = int(rand($max + 1));

    ...produces $answer in [0,$max]. (Just thinking outloud.)

    Duplicate: Ah crap! The similar post above should not have been there. Please ignore that.

      This message kind of confuses me, too many variables and things to think about in the lines, lol. I believe I did test my version of int(rand($max)) + 1); with a range of 10 and it did randomly generate the top number (10) atleast once. I will check again just to be sure though.

      Thanks.

      "Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

      sulfericacid