Optional digits in a sum? - ruby

This is my first programming language so please bear with me!
I can't quite figure out where it's going wrong. I'm not necessarily asking for a solution as this is a learning exercise; I just need a helping hand as to where I should be looking.
#Calculate the sum of two numbers and an optional third
#get first number
print "Please enter your first digit: "
value_1 = gets.chomp
print value_1
#get second number
print "Please enter your second digit: "
value_2 = gets.chomp
#get the additional number
print "Do you want to add an additional number?"
add_num_req = gets.chomp
#calculate result and put
if gets.chomp = "yes" || "Yes" || "YES"
print "Please enter the additional digit: "
add_num_1 = gets.chomp
#print sum of three values
print "Answer: " , (value_1.to_i + value_2.to_i + add_num_1.to_i), "\n";
else
#print value_1 + value_2
print "Answer: " , (value_1.to_i + value_2.to_i), "\n";
end
But this produces a blank return after putting in the response to the get.chomp for an additional digit. Any help?

As a fourth alternative (and what I usually use) ...
if gets.chomp.downcase == "yes"
As with the regex match, it also accepts unexpected case arrangements (e.g. "yEs", "yES", "YeS" and so on)

In Ruby you can't compare a variable to many options as you have there. You have to do something like this:
if add_num_req == "yes" || add_num_req == "Yes" || add_num_req == "YES"
Another way to do it is to take advantage of the Enumerable module. But this is a little more advanced, although you will find it useful as you continue to use Ruby.
answers = ["yes", "Yes", "YES"]
if answers.any? { |e| add_num_req == e }

change:
if gets.chomp = "yes" || "Yes" || "YES" #you are using = instead of == which is equality
to:
if gets.chomp.match(/yes/i) #This is a case-insensitive regex to match "yes", "Yes" or "YES"

A third alternative:
if ( ['yes','Yes','YES'].include?(add_num_req) )
...

Here's a more Ruby-like way to write your program:
def doit
value_1 = obtain_entry("Please enter your first digit: ").to_i
value_2 = obtain_entry("Please enter your second digit: ").to_i
loop do
case obtain_entry("Do you want to add an additional digit?: ")
when "yes", "Yes", "YES"
print "Please enter the additional digit: "
puts "Answer: #{value_1 + value_2 + gets.to_i}"
break
when "no", "No", "NO"
puts "Answer: #{value_1 + value_2}"
break
end
end
end
def obtain_entry(str)
print str
gets.chomp
end
doit
A few points:
Since you are getting a response from the user more than once, put that in a method to which you pass the question to be asked (here, obtain_entry). For answers that are to be treated as integers, you may as well convert them to integers when they are returned. (In a real application you would of course want to make various checks on the type and reasonableness of answers.)
Do not define variables when it is not necessary to do so. For example, I've not created a variable for the reply to either of the questions "Do you want to add an additional digit?: " and "Please enter the additional digit: ".
I've added an endless loop that ensures that an acceptable "yes" or "no" answer is given to the question "Do you want to add an additional digit?. If an acceptable answer is given, we break out of the loop; if not, the question is repeated and the user is given another opportunity to answer.
It is often convenient to use a case statement in the way I have done when several replies result in the same action being taken.
When displaying output, I've used the more conventional way of forming a string, using string interpolation (e.g., #{variable_x}), as in puts "Answer: #{value_1 + value_2 + gets.to_i}". You must use double quotes for string interpolation to work.
When using IO#gets to obtain a string that is to be converted to an integer, String#chomp is not needed; gets.to_i is sufficient.

My guess is your problem is happening here:
#get the additional number
print "Do you want to add an additional number?"
add_num_req = gets.chomp
#calculate result and put
if gets.chomp = "yes" || "Yes" || "YES"
Since you are calling gets.chomp twice for the same input and using an assignment operator = in place of comparison operator ==. Also, as someone else has pointed out, each || operator should evaluate a Boolean expression, e.g. add_num_req == 'yes' || add_num_req == 'YES'. Without modifying your code too much, I think you want something like this:
print "Do you want to add an additional number? "
add_num_req = gets.chomp
#calculate results and put
if add_num_req.downcase == 'yes'
# ...
On that note, if you plan to be evaluating a lot of strings, regular expressions are invaluable. I still can't write a decent regexp without checking a reference, but even so they make a world of difference!

Related

How to use .include? to capture multiple options resulting in same operation

