1 /// People name generator
2 module namegen.people;
3 
4 struct Name
5 {
6     string first;
7     string last;
8 
9     string full() const
10     {
11         return first~" "~last;
12     }
13 
14     alias full this;
15 }
16 
17 Name createName(bool isFemale = false)
18 {
19     Name ret;
20 
21     ret.first = selectName(isFemale ? femaleFirst : maleFirst);
22     ret.last = selectName(lastNames);
23 
24     return ret;
25 }
26 
27 unittest
28 {
29     assert(createName(false) == "Kevin Toll");
30     assert(createName(false) == "Rob Price");
31 
32     assert(createName(true) == "Erika Ressler");
33     assert(createName(true) == "Sally Coe");
34 
35     // It is to reset RNDG to initial value
36     rndg = Random(42);
37 }
38 
39 private:
40 
41 import std.random;
42 
43 auto rndg = Random(42);
44 
45 string selectName(in NameRecord[] names)
46 {
47     enum cumMax = 90.5f;
48 
49     assert(names[$-1].cumulative < cumMax);
50 
51     float selected = uniform(0.0f, cumMax, rndg);
52 
53     foreach(const ref n; names)
54     {
55         if(n.cumulative > selected)
56             return n.name;
57     }
58 
59     assert(false);
60 }
61 
62 struct NameRecord
63 {
64     import std.string: isNumeric, capitalize;
65     import std.conv: to;
66 
67     string name;
68     float cumulative;
69 
70     this(string[] a)
71     {
72         assert(a.length == 4);
73         assert(a[1].isNumeric);
74         assert(a[2].isNumeric);
75         assert(a[3].isNumeric);
76 
77         name = a[0].capitalize;
78         cumulative = a[2].to!float;
79 
80         assert(cumulative > 0);
81     }
82 }
83 
84 // Compile time parsing for big text files is too slow by now, therefore this function is unused
85 NameRecord[] getNamesRecordsCTFE(string filename)()
86 {
87     enum text = import(filename);
88 
89     return getNamesRecordsFromText(text);
90 }
91 
92 NameRecord[] getNamesRecordsFromText(string text)
93 {
94     string line;
95     NameRecord[] recs;
96 
97     foreach(c; text)
98     {
99         if(c != '\n')
100         {
101             line ~= c;
102         }
103         else
104         {
105             import std.array: split;
106 
107             recs ~= NameRecord(line.split);
108             line.length = 0;
109         }
110     }
111 
112     return recs;
113 }
114 
115 const NameRecord[] maleFirst;
116 const NameRecord[] femaleFirst;
117 const NameRecord[] lastNames;
118 
119 static this()
120 {
121     immutable maleFirstTextLines = import("dist.male.first");
122     immutable femaleFirstLines = import("dist.female.first");
123     immutable lastTextLines = import("dist.all.last");
124 
125     maleFirst = getNamesRecordsFromText(maleFirstTextLines);
126     femaleFirst = getNamesRecordsFromText(femaleFirstLines);
127     lastNames = getNamesRecordsFromText(lastTextLines);
128 }
129 
130 unittest
131 {
132     assert(maleFirst[0].name == "James", maleFirst[0].name);
133     assert(maleFirst[1218].name == "Alonso", maleFirst[1218].name);
134 }