我是Perl的新手并且已经获得了一个简单的猜谜游戏,用户有8次机会猜测1到100之间的数字。我不断得到上面提到的错误而无法弄明白
这是我的代码:
use Modern::Perl;
my ($guess,$target,$counter);
$target = (int rand 100) + 1;
while ($guess < $target)
{
chomp ($guess=<>);
print "Enter guess $counter: ";
$counter++;
if ($guess eq $target) {
print "\nCongratulations! You guessed the secret number $target in $counter";
}
elsif ($guess > $target) {
print "\nYour guess, $guess, is too high.";
}
elsif ($guess < $target) {
print "\nYour guess, $guess, is too low.";
}
else {
print "You lose. The number was $target.";
}
}
答案 0 :(得分:3)
您的代码遇到了一些问题。这是我的代码,使用不同的方法:
#!/usr/bin/perl
use 5.012; # use strict; use feature 'say';
use warnings;
my $number = (int rand 100) + 1;
my $max_guesses = 8;
GUESS: foreach my $guess_no (1..$max_guesses) {
say "($guess_no) Please enter a guess:";
my $guess = <>;
chomp $guess;
unless ($guess =~ /^\d+$/) {
say "Hey, that didn't look like a number!";
redo GUESS;
}
if ($guess == $number) {
say "Congrats, you were on target!";
last GUESS;
} elsif ($guess < $number) {
say "Nay, your guess was TOO SMALL.";
} elsif ($guess > $number) {
say "Nay, your guess was TOO BIG.";
} else {
die "Illegal state";
}
if ($guess_no == $max_guesses) {
say "However, you have wasted all your guesses. YOU LOOSE.";
last GUESS;
}
}
使用示例:
$ perl guess-the-number.pl
(1) Please enter a guess:
15
Nay, your guess was TOO SMALL.
(2) Please enter a guess:
60
Nay, your guess was TOO BIG.
(3) Please enter a guess:
45
Nay, your guess was TOO BIG.
(4) Please enter a guess:
30
Nay, your guess was TOO SMALL.
(5) Please enter a guess:
38
Congrats, you were on target!
(所有其他极端情况(太多猜测,非数字作为输入)按预期工作)
我做了哪些不同的事情?
while (1)
循环也会起作用。我使用正确的比较运算符。 Perl标量有两种形式:stringy和numeric:
Stringy Numeric
lt <
le <=
eq ==
ne !=
ge >=
gt >
cmp <=>
say
函数打印字符串print
,但附加换行符。这将删除字符串开头或结尾的akward \n
。它使阅读代码更容易。答案 1 :(得分:2)
你没有提到第25行是哪一行!这可能很重要。
但是,请查看您的while
声明。请注意,您要将$guess
与$target
进行比较,但尚未设置$guess
。这是设置 你是while
循环。这就是你得到未定义变量的原因。
我也看不到$counter
的设置位置。这也可能是一个问题。
让我们再看一下你的while
循环:
while ( $guess < $target ) {
blah, blah, blah
}
假设有一个$guess
,您将循环,直到用户猜到一个大于$target
的数字。那是你要的吗?不,你声明你想给用户八个回合,就是这样。你想要的是更多的东西:
my $count = 1;
while ( $count <= 8 ) {
$count++;
blah, blah, blah
}
这样做的一个更好的方法是使用for循环:
for ( my $count = 1; $count <= 8; $count++ ) {
blah, blah, blah
}
然而,这些C风格的for循环是如此过时。另外,使用1..8
语法有更清晰的方法。这与说(1, 2, 3, 4, 5, 6, 7, 8)
相同。它干净且易于理解:
for my $counter (1..8) {
blah, blah, blah
}
(注意:有些人在执行此类循环时使用foreach
关键字而不是for
关键字,以区别于C-Style for循环。有些人(咳嗽!Damian Conway,咳嗽!)对foreach
的使用不以为然,因为它并没有真正增加清晰度。)
让我们看一下你逻辑的另一个方面:
if ($guess eq $target) {
print "\nCongratulations! You guessed the secret number $target in $counter";
}
elsif ($guess > $target) {
print "\nYour guess, $guess, is too high.";
}
elsif ($guess < $target) {
print "\nYour guess, $guess, is too low.";
}
else { #Do this if the guess isn't equal to, greater than or less than the target
print "You lose. The number was $target.";
}
您的else
条款何时执行?答案永远不会。毕竟,除非$guess
不大于,等于或小于$target
,否则您不会执行此操作。此外,即使你输了,你仍然处于那个循环中。
您可能想要做的是将 You lose 行放在循环之外。这样,在第八次猜测和你的循环结束后,你得到你输了 spiel。
另外,让我们来看看这一行:
chomp ( $guess = <> );
print "Enter guess $counter: ";
首先,<>
是 null文件句柄操作符,它与<STDIN>
非常不同:
null文件句柄&lt;&gt;很特别:它可以用来模拟sed和awk的行为,以及任何其他带有文件名列表的Unix过滤器程序,对所有输入的每一行做同样的事情。来自&lt;&gt;的输入来自标准输入,或来自命令行中列出的每个文件。以下是它的工作原理:第一次&lt;&gt;如果进行评估,则检查@ARGV数组,如果为空,则将$ ARGV [0]设置为“ - ”,打开时会为您提供标准输入。然后将@ARGV数组作为文件名列表处理。
你想要的是<STDIN>
。
另请注意,在打印提示之前,您正在获取输入。你真的想这样做:
print "Enter guess $counter: ";
chomp ($guess = <STDIN>);
此外,您希望将$|
设置为非零值以关闭缓冲。否则,您可能仍需要在看到提示之前输入$guess
。
以下修改后的程序Modern::Perl
对我的系统不起作用,因此我使用三个单独的编译指示来覆盖它:
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
use constant {
UPPER_RANGE => 100,
MAX_GUESSES => 8,
};
$| = 1;
my $target = int ( ( rand UPPER_RANGE ) + 1 );
for my $counter (1..MAX_GUESSES) {
print "Enter guess #$counter: ";
chomp ( my $guess = <STDIN> );
if ($guess == $target) {
say "Congratulations! You guessed the secret number $target in $counter turns";
exit;
}
elsif ($guess > $target) {
say "Your guess, $guess, is too high.";
}
else {
say "Your guess, $guess, is too low.";
}
}
say "You lose. The number was $target.";
我没有涉及的一些事情:
==
运算符,而不是eq
字符串。say
代替print
。 say
命令与print
类似,不过它会自动为我添加一个NL。exit;
。我想在那时结束我的计划。$guess
和$counter
仅存在于for
循环内,而$target
循环内外均存在for
。use constant
以帮助避免神秘的号码。例如,1..MAX_GUESSES
帮助我理解循环是我的最大猜测,而1..8
无法解释为什么我要去8。而且,我可以简单地改变我的常数,突然间你有猜测数字在1到1000之间的10次更改。答案 2 :(得分:1)
这里的问题是您没有明确初始化变量。默认情况下,Perl会将您使用my()
创建的变量初始化为undef
值。因此,请查看脚本中的以下行:
my ($guess,$target,$counter);
此行创建三个变量,所有设置为undef
。有关my()
运算符的详细信息,请查看perlsub docs。以下是该文档页面的相关引用:
如果需要,可以将my()的参数列表分配给,允许 你初始化你的变量。 (如果没有给出初始化器 特殊变量,使用未定义的值创建。)