I am writing a simple calculator that asks the user what calculation she wants to perform with a choice between '+', '-', '*' and '/'.
The code works when I separate each option with ||. However, I would prefer to use .include? to avoid repetition.
while play_again != "N"
puts "Enter a first number:"
first_num = gets.chomp.to_i
puts "Enter a second number:"
second_num = gets.chomp.to_i
puts "Which operation would you like to perform? '+', '-', 'x', '/'"
operator = gets.chomp
if operator == "+" || operator == "-" || operator == "x" || operator
== "/"
puts calculator(first_num, second_num, operator)
else
puts "That wasn't a valid selection."
end
puts "Do you want to calculate something else? (Y/N)"
play_again = gets.chomp
end
I tried to rewrite the line starting with if operator with if operator.include?(%w[+ - X /].to_s) but this doesn't capture the user input properly and always puts " That wasn't a valid selection."
In this way
if %w(+ - * /).include?(operator)
a shorter way for this one
if ["+", "-", "*", "/"].include?(operator)
This makes sense, don't you think? You're checking that the operator is included in some options. In this case the options are four strings, the symbols for the four basic mathematical operations.
A case when control structure lets you specify multiple conditionals. Sounds hard, is actually easy:
puts case operator
when '+', '-', 'x', '/' then calculator(first_num, second_num, operator)
else "That wasn't a valid selection."
end

How do I check if user input is an integer in Ruby?

