using System.Collections; using System.Collections.Generic; using Godot; using System; namespace Rokojori { public abstract class RandomEngine { public abstract float Next(); public float Value( float scalar ) { return Next() * scalar; } public float Range( float a, float b) { return this.Next()*( b - a ) + a; } public float Sample( Curve curve ) { return curve.Sample( Next() ); } public float Polar() { return this.Next() * 2f - 1f; } public float Polar( float value ) { return Polar() * value; } 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; return Range( value, 1f / value ); } public bool WithChanceOf( float value ) { return ( this.Next() * 100 ) <= value ; } public Vector3 Between( Vector3 a, Vector3 b ) { return a.Lerp( b, this.Next() ); } public Color RandomHue( float saturation = 1f, float luminance = 0.5f) { var hue = Range( 0, 360 ); 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 ); } public float AngleRadians() { return Range( 0, Mathf.Pi * 2f ); } public Vector3 InCube() { return new Vector3( Polar(), Polar(), Polar() ); } 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; } public Vector3 OnSphere( float size ) { 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 ) { var h = Range( hMin, hMax ); var s = Range( sMin, sMax ); var l = Range( lMin, lMax ); return new HSLColor( h, s, l ); } public int IntegerInclusive( int min, int max ) { return (int) ( Mathf.Floor( this.Next() * ( max - min + 1 ) ) + min ) ; } public int IntegerInclusive( int max ) { return IntegerInclusive( 0, max ); } public int IntegerExclusive( int min, int max ) { var nextValue = this.Next(); var randomValue = nextValue * ( max - min ) + min; var value = (int) ( Mathf.Floor( randomValue ) ); return Mathf.Min( max - 1, value ); } public int IntegerExclusive( int max ) { return IntegerExclusive( 0, max ); } public char From( string source ) { var index = IntegerExclusive( source.Length ); return source[ index ]; } public T From( T[] array ) { if ( array.Length == 0 ) { return default ( T ); } var index = IntegerExclusive( array.Length ); return array[ index ]; } public T From( HashSet set ) { var selectedIndex = IntegerExclusive( set.Count ); var currentIndex = 0; foreach ( var e in set ) { if ( selectedIndex == currentIndex ) { return e; } currentIndex++; } return default( T ); } public T FromValues( T first, params T[] values ) { if ( values.Length == 0 ) { return first; } var index = IntegerExclusive( values.Length + 1 ); return index == 0 ? first : values[ index - 1 ]; } public T From( List list ) { if ( list.Count == 0 ) { return default ( T ); } var index = this.IntegerExclusive( 0, list.Count ); return list[ index ]; } public T RemoveFrom( List list ) { if ( list.Count == 0 ) { return default ( T ); } var index = this.IntegerExclusive( 0, list.Count ); var item = list[ index ]; list.RemoveAt( index ); return item; } public List RemoveMutlipleFrom( List list, int amount ) { if ( amount >= list.Count ) { return list; } var items = new List(); for ( int i = 0; i < amount; i++ ) { var itemIndex = this.IntegerExclusive( 0, list.Count ); var item = list[ itemIndex ]; list.RemoveAt( itemIndex ); items.Add( item ); } return items; } public T RemoveWeightedFrom( List list, List 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 RemoveMultipleWeightedFrom( List list, List weights, int amount ) { if ( amount >= list.Count ) { return list; } var sumWeights = 0f; weights.ForEach( w => sumWeights += w ); var selection = new List(); for ( int i = 0; i < amount; i++ ) { var number = Range( 0, sumWeights ); var index = _FindElementIndexWithWeights( weights, Range( 0, sumWeights ) ); var element = list[ index ]; var weight = weights[ index ]; list.RemoveAt( index ); sumWeights -= weight; selection.Add( element ); } return selection; } public int IndexFromUnnormalizedWeights( List weights, float sumWeights = 0 ) { if ( sumWeights <= 0 ) { sumWeights = 0; weights.ForEach( w => sumWeights += w ); } return _FindElementIndexWithWeights( weights, Next() * sumWeights ); } public int IndexFromCurveWeights( Curve curve, int numIndices ) { var weights = new List(); 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 ); } public int IndexFromNormalizedWeights( List weights, float sumWeights = 0 ) { return IndexFromUnnormalizedWeights( weights, 1 ); } int _FindElementIndexWithWeights( List 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; } } public abstract class SeedableRandomEngine:RandomEngine { public abstract void SetSeed( int number ); public abstract object GetSeedState(); public abstract void SetSeedState( object seedState ); } }