How do you generate multiple unique random numbers within a range based on a seed?

In the game I’m making right now, I need several different npc’s to generate a random number, between one and one hundred based on the same seed, but I don’t want them to generate the same number, I want each number to be completely random, but I can only use 1 seed for all of them. There are 10 npcs in this scene. Can anyone show me how to do this (In script if you please). I’ve thought about using the the original seed to generate a random number, and use that random number as a seed to generate another random number, and so on and so forth until I have 10 random values, this might actually work, but I’m afraid this will make some strange pattern between the values and it’s important for the game that each value is completely random and independent of the others, and I don’t even know how to generate a number within a range and based on a seed to test this theory. Please Help

Well, searching for “Unity random” would lead to the Random class documentation, which provides the static methods InitState(int seed) and Range(float/int min, float/int max), initializing the random number generator state with a custom seed and returning a pseudorandom float or int value between the provided min and max values respectively. However, this doesn’t produce completely random values (read the InitState documentation), but I don’t think that should be a problem. If you actually don’t call InitState, the seed used is based on the system clock to prevent it from being the same every time, so you can just call Range for each of the NPCs, that should work nicely.

To make sure each value is only present once just fill an array with numbers 1 to 100 and shuffle it. Then take the values out there. Fisher-Yates shuffle is a good algorithm for this kind of thing.

Edit: formatting

1 Like

Can you s

Can you please show me what that would look like in script. I have no experience writing scripts using the randomizer in unity

As a matter of fact, your hunch is pretty good. Yes, there is a chance you’ll inadvertently defeat the apparent randomization of RNG.

Here’s an excellent explanation of what is going on without me having to write a book on the subject.
https://blogs.unity3d.com/2015/01/07/a-primer-on-repeatable-random-numbers/

After you read the article:
I am personally using a combination of my own implementation of PCG and xxHash. And I’ve built decent libraries on top of this, so am pretty well acquainted with all the issues, use cases, performance considerations, and things like saving and reusing states, and so on. Rolling your own libraries isn’t for beginners, but given that I went through this hassle I can help you with any step along the way.

xxHash you can find and repurpose, while core PCG is incredibly tiny in fact, and you need to build everything surrounding this core to make it work like Unity’s Random works (and much better than that, I hate Unity’s take on Random). Both solutions are lightning fast, and PCG can even overtake Unity’s Random and System.Random in some optimized scenarios.

1 Like

just

int randomValue = Random.Range(1, 101);

?

EDIT: sorry, forgot that the max value is exclusive, corrected to …Range(1, 101)

For some reason, the random.value, is only coming up as numbers less than 1, and since I’m rounding so, it’

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Characteristics : MonoBehaviour
{
    public int seed;
    public float Honesty;

    // Start is called before the first frame update
    void Start()
    {
        Random.InitState(seed);
        Random.Range(1, 100);
        Honesty = Mathf.Round(Random.value);
    }

    // Update is called once per frame
    void Update()
    {
       
    }
}

s just coming up with 1, and 0

Well, you’re using it wrong.
Random.Range is a function that does it for you, and you’re dismissing its result.
Random.value is something else. It returns a value that is guaranteed to be in the 0…1 range.
I recommend reading the specification in the docs.

The point of Random class is to provide convenient commonly-used methods when working with randomized sequences. The reality of all pseudo-random generators is that they produce sequences of bits (0s and 1s) without apparent patterns of repetition, especially when under stress and/or certain degree of mathematical scrutiny. However they are pseudo for a reason, but nominally because they all depend on starting seeds, thus producing sequences that are entirely predictable given the same initial conditions (if the generating algorithm is known).

Unity’s Random.Range and Random.value are two different outcomes of the same base number generation, just a simple transformation to provide you with a result that is convenient to you. The actual number generation yields a number that is just a 32-bit sausage of 0s and 1s. This means that every time you call it again, you’re basically pulling out the next 32-bit sausage from the sequence, meaning that the order and the quantity of these calls matter.

If you consider this, and expect a value that is just an unsigned integer R,
Random.value is simply (float)R / (float)max_uint, while Random.Range does the following: (int)(min + ((float)R / (float)max_uint) * (max - min)) (for the integer variant, see below though)

(where max_uint equals 2^32-1)

Honesty = Random.Range(1, 100);

Honesty needs to be int in this case.

Random.Range has two overloads, one takes floating point values, the other takes integers. Be careful because their implementation is slightly different, namely integer version maximum is EXclusive, meaning it will never be returned. In this case above, you cannot obtain 100.

In this code

Honesty = Random.Range(1f, 100f);

The result here can approach 100f ever so slightly so that it doesn’t feel as exclusive anymore. Thus the docs say the implementation is maximum-INclusive.

Honesty needs to be float in this case.

Now that you know the difference, Random.Range is just a user-scaled random interpolant.
If you know that linear interpolation is lerp(value, min, max) => min + value * (max - min) then you know that Random.Range(min, max) => lerp(Random.value, min, max). Integer variant is just a version of that, cast back into int (thus the decimal part is truncated), i.e. Random.Range(min, max) => (int)lerp(Random.value, min, max)

When you have Random.value you could’ve made it yourself, it’s only just a convenience.

1 Like

Thank you alot, it’s working now!