Test for repeated gets.chomp input in Ruby - ruby

I am working in Ruby, and I am trying to test for a user's input (the variable kid) being the same three times.
I want my method speak to be called on endlessly until the user enters "BYE" three separate times when asked the three separate questions.
Right now, if the user inputs "BYE" even only for one question the entire conversation between the terminal and user ends.
Is there a way to have the program test for "BYE" being said three times, and only once said three separate times, have the conversation end?
kid = gets.chomp
unless kid == "BYE"
speak
end
I don't know if there is a really simple solution or only a complex one, but any answers help.

You need to keep track of how many times the user has input "BYE". When that number reaches 3 you exit:
byecount = 0
while kid = gets.chomp
case kid
when "BYE"
#increase the count of bye
byecount +=1
puts byecount
break if byecount == 3
else
#reset our count
byecount = 0
speak
end
end
The code resets to 0 on a non "BYE" answer.
I find a case statement to be very handy in situations like this when dealing with different user input, especially coupled with regular expressions.

I suggest looking for a ruby tutorial about "loops" and "control flow".
I think the Ruby Primer lesson at rubymonk.com may have what you need.
This example may also be helpful:
times = 0 # keep track of iterations
while times < 10 # repeatedly, while this condition is true
puts "hello!" # output "hello!"
times += 1 # increase count of iterations
end

Related

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

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

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"

Case statement don't work

I'm learning Ruby from "Programming Ruby, The Pragmatic Programmers(2nd, 2005)" and I'm stuck in the Case statement chapter.
So i copy-paste some code in my version from book:
def kind
puts "Type year and I'll tell you genre: "
ask = gets.chomp
kind = case ask
when 1850..1889 then "Blues"
when 1890..1909 then "Ragtime"
when 1910..1929 then "New Orleans Jazz"
when 1930..1939 then "Swing"
when 1940..1950 then "Bebop"
else "Jazz"
end
puts "You typed year #{ask}. Genre of music in that period is
#{kind}."
end
kind
Hence, whatever year I'm put, output is "Jazz"...What am I working incorrectly?
gets.chomp returns a string, and you are comparing that with integers.
You can inspect ask after you assigned it:
ask = gets.chomp
p ask
When you run the script and enter a number (e.g. 1940), you should see "1940" printed in the terminal. The quotes around the number show you that the variable holds a string, not a number. (FYI don't use puts here, since it won't show the quotes.)
As mudasobwa wrote in his comment, the way to fix this is to cast the input to a number before you compare it:
ask = gets.chomp.to_i
If you add p ask again, you should now see that only the number is printed to the terminal, without any " surrounding it. This shows you that the variable holds an integer.

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.

Fastest way to read user input in Ruby

I have some time now and I do some challenges from SPOJ in Ruby. One think that bothers me is how I read user input faster.
For example, this problem: http://www.spoj.com/problems/TEST/
I have tried many solutions, all based on gets:
while ((i=STDIN.gets.to_i) != 42) do
puts i
end
$stdin.each_line do |line|
exit if line.strip! == "42"
puts line
end
def input
while (true)
gets
exit if ($_.chomp == "42")
puts $_.chomp
end
end
input
and other variations with gets. Best time that I get is 0.01s and memory footprint of 7.2 Mb. But looking at best submissions using Ruby language first 5 pages are all 0.00s and 3.1Mb of memory used.
Any idea how I can get the input faster?
Also all the tests there are using STDIN to pass the test cases to the app, some very large (hundreds of Mb) and I suspect that gets is too slow for reading that kind of input (or chomp might be). Is some other way faster than gets?
I can get 0.0 times by keeping the code simple and knowing what's going to be a faster way to do things. I won't show my code, because people are supposed to figure out the problem on their own:
while ((i=STDIN.gets.to_i) != 42) do
puts i
end
Ugh. Don't convert from the retrieved string to an integer just to compare it to 42. Instead compare to '42', though, remember, you could be getting trailing line-endings on the strings.
$stdin.each_line do |line|
exit if line.strip! == "42"
puts line
end
Again, don't strip, instead use a smarter comparison. Also, strip! could bite you if nothing changed in the string by returning nil instead of the string you're expecting. I'd use strip instead, because it'd is guaranteed to return the expected value.
def input
while (true)
gets
exit if ($_.chomp == "42")
puts $_.chomp
end
end
input
Two chomp are costly. You should $_.chomp! separately.
Something to know, Ruby's regular expression engine is very fast, and an anchored regular expression pattern will outrun a regular instring search.
Test your code variations using Ruby's Benchmark class and you can narrow down which differences help.
I have one version that uses a loop, very similar to your middle solution, and another that's a single line of code. Both were 0.0 sec.

Resources