chainy/node_modules/deck/index.js

100 lines
2.6 KiB
JavaScript
Raw Normal View History

2020-01-26 19:03:32 +00:00
var exports = module.exports = function (xs) {
if (typeof xs !== 'object') { // of which Arrays are
throw new TypeError('Must be an Array or an object');
}
return Object.keys(exports).reduce(function (acc, name) {
acc[name] = exports[name].bind(null, xs);
return acc;
}, {});
};
exports.shuffle = function (xs) {
if (Array.isArray(xs)) {
// uniform shuffle
var res = xs.slice();
for (var i = res.length - 1; i >= 0; i--) {
var n = Math.floor(Math.random() * i);
var t = res[i];
res[i] = res[n];
res[n] = t;
}
return res;
}
else if (typeof xs === 'object') {
// weighted shuffle
var weights = Object.keys(xs).reduce(function (acc, key) {
acc[key] = xs[key];
return acc;
}, {});
var ret = [];
while (Object.keys(weights).length > 0) {
var key = exports.pick(weights);
delete weights[key];
ret.push(key);
}
return ret;
}
else {
throw new TypeError('Must be an Array or an object');
}
};
exports.pick = function (xs) {
if (Array.isArray(xs)) {
// uniform sample
return xs[Math.floor(Math.random() * xs.length)];
}
else if (typeof xs === 'object') {
// weighted sample
var weights = exports.normalize(xs);
if (!weights) return undefined;
var n = Math.random();
var threshold = 0;
var keys = Object.keys(weights);
for (var i = 0; i < keys.length; i++) {
threshold += weights[keys[i]];
if (n < threshold) return keys[i];
}
throw new Error('Exceeded threshold. Something is very wrong.');
}
else {
throw new TypeError('Must be an Array or an object');
}
};
exports.normalize = function (weights) {
if (typeof weights !== 'object' || Array.isArray(weights)) {
throw 'Not an object'
}
var keys = Object.keys(weights);
if (keys.length === 0) return undefined;
var total = keys.reduce(function (sum, key) {
var x = weights[key];
if (x < 0) {
throw new Error('Negative weight encountered at key ' + key);
}
else if (typeof x !== 'number') {
throw new TypeError('Number expected, got ' + typeof x);
}
else {
return sum + x;
}
}, 0);
return total === 1
? weights
: keys.reduce(function (acc, key) {
acc[key] = weights[key] / total;
return acc;
}, {})
;
};