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