Trying to reference earlier 'case' in a case statement - ruby

When someone tries to update a value that is not currently stored in my hash, I would like to immediately refer back to when 'add' without restarting the entire case statement since I already know they want to add and don't want to prompt them again.
Is there a way to refer back to the case choice -> when "add" section of my code without restarting the entire case statement?
I know I could use nested case statements but I would rather not copy/paste identical code if I don't have to.
hash = {}
puts "Would you like to add or update this hash?"
choice = gets.chomp
case choice
when "add"
puts "What key you like to add?"
key = gets.chomp
puts "With what value?"
value = gets.chomp
hash[key] = value
when "update"
puts "Which key would you like to update?"
key = gets.chomp
if hash[key].nil?
puts "Key not present, would you like to add it?"
#here I would like the code that references back to "when 'add'" if the user types 'yes'
Sorry for the abrupt ending of the code. I didn't want to put in anything unnecessary to the solution.

Create a method/function that wraps the functionality inside that case. Then you can call that function from both places
hash = {}
def add_key
puts "What key you like to add?"
key = gets.chomp
puts "With what value?"
value = gets.chomp
hash[key] = value
end
puts "Would you like to add or update this hash?"
choice = gets.chomp
case choice
when "add"
add_key
when "update"
puts "Which key would you like to update?"
key = gets.chomp
if hash[key].nil?
puts "Key not present, would you like to add it?"
add_key

Related

Get a value to access a value in a hash

I want to use an input from gets to access a value in a hash.
This code does not work:
puts "Which word?"
question = gets
question = question.to_s
puts dic_hash["#{question}"]
nor does this:
puts "Which word?"
question = gets
question = question.to_s
puts dic_hash[question]
but this works:
puts "Which word?"
puts dic_hash["zwembad"]
How do I get the gets input from the user to access a value in a hash?
You may not be aware of this, but the gets result includes the return character you typed to submit the value.
result = gets
type "hello"
p result
"hello\n"
Change your gets to gets.chomp to remove the trailing '\n`
puts "Which word?"
question = gets.chomp
puts dic_hash[question]

How to permanently update a hash in Ruby?

So I've seen questions on here about how to write to an external text file etc.
For example to write my hash to another file I put:
hash = {
Key1: Value1,
Key2: Value2
}
open(FileToWriteTo, 'w') do |f|
hash.each { |key, value| f.puts "#{key}: #{value}" }
But what I'd like to achieve is if I run the program and add something to my hash list, then the next time I run and display the hash, the new addition will be there. Here's the code I'm using to add to my hash:
puts "Type 'add' to add an item to the hash"
choice = gets.chomp.downcase
case choice
when 'add'
puts "What do you want to add?"
addition = gets.chomp
if hash[addition.to_sym].nil?
puts "What value will #{addition} have? (integer)"
add_value = gets.chomp
hash[addition.to_sym] = add_value.to_i
puts "#{addition} has been added with a value of #{value}."
else
puts "That item already exists! Its value is #{hash[addition.to_sym]}."
end
So if I add the item, rerun the program and choose to display instead of add, how should I get the last addition to show. Thanks.
Here is code you could use. It takes advantage of yaml to store the hash.
require 'yaml'
file = '/tmp/test.yml'
if File.exists?(file)
hash = YAML::load_file(file) # load yaml
else
hash = Hash.new
end
puts "Type 'add' to add an item to the hash"
choice = gets.chomp.downcase
if choice == 'add'
puts "What do you want to add?"
addition = gets.chomp
if hash[addition.to_sym].nil?
puts "What value will #{addition} have? (integer)"
add_value = gets.chomp
hash[addition.to_sym] = add_value.to_i
puts "#{addition} has been added with a value of #{add_value}."
else
puts "That item already exists! Its value is # {hash[addition.to_sym]}."
end
end
File.open(file, 'w') {|f| f.write hash.to_yaml } #store yaml
If I understood the question correctly, you want to show the added option.
Since you are using the file and rerunning the code, better read the file (and store it in hash) at start and append new items (key-val) to file.
So whenever anyone adds something, append it to file. Now when you read the file again at start, its updated.
Let me know if this is not your use case.

Ruby Character Creation for text RPG

