using System;
using System.Collections.Generic;
using GrimoireEngine.Framework.Logic;
using GrimoireEngine.Framework.Maths;
using OpenTK;
namespace GrimoireEngine.Framework.Utilities
{
public sealed class GrimoireRandom
{
private int _seed;
private int _inext;
private int _inextp;
private int[] _seedArray = new int[56];
///
/// The current seed of this instance.
///
public int Seed
{
get
{
return _seed;
}
set
{
_seed = value;
int subtraction = (_seed == Int32.MinValue) ? Int32.MaxValue : Math.Abs(_seed);
int mj = 0x9a4ec86 - subtraction;
_seedArray[0x37] = mj;
int mk = 1;
for (int i = 1; i < 0x37; i++)
{
int ii = (0x15 * i) % 0x37;
_seedArray[ii] = mk;
mk = mj - mk;
if (mk < 0x0)
{
mk += Int32.MaxValue;
}
mj = _seedArray[ii];
}
for (int k = 1; k < 0x5; k++)
{
for (int i = 1; i < 0x38; i++)
{
_seedArray[i] -= _seedArray[1 + (i + 0x1e) % 0x37];
if (_seedArray[i] < 0)
{
_seedArray[i] += Int32.MaxValue;
}
}
}
_inext = 0;
_inextp = 21;
}
}
public GrimoireRandom()
// Used to generate a varying seed, regardless of close-frequency allocation
: this(Guid.NewGuid().GetHashCode())
{ }
public GrimoireRandom(string seed)
: this(seed.GetHashCode())
{ }
public GrimoireRandom(int[] saveState)
{
LoadState(saveState);
}
public GrimoireRandom(int seed)
{
Seed = seed;
}
///
/// Resets this instance using it's current seed.
/// This means that the RNG will start over again,
/// repeating the same values that it originally had.
///
public void Reset()
{
Reseed(this.Seed);
}
///
/// Reseeds this instance using a new GUID Hashcode
///
public void Reseed()
{
Reseed(Guid.NewGuid().GetHashCode());
}
///
/// Reseeds this instance using the hashcode of a given string.
///
///
public void Reseed(string seed)
{
Reseed(seed.GetHashCode());
}
///
/// Reseeds this instance using a given integer seed.
///
///
public void Reseed(int seed)
{
this.Seed = seed;
}
public int NextInteger()
{
return NextSample();
}
public void NextIntegers(int[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextInteger();
}
}
public int[] NextIntegers(int quantity)
{
int[] buffer = new int[quantity];
NextIntegers(buffer);
return buffer;
}
public int NextInteger(int minValue, int maxValue)
{
return (int)(this.NextSample() * (1.0D / Int32.MaxValue) * (maxValue - minValue)) + minValue;
}
public void NextIntegers(int minValue, int maxValue, int[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextInteger(minValue, maxValue);
}
}
public int[] NextIntegers(int minValue, int maxValue, int quantity)
{
int[] buffer = new int[quantity];
NextIntegers(minValue, maxValue, buffer);
return buffer;
}
public int NextInteger(int maxValue)
{
return NextInteger(0, maxValue);
}
public void NextIntegers(int maxValue, int[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextInteger(maxValue);
}
}
public int[] NextIntegers(int maxValue, int quantity)
{
int[] buffer = new int[quantity];
NextIntegers(maxValue, buffer);
return buffer;
}
public double NextDouble()
{
return NextSample() * (1.0D / Int32.MaxValue);
}
public void NextDoubles(double[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextDouble();
}
}
public double[] NextDoubles(int quantity)
{
double[] buffer = new double[quantity];
NextDoubles(buffer);
return buffer;
}
public double NextDouble(double minValue, double maxValue)
{
return NextDouble() * (maxValue - minValue) + minValue;
}
public void NextDoubles(double minValue, double maxValue, double[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextDouble(minValue, maxValue);
}
}
public double[] NextDoubles(double minValue, double maxValue, int quantity)
{
double[] buffer = new double[quantity];
NextDoubles(minValue, maxValue, buffer);
return buffer;
}
public float NextFloat()
{
return (float)(NextSample() * (1.0D / Int32.MaxValue));
}
public void NextFloats(float[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextFloat();
}
}
public float[] NextFloats(int quantity)
{
float[] buffer = new float[quantity];
NextFloats(buffer);
return buffer;
}
public float NextFloat(float minValue, float maxValue)
{
return NextFloat() * (maxValue - minValue) + minValue;
}
public void NextFloats(float minValue, float maxValue, float[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextFloat(minValue, maxValue);
}
}
public float[] NextFloats(float minValue, float maxValue, int quantity)
{
float[] buffer = new float[quantity];
NextFloats(minValue, maxValue, buffer);
return buffer;
}
public int NextRange(Range range)
{
return NextInteger(range.Minimum, range.Maximum + 1);
}
public void NextRanges(Range range, int[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextRange(range);
}
}
public int[] NextRanges(Range range, int quantity)
{
int[] buffer = new int[quantity];
NextRanges(range, buffer);
return buffer;
}
public int NextRange(int minValue, int maxValue)
{
return NextInteger(minValue, maxValue + 1);
}
public void NextRanges(int minValue, int maxValue, int[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextRange(minValue, maxValue);
}
}
public int[] NextRanges(int minValue, int maxValue, int quantity)
{
int[] buffer = new int[quantity];
NextRanges(minValue, maxValue, buffer);
return buffer;
}
public byte NextByte()
{
return (byte)NextInteger(0, 256);
}
public void NextBytes(byte[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextByte();
}
}
public byte[] NextBytes(int quantity)
{
byte[] buffer = new byte[quantity];
NextBytes(buffer);
return buffer;
}
public byte NextByte(byte minValue, byte maxValue)
{
return (byte)NextInteger(minValue, maxValue);
}
public void NextBytes(byte minValue, byte maxValue, byte[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextByte(minValue, maxValue);
}
}
public byte[] NextBytes(byte minValue, byte maxValue, int quantity)
{
byte[] buffer = new byte[quantity];
NextBytes(minValue, maxValue, buffer);
return buffer;
}
public byte NextByte(byte maxValue)
{
return (byte)NextInteger(0, maxValue);
}
public void NextBytes(byte maxValue, byte[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextByte(maxValue);
}
}
public byte[] NextBytes(byte maxValue, int quantity)
{
byte[] buffer = new byte[quantity];
NextBytes(maxValue, buffer);
return buffer;
}
public bool NextBool()
{
return NextInteger(0, 2) == 1;
}
public void NextBools(bool[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextBool();
}
}
public bool[] NextBools(int quantity)
{
bool[] buffer = new bool[quantity];
NextBools(buffer);
return buffer;
}
public string NextString(char[] possibleCharacters, int length)
{
char[] buffer = new char[length];
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = possibleCharacters[NextInteger(0, possibleCharacters.Length)];
}
return new string(buffer);
}
public void NextStrings(char[] possibleCharacters, int length, string[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextString(possibleCharacters, length);
}
}
public string[] NextStrings(char[] possibleCharacters, int length, int quantity)
{
string[] buffer = new string[quantity];
NextStrings(possibleCharacters, length, buffer);
return buffer;
}
public void Shuffle(List list)
{
int n = list.Count;
while (n > 1)
{
n--;
int k = NextInteger(0, n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
public void Shuffle(T[] list)
{
int n = list.Length;
while (n > 1)
{
n--;
int k = NextInteger(0, n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
public int NextIndex(T[] array)
{
return NextInteger(array.Length);
}
public int NextIndex(List list)
{
return NextInteger(list.Count);
}
public T Choose(T[] items)
{
return items[NextInteger(items.Length)];
}
public void Choose(T[] items, T[] resultBuffer)
{
for (int i = 0; i < resultBuffer.Length; i++)
{
resultBuffer[i] = Choose(items);
}
}
public T[] Choose(T[] items, int quantity)
{
T[] buffer = new T[quantity];
Choose(items, buffer);
return buffer;
}
public T Choose(List items)
{
return items[NextInteger(0, items.Count)];
}
public List Choose(List items, int quantity)
{
List buffer = new List(quantity);
for (int i = 0; i < quantity; i++)
{
buffer.Add(Choose(items));
}
return buffer;
}
public bool NextProbability(float percent)
{
if (percent >= 1.0f) return true;
if (percent <= 0.0f) return false;
return NextDouble() <= percent;
}
public void NextProbability(float percent, bool[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextProbability(percent);
}
}
public bool[] NextProbabilities(float percent, int quantity)
{
bool[] buffer = new bool[quantity];
NextProbability(percent, buffer);
return buffer;
}
public bool NextProbability(int percent)
{
if (percent >= 100) return true;
if (percent <= 0) return false;
return NextInteger(101) <= percent;
}
public void NextProbabilities(int percent, bool[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextProbability(percent);
}
}
public bool[] NextProbabilities(int percent, int quantity)
{
bool[] buffer = new bool[quantity];
NextProbabilities(percent, buffer);
return buffer;
}
public bool NextOdds(int a, int b)
{
return NextProbability(((float)a / b));
}
public void NextOdds(int a, int b, bool[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextOdds(a, b);
}
}
public bool[] NextOdds(int a, int b, int quantity)
{
bool[] buffer = new bool[quantity];
NextOdds(a, b, buffer);
return buffer;
}
public int NextDiceRoll(DiceType d)
{
return NextInteger(1, (int)d + 1);
}
public void NextDiceRolls(DiceType d, int[] buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = NextDiceRoll(d);
}
}
public int[] NextDiceRolls(DiceType d, int quantity)
{
int[] buffer = new int[quantity];
NextDiceRolls(d, buffer);
return buffer;
}
public Vector3 NextVector3(float xMin, float xMax, float yMin, float yMax, float zMin, float zMax)
{
return new Vector3(NextFloat(xMin, xMax), NextFloat(yMin, yMax), NextFloat(zMin, zMax));
}
public Vector3 NextVector3(Vector3 min, Vector3 max)
{
return NextVector3(min.X, max.X, min.Y, max.Y, min.Z, max.Z);
}
public Vector3 NextVector3(float min, float max)
{
return NextVector3(min, max, min, max, min, max);
}
private int NextSample()
{
int locINext = _inext;
int locINextp = _inextp;
if (++locINext >= 56)
{
locINext = 1;
}
if (++locINextp >= 56)
{
locINextp = 1;
}
int retVal = _seedArray[locINext] - _seedArray[locINextp];
if (retVal == Int32.MaxValue)
{
retVal--;
}
if (retVal < 0)
{
retVal += Int32.MaxValue;
}
_seedArray[locINext] = retVal;
_inext = locINext;
_inextp = locINextp;
return retVal;
}
public int[] GetState()
{
int[] state = new int[59];
state[0] = _seed;
state[1] = _inext;
state[2] = _inextp;
for (int i = 3; i < this._seedArray.Length; i++)
{
state[i] = _seedArray[i - 3];
}
return state;
}
public void LoadState(int[] saveState)
{
if (saveState.Length != 59)
{
throw new Exception("GrimoireRandom state was corrupted!");
}
_seed = saveState[0];
_inext = saveState[1];
_inextp = saveState[2];
_seedArray = new int[59];
for (int i = 3; i < this._seedArray.Length; i++)
{
_seedArray[i - 3] = saveState[i];
}
}
}
}