2

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

我可以使用的是一个随机噪声函数:一个返回随机数的函数,并且noise无论何时使用相同的. 现在,对于游戏环境中的每个点,我可以使用 生成随机数,然后将其丢弃,然后再生成相同的数字,而不是使用生成随机数并将结果存储在 中。noise(x)x(x,y)random()env[(x,y)]noise((x,y))

4

3 回答 3

4

不太确定我说的是不是显而易见的,但是使用 Perlin 噪声发生器的一些变体是一种常见的方法。这篇文章很好地描述了这样做(正如评论中提到的,这不完全是 Perlin 噪音

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

有一个噪音模块,这个页面有它的实现

gamedev.SE上有一个类似的线程

于 2012-10-18T02:14:40.323 回答
2

首先,如果您需要确保noise(x) 始终为相同的x 返回相同的值,无论如何,即使它从未被调用过,那么您根本就不能真正使用随机性。一个好的散列函数是唯一的可能性。

但是,如果您只需要能够恢复由所有先前探索过的点的值组成的先前状态(保存和加载后从未探索过的点可能会与您没有退出时不同......但是如何任何人都知道没有访问多个宇宙?),并且您不想存储所有这些点,那么重新生成它们可能是合理的。

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

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

zlib.adler32(or )的“随机周期”可能zlib.crc32太短,但如果不hash考虑它是否足够好,我不会拒绝它(可能除外)。就此而言,即使hash加上一个不错的固定端搅拌器功能也可能足够好(至少在 64 位系统上)。

Python 没有md5开箱即用的“介于”和“adler32”之间的任何东西。但是您可以找到数百种其他哈希算法的 PyPI 模块或源代码。就此而言,如果您熟悉任何听起来不错的特定哈希算法,那么它们中的大多数都是微不足道的——您可能可以编写一个具有 xor-folding 的FNV 哈希,所需时间比您浏览备择方案。

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

如果您已经用尽了可能性,那么您确实需要比具有任意盐的足够快的散列函数单独给您更多的随机性,那么:

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

但是,seed不是这样做的方法。不能保证每次运行、Python 版本、机器等都将 RNG 置于相同的状态。为此,您需要setstate

  • 保存,调用random.getstate(),pickle 和 stash 结果。
  • 要加载、读取和取消选中状态,然后调用random.setstate(state).

有关完整详细信息,请参阅文档

如果您使用的是random.Random实例,则完全相同,当然除了您必须先构造 arandom.Random才能调用setstate它。

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

这仅对模块本身有保证random.Randomrandom因为顶级模块函数只使用 hidden random.Random)。特别是,random.SystemRandom明确记录不工作。

实际上,您也可以random.Random直接腌制 a ,因为状态被腌制了。看起来应该可以工作,或者腌制一个Random对象是什么感觉?它确实有效。但实际上并没有记录它可以工作,所以getstate为了安全起见,我会坚持腌制 .

于 2012-10-18T01:06:40.820 回答
1

一种可能的实现noise是:

import random

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

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

于 2012-10-18T00:19:15.347 回答