First I just wanted to state I am very new to Ruby. I am a hug fan of Dnd and I wanted to create a text adventure game based off of Dnd rules. The issue I am having (I don't even know if it is possible) is that I am creating a character class and I want the variables assigned outside the class. The reason for this is I don't want the player to have to type:
character.new("Havatr", "elf", "tall and lean", "etc")
This is just an experiment before actually creating the file. This is what i have so far:
class Character
attr_reader :name, :race, :description
def initalize (name, race, description)
#name = name
#race = race
#description = description
end
end
def prompt
print "Enter Command >"
end
puts "What is your name?"
prompt; next_move = gets.chomp.downcase
puts "what is your race?"
prompt; next_move = gets.chomp.downcase
puts "What do you look like?"
prompt; next_move = gets.chomp.downcase
player_one = Character.new("#{a}","#{b}","#{c}")
print player_one
If there is a way to do this can I get assistance with it and if there is a better method then what I am trying please let me know. The idea behind this is to try and dump the class into a yaml file to create a character save.
When I run the code this is what it looks like:
What is your name?
Enter Command > Havatr
What is your race?
Enter Command > Elf
What do you look like?
Enter Command > I look like me
C://core_rules0.0.1/Characters.rb:27:in '': undefined local variable or method 'a' for main:Object (NameError)
There are two problems here. The first is that you misspelled initialize. The second is that instead of saving the values entered by the user in a, b, and c you save each in next_move. That's an easy fix:
puts "What is your name?"
prompt; name = gets.chomp.downcase
puts "What is your race?"
prompt; race = gets.chomp.downcase
puts "What do you look like?"
prompt; desc = gets.chomp.downcase
player_one = Character.new(name, race, desc)
print player_one
You'll notice that I did Character.new(name, race, desc) instead of Character.new("#{a}", "#{b}", "#{c}"). First, I used more descriptive names (one-character variable names are almost always a poor choice, except for well-known conventions like i to represent the iteration number in a loop). Second, I did name instead of "#{name}" because the latter doesn't actually do anything. #{...} is string interpolation in Ruby. It's a way to put values into a string, e.g. "Hello #{name}". But when you don't have anything else in the string, as in "#{name}", it doesn't do anything except convert a to a string—a task for which name.to_s is a better solution, and which is unnecessary anyway because we know name is already a string. "#{whatever}" is always unnecessary; whatever.to_s is sometimes necessary.
The other thing you'll notice is that print player_one prints something like:
#<Character:0x007fc23b88bf08>
...which maybe isn't what you expected. That's because Ruby doesn't know how to print your Character object in a human-readable way. You can tell it how by defining a to_s method. For example:
class Character
# ...
def to_s
"#{name} (#{race} - #{desc})"
end
end
For the inputs in your question, this would yield the following:
puts player_one
# => havatr (elf - i look like me)
(It's all lower-case because you called downcase on each input, which may or may not be the behavior you actually want.)
It looks like there is a simple bug here:
class Character
attr_reader :name, :race, :description
def initalize (name, race, description)
#name = name
#race = race
#description = description
end
end
def prompt
print "Enter Command >"
end
puts "What is your name?"
prompt; a = gets.chomp.downcase
puts "what is your race?"
prompt; b = gets.chomp.downcase
puts "What do you look like?"
prompt; c = gets.chomp.downcase
player_one = Character.new("#{a}","#{b}","#{c}")
print player_one
You were setting the results of the prompt to the variable next_move

Hashes and case statements

I have to update and add a movie title and its associated rating to an existing hash. This is the code that i have so far:
movies = {
Titanic:4,
Bestman: 3,
Agora: 2
}
puts "What would you like to do?"
choice = gets.chomp
case movies
when "add"
puts "What movie do you want to add?"
title = gets.chomp
puts "What's the rating of the movie?"
rating = gets.chomp
movies[title] = rating
puts "#{title} has been added with a rating of #{rating}."
when "update"
puts "Updated!"
when "display"
puts "Movies!"
when "delete"
puts "Deleted!"
else
puts "Error!"
end
When I run the code, I get this error "it looks like you didn't add to the movies hash"
I know the error lies somewhere between these lines:
case movies
when "add"
puts "What movie do you want to add?"
title = gets.chomp
puts "What's the rating of the movie?"
rating = gets.chomp
movies[title] = rating
puts "#{title} has been added with a rating of #{rating}."
I have been trying to figure it out but thus far have failed to figure out what I am doing wrong.
Is there an alternative way to add to my movies hash? And what is wrong with my puts code for letting the user know that his/her movie title and rating has been added?
Thank you
EDIT
As pointed out by Some Guy, changing the case statement from
case movies
to
case choice
resolved the issue.
What I need to learn/figure out is why the 2nd works but the 1st does not.
Change
case movies
to
case choice # because this is where your choice of what to do is being stored
If it's still not clear, it may help to think of a case statement as a series of if/elsif (there are differences, but for this scenario it works), so:
case movies
when "add" # do stuff
is akin to:
if movies == "add"
# do stuff
end
Hoping that makes it clearer.

Unexpected boolean result using .nil? on a hash

I am working through exercises on codecademy and I came across a solution that I do not completely understand involving .nil? 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.to_sym] = rating.to_i
puts "Your info was saved brah!"
case movies
when 'add'
puts "What movie do you want to add son?"
title = gets.chomp
if movies[title.to_sym].nil?
puts "What's your new rating brah?"
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"
if movies[title.to_sym].nil?
when "display"
puts "Movies!"
when "delete"
puts "Deleted!"
else puts "Error!"
end
I am only referring to the add method. the rest of the script is a work in progress. I don't like not understanding things though and this has me in a bit of a quandry.
My question is does Ruby know not to add a title that already exists because two symbols cannot have the same name? I am curious how it determines when the hash has no value. Can anyone clarify this for me? I would really appreciate it!
The answer is a bit more complicated than that.
From the RubyDoc: "Two objects refer to the same hash key when their hash value is identical and the two objects are eql? to each other."
An object's hash value is a calculated numerical result based on the data the object contains. And the eql? method tests if two objects are equal, and this is usually aliased to == in ruby (i.e my_string1 == my_string2 is the same as my_string1.eql? my_string2).
When you say movies[title.to_sym], Ruby is saying "In the movies hash, are there any pairs currently stored where the key.eql? title.to_sym and key.hash == title.to_sym.hash? If so, return that value of the pairing, and if not return nil.
The reason Ruby doesn't add the title if it already exists is because of your if movies[title.to_sym].nil? line, which in English translates to "only do what follows if no pairing for the key title.to_sym exists."
If you had title = "GIS", and you were to just say movies[title.to_sym] = 1, Ruby would gladly over write the 10.0 you currently have stored there so that movies[:GIS] returned 1.

Resources