gets.chomp three times in a row to exit - ruby

The task is taken from "Learn to Program" by Chrise Pine. The program is called 'Deaf Grandma'. Here's the task: "whatever you type, grandma (the program) should respond with this:
`HUH?! SPEAK UP, SONNY!`
unless you shout it (type in all capitals). In this case she responds with:
`NO, NOT SINCE 1938!`
Have Grandma shout a different year each time, maybe any year at random between 1930 and 1950. You have to shout BYE three times in a row. Make sure to test your program: if you shout
BYE three times but not in a row, you should still be talking to
Grandma."
Now, everything looks fine to me, except I didn't get where to put gets.chomp 3 times to exit a program. Eventually, I came up with this:
speak = gets.chomp
while speak != 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
if speak == speak.upcase
puts 'NO, NOT SINCE ' + (1930 + rand(20)).to_s + '!'
else repeat = gets.chomp
end
end
But in this case if I type BYE grandma still asks me:
`HUH?! SPEAK UP, SONNY!`
My question is: how can I properly make the program exit after I type BYE three times in a row?

Have a look at this, I've made some changes though. But should give you the expected output.
bye_count = 0
while true
speak = gets.chomp
if speak == 'BYE'
bye_count +=1
bye_count == 3 ? break : next
end
bye_count = 0 # Resets count
if speak == speak.upcase
puts 'NO, NOT SINCE ' + (1930 + rand(20)).to_s + '!'
else
puts 'HUH?! SPEAK UP, SONNY!'
end
end

You've not added anywhere in your code that using 'bye' 3 times will exit the program.
while bye < 3
Try looking at your code again and implementing the changes to exit after 3 byes.

Here's another way:
responses = ["", "", ""]
loop do
speak = gets.chomp
responses.shift
responses << speak
break if responses.all? { |r| r == "BYE" }
if speak == speak.upcase
puts 'NO, NOT SINCE ' + (1930 + rand(20)).to_s + '!'
else
puts 'HUH?! SPEAK UP, SONNY!'
end
end
Alternatively,
break if responses.uniq == ["BYE"]

puts "what can i do for your son?"
a=0
while a != 3
n= gets.chomp
if n.include? 'BYE'
puts "NO NOT SINCE #{rand(1897..1930)}".chomp
a = (a + 1)
end
if n != n.upcase
puts 'HUH?! SPEAK UP, SONNY!'.chomp
a=0
end
if n == n.upcase and n != 'BYE'
puts "NO NOT SINCE #{rand(1897..1930)}".chomp
a=0
end
end

Related

Iterator in a while loop executes one more time than expected

