How would I set a variable to a boolean? - ruby

Instead of gets.chomp, is there anything I can use to turn their response into a boolean?
puts "Do you like pizza? (yes or no)"
pizza = gets.chomp
if pizza == "yes"
pizza = true
else
pizza = false
end
I tried gets.to_b and gets.bool, but it doesn't seems to be working.

I would just use get[0] what returns the first character and allows you to accept y or yes:
puts 'Do you like pizza? (yes or no)'
pizza = gets[0] == 'y'
Or you can define a to_b method on String yourself:
class String
def to_b
# might want to add even more values to the list
%w( y yes true 1 ).include?(self.chomp.downcase)
end
end
'yes'.to_b
#=> true
'no'.to_b
#=> false

You can do something like this:
puts "Do you like pizza? [yes/no]:"
pizza = gets.chomp
case pizza
when 'y','Y','yes'
pizza = true
when 'n', 'N','no'
pizza = false
end
puts pizza

Related

I can't interpolate my hash because apparently it is nil class? Could anyone shed some light on this?

Is there an alternative to iteration or a condition I can make that will allow me to interpolate the values of just one hash? I've inspected the results of my input and apparently the array that i'm saving my hashes into disappears when there is only one hash. I've also tested the results and they're of Nil class.
def print_with_index(students)
students.each_with_index do |student, index|
index_plus_one = index + 1
puts "#{index_plus_one}. #{students[:name]} (#{students[:cohort]} cohort)"
end
end
How do i solve my problem and also why do hashes behave this way?
Full code:
def print_header
puts "The students of Villains Academy"
puts "--------------"
end
def print_footer(names)
puts "Overall, we have #{names.count} great students"
end
def input_students
puts "Please enter the names and then the cohort of the students"
puts "To finish, just hit return twice"
#created an empty array
students = []
#getting the first name
name = gets.chomp
cohort = gets.chomp.to_sym
if cohort.empty?
cohort = :november
end
if cohort !~ /january|february|march|april|may|june|july|august|september|october|november|december/
puts "Please enter a valid month"
puts "Warning months are case sensitive. Please enter in lowercase characters."
cohort = gets.chomp.to_sym
end
while !name.empty? do
# add the student hash to the array called students
students << {name: name, cohort: cohort}
if students.count > 1
puts "Now we have #{students.count} students"
else students.count == 1
puts "Now we have #{students.count} student"
end
#getting another name from the user
name = gets.chomp
cohort = gets.chomp.to_sym
if cohort.empty?
cohort = :november
end
if cohort !~ /january|february|march|april|may|june|july|august|september|october|november|december/
puts "Please enter a valid month"
puts "Warning months are case sensitive. Please enter in lowercase characters."
cohort = gets.chomp.to_sym
end
end
bycohort = students.sort_by { |v| v[:cohort] }
filter = students.select! { |student| student[:cohort] == :november }
puts bycohort #This allows me to see all of my hashes before they are filtered
puts ""
bycohort
filter
end
def print_with_index(students)
students.each_with_index do |students, index|
index_plus_one = index + 1
puts "#{index_plus_one}. #{students[:name]} (#{students[:cohort]} cohort)"
end
end
### body ###
students = input_students
print_header
print_with_index(students)
print_footer(students)
this works for me though, i think with each_with_index enum, you have to pass in an array of hashes i.e. [{...}, {...}, {...}], not a single hash with multiple keys-values
def print_with_index(students)
students.each_with_index do |students, index|
index_plus_one = index + 1
puts "#{index_plus_one}. #{students[:name]} (#{students[:cohort]} cohort)"
end
end
print_with_index([{name:"b", cohort: "c"}])
# 1. b (c cohort)
You should use student instead of students as the block parameter. You can check if the student object is nil.
def print_with_index(students)
students.each_with_index do |student, index|
if !student.nil?
index_plus_one = index + 1
puts "#{index_plus_one}. #{student[:name]} (#{student[:cohort]} cohort)"
end
end
end

How to get a default value with hashes in ruby

