I am trying to generate random numbers that are used to generate a part of a world (I am working on world generation for a game). I could create these with something like [random.randint(0, 100) for n in range(1000)]
to generate 1000 random numbers from 0 to 100, but I don't know how many numbers in a list I need. What I want is to be able to say something like random.nth_randint(0, 100, 5)
which would generate the 5th random number from 0 to 100. (The same number every time as long as you use the same seed) How would I go about doing this? And if there is no way to do this, how else could I get the same behavior?

- 748
- 8
- 26
-
2It's not clear to me why you don't just do random.randint(0, 100) when needed instead of taking the 5th random generated number – abc Sep 03 '18 at 20:52
-
2Why exactly do you need to re-create the 5th random number? After you've used it to generate a part of your map, why do you need to access it *again*? – Aran-Fey Sep 03 '18 at 20:54
-
First of you'll need to create your own instance of `random.Random` and to set its seed with `.seed()`, but that probably doesn't guarantee the same generated numbers on different machines, I'm not sure. – Domino Sep 03 '18 at 21:10
-
Surely any PRNG will do for this. See for example: https://stackoverflow.com/questions/9023660/how-to-generate-a-repeatable-random-number-sequence the second answer down has a good solurtion – tim-mccurrach Sep 03 '18 at 21:11
4 Answers
Python's random module produces deterministic pseudo random values.
In simpler words, it behaves as if it generated a list of predetermined values when a seed is provided (or when default seed is taken from OS), and those values will always be the same for a given seed. Which is basically what we want here.
So to get nth random value you need to either remember its state for each generated value (probably just keeping track of the values would be less memory hungry) or you need to reset (reseed) the generator each time and produce N random numbers each time to get yours.
def randgen(a, b, n, seed=4):
# our default seed is random in itself as evidenced by https://xkcd.com/221/
random.seed(seed)
for i in range(n-1):
x = random.random()
return random.randint(a, b)

- 1,000
- 9
- 11
If I understood well your question you want every time the same n-th
number. You may create a class where you keep track of the generated numbers (if you use the same seed
).
The main idea is that, when you ask for then nth-number it will generate all the previous in order to be always the same for all the run of the program.
import random
class myRandom():
def __init__(self):
self.generated = []
#your instance of random.Random()
self.rand = random.Random(99)
def generate(self, nth):
if nth < len(self.generated) + 1:
return self.generated[nth - 1]
else:
for _ in range(len(self.generated), nth):
self.generated.append(self.rand.randint(1,100))
return self.generated[nth - 1]
r = myRandom()
print(r.generate(1))
print(r.generate(5))
print(r.generate(10))

- 11,579
- 2
- 26
- 51
Using a defaultdict
, you can have a structure that generates a new number on the first access of each key.
from collections import defaultdict
from random import randint
random_numbers = defaultdict(lambda: randint(0, 100))
random_number[5] # 42
random_number[5] # 42
random_number[0] # 63
Numbers are thus lazily generated on access.
Since you are working on a game, it is likely you will then need to preserve random_numbers
through interruptions of your program. You can use pickle
to save your data.
import pickle
random_numbers[0] # 24
# Save the current state
with open('random', 'wb') as f:
pickle.dump(dict(random_numbers), f)
# Load the last saved state
with open('random', 'rb') as f:
opened_random_numbers = defaultdict(lambda: randint(0, 100), pickle.load(f))
opened_random_numbers[0] # 24

- 21,584
- 4
- 41
- 73
-
But for different run of the program `random_number[5]` is not the same in this way – abc Sep 03 '18 at 21:42
-
Just what I wanted, any number randomly generated on the fly! Thanks! – Eb946207 Sep 03 '18 at 21:53
-
-
Numpy's new random BitGenerator interface provides a method advance(delta)
some of the BitGenerator implementations (including the default BitGenerator used). This function allows you to seed and then advance to get the n-th random number.
From the docs:
Advance the underlying RNG as-if delta draws have occurred.

- 30,789
- 47
- 185
- 328