Getting User input in letters for elsif - ruby

I have been trying to get user input to execute a code. I have trying to get user input in letters not number but not finding how to. Like below is sample code I try get user input using gets.chomp() but its giving an error. Is there a way to get through this?
puts "Are you tall"
istall = gets.chomp()
puts "Are you male"
ismale = gets.chomp()
if
istall == true
ismale == false
print "Hello Erica, Welcome"
elsif
istall == false
ismale == true
print "Hello Nikola"
elsif
istall == false
ismale == false
print "Hello Cathie"
elsif
istall == true
istall == true
print "Hello Adam"
end

There are two problems with your code:
1. Gathering input
gets returns a string but you expect a boolean. Therefore, you have to convert the input, e.g.:
istall = gets.match?(/yes|true/i)
The above uses a regular expression to check whether gets matches "yes" or "true". The result (a boolean) is then assigned to istall.
2. Processing input
Your code
if
istall == true
ismale == false
print "Hello Erica, Welcome"
end
is parsed as:
if istall == true
# anything else
end
i.e. only the first condition is taken into account. To combine both conditions, you have to use &&:
if istall == true && ismale == false
print "Hello Erica, Welcome"
end
or a little more succinct:
if istall && !ismale
print "Hello Erica, Welcome"
end
Suggestions
For better readability, you should separate words by underscores, e.g.:
is_tall = true
is_male = false
You could put the people in an array, e.g. by creating a Person class via Struct:
Person = Struct.new(:name, :tall, :male)
people = [
Person.new('Erica', true, false),
Person.new('Nikola', false, true),
Person.new('Cathie', false, false),
Person.new('Adam', true, true),
]
Now you can find a person meeting your criteria:
is_tall = true # <- replace with actual user input
is_male = false
user = people.find { |person| person.tall == is_tall && person.male == is_male }
#=> #<struct Person name="Erica", tall=true, male=false>
and finally print a welcome message:
print "Hello #{user.name}, Welcome"

If you want to get char then use
char = STDIN.getc.chr
below is another way with your working script
puts "Are you tall"
is_tall = gets.chomp()[0].downcase == "y"
puts "Are you male"
is_male = gets.chomp()[0].downcase == "y"
result =
if is_tall && !is_male
"Hello Erica, Welcome"
elsif !is_tall && is_male
"Hello Nikola"
elsif !is_tall && is_male
"Hello Cathie"
elsif is_tall && is_tall
"Hello Adam"
end
print result

