How can I stop Ruby if/elsif statement from looping? - ruby

I am teaching myself Ruby by making a small game in order to test out how I feel about the language. My code was going rather smoothly until I encountered a problem in which the first decision of the game loops instead of progressing forwards.
This code is what I have been using for a short part in the Exposition of my game.
def getup_or_sleep?
puts"Cole";
puts"----";
puts"Will you get up or go back to sleep?";
decision = gets
if decision == "sleep";
puts"Cole";
puts"----";
puts"You decide to go back sleep. It is far too early.";
elsif decision == "get up";
Exposition.stretch
else;
Exposition.getup_or_sleep?
end
This is the expected result I was hoping to achieve:
Cole
Will you get up or go back to sleep?
If player chooses 'sleep'
1)Cole
You decide to go back to sleep, it is far too early.
*I plan to make a new method to direct the user to, but I first want to fix this issue.
**if player chooses 'get up'
->>> to stretch method which is inside of the same class.
I'm new to coding so I may be confused on a few things. Thanks in advance! =)

Your method calls itself recursively because it all conditions fail, and it always falls back to the else branch.
This happens because gets reads input from the user and returns the input including the invisible newline character that is added when the user hits the enter key. But your conditions do not include such new line characters.
A common Ruby idiom is to call gets.chomp to get user input, where the chomp removes the newline character from the input.
Just change this line decision = gets to
decision = gets.chomp
to fix your issue.
Apart from that, your code isn't following Ruby idioms, for example, Ruby does not require a ; at the end of a line, or you usually add a whitespace between a method name and its argument, like in puts "Cole". Therefore, I suggest formatting your code like this:
def getup_or_sleep?
puts 'Cole'
puts '----'
puts 'Will you get up or go back to sleep?'
decision = gets.chomp
if decision == 'sleep'
puts 'Cole'
puts '----'
puts 'You decide to go back sleep. It is far too early.'
elsif decision == 'get up'
Exposition.stretch
else
Exposition.getup_or_sleep?
end
end
Or with a case block and some duplication extracted into a method:
def greeting
puts 'Cole'
puts '----'
end
def getup_or_sleep?
greeting
puts 'Will you get up or go back to sleep?'
case gets.chomp
when 'sleep'
greeting
puts 'You decide to go back sleep. It is far too early.'
when 'get up'
Exposition.stretch
else
Exposition.getup_or_sleep?
end
end

Related

(Ruby) while loop stops my code from running

I'm trying to run the following code (my goal was to make a "game" where i make two objects and have them "fight" each other):
#player definition
Player=Struct.new(:health, :dmg)
active_player=Player.new(10, 2)
puts "test"
#monster definition
class Monster
attr_accessor :health, :damage
def initialize(health, damage)
#health=health
#damage=damage
end
end
big_spider=Monster.new(4, 1)
player_win=false
monster_win=false
#the fight itself
while (!player_win) or (!monster_win)
big_spider.health-=active_player.dmg
active_player.health-=big_spider.damage
if big_spider.health<=0
player_win=true
elsif active_player.health<=0
monster_win=true
end
end
#prints out who wins
case monster_win
when true
puts "the monster wins"
when false
puts "the player wins"
else
puts "error"
end
gets.chomp #is there to ensure that the program doesn't exit immediately after execution(yes i have tried removing it)
When I try to run that code (from Windows 10 PowerShell) it prints out "test" and then stops as if it was asking for input, however when I try to type anything it doesn't appear on the screen and I can't react with PowerShell in any other way than closing/minimising it (I even try pressing Ctrl+D as when exiting irb). I tried running the code in many other ways (through Notepad++, from file explorer, and through cmd.exe), yet i still ran into the same problem. When I comment out the lines from the "the fight itself" comment to the end of the code the program prints out "test",then asks for input and then stops executing. I haven't really found anyone with a similar issue anywhere.
That loop spins until BOTH win. With your current code, this is impossible. You want to change it to something like
while !player_win && !monster_win
Personally, I prefer to write such loops like this:
loop do
break if player_win
break if monster_win
...
end

Why is my Ruby code not executing as I expect it to?

