Comparing user's input to multiple values - ruby

I am starting to learn programming and I have chosen to learn Ruby using Codecademy. However, I was trying to consolidate my learning but I just can't get this to work!
print "What is 2 + 2 ="
sum_var = gets.chomp
sum_var.downcase!
if sum_var == "four" || 4
puts "Correct!"
else sum_var != "four" || 4
puts "Wrong! #{sum_var} is not the answer!"
end
It just returns 'Correct!' even if it is wrong.

You need write the code as below :
print "What is 2 + 2 ="
sum_var = gets.chomp
# don't need to apply the bang method like you did - sum_var.downcase!
if sum_var.downcase == "four" || sum_var == '4'
puts "Correct!"
else # else don't need condition checking, so I removed.
puts "Wrong! #{sum_var} is not the answer!"
end
sum_var = gets.chomp gives you a string, no where you are converting it to a number. So, evenif you are passing number from the console it became "4" or "7" etc.
Let me explain you also why always you got "Correct!" as a output
sum_var == "four" || 4 - In this expression, whenever sum_var is not equal to "four", your first expression was evaluated to false, but when control went to test the second expression, it found there 4. You know in Ruby all objects are true, except nil and false. So 4 is considered as true. Thus in your code always if block was getting executed, and you were keep getting as the output "Correct!".
Now in your code, some other mess you did, that I corrected in my above code.

The problem with your code lies in the line
if sum_var == "four" || 4
The == will usually return false, so the second part will be evaluated because the precedence of == is higher than the precedence of ||. Since all objects except false and nil are "truthy" in Ruby the expression will end up being true regardless of the users input. Correction as proposed by #ArupRakshit, just wanted to add some more reason to it.

Related

A Ruby branching way to allow different user's input options to check for all possible valid answer stored in an array

I have a small code for determining the number of hours per year.
What I am looking for is for a Ruby way to allow different user's input options for all possible valid answer stored in an array
to check if the user provided a valid option by calling include? on the array.
When year consist of 52 weeks.
Week consists of 7 days.
Day consists of 24 hours
My problem comes up when trying to pass different answers for the gets method such as follows:
if answer == "yes" || "yup" || "yeah" || "positive";
if answer == ("yes", "yup", "yeah", "positive")
if answer == ["yes" or "yup" or "yeah" or "positive"]
I receive an error which I couldn't solve
answer = gets.chomp
if answer == "yes" or "yup" or "yeah" or "positive"
puts "Good!"
puts desc_text
my_var = gets.chomp.to_i
if my_var == 3736
puts good_text
else
puts wrong_text
puts bad_text
end
elsif answer == [ "no" || "nop" || "nay || ""negative" ]
puts bad_text
else
puts yes_no
end
I'd like to pass different answer options such as yes, yup, yeah, positive instead of just enclose me to a yes and/or no answer
A more idiomatic Ruby way of allowing for these different user options would be to have all possible valid user input stored in an array, then checking if the user provided a valid option by calling include? on the array. This way, you can update the array with more possible options at a later time. Generally arrays like this are stored as constants, though you can also store them as local variables. I find that for a script like this, variables are fine, but if I'm writing a larger program and I need arrays like this (for example, arrays that specify valid options) in a class, then I use constants to make it easy for other contributors to find them. Another option yet would be to have a configuration file (can be a Ruby file, yaml file, JSON file...) that defines valid options, and then you can load this file when executing your program.
Here is an example of what I mean:
VALID_AFFIRMATIVE_ANSWERS = %w(yes yup yea positive)
VALID_NEGATIVE_ANSWERS = %w(no not nay negative)
answer = gets.chomp
if VALID_AFFIRMATIVE_ANSWERS.include?(answer)
puts "Good!"
puts desc_text
my_var = gets.chomp.to_i
if my_var == 3736
puts good_text
else
puts wrong_text
puts bad_text
end
elsif VALID_NEGATIVE_ANSWERS.include?(answer)
puts bad_text
else
puts yes_no
end
I'm not sure what errors you're receiving, but I'm not sure if you're ever defining some of these variables (for example desc_text etc.).
if code is excetly as you write above your issue is in line written below
elsif answer == [ "no" || "nop" || "nay || ""negative" ]
although it won't work , so the solution for you would be like below
def process_positive_response
my_var = gets.chomp.to_i
if my_var == 3736
puts good_text
else
puts wrong_text
puts bad_text
end
end
answer = gets.chomp
case answer
when 'yes','yup','yeah','positive'
puts "Good!"
puts desc_text
process_positive_response
when 'no', 'nop', 'nay', 'negative'
puts bad_text
else
puts yes_no
end
first why write so much conditions when ruby already does that for you with case statement, and second distribute your code in chunks so it will make your code more traceable.

