#random #table #outcome #probability #weight #generate #set

droprate

一个基于一组选项和权重生成不同随机试验的库

1 个稳定版本

1.0.0 2019 年 8 月 9 日

#7#outcome

MIT 许可证

26KB
144

Drop Rate

一个基于加权概率列表选择结果的 Rust 包。

您可以使用它实时计算表格结果,或者存储表格并重复使用以从同一表格中计算结果。

随机

RandomTable 使用最简单的随机选择。这应该与 Rust 中使用的伪随机数生成器的“真正随机”程度相当。它将包括所有著名随机数的属性,如聚类和不可预测性,并最终(经过足够多的试验)趋向于理论结果比率。

如果您只需要一个随机选择结果的工具,那么这是一个相当简单、直接的解决方案。

工作原理

在创建时,RandomTable 会将表中所有可能结果的权重相加以确定总和,当您调用 random() 时,它会生成一个介于 0 和最大值之间的随机数,找到它落在哪个条目上,并返回该结果。

注意

当用于游戏时,随机分布可以是极其残忍或极其慷慨的。如果某件事情有 10% 的概率,那么在无限次的试验中,您将看到该结果平均每 10 次出现一次。但您也可能看到它需要 100 次试验才能看到该结果,或者您可能在一开始就得到该结果。随机性的本质是每次试验都有相同的概率,过去不会影响下一次结果的概率。(您可以谈论任何给定结果序列的可能性,但这完全是另一回事。)

