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

Hey guys i've created a game kind of thing which generates a random integer between 1 'n' 100. User has to guess it and at the end it saves the score in a file called high_score.dat. I had to edit the program so if an existing user, plays the game only his score his changed, but it doesn't work. It doesn't show any errors but it has a semantic error. Here's the code Please HELP ME:
open FILE, "high_score.dat"; while (1){ while defined($score = <FILE>){ print "$score\n"; } $num = int(1 + rand 100); print "If you want to exit type 'quit' or 'exit' or leave a blank +line\n"; INPUT_TAKER: { $count++; print "Guess a num: "; chomp ($guess = <STDIN>); if ($guess == $num) { print "Right!!!.\n"; print "enter youre name: "; chomp($name = <STDIN>); while defined ($line = (<FILE>)){ if ($line =~ /^($name)/){ $line =~ s/\d+$/$count/; } else{ open FILE, ">>high_score.dat"; print FILE "$name has the score of $count\n"; } } print "You took $count chances to complete\n"; } elsif ($guess =~ /^(exit||quit||\n)$/){ last; } elsif ($guess > $num){ print "High!!!. Go lower \n"; redo INPUT_TAKER; } elsif ($guess < $num){ print "Low!!!. Go higher \n"; redo INPUT_TAKER; } } if ($guess =~ /^exit||quit||\n$/){ last; } } print "Thank you for playing my game\n";

Replies are listed 'Best First'.
Re: Random numbers and substitution
by ig (Vicar) on May 31, 2011 at 09:07 UTC

    I haven't tried running your program, but I have a few suggestions for you to think about:

    At the beginning of your program you open high_score.dat, then each time through your loop you read until end of file. So, the first time through the loop you read all the lines in the file, stopping when you reach end of file. What do you think happens the second time through the loop? When you start the second iteration of the loop, where do you start reading the file?

    In your loop, after having read all the lines in the file, if the user guesses the correct name, you try to read more lines from the file. What do you think happens when you try to read a line from the file after having read all the way to the end of the file?

    If you find the name of the user in the file, you change the score in $line. That's data in memory. What do you think you have to do to get that string from the scalar variable in memory to the file?

Re: Random numbers and substitution
by Marshall (Canon) on May 31, 2011 at 09:19 UTC
    I've seen this assignment many times in many different beginning programming language classes. I doubt that you created this game on your own. If this is a homework assignment, say so. Also, please note that SHOUTING is frowned upon here.

    The basic problem with updating any disk file is that since it is fundamentally a sequential device (processes things in a serial order), you cannot just modify something in the middle of a single file. You cannot read and write to the same file at the same time when using variable length records. The easy solution for this problem is to read all of the file's data into memory. If the data needs to changed, then re-write the entire file. You can use either an array or a hash to store the data in memory.

    Past this issue, the problems with your code are legion. The use of a while(1) loop is just not appropriate here. That sort of thing appears in applications like servers. Here, you should strive to put the condition that causes the loop to exit in the while () condition. Improper loop design is at the root of this confusing mess. All of this labeled redo: stuff just goes away if the loop is designed correctly. Indenting and spacing are important in programming style.

    Another way to code this problem:

      The basic problem with updating any disk file is that since it is fundamentally a sequential device (processes things in a serial order), you cannot just modify something in the middle of a single file.
      Technically, that isn't true. There are file systems that provide record based files. And you may see DBfiles and database as record based files as well. Now, when you're talking about plain text files on most Unix and Windows based OSses, your claim is true. But that doesn't make it true for every file.
Re: Random numbers and substitution
by GrandFather (Saint) on May 31, 2011 at 21:11 UTC

    I haven't run your code either, but I did add strictures (always use strictures - use strict; use warnings;) and fixed the immediate problems. The first major problem in two places was:

    while defined (...) {

    which is simply broken syntax. while, for and if require () around their expression. Your while head should look like:

    while (defined ...) {

    I also changed your open to use a lexical file handle, to use the three parameter version of open, and checked the result. See the open line in the code below and compare it with your original version. These are things you should always do!

    I removed the needless INPUT_TAKER label, but I did add a Forever label on the outermost loop to avoid retesting the contents of guess.

    Having added strictures I needed to declare everything. Declaration and initialisation for scalar variables should pretty much always go together so in most cases that showed where things needed to be declared. In particular $count needs to be declared and initialised to 0 outside the guess loop.

    It bothers me that the file is opened as the first thing, but is read in a deeply nested loop. Something is wrong with the logic there. In fact the entire logic of the file handling eludes me, however it looks like you would be better using YAML as a light weight database, or get really serious and learn a little real database stuff using DBD::SQLite.

    My cleaned up, but otherwise uncorrected, version of your code is:

    #!/usr/bin/perl use strict; use warnings; my $scoreFile = "high_score.dat"; open my $inFile, '<', $scoreFile or die "Can't open $scoreFile: $!\n"; Forever: while (1) { while (defined(my $score = <$inFile>)) { print "$score\n"; } my $num = int(1 + rand 100); my $count = 0; print "If you want to exit type 'quit' or 'exit' or leave a blank +line\n"; while (1) { $count++; print "Guess a num: "; chomp(my $guess = <STDIN>); if ($guess == $num) { print "Right!!!.\n"; print "enter your name: "; chomp(my $name = <STDIN>); while (defined(my $line = <$inFile>)) { if ($line =~ /^($name)/) { $line =~ s/\d+$/$count/; } else { open $inFile, $scoreFile or die "Can't reopen $scoreFile: $!\n"; print $inFile "$name has the score of $count\n"; } } print "You took $count chances to complete\n"; next; } last Forever if $guess =~ /^(exit||quit||\n)$/; if ($guess > $num) { print "High!!!. Go lower \n"; } else { print "Low!!!. Go higher \n"; } redo; } } print "Thank you for playing my game\n";
    True laziness is hard work