Towers of Hanoi, Ruby conditional

I'm having trouble with my first if conditional, which checks to make sure the the new piece added is smaller than the one under/before it. My Towers of Hanoi game worked fine until I added it. Below is my code:
arrays = [[5,4,3,2,1],[],[]]
win = false
while win != true
puts "Choose a top piece: (1, 2, 3) "
top = gets.to_i
puts "Which stack to place this piece? (1, 2, 3)"
stack = gets.to_i
if (arrays[stack-1] == nil) ||
(arrays[stack-1][arrays[stack-1].count-1] > arrays[top-1][arrays[top-1][arrays[top-1].count]])
arrays[stack-1].push(arrays[top-1].pop)
else
"You need to follow the rules."
end
print arrays
if arrays[1] == [5,4,3,2,1] || arrays[2] == [5,4,3,2,1]
print "You're a winner!"
win = true
end
end
~
Below is the error I get. How do I perform my check and deal with my nil value arrays in a concise manner?
towers_hanoi:13:in `[]': no implicit conversion from nil to integer (TypeError)
from towers_hanoi:13:in `<main>'
Use the empty? method to determine if an array is empty. FYI, though, if you want to see if a variable has a nil value, use nil?
Also, the last method will help a ton here and subtracting 1 from the inputs right away will make the code more readable. Try this:
arrays = [[5,4,3,2,1],[],[]]
win = false
while win != true
puts "Choose a top piece: (1, 2, 3) "
stack_from = gets.to_i - 1
puts "Which stack to place this piece? (1, 2, 3)"
stack_to = gets.to_i - 1
if (arrays[stack_to].empty?) ||
(arrays[stack_to].last > arrays[stack_from].last)
arrays[stack_to].push(arrays[stack_from].pop)
else
"You need to follow the rules."
end
print arrays
if arrays[1] == [5,4,3,2,1] || arrays[2] == [5,4,3,2,1]
print "You're a winner!"
win = true
end
end
There are a lot of strange things going on in that if statement.
Definitely use Array#empty? to check if an array if empty. An empty array is not nil.
Secondly some of your array bracketing is way too convoluted, I'm not sure what you are trying to accomplish here but you are definitely going to be checking if nil > number in some cases:
(arrays[stack-1][arrays[stack-1].count-1] > arrays[top-1][arrays[top-1][arrays[top-1].count]])
I doubt this is what you are trying to do (since it will throw an error). I would take a minute to think about your logic and refactor. In Towers of Hanoi, you only need to worry about checking if the piece you are moving is less than the LAST piece on the stack you are moving to (which represents the top).
Use Array#last and you will be on your way to a much simpler solution.

Is it possible to execute a condition differently in a multiple condition while loop without creating an entire new while loop?