大多数人都不太理解“随机”是如何真正工作的,这导致了赌徒谬误(https://en.wikipedia.org/wiki/Gambler%27s_fallacy)。这导致用户(错误地)认为游戏有时有内置的系统来“欺骗”他们,而实际上,这只是真正随机类似分布的工作方式。

计算机生成的“随机”数字实际上并不是随机的。通常会有一个可预测的结果,给定一个恒定的起始“种子”,会产生一个一致的数字序列。更准确地说,这些被称为“伪随机”数字序列。它们相当符合真正随机序列的属性,并且序列(如果我没有错的话)在没有知道随机种子和序列索引的情况下通常是不可能预测的(虽然我想,一个足够长的数字序列可以帮助你合理地推断出索引)。所以,如果你在计算机意义上看到“随机”,请原谅,因为它实际上并不是“真正的”随机,但对于大多数日常使用来说,“足够随机”。

如果你想要真正的随机,这里有一个网站使用“真空的量子涨落”来生成数字序列,到目前为止,这些序列在统计学上被证明与真正的随机序列无法区分。(https://qrng.anu.edu.au/

相当随机

相当随机算法旨在产生更“类似人类”的伪随机结果,具有更少的聚集和更快地向理论概率趋近的趋势。换句话说,它证明了赌徒谬误是正确的。当然,这些结果与真正的随机结果相差甚远。

更具体地说,在结果被选中后,其发生的可能性会立即降低,而未被选中的次数越多,其发生的可能性就越大。聚集(即你可以有一个“热手”)是此算法的一个目标,但发生的频率会降低,并且随着时间的推移,持续的时间越长,发生的可能性就会呈指数级降低。然而,大多数用户会体验到他们认为的“公平”的随机分布。

这在创建用户不希望预测(除非跟踪)的结果的情景中很有用,但这些结果将符合用户的期望,并持续地奖励他们“它很快就会发生”的希望。这种用法可以用于带有随机物品掉落的游戏,用户需要为此努力。玩家的体验可能感觉像是游戏(或开发者)故意编写了底层系统,以阻止他们获得他们想要的物品。实际上,这就是随机数字的工作方式——它们并不友好,也不在乎你尝试了多久才得到10%的掉落。机会总是相同的,并且对许多玩家来说这不是乐趣。如果你想对玩家更好,并防止他们需要比预期更长的时间进行打磨,那么这就是适合你的算法!

工作原理

相当随机算法将每次试验结果的概率权重按比例重新分配到所有可能的结果中(包括选定的结果)。例如,如果结果 A 有20%的发生概率,并且它被选中,那么这20%将被重新分配到所有其他可能的结果中——这意味着如果结果 B 原始有50%的概率,而 C 有30%的概率,那么 A 的概率将增加10个百分点(20%的50%)到60%,结果 C 将增加6个百分点(20%的30%)到36%,而 A 将被设置为只有4%(20%的20%)。所有的权重都在系统中保留(60% + 36% + 4% = 100%)。你可以看到,A 仍然有可能再次被选中,但现在BC 被选中的可能性要大得多,就像人类试图保持“随机”的感觉一样。下次,如果结果 B 被选中,这60个点将被重新分配,但总是使用原始的权重比,而不是修改后的一个——所以 A 增加12并成为16%,B 被设置为30%,而 C 增加18并成为54%。现在 C 将是最可能的结果,这对许多人来说是有“道理”的,因为它还没有被选中。

注意

我没有正确地进行数学分析,但似乎Fairly Random在返回预期结果比率方面表现相当不错,实际上比基本伪随机生成器更快地收敛到理论结果。作为一个额外的想法,这可能是相当明显的,算法积极努力更快地实现理论结果,同时仍然允许随机性发挥作用。

待办事项:解释Fairly Random的工作原理...

ShuffleRandom

(未来) 这个随机数需要指定每个结果的概率作为整数。然后它会创建一个所有可能结果的打乱(就像一副牌)列表,您可以通过运行random()函数来遍历该列表。当遍历列表时,该列表将自动重新打乱所有结果。

注意

由于在用尽时“牌堆”会被重新洗牌,唯一可能在连续多次得到唯一结果的情况是在洗牌的边界处,牌堆末尾的结果可能在下一次洗牌时被重新洗到牌堆的开始处。(如果一个结果有概率权重 > 1,它理论上可能连续发生多次,但这些将被视为牌堆中的单独“卡片”。)换句话说,如果您有一副数字[1-10]的“牌堆”,并且每个数字的概率权重都是1,那么同一个数字可能连续两次出现,但只有在10的倍数的边界上,因此在更真实的随机中的分组就不会发生。

PlaylistRandom

(未来) 播单旨在提供一个有吸引力的随机选择器,就像在媒体播放器中播放随机歌曲时可能使用的那样。

洗牌播单的期望与洗牌牌堆的期望有何不同?

  • 当播单再次开始时,它不应该选择最近播放过的歌曲。
  • 也许可以使用阈值/优先级权衡来连续播放,它选择最古老的播放过的歌曲(如果它足够陈旧)或从所有最不常选择的选择(在“最古老”的阈值内)。
    • 确保这实际上允许选择顺序的改变。

待办事项:实现并解释

TrueRandom

(未来) 这可能是最慢的算法。它实际上为每次试验查询在线服务的随机数(额外优惠:请求多次试验以最小化停机时间),确保您的随机性尽可能接近真正的随机,而不必为商业级硬件随机数生成器(HRNGs)付费。

重复间隔

(未来) 在研究语言或学习新术语时,研究表明,通过增加重复间隔,可以使近期看到的项目被非常频繁地看到,然后随着它们对研究者的“熟悉度”增加而频率逐渐降低。

这个随机表最初将被打乱(例如,就像ShuffleRandom),并设置为适中的重复间隔。已返回的选项将比未见选项有更高的优先级,直到它们超过默认的重复阈值,此时将从未返回的列表中添加新项目。

这非常适合创建闪卡程序,但可以用于任何需要让用户熟悉他们已经看到的东西,并在引入新项目之前给他们时间掌握每个项目的场景(例如,生成随机地牢并选择要添加到每个级别的怪物)。

注意

  • 可以为每个项目指定初始重复值,从而使每个条目从开始就更有或更少地常见,这是理想的(例如,您可以按难度分类怪物,然后选择并随机引入每个难度级别的怪物,但每个等级都应该在引入下一等级的任何怪物之前被看到)。
  • 添加一个模糊阈值,以便如果项目接近相同的阈值,它们在下次出现时不必总是保持相同的顺序。
  • Vec<T> 初始化并自动选择一个权重。
  • 保留最近的试验结果,并允许API调整复现间隔(乘数?)(例如,使用闪卡,如果用户不记得,则标记为更早而不是更晚复现)。
  • 允许自定义复现算法/函数以自定义线性/非线性复现间隔。
  • 确保间隔可以像现实世界的时间一样使用,同时也能很好地工作,不表示现实世界的时间间隔。
    • 这可能意味着用户可以提供“自上次试验以来”的时间值,从而重新排列列表?

路线图

  • 实现洗牌表
  • 实现播放列表表
  • 创建一个宏以便更容易地创建内联表?
  • 生成一些示例代码(目前,请查看测试用例——它很简单)
  • 从表中输出统计数据
    • 例如,理论概率、相对概率等...
    • 例如,连续N的概率或其他模式
  • 创建参考表,它们有自己的本地历史记录,但可以引用其他基本表

依赖关系

约1.5-2MB
约37K SLoC