1

I have a game implemented in Unity/C# that generates simple environments using the built-in PRNG (UnityEngine.Random). I am trying to reimplement the environment generation procedure in Python 3. I need the random number generators to be synchronized so that when provided with the same seed, the actual game in Unity and the Python reimplementation generate the exact same environment. What would be the best approach to synchronizing the two platforms?

Some solutions I have considered so far:

  • Attempt to reimplement Python's default random number generator (random) in C#. The source code is available, but fairly long so may difficult to implement in practice.
  • Attempt to reimplement UnityEngine.Random in Python. However, I don't have any source code, and even if I knew the class of PRNG used, there is no guarantee that I will be able to successfully reimplement it exactly the same.
  • Implement the same PRNG in both. However, I don't know what a good option for a PRNG is for my use case. I basically need something that looks random (though it doesn't have to be secure) and doesn't take more than an hour or two to put together. Wikipedia has a long list of PRNGs, and I have no idea the difficulty in implementing each of them.
  • Or maybe someone else has done this at some point...? I couldn't find anything online, though.

Any suggestions on the best approach, or a simple PRNG I can implement easily in both C# and Python?

Thanks!

alsuhr
  • 129
  • 2
  • 11
  • 1
    Why do you need to reimplement it in the first place? And why does the generation have to happen at runtime? Though if you really need to do it you should split out the code for generation to be independent enough to be able to include it in both projects (e.g.: as a dynamically linked library) – UnholySheep Jan 20 '20 at 18:58
  • I am doing reinforcement learning in the game and need to generate a large number of environments extremely quickly. I don't need to render them, so the overhead of using a compiled version of the game is unnecessary and slows down the process. But I do need them to be consistent across platforms so I can render them for debugging purposes. I didn't think about generating a huge list of sequences of random numbers to start with, but that may be relatively simple. Figuring out how to create a DLL may be too time-consuming. – alsuhr Jan 20 '20 at 19:06
  • 1
    You can run Python's `random` inside C# via [IronPython](https://ironpython.net). It should work if you don't care about speed or elegance. – Sweeper Jan 20 '20 at 19:06
  • FWIW, a friend just suggested the mulberry32 PRNG. I think I will try implementing it first (seems to be relatively simple to implement). Thanks! – alsuhr Jan 20 '20 at 19:07
  • @Sweeper, cool, I will check it out! – alsuhr Jan 20 '20 at 19:07

1 Answers1

2

In general, the best way to "sync" PRNGs between two programs in different languages is to implement the same PRNG in both languages.

For your purposes, a linear congruential generator (LCG) is a simple PRNG if you only want "something that looks random (though it doesn't have to be secure)". This kind of generator is trivial to implement in both C# and Python.

One example, among many other possibilities, is the following 32-bit LCG (where x is the seed):

C#:

// Generate the next x from the current one.
unchecked {
    // NOTE: x is an `int`
    x = ((int)0xadb4a92d * x) + 9999999;
}

Python:

# Generate the next x from the current one.
x = ((0xadb4a92d * x) + 9999999) & 0xFFFFFFFF

See section 8 of the very very recent paper by Steele and Vigna for other parameter choices as well as a review of the theory involving LCGs.

However, LCGs are far from perfect. (For instance, the above LCG produces x's with weak low bits, so that, e.g., every other x is odd and every other x is even.) And in general, LCGs, especially those with 32-bit seeds or other short seeds, are far from appropriate for many situations, including scientific work or information security. In case you want another choice for a PRNG, I list many of them.

Peter O.
  • 32,158
  • 14
  • 82
  • 96