While loops in Ruby - 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 :)

Related

Handling Ruby Case Statement

I tried to rewrite the "if/else statement" in the following piece of code by replacing it with a "case" statement, and I am deadly stuck with it for a few hours - what am I missing?
puts "Welcome to 'Guess My Number!'"
print "What is your name?"
input = gets
name = input.chomp
puts "Welcome, #{name.upcase!}!"
puts "I've got a random number between 1 and 100!"
puts "Can you guess it?"
target = rand(100) + 1
num_guesses = 0
guessed_it = false
until num_guesses == 10 || guessed_it
remaining_guesses = 10 - num_guesses
puts "You've got #{remaining_guesses.to_s} guesses left!"
print "Make a guess, put down a number: "
guess = gets.chomp.to_i
num_guesses = num_guesses + 1
end
puts case verification
when guess < target
then "Ooops. Your guess was LOW."
when guess > target
then "Ooops. Your guess was HIGH."
when guess < -1
then puts "Oooops. You have entered a number lower that 1!"
when guess > 100
then puts "Oooops. You have entered a number higher than 100!"
when guess =~ /^([w])/
then puts "Ooops. Looks like you have entered a non numeric
value!"
when guess == String
then puts "Oooops! Looks like you have entered a non numeric
value"
when guess == target
then puts "Good job, #{name}!"
puts "You guessed my number in #{num_guesses} guesses!"
guessed_it = true
end
unless guessed_it
puts "Sorry, you didn't get my number. My number was #{target}."
end
The "case statement" was used to replace and enhance the logic of the following if else statement:
if guess < target
puts "Ooops. Your guess was LOW."
elsif guess > target
puts "Ooops. Your guess was HIGH."
elsif guess == target
puts "Good job, #{name}!"
puts "You guessed my number in #{num_guesses} guesses!"
guessed_it = true
end
Your problem is that you're using the form of case with the optional condition, but you're using when clauses as if you were using the condition-less case.
puts case
when guess < target
"Ooops. Your guess was LOW."
should work.
Further explanation:
using case without a condition, the earliest when branch with a truthy expression is executed. This is what you want here.
But you were using case with verification. In this case, all branches are compared to verification, and the first branch where verification === branch condition is true is executed.
Since in your example I'm guessing verification is always nil, and all your branches' conditions are always true or false, no branch will ever get executed.
You can use a case statement like so:
class String
def green;"\e[32m#{self}\e[0m";end
def yellow;"\e[33m#{self}\e[0m";end
def cyan;"\e[36m#{self}\e[0m";end
def bg_blue;"\e[44m#{self}\e[0m";end
def bold;"\e[1m#{self}\e[22m";end
def underline;"\e[4m#{self}\e[24m";end
def border(num);"\n#{'-' * num}\n#{self}\n#{'-' * num}\n";end
end
puts;puts "Welcome to 'Guess My Number!'".bold.bg_blue;puts
print 'What is your name? '.green
name = gets.chomp
puts "\nWelcome, #{name.upcase!}!\n".cyan.underline
puts "I've got a random number between 1 and 100!\nCan you guess it?".border(44)
target = rand(100) + 1
num_guesses = 0
guessed_it = false
until num_guesses == 10 || guessed_it
remaining_guesses = 10 - num_guesses
puts "\nYou've got #{remaining_guesses} guesses left!\n"
puts;print 'Make a guess, put down a number: '
guess = gets.chomp
case guess.to_i
when (1...target)
puts 'Ooops. Your guess was LOW'.yellow.border(26)
when (target + 1..100)
puts 'Ooops. Your guess was HIGH'.yellow.border(26)
when target
puts; puts; puts
puts "Good job, #{name}!".bold.green
puts 'You guessed my number in ' + "#{num_guesses} guesses!".cyan
puts; puts; puts
guessed_it = true
else
puts "Oooops. You didn't enter a number from 1 to 100".yellow.border(47); puts
end
num_guesses += 1
end
unless guessed_it
puts;puts;puts "Sorry, you didn't get my number. My number was #{target}.".yellow;puts
end
Thanks a lot to everybody! With your invaluable help I managed to regain patience in my soul and satisfaction from this small task :) My mistake is that I violated the rules of common sense by trying to run several pieces of code in a wrong sequence. I moved the case statement inside the until loop and now all I have to do is correct the mistakes in particular when/then statements. It works :)
until num_guesses == 10 || guessed_it
remaining_guesses = 10 - num_guesses
puts "You've got #{remaining_guesses.to_s} guesses left!"
print "Make a guess, put down a number: "
guess = gets.chomp.to_i
num_guesses = num_guesses + 1
puts case
when guess < target
then "Ooops. Your guess was LOW."
when guess > target
then "Ooops. Your guess was HIGH."
when guess < -1
then puts "Oooops. You have entered a number lower that 1!"
when guess > 100
then puts "Oooops. You have entered a number higher than 100!"
when guess =~ /^([w])/
then puts "Ooops. Looks like you have entered a non numeric value!"
when guess == String
then puts "Oooops! Looks like you have entered a non numeric value"
when guess == target
then puts "Good job, #{name}!"
puts "You guessed my number in #{num_guesses} guesses!"
guessed_it = true
end
end
unless guessed_it
puts "Sorry, you didn't get my number. My number was #{target}."
end

