blendish: cosmetix
[iv.d.git] / namegen.d
blobd9670472b9a71fba3dfdbb5fcc194ed5cb8792fe
1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 // Totro-inspired random name generator, clean room implementation
19 module iv.namegen /*is aliced*/;
20 private:
22 import iv.alice;
23 import iv.vfs;
26 public struct NameGen {
27 private:
28 enum { Vowel = 0, Consonant = 1 }
30 enum {
31 WordBeg = 0x01,
32 WordMid = 0x02,
33 WordEnd = 0x04,
36 static struct Syllable {
37 private:
38 char[3] sytext = 0;
39 ubyte code; // WordXXX mask
40 uint count;
42 public:
43 bool opEqual (in Syllable sy) const @safe pure nothrow @nogc {
44 return (this.code == sy.code && this.count == sy.count && this.str == sy.str);
47 @property string str () const @trusted pure nothrow @nogc {
48 usize sz = 0;
49 while (sz < sytext.length && sytext[sz]) ++sz;
50 return cast(string)sytext[0..sz];
53 debug @property string codeStr () const @trusted pure nothrow @nogc {
54 switch (code) {
55 case WordBeg: return "WordBeg";
56 case WordMid: return "WordMid";
57 case WordEnd: return "WordEnd";
58 case WordBeg|WordMid: return "WordBeg|WordMid";
59 case WordBeg|WordEnd: return "WordBeg|WordEnd";
60 case WordBeg|WordMid|WordEnd: return "WordBeg|WordMid|WordEnd";
61 case WordMid|WordEnd: return "WordMid|WordEnd";
62 default: return "FUCKED";
67 // totro tables
68 static immutable Syllable[26] totroSyllsV = [
69 {sytext:"'\0", count:1, code:WordMid},
70 {sytext:"y\0", count:1, code:WordBeg|WordMid|WordEnd},
71 {sytext:"aa\0", count:1, code:WordBeg|WordMid|WordEnd},
72 {sytext:"ae\0", count:1, code:WordBeg|WordMid|WordEnd},
73 {sytext:"ai\0", count:1, code:WordBeg|WordMid|WordEnd},
74 {sytext:"ao\0", count:1, code:WordBeg|WordMid|WordEnd},
75 {sytext:"au\0", count:1, code:WordBeg|WordMid|WordEnd},
76 {sytext:"ea\0", count:1, code:WordBeg|WordMid|WordEnd},
77 {sytext:"ee\0", count:1, code:WordBeg|WordMid|WordEnd},
78 {sytext:"eo\0", count:1, code:WordBeg|WordMid|WordEnd},
79 {sytext:"eu\0", count:1, code:WordBeg|WordMid|WordEnd},
80 {sytext:"ia\0", count:1, code:WordBeg|WordMid|WordEnd},
81 {sytext:"ii\0", count:1, code:WordBeg|WordMid|WordEnd},
82 {sytext:"io\0", count:1, code:WordBeg|WordMid|WordEnd},
83 {sytext:"iu\0", count:1, code:WordBeg|WordMid|WordEnd},
84 {sytext:"oa\0", count:1, code:WordBeg|WordMid|WordEnd},
85 {sytext:"oe\0", count:1, code:WordBeg|WordMid|WordEnd},
86 {sytext:"oi\0", count:1, code:WordBeg|WordMid|WordEnd},
87 {sytext:"oo\0", count:1, code:WordBeg|WordMid|WordEnd},
88 {sytext:"ou\0", count:1, code:WordBeg|WordMid|WordEnd},
89 {sytext:"eau", count:1, code:WordBeg|WordMid|WordEnd},
90 {sytext:"a\0", count:12, code:WordBeg|WordMid|WordEnd},
91 {sytext:"e\0", count:12, code:WordBeg|WordMid|WordEnd},
92 {sytext:"i\0", count:12, code:WordBeg|WordMid|WordEnd},
93 {sytext:"o\0", count:12, code:WordBeg|WordMid|WordEnd},
94 {sytext:"u\0", count:12, code:WordBeg|WordMid|WordEnd},
96 static immutable Syllable[51] totroSyllsC = [
97 {sytext:"x\0", count:1, code:WordBeg|WordMid|WordEnd},
98 {sytext:"y\0", count:1, code:WordBeg|WordMid|WordEnd},
99 {sytext:"z\0", count:1, code:WordBeg|WordMid|WordEnd},
100 {sytext:"ch\0", count:1, code:WordBeg|WordMid|WordEnd},
101 {sytext:"ck\0", count:1, code:WordMid|WordEnd},
102 {sytext:"cl\0", count:1, code:WordBeg|WordMid},
103 {sytext:"cr\0", count:1, code:WordBeg|WordMid},
104 {sytext:"fl\0", count:1, code:WordBeg|WordMid},
105 {sytext:"gh\0", count:1, code:WordBeg|WordMid|WordEnd},
106 {sytext:"gl\0", count:1, code:WordBeg|WordMid},
107 {sytext:"kl\0", count:1, code:WordBeg|WordMid},
108 {sytext:"ll\0", count:1, code:WordBeg|WordMid},
109 {sytext:"nk\0", count:1, code:WordMid|WordEnd},
110 {sytext:"ph\0", count:1, code:WordBeg|WordMid|WordEnd},
111 {sytext:"pl\0", count:1, code:WordBeg|WordMid},
112 {sytext:"pr\0", count:1, code:WordBeg|WordMid},
113 {sytext:"qu\0", count:1, code:WordBeg|WordMid},
114 {sytext:"rk\0", count:1, code:WordMid|WordEnd},
115 {sytext:"sc\0", count:1, code:WordBeg|WordMid|WordEnd},
116 {sytext:"sh\0", count:1, code:WordBeg|WordMid|WordEnd},
117 {sytext:"sk\0", count:1, code:WordBeg|WordMid|WordEnd},
118 {sytext:"sl\0", count:1, code:WordBeg|WordMid},
119 {sytext:"sr\0", count:1, code:WordBeg|WordMid},
120 {sytext:"ss\0", count:1, code:WordMid|WordEnd},
121 {sytext:"st\0", count:1, code:WordBeg|WordMid|WordEnd},
122 {sytext:"th\0", count:1, code:WordBeg|WordMid|WordEnd},
123 {sytext:"tr\0", count:1, code:WordBeg|WordMid},
124 {sytext:"wh\0", count:1, code:WordBeg|WordMid},
125 {sytext:"str", count:1, code:WordBeg|WordMid},
126 {sytext:"br\0", count:2, code:WordBeg|WordMid},
127 {sytext:"dr\0", count:2, code:WordBeg|WordMid},
128 {sytext:"fr\0", count:2, code:WordBeg|WordMid},
129 {sytext:"gr\0", count:2, code:WordBeg|WordMid},
130 {sytext:"kr\0", count:2, code:WordBeg|WordMid},
131 {sytext:"b\0", count:3, code:WordBeg|WordMid|WordEnd},
132 {sytext:"c\0", count:3, code:WordBeg|WordMid|WordEnd},
133 {sytext:"d\0", count:3, code:WordBeg|WordMid|WordEnd},
134 {sytext:"f\0", count:3, code:WordBeg|WordMid|WordEnd},
135 {sytext:"g\0", count:3, code:WordBeg|WordMid|WordEnd},
136 {sytext:"h\0", count:3, code:WordBeg|WordMid|WordEnd},
137 {sytext:"j\0", count:3, code:WordBeg|WordMid|WordEnd},
138 {sytext:"k\0", count:3, code:WordBeg|WordMid|WordEnd},
139 {sytext:"l\0", count:3, code:WordBeg|WordMid|WordEnd},
140 {sytext:"m\0", count:3, code:WordBeg|WordMid|WordEnd},
141 {sytext:"n\0", count:3, code:WordBeg|WordMid|WordEnd},
142 {sytext:"p\0", count:3, code:WordBeg|WordMid|WordEnd},
143 {sytext:"r\0", count:3, code:WordBeg|WordMid|WordEnd},
144 {sytext:"s\0", count:3, code:WordBeg|WordMid|WordEnd},
145 {sytext:"t\0", count:3, code:WordBeg|WordMid|WordEnd},
146 {sytext:"v\0", count:3, code:WordBeg|WordMid|WordEnd},
147 {sytext:"w\0", count:3, code:WordBeg|WordMid|WordEnd},
150 Syllable[][2] sylls = [totroSyllsV, totroSyllsC];
151 uint[2] totals = [81, 90];
153 static uint defaultUni (uint max) @trusted nothrow @nogc {
154 import iv.prng.pcg32;
155 static PCG32 prng;
156 static bool inited = false;
157 if (!inited) {
158 import iv.prng.seeder;
159 prng.seed(getUlongSeed, 42);
160 inited = true;
162 uint res = prng.front%max; // this is not uniform, but i don't care
163 prng.popFront();
164 return res;
167 uint rand (uint min, uint max) const @trusted nothrow @nogc {
168 return (genRand is null ? defaultUni(max-min+1) : genRand(max-min+1))+min;
171 public:
172 // generate random number, [0..max); max is never uint.max or 0
173 uint delegate (uint max) @trusted nothrow @nogc genRand;
175 void setTotro() () {
176 sylls[0] = totroSyllsV.dup;
177 sylls[1] = totroSyllsC.dup;
178 totals = [81, 90];
181 void setSW() () {
182 // [11979, 16732]
183 static immutable Syllable[56] swSyllsV = [
184 {sytext:"ui\0", count:1, code:WordMid},
185 {sytext:"aea", count:1, code:WordBeg},
186 {sytext:"ooo", count:1, code:WordBeg},
187 {sytext:"uee", count:2, code:WordMid},
188 {sytext:"oe\0", count:2, code:WordBeg},
189 {sytext:"aee", count:2, code:WordBeg},
190 {sytext:"aeo", count:2, code:WordBeg},
191 {sytext:"eeo", count:2, code:WordMid},
192 {sytext:"oa\0", count:2, code:WordBeg},
193 {sytext:"eu\0", count:3, code:WordMid},
194 {sytext:"io\0", count:3, code:WordMid},
195 {sytext:"ou\0", count:4, code:WordMid},
196 {sytext:"uo\0", count:4, code:WordMid},
197 {sytext:"eeu", count:4, code:WordMid},
198 {sytext:"ooe", count:4, code:WordBeg},
199 {sytext:"ooi", count:4, code:WordBeg},
200 {sytext:"ou\0", count:5, code:WordBeg},
201 {sytext:"eea", count:5, code:WordMid},
202 {sytext:"aei", count:5, code:WordBeg},
203 {sytext:"oi\0", count:6, code:WordBeg},
204 {sytext:"eee", count:6, code:WordMid},
205 {sytext:"au\0", count:8, code:WordMid},
206 {sytext:"eei", count:9, code:WordMid},
207 {sytext:"oee", count:12, code:WordMid},
208 {sytext:"ie\0", count:14, code:WordMid},
209 {sytext:"ii\0", count:14, code:WordMid},
210 {sytext:"aee", count:15, code:WordMid},
211 {sytext:"eo\0", count:15, code:WordMid},
212 {sytext:"oo\0", count:16, code:WordMid},
213 {sytext:"ei\0", count:16, code:WordMid},
214 {sytext:"oe\0", count:17, code:WordMid},
215 {sytext:"oa\0", count:22, code:WordMid},
216 {sytext:"ea\0", count:25, code:WordMid},
217 {sytext:"aa\0", count:29, code:WordMid},
218 {sytext:"ae\0", count:49, code:WordBeg},
219 {sytext:"ai\0", count:51, code:WordMid},
220 {sytext:"oo\0", count:54, code:WordBeg},
221 {sytext:"ae\0", count:55, code:WordMid},
222 {sytext:"ue\0", count:61, code:WordMid},
223 {sytext:"ia\0", count:64, code:WordMid},
224 {sytext:"ua\0", count:69, code:WordMid},
225 {sytext:"ao\0", count:86, code:WordMid},
226 {sytext:"oi\0", count:91, code:WordMid},
227 {sytext:"o\0", count:106, code:WordBeg},
228 {sytext:"e\0", count:113, code:WordBeg},
229 {sytext:"o\0", count:130, code:WordEnd},
230 {sytext:"ee\0", count:152, code:WordMid},
231 {sytext:"i\0", count:165, code:WordEnd},
232 {sytext:"e\0", count:455, code:WordEnd},
233 {sytext:"a\0", count:477, code:WordBeg},
234 {sytext:"u\0", count:815, code:WordMid},
235 {sytext:"a\0", count:890, code:WordEnd},
236 {sytext:"o\0", count:1322, code:WordMid},
237 {sytext:"i\0", count:1481, code:WordMid},
238 {sytext:"e\0", count:2376, code:WordMid},
239 {sytext:"a\0", count:2637, code:WordMid},
241 static immutable Syllable[389] swSyllsC = [
242 {sytext:"ntg", count:1, code:WordMid},
243 {sytext:"yc\0", count:1, code:WordMid},
244 {sytext:"xg\0", count:1, code:WordMid},
245 {sytext:"xw\0", count:1, code:WordMid},
246 {sytext:"tm\0", count:1, code:WordMid},
247 {sytext:"td\0", count:1, code:WordMid},
248 {sytext:"sq\0", count:1, code:WordMid},
249 {sytext:"thh", count:1, code:WordMid},
250 {sytext:"rrc", count:1, code:WordMid},
251 {sytext:"yg\0", count:1, code:WordMid},
252 {sytext:"rdv", count:1, code:WordMid},
253 {sytext:"ndb", count:1, code:WordMid},
254 {sytext:"trd", count:1, code:WordBeg},
255 {sytext:"bv\0", count:1, code:WordMid},
256 {sytext:"vpr", count:1, code:WordMid},
257 {sytext:"shr", count:1, code:WordMid},
258 {sytext:"xhr", count:1, code:WordMid},
259 {sytext:"dm\0", count:1, code:WordMid},
260 {sytext:"ndw", count:1, code:WordMid},
261 {sytext:"sv\0", count:1, code:WordMid},
262 {sytext:"yd\0", count:1, code:WordMid},
263 {sytext:"tg\0", count:1, code:WordMid},
264 {sytext:"ndp", count:1, code:WordMid},
265 {sytext:"rrn", count:1, code:WordMid},
266 {sytext:"lfb", count:1, code:WordMid},
267 {sytext:"sck", count:1, code:WordMid},
268 {sytext:"bs\0", count:1, code:WordMid},
269 {sytext:"kdg", count:1, code:WordMid},
270 {sytext:"ss\0", count:1, code:WordMid},
271 {sytext:"ntp", count:1, code:WordMid},
272 {sytext:"xq\0", count:1, code:WordMid},
273 {sytext:"thv", count:1, code:WordMid},
274 {sytext:"tb\0", count:1, code:WordMid},
275 {sytext:"sm\0", count:1, code:WordMid},
276 {sytext:"ntb", count:1, code:WordMid},
277 {sytext:"trc", count:1, code:WordBeg},
278 {sytext:"xs\0", count:1, code:WordMid},
279 {sytext:"ntc", count:1, code:WordMid},
280 {sytext:"thw", count:1, code:WordMid},
281 {sytext:"vg\0", count:1, code:WordMid},
282 {sytext:"ntd", count:1, code:WordMid},
283 {sytext:"yt\0", count:1, code:WordMid},
284 {sytext:"trh", count:1, code:WordBeg},
285 {sytext:"ryg", count:1, code:WordBeg},
286 {sytext:"xtr", count:1, code:WordMid},
287 {sytext:"rrb", count:1, code:WordMid},
288 {sytext:"sh\0", count:1, code:WordMid},
289 {sytext:"ryc", count:1, code:WordBeg},
290 {sytext:"tsy", count:1, code:WordMid},
291 {sytext:"bk\0", count:1, code:WordMid},
292 {sytext:"bg\0", count:1, code:WordMid},
293 {sytext:"lfq", count:1, code:WordMid},
294 {sytext:"lfg", count:1, code:WordMid},
295 {sytext:"vv\0", count:1, code:WordMid},
296 {sytext:"nds", count:1, code:WordMid},
297 {sytext:"tt\0", count:1, code:WordMid},
298 {sytext:"rkc", count:1, code:WordMid},
299 {sytext:"ntw", count:1, code:WordMid},
300 {sytext:"tck", count:1, code:WordMid},
301 {sytext:"bb\0", count:1, code:WordMid},
302 {sytext:"bll", count:1, code:WordMid},
303 {sytext:"lfn", count:1, code:WordMid},
304 {sytext:"rkg", count:1, code:WordMid},
305 {sytext:"rkq", count:2, code:WordMid},
306 {sytext:"xck", count:2, code:WordMid},
307 {sytext:"xv\0", count:2, code:WordMid},
308 {sytext:"ydr", count:2, code:WordMid},
309 {sytext:"ttr", count:2, code:WordMid},
310 {sytext:"vc\0", count:2, code:WordMid},
311 {sytext:"ts\0", count:2, code:WordMid},
312 {sytext:"trb", count:2, code:WordBeg},
313 {sytext:"sw\0", count:2, code:WordMid},
314 {sytext:"tw\0", count:2, code:WordMid},
315 {sytext:"ryn", count:2, code:WordBeg},
316 {sytext:"vs\0", count:2, code:WordMid},
317 {sytext:"yb\0", count:2, code:WordMid},
318 {sytext:"xt\0", count:2, code:WordMid},
319 {sytext:"str", count:2, code:WordMid},
320 {sytext:"kpr", count:2, code:WordMid},
321 {sytext:"khr", count:2, code:WordMid},
322 {sytext:"nts", count:2, code:WordMid},
323 {sytext:"xk\0", count:2, code:WordMid},
324 {sytext:"rkv", count:2, code:WordMid},
325 {sytext:"nth", count:2, code:WordMid},
326 {sytext:"rrl", count:2, code:WordMid},
327 {sytext:"bhr", count:2, code:WordMid},
328 {sytext:"ryd", count:2, code:WordBeg},
329 {sytext:"thc", count:2, code:WordMid},
330 {sytext:"bdr", count:2, code:WordMid},
331 {sytext:"sc\0", count:2, code:WordMid},
332 {sytext:"sl\0", count:2, code:WordMid},
333 {sytext:"tc\0", count:2, code:WordMid},
334 {sytext:"rym", count:2, code:WordBeg},
335 {sytext:"rrg", count:2, code:WordMid},
336 {sytext:"kq\0", count:2, code:WordMid},
337 {sytext:"lfl", count:2, code:WordMid},
338 {sytext:"lfm", count:2, code:WordMid},
339 {sytext:"thb", count:2, code:WordMid},
340 {sytext:"vsy", count:2, code:WordMid},
341 {sytext:"sg\0", count:2, code:WordMid},
342 {sytext:"lfp", count:2, code:WordMid},
343 {sytext:"yw\0", count:2, code:WordMid},
344 {sytext:"rkb", count:2, code:WordMid},
345 {sytext:"trl", count:2, code:WordBeg},
346 {sytext:"ryh", count:2, code:WordBeg},
347 {sytext:"sn\0", count:2, code:WordMid},
348 {sytext:"rrq", count:2, code:WordMid},
349 {sytext:"nhr", count:2, code:WordMid},
350 {sytext:"ysy", count:2, code:WordMid},
351 {sytext:"thd", count:2, code:WordMid},
352 {sytext:"ndv", count:2, code:WordMid},
353 {sytext:"vq\0", count:2, code:WordMid},
354 {sytext:"db\0", count:2, code:WordMid},
355 {sytext:"ndh", count:2, code:WordMid},
356 {sytext:"tk\0", count:2, code:WordMid},
357 {sytext:"rdp", count:2, code:WordMid},
358 {sytext:"yck", count:2, code:WordMid},
359 {sytext:"bdg", count:2, code:WordMid},
360 {sytext:"dd\0", count:2, code:WordMid},
361 {sytext:"rrt", count:2, code:WordMid},
362 {sytext:"kll", count:2, code:WordMid},
363 {sytext:"thp", count:2, code:WordMid},
364 {sytext:"xm\0", count:2, code:WordMid},
365 {sytext:"ntt", count:2, code:WordMid},
366 {sytext:"xb\0", count:2, code:WordMid},
367 {sytext:"ds\0", count:2, code:WordMid},
368 {sytext:"tq\0", count:2, code:WordMid},
369 {sytext:"rdc", count:2, code:WordMid},
370 {sytext:"lfv", count:2, code:WordMid},
371 {sytext:"ym\0", count:2, code:WordMid},
372 {sytext:"rll", count:2, code:WordMid},
373 {sytext:"xdr", count:2, code:WordMid},
374 {sytext:"lfd", count:2, code:WordMid},
375 {sytext:"rrk", count:2, code:WordMid},
376 {sytext:"ytr", count:3, code:WordMid},
377 {sytext:"dk\0", count:3, code:WordMid},
378 {sytext:"vt\0", count:3, code:WordMid},
379 {sytext:"dll", count:3, code:WordMid},
380 {sytext:"tdr", count:3, code:WordMid},
381 {sytext:"thq", count:3, code:WordMid},
382 {sytext:"vh\0", count:3, code:WordMid},
383 {sytext:"ryk", count:3, code:WordBeg},
384 {sytext:"yh\0", count:3, code:WordMid},
385 {sytext:"npr", count:3, code:WordMid},
386 {sytext:"btr", count:3, code:WordMid},
387 {sytext:"dl\0", count:3, code:WordMid},
388 {sytext:"vm\0", count:3, code:WordMid},
389 {sytext:"vdg", count:3, code:WordMid},
390 {sytext:"lft", count:3, code:WordMid},
391 {sytext:"thn", count:3, code:WordMid},
392 {sytext:"kh\0", count:3, code:WordMid},
393 {sytext:"lfc", count:3, code:WordMid},
394 {sytext:"ndt", count:3, code:WordMid},
395 {sytext:"yn\0", count:3, code:WordMid},
396 {sytext:"trn", count:3, code:WordBeg},
397 {sytext:"dt\0", count:3, code:WordMid},
398 {sytext:"ryt", count:3, code:WordBeg},
399 {sytext:"vb\0", count:3, code:WordMid},
400 {sytext:"vtr", count:3, code:WordMid},
401 {sytext:"lfk", count:3, code:WordMid},
402 {sytext:"ddr", count:3, code:WordMid},
403 {sytext:"bw\0", count:4, code:WordMid},
404 {sytext:"bt\0", count:4, code:WordMid},
405 {sytext:"tht", count:4, code:WordMid},
406 {sytext:"kg\0", count:4, code:WordMid},
407 {sytext:"rrw", count:4, code:WordMid},
408 {sytext:"rrm", count:4, code:WordMid},
409 {sytext:"rdw", count:4, code:WordMid},
410 {sytext:"ksy", count:4, code:WordMid},
411 {sytext:"ndl", count:4, code:WordMid},
412 {sytext:"sk\0", count:4, code:WordMid},
413 {sytext:"rdn", count:4, code:WordMid},
414 {sytext:"rdt", count:4, code:WordMid},
415 {sytext:"rdm", count:4, code:WordMid},
416 {sytext:"thm", count:4, code:WordMid},
417 {sytext:"ntk", count:4, code:WordMid},
418 {sytext:"dn\0", count:4, code:WordMid},
419 {sytext:"dc\0", count:4, code:WordMid},
420 {sytext:"rrh", count:4, code:WordMid},
421 {sytext:"rkd", count:4, code:WordMid},
422 {sytext:"rdh", count:4, code:WordMid},
423 {sytext:"dh\0", count:4, code:WordMid},
424 {sytext:"nv\0", count:4, code:WordMid},
425 {sytext:"bm\0", count:4, code:WordMid},
426 {sytext:"vhr", count:4, code:WordMid},
427 {sytext:"lfw", count:4, code:WordMid},
428 {sytext:"trs", count:4, code:WordBeg},
429 {sytext:"rdb", count:4, code:WordMid},
430 {sytext:"rks", count:4, code:WordMid},
431 {sytext:"kb\0", count:4, code:WordMid},
432 {sytext:"ryb", count:4, code:WordBeg},
433 {sytext:"rkt", count:4, code:WordMid},
434 {sytext:"kw\0", count:5, code:WordMid},
435 {sytext:"vw\0", count:5, code:WordMid},
436 {sytext:"vd\0", count:5, code:WordMid},
437 {sytext:"trr", count:5, code:WordBeg},
438 {sytext:"trk", count:5, code:WordBeg},
439 {sytext:"ndc", count:5, code:WordMid},
440 {sytext:"xl\0", count:5, code:WordMid},
441 {sytext:"nck", count:5, code:WordMid},
442 {sytext:"rkw", count:5, code:WordMid},
443 {sytext:"kd\0", count:5, code:WordMid},
444 {sytext:"rrs", count:5, code:WordMid},
445 {sytext:"nsy", count:5, code:WordMid},
446 {sytext:"lsy", count:5, code:WordMid},
447 {sytext:"bn\0", count:5, code:WordMid},
448 {sytext:"nll", count:5, code:WordMid},
449 {sytext:"lfh", count:5, code:WordMid},
450 {sytext:"thk", count:5, code:WordMid},
451 {sytext:"ndd", count:5, code:WordMid},
452 {sytext:"ndm", count:5, code:WordMid},
453 {sytext:"kt\0", count:5, code:WordMid},
454 {sytext:"ktr", count:5, code:WordMid},
455 {sytext:"lpr", count:5, code:WordMid},
456 {sytext:"trt", count:6, code:WordBeg},
457 {sytext:"ryl", count:6, code:WordBeg},
458 {sytext:"ndk", count:6, code:WordMid},
459 {sytext:"km\0", count:6, code:WordMid},
460 {sytext:"ntm", count:6, code:WordMid},
461 {sytext:"rkn", count:6, code:WordMid},
462 {sytext:"thl", count:6, code:WordMid},
463 {sytext:"rkh", count:6, code:WordMid},
464 {sytext:"rkm", count:6, code:WordMid},
465 {sytext:"bd\0", count:6, code:WordMid},
466 {sytext:"tl\0", count:6, code:WordMid},
467 {sytext:"bc\0", count:6, code:WordMid},
468 {sytext:"rds", count:6, code:WordMid},
469 {sytext:"yr\0", count:7, code:WordMid},
470 {sytext:"ndg", count:7, code:WordMid},
471 {sytext:"rdd", count:7, code:WordMid},
472 {sytext:"ng\0", count:7, code:WordMid},
473 {sytext:"rrr", count:7, code:WordMid},
474 {sytext:"kdr", count:7, code:WordMid},
475 {sytext:"ntl", count:7, code:WordMid},
476 {sytext:"nw\0", count:7, code:WordMid},
477 {sytext:"rkk", count:7, code:WordMid},
478 {sytext:"yk\0", count:7, code:WordMid},
479 {sytext:"ryr", count:7, code:WordBeg},
480 {sytext:"ks\0", count:7, code:WordMid},
481 {sytext:"bh\0", count:7, code:WordMid},
482 {sytext:"nh\0", count:7, code:WordMid},
483 {sytext:"kc\0", count:8, code:WordMid},
484 {sytext:"lv\0", count:8, code:WordMid},
485 {sytext:"rdl", count:8, code:WordMid},
486 {sytext:"kk\0", count:8, code:WordMid},
487 {sytext:"vk\0", count:9, code:WordMid},
488 {sytext:"rdg", count:9, code:WordMid},
489 {sytext:"lll", count:9, code:WordMid},
490 {sytext:"lq\0", count:9, code:WordMid},
491 {sytext:"vl\0", count:9, code:WordMid},
492 {sytext:"rkl", count:9, code:WordMid},
493 {sytext:"bl\0", count:9, code:WordMid},
494 {sytext:"yl\0", count:9, code:WordMid},
495 {sytext:"nb\0", count:10, code:WordMid},
496 {sytext:"xr\0", count:10, code:WordMid},
497 {sytext:"lck", count:10, code:WordMid},
498 {sytext:"kl\0", count:10, code:WordMid},
499 {sytext:"ldg", count:10, code:WordMid},
500 {sytext:"nc\0", count:11, code:WordMid},
501 {sytext:"vn\0", count:11, code:WordMid},
502 {sytext:"pr\0", count:12, code:WordMid},
503 {sytext:"rdk", count:12, code:WordMid},
504 {sytext:"rv\0", count:12, code:WordMid},
505 {sytext:"hr\0", count:12, code:WordMid},
506 {sytext:"kn\0", count:12, code:WordMid},
507 {sytext:"lw\0", count:12, code:WordMid},
508 {sytext:"lhr", count:13, code:WordMid},
509 {sytext:"rck", count:13, code:WordMid},
510 {sytext:"rhr", count:13, code:WordMid},
511 {sytext:"lg\0", count:14, code:WordMid},
512 {sytext:"sr\0", count:14, code:WordMid},
513 {sytext:"lfr", count:14, code:WordMid},
514 {sytext:"rh\0", count:14, code:WordMid},
515 {sytext:"thr", count:15, code:WordMid},
516 {sytext:"br\0", count:15, code:WordMid},
517 {sytext:"q\0", count:15, code:WordMid},
518 {sytext:"lf\0", count:15, code:WordMid},
519 {sytext:"rsy", count:15, code:WordMid},
520 {sytext:"ld\0", count:16, code:WordMid},
521 {sytext:"x\0", count:16, code:WordMid},
522 {sytext:"rs\0", count:16, code:WordMid},
523 {sytext:"rpr", count:16, code:WordMid},
524 {sytext:"rc\0", count:16, code:WordMid},
525 {sytext:"rq\0", count:17, code:WordMid},
526 {sytext:"rg\0", count:17, code:WordMid},
527 {sytext:"rkr", count:18, code:WordMid},
528 {sytext:"ldr", count:18, code:WordMid},
529 {sytext:"lh\0", count:18, code:WordMid},
530 {sytext:"ns\0", count:19, code:WordMid},
531 {sytext:"th\0", count:20, code:WordMid},
532 {sytext:"sy\0", count:20, code:WordMid},
533 {sytext:"lb\0", count:20, code:WordMid},
534 {sytext:"rb\0", count:20, code:WordMid},
535 {sytext:"ndr", count:20, code:WordMid},
536 {sytext:"ltr", count:20, code:WordMid},
537 {sytext:"tr\0", count:20, code:WordBeg},
538 {sytext:"kr\0", count:20, code:WordMid},
539 {sytext:"lt\0", count:21, code:WordMid},
540 {sytext:"rw\0", count:22, code:WordMid},
541 {sytext:"ck\0", count:22, code:WordMid},
542 {sytext:"ntr", count:22, code:WordMid},
543 {sytext:"vr\0", count:22, code:WordMid},
544 {sytext:"ls\0", count:22, code:WordMid},
545 {sytext:"ry\0", count:23, code:WordBeg},
546 {sytext:"nm\0", count:23, code:WordMid},
547 {sytext:"nt\0", count:23, code:WordMid},
548 {sytext:"rt\0", count:24, code:WordMid},
549 {sytext:"nd\0", count:24, code:WordMid},
550 {sytext:"lc\0", count:27, code:WordMid},
551 {sytext:"rtr", count:29, code:WordMid},
552 {sytext:"w\0", count:30, code:WordMid},
553 {sytext:"rdr", count:31, code:WordMid},
554 {sytext:"lm\0", count:31, code:WordMid},
555 {sytext:"nl\0", count:33, code:WordMid},
556 {sytext:"dg\0", count:33, code:WordMid},
557 {sytext:"rm\0", count:34, code:WordMid},
558 {sytext:"ln\0", count:35, code:WordMid},
559 {sytext:"nk\0", count:36, code:WordMid},
560 {sytext:"rn\0", count:37, code:WordMid},
561 {sytext:"ght", count:46, code:WordMid},
562 {sytext:"g\0", count:52, code:WordMid},
563 {sytext:"d\0", count:52, code:WordEnd},
564 {sytext:"rhy", count:52, code:WordBeg},
565 {sytext:"rd\0", count:54, code:WordMid},
566 {sytext:"h\0", count:54, code:WordMid},
567 {sytext:"tyr", count:55, code:WordBeg},
568 {sytext:"g\0", count:55, code:WordEnd},
569 {sytext:"c\0", count:56, code:WordEnd},
570 {sytext:"f\0", count:57, code:WordBeg},
571 {sytext:"v\0", count:58, code:WordMid},
572 {sytext:"thr", count:59, code:WordBeg},
573 {sytext:"cyn", count:62, code:WordBeg},
574 {sytext:"zs\0", count:65, code:WordMid},
575 {sytext:"sr\0", count:67, code:WordBeg},
576 {sytext:"dr\0", count:67, code:WordMid},
577 {sytext:"x\0", count:69, code:WordEnd},
578 {sytext:"rch", count:70, code:WordMid},
579 {sytext:"f\0", count:72, code:WordMid},
580 {sytext:"try", count:72, code:WordBeg},
581 {sytext:"dry", count:75, code:WordBeg},
582 {sytext:"rl\0", count:79, code:WordMid},
583 {sytext:"rk\0", count:80, code:WordMid},
584 {sytext:"nr\0", count:81, code:WordMid},
585 {sytext:"tr\0", count:85, code:WordMid},
586 {sytext:"nn\0", count:85, code:WordMid},
587 {sytext:"b\0", count:95, code:WordMid},
588 {sytext:"g\0", count:99, code:WordBeg},
589 {sytext:"z\0", count:110, code:WordBeg},
590 {sytext:"d\0", count:110, code:WordBeg},
591 {sytext:"kr\0", count:111, code:WordBeg},
592 {sytext:"b\0", count:112, code:WordBeg},
593 {sytext:"p\0", count:114, code:WordBeg},
594 {sytext:"q\0", count:114, code:WordBeg},
595 {sytext:"lk\0", count:115, code:WordMid},
596 {sytext:"sky", count:116, code:WordBeg},
597 {sytext:"y\0", count:116, code:WordEnd},
598 {sytext:"sh\0", count:119, code:WordBeg},
599 {sytext:"d\0", count:134, code:WordMid},
600 {sytext:"lr\0", count:136, code:WordMid},
601 {sytext:"c\0", count:149, code:WordMid},
602 {sytext:"ll\0", count:155, code:WordMid},
603 {sytext:"r\0", count:166, code:WordBeg},
604 {sytext:"y\0", count:167, code:WordMid},
605 {sytext:"m\0", count:171, code:WordMid},
606 {sytext:"h\0", count:172, code:WordBeg},
607 {sytext:"k\0", count:173, code:WordBeg},
608 {sytext:"r\0", count:174, code:WordEnd},
609 {sytext:"w\0", count:181, code:WordBeg},
610 {sytext:"c\0", count:187, code:WordBeg},
611 {sytext:"f\0", count:204, code:WordEnd},
612 {sytext:"rr\0", count:222, code:WordMid},
613 {sytext:"t\0", count:224, code:WordEnd},
614 {sytext:"s\0", count:226, code:WordMid},
615 {sytext:"k\0", count:248, code:WordEnd},
616 {sytext:"h\0", count:254, code:WordEnd},
617 {sytext:"j\0", count:260, code:WordBeg},
618 {sytext:"l\0", count:282, code:WordEnd},
619 {sytext:"t\0", count:285, code:WordMid},
620 {sytext:"s\0", count:329, code:WordBeg},
621 {sytext:"k\0", count:332, code:WordMid},
622 {sytext:"l\0", count:476, code:WordBeg},
623 {sytext:"t\0", count:492, code:WordBeg},
624 {sytext:"n\0", count:535, code:WordBeg},
625 {sytext:"l\0", count:536, code:WordMid},
626 {sytext:"m\0", count:586, code:WordBeg},
627 {sytext:"n\0", count:780, code:WordMid},
628 {sytext:"r\0", count:795, code:WordMid},
629 {sytext:"s\0", count:903, code:WordEnd},
630 {sytext:"n\0", count:1723, code:WordEnd},
632 sylls[0] = swSyllsV.dup;
633 sylls[1] = swSyllsC.dup;
634 totals = [11979, 16732];
637 bool checkCorrectness() () const @safe nothrow @nogc {
638 foreach (immutable aidx; 0..sylls.length) {
639 if (sylls[aidx].length < 1 || sylls[aidx].length > 0xffff) {
640 //assert(0);
641 return false;
643 if (totals[aidx] < 1 || totals[aidx] > 0x00ff_ffffu) {
644 //assert(0);
645 return false;
647 ubyte hasCodes = 0;
648 foreach (immutable sy; sylls[aidx]) {
649 if (sy.code < 1 || sy.code > 7 || sy.sytext[0] == 0) {
650 //assert(0);
651 return false;
653 hasCodes |= sy.code;
655 if (hasCodes != (WordBeg|WordMid|WordEnd)) {
656 //assert(0);
657 return false;
660 return true;
663 void clear () @safe nothrow @nogc {
664 sylls[0] = sylls[1] = null;
665 totals[0] = totals[1] = 0;
668 string next (int minsyl=2, int maxsyl=8) const @trusted nothrow
669 in {
670 assert(minsyl > 0);
671 assert(maxsyl > 0);
672 assert(minsyl <= maxsyl);
674 body {
675 auto leng = rand(minsyl, maxsyl);
676 uint iscons = rand(0, 1);
677 auto res = new char[](leng*3);
678 usize respos = 0;
679 foreach (immutable i; 0..leng) {
680 // WARNING: may hang if no termination vowel/consonants are present
681 const(Syllable)* sy = null;
682 while (sy is null) {
683 uint count = rand(1, totals[iscons]);
684 //try { writefln("count=%s, total=%s", count, totals[iscons]); } catch (Exception) {}
685 foreach (immutable idx; 0..sylls[iscons].length) {
686 auto cc = sylls[iscons][idx].count;
687 if (count > cc) {
688 count -= cc;
689 } else {
690 sy = &sylls[iscons][idx];
691 break;
694 if (sy is null) assert(0, "internal error");
695 ubyte cde = WordMid;
696 if (i == 0) cde = WordBeg;
697 else if (i == leng-1) cde = WordEnd;
698 if ((sy.code&cde) == 0) sy = null;
700 // add the syllable
701 foreach (immutable char ch; sy.sytext) {
702 if (ch == 0) break;
703 res[respos++] = ch;
705 iscons = 1-iscons;
708 assert(respos > 0);
709 if (res[0] >= 'a' && res[0] <= 'z') res[0] -= 32;
710 return cast(string)res[0..respos];
714 // ////////////////////////////////////////////////////////////////////////// //
715 private void parseText() (const(char)[] text) {
716 enum MaxSyllableLen = 2;
717 static assert(MaxSyllableLen > 0 && MaxSyllableLen < Syllable.sytext.length, "invalid max syllable length");
719 static usize isvowel() (immutable char ch) {
720 return
721 ((ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') ||
722 (ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') ? Vowel : Consonant);
725 static bool isalpha() (immutable char ch) {
726 return
727 (ch >= 'A' && ch <= 'Z') ||
728 (ch >= 'a' && ch <= 'z');
731 while (text.length > 0) {
732 // get next word
733 usize pos = 0;
734 while (pos < text.length && !isalpha(text[pos])) ++pos;
735 if (pos >= text.length) break;
736 text = text[pos..$];
737 pos = 1;
738 while (pos < text.length && isalpha(text[pos])) ++pos;
739 auto word = text[0..pos];
740 text = text[pos..$];
741 //writeln("[", word, "]");
742 // process word
743 Syllable sy;
744 sy.code = WordBeg;
745 sy.count = 1;
746 while (word.length > 0) {
747 // get syllable
748 auto vowel = isvowel(word[0]);
749 pos = 1;
750 while (pos < word.length && pos < MaxSyllableLen && isvowel(word[pos]) == vowel) ++pos;
751 if (pos == word.length) sy.code |= WordEnd;
752 sy.sytext[] = 0; // clear array
753 sy.sytext[0..pos] = word[0..pos]; // copy syllable
754 foreach (ref ch; sy.sytext) if (ch >= 'A' && ch <= 'Z') ch += 32;
755 //{ import std.conv : to; writeln("SYL: [", to!string(sy.sytext.ptr), "]"); }
756 // add/fix syllable info
757 if (totals[vowel] >= 0x00ff_ffffu) throw new Exception("too many syllables");
758 ++totals[vowel];
759 bool doAdd = true;
760 foreach (ref sx; sylls[vowel]) {
761 import core.stdc.string : strcmp;
762 if (sy.code == sx.code && strcmp(sy.sytext.ptr, sx.sytext.ptr) == 0) {
763 ++sx.count;
764 doAdd = false;
765 break;
768 if (doAdd) sylls[vowel] ~= sy;
769 // next syllable
770 sy.code = WordMid;
771 word = word[pos..$];
776 public void loadText() (const(char)[] text) {
777 import std.algorithm : sort;
778 clear();
779 scope(failure) clear();
780 parseText(text);
781 if (!checkCorrectness()) throw new Exception("incorrect resulting set");
782 foreach (immutable idx; 0..sylls.length) sort!((ref a, ref b) => a.count < b.count)(sylls[idx]);
785 void saveToStream(ST) (auto ref ST fo) if (isWriteableStream!ST) {
786 fo.rawWriteExact("SYLLDATA");
787 fo.writeNum!ubyte(0); // version
788 foreach (immutable aidx; 0..sylls.length) {
789 fo.writeNum!ushort(cast(ushort)sylls[aidx].length); // count
790 foreach (immutable sy; sylls[aidx]) {
791 fo.writeNum!ubyte(cast(ubyte)sy.str.length);
792 fo.rawWriteExact(sy.str);
793 uint cc = sy.count|(sy.code<<24);
794 fo.writeNum!uint(cc);
799 void loadFromStream(ST) (auto ref ST st) if (isReadableStream!ST) {
800 clear();
801 scope(failure) clear();
802 char[8] sign = void;
803 st.rawReadExact(sign);
804 if (sign != "SYLLDATA") throw new Exception("invalid signature");
805 if (st.readNum!ubyte() != 0) throw new Exception("invalid version");
806 foreach (immutable aidx; 0..sylls.length) {
807 auto len = st.readNum!ushort();
808 if (len < 1) throw new Exception("invalid length");
809 sylls[aidx].length = len;
810 foreach (ref sy; sylls[aidx]) {
811 auto slen = st.readNum!ubyte();
812 if (slen < 1 || slen > 3) throw new Exception("invalid syllable length");
813 sy.sytext[] = 0;
814 st.rawReadExact(sy.sytext[0..slen]);
815 uint cc = st.readNum!uint();
816 sy.code = (cc>>24)&0xff;
817 if (sy.code < 1 || sy.code > 7) throw new Exception("invalid syllable code");
818 sy.count = cc&0x00ff_ffffu;
819 if (sy.count < 1) throw new Exception("invalid syllable count");
820 uint ntot = cast(uint)(totals[aidx]+sy.count);
821 if (ntot <= totals[aidx] || ntot > 0x00ff_ffffu) throw new Exception("invalid syllable total");
822 totals[aidx] = ntot;
825 if (!checkCorrectness()) throw new Exception("invalid syllable data");
828 string infoStr() () const {
829 import std.string;
830 return format("%s vowels and %s consonants grouped into {%s, %s} rules", totals[Vowel], totals[Consonant], sylls[Vowel].length, sylls[Consonant].length);
833 debug {
834 import std.stdio : File;
835 void dumpToFile (File fo, string name="table") {
836 fo.writeln(" // [", totals[0], ", ", totals[1], "]");
837 foreach (immutable sidx; 0..sylls.length) {
838 fo.writeln(" static immutable Syllable[", sylls[sidx].length, "] ", name, (sidx ? "C" : "V"), " = [");
839 foreach (immutable sy; sylls[sidx]) {
840 string s = sy.str;
841 if (s.length < 3) s ~= `\0`;
842 fo.writeln(" {sytext:\"", s, "\", count:", sy.count, ", code:", sy.codeStr, "},");
844 fo.writeln(" ];");
851 version(test_namegen)
852 unittest {
853 import std.stdio;
854 auto ng = NameGen();
855 //ng.loadFromStream(File("names.syl"));
856 //ng.loadText(readText("names.txt"));
857 //ng.saveToStream(File("names.syl", "w"));
858 writeln("==========="); foreach (immutable _; 0..10) writeln(ng.next, " ", ng.next);
859 ng.setSW();
860 writeln("==========="); foreach (immutable _; 0..10) writeln(ng.next, " ", ng.next);
861 ng.setTotro();
862 writeln("==========="); foreach (immutable _; 0..10) writeln(ng.next, " ", ng.next);