I am trying to create a code that runs until a person says 'BYE' three consecutive times.
With the following code:
ask = gets.chomp
count = 0
while (count != 3)
if (ask == 'BYE')
puts 'HUH?! SPEAK UP, SONNY!'
count = count + 1
ask = gets.chomp
elsif (ask != ask.upcase)
puts 'HUH?! SPEAK UP, SONNY!'
count = 0
ask = gets.chomp
else
puts 'NO, NOT SINCE ' + rand(1930..1950).to_s + '!'
count = 0
ask = gets.chomp
end
end
puts 'Goodbye for now'
I actually need to type 'BYE' four times. Can someone point to how to fix it?
You don't actually have to type BYE four times. Just three is enough. The fourth input can be anything.
BYE # input 1
HUH?! SPEAK UP, SONNY!
BYE # input 2
HUH?! SPEAK UP, SONNY!
BYE # input 3
HUH?! SPEAK UP, SONNY!
nah, I give up # input 4
Goodbye for now
The problem with your code is that you request next input immediately after you have chosen a handler. Even if, by your logic, you're not going to need that input. So you'll have to rework this part.
Putting gets only once at the beginning of the loop fixes it :
count = 0
while count != 3
ask = gets.chomp
if ask == 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
count = count + 1
elsif ask != ask.upcase
puts 'HUH?! SPEAK UP, SONNY!'
count = 0
else
puts 'NO, NOT SINCE ' + rand(1930..1950).to_s + '!'
count = 0
end
end
puts 'Goodbye for now'
Execution :
$ ruby -w topc.rb
a
HUH?! SPEAK UP, SONNY!
A
NO, NOT SINCE 1931!
BYE
HUH?! SPEAK UP, SONNY!
BYE
HUH?! SPEAK UP, SONNY!
BYEE
NO, NOT SINCE 1939!
BYE
HUH?! SPEAK UP, SONNY!
BYE
HUH?! SPEAK UP, SONNY!
BYE
HUH?! SPEAK UP, SONNY!
Goodbye for now
Your while (count != 3) is so Javaish (no need for parentheses in Ruby) that I can't resist to write a more rubyesque solution. Not shorter, but more DRY, with more code that you are likely to see in Ruby programs, and certainly not exemplary, there are always many ways to do the same thing in Ruby.
class Strange
def initialize(wanted)
#answer = true
#count = 0
#wanted = wanted # desired number of correct consecutive answers
end
# Increment #count if true, else reset to zero.
def answer(boolean)
#answer = boolean
if boolean
then # then is optional, but I like it
#count = #count + 1
else
#count = 0
end
end
# Write a message.
def message(number)
puts case number
when 1 then 'HUH?! SPEAK UP, SONNY!'
when 2 then "NO, NOT SINCE #{rand(1930..1950)} !"
else 'WHAT ?'
end
end
def prompt
print #answer ? 'Talk please > ' : 'Wrong answer, retry > '
#ask = gets.chomp
end
# Recursively loop until the number of correct consecutive answers
# corresponds to the desired number.
def run
prompt
case
when #ask == 'BYE'
message 1
answer(true)
when #ask != #ask.upcase
message 1
answer(false)
else
message 2
answer(false)
end
run unless #count == #wanted # recursive loop
end
end # class Strange
Strange.new(3).run
puts 'Goodbye for now'
Execution :
$ ruby -w t.rb
Talk please > xyz
HUH?! SPEAK UP, SONNY!
Wrong answer, retry > XYZ
NO, NOT SINCE 1935 !
Wrong answer, retry > BYE
HUH?! SPEAK UP, SONNY!
Talk please > what ?
HUH?! SPEAK UP, SONNY!
Wrong answer, retry > BYE
HUH?! SPEAK UP, SONNY!
Talk please > BYE
HUH?! SPEAK UP, SONNY!
Talk please > BYE
HUH?! SPEAK UP, SONNY!
Goodbye for now

Deaf Grandma Ruby

I am going through the Chris Pine Ruby tutorial. In one of the exercises, I have to extend the program by making the user write "BYE" three times in a row to shut the program. I wanted to take it a step further and have Grandma respond on the third "BYE" before the program shuts down. Every time I type "BYE" i get two error messages, but the program still runs like it should aside from that. The error messages are:
DeafGrandma.rb:11: warning: already initialized constant BYE
DeafGrandma.rb:3: warning: previous definition of BYE was here
Here is my code:
# DeafGrandma
BYE = 0
while BYE < 3
puts "What do you want to say to Grandma?"
tell_grandma = gets.chomp
if tell_grandma == "BYE"
BYE += 1
end
if tell_grandma != tell_grandma.upcase
puts "HUH!? SPEAK UP, SONNY!"
else
puts "NO, NOT SINCE #{1929 + rand(22)}!"
end
end
while BYE = 3
puts "BYE BYE, SONNY!"
break
end
What must I change to get rid of these errors? Thank you in advance.
Constants start with capital letters and are just like variables, with the only exception that constants are meant to remain constant and not change throughout your program. In this case you're changing it by adding +=1 every time you mention 'BYE'.
Constants can not be reinitialized generally speaking, to fix your problem and get rid of the errors you need to change all references from BYE to bye
bye = 0
while bye < 3
puts "What do you want to say to Grandma?"
tell_grandma = gets.chomp
if tell_grandma == "BYE"
bye += 1
end
if tell_grandma != tell_grandma.upcase
puts "HUH!? SPEAK UP, SONNY!"
else
puts "NO, NOT SINCE #{1929 + rand(22)}!"
end
end
while bye = 3
puts "BYE BYE, SONNY!"
break
end
To expand on the answer given by Nabeel Amjad, a variable whose name begins with a capital letter is a 'constant' in Ruby. Of course, Ruby being Ruby, it's still possible to reassign these so-called 'constants' (because Ruby is flexible that way), but you get a warning, because that's not what constants are actually for, and in most cases when you reassign a constant it's a mistake.
You can fix it by simply renaming the variable BYE to bye (or bYE or the_number_of_times_the_user_said_bye)
This is what I did when doing Chris' Pine exercises:
puts "Start talking to Grandma. Sometimes she can't hear, so you might need to SPEAK UP! To leave just shout 'Bye'"
talk = gets.chomp
while talk != "BYE"
if talk == talk.downcase || talk == talk.capitalize
puts "HUH?! SPEAK UP, SONNY!"
talk = gets.chomp
elsif talk == talk.upcase
puts "NO, NOT SINCE" + " " + (1900 + rand(81)).to_s + "!"
talk = gets.chomp
elsif talk == "BYE"
break
end
end
Hope this helps! I had so much fun with this...Love Chris Pine's Learn to Program

