Цикл Ruby не работает так, как я думал

Я новичок в программировании и только начал изучать Ruby. Я написал приведенную ниже программу, чтобы попрактиковаться в циклах, переменных и т. д. По сути, программа имитирует карточную машину для стирки, где пользователь может получить новую карту или загрузить значение в существующую карту. Принцип работы заключается в том, что он случайным образом выбирает значение карты: либо необходимо купить новую карту, либо иметь существующую карту с суммой X в $s.

Кажется, это работает, но у меня возникает проблема: когда пользователь пытается вернуться к экрану приветствия, а затем вводит значение, независимо от того, что вводит пользователь, он просто переходит непосредственно к отображению меню. В идеале он должен отображать «НЕВЕРНЫЙ ВВОД», если пользователь вводит что-либо, кроме «ввод». Я подозреваю, что я неправильно написал свой цикл.

Что я делаю неправильно?

Заранее спасибо, что нашли время прочитать и помочь :)

# Method that randomly generates either need for a card or existing card with balance between $1-25
def card_value
  # "NO CARD"
  arr = [nil, (1..25)]
  value = arr.sample
  if value == nil
    "NO CARD"
  else
    rand(value)
  end
end

# Variable assigned to return value of method card_value
balance = card_value

# Method that outputs a string when user input is incorrect
def invalid
  puts "INVALID RESPONSE"
end

# Method for main screen, prompts user to start
def welcome
  puts ""
  puts "*******************************"
  puts "  HERCULES ADD VALUE STATION"
  puts "          WELCOME"
  puts ""
  puts "        | Enter? |"
  puts "*******************************"
  puts "    Type Enter to continue:"
  puts "-------------------------------"
  puts ""
  start = gets.chomp
end

# Method that displays the need of a card or the card balance
def card_balance(balance)
  puts ""
  puts "-------------------------------"
  puts ""
  if balance == "NO CARD"
    puts "       |  #{balance}  |"
  else
    puts "    | BALANCE IS $#{balance}  |"
  end
  puts ""
  puts "-------------------------------"
  balance
end

# Method that displays the option screen, prompts user to get a card or add balance to card
def menu(balance)
  loop do
    card_balance(balance)
    puts ""
    puts "*******************************"
    puts "| NEW CARD? | or | ADD VALUE? |"
    puts "*******************************"
    puts "   Type '1' to buy new card"
    puts "   Type '2' to add value"
    puts "   Type 'X' to exit"
    puts "-------------------------------"
    puts ""

    buy_add = gets.chomp
    if buy_add == "1" && balance == "NO CARD"
      buy_card(balance)
    elsif buy_add == "2" && (balance.is_a? Integer)
      add_value(balance)
    elsif buy_add.upcase == "X"
      welcome
    else
      invalid
    end
  end
end

# Method that displays buy new card, prompts user to add money to buy card
def buy_card(balance)
  loop do
    puts ""
    puts "*******************************"
    puts "        |NEW CARD - $5|"
    puts "*******************************"
    puts "  Type '5' to purchase card"
    puts "  Type 'X' to exit"
    puts "-------------------------------"
    puts ""
    new_card = gets.chomp
    if new_card == "5" && balance == "NO CARD"
      puts ""
      puts "*******************************"
      puts "     |NEW CARD PURCHASED!|"
      puts "*******************************"
      balance = 0
      puts "BALANCE IS $#{balance}"
      balance
    elsif new_card == "5" && balance == 0
      puts "YOU ALREADY HAVE A CARD"
    elsif new_card.upcase == "X"
      menu(balance)
    else
      invalid
    end
  end
end

# Method that displays the options for loading card value, prompts user for amount and displays
# the updated balance
def add_value(balance)
  loop do
    puts ""
    puts "*******************************"
    puts "          |ADD VALUE|"
    puts "    |$15| |$35| |$50| |$75|"
    puts "*******************************"
    puts "    Type '15' to add $15"
    puts "    Type '35' to add $35"
    puts "    Type '50' to add $50"
    puts "    Type '75' to add $75"
    puts "    Type 'X' to exit"
    puts "-------------------------------"
    puts ""
    puts "BALANCE IS $#{balance}"
    add_more = gets.chomp
    if add_more == "15"
      new_balance = balance += 15
    elsif add_more == "35"
      new_balance = balance += 35
    elsif add_more == "50"
      new_balance = balance += 50
    elsif add_more == "75"
      new_balance = balance += 75
    elsif add_more.upcase == "X"
      menu(balance)
    else
      invalid
    end
    puts "NEW BALANCE = #{balance}"
  end 
end

loop do
  if welcome.downcase == "enter"
    menu(balance)
  else
    invalid
  end
end

Я думаю, что проблема заключается в :menu(balance).. но не могу понять, что делать.

Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
0
0
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

После входа в цикл menu он останется там навсегда, так как вы никогда из него не вырветесь.

Один из быстрых способов исправить это — использовать break после вызова экрана welcome, чтобы он возвращался к основному циклу в конце файла:

elsif buy_add.upcase == "X"
  welcome
  break

В этом отношении, всякий раз, когда вам нужно вернуться к родительскому/внешнему циклу, просто используйте break еще раз. Я вижу еще два случая в вашем коде: buy_card и add_value. Если вы добавите break в условие "X" на этих экранах, это должно исправить все застрявшие циклы.

И если вы проанализируете код еще немного, вы также обнаружите, что вызов «родительского» экрана и прерывание после него не исправляет еще одну скрытую ошибку, которая, как ни странно, представляет собой переполнение стека. Если вы продолжаете входить и выходить из экранов в течение длительного времени, через некоторое время стек переполнится, потому что вы продолжаете входить в циклы и вызывать новые функции, которые создают новые циклы и никогда фактически не завершают предыдущие циклы. Чтобы исправить это раз и навсегда, вы должны сделать что-то вроде:

elsif buy_add.upcase == "X"
  break

Что также следует воспроизвести в других "X" условиях и для других функций. Таким образом, после того, как пользователь введет «X», он просто завершит функцию и вернется к родительской/вызывающей функции.

В тех случаях, когда вы вызываете menu(balance), конечно, замена его только на break не приведет к обновлению баланса пользователя, поэтому вам нужно воспользоваться преимуществами работы функций, чтобы действительно правильно обновить баланс. Я бы посоветовал вам всегда return balance в конце любого подменю вместо использования break в таких случаях и обновлять баланс в функции menu, например balance = buy_card(balance). Я не буду раскрывать вам весь фиксированный фрагмент кода, но этого должно быть достаточно, чтобы вы могли начать отладку и исправление некоторых проблем, с которыми вы сталкиваетесь.

Это потрясающе – определенно есть над чем подумать. Большое спасибо, что нашли время ответить на мой вопрос.

pajeric_raval 27.08.2024 00:06

Другие вопросы по теме