From: Joe Wreschnig Date: Fri, 10 Oct 2014 11:53:24 +0000 (+0200) Subject: Use RRR for name generation. X-Git-Url: https://git.yukkurigames.com/?a=commitdiff_plain;h=6305404cdf2be33bc1d29b4f1250035a7380ce5d;p=ogre.git Use RRR for name generation. --- diff --git a/ogre.html b/ogre.html index bcdb0f5..f8d5df4 100644 --- a/ogre.html +++ b/ogre.html @@ -27,6 +27,7 @@ + diff --git a/ogre.js b/ogre.js index c670e93..9bc3211 100644 --- a/ogre.js +++ b/ogre.js @@ -57,64 +57,8 @@ var CHECK = "☒"; var FIRST_EMPTY = /☐/; var LAST_TICKED = /☒([^☒]*)$/; -function choice (a) { - return a[(Math.random() * a.length) | 0]; -} - -function cap (s) { - return s && s[0].toUpperCase() + s.slice(1); -} - -function letters (n) { - var r = ""; - n = n || 1; - while (n-- > 0) - r += choice("abcdefghijklmnopqrstuvwxyz"); - return r; -} - -function range (a, b) { - return a + (Math.random() * (b - a)) | 0; -} - -function numerals (n) { - var r = ""; - n = n || 1; - while (n-- > 0) - r += choice("0123456789"); - return r; -} - -function pid () { - return letters(range(1, 4)).toUpperCase() - + choice(["‑", "", ".", "/"]) - + numerals(range(1, 4)); -} - -function roman () { - return choice(["I", "II", "III", "IV", "V", "VI", - "VII", "VIII", "IX", "X", "XI", "XII", - "XIV"]); -} - -function oid () { - return choice([letters(1).toUpperCase() + choice("-./") + numerals(2)]); -} - function randomName (scheme) { - switch (scheme) { - case "id": - return choice([pid() + " " + cap(choice(NOUNS))], - [cap(choice(NOUNS)) + " " + pid()]); - case "air": - return choice([ - oid() + " " + cap(choice(ADJECTIVES)) + " " + cap(choice(BIRDS)), - cap(choice(ADJECTIVES)) + " " + cap(choice(BIRDS)) + " " + roman()]); - default: - return choice([ - oid() + " " + cap(choice(ADJECTIVES)) + " " + cap(choice(NOUNS)), - cap(choice(ADJECTIVES)) + " " + cap(choice(NOUNS)) + " " + roman()]); - } + return G.expand(scheme); } var STATS = ["attack", "range", "defense", "aside"]; 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 = {}); diff --git a/units.js b/units.js index 984b6fd..30f0841 100644 --- a/units.js +++ b/units.js @@ -9,79 +9,96 @@ See https://creativecommons.org/publicdomain/zero/1.0/ for details. */ -var ADJECTIVES = [ - "angry", - "cold", - "deadly", - "easy", - "faithful", - "fatal", - "fiery", - "harsh", - "lost", - "mean", - "mighty", - "noisy", - "old", - "proud", - "pure", - "quiet", - "sharp", - "slow", - "strong", - "true", - "", - "", - "", -]; +var G = new rrr.Grammar({ -var BIRDS = [ - "angel", - "arrow", - "cloud", - "eagle", - "falcon", - "owl", - "raptor", - "storm", - "swan", - "swarm", -]; + Model: [" ", " "], + Flying: [" ", " "], + Id: [" ", " "], -var NOUNS = [ - "axe", - "boar", - "brute", - "claw", - "cobra", - "dagger", - "demon", - "fox", - "hyena", - "knife", - "lion", - "lynx", - "saber", - "scout", - "snake", - "spear", - "spire", - "stone", - "stream", - "sword", - "talon", - "thorn", - "tide", - "tooth", - "tower", - "tusk", - "venom", - "viper", - "wall", - "wave", - "wolf", - "worker", -]; + Adjective: { "": 0.9, "": 0.1 }, + Separator: { "": 1, "": 0.25 }, + Oid: ["{2}"], + Pid: ["{1,4}{1,4}"], + + adjective: [ + "Angry", + "Cold", + "Deadly", + "Easy", + "Faithful", + "Fatal", + "Fiery", + "Harsh", + "Lost", + "Mean", + "Mighty", + "Noisy", + "Old", + "Proud", + "Pure", + "Quiet", + "Sharp", + "Slow", + "Strong", + "True", + ], + + bird: [ + "Angel", + "Arrow", + "Cloud", + "Eagle", + "Falcon", + "Owl", + "Raptor", + "Storm", + "Swan", + "Swarm", + ], + + noun: [ + "Axe", + "Boar", + "Brute", + "Claw", + "Cobra", + "Dagger", + "Demon", + "Fox", + "Hyena", + "Knife", + "Lion", + "Lynx", + "Saber", + "Scout", + "Snake", + "Spear", + "Spire", + "Stone", + "Stream", + "Sword", + "Talon", + "Thorn", + "Tide", + "Tooth", + "Tower", + "Tusk", + "Venom", + "Viper", + "Wall", + "Wave", + "Wolf", + "Worker", + ], + + roman: ["I", "II", "III", "IV", "V", "VI", + "VII", "VIII", "IX", "X", "XI", "XII", + "XIV"], + + letter: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + digit: "0123456789", + separator: "-./", +}, ""); // Most game data in this file based on // http://www.sjgames.com/ogre/kickstarter/ogre-rec-sheets.pdf @@ -115,7 +132,7 @@ var WEAPONS = { var UNITS = { "Superheavy Tank": { weapons: ["3 Main Guns", "3 Antipersonnel"], - nameScheme: "id", + nameScheme: "", tread: 18, size: 5, au: 3 @@ -184,7 +201,6 @@ var UNITS = { au: 25 }, "Ogre Mk. VI": { - nameScheme: "grand", weapons: [ "3 Main Battery", "6 Secondary Battery", @@ -224,7 +240,6 @@ var UNITS = { au: "25+" }, "Doppelsoldner": { - nameScheme: "grand", weapons: [ "2 Main Battery", "8 Secondary Battery", @@ -266,7 +281,7 @@ var UNITS = { }, // http://www.sjgames.com/ogre/articles/csa.html "CSA-10 (Magi)": { - nameScheme: "air", + nameScheme: "", weapons: [ "2 Bombloads", "1 Air-to-Air Missile", @@ -278,7 +293,7 @@ var UNITS = { propulsion: 48, }, "CSA-15 (Magi)": { - nameScheme: "air", + nameScheme: "", weapons: [ "4 Bombloads", "3 Air-to-Air Missiles",