rokojori_action_library/Runtime/Random/RandomEngine.cs

490 lines
11 KiB
C#
Raw Normal View History

2024-05-12 17:03:20 +00:00
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
2026-05-22 12:25:02 +00:00
using Rokojori.Extensions;
2024-05-12 17:03:20 +00:00
namespace Rokojori
{
2024-08-11 17:38:06 +00:00
public abstract class RandomEngine
2024-05-12 17:03:20 +00:00
{
2025-01-03 12:09:23 +00:00
public static RandomEngine CreateIfNull( RandomEngine r )
{
if ( r == null )
{
return new GodotRandom();
}
return r;
}
2024-05-12 17:03:20 +00:00
public abstract float Next();
public float Value( float scalar )
{
return Next() * scalar;
}
2026-05-22 12:25:02 +00:00
public float FromRange( float a, float b)
2024-05-12 17:03:20 +00:00
{
return this.Next()*( b - a ) + a;
}
2025-06-27 05:12:53 +00:00
public float Sample( Curve curve, float min = 0, float max = 0 )
2024-11-12 08:03:36 +00:00
{
2025-06-27 05:12:53 +00:00
if ( curve == null )
{
2026-05-22 12:25:02 +00:00
return FromRange( min, max );
2025-06-27 05:12:53 +00:00
}
2024-11-12 08:03:36 +00:00
return curve.Sample( Next() );
}
2025-01-26 09:15:28 +00:00
public int SampleInteger( Curve curve )
{
return Mathf.RoundToInt( curve.Sample( Next() ) );
}
2026-05-22 12:25:02 +00:00
public float Polar1()
2024-05-12 17:03:20 +00:00
{
return this.Next() * 2f - 1f;
}
public float Polar( float value )
{
2026-05-22 12:25:02 +00:00
return Polar1() * value;
2024-05-12 17:03:20 +00:00
}
public bool Bool()
{
return this.Next() > 0.5f;
}
public bool Chance( float value )
{
return value / 100f >= Next();
}
public bool FlipCoin()
{
return Chance( 50f );
}
public float PercentageVariation( float variation )
{
var value = ( 100f - variation ) / 100f;
2026-05-22 12:25:02 +00:00
return FromRange( value, 1f / value );
2024-05-12 17:03:20 +00:00
}
public bool WithChanceOf( float value )
{
return ( this.Next() * 100 ) <= value ;
}
public Vector3 Between( Vector3 a, Vector3 b )
{
return a.Lerp( b, this.Next() );
}
2025-01-08 18:46:17 +00:00
public Vector3 IndividualBetween( Vector3 a, Vector3 b )
{
var x = Mathf.Lerp( a.X, b.X, this.Next() );
var y = Mathf.Lerp( a.Y, b.Y, this.Next() );
var z = Mathf.Lerp( a.Z, b.Z, this.Next() );
return new Vector3( x, y, z );
}
2024-05-12 17:03:20 +00:00
public Color RandomHue( float saturation = 1f, float luminance = 0.5f)
{
2026-05-22 12:25:02 +00:00
var hue = FromRange( 0, 360 );
2024-05-12 17:03:20 +00:00
var color = new HSLColor( hue, saturation, luminance );
return color;
}
public Vector2 InRectangle( Vector2 min, Vector2 max )
{
var x = Mathf.Lerp( min.X, max.X, Next() );
var y = Mathf.Lerp( min.Y, max.Y, Next() );
return new Vector2( x, y );
}
2024-11-12 08:03:36 +00:00
public float AngleRadians()
{
2026-05-22 12:25:02 +00:00
return FromRange( 0, Mathf.Pi * 2f );
2024-11-12 08:03:36 +00:00
}
2024-05-12 17:03:20 +00:00
public Vector3 InCube()
{
2026-05-22 12:25:02 +00:00
return new Vector3( Polar1(), Polar1(), Polar1() );
2024-05-12 17:03:20 +00:00
}
public Vector3 InsideCube( float size )
{
return InCube() * ( size * 0.5f );
}
public Vector3 InsideSphere()
{
var inCube = InCube();
if ( inCube.LengthSquared() > 1 )
{
inCube = inCube.Normalized() * Next();
}
return inCube;
}
2025-09-26 12:00:59 +00:00
public Vector2 OnCircle( float size = 1 )
{
var angle = Mathf.Pi * 2.0f * Next();
return new Vector2( Mathf.Cos( angle ), Mathf.Sin( angle ) ) * size ;
}
public Vector2 InsideCircle( float maxSize = 1, float minSize = 0f )
{
var size = Next() * ( maxSize - minSize ) + minSize;
var angle = Mathf.Pi * 2.0f * Next();
return new Vector2( Mathf.Cos( angle ), Mathf.Sin( angle ) ) * size ;
}
2026-05-22 12:25:02 +00:00
public Vector3 OnSphereScaled( float size )
2024-05-12 17:03:20 +00:00
{
return OnSphere() * size;
}
public Vector3 OnSphere()
{
var dir = InsideSphere();
while ( dir.LengthSquared() == 0 )
{
dir = InsideSphere();
}
return dir;
}
public Vector3 InSphere( float size )
{
return InsideSphere() * ( size * 0.5f );
}
public Color HSL( float hMin = 0 , float hMax = 360, float sMin = 1, float sMax = 1, float lMin = 0.5f, float lMax = 0.5f )
{
2026-05-22 12:25:02 +00:00
var h = FromRange( hMin, hMax );
var s = FromRange( sMin, sMax );
var l = FromRange( lMin, lMax );
return new HSLColor( h, s, l );
}
2026-05-22 12:25:02 +00:00
public int IntegerInclusiveInRange( int min, int max )
2024-05-12 17:03:20 +00:00
{
return (int) ( Mathf.Floor( this.Next() * ( max - min + 1 ) ) + min ) ;
}
2026-05-22 12:25:02 +00:00
public int IntegerInclusivePositive( int max )
2024-05-12 17:03:20 +00:00
{
2026-05-22 12:25:02 +00:00
return IntegerInclusiveInRange( 0, max );
2024-05-12 17:03:20 +00:00
}
2026-05-22 12:25:02 +00:00
public int IntegerExclusiveInRange( int min, int max )
2024-05-12 17:03:20 +00:00
{
var nextValue = this.Next();
var randomValue = nextValue * ( max - min ) + min;
var value = (int) ( Mathf.Floor( randomValue ) );
return Mathf.Min( max - 1, value );
}
2026-05-22 12:25:02 +00:00
public int IntegerExclusivePositive( int max )
2024-05-12 17:03:20 +00:00
{
2026-05-22 12:25:02 +00:00
return IntegerExclusiveInRange( 0, max );
2024-05-12 17:03:20 +00:00
}
2026-05-22 12:25:02 +00:00
public char FromText( string source )
2024-05-12 17:03:20 +00:00
{
2026-05-22 12:25:02 +00:00
var index = IntegerExclusivePositive( source.Length );
2024-05-12 17:03:20 +00:00
return source[ index ];
}
public T From<T>( T[] array )
{
if ( array.Length == 0 )
{
return default ( T );
}
2026-05-22 12:25:02 +00:00
var index = IntegerExclusivePositive( array.Length );
2024-05-12 17:03:20 +00:00
return array[ index ];
}
2026-05-22 12:25:02 +00:00
#if !ROKOJORI_ACTION_CORE_GD
public T From<T>( List<T> list )
{
if ( list.Count == 0 )
{
return default ( T );
}
var index = IntegerExclusivePositive( list.Count );
return list[ index ];
}
#endif
public T GrabFromRange<T>( List<T> list, int start, int end )
{
if ( list.Count == 0 )
{
return default ( T );
}
var index = this.IntegerInclusiveInRange( start, end );
return list[ index ];
}
public T FromSet<T>( HashSet<T> set )
2024-05-12 17:03:20 +00:00
{
2026-05-22 12:25:02 +00:00
var selectedIndex = IntegerExclusivePositive( set.Count );
2024-05-12 17:03:20 +00:00
var currentIndex = 0;
foreach ( var e in set )
{
if ( selectedIndex == currentIndex )
{
return e;
}
currentIndex++;
}
return default( T );
}
public T FromValues<T>( T first, params T[] values )
{
if ( values.Length == 0 )
{
return first;
}
2026-05-22 12:25:02 +00:00
var index = IntegerExclusivePositive( values.Length + 1 );
2024-05-12 17:03:20 +00:00
return index == 0 ? first : values[ index - 1 ];
}
2026-05-22 12:25:02 +00:00
2025-06-23 11:16:01 +00:00
2024-08-11 17:38:06 +00:00
public T RemoveFrom<T>( List<T> list )
{
if ( list.Count == 0 )
{
return default ( T );
}
2025-01-03 12:09:23 +00:00
if ( list.Count == 1 )
{
var element = list[ 0 ];
list.Clear();
return element;
}
2026-05-22 12:25:02 +00:00
var index = this.IntegerExclusiveInRange( 0, list.Count );
2024-08-11 17:38:06 +00:00
var item = list[ index ];
list.RemoveAt( index );
return item;
}
public List<T> RemoveMutlipleFrom<T>( List<T> list, int amount )
{
if ( amount >= list.Count )
{
return list;
}
var items = new List<T>();
for ( int i = 0; i < amount; i++ )
{
2026-05-22 12:25:02 +00:00
var itemIndex = this.IntegerExclusiveInRange( 0, list.Count );
2024-08-11 17:38:06 +00:00
var item = list[ itemIndex ];
list.RemoveAt( itemIndex );
items.Add( item );
}
return items;
}
public T RemoveWeightedFrom<T>( List<T> list, List<float> weights )
{
if ( list == null || list.Count == 0 )
{
return default(T);
}
if ( list.Count == 1 )
{
return list[ 0 ];
}
var weightedSelection = RemoveMultipleWeightedFrom( list, weights, 1 );
return weightedSelection[ 0 ];
}
public List<T> RemoveMultipleWeightedFrom<T>( List<T> list, List<float> weights, int amount )
{
if ( amount >= list.Count )
{
return list;
}
var sumWeights = 0f;
weights.ForEach( w => sumWeights += w );
var selection = new List<T>();
for ( int i = 0; i < amount; i++ )
{
2026-05-22 12:25:02 +00:00
var number = FromRange( 0, sumWeights );
2024-08-11 17:38:06 +00:00
2026-05-22 12:25:02 +00:00
var index = _FindElementIndexWithWeights( weights, FromRange( 0, sumWeights ) );
2024-08-11 17:38:06 +00:00
var element = list[ index ];
var weight = weights[ index ];
list.RemoveAt( index );
sumWeights -= weight;
selection.Add( element );
}
return selection;
}
2026-03-20 13:31:31 +00:00
public T FromWeightedElements<T>( IList<T> elements, Func<T,float> getWeight )
{
var weights = new List<float>( elements.Count );
foreach ( var e in elements )
{
weights.Add( getWeight( e ) );
}
var index = IndexFromUnnormalizedWeights( weights );
return elements[ index ];
}
2024-09-14 06:41:52 +00:00
public int IndexFromUnnormalizedWeights( List<float> weights, float sumWeights = 0 )
{
if ( sumWeights <= 0 )
{
sumWeights = 0;
weights.ForEach( w => sumWeights += w );
}
return _FindElementIndexWithWeights( weights, Next() * sumWeights );
}
2025-06-27 05:12:53 +00:00
public float SelectCurveWeights( Curve curve, int numSteps = 100 )
{
return IndexFromCurveWeights( curve, numSteps ) / (float) numSteps;
}
2024-11-12 08:03:36 +00:00
public int IndexFromCurveWeights( Curve curve, int numIndices )
{
var weights = new List<float>();
var sumWeights = 0f;
for ( int i = 0; i < numIndices; i++ )
{
var t = (float)i / ( numIndices - 1 );
var w = curve.Sample( t );
weights.Add( w );
sumWeights += w;
}
return IndexFromUnnormalizedWeights( weights, sumWeights );
}
2024-09-14 06:41:52 +00:00
public int IndexFromNormalizedWeights( List<float> weights, float sumWeights = 0 )
{
return IndexFromUnnormalizedWeights( weights, 1 );
}
public List<int> Numbers( int numValues, int offset = 0 )
{
var list = new List<int>();
for ( int i = 0; i < numValues; i++ )
{
list.Add( i + offset );
}
return new RandomList<int>( list, this ).GetList();
}
public List<int> Selection( int possibleValues, int selection )
{
2025-04-06 16:39:24 +00:00
selection = Mathf.Min( selection, possibleValues );
var list = new List<int>();
for ( int i = 0; i < possibleValues; i++ )
{
list.Add( i );
}
return new RandomList<int>( list, this ).GetList().GetRange( 0, selection );
}
2024-08-11 17:38:06 +00:00
int _FindElementIndexWithWeights( List<float> weights, float value )
{
var limit = 0f;
for ( int i = 0; i < weights.Count; i++ )
{
var before = limit;
limit += weights[ i ];
if ( before <= value && value < limit )
{
return i;
}
}
return weights.Count - 1;
}
2024-05-12 17:03:20 +00:00
}
public abstract class SeedableRandomEngine:RandomEngine
{
public abstract void SetSeed( int number );
public abstract object GetSeedState();
public abstract void SetSeedState( object seedState );
}
}