Files
BracerLib/Assets/Scripts/Utility/RandomUtility.cs
T
2026-06-02 18:57:47 -04:00

114 lines
4.4 KiB
C#

using System;
using UnityEngine;
using UnityEngine.TestTools;
using Random = System.Random;
using Vector2 = System.Numerics.Vector2;
using Vector3 = System.Numerics.Vector3;
namespace BracerLib.Utility
{
[ExcludeFromCoverage]
public static class RandomUtility
{
public static readonly string CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
[ThreadStatic]
private static Random unrepeatedRandomThreadInstance;
private static Random unrepeatedRandom => unrepeatedRandomThreadInstance ??= new Random(DateTime.Now.Millisecond);
private static int prevSeed = -1;
public static float NextFloat(this Random prng) => (float)prng.NextDouble();
public static float Range(this Random prng, float minInclusive, float maxExclusive)
=> minInclusive + (maxExclusive - minInclusive) * prng.NextFloat();
public static void RandomizeUnityRandom()
{
var seed = (int)DateTime.Now.Ticks;
if (seed != prevSeed)
return;
prevSeed = seed;
UnityEngine.Random.InitState(seed);
}
/// <summary> Random between 0.0 inclusive and 1.0 exclusive. </summary>
public static double NextDouble() => unrepeatedRandom.NextDouble();
/// <summary> Random between 0f inclusive and 1f exclusive. </summary>
public static float NextFloat() => unrepeatedRandom.NextFloat();
/// <summary>
/// Given a value, return a random number between the negative and positive of the input value.
/// </summary>
/// <param name="bookendRangeValue">Non-negative value.</param>
public static float Range(float bookendRangeValue) => unrepeatedRandom.Range(-bookendRangeValue, bookendRangeValue);
public static float Range(float minInclusive, float maxExclusive) => unrepeatedRandom.Range(minInclusive, maxExclusive);
public static int Range(int minInclusive, int maxExclusive) => unrepeatedRandom.Next(minInclusive, maxExclusive);
/// <summary> Random point uniformly distributed on the surface of a sphere of radius 1. </summary>
public static Vector3 RandomOnUnitSphere() {
var theta = MathUtility.TWO_PI * NextDouble();
var phi = Math.Acos(2.0 * NextDouble() - 1.0);
var sinPhi = Math.Sin(phi);
return new Vector3(
(float)(sinPhi * Math.Cos(theta)),
(float)(sinPhi * Math.Sin(theta)),
(float)Math.Cos(phi)
);
}
/// <summary> Random point uniformly distributed inside a sphere of radius 1. </summary>
public static Vector3 RandomInUnitSphere() => RandomOnUnitSphere() * (float)Math.Pow(NextDouble(), 1.0 / 3.0);
/// <summary> Random point uniformly distributed on the perimeter of a circle of radius 1. </summary>
public static Vector2 RandomOnUnitCircle() {
var angle = MathUtility.TWO_PI * NextDouble();
return new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
}
/// <summary> Random point uniformly distributed in a circle of radius 1. </summary>
public static Vector2 RandomInUnitCircle() => RandomOnUnitCircle() * (float)Math.Sqrt(NextDouble());
/// <summary> Random point uniformly distributed in a ring starting at radius1 and ending at radius2. </summary>
public static Vector2 RandomInRing(float r1, float r2) {
var r2sq = r2 * r2;
return RandomOnUnitCircle() * (float)Math.Sqrt(NextDouble() * (r1 * r1 - r2sq) + r2sq);
}
public static Color RandomColorRGB()
{
return new Color(
unrepeatedRandom.NextFloat(),
unrepeatedRandom.NextFloat(),
unrepeatedRandom.NextFloat(),
1f
);
}
public static Color RandomColorRGBA()
{
return new Color(
unrepeatedRandom.NextFloat(),
unrepeatedRandom.NextFloat(),
unrepeatedRandom.NextFloat(),
unrepeatedRandom.NextFloat()
);
}
public static string GetRandomString(int length)
{
var stringChars = new char[length];
var random = new Random();
for (var i = 0; i < stringChars.Length; i++)
stringChars[i] = CHARS[random.Next(CHARS.Length)];
return new string(stringChars);
}
}
}