Newbie Ruby question - project basic calculator - ruby

I just started to learn ruby and I have a small project I'm working on. I'm making a simple two number calculator. What I want to do is get the user to input two numbers and then ask them if they would like to add/subtract/multiply them. My problem is, I want a message to fire if the user doesn't type in add/subtract/multiply. Say the user types Ad instead of Add, I want the computer to say "I don't understand!" I'm not sure how to execute this.
Here is my code so far.
puts "Welcome to math.rb!"
puts "Enter a number!"
user = gets.to_i
puts "Enter another number!"
user2 = gets.to_i
puts "What would you like to do with your number? You can add, subtract, or multiply!"
math = gets.chomp.downcase
if math == "add"
puts user + user2
end
if math == "subtract"
puts user - user2
end
if math == "multiply"
puts user * user2
end
if math != ["add", "subtract", "multiply"]
puts "I don't understand"
end

Use if statement with elsif and else.
math = gets.chomp.downcase
if math == "add"
puts user + user2
elsif math == "subtract"
puts user - user2
elsif math == "multiply"
puts user * user2
else
puts "I don't understand"
end
case is also nice for this usecase.
math = gets.chomp.downcase
case math
when "add"
puts user + user2
when "subtract"
puts user - user2
when "multiply"
puts user * user2
else
puts "I don't understand"
end

You can shorten the code further and use a hash to store allowed operations, and eval to evaluate the resulting string as an arithmetic expression. Even though eval is not safe in many cases, here we strictly control its input, making it much safer.
Note that to control the input, I keep the to_i conversion (without it, the user can enter arbitrary strings, which would be unsafe to be directly eval-ed). The hash further controls the input by converting the string operators to hash values, which we completely control.
puts 'Welcome to math.rb!'
puts 'Enter a number!'
x = gets.to_i
puts 'Enter another number!'
y = gets.to_i
puts 'What would you like to do with your number? You can add, subtract, or multiply!'
op_str = gets.chomp.downcase
op_str_to_math = { 'add' => '+', 'subtract' => '-', 'multiply' => '*' }
if op_str_to_math.key? op_str
puts eval "#{x} #{op_str_to_math[op_str]} #{y}"
else
puts "I don't understand"
end
op_str_to_math = { ... } defines a hash with key => value pairs. The elements of the hash can be accessed like so:
puts op_str_to_math['add'] # prints: +
puts op_str_to_math['subtract'] # prints: -
We check if the operator is allowed by looking up the user input (op_str) among the hash keys: if op_str_to_math.key? op_str .
eval "..." evaluates the string. Because the string is double-quoted, the values in #{...} are interpolated. So if the user entered, for example, 2, 3, add, the string gets interpolated to 2 + 3, which is 5.
Finally, I replaced where appropriate all double quotes with single quotes, per Ruby coding conventions.

Related

Using Key Value pairs in Hash as question and answer

I'm working on an assignment in my code bootcamp, it involves ruby.
Create a program with a hash of countries & capitals such as the following:
cos_n_caps = {
"USA" => "Washington, DC",
"Canada"=>"Ottawa",
"United Kingdom"=>"London",
"France"=>"Paris",
"Germany"=>"Berlin",
"Egypt"=>"Cairo",
"Ghana"=>"Accra",
"Kenya"=>"Nairobi",
"Somalia"=>"Mogadishu",
"Sudan"=>"Khartoum",
"Tunisia"=>"Tunis",
"Japan"=>"Tokyo",
"China"=>"Beijing",
"Thailand"=>"Bangkok",
"India"=>"New Delhi",
"Philippines"=>"Manila",
"Australia"=>"Canberra",
"Kyrgyzstan"=>"Bishkek"
}
Ask the user for the capital of each country, and tell them if they are correct. Also, keep score and give them their score at the end of the quiz.
I want to know if I can somehow cycle through the list of keys and ask for user_input after each key and then check again value.
I've tried to use hash.for_each{|key| puts key}, but I don't know how to ask for user_input between the keys.
This is what I was going to do, unless I can find something easier:
s = "What is the capital of"
score = 0
count = 0
until count == 1
puts "#{s} USA"
a = gets.chomp.downcase
if a == c["USA"].downcase
puts "Congrats"
score += 1
count += 1
else
puts "nope"
count +=1
end
end
Use Hash#each to loop through each pair of countries and capitals. In that loop, use Kernel#gets to read their answer and String#chomp to remove the newline off their answer.
cos_n_caps.each do |country,capital|
puts "What is the capital of #{country}?"
answer = gets.chomp
if capital.downcase == answer.downcase
puts "Right!"
else
puts "Sorry, it's #{capital}."
end
end