Map you info
You can use a Hash to store your data:
people = { male: { tall: 'Adam', short: 'Nikola' }, female: { tall: 'Erica', short: 'Cathie' } }
Define the way to interact with user
You need to get the answer from the user and validate it. This is one way using those methods:
def get_sex
message = 'Is this person male?'
get_user_input(message) ? :male : :female
end
def get_heigh
message = 'Is this person tall?'
get_user_input(message) ? :tall : :short
end
The methods above call a common method that loops and interact with the user, providing her with the information about the accepted answer:
def get_user_input(message)
valid_answers = {true: ['y', 'yes', 'true'], false: ['n', 'no', 'false']}
3.downto(1) do |n|
puts "Valid answers are #{valid_answers[:true]} or #{valid_answers[:false]}."
puts "(Default answer will be 'no' after #{n} times again."
puts message
user_input = gets.chomp
return true if valid_answers[:true].include? user_input
return false if valid_answers[:false].include? user_input
end
puts "Took 'no' as default answer\n\n"
end
Make use of it
Finally, just get the name by calling
name = people[get_sex][get_heigh]
When you have more people, consider to use a different mapping, something like
people = [{ name: 'Adam', heigh: 190, sex: :male }, { name: 'Erica', heigh: 175, sex: :female }, ...
Of course accessing the data is a bit different, you should look at Enumerable documentation (and also Array and Hash).

Related

Using include? command to search through the string containing mix of numbers and letters

I'm trying to check if the string is a valid phone number in the format
"XXXX XXXX", where every X is an integer from 0 to 9. If its valid return TRUE, else return FALSE.
I'm not sure why !(0..9).include?(char) doesnt work properly.
Any advice would be appreciated.
Thanks
def phone_number(str)
if str.length == 9 && str[4] = " "
str[4] = ""
str.each_char do |char|
if !(0..9).include?(char)
print false
end
end
return true
end
return false
end
print phone_number("1234 5678") # => true
puts
print phone_number("123 5678") # => false
puts
print phone_number("1234 df78") # => false
puts
print phone_number("12345678") # => false
I would advise using a regex to achieve what you want to do !
Here is the example code:
def phone_number(str)
!!str.match(/^\d{4}\s{1}\d{4}$/)
end
print phone_number("1234 5678") # => true
puts
print phone_number("123 5678") # => false
puts
print phone_number("1234 df78") # => false
puts
print phone_number("12345678") # => false
If you for some reason don’t use the regular expression, it’s still possible with plain Ruby:
λ = ->(str) {
str.split(' ').tap do |parts|
break [""] unless parts.size == 2
end.all? do |s|
s.length == 4 && s.delete('[0-9]').empty?
end
}
["1234 5678", "123 5678", "1234 df78", "12345678", "1234"].map(&λ)
#⇒ [true, false, false, false, false]
Here we split the string by parts, check that an amount of parts is exactly 2, both have a length of 4 and consist from digits only.

How do I parse strings into their data types?

I want to parse strings as follows:
"1.0" # => 1.0 (Float)
"1" # => 1 (FixNum)
"hello" # => "hello" (String)
"true" # => true (TrueClass)
"false" # => false (FalseClass)
I have the following code:
def parse_value(val)
raise ArgumentError, "value must be a string" unless val.is_a? String
if val.to_i.to_s == val
val.to_i
elsif val.to_f.to_s == val
val.to_f
elsif val == 'true'
true
elsif val == 'false'
false
else
val
end
end
This does what is needed, but it seems horrible and inefficient. What would be the best way to do this?
Short of using eval, you can't get much more concise/elegant code, I'm afraid. Here's a variant using case/when, but it's a lipstick on the same pig.
def parse_value(val)
raise ArgumentError, "value must be a string" unless val.is_a? String
case val
when /\A\d+\z/
val.to_i
when /\A\d+(\.\d+)?\z/
val.to_f
when 'true'
true
when 'false'
false
else
val
end
end
def parse_value(val)
raise ArgumentError, "value must be a string" unless val.is_a? String
case val
when /\A\d+\z/ then val.to_i
when /\A\d+(\.\d+)?\z/ then val.to_f
when 'true' then true
when 'false' then false
else val
end
end
I wrote this as a more concise version of the Sergios answer.
I would like feedback on whether this would be against Ruby style guidelines.
You could use eval along with a regular expression:
def parse_string(val)
raise ArgumentError, "value must be a string" unless val.is_a? String
val =~ /\A(\d+(\.\d+)?|true|false)\z/ ? eval(val) : val
end
parse_string '1.0' #=> 1.0
parse_string '1' #=> 1
parse_string 'hello' #=> "hello"
parse_string 'true' #=> true
parse_string 'false' #=> false
def convert(s)
i = Integer(s) rescue nil
return i if i
f = Float(s) rescue nil
return f if f
return true if s == "true"
return false if s == "false"
s
end
arr = %w| 1 1.0 true false hello |
#=> ["1", "1.0", "true", "false", "hello"]
arr.each { |s| e = convert(s); puts "#{e.class}: #{e}" }
# Fixnum: 1
# Float: 1.0
# TrueClass: true
# FalseClass: false
# String: hello

how to use .include? in Ruby with a hash statement

How do I get the .include? to work? When the user chooses a character, I want the console to print the puts ok statement and then go to the if statement.
name = {"1" => "Mario",
"2" => "Luigi",
"3" => "Kirby",
}
puts "Peach's apocalypse, will you survive?"
def character (prompt, options)
puts = "who will you be?"
options = name[1] || name[2] || name[3]
character = gets.chomp.downcase
until character.include? name
end
puts "ok #{name} all three of you run out of peach's castle which has been overrun"
if character = name[1] || name[2] || name[3]
puts ("zombies are in the castle grounds, there are weapons over the bridge")
puts "What do you do, charge through or sneak?"
x = gets.chomp.downcase
if x == "sneak"
puts "oh you died"
if x == "charge through"
puts "the zombies tumbled over the bridge's edge, you made it safe and sound"
else
puts "you did nothing and were eaten alive by Princess Peach"
end
end
end
end
It looks like you're calling include? on a string. This will only return true if you pass it a substring of itself. For example:
"Mario".include?("Mar") #=> true
You want to call include? on the array of keys in the name hash. You could do:
name.values.include?(character)
or more concisely
name.has_value?(character)
Here's some documentation on the include? method of the Array class and the include? method of the string class, as well as the has_value? method of the Hash class.
There's considerably more that needs modifying for this program to run as you're expecting it to though. Here's one working implementation:
puts "Peach's apocalypse, will you survive?"
names = {
"1" => "Mario",
"2" => "Luigi",
"3" => "Kirby"
}
def choose_character(character = "", options)
puts = "who will you be?"
options.each do |num, name|
puts "#{num}: #{name}"
end
until options.has_key? character or options.has_value? character
character = gets.chomp.capitalize
end
return options[character] || character
end
name = choose_character(names)
puts "ok #{name} all three of you run out of peach's castle which has been overrun"
puts "zombies are in the castle grounds, there are weapons over the bridge"
puts "What do you do, charge through or sneak?"
case gets.chomp.downcase
when "sneak"
puts "oh you died"
when "charge through"
puts "the zombies tumbled over the bridge's edge, you made it safe and sound"
else
puts "you did nothing and were eaten alive by Princess Peach"
end
The answer above is great and features awesome refactoring, but I would use
character = gets.strip.downcase
instead as it also gets rid of any potential whitespace.
To elaborate on the string thing, 'gets' stands for 'get string' (or at least so I was taught), so everything you get via 'gets' will be a string until you convert it further. Consider this:
2.2.1 :001 > puts "put in your input"
put in your input
=> nil
2.2.1 :002 > input = gets.strip
5
=> "5"
2.2.1 :003 > input.class
=> String
You would have to use .to_i to convert your input back to integer.

ruby using if inside loop with user input

I trying to make loop through if statement if user input is invalid it keep telling to enter number only or break if true
I tried this is my code
class String
def numeric?
Float(self) != nil rescue false
end
end
cond = false
puts "Enter number "
line = gets.chomp.strip
while cond == false
if (line.numeric? )
puts "Ok nice "
cond = true
else
puts "Please enter number only "
end
end
but it keep looping if the condition is false just printing "Please enter number only "
i will be very happy for any suggestion
Thank you
The problem is that after telling the user to just enter a number you don't read another number, you just loop back around.
The easiest way to fix this is to move the prompt and input into the while loop, a bit like this:
class String
def numeric?
Float(self) != nil rescue false
end
end
cond = false
while cond == false
puts "Enter number "
line = gets.chomp.strip
if (line.numeric? )
puts "Ok nice "
cond = true
else
puts "Please enter number only "
end
end
try this:
while cond == false
if (line.numeric? )
puts "Ok nice "
cond = true
else
puts "Please enter number only "
line = gets.chomp.strip
end
end
Right after overriding String method, try this:
while true
print "Enter number "
line = gets.chomp.strip
if line.numeric?
puts "Ok nice"
break
else
puts "Please enter number only"
end
end

Trying to go to a certain step after its completed one in ruby

Alright. I want it so the following would happen, Heres a sample:
puts "what would you like to see?"
var = gets.chomp
if var == "z"
puts "this"
elsif var == "d"
puts "stack"
elsif var == "y"
puts "overflow"
else
puts "I don't understand that."
end
Currently it works fine up until I want to have the user redefine the 'var'. Currently all the loops just loop back the puts from the elsif - i want it to ask for the user input again, then print out the elsif to that.
For example:
User types in y, the code would say overflow, then return to line 1. Any help would be awesome.
gets returns nil when there is no input, and since nil evaluates to false in a conditional, you can use gets in a loop like so
while var = gets
var.chomp!
if var == "z" # use == to test equality, not =
# do stuff
elsif var == "x"
# do stuff
....
end # while
You might find this works better with a case statement:
while var = gets
case var.chomp
when "z"
puts "this"
when "d"
puts "stack"
when "y"
puts "overflow"
else
puts "I don't understand that."
end # case
end # while
You're using the assignment operator (=) where you mean to test equality (==), I think.
You could also use case, but here's a version with while and if
print "Gimme an answer ('q' to quit) >> "
response = gets.chomp
while response != 'q'
if response == 'z'
puts "this"
elsif response == 'd'
puts "stack"
elsif response == 'y'
puts "overflow"
else
puts "I don't understand that."
end
print "Gimme another answer ('q' to quit) >> "
response = gets.chomp
end

Resources