开发者

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)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