While loops in Ruby

I want to exit only after I say 'BYE' three consecutive times. It is about a deaf grandma who will only hear things if the letters are all in caps.
I tried having three different variables, but that did not work. My code is below and it works when I say 'BYE' only once.
whatSaid = 'Hi!'
while (whatSaid != 'BYE')
whatSaid = gets.chomp
if (whatSaid == 'BYE')
puts 'FINE! LEAVE YOUR POOR GRANDMA TO DIE.'
else
if (whatSaid == whatSaid.upcase)
puts 'NO, NOT SINCE ' + rand(1930...1951).to_s + '!'
else
puts 'HUH!? SPEAK UP, SONNY!'
end
end
end
why not a variable called bye_count - start it out at 0 and increment it each time you hear 'BYE' - and when that gets to 3, exit
eg
what_said = 'Hi!'
bye_count = 0
while (bye_count < 3)
what_said = gets.chomp
if (what_said == 'BYE')
bye_count += 1
puts 'FINE! LEAVE YOUR POOR GRANDMA TO DIE.'
else
if (what_said == what_said.upcase)
puts 'NO, NOT SINCE ' + rand(1930...1951).to_s + '!'
else
puts 'HUH!? SPEAK UP, SONNY!'
end
end
end
Unrelated note: ruby generally uses underscore_case for variable names, rather than camelCase :)

Program won't output what it's supposed to

I am following tutorial and I can't figure out what I am doing wrong. It's outputting everything up to if down
puts "we are going down the cave" I can't get it to output the else statement or anything afterwards. I am just learning and the answer is probably really simple.
puts("Would you like to go up or down?")
user_input = gets()
down = "cave"
up = "mountain"
if down
puts "we are going down the cave"
else up
puts "we are going up the mountain"
puts("Pick a number between 1 and 100")
LOCATION = "cave"
NUMBER = gets()
if NUMBER == 100
puts "You've achieved enlightment in the #{LOCATION}! Spread joy around the world!"
elsif NUMBER >= 50 > 100
puts "There are #{NUMBER} goblins in the #{LOCATION}. WE MUST FIGHT!"
elsif NUMBER > 20 > 50
puts "There is still hope that we will make it to the #{LOCATION}. before the #{NUMBER} Snufflebums get us!"
else NUMBER <= 20
puts "We have conquered the Goon Squad of the #{LOCATION}.. It only took us #{NUMBER} years!!!"
end
end
down is "cave" and is always 'truthy' so if down is always, always true. You want to be testing the user_input, not the variable down
What I think you want is...
user_input = gets.chomp
# you need the chomp to remove the return character
down = "cave"
up = "mountain"
if user_input == down
puts "we are going down the cave"
elsif user_input == up
puts "we are going up the mountain"
end
# you need the end statement, otherwise everything that follows is part of the "else"
And remove the last end

Ruby script need fix

I'm having a problem with my ruby script. If anyone could help, I'd really appreciate it. The problem is that the number is stuck between 1-2; where 2 is too high and 1 is too low. The guesses should be integers only.
#!/usr/bin/ruby
def highLow(max)
again = "yes"
while again == "yes"
puts "Welcome to the High Low game"
playGame(max)
print "Would you like to play again? (yes/no): "
again = STDIN.gets.chomp
if again == 'no'
puts "Have a nice day, Goodbye"
end
end
end
#This method contains the logic for a single game and call the feedback method.
def playGame(max)
puts "The game gets played now"
puts "I am thinking of a number between 1 and #{max}." #It show what chosen by user
randomNumber = rand(max)+ 1
print "Make your guess: "
guess = STDIN.gets.chomp
feedback(guess, randomNumber)
end
#Start while loop
#Logic for feedback method. It's ganna check the guess if it's high or low.
def feedback(guess, randomNumber)
count = 1
while guess.to_i != randomNumber
count = count + 1
if guess.to_i < randomNumber
print "That's too low. Guess again: "
else
print "That's too high. Guess again: "
end
guess = STDIN.gets.chomp
end
puts "Correct! You guessed the answer in #{count} tries!"
end
highLow(ARGV[0])
Change your last line to this:
highLow(ARGV[0].to_i)
The ARGV array contains all the passed in arguments as strings, so you have to cast it to integer.

Resources