需要可预测的随机发生器

新手上路,请多包涵

我是一名网络游戏开发人员,我遇到了随机数问题。假设一个玩家有 20% 的机会用他的剑造成致命一击。这意味着,五分之一的命中应该是关键的。问题是我在现实生活中得到了非常糟糕的结果——有时玩家在 5 次命中中得到 3 个暴击,有时在 15 次命中中没有。战斗时间很短(3-10 次命中),因此获得良好的随机分布很重要。

目前我使用 PHP mt_rand() ,但我们只是将代码移动到 C++,所以我想在我们游戏的新引擎中解决这个问题。

我不知道解决方案是否是一些统一的随机生成器,或者可能要记住以前的随机状态以强制正确分布。

原文由 Thinker 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 455
2 个回答

我同意早期的答案,即在某些游戏的小运行中真正的随机性是不可取的——这对于某些用例来说似乎太不公平了。

我在 Ruby 中编写了一个类似 Shuffle Bag 的简单实现并进行了一些测试。实现是这样做的:

  • 如果它仍然看起来很公平,或者我们没有达到最小掷骰的阈值,它会根据正常概率返回一个公平的命中。
  • 如果从过去的掷骰中观察到的概率使它看起来不公平,它会返回一个“公平化”的命中。

基于边界概率,它被认为是不公平的。例如,对于 20% 的概率,您可以将 10% 设置为下限,将 40% 设置为上限。

使用这些界限,我发现运行 10 次命中时, 14.2% 的时间真正的伪随机实现产生的结果超出了这些界限。大约 11% 的情况下,在 10 次尝试中得分为 0 次重击。 3.3% 的时间,10 次重击中有 5 次或更多次命中。自然地,使用这种算法(最小掷骰数为 5),“Fairish”运行的数量(0.03%)少得多。 .即使下面的实现不合适(当然可以做更聪明的事情),值得注意的是,您的用户通常会觉得真正的伪随机解决方案是不公平的。

这是我用 Ruby 编写的 FairishBag 的内容。 此处提供了整个实现和快速蒙特卡罗模拟(要点)

 def fire!
  hit = if @rolls >= @min_rolls && observed_probability > @unfair_high
    false
  elsif @rolls >= @min_rolls && observed_probability < @unfair_low
    true
  else
    rand <= @probability
  end
  @hits += 1 if hit
  @rolls += 1
  return hit
end

def observed_probability
  @hits.to_f / @rolls
end

更新: 使用此方法确实会增加获得致命一击的总体概率,使用上述界限将其提高到大约 22%。您可以通过将其“真实”概率设置得低一点来抵消这一点。 17.5% 的概率与公平的修改产生了大约 20% 的观察到的长期概率,并保持短期运行感觉公平。

原文由 Ian Terrell 发布,翻译遵循 CC BY-SA 3.0 许可协议

这意味着,五分之一的命中应该是关键的。问题是我在现实生活中得到了非常糟糕的结果——有时玩家在 5 次点击中获得 3 个暴击,有时在 15 次点击中没有。

你需要的是一个 洗牌包。它解决了真随机对于游戏来说太随机的问题。

算法大概是这样的:你把 1 个重击和 4 个非重击放在一个袋子里。然后你将它们在袋子里的顺序随机化,一次挑出一个。当袋子是空的时,你再次用相同的值填充它并随机化它。这样,您将平均每 5 次命中获得 1 次重击,并且连续最多 2 次重击和 8 次非重击。增加包中物品的数量以获得更多随机性。

这是我前段时间编写的 一个实现(Java 语言) 及其测试用例 的示例。

原文由 Esko Luontola 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