I am trying to get a default value whilst using hashes in ruby. Looking up the documentation you use a fetch method. So if a hash is not entered then it defaults to a value. This is my code.
def input_students
puts "Please enter the names and hobbies of the students plus country of birth"
puts "To finish, just hit return three times"
#create the empty array
students = []
hobbies = []
country = []
cohort = []
# Get the first name
name = gets.chomp
hobbies = gets.chomp
country = gets.chomp
cohort = gets.chomp
while !name.empty? && !hobbies.empty? && !country.empty? && cohort.fetch(:cohort, january) do #This is to do with entering twice
students << {name: name, hobbies: hobbies, country: country, cohort: cohort} #import part of the code.
puts "Now we have #{students.count} students"
# get another name from the user
name = gets.chomp
hobbies = gets.chomp
country = gets.chomp
cohort = gets.chomp
end
students
end
You just need to give fetch a default it can handle. It doesn't know what to do with january as you haven't declared any variable with that name. If you want to set the default value to the string "january", then you just need to quote it like this:
cohort.fetch(:cohort, "january")
There are some decent examples in the documentation for fetch.
Also, cohort isn't a Hash, it's a String since gets.chomp returns a String. fetch is for "fetching" values from a Hash. The way you're using it should be throwing an error similar to: undefined method 'fetch' for "whatever text you entered":String.
Finally, since you're using it in a conditional, the result of your call to fetch is being evaluated for its truthiness. If you're setting a default, it will always be evaluated as true.
If you just want to set a default for cohort if it's empty, you can just do something like this:
cohort = gets.chomp
cohort = "january" if cohort.empty?
while !name.empty? && !hobbies.empty? && !country.empty?
students << {
name: name,
hobbies: hobbies,
country: country,
cohort: cohort
}
... # do more stuff
Hope that's helpful.
You have several options. #dinjas mentions one, likely the one you want to use. Suppose your hash is
h = { :a=>1 }
Then
h[:a] #=> 1
h[:b] #=> nil
Let's say the default is 4. Then as dinjas suggests, you can write
h.fetch(:a, 4) #=> 1
h.fetch(:b, 4) #=> 4
But other options are
h.fetch(:a) rescue 4 #=> 1
h.fetch(:b) rescue 4 #=> 4
or
h[:a] || 4 #=> 1
h[:b] || 4 #=> 4
You could also build the default into the hash itself, by using Hash#default=:
h.default = 4
h[:a] #=> 1
h[:b] #=> 4
or by defining the hash like so:
g = Hash.new(4).merge(h)
g[:a] #=> 1
g[:b] #=> 4
See Hash::new.

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.

.nil? value query when attached to an array

I am working through the codecademy exercises and I cannot figure out what .nil? means in the way that I am required to implement it. Here is my code :
movies = { GIS: 10.0, Phantasm: 1.5, Bourne: 4.0}
puts "Whats your movie brah?"
title = gets.chomp
puts "What's your rating brah?"
rating = gets.chomp
movies[title] = rating
puts "Your info was totally saved brah!"
case movies
when 'add'
puts "What movie do you want to add?"
title = gets.chomp
if movies[title.to_sym].nil?
puts "What's the rating? (Type a number 0 to 4.)"
rating = gets.chomp
movies[title.to_sym] = rating.to_i
puts "#{title} has been added with a rating of #{rating}."
else
puts "That movie already exists! Its rating is #{movies[title.to_sym]}."
end
when "update"
puts "Updated!"
when "display"
puts "Movies!"
when "delete"
puts "Deleted!"
else puts "Error!"
end
I am working though creating methods for each command starting with the "add" command. The thing that is totally confusing me though, is the
.nil?
From what I understand,
nil = false
So, what I am thinking is that
.nil?
is asking if the attached statement is false. The crux of my confusion based on the line :
if movies[title.to_sym].nil?
Is that line asking :
"If the title I just entered is already represented as a symbol in the movies array, is this statement then, false?"
In which case, I imagine the if statement would evaluate to true if the title does not exist and false if it already exists. If the movie is indeed new, it would lastly, simply ask for the pertinent info as stated in the
else
statement. If someone could help clarify my misunderstanding I would be very grateful!
.nil? is asking if the object you are sending the nil? message to is actually an instance of nil.
'a string'.nil? #=> false
nil.nil? #=> true
x = 'a string'
x.nil? #=> false
x = nil
x.nil? #=> true
Your understanding of how the if movies[title.to_sym].nil? conditional works is basically correct. By default if a value is not in a hash, the hash will return nil.
movies = { GIS: 10.0, Phantasm: 1.5, Bourne: 4.0 }
# Ignoring the user input
title = 'Bourne'
movies[title.to_sym].nil?
#=> movies["Bourne".to_sym].nil?
#=> movies[:Bourne].nil?
#=> 4.0.nil?
#=> false
movies[:NoSuchMovie].nil?
#=> nil.nil?
#=> true

How to store and retrieve values using Ruby?

