Python中的随机噪声函数

时间:2012-10-18 00:19:15

标签: python random

我正在用Python编写一个游戏,其中环境是随机生成的。目前,游戏的“保存”功能通过写出玩家探索过的环境的所有部分来工作。结果是保存文件比它们需要的大 - 为什么当你可以再次生成它时将随机数据写入磁盘?

我可以使用的是一个随机噪声函数:一个函数noise,使noise(x)返回一个随机数,并且每当用它调用时,它总是相同的数字值x。现在,对于游戏环境中的每个点(x,y),我不是使用random()生成随机数并将结果存储在env[(x,y)]中,而是使用noise((x,y))生成随机数扔掉它,然后生成相同的数字。

3 个答案:

答案 0 :(得分:4)

我不太确定我是否说明了这一点,但使用Perlin噪声发生器的某些变体是一种常见的方法。 This post很好地说明了这一点(正如评论中提到的那样not exactly Perlin noise

对于给定位置,Perlin函数将返回随机值(位置可以是2D,3D或任何维度)。

有一个noise模块,this page有一个实现

gamedev.SE

上有类似的帖子

答案 1 :(得分:2)

首先,如果你需要它是真的,噪声(x)将始终为相同的x返回相同的值,无论如何,即使它从未被调用过,那么你根本不能真正使用随机性。一个好的哈希函数是唯一的可能性。

但是,如果您只需要能够恢复包含所有之前探索过的点的值的先前状态(保存和加载后从未探索过的点可能会有所不同)如果你还没有退出......但是如果没有访问多个宇宙,谁能告诉你?),而你不想存储所有这些点,那么重新生成它们是合理的。

但是让我们退一步吧。你想要一些像哈希函数一样的东西。你可以使用哈希函数吗?

我认为hashlib中的算法太慢了(md5可能是最快的,但是测试它们全部),但我不会在没有实际测试的情况下拒绝它们。

zlib.adler32(或zlib.crc32)的“随机时段”可能太短,但我不会拒绝它(除了hash除外)而不考虑是否是hash够好了。就此而言,即使md5加上一个不错的固定侧混合器功能也可能足够好(至少在64位系统上)。

Python没有提供“seed和”adler32“之间的任何内容。但是你可以找到数百种其他哈希算法的PyPI模块或源代码。就此而言,如果您熟悉任何听起来不错的特定哈希算法,其中大多数都是微不足道的 - 您可能可以编写代码,例如FNV hash使用xor-folding,花费的时间比您需要的时间少。看看其他选择。

另外,请记住,您可以在“新游戏”时生成一堆随机字节,将其存储在保存文件中,并将其用作哈希函数的盐。

如果你已经筋疲力尽,那么你真的需要更多的随机性,而不是任意盐的快速哈希函数可以让你独自一人,那么:

听起来你已经需要存储用户探索过的点列表(因为你怎么知道还需要恢复哪些点?)。订单并不重要。因此,您可以按探索顺序存储它们。这意味着您可以确定性地重新生成值(只需迭代列表)。这意味着您可以根据自己的答案使用@delnan的建议。

但是,setstate不是这样做的方法。无法保证每次在运行,Python版本,机器等之间将RNG置于相同的状态。为此,您需要random.getstate()

  • 要保存,请致电random.setstate(state),然后挑选并存储结果。
  • 要加载,阅读和取消状态,请致电random.Random

有关详细信息,请参阅the docs

如果你使用的是random.Random个实例,那就完全相同了,当然除非你需要构建一个setstate,然后再调用random.Random

这保证可以在程序运行之间,跨机器等运行。即使使用较新版本的Python也是如此。但是,保证与较旧的版本的Python一起使用。 (也就是说,如果用户使用Python 2.6保存游戏,然后尝试用2.5加载它,状态将不兼容。我认为唯一的问题是2.6->更旧和2.3->更老,但是当然不能保证将来不会有其他的。)我建议存放Python版本,如果它们降级,则显示警告说“此保存文件需要Python 2.6或更高版本。你有Python 2.5负载可能会失败。无论如何都要继续?“

这仅保证randomrandom.Random模块本身(因为顶级模块功能只使用隐藏的random.SystemRandom)。特别是,明确记录random.Random不起作用。

实际上,你也可以直接挑选一个Random,因为状态被腌制了。看起来应该有效,或者腌制getstate对象的感觉是什么?它确实有效。但实际上并没有记录下来,所以为了安全起见,我会坚持使用{{1}}进行酸洗。

答案 2 :(得分:1)

noise的一种可能实现是:

import random

def noise(point):
    gen = random.Random()
    gen.seed(point)
    return gen.random()

我不知道Random.seed()有多快。此外,Random可能会从一个版本的Python变为另一个版本,导致我的游戏玩家在升级时发现环境发生变化。