I have the following code:
var_comparison = 5
print "Please enter a number: "
my_num = Integer(gets.chomp)
if my_num > var_comparison
print "You picked a number greater than 5!"
elsif my_num < var_comparison
print "You picked a number less than 5!"
elsif my_num > 99
print "Your number is too large, man."
else
print "You picked the number 5!"
end
The interpreter has no way of distinguishing between accepting the rule >5 or >99. How do I make it so that any number between 6-99 returns "You picked a number greater than 5!", but a number 100 or greater returns "Your number is too large, man!"?
Do I need to specifically state a range somehow? How would I best do that? Would it by the normal range methods e.g.
if my_num 6..99
or
if my_num.between(6..99)
?
You can express it as a range, but it would be much simpler to rearrange the order of your conditions to achieve what you want. The interpreter runs through conditional if/else statements in the order they are written, stopping when a condition is true or when else is reached. This makes the order important. We can know that if I get to an elsif, all the preceding conditions must have been false. So in your code:
var_comparison = 5
print "Please enter a number: "
my_num = Integer(gets.chomp)
if my_num > 99
# my_num is > 99
print "Your number is too large, man."
elsif my_num > var_comparison # to get here, my_num must be <= 99
print "You picked a number greater than 5!"
elsif my_num < var_comparison
print "You picked a number less than 5!"
else
print "You picked the number 5!"
end
If you needed to express a number as a range (if your conditional logic becomes more complex), you could do the following:
if (6..99).cover?(my_num)
Clearly the interpreter has no way of distinguishing between accepting the rule >5 or >99.
Yes it does: it tests the conditions in textual order! Since 100 is both greater than 5 and greater than 99, both conditions match, but in an if/elseif chain only one condition is ever evaluated. You should move the clauses around to achieve what you want.
Rather than use elseif, use case/when:
def test_range(foo)
case foo
when 5 .. 99
puts "#{ foo } is in range"
else
puts "#{ foo } is out of range"
end
end
test_range(4)
test_range(5)
test_range(99)
test_range(100)
# >> 4 is out of range
# >> 5 is in range
# >> 99 is in range
# >> 100 is out of range
In your code's case, it needs to be a bit different, because testing for less-than and greater-than doesn't lend itself to the normal range tests, because they expect discrete minimum and maximum values. So, instead, this is what I'd do:
my_num = 5
case
when my_num > 99
puts "Your number is too large, man."
when my_num > 5
puts "You picked a number greater than 5!"
when my_num < 5
puts "You picked a number less than 5!"
else
puts "You picked the number 5!"
end
I find that long chains of if/elseif/else become harder to read, so I prefer case statements.
As Kilian said, if clauses are evaluated in order, so the first to match is considered the chosen one.
You can even use case; when to achieve this:
Infinity = 1.0/0
var_comparison = 5
print "Please enter a number: "
my_num = Integer(gets.chomp)
case my_num
when -Infinity...var_comparison
puts "You picked a number less than #{var_comparison}!"
when var_comparison
puts "You picked the number #{var_comparison}!"
when var_comparison..99
puts "You picked a number greater than #{var_comparison}!"
else
puts "Your number is too large, man."
end
Related
I'm writing a pseudocode that describes the process of guessing a number between 1 and 100. After each guess, the player is told that the guess is too high or too low. The process continues until the player guesses the correct number. Can anyone give me any suggestions on what I should move around or remove, if any?
My code:
Start
Declarations
num GuessValue
num TRUE_VALUE = 47
output "Guess a number between 1 and 100."
input GuessValue
while GuessValue <> TRUE_VALUE
if GuessValue < TRUE_VALUE then
output "Number is too low."
elseif GuessValue > TRUE_VALUE then
output "Number is too high."
endwhile
output "Guess a number between 1 and 100."
input GuessValue
if GuessValue = TRUE_VALUE then
output "Correct!"
endif
end
I am brand new to programming. I am going through the Learn Ruby course on Codecademy. It's taking me through a exercise on experimenting with else/if statements. I'm attempting to run code where you input two integers (n and y) and print a statement based on whether n > y, n < y, or n == y.
As an example, when I input n = 5 and y = 15, it would print out the statement "I'm getting printed because n is greater than y) despite that not being true. Some set of numbers would print the correct statement, some set of numbers (as the one above) always printed the incorrect statement. After about 30 minutes of trying to figure out why it wouldn't work, I attempted adding the Integer method to my code and it works as intended. I'm just trying to understand why it wouldn't work properly prior to that.
Here is my code before:
print "Enter an integer for x:"
n = gets.chomp
print "Enter an integer for y:"
y = gets.chomp
if n < y
print "I'm getting printed because #{n} is less than #{y}"
elsif n > y
print "I'm getting printed because #{n} is greater than #{y}"
else
print "I'm getting printed because #{n} is equal to #{y}"
end
Here is my code after adding the Integer method:
print "Enter an integer for n:"
n = Integer(gets.chomp)
print "Enter an integer for y:"
y = Integer(gets.chomp)
if n < y
print "I'm getting printed because #{n} is less than #{y}"
elsif n > y
print "I'm getting printed because #{n} is greater than #{y}"
else
print "I'm getting printed because #{n} is equal to #{y}"
end
After going back in the lessons, I noticed an example Codecademy provided where they use the Integer method, but they do not go into detail about it. Regardless, I still added it to my code in the same fashion they used it in their example, and now it works properly. Like I said above, I just want to understand why it wouldn't work before and where it was going wrong in my code before I go any further in my lessons.
gets returns the string entered by the user, including the newline character created by pressing enter. gets.chomp removes the newline character at the end of the string, but still leaves the input a string.
And strings are sorted and compared alphabetically. "aa" < "b" correct when comparing strings and in the same sense "11" < "2" is correct for strings containing numbers.
But Integer(gets.chomp) translates the user input from a string containing a number into an integer (an actual number). And therefore the comparison works as expected afterward.
Documentation of the methods in play:
Kernel#gets
String#chomp
Kernel#Integer
This question already has answers here:
How to test if a string is basically an integer in quotes using Ruby
(19 answers)
Closed 6 years ago.
I have this code where I am entering input for sides of a triangle. Depending on the values, it will print it the triangle is equilateral, isoceles, or scalene. It's executing for number values, but how do I specify that the input should only be integers? For example, if I type in "w" , it should say invalid or error, but in this case, it executes. How do I solve this?
Basically, I am looking for a way to write that if a string were to be inputted, it should show up as an error (then I would write a print statement saying it is invalid). So could I put that into another if statement? (before the ones mentioned below)
Example Code:
puts "Enter the triangle length"
x = gets.chomp
puts "Enter the triangle width"
y = gets.chomp
puts "Enter the triangle height"
z = gets.chomp
if x == y and y == z
puts "This triangle is equilateral"
else if
x==y or y == z or x==z
puts "This triangle is isoceles"
else if
x!=y and y!=z and x!=z
puts "this triangle is scalene"
end
end
end
If you are dealing with integers, you can check this with ruby.
Note, this is not as robust as regex, but it covers most cases.
if (input != '0') && (input.to_i.to_s != input.strip)
# input is not a number
else
# input is a number
end
strip is there if you want to accept input with leading or trailing whitespace, otherwise you can leave it off.
While all the other answers are probably more or less robust, I would go with another one. Since you have a triangle sides lengths, they are to be greater than zero, right? Then one might use the side effect of String#to_i method: for everything that is not converting to integer it returns zero. Therefore:
x = gets.chomp.to_i
y = gets.chomp.to_i
z = gets.chomp.to_i
raise "Wrong input" unless x > 0 && y > 0 && z > 0
# ...
You can do something like this:
x = x.to_i
puts "Please enter an integer" if x == 0
Why?
Because:
"ABC".to_i # returns 0
You may be better off calling strip instead of chomp
gets.strip.to_i
An example:
## ruby user_age.rb
# input variables
name = ""
years = 0
MONTHS_PER_YEAR = 12 # a constant
# output variable
months = 0
# processing
print "What is your name? "
name = gets.strip
print "How many years old are you? "
years = gets.strip.to_i
puts "please enter an integer" if years == 0
months = years * MONTHS_PER_YEAR
puts "#{name}, at #{years} years old, "\
"you are #{months} months old."
There are several ways of doing it. If you allow for a leading sign,
x =~ /^[+-]?\d+$/
would be a possibility.
You will also have to think whether or not you allow surrounding or embedding spaces (for instance, a space between the sign and the first digit).
I assume that any string value that, when converted to a float, equals an integer is to be accepted and the integer value is to be returned. Moreover, I assume integers can be entered with the "xen" (or "xEn") notation, where x is an integer or float and n is an integer.
def integer(str)
x = Float(str) rescue nil
return nil if x==nil || x%1 > 0
x.to_i
end
integer("3") #=> 3
integer("-3") #=> -3
integer("3.0") #=> 3
integer("3.1") #=> nil
integer("9lives") #=> nil
integer("3e2") #=> 300
integer("-3.1e4") #=> -31000
integer("-30e-1") #=> -3
integer("3.0e-1") #=> nil
You could use Integer() to check if a string contains an integer:
Integer('1234')
#=> 1234
Integer('foo')
#=> ArgumentError: invalid value for Integer()
This could be combined with a retry:
begin
number = Integer(gets) rescue retry
end
I'm trying to see if the user enters a prime number. I want it to print "PRIME" or "NOT PRIME" to screen:
prime = ""
puts "TYPE IN A NUMBER TO SEE IF IT'S PRIME: "
gets.chomp(prime).to_i
for divide_by in 2..(prime.to_i - 1)
if prime % divide_by == 0
puts "NOT PRIME!!!"
else
puts "PRIME!!!"
end
end
Should I use a while loop instead?
Your gets.chomp(prime).to_i is not doing anything significant. I don't understand the purpose of chomp here, and it is not assigning any variable. If you want to receive the input number as prime, you need to do prime = gets.to_i.
Once you do that, you do not need to do to_i again as in for divide_by in 2..(prime.to_i - 1).
Furthermore, your logic is flawed. If prime is not divisible by 2, is that enough to say "PRIME!!"? I don't think so.
And if you are wondering what type of loop to use, the for loop is rarely useful. You should use each.
I am trying to teach myself Ruby using "Computer Science Programming Basics in Ruby" and other sources. I am stuck on a question and this book does not provide solutions.
The exercise is to write a program that given two points on a 2d graph outputs a message describing the line (horizontal or vertical) or it's slope (positive or negative). This is what I have so far.
# Get the first point from a user
puts "Please enter Point A's X value."
x_1 = gets.to_i
puts "Please enter Point A's Y value."
y_1 = gets.to_i
# Get the second point from a user
puts "Please enter Point B's X value."
x_2 = gets.to_i
puts "Please enter Point B's Y value."
y_2 = gets.to_i
slope = ((y_1-y_2) / (x_1-x_2))
#Check to see if the line is vertical or horizontal and the slope is +ve or -ve
case
when (slope == 0) then
puts "The line is horizontal."
when (slope > 0) then
puts "The slope is positive."
when (slope < 0) then
puts "The slope is negative."
when (x_1-x_2 == 0) then
puts "The line is vertical."
end
How would I make a value that is divided by zero return puts "The line is vertical!" without getting the ZeroDivisionError ?
Replace all to_i with to_f. Then you can test for a vertical line with slope.abs == Float::INFINITY.
For completeness, include the test slope.nan? as the first test to output Those are not two distinct points! This will cover the case when they enter in the same point twice.
x == 0 ? puts "The line is vertical!" : y/x
You can also rescue divide by zero operations in ruby
begin
1/0
rescue ZeroDivisionError => kaboom
p kaboom
end
One way to do this is to follow your equation with a rescue, such as
2/0 # this throws an error
2/0 rescue "This line is vertical" # this prints the rescue
2/2 rescue "This line is vertical" # this prints 1