X-Git-Url: https://git.yukkurigames.com/?p=ogre.git;a=blobdiff_plain;f=rrr.js;fp=rrr.js;h=4561421dd0e48065a1cfc108389962cdc57bea43;hp=0000000000000000000000000000000000000000;hb=6305404cdf2be33bc1d29b4f1250035a7380ce5d;hpb=42d76ec9269b0ae0252cfb6420902a63fd16a73f diff --git a/rrr.js b/rrr.js new file mode 100644 index 0000000..4561421 --- /dev/null +++ b/rrr.js @@ -0,0 +1,104 @@ +/* rrr - recursive random rewrites + Copyright 2014 Joe Wreschnig + Licensed under the terms of the GNU GPL v2 or later + @license https://www.gnu.org/licenses/gpl-2.0.html + @source: https://yukkurigames.com/rrr/ +*//* + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + As additional permission, you may distribute the program or works + based on it without the copy of the GNU GPL normally required, + provided you include this license notice and a URL through which + recipients can access the corresponding source code. +*/ + +(function (exports) { + "use strict"; + + function randfloat (hi) { return Math.random() * hi; } + function randint (hi) { return randfloat(hi) | 0; } + function randchoice (seq) { return seq[randint(seq.length)]; } + function randrange (lo, hi) { return lo + randint(hi - lo); } + + function Productions (dfn) { + this.__total = 0; + if (Array.isArray(dfn) || dfn.toString() === dfn) { + this.__rules = Array.prototype.slice.call(dfn); + } else if (typeof dfn === "function") { + this.__rules = dfn; + } else { + this.__rules = {}; + Object.keys(dfn).forEach(function (key) { + var value = dfn[key]; + this.__total += value; + this.__rules[key] = value; + }, this); + } + } + + Productions.prototype.randproduction = function () { + if (Array.isArray(this.__rules)) + return randchoice(this.__rules); + + else if (typeof this.__rules === "function") + return this.__rules(); + + var x = randfloat(this.__total); + for (var k in this.__rules) { + x -= this.__rules[k]; + if (x < 0) + return k; + } + return null; + }; + + function Grammar (productions, start) { + this.start = start || ""; + this.productions = {}; + for (var k in productions) + this.productions[k] = new Productions(productions[k]); + } + + function randcount (lo, hi, rep) { + var n = hi ? randrange(+lo, +hi + 1) + : lo ? +lo + : 1; + + var m = 1; + switch (rep) { + case '*': m = 0; while (Math.random() < 0.5) ++m; break; + case '+': while (Math.random() < 0.5) ++m; break; + case '?': m = +(Math.random() < 0.5); break; + } + return n * m; + } + + function repeat (n, f) { + var r = []; + while (n-- > 0) + r.push(f()); + return r; + } + + var R = /<([^> ]+)( ?)>(?:{([0-9]+)(?:,([0-9]+))?}|(\*|\+|\?))?/g; + Grammar.prototype.expand = function (start) { + var g = this; + start = start || this.start; + return start.replace(R, function _ (match, p, w, lo, hi, rep) { + var prod = g.productions[p]; + return repeat(randcount(lo, hi, rep), function () { + return prod.randproduction().replace(R, _); + }).join(w); + }); + }; + + exports.Grammar = Grammar; +})(typeof module !== "undefined" ? module.exports : this.rrr = {});