I am trying to build a "train game" based loosely on the old video game "Drug Wars." I am currently working my way through LRTHW, and I believe that I should be using OOP, but I'm not to that lesson yet.
The premise is that you have a set number of cars on your train and you can see what products are for sale in other cities (no limit on the amount you can buy or sale presuming you can fit them in your train). This code isn't complete, but I'm wondering if I'm even approaching this half way sanely in regard to creating and accessing the product prices in a reasonable manner.
#Initializing variables. Current_location should be changed to random
#in the future.
current_location = 'omaha'
train = []
new_york = []
chicago = []
omaha = []
dallas = []
seattle = []
def prompt()
print "> "
end
#Here is the selection menu. It is possible to exploit this and
#buy, sell and move all within the same turn.
#There needs to be a "safe selection" so that once you have moved you
#can't move again, but you can get info, buy and sell
#as many times as you would like.
def selection()
puts "Do you want to travel, buy, sell or get info?"
prompt; selection = gets.chomp
if selection.include? "travel"
puts "Where would you like to travel?"
prompt; city = gets.chomp
return 'city', city
elsif selection.include? "buy"
puts "Current Prices Are:"
puts "What would you like to Buy?"
elsif selection.include? "sell"
puts "Current Prices Are:"
puts "What would you like to sell?"
elsif selection.include? "info"
puts "What city or train would you like info on?"
else
puts "Would you like to exit selection or start selection again?"
end
end
#This generates a new cost for each good at the start of each turn.
def generate_costs(new_york, chicago, omaha, dallas, seattle)
new_york[0] = rand(10)
new_york[1] = rand(10) + 25
new_york[2] = rand(5) + 10
omaha[0] = rand(10)
omaha[1] = rand(10) + 25
omaha[2] = rand(5) + 10
chicago[0] = rand(25) + 5
chicago[1] = rand(5) + 10
chicago[2] = rand(4)
dallas[0] = rand(6) + 11
dallas[1] = rand(3) + 10
dallas[2] = rand(8)
seattle[0] = rand(6)
seattle[1] = rand(10) + 24
seattle[2] = rand(14) + 13
return new_york, chicago, omaha, dallas, seattle
end
# This is my main() loop. It drives the game forward.
for i in (0..5)
new_york, chicago, omaha, dallas, seattle = generate_costs(new_york, chicago, omaha, dallas, seattle)
turns = 5 - i
puts "You are currently in #{current_location}. You have #{turns} remaining."
puts "{ ___________________________ }"
#Code Here evaluates and accesses pricing based on current_location.
#Is this the correct way to do this?
fish = eval("#{current_location}[0]")
coal = eval("#{current_location}[1]")
cattle = eval("#{current_location}[2]")
puts "Fish is worth #{fish}"
puts "Coal is worth #{coal}"
puts "Cattle is worth #{cattle}"
puts "{ ___________________________ }"
change, value = selection()
if change == 'city'
current_location = value
elsif change == 'buy'
puts 'So you want to buy?'
else
puts "I don't understand what you want to do"
end
end
eval is a nasty way of accessing data ( When is `eval` in Ruby justified? ). You should consider moving things into an object.
I have improved the code slightly, storing the cities in a hash, which gets rid of the evals. I have stubbed out the generate_costs logic but you can assign it by doing:
cities[:new_york][0] = rand(10)
Ideally, the code should be re-written in an object-oriented syntax. If I get some time then I'll knock up an example for you.
Here is the code:
#Initializing variables. Current_location should be changed to random
#in the future.
current_location = :omaha
train = []
cities = {
:new_york => [],
:chicago => [],
:omaha => [],
:dallas => [],
:seattle => []
}
def prompt()
print "> "
end
#Here is the selection menu. It is possible to exploit this and
#buy, sell and move all within the same turn.
#There needs to be a "safe selection" so that once you have moved you
#can't move again, but you can get info, buy and sell
#as many times as you would like.
def selection()
puts "Do you want to travel, buy, sell or get info?"
prompt; selection = gets.chomp
if selection.include? "travel"
puts "Where would you like to travel?"
prompt; city = gets.chomp
return 'city', city
elsif selection.include? "buy"
puts "Current Prices Are:"
puts "What would you like to Buy?"
elsif selection.include? "sell"
puts "Current Prices Are:"
puts "What would you like to sell?"
elsif selection.include? "info"
puts "What city or train would you like info on?"
else
puts "Would you like to exit selection or start selection again?"
end
end
#This generates a new cost for each good at the start of each turn.
def generate_costs(cities)
cities.each do |key,city|
0.upto(2) do |i|
city[i] = rand(10)
end
end
end
# This is my main() loop. It drives the game forward.
for i in (0..5)
generate_costs(cities)
turns = 5 - i
puts "You are currently in #{current_location}. You have #{turns} remaining."
p cities
puts "{ ___________________________ }"
fish = cities[current_location][0]
coal = cities[current_location][1]
cattle = cities[current_location][2]
puts "Fish is worth #{fish}"
puts "Coal is worth #{coal}"
puts "Cattle is worth #{cattle}"
puts "{ ___________________________ }"
change, value = selection()
if change == 'city'
current_location = value
elsif change == 'buy'
puts 'So you want to buy?'
else
puts "I don't understand what you want to do"
end
end

Resources