Ruby Infinite Loop - ruby

I'm currently learning ruby, and I've gotten stuck on this problem:
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 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. You can't stop talking to grandma until you shout BYE.
This is the code I tried:
puts "Say something to Grandma!"
something = gets.chomp
while something != "BYE"
if something == something.upcase
puts "NO, NOT SINCE 19" + (rand(30..50)).to_s + "!"
else
puts "HUH? SPEAK UP SONNY!"
end
end
Whenever I execute this, the if and else strings just go on an infinite loop. What am I doing wrong here?

You are only getting the input once, you need to read it at the beginning of each loop, like so:
something=""
while something != "BYE"
puts "Say something to Grandma!"
something = gets.chomp
if something == something.upcase
puts "NO, NOT SINCE 19" + (rand(30..50)).to_s + "!"
else
puts "HUH? SPEAK UP SONNY!"
end
end
Hope that makes sense.

Related

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

How to understand end tag/loop relations in Ruby?

World!
New to all types of programming, so maybe I'm not understanding how loops/if/ else work in general?
My problem is this:
Any time I run this program, it runs fine, except for the exiting part, aka saying "BYE".
Whenever I say "BYE" grandma responds with "NO, NOT SINCE 1943" then the program exits.
My problem is that If I move the statement = gets.chomp to anywhere else besides the inside of the two ends it infinite loops, or gives me the same exiting issue.
This is the code I am using.
puts "Talk to grandma!"
puts "To stop talking to Grandma say 'BYE'"
sleep 1
puts "Remember grandma has bad hearing. You might need to Yell!"
statement = ""
while statement != "BYE"
statement =gets.chomp
if statement != statement.upcase
puts "WHAT?! SPEAK UP!"
else
year = rand(1940..1955).to_s
puts "NO, NOT SINCE " + year
end
end
Problem: Exits when "BYE" is spoken, but only after saying "NO, NOT SINCE" etc etc
However when I change the code around to:
puts "Talk to grandma!"
puts "To stop talking to Grandma say 'BYE'"
sleep 1
puts "Remember grandma has bad hearing. You might need to Yell!"
statement = gets.chomp
while statement != "BYE"
if statement != statement.upcase
puts "WHAT?! SPEAK UP!"
else
year = rand(1940..1955).to_s
puts "NO, NOT SINCE " + year
end
statement= gets.chomp
end
The program then works PERFECTLY.
Doesn't the loop end when it says end? How would the statement = gets.chomp in the bottom get included in the loop if it already ended? Or am I misunderstanding it, and the first end relates to the if/else, and the SECOND end refer to the "ending of the loop"?
I'm self learning with Chris Pines Learn to Program using Ruby, but... all it says is "Everything in the loop before end gets repeated."
Former code:
while statement != "BYE"
statement =gets.chomp
# if-else validation
end
Which means that you do these steps:
Read user input
Validate it with your if-else statement
Continue with loop.
Validate it against the while loop.
Latter code:
statement= gets.chomp
while statement != "BYE"
# if-else validation
statement= gets.chomp
end
Here you read user input, then start the while loop.:
Validate it against the while loop.
Validate it with your if-else statement.
Read user input.
Continue with loop.
The relevant part is when you decide to validate the user input to continue inside the while loop and what you do before or after that validation. Note that this doesn't belong to Ruby but to any programming language. The logic is which matters in this case.
In short, the order matters.
first end relates to the if/else, and the SECOND end refer to the "ending of the loop"?
Yes, this is entirely correct. This is easier to understand when you indent the code:
while statement != "BYE" # <----.
statement =gets.chomp # |
if statement != statement.upcase # <-. |
puts "WHAT?! SPEAK UP!" # | |
else # | |
year = rand(1940..1955).to_s # | |
puts "NO, NOT SINCE " + year # | |
end # <-. |
end # <----.
You could also have the loop in this form:
while true
statement = gets.chomp
# the statement below will be executed only if the condition on the right is met
break if statement == 'BYE'
# if-else condition
end
There are a number of issues with your script. The following is (in my opinion) easier to read and debug, and works in casual testing with Ruby 2.1.2:
puts "Talk to grandma!"
puts "To stop talking to Grandma say 'BYE'"
puts "Remember grandma has bad hearing. You might need to Yell!"
loop do
case gets.chomp
when 'BYE'
break
when /[[:lower:]]/
puts 'WHAT?! SPEAK UP!'
else
puts "NO, NOT SINCE #{rand 1940..1955}"
end
end

Ruby: How to exit a function and then return to it

