如何用Ruby实现含1%概率的物品分类随机抽取?
解决稀有度随机抽取的小数概率问题
嘿,这个场景我太熟悉了!之前用重复元素数组处理整数比例的概率确实省心,但碰到1%这种没法用整数个数凑的情况,就得换个更灵活的思路啦。给你两种Ruby里的实用方案:
方案一:直接用随机数区间判断
这是最直观的方法,不需要维护数组,直接通过随机数落在的区间来决定结果,完美适配任意百分比概率:
def pick_rarity # 生成0到99的随机整数,刚好对应0%-99%的范围 random_value = rand(100) case random_value when 0 then "S" # 仅0这1个数值,占1% when 1..29 then "A" # 1到29共29个数值,占29% when 30..59 then "B" # 30到59共30个数值,占30% else "C" # 剩下的60到99共40个数值,占40% end end # 测试抽取11次 11.times { puts pick_rarity }
这种方法的好处是代码简洁、容易理解,哪怕以后要调整成0.5%这种更精细的概率,只需要把随机数范围改成rand(200),对应调整区间就行。
方案二:权重数组法(扩展性更强)
如果以后需要频繁调整稀有度或者新增更多类型,用权重数组会更灵活——你只需要给每个稀有度设置对应的权重值,不用关心具体的区间计算:
# 定义每个稀有度的权重,权重总和刚好是100,对应百分比 rarity_weights = [ { name: "S", weight: 1 }, { name: "A", weight: 29 }, { name: "B", weight: 30 }, { name: "C", weight: 40 } ] total_weight = rarity_weights.sum { |item| item[:weight] } def pick_with_weights(weights, total) random_num = rand(total) current_weight_sum = 0 weights.each do |rarity| current_weight_sum += rarity[:weight] return rarity[:name] if random_num < current_weight_sum end end # 测试抽取11次 11.times { puts pick_with_weights(rarity_weights, total_weight) }
这个方法的核心是通过累加权重来判断随机数落在哪个稀有度的区间里,权重可以是任意正整数,哪怕总和不是100也没关系(比如权重设成10、290、300、400,结果是一样的),后期维护起来特别方便。
另外提一句,你原来的代码里rand(10)-1会生成-1到8的数值,当rand(10)返回0时,pool[-1]会取数组最后一个元素(也就是"B"),相当于实际是从9个元素里抽取?不过你说测试符合预期,可能是碰巧啦,上面的两种方案就不会有这个小问题~
内容的提问来源于stack exchange,提问作者Dedy Puji
相关产品推荐
相关产品推荐

