3

I'm trying to get my if statement to catch when a person enters an input that says quit or exit but it isn't. Here is my code

use strict;
use warnings;
my $g=0;
my $rn = int(rand(25));
until ($g == $rn) {
      $g = <STDIN>;
      if ($g == $rn) {
            print "You got it";
            } elsif (chomp($g) eq "quit" || chomp($g) eq "exit") {
            print "it triggered";
            } elsif ($g > $rn) { 
            print "incorrect its lower";
            } elsif ($g <$rn) {
            print "incorrect its higher";
            } else {
            print "end";
            }      
}
}

The

elsif (chomp($g) eq "quit" || chomp($g) eq "exit) {

line is not catching despite numerous attempts to catch the error. I've tried printing off what the program is seeing to no avail. What I get in response when I type in quit from the strict/warnings is that

argument "quit\n" isn't numeric in numeric eq (==) at ./program24.pl line 30, <STDIN> line 1.
argument "quit" isn't numeric in numeric gt (>) at ./program24.pl line 36, line 1.

I've looked at several of the other posts on this but nothing from them seems to be whats causing this. What am I doing wrong?

masral
  • 69
  • 5
  • 5
    1) `chomp` doesn't return the chomped string; it modifies its argument in place. 2) Do the string comparison before the numerical comparison. 3) You don't handle EOF (`!defined($g)`). – ikegami Mar 25 '18 at 20:45

1 Answers1

5

The chomp command removes the trailing newline, but acts on the variable itself, its return value is the number of characters removed. So typically, one only needs to chomp a variable or an expression once. Since there are 2-types of comparison operators in perl, < <= == != >= > for numbers, lt le eq ne ge gt for strings, we should determine what kind of value we have before performing the comparison to avoid triggering a warning.

The $guess =~ m|^\d+$| statement returns true if $guess is a positive integer or 0, by checking that the stringified version of $guess is only made up of digits.

Since rand returns a decimal 0 <= x < 1 then rand 25 will return a number 0 <= x < 25 so 25 will never be reached. int will round the number down towards zero, so int rand 25 will return one of (0,1,2,...,22,23,24). To get (1,2,...,25) we need to add 1.

Single letter variables like $g are generally a bad idea, as they do not convey the meaning of the variable and make it more difficult to rename later if it becomes prevalent in the code. I have replaced it with $guess. In perl, the only generally accepted single letter variables are $a and $b which are global and used for comparison functions, and the perl predefined variables like $_, $@, etc. which are documented in perldoc perlvar

#!/usr/bin/perl

use strict;
use warnings;

my $guess = 0;
my $int_max = 25;
my $rn = int(rand($int_max)) + 1;

print "I have picked a number between 1 and $int_max, can you guess it?\n";
until ($guess == $rn) {
    chomp ($guess = <STDIN>);
    if ( $guess =~ m|^\d+$| ) {
        # Answer is an integer
        if ( $guess == $rn ) {
            print "You got it!\n";
        } elsif ( $guess > $rn ) {
            print "Too high, try again.\n";
        } elsif ( $guess < $rn ) {
            print "Too low, try again.\n";
        }
    } else {
        # Anything else
        if ('quit' eq $guess or 'exit' eq $guess) {
            print "Exiting...\n";
            exit 0;
        } else {
            print "Unclear answer : '$guess' : try again!\n";
            $guess = 0; # So the equality test does not warn
        }
    }
}
xxfelixxx
  • 6,512
  • 3
  • 31
  • 38