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

116 views Asked by At

I am using GDScript (Godot's Python) attempting to create an algorithm that generates random noise between an integer of 0 or 1, onto a 2 dimensional array. To do so, I am iterating with predefined variables to append each value to the relevant spot on the array. I understand that pseudorandom number generators can reveal bias, especially if used within a short period of time and defined with a low range, but even accounting for those factors I seem to be getting 100% consistent (i.e. not random) results. That is to say, every sub-array on the array contains the exact same set of characters at the exact same indexes.

My code is quite simple:

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)

And the results always come out something like this:

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]

The placement of 1s and 0s across an individual sub-array changes with each attempt, but they always match up across the array every time. This does not change when I force the function to slow down, force it to take a new seed every time, change the dimensions of the array, or when I change the range of the rng.

Am I using the pseudo-random generator wrong? I can't seem to get this code to generate anything actually random across the board, only within an individual sub-array, to which that pattern repeats across the array. Of course, I am clearing the subMap array to ensure I'm not pasting the same result at every element or continuously extending the length of each element, so it shouldn't be a result of the subMap array not changing. Any help in making this rng truly rng would be much appreciated.

edit: included the part where I declare the subMap array

edit2: fixed code formatting

edit3: included section of code that prints the results to console

edit4: additional context

Note: Apparently, the randomize() function (which generates a seed for the randi function to use) is called when the project is run by default now, according to GDScript documentation. Just in case, I have tried a version of this code that includes the randomize() function at _ready(), but this does not solve the problem. Calling randomize() at every iteration of the random number generator (which the documentation does not recommend anyways) didn't fix the problem either.

1

There are 1 answers

1
Faye Rauscher On

Figured out the issue. The append() function for arrays in GDScript, by default, rely on a shallow copy of whatever value you put in the parameter. In other words, despite clearing and creating a new subMap array at each element in geographyMap, every time I did so all elements within geographyMap would update to match the new subMap array. I fixed this issue by calling the duplicate(true) function within the append() function to force a deep copy, which looks like this:

geographyMap.append(subMap.duplicate(true))