1

我写了一个简单的猜数字游戏。但即使我输入正确的数字,它也会一直循环。请帮忙,谢谢!

puts "Pick a number between 0 - 1000."
user_guess = gets.chomp.to_i

my_num = rand(831)
guess_count = 0

until user_guess == my_num do
  if user_guess == my_num
    guess_count += 1
    puts "you got it!"
  elsif  user_guess <= 830
    guess_count += 1
    puts "higher"
  else user_guess >= 1000
    guess_count += 1
    puts "lower"
  end 
end

puts "You guessed my number in #{guess_count} attempts. Not bad"
4

2 回答 2

1

正如@Tobias 已经回答了您的问题,我想花一些时间来建议您如何使您的代码更像 Ruby。

首先,虽然您可以使用whileoruntil循环,但我建议您主要依靠Kernel#loop方法来编写大多数循环。loop这只会导致循环在' 块内继续,直到break遇到关键字1。它很像while trueor until false(在某些语言中常用),但我认为它读起来更好。更重要的是,使用loop保护其块内的计算免受窥探。(有关这一点的示例,请参见下面的其他注意事项部分。)

您也可以通过执行or退出loop' 块,但通常您会使用. returnexitbreak

我的第二个主要建议是,对于此类问题,您使用 acase statement而不是if/elsif/else/end构造。让我们首先使用范围来做到这一点。

使用带范围的 case 语句

my_num = rand(831)
guess_count = 0

loop do
  print "Pick a number between 0 and 830: "
  guess_count += 1
  case gets.chomp.to_i
  when my_num
    puts "you got it!"
    break
  when 0..my_num-1
    puts "higher"
  else
    puts "lower"
  end
end

这里有几点需要注意。

  • 我使用print而不是puts这样,用户将在与提示相同的行上输入他们的响应。
  • guess_count无论用户的响应如何,都会递增,因此可以在执行 case 语句之前完成。
  • 无需将用户的响应 ( gets.chomp.to_i) 分配给变量。
  • case 语句将值与适当的大小写相等方法 ===进行比较。

关于最后一点,这里我们将一个整数 ( gets.chomp.to_i) 与另一个整数 ( my_num) 和一个范围进行比较(0..my_num-1)。在第一种情况下,Integer#===使用 ,相当于Integer#==。对于范围,使用Range#===方法。

例如,假设my_num = 100gets.chomp.to_i #=> 50case 语句如下所示。

case 50
when 100
  puts "you got it!"
  break
when 0..99
  puts "higher"
else
  puts "lower"
end

在这里,我们发现100 == 50 #=> false(0..99) === 50 #=> true,所以puts "higher"显示。(0..99) === 50返回true,因为整数(右侧===)被范围(左侧)覆盖。这与 不一样50 === (0..90),后者松散地读作“(0..99)是”的成员50因此false返回。

这里有几个例子,说明如何使用 case 语句来发挥优势,因为它们依赖于三等式方法。

case obj
when Integer
  obj + 10
when String
  obj.upcase
when Array
  obj.reverse
...
end

case str
when /\A#/
  puts "A comment"
when /\blaunch missiles\b/
  big_red_button.push
...
end 

对spaceship 运算符使用 case 语句 <=>

spaceship 运算符由 Ruby 的Array#sortEnumerable#sort方法使用,但还有其他用途,例如在 case 语句中。这里我们可以使用Integer#<=>来比较两个整数。

my_num = rand(831)
guess_count = 0

loop do
  print "Pick a number between 0 and 830: "
  case gets.chomp.to_i <=> my_num
  when 0
    puts "you got it!"
    break
  when -1         
    puts "higher"
  else # 1
    puts "lower"
  end
end

在其他应用程序中,宇宙飞船运算符可能用于比较字符串(String#<=>)、数组(Array#<=>)、Date对象(Date#<=>)等等。

使用哈希

哈希通常可以用作case statements. 在这里,我们可以编写以下内容。

response = { -1=>"higher", 0=>"you got it!", 1=>"lower" }
my_num = rand(831)
guess_count = 0

loop do
  print "Pick a number between 0 and 830: "
  guess = gets.chomp.to_i
  puts response[guess <=> my_num]
  break if guess == my_num
end

这里我们需要gets.chomp.to_i两次的值,所以我把它保存到一个变量中。

其他注意事项

假设我们编写以下内容:

i = 0
while i < 5
  i += 1
  j = i
end
j #=> 5

j在循环之后发现等于5

如果我们改为使用loop

i = 0
loop do
  i += 1
  j = i
  break if i == 5
end
j #=> NameError (undefined local variable or method 'j')

虽然whileloop都可以访问i, 但是loop将在其块中创建的局部变量的值限制在块中。那是因为块创建了一个新的范围,这是一种很好的编码习惯。while并且until不要使用块。我们通常不希望循环之后的代码能够访问在循环中创建的局部变量,这是支持andloop的原因之一。whileuntil

最后,关键字break也可以与由 . 返回的参数一起使用loop。例如:

def m
  i = 0
  loop do
    i += 1
    break 5*i if i == 10
  end
end

m #=> 50

或者

i = 0
n = loop do
  i += 1
  break 5*i if i == 10
end
n #=> 50

1. 如果您检查文档,Kernel#loop您会发现breakloop's 块内执行等同于引发StopIteration异常。

于 2020-01-12T07:39:30.253 回答
1

向用户询问数字的部分代码在循环之外,因此在检查答案后不会重复。如果您想在用户猜测错误时让用户再次猜测,则该代码需要在循环内。

my_num = rand(831)
guess_count = 0
keep_going = true


while keep_going do
  puts "Pick a number between 0 - 1000."
  user_guess = gets.chomp.to_i
  if user_guess == my_num
    guess_count += 1
    puts "you got it!"
    keep_going = false
  elsif  user_guess <= 830
    guess_count += 1
    puts "higher"
  else user_guess >= 1000
    guess_count += 1
    puts "lower"
  end 
end


puts "You guessed my number in #{guess_count} attempts. Not bad"

这段代码仍然有一些错误会阻止游戏正常运行,看看你是否能发现它们是什么。

于 2020-01-12T05:48:19.690 回答