library-ts/browser/random/RandomEngine.ts

213 lines
3.9 KiB
TypeScript
Raw Normal View History

2025-03-08 08:16:54 +00:00
import { HTMLColor } from '../colors/HTMLColor';
import { HSLColor } from '../colors/HSLColor';
import { RGBColor } from "../colors/RGBColor";
import { Range } from '../geometry/Range';
export abstract class RandomEngine
{
abstract next():number;
value( scalar:number ):number
{
return this.next() * scalar;
}
range( a:number, b:number ):number
{
return this.next()*( b - a ) + a;
}
in( range:Range ):number
{
return this.range( range.min, range.max );
}
polarOne():number
{
return this.next() * 2 - 1;
}
polar( value:number ):number
{
return this.polarOne() * value;
}
bool():boolean
{
return this.next() > 0.5;
}
percentageVariation( variation:number ):Range
{
var value = ( 100 - variation ) / 100;
return new Range( value, 1 / value );
}
withChanceOf( value:number ):boolean
{
return ( this.next() * 100 ) <= value ;
}
randomHue( saturation:number = 1, luminance:number = 0.5):HTMLColor
{
let hue = this.range( 0, 360 );
let color = new HSLColor( hue, saturation, luminance );
return color;
}
lerpRGB( colors:HTMLColor[]):HTMLColor
{
if ( colors.length == 1 )
{
return colors[ 0 ];
}
return RGBColor.lerpFrom( colors, this.next() );
}
/*
inCubeOne():Vector3
{
return new Vector3( this.polarOne(), this.polarOne(), this.polarOne() );
}
inCube( size:number ):Vector3
{
return this.inCubeOne().multiplyScalar( size * 0.5 );
}
inSphereOne():Vector3
{
var inCube = this.inCubeOne();
if ( inCube.lengthSq() > 1 )
{
inCube.normalize().multiplyScalar( this.next() );
}
return inCube;
}
inSphere( size:number ):Vector3
{
return this.inSphereOne().multiplyScalar( size * 0.5 );
}
*/
integerInclusive( min:number, max:number ):number
{
return ( Math.floor( this.next() * ( max - min + 1 ) ) + min ) ;
}
integerInclusiveFromZero( max:number ):number
{
return this.integerInclusive( 0, max );
}
integerExclusive( min:number, max:number ):number
{
var nextValue = this.next();
var randomValue = nextValue * ( max - min ) + min;
var value = ( Math.floor( randomValue ) );
return Math.min( max - 1, value );
}
integerExclusiveFromZero( max:number ):number
{
return this.integerExclusive( 0, max );
}
fromString( text: string, alternative:string = null ):string
{
if ( ! text || text.length === 0 )
{
return alternative;
}
let index = this.integerExclusive( 0, text.length );
return text[ index ];
}
from<T>( array: T[], alternative:T = null ):T
{
if ( array.length == 0 )
{
return alternative;
}
var index = this.integerExclusive( 0, array.length );
return array[ index ];
}
arrayFrom<T>( numElements:number, array: T[], alternative:T = null ):T[]
{
let randomArray:T[] = [];
for ( let i = 0; i < numElements; i++ )
{
randomArray.push( this.from<T>( array, alternative ) );
}
return randomArray;
}
fromValues<T>( first:T, ...values:T[] ):T
{
if ( values.length == 0 )
{
return first;
}
var index = this.integerExclusive( 0, values.length + 1 );
return index == 0 ? first : values[ index - 1];
}
arrayFromValues<T>( numElements:number, first:T, ...values:T[] ):T[]
{
let randomArray:T[] = [];
for ( let i = 0; i < numElements; i++ )
{
randomArray.push( this.from<T>( [first].concat( values ) ) );
}
return randomArray;
}
fromSet<T>( set:Set<T> )
{
let index = this.integerExclusiveFromZero( set.size );
let i = 0;
for ( let t of set )
{
if ( index === i )
{
return t;
}
i++;
}
return null;
}
}
export abstract class SeedableRandomEngine<S> extends RandomEngine
{
abstract setSeed( seed:number ):void;
abstract getSeedState():S;
abstract setSeedState( seedState:S ):void;
}