我正在制作一个简单的RPG作为学习项目,并且与部分角色创建器有问题。
此代码应确定分配给player[:caste][:skill]
和player[:sub][:skill]
的技能字符串,然后将每个技能的值(player[:skills]
)增加 2。无论分配给player[:caste][:skill]
和player[:sub][:skill]
什么字符串,只要它等于player[:skills].to_s
,这段代码都应该有效。
目前,它仅将更改应用于player[:skills][:endurance]
而不是player[:skills][:athletics]
。
player = {
caste: {skill: "athletics"},
sub: {skill: "endurance"},
skills: {acrobatics: 0, athletics: 0, engineering: 0, endurance: 0, heal: 0, history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0, stealth: 0, streetwise: 0, thievery: 0},
}
player[:skills] = player[:skills].map do |skill, mod|
[skill, (mod += 2 if skill.to_s == player[:caste][:skill])]
[skill, (mod += 2 if skill.to_s == player[:sub][:skill])]
end.to_h
换句话说,我的代码返回以下player[:skills]
哈希:
skills: {acrobatics: 0, athletics: 0, engineering: 0, endurance: 2, heal: 0, history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0, stealth: 0, streetwise: 0, thievery: 0}
但我希望它返回:
skills: {acrobatics: 0, athletics: 2, engineering: 0, endurance: 2, heal: 0, history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0, stealth: 0, streetwise: 0, thievery: 0}
请让我知道是否有更简单的方法可以做到这一点。我还尝试了以下方法:
player[:skills] = player[:skills].map do |skill, mod|
[skill, (mod += 2 if skill.to_s == (player[:caste][:skill] || player[:sub][:skill]))]
end.to_h
这只会影响在player[:caste][:skill]
中找到的技能。
当我运行你的代码时,我得到这个结果。
{:acrobatics=>nil, :athletics=>nil, :engineering=>nil, :endurance=>2, :heal=>nil, :history=>nil, :influence=>nil, :insight=>nil, :magicka=>nil, :perception=>nil, :riding=>nil, :stealth=>nil, :streetwise=>nil, :thievery=>nil}
这是因为 map 返回执行的最后一个语句。此外,您实际上只在技能与子技能匹配时才为技能设置值,否则,它将设置为 nil。
因此,代码中发生的事情是每次迭代都返回以下内容,这是块中最后一个语句传递到 map 的结果。
[:acrobatics, nil]
[:athletics, nil]
[:engineering, nil]
[:endurance, 2]
[:heal, nil]
[:history, nil]
[:influence, nil]
[:insight, nil]
[:magicka, nil]
[:perception, nil]
[:riding, nil]
[:stealth, nil]
[:streetwise, nil]
[:thievery, nil]
最终结果是一个看起来像这样的数组。
[[:acrobatics, nil], [:athletics, nil], [:engineering, nil], [:endurance, 2], [:heal, nil], [:history, nil], [:influence, nil], [:insight, nil], [:magicka, nil], [:perception, nil], [:riding, nil], [:stealth, nil], [:streetwise, nil], [:thievery, nil]]
最终映射到新的哈希
{:acrobatics=>nil, :athletics=>nil, :engineering=>nil, :endurance=>2, :heal=>nil, :history=>nil, :influence=>nil, :insight=>nil, :magicka=>nil, :perception=>nil, :riding=>nil, :stealth=>nil, :streetwise=>nil, :thievery=>nil}
你得到所有这些 nil 的原因是在你的陈述中,案例的结果是 if 陈述不真实是 nil。 例如:
[skill (mod += 2 if skill.to_s == player[:caste][:skill])]
将返回[the_skill, nil]
为案件skill.to_s == player[:caste][:skill]
不是真的
要查看发生了什么,请尝试在 irb 中执行此操作。
x = 0
=> 0
x += 1 if false
=> nil
x += 1 if true
=> 1
你可以用这样的东西来克服它。
[skill, skill.to_s == player[:caste][:skill] ? mod + 2 : mod ]
或使用上面的例子:
x = 0
=> 0
x = false ? x + 1 : x
=> 0
x = true ? x + 1 : x
=> 1
以下修改后的代码版本应该可以工作。
player[:skills] = player[:skills].map do |skill, mod|
[skill, skill.to_s == player[:caste][:skill] || skill.to_s == player[:sub][:skill] ? mod + 2 : mod ]
end.to_h
但是,这是一个稍微冗长,但希望更容易遵循的方式来完成您想要做的事情,并允许将来添加修改而不会使代码变得过于混乱。
player = {
caste: {skill: "athletics"},
sub: {skill: "endurance"},
skills: {acrobatics: 0, athletics: 0, engineering: 0, endurance: 0, heal: 0, history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0, stealth: 0, streetwise: 0, thievery: 0},
}
player_caste_skill = player[:caste][:skill]
player_sub_skill = player[:sub][:skill]
current_skills = player[:skills]
updated_skills = {}
current_skills.each_pair do |skill, prev_value|
new_value = prev_value
case skill.to_s
when player_caste_skill, player_sub_skill
new_value = prev_value + 2
when "some_other_skill"
new_value = prev_value + 3
end
updated_skills[skill] = new_value
end
puts current_skills
puts updated_skills
我会为player[:skill]
哈希设置一个默认值(Hash#default),只是为了避免在缺少键的情况下出错(它添加了键!!),允许添加一个新键,而无需初始化为0每个技能。
player[:skills].default = 0
然后扫描您需要在一个行中递增的键:
[:caste, :sub].each { |key| player.dig(key, :skill).to_sym.then { |skill| player[:skills][skill] += 2 } }
由于初始化,您的播放器也可以
player = {
caste: {skill: "athletics"},
sub: {skill: "endurance"},
skills: {}
}
返回如下结果:
player #=> {:caste=>{:skill=>"athletics"}, :sub=>{:skill=>"endurance"}, :skills=>{:athletics=>2, :endurance=>2}}
哪里:
player[:skills][:whatever] #=> 0
我会遍历定义的技能,而不是通过技能值。
player.
map { |_, h| h[:skill] }.
compact.
map(&:to_sym).
each { |skill| player[:skills][skill] += 2 }
现在player
会相应地更新,因为您可以通过使用p player
或类似来瞄准player
。
将代码更改为如下所示:
player = {
caste: {skill: "athletics"},
sub: {skill: "endurance"},
skills: {acrobatics: 0, athletics: 0, engineering: 0, endurance: 0, heal: 0,
history: 0, influence: 0, insight: 0, magicka: 0, perception: 0, riding: 0,
stealth: 0, streetwise: 0, thievery: 0},
}
player[:skills] = player[:skills].map do |skill, mod|
[skill, (mod += 2 if [player[:caste][:skill], player[:sub][:skill]].include?
(skill.to_s))]
end.to_h
您的代码不起作用的原因是因为 map 返回最后一行作为当前迭代的结果,因此在athletics
情况下,最后一行是
[skill, (mod += 2 if skill.to_s == player[:sub][:skill])]
将是错误的,这将是nil
这就是为什么只有endurance
情况有效。
希望对您有所帮助。