I am trying to loop until user inputs an integer. When user inputs a letter, the following code should print "Think of a number":
print "Think of a number "
while user_input = gets.to_i
if user_input.is_a? Integer
puts "your number is #{user_input}"
break
else
print "Think of a number "
end
end
I succeeded with my code when user inputs an integer. However when user inputs a string, the to_i method returns 0, and does not execute the else statement because it is a number.
The main issue with your code is String#to_i method is omnivorous.
"0".to_i #⇒ 0
"0.1".to_i #⇒ 0
"foo".to_i #⇒ 0
That said, user_input in your code is always integer.
What you probably want is to accept digits only (and maybe a leading minus for negatives.) The only concise way to accept a subset of characters is a regular expression.
# chomp to strip out trailing carriage return
user_input = gets.chomp
if user_input =~ /\A-?\d+\z/
...
The regular expression above means nothing save for digits with optional leading minus.
Or, even better (credits to #Stefan)
if gets =~ /\A-?\d+\Z/
If you only want to accept postive digits, you can use a range:
user_input = gets.chomp
if ('0'..'9').cover? user_input
let check below one used Integer(gets.chomp) rescue ''
print "Think of a number "
while user_input = Integer(gets.chomp) rescue ''
if user_input.is_a? Integer
puts "your number is #{user_input}"
break
else
print "Think of a number "
end
end
I came across a similar problem. I ended up doing this:
if user_input.strip == user_input.to_i.to_s
# More code here!
end
Testing for float would be:
if user_input.strip == user_input.to_f.to_s
# More code here!
end
Solved my issue. See if it helps.

Code to see if user input was filled

I want to check if a field was filled in. I have an imcompleted code:
print "What is your name?"
user_input = gets.chomp.upcase
if user_input = ??
print "Nice to meet you user_input!"
else
puts "Please enter your name."
end
How do I complete the code to do that?
Under the premise that you would like to:
Print out a message: "What is your name?"
Have the user enter their name and store it in the user_input variable(with gets.chomp)
Output either "Nice to meet you << user name >>" or "Please enter your name" depending on whether the input matches certain criteria
...we have a few changes to make.
The first being the condition of checking to make sure the input isn't blank and the second being seeing if the input matches a certain value.
First, let's check to see if the input is empty before continuing. We can use String#empty to make sure the string has at least one character (including whitespace):
print "What is your name?"
user_input = gets.chomp.upcase
# Check to make sure the input isn't empty
if !user_input.empty?
print "Nice to meet you user_input!"
else
puts "Please enter your name."
end
Then, we can check to see if the input matches certain criteria. Unfortunately, your question doesn't specify what these criteria are, so as other users are suggesting you can use regex to see if it matches a particular pattern, or just use a hard coded string to compare:
print "What is your name?"
user_input = gets.chomp.upcase
# After making sure the input is empty, check to make sure it matches the string "Bob"
if !user_input.empty? && user.input == "Bob"
print "Nice to meet you user_input!"
else
puts "Please enter your name."
end
Lastly, there is one bug in the code. The output once a user's input has been validated will always be "Nice to meet you user_input", even when the user_input variable is another value. This is because we aren't using String Interpolation properly:
print "What is your name?"
user_input = gets.chomp.upcase
if !user_input.empty? && user.input == "Bob"
# When using string interpolation, surround the variable you'd like to print with #{}
print "Nice to meet you #{user_input}!"
else
puts "Please enter your name."
end
As other users have stated, you should consider fine tuning the requirements of your problem a bit more. You can add a lot of detail and experimentation to this simple example!
There's a lot of context missing from the question, but there are a couple of things that may be helpful to you.
Basic check if it's nil or empty:
if user_input.nil? || user_input.empty?
# Ask the user to try again
end
Check if it matches a pattern you specify using a Regex (see https://ruby-doc.org/core-2.1.1/Regexp.html). For example:
if user_input =~ /^[[:upper:]][[:lower:]]+/
# One uppercase character, followed by at least one lowercase
end
The second option has far more possibilities, but again it depends on your needs.
if user_input.blank?
puts "please enter your name"
else
puts "Nice to met you"
end

How to tell users how many years they have left till 21

What I am trying to do is tell the your how many years they have left till there 21. I have been trying to think of it but nothing.
Here is my code:
#!/usr/bin/env ruby
under_age = 21
print "What is your first name? "
first_name = gets.chomp
print "What is your last name? "
last_name = gets.chomp
print "What is your age? "
user_age = Integer(gets.chomp)
if user_age < legal_age
print "You may not continue"
else if > 21
print "Welcome!"
You set this at the beginning:
under_age = 21
But then you don't use it, you use legal_age I think if you change the first line to
legal_age = 21
and then drop the last less-than like:
if user_age < legal_age
years_to_wait = 21 - user_age
print "You may not continue, come back in #{years_to_wait} year#{years_to_wait > 1? 's' : ''} "
else
print "Welcome!"
end
I added a little bit there that you may have not covered being new to Ruby. Just to be clear:
#{years_to_wait} inside of a double quote string (" vs ') prints out as the value of the variable. If the variable is 1, then the response would be the singular "year", if greater than 1 it would be plural "years". I used the very compact version of if/then/else to make it clean (called the Ternary operator).
The first part is the comparison followed by the ? for an implied "if"
years_to_wait > 1?
followed by the return value if true which is the character 's' then a ":" and the return value if false, no character ''. That gets us the correct version of the word "year(s)" when the interpolation happens.
Your variable names are all over the place. But I think you just want
legal_age - user_age
Also your last if is unnessary
You miss the variable in the elsif statement in ruby it should look:
if user_age < 21
print "You may not continue"
elsif user_age > 21
print "Welcome!"
end
the legal_age variable is also not assigned, maybe you mean the under_age variable instead.
your if..else syntax is not proper. for more info
if user_age < under_age
print "You may not continue, come back after #{under_age - user_age} years"
else
print "Welcome!"
end
Note: legal_age is also not assigned, you can replace it with under_age or change under_age to legal_age

how to meet a condition before going on to the next step?

how do I loop if a condition is not met?
print "Please enter first number "
first_number = gets.chomp
if first_number =~ /[a-zA-Z]/
puts "not a number"
end
As per the code posted above, if you enter a letter, you'll get the statement of it not being a number.
How do I repeat it, if a user enters a letter?
As of now, it goes to the next one which is this:
print "Please enter second number "
second_number = gets.chomp
if second_number =~ /[a-zA-Z]/
puts "not a number"
end
I don't want it to it to go to the next one, until the user has entered a number in the first one.
You can use while and until as a modifier to a block. This will run the block first and then check a conditional and run the block again until it passes, which is the behavior you want.
begin
puts 'Please enter first number'
first_number = gets.chomp
end until first_number =~ /\d+/
I suggest you consider doing it like this:
num = nil # initialize to anything
loop do
puts 'Enter a number'
num = gets.chomp.strip
case num
when /^\d+$/
break
when /^[a-z]+$/i
print "You entered one or more letters and no digits."
else
print "You made some other illegal entry."
end
puts " Try again"
end
puts "You enterered the number #{num}"
Some notes:
num must be initialized (to anything) before the loop in order for it to be visible after the loop's end statement.
the case statement, since it uses === for evaluating when expressions, allows you to enter a regex for each case.
^ and $ in the regexes are anchors, so that, for example, "34b" =~ /^\d+$/ => nil (what I assume you want), rather than "34b" =~ /\d+/ => 0.
the i in /[a-z]+$/i allows matching letters to be uppercase or lowercase.
the user may enter one or more digits, or one or more letters, but there are many other possibilities as well ("3$,a"), so I added another "catch-all" possibility in the case statement.

Resources