使用 GDScript 的原生伪随机数生成器获得 100% 可预测的结果

100% predictable results using GDScript's native pseudo-random number generators

提问人:Faye Rauscher 提问时间:11/11/2023 最后编辑:Raymond ChenFaye Rauscher 更新时间:11/11/2023 访问量:47

问:

我正在使用 GDScript(Godot 的 Python)尝试创建一种算法,该算法可以在 0 或 1 的整数之间生成 2 维数组之间的随机噪声。为此,我正在迭代预定义的变量,以将每个值附加到数组上的相关点。我知道伪随机数生成器可以揭示偏差,特别是如果在短时间内使用并以低范围定义,但即使考虑到这些因素,我似乎也得到了 100% 一致(即非随机)的结果。也就是说,数组上的每个子数组都包含完全相同的字符集,索引完全相同。

我的代码很简单:

var subMap: Array[int]
var geographyMap: Array[Array]
func generate_map():
    print("Generate map function called")
    var mapHeight: int = 10
    var mapWidth: int = 10
    geographyMap.clear()
    for yy in mapHeight:
        subMap.clear()
        for xx in mapWidth:
            var chance: int = randi_range(0, 1000)
            if (chance > 500):
                subMap.append(1)
            else:
                subMap.append(0)
        geographyMap.append(subMap)

    for i in geographyMap:
        print(i)

结果总是这样:

example 1:
[1, 0, 0, 1, 0, 0, 1, 0, 1, 0]
[1, 0, 0, 1, 0, 0, 1, 0, 1, 0]
[1, 0, 0, 1, 0, 0, 1, 0, 1, 0]
[1, 0, 0, 1, 0, 0, 1, 0, 1, 0]
[1, 0, 0, 1, 0, 0, 1, 0, 1, 0]
[1, 0, 0, 1, 0, 0, 1, 0, 1, 0]
[1, 0, 0, 1, 0, 0, 1, 0, 1, 0]
[1, 0, 0, 1, 0, 0, 1, 0, 1, 0]
[1, 0, 0, 1, 0, 0, 1, 0, 1, 0]
[1, 0, 0, 1, 0, 0, 1, 0, 1, 0]

example 2:
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0]

example 3:
[1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
[1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
[1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
[1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
[1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
[1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
[1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
[1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
[1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
[1, 1, 0, 1, 1, 1, 0, 1, 1, 1]

1 和 0 在单个子数组中的位置会随着每次尝试而变化,但它们每次在数组中始终匹配。当我强制函数放慢速度、每次强制它获取新种子、更改数组的尺寸或更改 rng 的范围时,这不会改变。

我用错了伪随机生成器吗?我似乎无法让这段代码生成任何实际随机的东西,只能在一个单独的子数组中生成,该模式在整个数组中重复。当然,我正在清除 subMap 数组,以确保我不会在每个元素上粘贴相同的结果或不断扩展每个元素的长度,因此它不应该是 subMap 数组未更改的结果。任何帮助使这个 rng 真正 rng 将不胜感激。

edit:包括我声明 subMap 数组的部分

编辑 2:修复了代码格式

Edit3:包含将结果打印到控制台的代码部分

编辑 4:附加上下文

注意:显然,根据 GDScript 文档,randomize() 函数(为要使用的 randi 函数生成种子)在项目现在默认运行时被调用。为了以防万一,我已经尝试了此代码的一个版本,该版本在 _ready() 中包含 randomize() 函数,但这并不能解决问题。在随机数生成器的每次迭代中调用 randomize()(无论如何文档都不建议这样做)也没有解决问题。

随机 随机种子 GDScript Perlin-噪声

评论

0赞 Mike Doe 11/11/2023
ask.godotengine.org/94988/randi_range-not-working TL;DR:你在跑步吗?randomize
0赞 Faye Rauscher 11/11/2023
@MikeDoe 根据 GDScript 的文档,该函数会在项目运行时自动调用(我相信这是 Godot 4.0 中的更改)。此外,我还运行了此代码的一个版本,该版本打印每次生成的单个数字,在这种情况下,结果肯定是随机的。我没有收到链接文章中描述的错误,其中 rng 每次都生成相同的数字,但子数组保持匹配。
0赞 Faye Rauscher 11/11/2023
@MikeDoe 无论如何,我继续添加了 randomize() 函数,只是为了看看文档是否不准确,不幸的是它没有改变结果。我运行了两次迭代,一次是在 _ready() 处调用函数,另一次是在机会变量声明之前生成数字之前每次调用函数,不幸的是,两次迭代都没有解决问题。

答:

1赞 Faye Rauscher 11/11/2023 #1

找出问题所在。默认情况下,GDScript 中数组的 append() 函数依赖于您在参数中放置的任何值的浅拷贝。换句话说,尽管在 geographyMap 中的每个元素上清除并创建了一个新的 subMap 数组,但每次我这样做时,geographyMap 中的所有元素都会更新以匹配新的 subMap 数组。我通过调用 append() 函数中的 duplicate(true) 函数来强制深度复制来解决此问题,如下所示:

geographyMap.append(subMap.duplicate(true))

评论

0赞 Mike Doe 11/11/2023
请将您的答案标记为解决方案:)