diff --git a/ext/random/random.js b/ext/random/random.js new file mode 100644 index 000000000..02dc04908 --- /dev/null +++ b/ext/random/random.js @@ -0,0 +1,120 @@ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define(['ramda'], factory); + } else if (typeof exports === 'object') { + module.exports = factory(require('../../ramda')); + } else { + root.Random = factory(root.ramda); + } +}(this, function (R) { + + // Random + // ---------- + // + // TODO: (possibly?) + // var random = new Random(seeds); // then... + // random.nextInt(below): () -> random int, where 0 <= int < < below + // random.intBetween(start, upTo): () -> random int, where start <= int < upTo + // random.boolean(): () -> random boolean + // random.fromChars(characters): int -> random String consisting of `int` chars drawn from `characters`. + + // From http://baagoe.com/en/RandomMusings/javascript/ + // mirrored at https://github.com/nquinlan/better-random-numbers-for-javascript-mirror + // Johannes Baagøe , 2010 + var Mash = function Mash() { + var n = 0xefc8249d; + + var mash = function (data) { + data = data.toString(); + for (var i = 0; i < data.length; i++) { + n += data.charCodeAt(i); + var h = 0.02519603282416938 * n; + n = h >>> 0; + h -= n; + h *= n; + n = h >>> 0; + h -= n; + n += h * 0x100000000; // 2^32 + } + return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 + }; + + mash.version = 'Mash 0.9'; + return mash; + }; + + // From http://baagoe.com/en/RandomMusings/javascript/ + // mirrored at https://github.com/nquinlan/better-random-numbers-for-javascript-mirror + // Johannes Baagøe , 2010 + var Random = function Random() { + return (function (args) { + var s0 = 0; + var s1 = 0; + var s2 = 0; + var c = 1; + + if (args.length == 0) { + args = [+new Date]; + } + var mash = Mash(); + s0 = mash(' '); + s1 = mash(' '); + s2 = mash(' '); + + for (var i = 0; i < args.length; i++) { + s0 -= mash(args[i]); + if (s0 < 0) { + s0 += 1; + } + s1 -= mash(args[i]); + if (s1 < 0) { + s1 += 1; + } + s2 -= mash(args[i]); + if (s2 < 0) { + s2 += 1; + } + } + mash = null; + + var random = function () { + var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32 + s0 = s1; + s1 = s2; + return s2 = t - (c = t | 0); + }; + random.uint32 = function () { + return random() * 0x100000000; // 2^32 + }; + random.fract53 = function () { + return random() + + (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53 + }; + random.version = 'Alea 0.9'; + random.args = args; + return random; + + }(Array.prototype.slice.call(arguments))); + }; + + // Returns a shuffled version of a list, using the + // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). + var shuffle = R.shuffle = function(random, list) { + var idx = -1; + var len = list.length; + var position; + var result = []; + while (++idx < len) { + position = Math.floor((idx + 1) * random()); + result[idx] = result[position]; + result[position] = list[idx]; + } + return result; + }; + + R.Random = Random; + + return Random; +})); + + diff --git a/ext/random/test/test.random.js b/ext/random/test/test.random.js new file mode 100644 index 000000000..dc5376408 --- /dev/null +++ b/ext/random/test/test.random.js @@ -0,0 +1,42 @@ +var assert = require('assert'); +var Lib = require('../../../ramda'); +var Random = require('../random'); + +describe('Random', function() { + it('is a function', function() { + assert.equal(typeof Random, 'function'); + }); + + it('returns a function', function() { + assert.equal(typeof Random(), 'function'); + }); + + it('returns consistent results for the same seeds', function() { + var random = new Random("my", 3, "seeds"); + assert.equal(random(), 0.30802189325913787); + assert.equal(random(), 0.5190450621303171); + assert.equal(random(), 0.43635262292809784); + }); + + it('but returns entirely different results for even slightly different seeds', function() { + var random = new Random("my", 3, "weeds"); + assert.equal(random(), 0.7021001486573368); + assert.equal(random(), 0.6134823360480368); + assert.equal(random(), 0.6507473199162632); + }); +}); + +describe('shuffle', function() { + var shuffle = Lib.shuffle; + var random; + + beforeEach(function() { + random = Random("my", 3, "seeds"); + }); + + it('returns a shuffled copy of a list', function() { + var list = [1, 2, 3,4, 5, 6, 7, 8, 9, 10]; + assert.deepEqual(shuffle(random, list), [6, 3, 4, 8, 5, 1, 7, 10, 2, 9]); + }); + +}); \ No newline at end of file