I don't really know how to word this short enough for me to google it.
But is it possible to execute a certain condition in a multiple condition while loop differently, without creating a whole entire while loop.
For example, Is it possible to do something like this
while num == "" || num == "0"
#ENTER CODE
Instead of doing this
while num == ""
print "YOU MUST ENTER A NUMBER!"
num = gets.chomp
end
while num == "0"
print "ZERO IS NOT A VALID NUMBER!"
num = gets.chomp
end
I want to know is it possible to do this, but make it look more visually appealing and concise.
This should do the trick, one loop and use conditionals for which error message to print.
while num == "" || num == "0"
print "YOU MUST ENTER A NUMBER!" if num == ""
print "ZERO IS NOT A VALID NUMBER!" if num == "0"
num = gets.chomp
end
You could write something like this:
while num.to_i.zero?
case number
when ''
print 'YOU MUST ENTER A NUMBER!'
when '0'
print 'ZERO IS NOT A VALID NUMBER!'
end
num = gets.chomp
end
This works, because to_i returns 0 for both the string "0" and nil.
Furthermore I would suggest to change the error message to simplify the code even more:
while num.to_i.zero?
print 'Please enter a number greater then zero'
num = gets.chomp
end

Ruby if/elseif coding error

I'm writing a simple and small program in Ruby to output the ordinal of a number based on user input. Here is what I wrote:
puts "Enter a number"
number = gets.chomp.to_i
conversion = number % 10
if number == 11 || number == 12 || number == 13
puts "That is #{number}th"
end
if conversion == 1
puts "That is #{number}st"
elsif conversion == 2
puts "That is #{number}nd"
elsif conversion == 3
puts "That is #{number}rd"
else
puts "That is #{number}th"
end
As my code shows, I wanted to take the "number" from the user input, cut off the last number, and use that single digit number to determine whether "number" should be a (fir)st, (seco)nd, (thi)rd, or (four)th type of ordinal. The "conversion" value should convert that for me. However, it can be seen that the numbers 11, 12, and 13 are exceptions. My program works fine except that when I input one of these three values, I get two outcomes, not one, in the terminal such as:
That is 11st
That is 11th
My intention is that "11th" should be displayed, not "11st". Even though I tried to write an exception into my code, the "conversion" still gets executed. I'm not sure what error I made, but is there a way I can isolate the first if statement, so that my conversion does not include 11, 12, and 13?
That is exactly how you have the program written!
If the number is 11,12,13 it will trigger the first if statement, as you expect it to. It will then go to the next if statement because it doesn't have any reason to end. puts is not a return/break statement (a return/break statement would break this code, but that is a different problem) so code will continue to run until the end.
The easiest solution would be to simply combine the two if statements into your main if/else statement:
if number == 11 || number == 12 || number == 13
puts "That is #{number}th"
elsif conversion == 1
puts "That is #{number}st"
elsif conversion == 2
puts "That is #{number}nd"
elsif conversion == 3
puts "That is #{number}rd"
else
puts "That is #{number}th"
end
This will prevent any number from being able to be true in different if loops.

How to run a simple Ruby script

I would like to make a program that checks to see if the number you enter is an even number. Sort of like making a leap year program but for any number divisible by 2.
Something along the lines of:
num = gets.chomp
while num != 0
if (num%2) == 0
puts 'yess'
else
puts 'nooo'
end
end
I knows there's something easy that I need to change for it to run.
(btw I just started learning Ruby yesterday!)
There are two problems here.
First being something that others have put, you need to make sure you turn the input into an integer using ".to_i" on your num variable.
Secondly, this code puts you into an infinite loop since you are using a "while" loop.
Since the number is only input once, you get stuck in the "while" loop forever no matter what the input is. Basically, "num" never stops being not 0.
You'd be better off using an if..else statement. Something like:
num = gets.chomp.to_i
if num != 0
if (num%2) == 0
puts 'yess'
else
puts 'nooo'
end
else
puts "that's 0, dude"
end
Integers have two methods for this. They are even? and odd?.
You can use this in your if statement as so:
if num.even?
puts 'yess'
else
puts 'nooo'
end
However, an easier way to write this is with ternary expressions:
puts num.even? ? "yes" : "no"
However, make sure num is an Integer. Anything coming from gets will be a String. So, you should be doing num = gets.chomp.to_i. Anything that is not a number, like "h", will return 0.
"5".to_i #=> 5
"h".to_i #=> 0

Resources