Last active
August 29, 2015 14:24
-
-
Save satori99/7c1200f2c0eee8b9e36a to your computer and use it in GitHub Desktop.
A seedable psuedo-random number generator for browser use
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function(){ | |
/** | |
* rc4.js - A fast seedable psuedo-random number generator | |
* @public | |
* @class | |
* @param {string} [seed] - seed. IF specified, the first 256 chars will | |
* be used to seed the RC4 PRNG, otherwise a random character | |
* string will used. | |
* @example | |
* // Get a psuedo-random floating point value | |
* RC4.random(); // same as Math.random() | |
* @example | |
* // Get deterministic psuedo-random floating point values | |
* var rc4 = new RC4( 'test' ); | |
* rc4.random(); // 0.6818718355790825 | |
* rc4.random(); // 0.14780130176502 | |
* rc4.random(); // 0.9055136215611361 | |
* rc4.reset(); // reset state using existing seed | |
* rc4.random(); // 0.6818718355790825 (again) | |
* rc4.random(); // 0.14780130176502 (again) | |
*/ | |
function RC4 ( seed ) { | |
this.state = new Uint8Array( 256 ); | |
this.reset( seed ); | |
} | |
RC4.prototype = { | |
/** @constructs */ | |
constructor: RC4, | |
/** | |
* rc4 seed | |
* @public | |
* @type {!string} | |
*/ | |
seed: undefined, | |
/** | |
* rc4 state array | |
* @public | |
* @type {Uint8Array} | |
*/ | |
state: undefined, | |
/** | |
* rc4 state ptr | |
* @public | |
* @type {number} | |
*/ | |
i: 0, | |
/** | |
* rc4 state ptr | |
* @public | |
* @type {number} | |
*/ | |
j: 0, | |
/** | |
* swaps the byte values at the specifed positions in the state buffer | |
* @private | |
* @param {!number} i - position one | |
* @param {!number} j - position two | |
*/ | |
swap: function( i, j ) { | |
tmp = this.state[ i ]; | |
this.state[ i ] = this.state[ j ]; | |
this.state[ j ] = tmp; | |
}, | |
/** | |
* resets the PRNG state | |
* @public | |
* @param {string} [seed] - new seed value. If specified, the first 256 bytes | |
* will be used to initialize the state buffer, otherwise the | |
* existing seed will be re-used. | |
*/ | |
reset: function ( seed ) { | |
this.seed = ( seed !== undefined ? | |
String( seed ).trim().slice( 0, 256 ) : false ) | |
|| this.seed | |
|| Math.random().toString( 36 ).slice( 2 ); | |
this.state.set( Array.apply( 0, Array( 256 ) ) | |
.map( function ( x, y ) { return y; } ) ); | |
for ( var i = 0, j = 0, t = 0; i < 256; i ++ ) { | |
this.swap( i, j = ( j + this.state[ i ] + | |
this.seed[ i % this.seed.length ].charCodeAt( 0 ) ) % 256 ); | |
} | |
this.i = 0; | |
this.j = 0; | |
}, | |
/** | |
* Gets the next byte value from the psuedo-random byte stream | |
* @public | |
* @returns {number} random integer between 0 (inc) and 255 (inc) | |
*/ | |
next: function () { | |
// consume next byte | |
this.i = ( this.i + 1 ) % 256; | |
this.j = ( this.j + this.state[ this.i ] ) % 256; | |
this.swap( this.i, this.j ); | |
return this.state[ ( this.state[ this.i ] + this.state[ this.j ] ) % 256 ]; | |
}, | |
/** | |
* Gets a random sign | |
* @public | |
* @returns {number} -1 or + 1 | |
*/ | |
sign: function () { | |
// consume 1 bytes to create a random sign | |
return ( ( this.next() >> 7 ) << 1 ) - 1; | |
}, | |
/** | |
* Gets the next float value from the psuedo-random byte stream | |
* @public | |
* @returns {number} a random number between zero (inc) and one (exc). | |
*/ | |
random: function () { | |
// consume 7 bytes to create a 53 bit double | |
var out = this.next(); | |
out = out * 256 + this.next(); | |
out = out * 256 + this.next(); | |
out = out * 256 + this.next(); | |
out = out * 256 + this.next(); | |
out = out * 256 + this.next(); | |
out = out * 256 + this.next(); | |
return out / 0x100000000000004; | |
}, | |
/** | |
* Gets a random number in the range -1.0 to 1.0 (exclusive) | |
* @public | |
* @returns {number} A random number between -1 and 1 | |
*/ | |
signedRandom: function () { | |
// consumes 8 bytes from the psuedo-random stream | |
return this.sign() * this.random(); | |
}, | |
/** @inheritdoc */ | |
toString: function () { return '[object RC4]'; } | |
} | |
// temp var for swap operations | |
var tmp = 0; | |
// internal instance with random seed for binding static methods | |
var rc4 = new RC4(); | |
/** | |
* Gets a random byte | |
* @public | |
* @static | |
* @returns {number} random integer between zero (inc) and 255 (inc) | |
*/ | |
RC4.next = function () { return rc4.next(); }; | |
/** | |
* Gets a random sign | |
* @public | |
* @static | |
* @returns {number} positive or negative one | |
*/ | |
RC4.sign = function () { return rc4.sign(); }; | |
/** | |
* Gets a random floating point number ( functionally equivalent to `Math.random()`) | |
* @public | |
* @static | |
* @returns {number} a random number between zero (inc) and one (exc). | |
*/ | |
// | |
RC4.random = function () { return rc4.random(); }; | |
/** | |
* Gets a random number in the range -1.0 to 1.0 (exclusive) | |
* @public | |
* @static | |
* @returns {number} a random number between zero (inc) and one (exc). | |
*/ | |
RC4.signedRandom = function () { return rc4.signedRandom(); }; | |
// export to global scope | |
self.RC4 = RC4; | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment