Picking a hash in ruby, based on a comparison
Take a look at this code please :
fighter = [:str => 2, :dex => 3, :mag => 3, :acc => 2, :hp => 2]
ranger = [:str => 3, :dex =>开发者_运维问答 2, :mag => 3, :acc => 2, :hp => 2]
magician = [:str => 3, :dex => 3, :mag => 2, :acc => 2, :hp => 2]
rate = Hash.new
if user.first_class == 'Fighter' then rate = fighter end
if user.first_class == 'Ranger' then rate = magician end
if user.first_class == 'Magician' then rate = ranger end
cost = Hash.new
cost[:str] = (user.strength_points + 1) * rate[:str]
cost[:dex] = (user.dexterity_points + 1) * rate[:dex]
cost[:mag] = (user.magic_points + 1) * rate[:mag]
cost[:acc] = (user.accuracy_points + 1) * rate[:acc]
cost[:hp] = (user.health_points + 1) * rate[:hp]
cost
This reside in a function i've made, and i get a "Symbol as array index" when i execute it in Rails. I'm guessing that this is because of rate = fighter, rate = magician or rate = ranger possibility. Maybe i have to use clone on that.
My question is, what is the better way of selecting a hash based on an if comparison, doing the above thing ?
You are creating an Array
with one entry which is a Hash
:
fighter = [:str => 2, :dex => 3, :mag => 3, :acc => 2, :hp => 2]
=> [{:str=>2, :dex=>3, :mag=>3, :acc=>2, :hp=>2}]
What you meant to do is just create a Hash
:
fighter = {:str => 2, :dex => 3, :mag => 3, :acc => 2, :hp => 2}
=> {:str=>2, :dex=>3, :mag=>3, :acc=>2, :hp=>2}
Also, instead of three if
statements, use a case
statement:
rate = case user.first_class
when "ranger"
ranger
when "magician"
magician
when "fighter"
fighter
end
This is probably not the best way to organize your code. I would recommend storing a user's first class as an object that performs the calculations itself. This is a more object oriented approach:
class User
def first_class= klass
@first_class = klass.new(self)
end
def first_class
@first_class
end
end
class FirstClass
attr_accessor :user
def initialize user
@user = user
end
def cost
{ :str => (user.strength_points + 1)*rate[:str],
:dex => (user.dexterity_points + 1) * rate[:dex],
:mag => (user.magic_points + 1) * rate[:mag],
:acc => (user.accuracy_points + 1) * rate[:acc],
:hp => (user.health_points + 1) * rate[:hp] }
end
end
You can then define first class types:
class Fighter < FirstClass
def rate
{:str => 2, :dex => 3, :mag => 3, :acc => 2, :hp => 2}
end
end
class Magician < FirstClass
def rate
{:str => 3, :dex => 3, :mag => 2, :acc => 2, :hp => 2}
end
end
class Ranger < FirstClass
def rate
{:str => 3, :dex => 2, :mag => 3, :acc => 2, :hp => 2}
end
end
Then you can adjust your function to this:
user.first_class.cost
Keep in mind that you'll have to set the first class as an object as well:
user.first_class = Fighter
But I think this looks cleaner, is more object oriented and drastically reduces the complexity of your code.
You are having issues because you are setting fighter/ranger/magician as a list of single element hashes.
You want:
fighter = {:str => 2, :dex => 3, :mag => 3, :acc => 2, :hp => 2}
ranger = {:str => 3, :dex => 2, :mag => 3, :acc => 2, :hp => 2}
magician = {:str => 3, :dex => 3, :mag => 2, :acc => 2, :hp => 2}
Put the rates in a hash
rates = {
"fighter" => { :str => 2, :dex => 3, :mag => 3, :acc => 2, :hp => 2 },
"ranger" => { :str => 3, :dex => 2, :mag => 3, :acc => 2, :hp => 2 },
"magician" => { :str => 3, :dex => 3, :mag => 2, :acc => 2, :hp => 2 }
}
rate = rates[user.first_class.downcase]
You were also using square instead of curly brackets, which made an array instead of a hash.
(Another tip, you can do one-line if statements more readably like so: my_number = 10 if my_number > 10
)
精彩评论