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

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)

Related

unique rand number in a ruby loop

I am reading the book "Learn to program", and I have come across an exercise that I am having trouble with.
year = (rand(1900...1990))
while true do
puts "What would you like to say to grandma?"
ask = gets.chomp
if
ask == ask.downcase
puts "SPEAK UP SONNY"
elsif
ask == ask.upcase
puts "NO, NOT SINCE #{year}!"
end
break if ask == "BYE"
end
everything is functioning properly, but if the rand number "year" comes up more than once, it repeats the same number. Is there a way to have it become a unique random number each time it comes up during the same loop?
thank you in advance
Move year assignment into the loop to have it assigned before each chomp.
The value of year does not change within the loop because it is defined outside the loop. It would change if the definition were moved inside the loop, but you still may have years repeated. To fix both of these problems, change
year = rand(1900...1990)
to
years = (1900...1990).to_a.shuffle
(outside the loop) and change
puts "NO, NOT SINCE #{year}!"
to
puts "NO, NOT SINCE #{years.shift}!"
(or years.pop). If this is repeated more than 91 times an exception will be raised.

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

trying to use each method to find divisible numbers and print them

I'm new to ruby and new to stack. I am trying to use the .each method on an array of numbers to see which numbers are divisible by 4, and 400. It is based on an exercises from Chris Pine's "Learn to Program" Ruby tutorial. In it you are supposed to find the leap years, then print them, from a range of years that the user inputs. I accomplished this using an if/else statement...but it seems to me this should be able to be done using the each method, or maybe the map method? Less code.
For example:
puts "Enter two years (to - from) to find out which years are leap years!"
puts "Enter the first year.."
year1 = gets.chomp.to_i
puts "Now enter the second year"
year2 = gets.chomp.to_i
range = (year1..year2).to_a
puts "These are the leap years between those years:"
range.each do |year|
leaps = (year % 4 == 0 || year % 400 == 0)
end
puts leaps
this code may not be correct, but i have toyed with different ways of doing it (puts inside .each, defining variable outside, etc...) but nothing seems to work. Like I said, I accomplished it with an if/else...I just feel there may be a better way, and it's driving me nuts. Do i not understand the .each correctly? am i using the wrong method? can it be done at all using each/map/or collect???? Thanks in advance!
You need to puts inside the each block too. Also, you can just divide by 4 and check if the remainder is 0. No need of 400
range.each do |year|
puts year if year % 4 == 0;
end
The puts year will be executed only if the if condition is satisfied.

Ruby Infinite Loop

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.

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