如何在随机数生成中避免“太”幸运/不幸的条纹?


30

我目前正在使用一种多人战斗系统,其中玩家造成的伤害总是乘以0.8到1.2之间的随机因子。

从理论上讲,真正随机的RNG最终可能会多次产生相同的数目(请参阅“ 俄罗斯方块困境”)。这可能导致一场比赛,其中一名球员总是造成很高的伤害,而另一名球员总是造成非常低的伤害。

我该怎么做才能确保不会发生这种情况?有些RNG在避免重复方面比其他RNG好吗?


我不知道这是怎么回事。当然,您将获得x1,x2,x3,x4的序列。所有x都很大。那不是随便吗?
共产主义鸭子

Answers:


26

您可以通过列出损坏结果和混排的预设列表,以与Tetris相同的方式解决该问题。

假设您知道玩家将以线性分布造成0.8到1.2倍的伤害。拿列表[0.8,0.9,1.0,1.1,1.2]。随机洗牌,得到[1.2,1.0,0.8,0.9,1.1]。

玩家第一次造成伤害时,他们造成1.2倍伤害。然后1x。然后,依此类推,直到1.1倍。仅当数组为空时,才应生成并重新排列新数组。

实际上,您可能希望一次对4个以上的数组执行此操作(例如,以[0.8,0.8,0.8,0.8,0.9,0.9,0.9,0.9,...]开头)。否则,序列的周期足够短,以至于玩家可以弄清楚他们的下一个打击是否是“好”。(尽管这也可以为战斗增加更多的策略,例如在《勇者斗恶龙IX》的Hoimi表中,人们想出了如何通过查看治疗数值并进行调整直到找到保证的下降来进行探测的方法。)


3
为了使它更具随机性,您总是可以将列表的一半作为随机数,另一半计算为(2-x)以得到正确的平均值。
亚当

2
@Adam:该方法实际上仅适用于该特定示例。如果您要处理俄罗斯方块而不是伤害乘数,那么2-S格是什么?

6
通常的说法是系统是“无替换的随机”。确实,这类似于使用一副纸牌而不是骰子。
Kylotan

更好的是,您可以真正随机地做一半的数字,而只有一半受此规则约束。
o0'。

1
它仍然可能导致本地分布与全局分布不相似,这正是问题所不希望的。诸如“真正随机”之类的术语是模糊的伪数学。您定义的统计信息越多,意图和游戏设计就越清晰。

5

我实际上写了一些代码来做到这一点。其要旨是使用统计数据来纠正不幸的条纹。您可以执行此操作的方法是跟踪事件发生的次数,并以此来偏移PRNG生成的数字。

首先,我们如何跟踪事件的百分比?幼稚的做法是将所有曾经生成的数字保存在内存中,然后将它们平均化:这虽然有效,但效率极低。经过一番思考,我提出了以下内容(基本上是一个累积移动平均线)。

采取以下PRNG样本(如果样本> = 0.5,我们将在其中进行处理):

Values: 0.1, 0.5, 0.9, 0.4, 0.8
Events: 0  , 1  , 1  , 0  , 1
Percentage: 60%

请注意,每个值占最终结果的1/5。让我们以另一种方式看待它:

Values: 0.1, 0.5
Events: 0  , 1

注意,0贡献贡献了价值的150%,贡献贡献了价值的50%。更进一步:

Values: [0.1, 0.5], 0.9
Events: [0  , 1  ], 1

现在,第一个值占该值的66%,最后一个33%。我们基本上可以将其分解为以下过程:

result = // 0 or 1 depending on the result of the event that was just generated
new_samples = samples + 1

average = (average * samples / new_samples) + (result * 1 / new_samples)
// Essentially:
average = (average * samples / new_samples) + (result / new_samples)

// You might want to limit this to, say, 100.
// Leaving it to carry on increasing can lead to unfairness
// if the game draws on forever.
samples = new_samples

现在,我们需要对从PRNG采样的值的结果进行偏倚,因为我们在这里有一定百分比的机会,事情变得容易得多(例如,RTS中的随机损坏数量)。这将很难解释,因为它“只是我发生的”。如果平均值较低,则意味着我们需要增加事件发生的机会,反之亦然。所以一些例子

average = 0.1
desired = 0.5
corrected_chance = 83%

average = 0.2
desired = 0.5
corrected_chance = 71%

average = 0.5
desired = 0.5
corrected_change = 50%