I'm learning Ruby through the book Learn to Program by Chris Pine. In the book, there's an exercise which says:
Write a Deaf Grandma program. Whatever you say to grandma (whatever you type in), she should respond with HUH?! SPEAK UP, SONNY!, unless you shout it (type in all capitals). If you shout, she can hear you (or at least she thinks so) and yells back, NO, NOT SINCE 1938! To make your program really believable, have grandma shout a different year each time; maybe any year at random between 1930 and 1950. (This part is optional, and would be much easier if you read the section on Ruby's random number generator at the end of the methods chapter.) You can't stop talking to grandma until you shout BYE.
Hint: Don't forget about chomp! 'BYE'with an Enter is not the same as 'BYE' without one!
Hint 2: Try to think about what parts of your program should happen over and over again. All of those should be in your while loop.
I have written my code and it doesn't work as expected. Basically, when I input information, it follows the order in which the code was written. For example if I input "HELLO" it'll reply "HUH?! SPEAK UP, SONNY! but really it should be writing back "NO, NOT SINCE 1938!".
When I input 'BYE' nothing will come up unless I follow the order in which the code was written in (I hope that makes sense).
I have tried a lot of things, like not using the break (for the loop). I have tried to write it as one long piece of code without any ifs or else's.
Here is the code I have written:
puts 'Go speak to Grandma, she\'s in the kitchen!'
speaking = gets.chomp
if speaking == speaking.downcase
puts 'HUH?! SPEAK UP, SONNY!'
gets.chomp
while speaking == 'BYE'
puts 'BYE! COME AGAIN SOON!'
gets.chomp
break
end
else speaking == speaking.upcase
puts 'NO, NOT SINCE 1983!'
gets.chomp
end
I expect when I write HELLO to get the appropriate answer of 'NO, NOT SINCE 1983!'. Also, I expect the conversation to keep going because I have used gets.chomp on all pieces of the code. Sp why is the code stopping?
Problem in the code is that if ... else condition not wrapped within loop, so it would no be executed repeatedly.
Hint 2: Try to think about what parts of your program should happen
over and over again. All of those should be in your while loop
To make loop works you need wrap all repeatable lines within loop.
In your case loop should break only when input will be BYE
puts 'Go speak to Grandma, she\'s in the kitchen!'
speaking = gets.chomp
until speaking == 'BYE'
if speaking == speaking.upcase
puts 'NO, NOT SINCE 1983!'
else
puts 'HUH?! SPEAK UP, SONNY!'
end
# Get input before next loop
speaking = gets.chomp
end
puts 'BYE! COME AGAIN SOON!'
You don't need to check for downcase explicitly, only you care about is "does input contains only upper case characters"

Sample ruby program keeps running with errors, can't figure them out [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Alright, I have tried my best to get this code to just run without spitting out errors, but to no avail. Hopefully you can help me out.
require 'launchy'
#def linebreak(breakline)
def program()
puts "Welcome to test program v1. Would you like to continue? ENTER y for Yes or n for no"
user_input_1 = gets.chomp
if user_input_1 == "y"
puts "How would you like to proceed CRASH | TEXTMAKER | UNDECIDED // CASE SENSITIVE"
user_input_2 = gets.chomp
if user_input_2 == "CRASH"
while true Launchy.open("http://google.com")
elsif user_input_2 = "TEXTMAKER"
while true out_file.puts("test program v1")
else
puts "You have not entered a method."
elsif user_input_1 == "n"
abort
else
puts "That is not a valid command. Please run the script again."
end
end
Alright there's a few problems, but don't worry everything can be
fixed!
Let's start with what you did well
Good job using your booleans in most cases, most beginners don't seem
to grasp that == means equal, and = means something completely
different
Good job with the puts and using it properly, there are other
methods which I will cover later, that will look much better in your
case.
Now let's cover what can be fixed
As I stated above in most cases you used your Boolean correctly
however you seem to have missed one. elsif user_input_2 = "TEXTMAKER" you need a == to show that it is equal.
Your while loop doesn't seem to make any sense because you don't ever really set anything as true. In Ruby it is highly
recommended to never use a while loop, of course there are times
that you have to, but only after you've tried everything else.
elsif; else; elsif never use an elsif after an else. elsif is to provide an exception, in your case there's more then
one option so use the elsifs before the else, you'd be better using a case statement here.
Not to sound like an ass, but your indentation is horrible. You'd find a lot more problems with good indentation, in Ruby that's two
spaces, here's the style guide:
https://github.com/bbatsov/ruby-style-guide
Never have your users options be case sensitive, if somebody else is going to use your program, just assume they are the dumbest people in the world and make it super easy for them. user_input_2.gets.chomp.upcase this will set it so that no matter how they enter their text, it will always be upper case.
You're missing an end this will become clear once you've used proper indentation
Alright let's rewrite this thing:
require 'launchy'
def program #<= you don't need the parentheses
print "Welcome to the test program version 1, to continue type 'c' to exit type 'e': "
user_input = gets.chomp.upcase
if user_input == "C"
program_choices
elsif user_input == "E"
puts "Exiting.."
exit
#if you really want to use abort
#abort("Exiting..")
#you won't need to use exit if you use abort
else
puts "Invalid input, try again"
program #<= this is a loop known as recursion, don't use it to much
end
end
def program_choices
print "Pick an option, the choices include CRASH | TEXTMAKER | UNDECIDED: "
user_input = gets.chomp.upcase
case user_input #<= this is how you start a case statement
when "CRASH"
Launchy.open("http://google.com")
when "TEXTMAKER"
write_test_data
when "UNDECIDED"
puts "You really need to make up your mind.." #<= have some fun with it, that's the point of programming.
program_choices
else
puts "Invalid input, try again"
program_choices
end
end
def write_test_data
x = "Test file version 1"
if File.exist?("path/to/test/file.txt")
File.open("path/to/test/file.txt", "a"){ |s| s.write(x) }
else
new_test_file = File.new("path/to/test/file.txt")
new_test_file.puts(x)
end
end
And bam! Your program is up and running! If you have any questions about anything don't hesitate to ask, programming can be very tricky, and it can be very hard. Keep it up and you'll get there!
I see plenty of problems.
This isn't valid:
while true Launchy.open("http://google.com")
Neither is this:
while true out_file.puts("test program v1")
I can't tell you how to fix this, though, since it's not at all clear what you're trying to do.
An if block may only have one else, and it must come after all elsifs.
Here:
elsif user_input_2 = "TEXTMAKER"
You're assigning a new value to user_input_2. I'm guessing you meant to use the equality operator, which is ==.
Your def block doesn't have an end. This became obvious after I edited your code to use proper indentation. You'll save yourself a lot of trouble by using sensible indentation and whitespace.

Simple Word Game Loop

# Guessing Game
# 1.0
# by Proto
words = ["cat", "snake", "wolf", "giraffe", "elephant"]
picked = words.sample
puts "Welcome to the guessing game! I'm thinking of an animal.
It's a #{picked.length} letter word. Can you guess what it is?"
try = gets.chomp
while try != picked
puts "Try again."
try = gets.chomp
if try == picked
puts "You win!"
break
end
end
It works but only sometimes and I get no errors from running it. The problem is that if I get the guess right on the first try, the game doesn't seem to enter the loop at all (it doesn't tell me "You win!"), it just exits the program. But that result is inconsistent. If i immediately restart and get it right sometimes it will tell me that I won. Sometimes it works, sometimes it doesn't. There seems to be something wrong with my loop or syntax, but I can't see it. Any help appreciated. Thanks.
Remove the if block and put the "You win!" statement outside the while statement. Reason being, eventually, in your current logic the player will win, and only then the logic breaks, so you might as well move it out.
while try != picked
puts "Try again."
try = gets.chomp
end
puts "You win!"
The reason the "You win!" is not printed in your existing code is that the loop is never entered when try == picked initially, because that is the condition in the while loop.
The above changes take care of that scenario as well.

What is provoking a strange 'break' after 'gets.chomp' in Ruby?

I am following this tutorial to create a text adventure but I am having trouble with the command prompt (a mere REPL): whenever I hit enter after the gets.chomp order that retrieves the user string, the program finishes unexpectedly returning no error.
This is the code for the console, a method for the Player class:
def play
loop do
do_look
print "> "
input = gets.chomp #The program seems to BREAK here.
puts "[DBG] input = #{input}"
command(input)
puts "[DBG] Command '#{input}' finished."
end
end
I used to think that it was something with the command method (the one that gets the first word as a verb and the rest as arguments so the player can say, f.e., go north); but after marking both methods with debug tags (puts "[DBG]...") I realized my program does not even print the line above command(input), so I guess something goes wrong after gets.chomp gets the string.
Do you have any idea about what is going on?
Note: the REPL is triggered this way:
$gamer = player
$gamer.play
puts "Program finished"

Resources