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( array: T[], alternative:T = null ):T { if ( array.length == 0 ) { return alternative; } var index = this.integerExclusive( 0, array.length ); return array[ index ]; } arrayFrom( numElements:number, array: T[], alternative:T = null ):T[] { let randomArray:T[] = []; for ( let i = 0; i < numElements; i++ ) { randomArray.push( this.from( array, alternative ) ); } return randomArray; } fromValues( 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( numElements:number, first:T, ...values:T[] ):T[] { let randomArray:T[] = []; for ( let i = 0; i < numElements; i++ ) { randomArray.push( this.from( [first].concat( values ) ) ); } return randomArray; } fromSet( set:Set ) { 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 extends RandomEngine { abstract setSeed( seed:number ):void; abstract getSeedState():S; abstract setSeedState( seedState:S ):void; }