现在,“发生在我身上”的是,在第一个示例中,83%只是“ 0.6中的0.5”(换句话说,“ 0.5中的0.5加0.1”)。在随机事件中,这意味着:

procced = (sample * 0.6) > 0.1
// or
procced = (sample * 0.6) <= 0.5

因此,为了生成事件,您基本上可以使用以下代码:

total = average + desired
sample = rng_sample() * total // where the RNG provides a value between 0 and 1
procced = sample <= desired

因此,您得到了我放入要点中的代码。我很确定这一切都可以在随机损坏的情况下使用,但是我还没有花时间来弄清楚这一点。

免责声明:这是所有本地统计数据,我在该领域没有任何教育。我的单元测试确实通过了。


在第一个示例中看起来像是一个错误,因为0.1和0.9值都导致0事件。但是,您基本上是在描述如何保持累积移动平均值(en.wikipedia.org/wiki/Moving_average#Cumulative_moving_average)并根据此值进行校正。一个风险是,每个结果将与先前的结果显着反相关,尽管这种相关会随着时间的推移而降低。
Kylotan

1
我很想将其更改为使用“泄漏积分器”系统:从平均值初始化为0.5开始,而不是对样本进行计数,而是选择不会递增的任意常数值(例如10、20、50或100) 。这样,在整个发生器的使用过程中,至少两个后续值之间的相关性是恒定的。您还可以调整常量值-较大的值表示较慢的校正和更明显的随机性。
Kylotan

@Kylotan谢谢,感谢您提供名字。我不确定您第二句话的意思-也许提供一个新的答案?
乔纳森·迪金森

这是非常聪明的,并且没有数组的限制。我了解Kylotan的建议,即samples从一开始就将其最大值初始化(在这种情况下为100)。这样,RNG不需要经过99次迭代即可稳定下来。无论哪种方式,我可以用这种方法看到的一个缺点是它不能保证公平性,而只能保证恒定的平均值。
找不到用户

@jSepia-的确,您仍然会遇到公平/不公平的情况,但是(通常)他们会得到平衡的结果。例如,在我的单元测试中,我“强制”执行了100次非过程,当我进行实际采样时,我遇到了约60次过程。在不受影响的情况下(如果您查看代码),在最坏的情况下,通常在任一方向上运行50%proc的速度为2/3。但是一个玩家可以逃跑,让他们击败另一位玩家。如果您想更偏重于公平:total = (average / 2) + desired
乔纳森·迪金森

3

实际上,您要的是大多数PRNG的对立面,即非线性分布。只需在您的规则中加入某种递减的收益逻辑,假设超过1.0x的一切都是某种“严重打击”,只需说您每回合将爆击的几率提高X,直到得到然后将其重置为Y。然后每轮进行两次掷骰,一个掷骰以确定是否暴击,然后另一个掷骰确定实际的震级。


1
这是我要采用的一般方法,您可以使用RNG的均匀分布进行转换。您还可以将RNG的输出用作您自己的自定义发行版的输入,该自定义发行版会根据最近的历史记录进行自我调整,即强制输出​​中出现差异,从而使RNG在人类感知方面看起来“更加随机”。
迈克尔

3
我实际上知道做这样的MMO,但是每次您获得一次暴击的机会实际上会增加,直到您没有一次,才会重置为非常低的值。这会导致罕见的脆皮条纹,令玩家非常满意。
coderanger 2011年

听起来像是个不错的算法,长时间的干咒总是令人沮丧,但这并不会导致疯狂的暴行。
迈克尔

2
要解决此问题,不需要非线性分布,仅需要分布的短时间顺序子集具有与分布本身相同的属性。

这是暴雪游戏做到的方式,自魔兽争霸3以来至少
德拉

2

席德·迈耶(Sid Meier)在GDC 2010上就该主题和《文明游戏》发表了精彩演讲。稍后,我将尝试查找并粘贴链接。本质上,感知的随机性与真实的随机性不同。为了使事情变得公平,您需要分析以前的结果并注意玩家的心理。

不惜一切代价避免遭受不幸的连胜(如果前两回合不走运,则应保证下一回合是幸运的)。玩家应该总是比AI对手幸运。


0

使用偏移偏差

01rb0

总体分布将受到以下公式的影响:

rexp(b)

b1b0

取该数字并将其适当缩放至所需范围。

每次玩家掷出好球时,都要从偏差中减去。每次玩家滚动不利时,请增加偏见。更改的数量可以根据卷的(不)有利程度来定标,也可以是统一数量(或组合)。您将需要调整特定的值以适合您想要的感觉。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.