I'm writing a text-adventure game for exercise 36 of Learn Ruby the hard Way: http://ruby.learncodethehardway.org/book/ex36.html
I want to include 'instructions' as an option players can use anytime, but once the player exits the Room() function and enters the intructions() function, I am unsure how to return them to the appropriate room. I can have the instructions() always return player to the start after, but is there a way to get them back to the same location?
Here is a quick example, sorry it's incomplete...I'm still in the middle of building it:
puts
puts <<INTRO
"Welcome to the Cave of Indifference.
It doesn't much care for you. Beware!
There are deadly areas of this cave, but if you seek
it you may find the secret treasure and escape with your life."
INTRO
puts
puts "Type \'Instructions\' at any time for direction"
puts
sword = false
monster = true
treasure = false
def Command()
puts ">>> "
end
def dead(how)
puts how.to_s
puts "PLAYER DEAD!"
Process.exit(0)
end
def instruction()
puts "Rooms will have individual instructions"
puts "but here are some general items."
puts "west, east, north, south: goes that direction"
puts "look: look around the room"
puts "take: to take item or object"
end
def Room1()
puts "You are now at the cave entrance."
puts "You may go west or east. OR exit with your life!"
Command(); choice = gets.chomp()
if choice.downcase == "exit" && treasure = true
puts "Congratulations! You win!"
Process.break
elsif choice.downcase == "exit" && treasure = false
puts "Seriously?! Giving up already?"
puts "Fine. Here is what happens:"
dead("You stumble on your exit from the cave and trip
on a rock. The fall cracks your skull and you bleed
to death. Bye bye!")
elsif choice.downcase.include? "right"
#INPUT
elsif choice.downcase.include? "left"
#INPUT
elsif choice.downcase.include? "instructions"
instructions()
else
"That command makes no sense, try again."
end
end
Room1()
I also assume there are many issues with the code and would be very appreciative of your help, but no worries I am going to keep working on this and make it really fun to play :)
You can give the instruction method the last location.
def instruction(last_room)
#do stuff
last_room.call()
end
You would call that function like so:
instructions(method(:Room1)), where Room1 is the name of the method you want to return to.
The problem you have isn't having instructions return to Room1 (or RoomX). It'll do that without you doing anything special. What you need is something like:
#room = :Room1
while true
send(#room)
end
and then set the variable #room to control which room you're in.
It's not the greatest way in the world to do that, but it'll get you started.

Ruby: rand method is not giving me a truly random number

I am trying to answer the following question from Chris Pine "Learn to Program" book:
• 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.
• Extend your Deaf Grandma program: What if grandma doesn't want you
to leave? When you shout BYE, she could pretend not to hear you.
Change your previous program so that 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.
My code is giving me the same "random_year" when I run it. Why is the code not providing me an actual random year (between 1930 and 1950)?
Code in ruby.
# Deaf Grandma
random_year = 1930 + rand(1950 - 1930)
puts 'WHAT DO YOU WANT KID?'
bye = 0
talk_to_grandma = nil
while bye < 3
talk_to_grandma = gets.chomp
if talk_to_grandma == "BYE"
puts 'NO, NOT SINCE ' + random_year.to_s
bye+=1
elsif talk_to_grandma == talk_to_grandma.upcase
puts 'NO, NOT SINCE ' + random_year.to_s
bye = 0
else
puts "HUH?! SPEAK UP, SONNY!"
bye = 0
end
end
You need to generate the random number inside your loop. Right now you generated it ONCE at the start of the program, and then it never changes. Basically:
while bye < 3
random_year = 1930 + rand(1950 - 1930) // move the random generation to here
puts 'NO, NOT SINCE ' + random_year.to_s
You have assigned a value to the random_year variable in the first code line. It is selected randomly.
On each call to
puts 'NO, NOT SINCE ' + random_year.to_s
the variable is accessed/read, but not modified.
You may want to encapsulate the random year generation in a method:
def random_year( start=1930, range = 20 )
start + rand( range )
end
then you can use it like this:
puts "NO, NOT SINCE #{random_year}"
or, for a slightly older grandma:
puts "NO, NOT SINCE #{random_year(1910, 50)}"
For that exercise I've used: rand(1930..1950)

Ruby Loops with Grandma

Okay, I'm trying to write a ruby simulation of my grandmother. I can't quite get the loop to work the way I'd like though. I want granny to respond with
"OH, THAT REMINDS ME OF BACK IN (random year) ..."
when you answer her in all caps but I also want her to respond with
"WHAT'D YOU SAY????"
when you don't use all caps. I can get each one to work separately but I can't seem to make a continuous loop of granny with her crazy responses. Here's the code:
puts 'HELLO SONNY! WHAT\'S NEW IN THE WHO\'S IT WHAT\'S IT?'
response = gets.chomp
while response == response.upcase
puts 'OH, THAT REMINDS ME OF BACK IN ' + (rand(50) + 1905).to_s + '...'
response = gets.chomp
end
while response != response.upcase
puts 'WHAT\'D YOU SAY????'
response = gets.chomp
end
Any ideas?
The issue is that once you exit the first while loop, you're never returning back to it. Try something like this:
while true
response = gets.strip
if response == response.upcase
puts msg1
else
puts msg2
end
end
That'll run forever, until you decide to kill virtual-granny with Ctrl-C.
This program works, though Im a noob so it may not be the best way. Also my math is more creative then practical, the other guys is way better. :)
puts 'Talk to your grandma!'
while true
say = gets.chomp
if say == say.downcase
puts 'WHAT DID YOU SAY? SPEAK UP!'
else say == say.upcase
puts "NO HONEY, NOT SINCE 19" + (rand(90) + 10).to_s
end
break if say == 'bye'.upcase
end

Resources