.nil? value query when attached to an array - ruby

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

Related

Stand alone method is calling another method by itself

Ok i seriously suck at passing method to methods whenever i want to return something from the method. Can you guys explain on how do i go about passing it.
Here's my hash
$choosen_gun = {}
$Weapon = {
:Bazoka => ["Bazoka",5],
:Machine_gun => ["Machine_gun",1000],
:Hand_gun => ["Hand_gun",24,2],
:Double_Hand_gun => ["Double_Hand_gun",24,4],
:Sniper => ["Sniper",12,1],
:Shot_gun => ["Shot_gun",8,2]
}
Here's my code for method Weapon
def Weapon
puts "Now it's time to select your weapon."
puts "Please choose a weapon that is good throughout the game."
puts "Whenever you are shortage of bullets, please reload it."
puts "Please avoid last minute of reloading of weapon."
puts "Now choose your weapon based on your own preferences."
print "\n"
puts "Type 1"
puts "Gun Name: Bazoka"
puts "Description: A powerful gun that is strong with only 5 bullets."
puts "Rating: ★ ★ ★ ★"
num = gets.chomp.to_i
case num
when 1
puts "Selection of Bazoka is chosen"
puts "Loaded 5 bullets only"
$choosen_gun[num] = $Weapon[:Bazoka]
end
return num
end
Upon calling the method. The user will choose his weapon and it will add it to the $choosen_gun hash with it's num, and it's return it's num what the user types
Here's my code for method ZombieRoom
def ZombieRoom(w)
zombie = {
:Construcied => [5],
:Invader => [5],
:Damned => [5],
:Steampunk => [5],
:Stoner => [5],
:Wasted => [5],
:Romero => [5]
}
puts "Welcome to the worst night mare of Zombie Room"
puts "You will be fighting with a random zombie"
while true
puts ".........."
puts "Selecting a random zombie"
puts "Selecting your prefered gun...."
case w
when 1
$choosen_gun[1]
puts "Your selected gun is #{$choosen_gun[1][0]}"
#values = zombie.values
#puts values[rand(values.size)]
#random_zombie = zombie.keys.sample(1)
#puts random_zombie[
random_zombie = zombie.to_a.sample(1).to_h
random_zombie.each do |key,value|
puts "Your random zombie is #{key}"
puts "With a health value of #{value[0]}"
puts "Time to take down that zombie now."
while true
puts "Type Shoot to knock it down or quit."
choice = gets.chomp
if $choosen_gun[1][1] >= 1
health = value[0] -= 1
$choosen_gun[1][1] -= 1
puts "#{key} health now is #{health}"
else
puts "Please reload your gun"
puts "Reloading......"
$choosen_gun[1][1] += 5
end
if health == 0
puts "You have defeated #{key}"
puts "Congrats!!!"
puts "We are happy for you"
puts "Lets begins to collect your prize"
CollectPrize()
else
puts "You did not defeat the #{key} yet"
end
end
end
end
end
end
Here's my code for method CollectPrize
def CollectPrize
puts "Congratulations on defeating"
puts "We would now like to give you some case prizes"
print "\n"
puts "Please choose only 1 prize for yourself"
print "\n"
puts "Type 1"
puts "$50,000"
print "\n"
puts "Type 2"
puts "$25,000"
print "\n"
puts "Type 3"
puts "$55,000"
hoho = gets.chomp.to_f
if hoho == 1
puts "hehe"
end
end
Here how i call my method
ZombieRoom(Weapon())
CollectPrize()
Now the problem is that whenever the CollectPrize method is called and i type my input to collect the prize example 1 then it print "$50,000". instead of the ending the problem, it went back to the ZombieRoom and continues to loop at the "Type Shoot to knock it down or quit." Can someone atleast tell me a proper way to solve this issue or also what other way to pass a method?
Your code is in a large while true loop. Since true is always true, it will never end, so after it calls CollectPrize() it just goes back to the while statement.
You could get out of it by inserting a break line after the CollectPrize() but there's another while true loop around this one.
I think you need to pay closer attention to how you want to exit the while loops.
puts "Time to take down that zombie now."
while true # <---------------- this is ALWAYS going to loop, without end
puts "Type Shoot to knock it down or quit."
choice = gets.chomp
if $choosen_gun[1][1] >= 1
health = value[0] -= 1
$choosen_gun[1][1] -= 1
puts "#{key} health now is #{health}"
else
puts "Please reload your gun"
puts "Reloading......"
$choosen_gun[1][1] += 5
end
if health == 0
puts "You have defeated #{key}"
puts "Congrats!!!"
puts "We are happy for you"
puts "Lets begins to collect your prize"
CollectPrize()
else
puts "You did not defeat the #{key} yet"
end
end
In ruby constants start with Capital letter.
Methods are always defined in lower case.
Try this in irb
irb(main):001:0> def Weapon
irb(main):002:1> end
=> :Weapon
irb(main):003:0> Weapon
NameError: uninitialized constant Weapon
To solve your problem name methods using ruby's naming conventions:
zombie_room, collect_prize etc.
Then this code will work:
zombie_room(weapon())
What you are doing there is not really passing method weapon to method zombie room.
What is really going on is that method weapon is executed, then it returns a value and result of that value is passed to method zombie_room.
I think that is what you wanted.
If you need to pass a method, check out documentation for proc and lambda or just use blocks.

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 would I set a variable to a boolean?

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

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.

