【问题标题】:Properly seeding a RNG for a card game为纸牌游戏正确播种 RNG
【发布时间】:2011-09-05 21:00:06
【问题描述】:

我正在开发一款纸牌游戏,我需要洗牌算法做得非常好,并且每次游戏运行时都不同,并且没有可预测的纸牌序列。

我正在使用 Mersenne twister 算法,但它仍然需要一个种子,所以说真的,虽然它产生了大量的数字,但现在只有 1000 个可能的游戏序列,因为我使用 time(NULL) 来种子。我应该如何播种?

【问题讨论】:

  • 为什么使用 time(NULL) 意味着你只有 1000 种可能性?
  • @SoapBox 如果我一直用 678 做种子,游戏总是完全一样的,time(NULL) 返回一个从 1 到 1000 的值
  • 如您所知,time_t... 的可能值只有 1000 个 ;)
  • time(NULL) 返回自 1970 年 1 月 1 日 GMT 以来的当前时间(以秒为单位)。 time(NULL) 的值几十年来一直大于1000,并且每秒增加一次。 ;)

标签: c++ algorithm random playing-cards mersenne-twister


【解决方案1】:

我的标准播种技术:

  1. 如果存在/dev/urandom,则从那里读取种子。

  2. 如果您使用的是 Windows,请使用 CryptGenRandom()

  3. 如果一切都失败了,请使用time()

(不确定你的 Mersenne twister 来自哪里,但新的标准库在 <random> 中有一个,它集成得非常优雅。)

我很高兴听到针对前两个步骤未涵盖的平台的建议!

【讨论】:

  • 好吧,人们总是可以将短波无线电天线插入串行端口并读取随机位的大气噪声...... ;)
  • 我会完全避免将选项 3 编码到你的代码中,因为任何有风险的东西 - 你不想意外地在不知不觉中生成可预测的随机数!
  • 尼克:嗯,这都是一个权衡。如果有钱,我相信你知道你的平台是什么,所以你可以找到一个合适的随机来源。
【解决方案2】:

您可以使用operating system's entropy source 来获得一个好的随机数种子。在 Windows 上,这是CryptoAPI;在 POSIX 上,从 /dev/urandom 提取字节。

【讨论】:

  • 请注意,从 /dev/random 读取可能会阻塞,尤其是当您同时运行大量进程副本时。
  • 四个字节还不够。 mersenne twister 的内部状态要大得多,有 52 个! ~= 2^225 种可能的洗牌方式。
  • @Kerrek 确实 - 和 /dev/urandom 在现代内核中应该是加密安全且完全足够的。
  • Nick:<random>(所有引擎,就此而言)中的 MT 从一个与其结果类型一样大的值作为种子,即unsigned int
  • @Kerrek SB:不是真的;见 26.5.1.2 种子序列要求。
【解决方案3】:

典型的种子值是 64 位当前时间的低 32 位。例如使用Linux gettimeofday 调用的返回值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-13
    • 2013-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多