Get a value to access a value in a hash - ruby

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]

Related

How to terminate Ruby array sort program using Nil entry

Noob rubyist here, working through "Learn to Program." I've set up the below code to take user entries and sort, but I can't figure out how to end the program on a nil entry instead of the 'done' that is currently set. Setting the user == '', obviously terminates before it takes any input. Any help is greatly appreciated!
array = []
user = ''
puts "Type as many words as you like. Press enter to end."
until user == 'done'
user = gets.chomp
array.push user
end
puts
puts array.sort
Start your variable from nil, so that it executes the body at least the first time
user = nil
until user == ''
user = gets.chomp
array.push user
end
Here is another implementation that will not add the blank user to the array. Although it would be nice to use a construct more specific than loop, loop gives us exactly what we need.
users = []
loop do
user = gets.chomp
if user != ''
users << user
else
break
end
end
puts users
Your message says "Press enter to end". So I suggest you get the user input in one go, split the string into words, sort and display.
user = ''
puts "Type as many words as you like. Press enter to end."
user = gets.chomp
array = user.split
puts array.sort

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

Trying to reference earlier 'case' in a case statement

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

Variables not matching in if/else statement

I am creating a method that makes you solve random math problems. Code is below:
def subtraction()
puts "Your goal is to solve the math problem."
# Asks if user is ready
ready()
a = rand(0..5)
b = rand(0..5)
c = a - b
puts "what is #{a} - #{b}?"
prompt; next_move = gets.chomp
if next_move == c
puts "Lucky guess!"
water()
elsif next_move != c
puts "The answer was: #{c}"
dead("You suck at life")
else
dead("You didn't type anything")
end
end
I keep trying to run this and I keep getting the elsif option. Even though my variables match when I check with puts statements. I am not moving in the direction I want to. What am I doing wrong?
Change
next_move = gets.chomp
to
next_move = gets.chomp.to_i # gets.to_i will work also.
Kernel#gets will give you string, and you need to convert it to appropriate object as per your need, if your work is not with string object like this example. As per the line c = a - b, I am very much sure, you need to change your string object, that you are getting from stdin to an integer object. So you have to use String#to_i.

Converting string into class [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
What I do need:
I pass a string that has to set an unmutable object inside an array, but I do not know hot how to make the transition from the string that the user inputs to the object name I need.
What I am intending to do:
I am working on a conversational adventure. The key point is to have a function that creates a command prompt so the user can interact with the game. Whenever the user says "go to somewhere", there is another function called "goto" that compares whether the input is included in the exits of the place where the player is; if so, the attribute "place" for the player takes a new place.
What I did:
I made a command prompt that actually works*
loop do
print "\n >>> "
input = gets.chomp
sentence = input.split
case
when sentence[0] == "inspect"
$action.inspect(sentence[1])
when sentence[0] == "go" && sentence[1] == "to"
$action.goto(sentence[2])
when sentence[0] == "quit"
break
else
puts "\nNo le entiendo Senor..."
end
And I initialized the objects as I need them (the third attribute goes for the exits):
room = Place.new("room", "Room", [newroom], "This is a blank room. You can _inspect_ the -clock- or go to [newroom].", ["this this"])
newroom = Place.new("newroom", "New Room", [room], "This is another blank room. You can _inspect_ the -clock-", ["this this"])
Then I made a method inside the action controller that has to compare and set the places properly. (Beware: monster newbie code following. Protect you eyes).
def goto(destiny) #trying to translate the commands into variable names
if (send "#{destiny}").is_in? $player.place.exits
$player.place = send "#{sentence[2]}"
puts destiny.description
else
puts "I cannot go there."
end
end
I think you want to convert a string to constant. Well it is easy. Read an example:
string = 'Hash'
const = Object.const_get(string) #=> Hash
const.new #=> {}; <- it is an empty Hash!
But be careful. If there's no such a constant you will get uninitialized constant error. In this case your adventures will stop.
I hope I understood your question and you will understand my answer.
How to change string to object, there are few options:
Bad(eval family):
eval("name_of_your_variable = #{21+21}")
eval("puts name_of_your_variable") #42
You can see that eval can make everything. So use with caution.
However, as pointed by #user2422869 you need(be in) scope - place where your variables are saved. So above code won't run everywhere
Everytime you run following method you create another scope
def meth1
puts "defined: #{(defined? local_a) ? 'yes' : 'no'}!"
eval 'local_a = 42'
local_a += 100
eval 'puts local_a'
end
meth1
and here is output:
defined: no!
142
If you want to grab local_a from one of scopes of meth1 you need binding.
def meth2
var_a = 222
binding
end
bin = meth2
bin.eval 'var_a'
#output:
#222
About binding you can read in doc. As for scopes, I don't have good site.
Better:
hash_variable = Hash.new # or just {}
hash[your_string_goes_here] = "some value #{42}"
puts hash[your_string_goes_here]
I don't know if good or bad:
As for this: send "#{destiny}". I assume that your destiny doesn't exist, so you can use method_missing:
def method_missing arg, *args, &block
#do some with "destiny"; save into variable/hash, check if "destiny" is in right place etc.
# return something
end

Resources