Can't get if statement to evaluate properly -- .include? always evaluates to false [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I'm having trouble getting my if statement for def is_valid_card_query(card_queried) to evaluate properly. I think it has something to do with my array and how I'm passing the variable in, perhaps?
I'm trying to evaluate first if the card is valid, meaning it's rank is (2 - A), second if the player has the card, and if so then I just return the card. But no matter what I do, it always defaults to the if.
cards_available.include? "card_queried" keeps evaluating to false *when I pass card_queried in through the method call*.
How can I fix this?
Here's the code. I have the portion I'm trying to run at the bottom:
require 'socket'
require 'rspec'
require 'json'
require_relative 'FishDeck.rb'
require_relative 'FishHand.rb'
require_relative 'FishGame.rb'
require_relative 'FishServer.rb'
require_relative 'FishPlayers.rb'
require_relative 'ServerTests.rb'
class ClientClass
attr_accessor :players_available, :card_choices_available
def initialize(host, port)
#socket = TCPSocket.new(host, port)
players_available = nil
card_choices_available = nil
end
def get_input
incoming = #socket.gets.chomp
#puts "Here is the output for incoming: #{incoming}"
end
def send_input(message)
outgoing = #socket.puts(message)
end
def close
#socket.close
end
def is_valid_player_query(player_queried)
if (player_queried > players_available) || (player_queried < 1)
puts "I'm sorry, that's not a player."
puts "Please enter a player number ranging from 1 through #{players_available}"
user_input = gets.chomp
is_valid_player_query(user_input) #Recursion until proper response
else
return player_queried
end
end
def is_valid_card_query(card_queried)
puts "CARD QUERIED: #{card_queried}"
cards_available = %w(2 3 4 5 6 7 8 9 10 J Q K A)
puts "CARDS AVAILABLE: #{cards_available}"
if (cards_available.include? "card_queried") == false
puts "CARD NOT AVAILABLE EVER"
puts "True if statement? #{cards_available.include? "card_queried"}"
puts "I'm sorry, that's not a valid card choice."
puts "Please enter a card number ranging from 2 through A. You're using a traditional deck"
user_input = gets.chomp
user_input = is_valid_card_query(user_input) #Recursion until proper response
elsif (((cards_available.include? "card_queried") == true) && ((card_choices_available.include? "card_queried") == false))
puts "CARD IN DECK BUT NOT HAND"
puts "True if statement? #{cards_available.include? "card_queried"}"
puts "I'm sorry, you don't have that card, so you can't ask for it."
puts "Here are the cards for which you may ask: #{card_choices_available}"
user_input = gets.chomp
user_input = is_valid_card_query(user_input)
else
puts "True if statement? #{cards_available.include? "card_queried"}"
puts "PASS!"
return card_queried
end
end
def input_decision(input)
if input == "PLAYERS"
input = #socket.gets.chomp #gets the actual array
input = input.to_i
players_available = input
elsif input == "CARDS"
input = #socket.gets.chomp
input = JSON.parse(input)
card_choices_available = input
elsif input == "EXIT"
puts "The server has closed. Goodbye!"
#I need some way to break the loop or close the client if the server has closed
elsif input == "ANNOUNCEMENT" #just reads it
input = #socket.gets.chomp
puts input
else #get input from user case
user_choice = []
puts "It is your turn. Please choose a player to ask for a card"
user_input = gets.chomp
user_input = is_valid_player_query(user_input)
user_choice << user_input
puts "Great! You're asking Player #{user_input} for a card. What card would you like?"
user_input = gets.chomp
user_input = is_valid_card_query(user_input)
user_choice << user_input
user_choice = user_choice.to_json
#socket.send_input(user_choice)
end
end
end
#server = SocketServerClass.new(2012, 3)
#client1 = ClientClass.new('localhost', 2012)
#client2 = ClientClass.new('localhost', 2012)
#client3 = ClientClass.new('localhost', 2012)
#server.accept_client(#server.fish_game)
#server.accept_client(#server.fish_game)
#server.accept_client(#server.fish_game)
#client1.card_choices_available = %w(3, 6, 9 K, 10)
#client1.is_valid_card_query("3") #Doesn't work just 3 , either.
Your code states that cards_available consists of the following array:
["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" ,"A"]
However, you are evaluating whether or not cards_available includes the string "card_queried" – this will never evaluate to true. What should be evaluating whether it includes the variable card_queried, which, according to your instructions, should be a string "ranging from 2 through A":
cards_available.include? card_queried

Resources