65.9K
CodeProject 正在变化。 阅读更多。
Home

XCOM 伪随机数生成器是否损坏?

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1投票)

2014 年 7 月 30 日

GPL3

2分钟阅读

viewsIcon

4895

XCOM 的伪随机数生成器是否损坏?

前几天我坐下来玩 XCOM。总的来说,这是一款很棒的游戏。然而,在几个回合中,我用 3 个不同的士兵射击,命中率高达 90% 以上,但都打空了。好吧,当你计算一下 ~.1^3 的概率时,你就会开始怀疑是不是哪里出了问题。作为任何游戏玩家,我当然认为我不可能玩不好这个游戏。问题肯定出在游戏本身 ;-p。

那么,对于这个大问题的答案?是的,XCOM 使用了一个数学上较差的伪随机数生成器。具体来说,它使用了一个线性同余生成器。要回答它是否损坏的问题:没有。它是否糟糕到真正影响游戏体验? 倒也不至于。所以对于所有那些错失了 98% 命中率的射击而感到愤怒的人来说,是的,你可能只是运气不好 ;-p。

现在,如果你想知道它是如何工作的,我会在下面解释 :-D。我先道歉一下,我写得有点快,所以解释可能不够清晰。

线性同余生成器使用公式 X(n+1) = (aXn + c) mod m,其中 X 是随机数生成的种子值。Xcom 使用 a = 0x0BB38435,c = 0×3619636。Xcom 使用自启动以来的 CPU 时钟周期作为种子值。以下是生成数字的实际代码

uint32_t seed; /* Set elsewhere.

float random_number_plox() {
static union {
uint32_t i;
float f;
} foo;
int bar;

/* LCG: x = 0x0BB38435 * x’ + 0x3619636B */
foo.i = seed * 0x0BB38435;
foo.i += 0x3619636B;
seed = foo.i;

/* Convert the integer to a floating point number between 1.0 and 2.0 by
* manipulating the floating point format.
*/
foo.i = foo.i & 0x7FFFFF | 0x3F800000;

return foo.f – 1.0f; /* Return something between 0.0 and 1.0 */
}

它实际上并没有使用模运算;而是使用一些浮点运算。这些行

foo.i = foo.i & 0x7FFFFF | 0x3F800000
return foo.f – 1.0f; /* Return something between 0.0 and 1.0 */

可能有点令人困惑。你需要了解一些关于计算机中浮点数存储方式的知识。与其在这里解释,我建议你阅读:http://kipirvine.com/asm/workbook/floating_tut.htm。一旦你理解了这些,这些行就会变得更清晰。foo.i & 0x7FFFFF 是将符号位和指数位清零,而 | 0x3F800000 是将符号位设为正数并将指数位设为 0。因为我们知道种子值大于 1,所以我们知道进入这个计算时,我们有一个大于 1 的值。然而,计算机将把这个数字的低 23 位解释为二进制尾数,这将产生一个介于 1 和 2 之间的数字。

最后一行 ” return foo.f – 1.0f;” 只是强制从整数到浮点数的隐式转换,并减去 1,这将给我们一个介于 0 和 1 之间的数字,然后将用于确定是否命中。感谢 Yawning Angel 在 http://www.schwanenlied.me/yawning/XCOM/XCOMPRNG.html 上提供的信息。

© . All rights reserved.