Ruby пока l oop повторяется независимо от ввода - PullRequest
1 голос
/ 12 января 2020

Я написал простую догадку числовую игру. Но он продолжает работать, даже когда я ввожу правильный номер. Пожалуйста, помогите, спасибо!

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"

Ответы [ 2 ]

1 голос
/ 12 января 2020

Поскольку @Tobias ответил на ваш вопрос, я хотел бы потратить некоторое время, чтобы предложить, как вы могли бы сделать свой код более Ruby -подобным.

Во-первых, в то время как вы могли бы использовать while или until l oop, я предлагаю вам полагаться в основном на метод Kernel # l oop для большинства циклов, которые вы напишите. Это просто заставляет цикл продолжаться в пределах блока loop, пока не будет найдено ключевое слово break 1 . Это очень похоже на while true или until false (обычно используется в некоторых языках), но я думаю, что это читается лучше. Что еще более важно, использование loop защищает вычисления в его блоке от посторонних глаз. (См. Раздел Другие соображения ниже для примера этой точки.)

Вы также можете выйти из блока loop, выполнив return или exit, но обычно вы будет использовать break.

Мое второе основное предложение заключается в том, что для этого типа проблемы вы используете case 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 = 100 и gets.chomp.to_i #=> 50 В этом случае выражение case читается следующим образом.

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 

Использование оператор case с оператором космического корабля <=>

оператор космического корабля используется Ruby '* Array # sort и Enumerable # Сортировать методов, но имеет другое применение, как в случае операторов. Здесь мы можем использовать 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 # <=> ) и т. Д.

Используйте ха sh

Хэши часто можно использовать в качестве альтернативы 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 после l oop равно 5.

Если вместо этого использовать loop:

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

Хотя while и loop оба имеют доступ к i, но loop ограничивает значения локальных переменных, созданных в его блоке, блоком. Это потому, что блоки создают новый scope , что является хорошей практикой кодирования. while и until не используют блоки. Обычно мы не хотим, чтобы код, следующий за l oop, имел доступ к локальным переменным, созданным в l oop, что является одной из причин предпочтения loop над while и until.

* 1153. * Наконец, ключевое слово 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. Если вы изучите do c для Kernel#loop, вы увидите, что выполнение break из блока loop эквивалентно вызову исключения StopIteration.

1 голос
/ 12 января 2020

Часть кода, которая запрашивает у пользователя число, находится за пределами l oop, поэтому она не будет повторяться после проверки ответа. Если вы хотите попросить пользователя угадать снова, когда его угадать неверно, этот код должен быть внутри l oop.

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"

В этом коде все еще есть ошибки, которые мешают игре хотя работает правильно, посмотрим, сможете ли вы определить, кто они.

...