Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
RNG.cs 10.05 KiB
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public static class RNG
{
    private static System.Random RNGNum = new System.Random();

    /// <summary>
    /// Returns true based on percent chance given.
    /// </summary>
    /// <param name="percentChance">A float [0 - 1]</param>
    /// <returns>True based on percent chance given.</returns>
    public static bool PercentChance(float percentChance)
    {
        return GetRandomFloat() < percentChance;
    }

    /// <summary>
    /// Returns an integer ranging from 0 - 99.
    /// </summary>
    /// <returns>An integer ranging from 0 - 99.</returns>
    public static float GetRandomPercent()
    {
        return GetRandomInteger(100);
    }

    /// <summary>
    /// Returns an integer ranging from minValue, inclusive, to maxValue, exclusive.
    /// </summary>
    /// <returns>An integer ranging from minValue to maxValue - 1.</returns>
    public static int GetRandomInteger(int minVal, int maxVal)
    {
        return RNGNum.Next(maxVal - minVal) + minVal;
    }

    /// <summary>
    /// Returns an integer ranging from 0, inclusive, to maxValue, exclusive.
    /// </summary>
    /// <returns>An integer ranging from 0 to maxValue - 1.</returns>
    public static int GetRandomInteger(int maxVal)
    {
        return GetRandomInteger(0, maxVal);
    }

    /// <summary>
    /// Returns a double ranging from minValue, inclusive, to maxValue, exclusive.
    /// </summary>
    /// <returns>An integer ranging from minValue to maxValue - 1.</returns>
    public static double GetRandomDouble(double minVal, double maxVal)
    {
        return RNGNum.NextDouble() * (maxVal - minVal) + minVal;
    }

    /// <summary>
    /// Returns a double ranging from 0, inclusive, to maxValue, exclusive.
    /// </summary>
    /// <returns>A double ranging from 0, inclusive, to maxValue, exclusive.</returns>
    public static double GetRandomDouble(double maxVal)
    {
        return GetRandomDouble(0, maxVal);
    }

    /// <summary>
    /// Returns a double ranging from 0, inclusive, to 1, exclusive.
    /// </summary>
    /// <returns>A double ranging from 0 to 1.</returns>
    public static double GetRandomDouble()
    {
        return RNGNum.NextDouble();
    }

    /// <summary>
    /// Returns a float ranging from minValue, inclusive, to maxValue, exclusive.
    /// </summary>
    /// <returns>A float ranging from minValue, inclusive, to maxValue, exclusive.</returns>
    public static float GetRandomFloat(float minVal, float maxVal)
    {
        return (float)(RNGNum.NextDouble() * (maxVal - minVal) + minVal);
    }

    /// <summary>
    /// Returns a float ranging from 0, inclusive, to maxValue, exclusive.
    /// </summary>
    /// <returns>A float ranging from minValue, inclusive, to maxValue, exclusive.</returns>
    public static float GetRandomFloat(float maxVal)
    {
        return GetRandomFloat(0, maxVal);
    }

    /// <summary>
    /// Returns a float ranging from the smallest value of the Vector2 (inclusive)
    /// to the largest value (exclusive) 
    /// </summary>
    public static float GetRandomFloat(Vector2 val)
    {
        return GetRandomFloat(Mathf.Min(val.x, val.y), Mathf.Max(val.x, val.y));
    }

    /// <summary>
    /// Returns a Vector2 with both components ranging from -val to val
    /// </summary>
    /// <param name="val"></param>
    /// <returns></returns>
    public static Vector2 GetRandomVector2(float val)
    {
        return GetRandomVector2(-val, val);
    }

    /// <summary>
    /// Returns a Vector2 with both components ranging from minVal to maxVal
    /// </summary>
    /// <param name="val"></param>
    /// <returns></returns>
    public static Vector2 GetRandomVector2(float minVal, float maxVal)
    {
        return GetRandomVector2(minVal, minVal, maxVal, maxVal);
    }

    ///// <summary>
    ///// Returns a random Vector2 ranging from +bound to -bound
    ///// </summary>
    ///// <param name="bound"></param>
    ///// <returns></returns>
    //public static Vector2 GetRandomVector2(Vector2 bound)
    //{
    //    return GetRandomVector2(bound.x, bound.y);
    //}

    /// <summary>
    /// Returns a random Vector2 ranging from min to max
    /// </summary>
    /// <param name="min"></param>
    /// <param name="max"></param>
    /// <returns></returns>
    public static Vector2 GetRandomVector2(Vector2 min, Vector2 max)
    {
        return GetRandomVector2(min.x, min.y, max.x, max.y);
    }

    public static Vector2 GetRandomVector2(float minValX, float minValY, float maxValX, float maxValY)
    {
        return new Vector2(GetRandomFloat(minValX, maxValX), GetRandomFloat(minValY, maxValY));
    }

    /// <summary>
    /// Returns a float ranging from 0, inclusive, to 1, exclusive.
    /// </summary>
    /// <returns>A float ranging from 0 to 1.</returns>
    public static float GetRandomFloat()
    {
        return (float)RNGNum.NextDouble();
    }
    
    /// <summary>
    /// Returns a random value from the provided enumeration of values.
    /// </summary>
    /// <param name="defaultOK">If true, then return default value if values length is 0. Else throw an error.</param>
    public static T GetRandomValue<T>(this IEnumerable<T> values, bool defaultOK = true)
    {
        int length = values.Count();

        if (length < 1 && defaultOK)
        {
            return default;
        }

        return values.ElementAt(GetRandomInteger(length));
    }

    ///// <summary>
    ///// Returns a random value along with its index in the enum.
    ///// </summary>
    ///// <param name="defaultOK">If true, then return default value if values length is 0. Else throw an error.</param>
    ///// <returns>(index, value)</returns>
    //public static Tuple<int, T> GetRandomValuePair<T>(this IEnumerable<T> values, bool defaultOK = true)
    //{
    //    int length = values.Count();

    //    if (length < 1 && defaultOK)
    //    {
    //        return default;
    //    }

    //    int randI = GetRandomInteger(length);

    //    return new(randI, values.ElementAt(randI));
    //}

    /// <summary>
    /// Selects multiple items from an IEnumerable. Can also select none.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="objs"></param>
    /// <param name="key">How to get to the percentage [0-1] from any obj.</param>
    /// <returns></returns>
    public static IEnumerable<T> RandomSelectMany<T>(this IEnumerable<T> objs, Func<T, float> key)
    {
        List<T> selected = new List<T>();

        foreach (T obj in objs)
        {
            if (PercentChance(key(obj)))
            {
                selected.Add(obj);
            }
        }

        return selected;
    }

    ///// <summary>
    ///// Selects multiple items from an IEnumerable. Can also select none.
    ///// </summary>
    ///// <typeparam name="T"></typeparam>
    ///// <param name="objs"></param>
    ///// <param name="key">How to get to the percentage [0-1] from any obj.</param>
    ///// <returns>(index, value)</returns>
    //public static IEnumerable<Tuple<int, T>> RandomSelectManyPairs<T>(this IEnumerable<T> objs, Func<T, float> key)
    //{
    //    List<Tuple<int, T>> selected = new List<Tuple<int, T>>();

    //    int i = 0;

    //    foreach (T obj in objs)
    //    {
    //        if (PercentChance(key(obj)))
    //        {
    //            selected.Add(new(i, obj));
    //        }

    //        i++;
    //    }

    //    return selected;
    //}

    /// <summary>
    /// Randomly selects multiple items from an IEnumerable. Guarenteed to select at least one
    /// item.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="objs"></param>
    /// <param name="key"></param>
    /// <returns></returns>
    public static IEnumerable<T> RandomSelectAtLeastOne<T>(this IEnumerable<T> objs, Func<T, float> key)
    {
        var selected = objs.RandomSelectMany(key);

        if (selected.Count() < 1)
        {
            T[] arr = { objs.GetRandomValue() };
            selected = arr.AsEnumerable();
        }

        return selected;
    }    

    /// <summary>
    /// Selects one or no items from an IEnumerable.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="objs"></param>
    /// <param name="key">How to get to the percentage [0-1] from any obj.</param>
    /// <returns></returns>
    public static T RandomSelectOneOrNone<T>(this IEnumerable<T> objs, Func<T, float> key)
    {
        IEnumerable<T> selected = objs.RandomSelectMany(key);

        if (selected.Count() < 1)
        {
            return objs.GetRandomValue();
        }
        else
        {
            return default;
        }
    }
    /// <summary>
    /// Selects one item from an IEnumerable
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="objs"></param>
    /// <param name="key">How to get to the percentage [0-1] from any obj.</param>
    /// <returns></returns>
    public static T RandomSelectOne<T>(this IEnumerable<T> objs, Func<T, float> key)
    {
        IEnumerable<T> selected = objs.RandomSelectMany(key);

        if (selected.Count() < 1)
        {
            return objs.GetRandomValue();
        }
        else
        {
            return selected.GetRandomValue();
        }
    }

    ///// <summary>
    ///// Selects one item pair from an IEnumerable
    ///// </summary>
    ///// <typeparam name="T"></typeparam>
    ///// <param name="objs"></param>
    ///// <param name="key">How to get to the percentage [0-1] from any obj.</param>
    ///// <returns>(index, value)</returns>
    //public static Tuple<int, T> RandomSelectOnePair<T>(this IEnumerable<T> objs, Func<T, float> key)
    //{
    //    IEnumerable<T> selected = objs.RandomSelectMany(key);

    //    if (selected.Count() < 1)
    //    {
    //        return objs.GetRandomValuePair();
    //    }
    //    else
    //    {
    //        return selected.GetRandomValuePair();
    //    }
    //}

    /// <summary>
    /// Removes duplicates from a list of values
    /// </summary>
    public static List<T> RemoveDuplicates<T>(this List<T> list)
    {
        return new HashSet<T>(list).ToList();
    }
}