Ruby - How to Execute something and then Break inside IF block?

EDIT: Someone pointed out that I needed to break correctly so I am editing the question
Scenario:
Please see following code:
print "UserID: "
uid = $stdin.gets.chomp
print "Password: "
pwd = $stdin.gets.chomp
usr_inp = "#{uid};#{pwd}"
login_status = -1
# login_info.txt - "#{userid};#{password}" - format
File.open(File.join(File.dirname(__FILE__), 'login_info.txt'), "r") do |f|
f.each_line do |line|
puts line
if (line.chomp == usr_inp)
login_status = 1
elsif (line.chomp != usr_inp && line.include?(uid)) #case a person inputs invalid password
login_status = 0
elsif (line.chomp != usr_inp && !(line.include?(uid))) #case a person inputs an invalid id
login_status = 2
end
end
end
if (login_status == 1)
puts "\nLogged in successfully: #{uid}"
elsif (login_status == 2)
puts "\nSorry, that Employee does not exist."
elsif (login_status == 0)
puts "\nLogin failed.\nPlease check credentials."
end
Problem:
break if (condition) exists in Ruby. But I don't waht that.
I want to do something like:
if (condition x)
(do something)
break
elsif (condition y)
(do something else)
break
else
(whatever)
end
Maybe I am not understanding how ruby code works. Whenever I try to put the break as I want to use it, it associates with the next elsif.
Please help.
It depends on what you need and where you need it.
A script like this:
condition = 1
case condition
when 1
puts 'one'
break
when 2
puts 'two'
else
puts 'Other %s' % condition
end
puts 'end'
has a syntax error. break leaves a loop and there is no loop.
But with a loop, this works:
[1,2,3].each{|condition|
case condition
when 1
puts 'one'
break
when 2
puts 'two'
else
puts 'Other %s' % condition
end
puts 'end'
}
puts 'very end'
The output is:
one
very end
You see, the loop is stopped.
If you want to continue the loop with the next element, you need next (sorry, I'm just not aware what break is doing really in Java - it's been a long time since my last Java program):
[1,2,3].each{|condition|
case condition
when 1
puts 'one'
next
when 2
puts 'two'
else
puts 'Other %s' % condition
end
puts 'end %s' % condition
}
puts 'very end'
The result:
one
two
end 2
Other 3
end 3
very end
When you are not inside a loop (like in your code snippet), you may use exit (leave the program) or return (leave a method).

gets.chomp three times in a row to exit

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

Rock, paper, scissors game in Ruby

I am trying to get this program to run:
cpucount = 0
playercount = 0
tiecount = 0
playerchoice =
while playerchoice != "n"
puts "Chose your Weapon. Paper (0), Rock (1), Scissors (2)"
player1 = 0 #gets
cpuplayer = 2#rand(3)
puts player1
puts cpuplayer
if player1 == 0 and cpuplayer == 1
puts "You Win"
playercount +=1
elsif player1 == 1 and cpuplayer == 2
puts "You Win!"
playercount +=1
elsif player1 == 2 and cpuplayer == 0
puts "You Win!"
playercount +=1
elsif player1 == cpuplayer
puts "You tied!"
tiecount +=1
else
puts "You lose"
cpucount +=1
end
puts cpucount
puts playercount
puts tiecount
puts "Do you want to play again? y/n?"
playerchoice = gets
puts playerchoice
end
but there are a few issues.
First, regardless of whether I select "y" to continue to another round or "n" to quit, it still runs another round.
Second, the logic is fine when I manually input the values for player1 and cpuplayer, but when I use the rand method and the user input, the program takes those and then the logic doesn't work.
Any help would be appreciated.
In your input statement which is using gets you need to take into account the newline that is placed in the string, and the fact that it is a string. When the player is inputting it, it is coming in as text, not an integer. A simple way to do this is to make it an integer on input, via
player1 = gets.to_i
That will guarantee that the conditional logic you use to test against integers is not going to fail because you are comparing a string.
The newline that is coming in with the playerchoice input needs get chomped to make that happy for comparison. So, there is another method to get rid of newlines.
playerchoice = gets.chomp
Try assigning the playerchoice variable in the following way:
playerchoice = gets.chomp
The #gets method by itself will output any carriage returns that come with the user's input, which is why if you were to inspect the returned value for playerchoice, you'd see that instead of "n", the value returned is actually "n\n", causing your comparison to resume looping the game. Calling #chomp on that value strips out the carriage return characters (\n, \r, \r\n), which should allow the game to end if "n" is typed in by the user.
Hope it helps!

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

Resources