using System;
namespace DunGen
{
public sealed class RandomStream
{
public static readonly RandomStream Global = new RandomStream();
private const int maxValue = int.MaxValue;
private const int seed = 161803398;
private int iNext;
private int iNextP;
private int[] seedArray = new int[56];
public RandomStream()
: this(Environment.TickCount)
{
}
public RandomStream(int Seed)
{
int ii;
int mj, mk;
int subtraction = (Seed == int.MinValue) ? int.MaxValue : Math.Abs(Seed);
mj = seed - subtraction;
seedArray[55] = mj;
mk = 1;
for (int i = 1; i < 55; i++)
{
ii = (21 * i) % 55;
seedArray[ii] = mk;
mk = mj - mk;
if (mk < 0)
mk += maxValue;
mj = seedArray[ii];
}
for (int k = 1; k < 5; k++)
{
for (int i = 1; i < 56; i++)
{
seedArray[i] -= seedArray[1 + (i + 30) % 55];
if (seedArray[i] < 0)
seedArray[i] += maxValue;
}
}
iNext = 0;
iNextP = 21;
Seed = 1;
}
private double Sample()
{
return (InternalSample() * (1.0 / maxValue));
}
private int InternalSample()
{
int retVal;
int locINext = iNext;
int locINextp = iNextP;
if (++locINext >= 56)
locINext = 1;
if (++locINextp >= 56)
locINextp = 1;
retVal = seedArray[locINext] - seedArray[locINextp];
if (retVal == maxValue)
retVal--;
if (retVal < 0)
retVal += maxValue;
seedArray[locINext] = retVal;
iNext = locINext;
iNextP = locINextp;
return retVal;
}
///
/// Returns a random integer between 0 (inclusive) and int.MaxValue (exclusive)
///
/// A random integer between 0 (inclusive) and int.MaxValue (exclusive)
public int Next()
{
return InternalSample();
}
private double GetSampleForLargeRange()
{
int result = InternalSample();
bool negative = (InternalSample() % 2 == 0) ? true : false;
if (negative)
result = -result;
double d = result;
d += (int.MaxValue - 1);
d /= 2 * (uint)int.MaxValue - 1;
return d;
}
///
/// Returns a random integer between minValue (inclusive) and maxValue (exclusive)
///
/// Inclusive min value
/// Exclusive max value
/// A random integer between minValue (inclusive) and maxValue (exclusive)
/// minValue must be greater than maxValue
public int Next(int minValue, int maxValue)
{
if (minValue > maxValue)
throw new ArgumentOutOfRangeException("minValue");
long range = (long)maxValue - minValue;
if (range <= (long)Int32.MaxValue)
return ((int)(Sample() * range) + minValue);
else
return (int)((long)(GetSampleForLargeRange() * range) + minValue);
}
///
/// Returns a non-negative random integer that is less than the specified maximum.
///
/// Exclusive maximum
/// Random integer between 0 and maxValue (exclusive)
/// Max value < 0
public int Next(int maxValue)
{
if (maxValue < 0)
throw new ArgumentOutOfRangeException("maxValue");
return (int)(Sample() * maxValue);
}
///
/// Returns a random double between 0.0 (inclusive) and 1.0 (exclusive)
///
/// A random double between 0.0 (inclusive) and 1.0 (exclusive)
public double NextDouble()
{
return Sample();
}
///
/// Fills an array with random bytes between 0 and 255 (inclusive)
///
/// The array to fill
/// `buffer` must not be null
public void NextBytes(byte[] buffer)
{
if (buffer == null)
throw new ArgumentNullException("buffer");
for (int i = 0; i < buffer.Length; i++)
buffer[i] = (byte)(InternalSample() % (byte.MaxValue + 1));
}
}
}