I am scripting my Unity code in c# and using System.Random() with a seed to generate predictable letters for my game. I am doing the same thing on a server written in c# using .NET and was expecting the numbers to match up.
However I am getting two separate predictable results for example Unity outputs:
94 92 67
with code:
System.Random rnd = new System.Random( 8675309 );
Debug.Log( rnd.Next( 100 ) );
Debug.Log( rnd.Next( 100 ) );
Debug.Log( rnd.Next( 100 ) );
The c# server outputs:
75 99 57
with code:
System.Random rnd = new System.Random( 8675309 );
Console.WriteLine( rnd.Next( 100 ) );
Console.WriteLine( rnd.Next( 100 ) );
Console.WriteLine( rnd.Next( 100 ) );
I downloaded MonoDevelop 3.0.6 to run the server and obtained the same random numbers. I also tried running the server in dot net 3.5 and 4.0 with the same results.
I was under the impression that Unity was running under Mono and I should obtain my expected results.
Does anybody know whats going on? I am using Linq in my Unity code so I know the dot.net api has to be version 3.5 or higher.
MonoDevelop is a code editor, not something that Unity runs under; presumably you’re talking about Mono. System.Random results with a seed are not even 100% guaranteed between versions in .NET, never mind between .NET and Mono. To get 100% predictable results across platforms you will need to write your own pseudo-random generator.
The simplest pseudo random generator i know is the one that comes with borland pascal. It works pretty well. I’ve never tried the implementation in C#, but it in general it should work.
Here’s a quick adaption of the generator:
// C#
public class MyRandom
{
private int m_Value = 0;
public MyRandom(){}
public MyRandom(int aSeed)
{
m_Value = aSeed;
}
private int Next()
{
m_Value = m_Value * 0x08088405 + 1;
return m_Value;
}
public int Range(int aMin, int aMax)
{
return aMin + Next() % (aMax-aMin);
}
}
Haven’t tried this implementation but it should work (unless C# complains about integer overflow ;)).
ps: it’s of course just a 32 bit random generator, but if i don’t used the wrong multiplier it shouldn’t repeat within the 32 bit limit. So it reapeats exactly after 0xFFFFFFFF times.
It just System.Random
namespace Game.Maze
{
public class SystemRandomAdaptor : IRandom
{
private readonly int[] SeedArray = new int[56];
private int inext;
private int inextp;
public SystemRandomAdaptor(int seed)
{
int num1 = 161803398 - System.Math.Abs(seed);
SeedArray[55] = num1;
int num2 = 1;
for (int index1 = 1; index1 < 55; ++index1)
{
int index2 = 21 * index1 % 55;
SeedArray[index2] = num2;
num2 = num1 - num2;
if (num2 < 0)
num2 += int.MaxValue;
num1 = SeedArray[index2];
}
for (int index1 = 1; index1 < 5; ++index1)
{
for (int index2 = 1; index2 < 56; ++index2)
{
SeedArray[index2] -= SeedArray[1 + (index2 + 30) % 55];
if (SeedArray[index2] < 0)
SeedArray[index2] += int.MaxValue;
}
}
inext = 0;
inextp = 21;
}
protected virtual double Sample()
{
return InternalSample() * 4.6566128752458E-10;
}
private int InternalSample()
{
int num1 = inext;
int num2 = inextp;
int index1;
if ((index1 = num1 + 1) >= 56)
index1 = 1;
int index2;
if ((index2 = num2 + 1) >= 56)
index2 = 1;
int num3 = SeedArray[index1] - SeedArray[index2];
if (num3 < 0)
num3 += int.MaxValue;
SeedArray[index1] = num3;
inext = index1;
inextp = index2;
return num3;
}
private double GetSampleForLargeRange()
{
int num = InternalSample();
if (InternalSample() % 2 == 0)
num = -num;
return (num + 2147483646.0) / 4294967293.0;
}
public SystemRandomAdaptor(long seed) : this((int)seed) { }
public int Random(int min, int max)
{
max += 1;
long num = max - (long)min;
if (num <= int.MaxValue)
return (int)(Sample() * num) + min;
return (int)((long)(GetSampleForLargeRange() * num) + min);
}
}
}
,It just using System.Random code
namespace Game.Maze
{
public class SystemRandomAdaptor : IRandom
{
private readonly int[] SeedArray = new int[56];
private int inext;
private int inextp;
public SystemRandomAdaptor(int seed)
{
int num1 = 161803398 - System.Math.Abs(seed);
SeedArray[55] = num1;
int num2 = 1;
for (int index1 = 1; index1 < 55; ++index1)
{
int index2 = 21 * index1 % 55;
SeedArray[index2] = num2;
num2 = num1 - num2;
if (num2 < 0)
num2 += int.MaxValue;
num1 = SeedArray[index2];
}
for (int index1 = 1; index1 < 5; ++index1)
{
for (int index2 = 1; index2 < 56; ++index2)
{
SeedArray[index2] -= SeedArray[1 + (index2 + 30) % 55];
if (SeedArray[index2] < 0)
SeedArray[index2] += int.MaxValue;
}
}
inext = 0;
inextp = 21;
}
protected virtual double Sample()
{
return InternalSample() * 4.6566128752458E-10;
}
private int InternalSample()
{
int num1 = inext;
int num2 = inextp;
int index1;
if ((index1 = num1 + 1) >= 56)
index1 = 1;
int index2;
if ((index2 = num2 + 1) >= 56)
index2 = 1;
int num3 = SeedArray[index1] - SeedArray[index2];
if (num3 < 0)
num3 += int.MaxValue;
SeedArray[index1] = num3;
inext = index1;
inextp = index2;
return num3;
}
private double GetSampleForLargeRange()
{
int num = InternalSample();
if (InternalSample() % 2 == 0)
num = -num;
return (num + 2147483646.0) / 4294967293.0;
}
public SystemRandomAdaptor(long seed) : this((int)seed) { }
public int Random(int min, int max)
{
max += 1;
long num = max - (long)min;
if (num <= int.MaxValue)
return (int)(Sample() * num) + min;
return (int)((long)(GetSampleForLargeRange() * num) + min);
}
}
}