Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save unitycoder/3e9af89c8460617d91e8caa234ac1120 to your computer and use it in GitHub Desktop.

Select an option

Save unitycoder/3e9af89c8460617d91e8caa234ac1120 to your computer and use it in GitHub Desktop.

Revisions

  1. @cs-altshift cs-altshift revised this gist May 6, 2022. 1 changed file with 161 additions and 0 deletions.
    161 changes: 161 additions & 0 deletions SeededRandomizer.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,161 @@
    using System.Collections.Generic;

    namespace AltShift.Maths.Randomization
    {
    public struct SeededRandomizer
    {
    public const string DEFAULT_CONSTRUCTOR_ERROR_STR = "SeededRandomizer created with the default constructor are not valid randomizer";

    public readonly bool isValid;

    private SeededRandomNumberGenerator random;
    public int Seed => random.seed;
    public int GenerationCount => random.GenerationCount;

    public double DoubleValue {
    get {
    if (!isValid) {
    throw new InvalidOperationException(DEFAULT_CONSTRUCTOR_ERROR_STR);
    }
    return random.NextDouble();
    }
    }

    /// <summary>
    /// Valeur dans l'interval [0; 1[
    /// </summary>
    public float Value {
    get {
    if (!isValid) {
    throw new InvalidOperationException(DEFAULT_CONSTRUCTOR_ERROR_STR);
    }
    return random.NextFloat();
    }
    }

    public int IntValue {
    get {
    if (!isValid) {
    throw new InvalidOperationException(DEFAULT_CONSTRUCTOR_ERROR_STR);
    }
    return random.NextInt();
    }
    }

    public bool BoolValue {
    get {
    if (!isValid) {
    throw new InvalidOperationException(DEFAULT_CONSTRUCTOR_ERROR_STR);
    }
    return (random.NextDouble() > 0.5);
    }
    }

    public static SeededRandomizer Create() {
    return new SeededRandomizer(-1);
    }

    public SeededRandomizer(SeededRandomizer _original) : this(_original.Seed, _original.GenerationCount) { }

    public SeededRandomizer(int _seed, int _generationCount = 0) {
    isValid = true;
    random = new SeededRandomNumberGenerator(_seed);
    FastForward(_generationCount);
    }

    public int Range(int _includedMin, int _excludedMax) {
    if (!isValid) {
    throw new InvalidOperationException(DEFAULT_CONSTRUCTOR_ERROR_STR);
    }
    return random.Range(_includedMin, _excludedMax);
    }

    public float Range(float _includedMin, float _excludedMax) {
    if (!isValid) {
    throw new InvalidOperationException(DEFAULT_CONSTRUCTOR_ERROR_STR);
    }
    return random.Range(_includedMin, _excludedMax);
    }

    /// <summary>
    /// Return true if random is lower than _normalizedPercent
    /// </summary>
    public bool TestPercent(float _normalizedPercent) {
    return Value < _normalizedPercent;
    }

    public T PickFrom<T>(IEnumerable<T> _enumerable) {
    int count = 0;
    foreach (T t in _enumerable) {
    count++;
    }

    if (count == 0) {
    throw new ArgumentException("Given enumerable should not be empty", nameof(_enumerable));
    }

    int randomIndex = random.Range(0, count);
    foreach (T t in _enumerable) {
    if (randomIndex <= 0) {
    return t;
    }
    randomIndex--;
    }

    return default(T);
    }

    public T PickFrom<T>(List<T> _list) {
    int randomIndex = random.Range(0, _list.Count);
    return _list[randomIndex];
    }

    public void Reset(int _count = 0) {
    if (!isValid) {
    throw new InvalidOperationException(DEFAULT_CONSTRUCTOR_ERROR_STR);
    }
    random = new SeededRandomNumberGenerator(Seed);
    FastForward(_count);
    }

    public void FastForward(int _count = 1) {
    if (!isValid) {
    throw new InvalidOperationException(DEFAULT_CONSTRUCTOR_ERROR_STR);
    }
    for (int i = 0; i < _count; i++) {
    random.NextInt();
    }
    }

    /// <summary>
    /// Create another randomizer with a seed generated from this randomizer.
    /// </summary>
    /// <param name="_generationCount">when != -1, the SeededRandomizer must have _generationCount generations or the game will assert</param>
    /// <returns>A SeededRandomizer with next generated int of current SeededRandomizer as its seed</returns>
    public SeededRandomizer CreateChild(int _generationCount = -1) {
    bool shouldCheckGenerationCount = (_generationCount >= 0);
    if (shouldCheckGenerationCount) {
    if (GenerationCount != _generationCount) {
    throw new ArgumentException(string.Format("SeededRandomizer Child must be the {0}th but it was the {1}th", _generationCount, GenerationCount));
    }
    }

    int childSeed = random.NextInt();
    return new SeededRandomizer(childSeed);
    }

    public override string ToString() {
    return string.Format("{0}({1})", Seed, GenerationCount);
    }

    public void Shuffle<T>(IList<T> list) {
    int n = list.Count;
    for (int i = 0; i < n; i++) {
    int r = i + random.Range(0, n - i);
    T t = list[r];
    list[r] = list[i];
    list[i] = t;
    }
    }
    }
    }
  2. @cs-altshift cs-altshift created this gist May 6, 2022.
    243 changes: 243 additions & 0 deletions SeededRandomNumberGenerator.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,243 @@
    using System;

    namespace AltShift.Maths.Randomization
    {
    // No-alloc version coded from Random source code
    // https://referencesource.microsoft.com/#mscorlib/system/random.cs
    public unsafe struct SeededRandomNumberGenerator
    {
    private const int MSEED = 161803398;
    private const int MZ = 0;

    public readonly int seed;

    public int GenerationCount { get; private set; }

    // Generation variables
    private int inext;
    private int inextp;

    private int cell00;
    private int cell01;
    private int cell02;
    private int cell03;
    private int cell04;
    private int cell05;
    private int cell06;
    private int cell07;
    private int cell08;
    private int cell09;
    private int cell10;
    private int cell11;
    private int cell12;
    private int cell13;
    private int cell14;
    private int cell15;
    private int cell16;
    private int cell17;
    private int cell18;
    private int cell19;
    private int cell20;
    private int cell21;
    private int cell22;
    private int cell23;
    private int cell24;
    private int cell25;
    private int cell26;
    private int cell27;
    private int cell28;
    private int cell29;
    private int cell30;
    private int cell31;
    private int cell32;
    private int cell33;
    private int cell34;
    private int cell35;
    private int cell36;
    private int cell37;
    private int cell38;
    private int cell39;
    private int cell40;
    private int cell41;
    private int cell42;
    private int cell43;
    private int cell44;
    private int cell45;
    private int cell46;
    private int cell47;
    private int cell48;
    private int cell49;
    private int cell50;
    private int cell51;
    private int cell52;
    private int cell53;
    private int cell54;
    private int cell55;

    public SeededRandomNumberGenerator(int _seed) {
    cell00 = 0;
    cell01 = 0;
    cell02 = 0;
    cell03 = 0;
    cell04 = 0;
    cell05 = 0;
    cell06 = 0;
    cell07 = 0;
    cell08 = 0;
    cell09 = 0;
    cell10 = 0;
    cell11 = 0;
    cell12 = 0;
    cell13 = 0;
    cell14 = 0;
    cell15 = 0;
    cell16 = 0;
    cell17 = 0;
    cell18 = 0;
    cell19 = 0;
    cell20 = 0;
    cell21 = 0;
    cell22 = 0;
    cell23 = 0;
    cell24 = 0;
    cell25 = 0;
    cell26 = 0;
    cell27 = 0;
    cell28 = 0;
    cell29 = 0;
    cell30 = 0;
    cell31 = 0;
    cell32 = 0;
    cell33 = 0;
    cell34 = 0;
    cell35 = 0;
    cell36 = 0;
    cell37 = 0;
    cell38 = 0;
    cell39 = 0;
    cell40 = 0;
    cell41 = 0;
    cell42 = 0;
    cell43 = 0;
    cell44 = 0;
    cell45 = 0;
    cell46 = 0;
    cell47 = 0;
    cell48 = 0;
    cell49 = 0;
    cell50 = 0;
    cell51 = 0;
    cell52 = 0;
    cell53 = 0;
    cell54 = 0;
    cell55 = 0;

    seed = (_seed == -1) ? Environment.TickCount : _seed;
    GenerationCount = 0;

    // Initializing generation properties
    int subtraction = (seed == int.MinValue) ? int.MaxValue : Math.Abs(seed);
    int mj = MSEED - subtraction;
    int mk = 1;
    fixed (int* seedArray = &cell00) {
    seedArray[55] = mj;
    for (int i = 1; i < 55; i++) {
    int ii = (21 * i) % 55;
    seedArray[ii] = mk;
    mk = mj - mk;
    if (mk < 0) {
    mk += int.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] += int.MaxValue;
    }
    }
    }
    }

    inext = 0;
    inextp = 21;
    }

    public float NextFloat() {
    return (float) NextDouble();
    }

    public double NextDouble() {
    return (NextInt() * (1.0 / int.MaxValue));
    }

    public double NextDoubleForLargeRange() {
    int result = NextInt();
    bool negative = (NextInt(_increaseGenerationCount: false) % 2 == 0);
    if (negative) {
    result = -result;
    }

    double d = result;
    d += (int.MaxValue - 1);
    d /= 2 * (uint) int.MaxValue - 1;
    return d;
    }

    public int NextInt() {
    return NextInt(_increaseGenerationCount: true);
    }

    private int NextInt(bool _increaseGenerationCount) {
    if (_increaseGenerationCount) {
    GenerationCount++;
    }

    int locINext = inext + 1;
    if (locINext >= 56) {
    locINext = 1;
    }

    int locINextp = inextp + 1;
    if (locINextp >= 56) {
    locINextp = 1;
    }

    fixed (int* seedArray = &cell00) {
    int retVal = seedArray[locINext] - seedArray[locINextp];
    if (retVal == int.MaxValue) {
    retVal--;
    }
    else if (retVal < 0) {
    retVal += int.MaxValue;
    }

    seedArray[locINext] = retVal;

    inext = locINext;
    inextp = locINextp;

    return retVal;
    }
    }

    public int Range(int _includedMin, int _excludedMax) {
    if (_excludedMax < _includedMin) {
    throw new ArgumentException("Maximum value must be greater or equal to minimum value");
    }

    long range = (long) _excludedMax - _includedMin;
    if (range <= (long) int.MaxValue) {
    return ((int) (NextDouble() * range) + _includedMin);
    }
    else {
    return (int) ((long) (NextDoubleForLargeRange() * range) + _includedMin);
    }
    }

    public float Range(float _includedMin, float _excludedMax) {
    return _includedMin + NextFloat() * (_excludedMax - _includedMin);
    }
    }
    }