1
0
Fork 0
mirror of https://github.com/Oreolek/raconteur.git synced 2024-06-30 21:45:00 +03:00
raconteur/lib/oneOf.js
2015-04-12 22:23:33 -03:00

164 lines
4 KiB
JavaScript

/*
Undularity Tools
Those functions are not a core part of Undularity, but provide some
general functionality that relates to adaptive text generation.
This is provided partly as a helper to less technical users, and as
a convenience for authors.
*/
/* Monkey patching */
/* Array.prototype.shuffle() */
/*
Shuffles an array. It can use Undum's random number generator implementation,
so it expects a System.rnd object to be passed into it. If one isn't
supplied, it will use Math.Random instead.
This is an implementation of the Fischer-Yates (Knuth) shuffle.
Returns the shuffled array.
*/
Array.prototype.shuffle = function (system) {
var rng = (system) ? system.rnd.random : Math.random;
// slice() clones the array. Object members are copied by reference,
// beware.
var newArr = this.slice();
var m = newArr.length;
while (m) {
let i = Math.floor(rng() * m --);
let t = newArr[m];
newArr[m] = newArr[i];
newArr[i] = t;
}
return newArr;
};
/*
oneOf()
Takes an array and returns an object with several methods. Each method
returns an iterator which iterates over the array in a specific way:
inOrder()
Returns the array items in order.
cycling()
Returns the array items in order, cycling back to the first item when
it runs out.
stopping()
Returns the array items in order, then repeats the last item when it
runs out.
randomly()
Returns the array items at random. Takes a system object, for consistent
randomness. Will never return the same item twice in a row.
trulyAtRandom()
Returns the array items purely at random. Takes a system object, for
consistent randomness.
inRandomOrder()
Returns the array items in a random order. Takes a system object, for
consistent randomness.
*/
/*
Takes a function and gives it a toString() property that calls itself and
returns its value, allowing for ambiguous use of the closure object
as a text snippet.
Returns the modified function.
*/
var stringish = function (callback) {
callback.toString = function () { return '' + this.call() };
return callback;
}
var oneOf = function (...ary) {
if (ary.length<1) {
throw new Error(
"tried to create a oneOf iterator with a 0-length array");
}
return {
inOrder () {
var i = 0;
return stringish(function () {
if (i >= ary.length) return null;
return ary[i++];
});
},
cycling () {
var i = 0;
return stringish(function () {
if (i >= ary.length) i = 0;
return ary[i++];
});
},
stopping () {
var i = 0;
return stringish(function () {
if (i >= ary.length) i = ary.length - 1;
return ary[i++];
});
},
randomly (system) {
var rng = (system) ? system.rnd.random : Math.random,
last;
if (ary.length<2) {
throw new Error(
"attempted to make randomly() iterator with a 1-length array");
}
return stringish(function () {
var i, offset;
if (last === undefined) {
i = Math.floor(rng() * ary.length)
} else {
/*
Let offset be a random number between 1 and the length of the
array, minus one. We jump offset items ahead on the array,
wrapping around to the beginning. This gives us a random item
other than the one we just chose.
*/
offset = Math.floor(rng() * (ary.length -1) + 1);
i = (last + offset) % ary.length;
}
last = i;
return ary[i];
});
},
trulyAtRandom (system) {
var rng = (system) ? system.rnd.random : Math.random;
return stringish(function () {
return ary[Math.floor(rng() * ary.length)];
});
},
inRandomOrder (system) {
var shuffled = ary.shuffle(system),
i = 0;
return stringish(function () {
if (i >= ary.length) i = 0;
return shuffled[i++];
});
}
};
};
module.exports = oneOf;