1 module unexpected.rando.names; 2 3 import reversineer; 4 import std.random : Random, uniform; 5 6 import unexpected.rando.common; 7 8 static immutable string[string] genTable; 9 static immutable string[string] genTableStarts; 10 11 enum minNameLength = 3; 12 13 shared static this() { 14 import std.uni : isUpper; 15 string[string] tableUpper; 16 string[string] tableLower; 17 genTableStarts = createTable!true(import("nametable.txt")); 18 genTable = createTable!false(import("nametable.txt")); 19 import std.stdio; 20 } 21 22 string[string] createTable(bool upper)(string data) @safe { 23 import std.algorithm.iteration : splitter; 24 import std.array : front; 25 import std.string : lineSplitter; 26 import std.uni : isUpper, toLower; 27 string[string] result; 28 foreach (line; data.lineSplitter()) { 29 auto split = line.splitter(" "); 30 string key = split.front; 31 if (upper) { 32 if (!key.front.isUpper) { 33 continue; 34 } 35 } else { 36 key = key.toLower(); 37 } 38 split.popFront(); 39 result[key] = split.front; 40 } 41 return result; 42 } 43 44 string generateName(size_t length, uint seed) @safe 45 in(length >= minNameLength, "Length must be at least "~('0'+minNameLength)) 46 { 47 import std.random : Random, uniform; 48 import std.uni : toLower; 49 string pickRandomKey(immutable string[string] assoc, ref Random rnd) @trusted { 50 return assoc.keys[uniform(0, assoc.length, rnd)]; 51 } 52 53 auto rand = Random(seed); 54 string result = pickRandomKey(genTableStarts, rand); 55 result.reserve(length); 56 while (result.length < length) { 57 auto lastChars = result[$-3 .. $].toLower(); 58 if (lastChars !in genTable) { 59 if (result.length < length - 4) { 60 result ~= ' '~pickRandomKey(genTableStarts, rand); 61 } else { 62 return result; 63 } 64 } else { 65 result ~= genTable[lastChars][uniform(0, genTable[lastChars].length, rand)]; 66 } 67 } 68 return result; 69 } 70 71 72 void randomizeNames(Name CTOptions, T)(ref T field, ref Random rng, ref uint seed, const Options options) { 73 seed = rng.uniform!uint; 74 field = generateName(field.length, seed); 75 }