我正在制作一个简单的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]
中的技能。
答案 0 :(得分:1)
当我运行您的代码时,会得到此结果。
{: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
答案 1 :(得分:1)
我为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
答案 2 :(得分:1)
我将遍历已定义的技能而不是技能值。
player.
map { |_, h| h[:skill] }.
compact.
map(&:to_sym).
each { |skill| player[:skills][skill] += 2 }
现在player
得到了相应的更新,您可以使用player
或类似的符号来检查p player
。
答案 3 :(得分:0)
将代码更改为以下形式:
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
代码由于当前迭代的结果而返回最后一行,所以代码无法工作的原因,因此在athletics
情况下,最后一行是
[skill, (mod += 2 if skill.to_s == player[:sub][:skill])]
为假,将为nil
,这就是仅endurance
大小写有效的原因。
希望有帮助。