Calculator program in ruby, taking "2+3" and giving output 6, issues with more than 2 digit numbers

First post, excuse if I break any etiquette. I am beginning, so this might be simple.
Trying to code in ruby, a calculator, where user inputs arithmetic sentence (only binary, PEMDAS/BIDMAS will do later) and the answer comes out.
Here is my code, by only works for single digit numbers.
class Calculator
def initializer (a,b)
#a = a,
#b = b
end
def add(a, b)
a+b
end
def subtract(a, b)
a-b
end
def multiply(a,b)
a*b
end
def divide (a,b)
a/b
end
def powers (a,b)
a**b
end
end
puts "Enter an expression to be evaluated"
a = gets.chomp.gsub(/\s+/, "")
puts case a[1]
when "+"
"#{a[0]} + #{a[2]} = #{Calculator.new.add(a[0].to_f,a[2].to_f)}"
when "-"
"#{a[0]} - #{a[2]} = #{Calculator.new.subtract(a[0].to_f,a[2].to_f)}"
when "*" || "x" || "X"
"#{a[0]} x #{a[2]} = #{Calculator.new.multiply(a[0].to_f,a[2].to_f)}"
when "/"
"#{a[0]} / #{a[2]} = #{Calculator.new.divide(a[0].to_f,a[2].to_f)}"
when "^"
"#{a[0]} to the power #{a[2]} = #Calculator.new.powers(a[0].to_f,a[2].to_f)}"
else
"Not valid"
end
I was thinking of trying to split a string like "234+342" (234 and 342 can be any sized length numbers) into an array such as ["234","+","342"].
But I am stuck on how to do this??? Or is there another way??
Help will be appreciated, just a personal challenge.
Thanks
As you already realized the issue is with the way you are carrying operations over input string.
The simplest way to proceed can be to ask users for two numbers and then ask them to enter the operation needed. Something like:
puts "Enter first number"
a = gets.chomp
puts "Enter second number"
b = gets.chomp
puts "Enter required operation [+, -, *, /]"
c = gets.chomp
You can do this all in one shot too, the way you are already trying, however I would advice against it as you never know what user will enter. Eg:
puts "Enter an expression to be evaluated"
a = gets.chomp # user enters: 123 + 457
# => "123 + 457"
Now extracting number:
numbers = a.scan(/\d+/)
#=> ["123", "457"]
operator = a[/\W+/]
#=> " + "
You can then proceed with your switch case.

Command not found Ruby - trying to create 24 game

I am trying to solve the "24" game. The point of the game is to generate 4 random integers from 1-9 and ask the player to use addition, subtraction, multiplication, or division to get the number 24. My code runs fine until a player enters a number, and then I get "Command not found". Can someone please take a look at this:
def evaluate (input,solved_v)
input = eval (input.to_f)
#convert to a float and then evaluates it; it computes
if input == 24
solved_v = true
puts "great job! you did it!"
else
puts "please try again"
end
end
def test_entry (input)
if input.scan(%r{[^\d\s()+*/-]}).empty?
#this scan detects letters and special characters because only numbers work
true
else
false
end
end
puts
puts "try to use +, -, / or * to"
puts "get 24 from the integers provided"
puts
series = (1..4).collect{ rand(1..9)}
#generates 4 random numbers between 1 and 9
for i in series
puts i
end
puts "Please guess"
solved = false
unless solved = true
user_input = gets.chomp
if test_entry(user_input) == true
evaluate(user_input)
else
puts "invalid characters entered"
puts "please try again"
puts
end
end
There are numerous problems with your program.
Don't put spaces between your method names and parentheses.
eval takes a string argument, not a float.
Ruby passes arguments by value, so solved_v isn't going to get
returned. Make it the return value of your evaluate method. I'd also
suggest renaming your methods to express their boolean intent. See below...
Don't check boolean expressions for equality to true or false, just use them.
def correct?(input)
if eval(input) == 24
puts "great job! you did it!"
true
else
puts "please try again"
false
end
end
def good_entry?(input)
input.scan(%r{[^\d\s()+*/-]}).empty?
end
and they get used as follows
while true
user_input = gets.chomp
if good_entry?(user_input)
break if correct?(user_input)
else
...
end
end
Finally, note that you're not actually checking that the input provided by the user uses only the supplied random numbers.

How Do You Put 'gets' Input Into An Array?

Ruby noob here learning the ropes. I'm currently going through this tutorial and am working on this exercise:
Let's write a program which asks us to
type in as many words as we want (one
word per line, continuing until we
just press Enter on an empty line),
and which then repeats the words back
to us in alphabetical order.
I'm ignoring the alphabetical order part, for now.
Here is my code:
puts 'Hi, do you need something sorted?'
yn = gets.chomp
while yn != 'no'
puts 'What else?'
array = [gets]
yn = gets.chomp
end
puts 'Here\'s what you told me: ' +array.to_s
I've tweaked this for a few hours. To prevent my laptop from breaking due to an act of frustration I'm taking a break. Can anybody with more experience, and possibly more patience, point out my errors?
Keep in mind that every time you gets is a method that asks the user for input. On your lines:
array = [gets]
yn = gets.chomp
You are actually asking for input twice. Instead, store the user input somewhere (such as the array, see below) and get the stored value rather than asking the user twice.
Further, array = [gets] replaces the existing array with an array containing one element (the user input). You are never building up user input into the array. Instead, initialize the array before the while loop and use << in the loop:
array = Array.new
...
while yn != "no"
...
array << gets.chomp
yn = array.last
...
end
If you're having difficulty with something, the first thing you should do is try something simpler.
Rather than doing gets and looping, just try doing a simple gets.
puts 'Hi, do you need something sorted?'
yn = gets.chomp
Then I'd see if yn was what I expected.
The next thing I'd do is, rather than doing a loop many times, just try it once
puts 'Hi, do you need something sorted?'
yn = gets.chomp
if yn != 'no'
puts 'What else?'
array = [gets]
yn = gets.chomp
STDERR.puts "array is #{array.inspect}"
STDERR.puts "yn is #{yn.inspect}"
end
Then you'd hopefully realize that array and yn are both getting input, which wouldn't make sense.
For more hints on how to debug Ruby code, see How do I debug Ruby scripts?
I was having the same problem. Here is where I ended up (I think it meets all the specifications from the question):
puts 'Type in as many words as you\'d like. When you\'re finished, press enter on an empty line'
array = []
input = ' '
while input != ''
input = gets.chomp
array.push input
end
puts
puts array.sort
while yn != "no"
array << yn
print "What else? "
yn = gets.chomp
end
The "<<" appends yn to your array. (The only reason I used print is because it puts the cursor right next to the question mark instead of on the next line. No other reason)
#encoding:utf-8
x = Array.new
puts "enter something:".capitalize
y = ''
while y !=#nill
y = gets.chomp
x.push y
end
x.delete ('')
x.compact
puts "You entered: " + x.sort.to_s
puts "Objects in array: " + x.size.to_s
#made by ~Pick#chu!!!
Another way to read ‘Arrays’ from the console could be:
1: print “enter the values: ”
2: a = gets.chomp # input: “tom mark rosiel suresh albert”
3: array = a.split(‘ ‘) # .split() method return an array
4: p array # ["tom, "mark, "rosiel", "suresh", "albert"]
now, lets say you want an array of integers, all you have to do is:
# input “1 2 3 4 5″
3: array = a.split(‘ ‘).map{ |value| value.to_i }
4: p array # [1, 2, 3, 4, 5]
the clue here is to use a standard separator in order to use the .split() function.
here is how I've done this program:
array = [ ]
input = gets.chomp
while
input != ''
array.push input
input = gets.chomp
end
puts array
puts
puts array.sort

Misbehaving Case Statement

I'm messing around in Ruby some more. I have a file containing a class with two methods and the following code:
if __FILE__ == $0
seq = NumericSequence.new
puts "\n1. Fibonacci Sequence"
puts "\n2. Pascal\'s Triangle"
puts "\nEnter your selection: "
choice = gets
puts "\nExcellent choice."
choice = case
when 1
puts "\n\nHow many fibonacci numbers would you like? "
limit = gets.to_i
seq.fibo(limit) { |x| puts "Fibonacci number: #{x}\n" }
when 2
puts "\n\nHow many rows of Pascal's Triangle would you like?"
n = gets.to_i
(0..n).each {|num| seq.pascal_triangle_row(num) \
{|row| puts "#{row} "}; puts "\n"}
end
end
How come if I run the code and supply option 2, it still runs the first case?
Your case syntax is wrong. Should be like this:
case choice
when '1'
some code
when '2'
some other code
end
Take a look here.
You also need to compare your variable against strings, as gets reads and returns user input as a string.
Your bug is this: choice = case should be case choice.
You're providing a case statement with no "default" object, so the first clause, when 1, always returns true.
Effectively, you've written: choice = if 1 then ... elsif 2 then ... end
And, as Mladen mentioned, compare strings to strings or convert to int: choice = gets.to_i

Resources