001package squidpony; 002 003import regexodus.MatchResult; 004import regexodus.Matcher; 005import regexodus.Pattern; 006import regexodus.Replacer; 007import squidpony.squidmath.CrossHash; 008import squidpony.squidmath.RNG; 009import squidpony.squidmath.StatefulRNG; 010 011import java.io.Serializable; 012import java.util.*; 013 014/** 015 * A text generator for producing sentences and/or words in nonsense languages that fit a theme. This does not use an 016 * existing word list as a basis for its output, so it may or may not produce existing words occasionally, but you can 017 * safely assume it won't generate a meaningful sentence except in the absolute unlikeliest of cases. 018 * Created by Tommy Ettinger on 11/29/2015. 019 * @author Tommy Ettinger 020 */ 021 022public class FakeLanguageGen implements Serializable { 023 private static final long serialVersionUID = -2396642435461186352L; 024 public final String[] openingVowels, midVowels, openingConsonants, midConsonants, closingConsonants, 025 vowelSplitters, closingSyllables; 026 public boolean clean; 027 public final LinkedHashMap<Integer, Double> syllableFrequencies; 028 protected double totalSyllableFrequency = 0.0; 029 public final double vowelStartFrequency, vowelEndFrequency, vowelSplitFrequency, syllableEndFrequency; 030 public final Pattern[] sanityChecks; 031 public ArrayList<Modifier> modifiers; 032 public static final StatefulRNG srng = new StatefulRNG(); 033 static final Pattern repeats = Pattern.compile("(.)\\1+"); 034 //, diacritics = Pattern.compile("[\u0300-\u036F\u1DC0-\u1DFF]+"); 035 static final Pattern[] 036 vulgarChecks = new Pattern[] 037 { 038 Pattern.compile("[SsξCcсςС][hнН].*[dtтτТΤ]"), 039 Pattern.compile("([PpрρРΡ][hнН])|[KkкκКΚFfDdCcсςСQq].{1,4}[KkкκКΚCcсςСxхжχХЖΧQq]"), // lots of these end in a 'k' sound, huh 040 Pattern.compile("[BbъыбвβЪЫБВΒ]..?.?[cсςС][hнН]"), 041 Pattern.compile("[WwшщψШЩHhнН]..?[rяЯ]"), 042 Pattern.compile("[TtтτТΤ]..?[tтτТΤ]"), 043 Pattern.compile("([PpрρРΡ][hнН])|[Ff]..?[rяЯ][tтτТΤ]"), 044 Pattern.compile("([Ssξ][hнН])[iτιΙ].?[sξzΖ]"), 045 Pattern.compile("[AaаαАΑΛ][NnийИЙΝ]..?[SsξlιζzΖ]"), 046 Pattern.compile("[AaаαАΑΛ][sξ][sξ]"), 047 Pattern.compile(".[uμυν][hнН]?[nийИЙΝ]+[tтτТΤ]"), 048 Pattern.compile("[NnFf]..?g"), // might as well remove two possible slurs with one check 049 Pattern.compile("[PpрρРΡ][eеёзξεЕЁЗΞΕΣioоюσοОЮΟuμυν][eеёзξεЕЁЗΞΕΣoоюσοОЮΟs]"), // the grab bag of juvenile words 050 Pattern.compile("[MmмМΜ]..?[rяЯ].?d"), // should pick up the #1 obscenity from Spanish and French 051 Pattern.compile("[Gg][HhнН]?[aаαАΑΛeеёзξεЕЁЗΞΕΣ][yуλγУΥeеёзξεЕЁЗΞΕΣ]") // could be inappropriate for random text 052 }, 053 englishSanityChecks = new Pattern[] 054 { 055 Pattern.compile("[AEIOUaeiou]{3}"), 056 Pattern.compile("(\\w)\\1\\1"), 057 Pattern.compile("(.)\\1(.)\\2"), 058 Pattern.compile("[Aa][ae]"), 059 Pattern.compile("[Uu][umlkj]"), 060 Pattern.compile("[Ii][iyqkhrl]"), 061 Pattern.compile("[Oo][c]"), 062 Pattern.compile("[Yy][aeiou]{2}"), 063 Pattern.compile("[Rr][aeiouy]+[xrhp]"), 064 Pattern.compile("[Qq]u[yu]"), 065 Pattern.compile("[^oai]uch"), 066 Pattern.compile("[^tcsz]hh"), 067 Pattern.compile("[Hh][tcszi]h"), 068 Pattern.compile("[Tt]t[^aeiouy]{2}"), 069 Pattern.compile("[IYiy]h[^aeiouy ]"), 070 Pattern.compile("[szSZrlRL][^aeiou][rlsz]"), 071 Pattern.compile("[UIuiYy][wy]"), 072 Pattern.compile("^[UIui][ae]"), 073 Pattern.compile("q$") 074 }, 075 japaneseSanityChecks = new Pattern[] 076 { 077 Pattern.compile("[AEIOUaeiou]{3}"), 078 Pattern.compile("(\\w)\\1\\1"), 079 Pattern.compile("[Tt]s[^u]"), 080 Pattern.compile("[Ff][^u]"), 081 Pattern.compile("[Yy][^auo]"), 082 Pattern.compile("[Tt][ui]"), 083 Pattern.compile("[SsZzDd]i"), 084 Pattern.compile("[Hh]u"), 085 }, 086 arabicSanityChecks = new Pattern[] 087 { 088 Pattern.compile("(\\w)\\1\\1"), 089 Pattern.compile("-[^aeiou]{2}"), 090 }; 091 static final Replacer[] 092 accentFinders = new Replacer[] 093 { 094 Pattern.compile("[àáâãäåæāăąǻǽ]").replacer("a"), 095 Pattern.compile("[èéêëēĕėęě]").replacer("e"), 096 Pattern.compile("[ìíîïĩīĭįı]").replacer("i"), 097 Pattern.compile("[òóôõöøōŏőœǿ]").replacer("o"), 098 Pattern.compile("[ùúûüũūŭůűų]").replacer("u"), 099 Pattern.compile("[ÀÁÂÃÄÅÆĀĂĄǺǼ]").replacer("A"), 100 Pattern.compile("[ÈÉÊËĒĔĖĘĚ]").replacer("E"), 101 Pattern.compile("[ÌÍÎÏĨĪĬĮI]").replacer("I"), 102 Pattern.compile("[ÒÓÔÕÖØŌŎŐŒǾ]").replacer("O"), 103 Pattern.compile("[ÙÚÛÜŨŪŬŮŰŲ]").replacer("U"), 104 Pattern.compile("[çćĉċč]").replacer("c"), 105 Pattern.compile("[þðďđḍ]").replacer("d"), 106 Pattern.compile("[ĝğġģ]").replacer("g"), 107 Pattern.compile("[ĥħḥ]").replacer("h"), 108 Pattern.compile("[ĵȷ]").replacer("j"), 109 Pattern.compile("ķ").replacer("k"), 110 Pattern.compile("[ĺļľŀłḷḹļ]").replacer("l"), 111 Pattern.compile("ṃ").replacer("m"), 112 Pattern.compile("[ñńņňŋṅṇ]").replacer("n"), 113 Pattern.compile("[ŕŗřṛṝŗŕ]").replacer("r"), 114 Pattern.compile("[śŝşšșṣ]").replacer("s"), 115 Pattern.compile("[ţťŧțṭ]").replacer("t"), 116 Pattern.compile("[ŵẁẃẅ]").replacer("w"), 117 Pattern.compile("[ýÿŷỳ]").replacer("y"), 118 Pattern.compile("[źżž]").replacer("z"), 119 Pattern.compile("[ÇĆĈĊČ]").replacer("C"), 120 Pattern.compile("[ÞÐĎĐḌ]").replacer("D"), 121 Pattern.compile("[ĜĞĠĢ]").replacer("G"), 122 Pattern.compile("[ĤĦḤ]").replacer("H"), 123 Pattern.compile("Ĵ").replacer("J"), 124 Pattern.compile("Ķ").replacer("K"), 125 Pattern.compile("[ĹĻĽĿŁḶḸĻ]").replacer("L"), 126 Pattern.compile("Ṃ").replacer("M"), 127 Pattern.compile("[ÑŃŅŇŊṄṆ]").replacer("N"), 128 Pattern.compile("[ŔŖŘṚṜŖŔ]").replacer("R"), 129 Pattern.compile("[ŚŜŞŠȘṢ]").replacer("S"), 130 Pattern.compile("[ŢŤŦȚṬ]").replacer("T"), 131 Pattern.compile("[ŴẀẂẄ]").replacer("W"), 132 Pattern.compile("[ÝŸŶỲ]").replacer("Y"), 133 Pattern.compile("[ŹŻŽ]").replacer("Z"), 134 135 }; 136 137 static final char[][] accentedVowels = new char[][]{ 138 new char[]{ 139 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ā', 'ă', 'ą', 'ǻ', 'ǽ' 140 }, 141 new char[]{ 142 'è', 'é', 'ê', 'ë', 'ē', 'ĕ', 'ė', 'ę', 'ě' 143 }, 144 new char[]{ 145 'ì', 'í', 'î', 'ï', 'ĩ', 'ī', 'ĭ', 'į', 'ı', 146 }, 147 new char[]{ 148 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ō', 'ŏ', 'ő', 'œ', 'ǿ' 149 }, 150 new char[]{ 151 'ù', 'ú', 'û', 'ü', 'ũ', 'ū', 'ŭ', 'ů', 'ű', 'ų' 152 } 153 }, 154 accentedConsonants = new char[][] 155 { 156 new char[]{ 157 'b' 158 }, 159 new char[]{ 160 'c', 'ç', 'ć', 'ĉ', 'ċ', 'č', 161 }, 162 new char[]{ 163 'd', 'þ', 'ð', 'ď', 'đ', 164 }, 165 new char[]{ 166 'f' 167 }, 168 new char[]{ 169 'g', 'ĝ', 'ğ', 'ġ', 'ģ', 170 }, 171 new char[]{ 172 'h', 'ĥ', 'ħ', 173 }, 174 new char[]{ 175 'j', 'ĵ', 'ȷ', 176 }, 177 new char[]{ 178 'k', 'ķ', 179 }, 180 new char[]{ 181 'l', 'ĺ', 'ļ', 'ľ', 'ŀ', 'ł', 182 }, 183 new char[]{ 184 'm', 185 }, 186 new char[]{ 187 'n', 'ñ', 'ń', 'ņ', 'ň', 'ŋ', 188 }, 189 new char[]{ 190 'p', 191 }, 192 new char[]{ 193 'q', 194 }, 195 new char[]{ 196 'r', 'ŕ', 'ŗ', 'ř', 197 }, 198 new char[]{ 199 's', 'ś', 'ŝ', 'ş', 'š', 'ș', 200 }, 201 new char[]{ 202 't', 'ţ', 'ť', 'ț', 203 }, 204 new char[]{ 205 'v', 206 }, 207 new char[]{ 208 'w', 'ŵ', 'ẁ', 'ẃ', 'ẅ', 209 }, 210 new char[]{ 211 'x', 212 }, 213 new char[]{ 214 'y', 'ý', 'ÿ', 'ŷ', 'ỳ', 215 }, 216 new char[]{ 217 'z', 'ź', 'ż', 'ž', 218 }, 219 }; 220 221 /* 222 * Removes accented characters from a string; if the "base" characters are non-English anyway then the result won't 223 * be an ASCII string, but otherwise it probably will be. 224 * <br> 225 * Credit to user hashable from http://stackoverflow.com/a/1215117 226 * 227 * @param str a string that may contain accented characters 228 * @return a string with all accented characters replaced with their (possibly ASCII) counterparts 229 * 230 public String removeAccents(String str) { 231 String alteredString = Normalizer.normalize(str, Normalizer.Form.NFD); 232 alteredString = diacritics.matcher(alteredString).replaceAll(""); 233 alteredString = alteredString.replace('æ', 'a'); 234 alteredString = alteredString.replace('œ', 'o'); 235 alteredString = alteredString.replace('Æ', 'A'); 236 alteredString = alteredString.replace('Œ', 'O'); 237 return alteredString; 238 }*/ 239 240 /** 241 * Removes accented Latin-script characters from a string; if the "base" characters are non-English anyway then the 242 * result won't be an ASCII string, but otherwise it probably will be. 243 * 244 * @param str a string that may contain accented Latin-script characters 245 * @return a string with all accented characters replaced with their (possibly ASCII) counterparts 246 */ 247 public CharSequence removeAccents(CharSequence str) { 248 CharSequence alteredString = str; 249 for (int i = 0; i < accentFinders.length; i++) { 250 alteredString = accentFinders[i].replace(alteredString); 251 } 252 return alteredString; 253 } 254 255 256 /** 257 * Ia! Ia! Cthulhu Rl'yeh ftaghn! Useful for generating cultist ramblings or unreadable occult texts. 258 * <br> 259 * Zvrugg pialuk, ya'as irlemrugle'eith iposh hmo-es nyeighi, glikreirk shaivro'ei! 260 */ 261 public static final FakeLanguageGen LOVECRAFT = new FakeLanguageGen( 262 new String[]{"a", "i", "o", "e", "u", "a", "i", "o", "e", "u", "ia", "ai", "aa", "ei"}, 263 new String[]{}, 264 new String[]{"s", "t", "k", "n", "y", "p", "k", "l", "g", "gl", "th", "sh", "ny", "ft", "hm", "zvr", "cth"}, 265 new String[]{"h", "gl", "gr", "nd", "mr", "vr", "kr"}, 266 new String[]{"l", "p", "s", "t", "n", "k", "g", "x", "rl", "th", "gg", "gh", "ts", "lt", "rk", "kh", "sh", "ng", "shk"}, 267 new String[]{"aghn", "ulhu", "urath", "oigor", "alos", "'yeh", "achtal", "urath", "ikhet", "adzek"}, 268 new String[]{"'", "-"}, new int[]{1, 2, 3}, new double[]{6, 7, 2}, 0.4, 0.31, 0.07, 0.04, null, true); 269 /** 270 * Imitation English; may seem closer to Dutch in some generated text, and is not exactly the best imitation. 271 * Should seem pretty fake to many readers; does not filter out dictionary words but does perform basic vulgarity 272 * filtering. If you want to avoid generating other words, you can subclass FakeLanguageGen and modify word() . 273 * <br> 274 * Mont tiste frot; mousation hauddes? 275 * Lily wrely stiebes; flarrousseal gapestist. 276 */ 277 public static final FakeLanguageGen ENGLISH = new FakeLanguageGen( 278 new String[]{ 279 "a", "a", "a", "a", "o", "o", "o", "e", "e", "e", "e", "e", "i", "i", "i", "i", "u", 280 "a", "a", "a", "a", "o", "o", "o", "e", "e", "e", "e", "e", "i", "i", "i", "i", "u", 281 "a", "a", "a", "o", "o", "e", "e", "e", "i", "i", "i", "u", 282 "a", "a", "a", "o", "o", "e", "e", "e", "i", "i", "i", "u", 283 "au", "ai", "ai", "ou", "ea", "ie", "io", "ei", 284 }, 285 new String[]{"u", "u", "oa", "oo", "oo", "oo", "ee", "ee", "ee", "ee",}, 286 new String[]{ 287 "b", "bl", "br", "c", "cl", "cr", "ch", "d", "dr", "f", "fl", "fr", "g", "gl", "gr", "h", "j", "k", "l", "m", "n", 288 "p", "pl", "pr", "qu", "r", "s", "sh", "sk", "st", "sp", "sl", "sm", "sn", "t", "tr", "th", "thr", "v", "w", "y", "z", 289 "b", "bl", "br", "c", "cl", "cr", "ch", "d", "dr", "f", "fl", "fr", "g", "gr", "h", "j", "k", "l", "m", "n", 290 "p", "pl", "pr", "r", "s", "sh", "st", "sp", "sl", "t", "tr", "th", "w", "y", 291 "b", "br", "c", "ch", "d", "dr", "f", "g", "h", "j", "l", "m", "n", 292 "p", "r", "s", "sh", "st", "sl", "t", "tr", "th", 293 "b", "d", "f", "g", "h", "l", "m", "n", 294 "p", "r", "s", "sh", "t", "th", 295 "b", "d", "f", "g", "h", "l", "m", "n", 296 "p", "r", "s", "sh", "t", "th", 297 "r", "s", "t", "l", "n", 298 "str", "spr", "spl", "wr", "kn", "kn", "gn", 299 }, 300 new String[]{"x", "cst", "bs", "ff", "lg", "g", "gs", 301 "ll", "ltr", "mb", "mn", "mm", "ng", "ng", "ngl", "nt", "ns", "nn", "ps", "mbl", "mpr", 302 "pp", "ppl", "ppr", "rr", "rr", "rr", "rl", "rtn", "ngr", "ss", "sc", "rst", "tt", "tt", "ts", "ltr", "zz" 303 }, 304 new String[]{"b", "rb", "bb", "c", "rc", "ld", "d", "ds", "dd", "f", "ff", "lf", "rf", "rg", "gs", "ch", "lch", "rch", "tch", 305 "ck", "ck", "lk", "rk", "l", "ll", "lm", "m", "rm", "mp", "n", "nk", "nch", "nd", "ng", "ng", "nt", "ns", "lp", "rp", 306 "p", "r", "rn", "rts", "s", "s", "s", "s", "ss", "ss", "st", "ls", "t", "t", "ts", "w", "wn", "x", "ly", "lly", "z", 307 "b", "c", "d", "f", "g", "k", "l", "m", "n", "p", "r", "s", "t", "w", 308 }, 309 new String[]{"ate", "ite", "ism", "ist", "er", "er", "er", "ed", "ed", "ed", "es", "es", "ied", "y", "y", "y", "y", 310 "ate", "ite", "ism", "ist", "er", "er", "er", "ed", "ed", "ed", "es", "es", "ied", "y", "y", "y", "y", 311 "ate", "ite", "ism", "ist", "er", "er", "er", "ed", "ed", "ed", "es", "es", "ied", "y", "y", "y", "y", 312 "ay", "ay", "ey", "oy", "ay", "ay", "ey", "oy", 313 "ough", "aught", "ant", "ont", "oe", "ance", "ell", "eal", "oa", "urt", "ut", "iom", "ion", "ion", "ision", "ation", "ation", "ition", 314 "ough", "aught", "ant", "ont", "oe", "ance", "ell", "eal", "oa", "urt", "ut", "iom", "ion", "ion", "ision", "ation", "ation", "ition", 315 "ily", "ily", "ily", "adly", "owly", "oorly", "ardly", "iedly", 316 }, 317 new String[]{}, new int[]{1, 2, 3, 4}, new double[]{7, 8, 4, 1}, 0.22, 0.1, 0.0, 0.25, englishSanityChecks, true); 318 /** 319 * Imitation ancient Greek, romanized to use the Latin alphabet. Likely to seem pretty fake to many readers. 320 * <br> 321 * Psuilas alor; aipeomarta le liaspa... 322 */ 323 public static final FakeLanguageGen GREEK_ROMANIZED = new FakeLanguageGen( 324 new String[]{"a", "a", "a", "o", "o", "o", "e", "e", "i", "i", "i", "au", "ai", "ai", "oi", "oi", "ia", "io", "ou", "ou", "eo", "ei"}, 325 new String[]{"ui", "ei"}, 326 new String[]{"rh", "s", "z", "t", "t", "k", "ch", "n", "th", "kth", "m", "p", "ps", "b", "l", "kr", "g", "phth"}, 327 new String[]{"lph", "pl", "l", "l", "kr", "nch", "nx", "ps"}, 328 new String[]{"s", "p", "t", "ch", "n", "m", "s", "p", "t", "ch", "n", "m", "b", "g", "st", "rst", "rt", "sp", "rk", "ph", "x", "z", "nk", "ng", "th"}, 329 new String[]{"os", "os", "is", "us", "um", "eum", "ium", "iam", "us", "um", "es", "anes", "eros", "or", "ophon", "on", "otron"}, 330 new String[]{}, new int[]{1, 2, 3}, new double[]{5, 7, 4}, 0.45, 0.45, 0.0, 0.3, null, true); 331 /** 332 * Imitation ancient Greek, using the original Greek alphabet. People may try to translate it and get gibberish. 333 * Make sure the font you use to render this supports the Greek alphabet! In the GDX display module, the "smooth" 334 * fonts support all the Greek you need for this. 335 * <br> 336 * Ψυιλασ αλορ; αιπεομαρτα λε λιασπα... 337 */ 338 public static final FakeLanguageGen GREEK_AUTHENTIC = new FakeLanguageGen( 339 new String[]{"α", "α", "α", "ο", "ο", "ο", "ε", "ε", "ι", "ι", "ι", "αυ", "αι", "αι", "οι", "οι", "ια", "ιο", "ου", "ου", "εο", "ει"}, 340 new String[]{"υι", "ει"}, 341 new String[]{"ρ", "σ", "ζ", "τ", "τ", "κ", "χ", "ν", "θ", "κθ", "μ", "π", "ψ", "β", "λ", "κρ", "γ", "φθ"}, 342 new String[]{"λφ", "πλ", "λ", "λ", "κρ", "γχ", "γξ", "ψ"}, 343 new String[]{"σ", "π", "τ", "χ", "ν", "μ", "σ", "π", "τ", "χ", "ν", "μ", "β", "γ", "στ", "ρστ", "ρτ", "σπ", "ρκ", "φ", "ξ", "ζ", "γκ", "γγ", "θ"}, 344 new String[]{"ος", "ος", "ις", "υς", "υμ", "ευμ", "ιυμ", "ιαμ", "υς", "υμ", "ες", "ανες", "ερος", "ορ", "οφον", "ον", "οτρον"}, 345 new String[]{}, new int[]{1, 2, 3}, new double[]{5, 7, 4}, 0.45, 0.45, 0.0, 0.3, null, true); 346 347 /** 348 * Imitation modern French, using (too many of) the accented vowels that are present in the language. Translating it 349 * will produce gibberish if it produces anything at all. In the GDX display module, the "smooth" and "unicode" 350 * fonts support all the accented characters you need for this. 351 * <br><br> 352 * Fa veau, ja ri avé re orçe jai braï aisté. 353 */ 354 public static final FakeLanguageGen FRENCH = new FakeLanguageGen( 355 new String[]{"a", "a", "a", "e", "e", "e", "i", "i", "o", "u", "a", "a", "a", "e", "e", "e", "i", "i", "o", 356 "a", "a", "a", "e", "e", "e", "i", "i", "o", "u", "a", "a", "a", "e", "e", "e", "i", "i", "o", 357 "a", "a", "e", "e", "i", "o", "a", "a", "a", "e", "e", "e", "i", "i", "o", 358 "ai", "oi", "oui", "au", "œu", "ou" 359 }, 360 new String[]{ 361 "ai", "aie", "aou", "eau", "oi", "oui", "oie", "eu", "eu", 362 "à", "â", "ai", "aî", "aï", "aie", "aou", "aoû", "au", "ay", "e", "é", "ée", "è", 363 "ê", "eau", "ei", "eî", "eu", "eû", "i", "î", "ï", "o", "ô", "oe", "oê", "oë", "œu", 364 "oi", "oie", "oï", "ou", "oû", "oy", "u", "û", "ue", 365 "a", "a", "a", "e", "e", "e", "i", "i", "o", "u", "a", "a", "a", "e", "e", "e", "i", "i", "o", 366 "a", "a", "e", "e", "i", "o", "a", "a", "a", "e", "e", "e", "i", "i", "o", 367 }, 368 new String[]{"tr", "ch", "m", "b", "b", "br", "j", "j", "j", "j", "g", "t", "t", "t", "c", "d", "f", "f", "h", "n", "l", "l", 369 "s", "s", "s", "r", "r", "r", "v", "v", "p", "pl", "pr", "bl", "br", "dr", "gl", "gr"}, 370 new String[]{"cqu", "gu", "qu", "rqu", "nt", "ng", "ngu", "mb", "ll", "nd", "ndr", "nct", "st", 371 "xt", "mbr", "pl", "g", "gg", "ggr", "gl", 372 "m", "m", "mm", "v", "v", "f", "f", "f", "ff", "b", "b", "bb", "d", "d", "dd", "s", "s", "s", "ss", "ss", "ss", 373 "cl", "cr", "ng", "ç", "ç", "rç"}, 374 new String[]{}, 375 new String[]{"e", "e", "e", "e", "e", "é", "é", "er", "er", "er", "er", "er", "es", "es", "es", "es", "es", "es", 376 "e", "e", "e", "e", "e", "é", "é", "er", "er", "er", "er", "er", "er", "es", "es", "es", "es", "es", 377 "e", "e", "e", "e", "e", "é", "é", "é", "er", "er", "er", "er", "er", "es", "es", "es", "es", "es", 378 "ent", "em", "en", "en", "aim", "ain", "an", "oin", "ien", "iere", "ors", "anse", 379 "ombs", "ommes", "ancs", "ends", "œufs", "erfs", "ongs", "aps", "ats", "ives", "ui", "illes", 380 "aen", "aon", "am", "an", "eun", "ein", "age", "age", "uile", "uin", "um", "un", "un", "un", 381 "aille", "ouille", "eille", "ille", "eur", "it", "ot", "oi", "oi", "oi", "aire", "om", "on", "on", 382 "im", "in", "in", "ien", "ien", "ion", "il", "eil", "oin", "oint", "iguïté", "ience", "incte", 383 "ang", "ong", "acré", "eau", "ouche", "oux", "oux", "ect", "ecri", "agne", "uer", "aix", "eth", "ut", "ant", 384 "anc", "anc", "anche", "ioche", "eaux", "ive", "eur", "ancois", "ecois"}, 385 new String[]{}, new int[]{1, 2, 3}, new double[]{18, 7, 2}, 0.35, 1.0, 0.0, 0.55, null, true); 386 387 /** 388 * Imitation modern Russian, romanized to use the Latin alphabet. Likely to seem pretty fake to many readers. 389 * <br> 390 * Zhydotuf ruts pitsas, gogutiar shyskuchebab - gichapofeglor giunuz ieskaziuzhin. 391 */ 392 public static final FakeLanguageGen RUSSIAN_ROMANIZED = new FakeLanguageGen( 393 new String[]{"a", "e", "e", "i", "i", "o", "u", "ie", "y", "e", "iu", "ia", "y", "a", "a", "o", "u"}, 394 new String[]{}, 395 new String[]{"b", "v", "g", "d", "k", "l", "p", "r", "s", "t", "f", "kh", "ts", 396 "b", "v", "g", "d", "k", "l", "p", "r", "s", "t", "f", "kh", "ts", 397 "b", "v", "g", "d", "k", "l", "p", "r", "s", "t", "f", 398 "zh", "m", "n", "z", "ch", "sh", "shch", 399 "br", "sk", "tr", "bl", "gl", "kr", "gr"}, 400 new String[]{"bl", "br", "pl", "dzh", "tr", "gl", "gr", "kr"}, 401 new String[]{"b", "v", "g", "d", "zh", "z", "k", "l", "m", "n", "p", "r", "s", "t", "f", "kh", "ts", "ch", "sh", 402 "v", "f", "sk", "sk", "sk", "s", "b", "d", "d", "n", "r", "r"}, 403 new String[]{"odka", "odna", "usk", "ask", "usky", "ad", "ar", "ovich", "ev", "ov", "of", "agda", "etsky", "ich", "on", "akh", "iev", "ian"}, 404 new String[]{}, new int[]{1, 2, 3, 4, 5, 6}, new double[]{4, 5, 6, 5, 3, 1}, 0.1, 0.2, 0.0, 0.12, englishSanityChecks, true); 405 406 407 /** 408 * Imitation modern Russian, using the authentic Cyrillic alphabet used in Russia and other countries. 409 * Make sure the font you use to render this supports the Cyrillic alphabet! 410 * In the GDX display module, the "smooth" fonts support all the Cyrillic alphabet you need for this. 411 * <br> 412 * Жыдотуф руц пйцас, гогутяр шыскучэбаб - гйчапофёглор гюнуз ъсказюжин. 413 */ 414 public static final FakeLanguageGen RUSSIAN_AUTHENTIC = new FakeLanguageGen( 415 new String[]{"а", "е", "ё", "и", "й", "о", "у", "ъ", "ы", "э", "ю", "я", "ы", "а", "а", "о", "у"}, 416 new String[]{}, 417 new String[]{"б", "в", "г", "д", "к", "л", "п", "р", "с", "т", "ф", "х", "ц", 418 "б", "в", "г", "д", "к", "л", "п", "р", "с", "т", "ф", "х", "ц", 419 "б", "в", "г", "д", "к", "л", "п", "р", "с", "т", "ф", 420 "ж", "м", "н", "з", "ч", "ш", "щ", 421 "бр", "ск", "тр", "бл", "гл", "кр", "гр"}, 422 new String[]{"бл", "бр", "пл", "дж", "тр", "гл", "гр", "кр"}, 423 new String[]{"б", "в", "г", "д", "ж", "з", "к", "л", "м", "н", "п", "р", "с", "т", "ф", "х", "ц", "ч", "ш", 424 "в", "ф", "ск", "ск", "ск", "с", "б", "д", "д", "н", "р", "р"}, 425 new String[]{"одка", "одна", "уск", "аск", "ускы", "ад", "ар", "овйч", "ев", "ов", "оф", "агда", "ёцкы", "йч", "он", "ах", "ъв", "ян"}, 426 new String[]{}, new int[]{1, 2, 3, 4, 5, 6}, new double[]{4, 5, 6, 5, 3, 1}, 0.1, 0.2, 0.0, 0.12, null, true); 427 428 /** 429 * Imitation Japanese, romanized to use the Latin alphabet. Likely to seem pretty fake to many readers. 430 * <br> 431 * Narurehyounan nikase keho... 432 */ 433 public static final FakeLanguageGen JAPANESE_ROMANIZED = new FakeLanguageGen( 434 new String[]{"a", "a", "a", "a", "e", "e", "i", "i", "i", "i", "o", "o", "o", "u", "ou", "u", "ai", "ai"}, 435 new String[]{}, 436 new String[]{"k", "ky", "s", "sh", "t", "ts", "ch", "n", "ny", "h", "f", "hy", "m", "my", "y", "r", "ry", "g", 437 "gy", "z", "j", "d", "b", "by", "p", "py", 438 "k", "t", "n", "s", "k", "t", "d", "s", "sh", "sh", "g", "r", "b", 439 "k", "t", "n", "s", "k", "t", "b", "s", "sh", "sh", "g", "r", "b", 440 "k", "t", "n", "s", "k", "t", "z", "s", "sh", "sh", "ch", "ry", "ts" 441 }, 442 new String[]{"k", "ky", "s", "sh", "t", "ts", "ch", "n", "ny", "h", "f", "hy", "m", "my", "y", "r", "ry", "g", 443 "gy", "z", "j", "d", "b", "by", "p", "py", 444 "k", "t", "d", "s", "k", "t", "d", "s", "sh", "sh", "y", "j", "p", "r", "d", 445 "k", "t", "b", "s", "k", "t", "b", "s", "sh", "sh", "y", "j", "p", "r", "d", 446 "k", "t", "z", "s", "f", "g", "z", "b", "d", "ts", 447 "nn", "nn", "nn", "nd", "nz", "mm", "kk", "kk", "tt", "ss", "ssh", "tch"}, 448 new String[]{"n"}, 449 new String[]{}, 450 new String[]{}, new int[]{1, 2, 3, 4, 5}, new double[]{5, 4, 5, 4, 3}, 0.3, 0.9, 0.0, 0.0, japaneseSanityChecks, true); 451 452 /** 453 * Swahili is one of the more commonly-spoken languages in sub-Saharan Africa, and serves mainly as a shared language 454 * that is often learned after becoming fluent in one of many other (vaguely-similar) languages of the area. An 455 * example sentence in Swahili, that this might try to imitate aesthetically, is "Mtoto mdogo amekisoma," meaning 456 * "The small child reads it" (where it is a book). A notable language feature used here is the redoubling of words, 457 * which is used in Swahili to emphasize or alter the meaning of the doubled word; here, it always repeats exactly 458 * and can't make minor changes like a real language might. This generates things like "gata-gata", "hapi-hapi", and 459 * "mimamzu-mimamzu", always separating with a hyphen here. 460 * <br> 461 * As an aside, please try to avoid the ugly stereotypes that fantasy media often assigns to speakers of African-like 462 * languages when using this or any of the generators. Many fantasy tropes come from older literature written with 463 * major cultural biases, and real-world cultural elements can be much more interesting to players than yet another 464 * depiction of a "jungle savage" with stereotypical traits. Consider drawing from existing lists of real-world 465 * technological discoveries, like https://en.wikipedia.org/wiki/History_of_science_and_technology_in_Africa , for 466 * inspiration when world-building; though some groups may not have developed agriculture by early medieval times, 467 * their neighbors may be working iron and studying astronomy just a short distance away. 468 * <br> 469 * Kondueyu; ma mpiyamdabota mise-mise nizakwaja alamsa amja, homa nkajupomba. 470 */ 471 public static final FakeLanguageGen SWAHILI = new FakeLanguageGen( 472 new String[]{"a", "i", "o", "e", "u", 473 "a", "a", "i", "o", "o", "e", "u", 474 "a", "a", "i", "o", "o", "u", 475 "a", "a", "i", "i", "o", 476 "a","a","a","a","a", 477 "a", "i", "o", "e", "u", 478 "a", "a", "i", "o", "o", "e", "u", 479 "a", "a", "i", "o", "o", "u", 480 "a", "a", "i", "i", "o", 481 "a","a","a","a","a", 482 "aa", "aa", "ue", "uo", "ii", "ea"}, 483 new String[]{}, 484 new String[]{ 485 "b", "h", "j", "l", "s", "y", "m", "n", 486 "b", "ch", "h", "j", "l", "s", "y", "z", "m", "n", 487 "b", "ch", "f", "g", "h", "j", "k", "l", "p", "s", "y", "z", "m", "n", 488 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "y", "z", "m", "n", "kw", 489 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "v", "w", "y", "z", "m", "n", "kw", 490 491 "b", "h", "j", "l", "s", "y", "m", "n", 492 "b", "ch", "h", "j", "l", "s", "y", "z", "m", "n", 493 "b", "ch", "f", "g", "h", "j", "k", "l", "p", "s", "y", "z", "m", "n", 494 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "y", "z", "m", "n", "kw", 495 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "v", "w", "y", "z", "m", "n", "kw", 496 497 "b", "h", "j", "l", "s", "y", "m", "n", 498 "b", "ch", "h", "j", "l", "s", "y", "z", "m", "n", 499 "b", "ch", "f", "g", "h", "j", "k", "l", "p", "s", "y", "z", "m", "n", 500 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "y", "z", "m", "n", "kw", 501 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "v", "w", "y", "z", "m", "n", "kw", 502 503 "b", "h", "j", "l", "s", "y", "m", "n", 504 "b", "ch", "h", "j", "l", "s", "y", "z", "m", "n", 505 "b", "ch", "f", "g", "h", "j", "k", "l", "p", "s", "y", "z", "m", "n", 506 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "y", "z", "m", "n", "kw", 507 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "v", "w", "y", "z", "m", "n", "kw", 508 509 "nb", "nj", "ns", "nz", 510 "nb", "nch", "nj", "ns", "ny", "nz", 511 "nb", "nch", "nf", "ng", "nj", "nk", "np", "ns", "nz", 512 "nb", "nch", "nd", "nf", "ng", "nj", "nk", "np", "ns", "nt", "nz", 513 "nb", "nch", "nd", "nf", "ng", "nj", "nk", "np", "ns", "nt", "nv", "nw", "nz", 514 515 "mb", "ms", "my", "mz", 516 "mb", "mch","ms", "my", "mz", 517 "mb", "mch", "mk", "mp", "ms", "my", "mz", 518 "mb", "mch", "md", "mk", "mp", "ms", "mt", "my", "mz", 519 "mb", "mch", "md", "mf", "mg", "mj", "mk", "mp", "ms", "mt", "mv", "mw", "my", "mz", 520 "sh", "sh", "sh", "ny", "kw", 521 "dh", "th", "sh", "ny", 522 "dh", "th", "sh", "gh", "r", "ny", 523 "dh", "th", "sh", "gh", "r", "ny", 524 }, 525 new String[]{ 526 "b", "h", "j", "l", "s", "y", "m", "n", 527 "b", "ch", "h", "j", "l", "s", "y", "z", "m", "n", 528 "b", "ch", "f", "g", "h", "j", "k", "l", "p", "s", "y", "z", "m", "n", 529 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "y", "z", "m", "n", "kw", 530 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "v", "w", "y", "z", "m", "n", "kw", 531 532 "b", "h", "j", "l", "s", "y", "m", "n", 533 "b", "ch", "h", "j", "l", "s", "y", "z", "m", "n", 534 "b", "ch", "f", "g", "h", "j", "k", "l", "p", "s", "y", "z", "m", "n", 535 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "y", "z", "m", "n", "kw", 536 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "v", "w", "y", "z", "m", "n", "kw", 537 538 "b", "h", "j", "l", "s", "y", "m", "n", 539 "b", "ch", "h", "j", "l", "s", "y", "z", "m", "n", 540 "b", "ch", "f", "g", "h", "j", "k", "l", "p", "s", "y", "z", "m", "n", 541 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "y", "z", "m", "n", "kw", 542 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "v", "w", "y", "z", "m", "n", "kw", 543 544 "b", "h", "j", "l", "s", "y", "m", "n", 545 "b", "ch", "h", "j", "l", "s", "y", "z", "m", "n", 546 "b", "ch", "f", "g", "h", "j", "k", "l", "p", "s", "y", "z", "m", "n", 547 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "y", "z", "m", "n", "kw", 548 "b", "ch", "d", "f", "g", "h", "j", "k", "l", "p", "s", "t", "v", "w", "y", "z", "m", "n", "kw", 549 550 "nb", "nj", "ns", "nz", 551 "nb", "nch", "nj", "ns", "ny", "nz", 552 "nb", "nch", "nf", "ng", "nj", "nk", "np", "ns", "nz", 553 "nb", "nch", "nd", "nf", "ng", "nj", "nk", "np", "ns", "nt", "nz", 554 "nb", "nch", "nd", "nf", "ng", "nj", "nk", "np", "ns", "nt", "nw", "nz", 555 556 "mb", "ms", "my", "mz", 557 "mb", "mch","ms", "my", "mz", 558 "mb", "mch", "mk", "mp", "ms", "my", "mz", 559 "mb", "mch", "md", "mk", "mp", "ms", "mt", "my", "mz", 560 "mb", "mch", "md", "mf", "mg", "mj", "mk", "mp", "ms", "mt", "mw", "my", "mz", 561 "sh", "sh", "sh", "ny", "kw", 562 "dh", "th", "sh", "ny", 563 "dh", "th", "sh", "gh", "r", "ny", 564 "dh", "th", "sh", "gh", "r", "ny", 565 "ng", "ng", "ng", "ng", "ng" 566 }, 567 new String[]{""}, 568 new String[]{"a-@2a", "a-@2a", "a-@3a","a-@2a", "a-@2a", "a-@3a","i-@2i", "i-@2i", "i-@3i", 569 "e-@2e", "e-@2e", "e-@3e", "u-@2u", "u-@2u", "u-@3u", 570 }, 571 new String[]{}, new int[]{1, 2, 3, 4, 5}, new double[]{1, 7, 6, 4, 2}, 0.2, 1.0, 0.0, 0.25, null, true); 572 573 /** 574 * Imitation Somali, using the Latin alphabet. Due to uncommon word structure, unusual allowed combinations of 575 * letters, and no common word roots with most familiar languages, this may seem like an unidentifiable or "alien" 576 * language to most readers. However, it's based on the Latin writing system for the Somali language (probably 577 * closest to the northern dialect), which due to the previously mentioned properties, makes it especially good for 578 * mixing with other languages to make letter combinations that seem strange to appear. It is unlikely that this 579 * particular generated language style will be familiar to readers, so it probably won't have existing stereotypes 580 * associated with the text. One early comment this received was, "it looks like a bunch of letters semi-randomly 581 * thrown together", which is probably a typical response (the comment was made by someone fluent in German and 582 * English, and most Western European languages are about as far as you can get from Somali). 583 * <br> 584 * Libor cat naqoxekh dhuugad gisiqir? 585 */ 586 public static final FakeLanguageGen SOMALI = new FakeLanguageGen( 587 new String[]{"a", "a", "a", "a", "a", "a", "a", "aa", "aa", "aa", 588 "e", "e", "ee", 589 "i", "i", "i", "i", "ii", 590 "o", "o", "o", "oo", 591 "u", "u", "u", "uu", "uu", 592 }, 593 new String[]{}, 594 new String[]{"b", "t", "j", "x", "kh", "d", "r", "s", "sh", "dh", "c", "g", "f", "q", "k", "l", "m", 595 "n", "w", "h", "y", 596 "x", "g", "b", "d", "s", "m", "dh", "n", "r", 597 "g", "b", "s", "dh", 598 }, 599 new String[]{ 600 "bb", "gg", "dd", "bb", "dd", "rr", "ddh", "cc", "gg", "ff", "ll", "mm", "nn", 601 "bb", "gg", "dd", "bb", "dd", "gg", 602 "bb", "gg", "dd", "bb", "dd", "gg", 603 "cy", "fk", "ft", "nt", "rt", "lt", "qm", "rdh", "rsh", "lq", 604 "my", "gy", "by", "lkh", "rx", "md", "bd", "dg", "fd", "mf", 605 "dh", "dh", "dh", "dh", 606 }, 607 new String[]{ 608 "b", "t", "j", "x", "kh", "d", "r", "s", "sh", "c", "g", "f", "q", "k", "l", "m", "n", "h", 609 "x", "g", "b", "d", "s", "m", "q", "n", "r", 610 "b", "t", "j", "x", "kh", "d", "r", "s", "sh", "c", "g", "f", "q", "k", "l", "m", "n", "h", 611 "x", "g", "b", "d", "s", "m", "q", "n", "r", 612 "b", "t", "j", "x", "kh", "d", "r", "s", "sh", "c", "g", "f", "q", "k", "l", "m", "n", 613 "g", "b", "d", "s", "q", "n", "r", 614 "b", "t", "x", "kh", "d", "r", "s", "sh", "g", "f", "q", "k", "l", "m", "n", 615 "g", "b", "d", "s", "r", "n", 616 "b", "t", "kh", "d", "r", "s", "sh", "g", "f", "q", "k", "l", "m", "n", 617 "g", "b", "d", "s", "r", "n", 618 "b", "t", "d", "r", "s", "sh", "g", "f", "q", "k", "l", "m", "n", 619 "g", "b", "d", "s", "r", "n", 620 }, 621 new String[]{"aw", "ow", "ay", "ey", "oy", "ay", "ay"}, 622 new String[]{}, new int[]{1, 2, 3, 4, 5}, new double[]{5, 4, 5, 4, 1}, 0.25, 0.3, 0.0, 0.08, null, true); 623 /** 624 * Imitation Hindi, romanized to use the Latin alphabet using accented glyphs similar to the IAST standard. 625 * Most fonts do not support the glyphs that IAST-standard romanization of Hindi needs, so this uses alternate 626 * glyphs from at most Latin Extended-A. Relative to HINDI_IAST, also defined here, the IAST standard glyphs 627 * {@code "ŗŕļĺđţńņşĕĭ"} become {@code "ŗŕļĺđţńņşĕĭ"}, with the nth glyph in the first string being substituted 628 * with the nth glyph in the second string. This version of imitation Hindi is preferred over the IAST kind because 629 * font support is much better for the glyphs this version uses. 630 * <br> 631 * Darvāga yar; ghađhinopŕauka āĕrdur, conśaigaijo śabhodhaĕđū jiviđaudu. 632 */ 633 public static final FakeLanguageGen HINDI_ROMANIZED = new FakeLanguageGen( 634 new String[]{ 635 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "ī", 636 "u", "u", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 637 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "ī", 638 "u", "u", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 639 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "ī", 640 "u", "u", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 641 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "ī", 642 "u", "u", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 643 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "i", "i", "ī", "ī", 644 "u", "u", "u", "ū", "u", "ū", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 645 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "i", "i", "ī", "ī", 646 "u", "u", "u", "ū", "u", "ū", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 647 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "i", "i", "ī", "ī", 648 "u", "u", "u", "ū", "u", "ū", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 649 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "i", "i", "ī", "ī", 650 "u", "u", "u", "ū", "u", "ū", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 651 "aĕ", "aĕ", "aĕ", "aĕ", "aĕ", "āĕ", "āĕ", "iĕ", "iĕ", "iĕ", "īĕ", "īĕ", 652 "uĕ", "uĕ", "ūĕ", "aiĕ", "aiĕ", "oĕ", "oĕ", "oĕ", "auĕ", 653 //"aĭ", "aĭ", "aĭ", "aĭ", "aĭ", "āĭ", "āĭ", "iĭ", "iĭ", "iĭ", "īĭ", "īĭ", 654 //"uĭ", "uĭ", "ūĭ", "aiĭ", "aiĭ", "oĭ", "oĭ", "oĭ", "auĭ", 655 }, 656 new String[]{"á","í","ú", "ó", "á","í","ú", "ó", 657 }, 658 new String[]{ 659 "k", "k", "k", "k", "k", "k", "k", "k", "kŗ", "kŕ", "kļ", 660 "c", "c", "c", "c", "c", "c", "cŗ", "cŕ", "cļ", 661 "ţ", "t", "t", "t", "t", "t", "t", "t", "t", "t", "tŗ", "tŕ", "tŗ", "tŕ", 662 "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "pŗ", "pŕ", "pļ", "pĺ", "pŗ", "pŕ", "p", "p", 663 "kh", "kh", "kh", "kh", "kh", "kh", "kh", "kh", "kh", "kh", "khŗ", "khŕ", "khļ", "khĺ", 664 "ch", "ch", "ch", "ch", "ch", "ch", "ch", "ch", "ch", "chŗ", "chŕ", "chļ", "chĺ", 665 "ţh", "th", "th", "th", "th", "th", "th", "th", "th", "th", "thŗ", "thŕ", "thļ", "thĺ", 666 "ph", "ph", "ph", "ph", "ph", "ph", "ph", "phŗ", "phŕ", "phļ", "phĺ", 667 "g", "j", "đ", "d", "b", "gh", "jh", "đh", "dh", "bh", 668 "ń", "ñ", "ņ", "n", "m", "h", "y", "r", "l", "v", "ś", "ş", "s", 669 "g", "j", "đ", "d", "b", "gh", "jh", "đh", "dh", "bh", 670 "ń", "ñ", "ņ", "n", "m", "h", "y", "r", "l", "v", "ś", "ş", "s", 671 "g", "j", "đ", "d", "b", "gh", "jh", "đh", "dh", "bh", 672 "ń", "ñ", "ņ", "n", "m", "h", "y", "r", "l", "v", "ś", "ş", "s", 673 "g", "j", "đ", "d", "b", "gh", "jh", "đh", "dh", "bh", 674 "ń", "ñ", "ņ", "n", "m", "h", "y", "r", "l", "v", "ś", "ş", "s", 675 "g", "j", "đ", "d", "b", "gh", "jh", "đh", "dh", "bh", 676 "ń", "ñ", "ņ", "n", "m", "h", "y", "r", "l", "v", "ś", "ş", "s", 677 "g", "j", "đ", "d", "b", "gh", "jh", "đh", "dh", "bh", 678 "ń", "ñ", "ņ", "n", "m", "h", "y", "r", "l", "v", "ś", "ş", "s", 679 "g", "j", "đ", "d", "b", "gh", "jh", "đh", "dh", "bh", 680 "ń", "ñ", "ņ", "n", "m", "h", "y", "r", "l", "v", "ś", "ş", "s", 681 "g", "j", "đ", "d", "b", "gh", "đh", "dh", "bh", 682 "ń", "ñ", "ņ", "n", "m", "h", "y", "r", "l", "v", "ś", "ş", "s", 683 "g", "j", "đ", "d", "b", "gh", "đh", "dh", "bh", 684 "ń", "ņ", "n", "m", "h", "y", "r", "l", "v", "ş", "s", 685 "g", "j", "đ", "d", "b", "gh", "đh", "dh", "bh", 686 "ń", "ņ", "n", "m", "h", "y", "r", "l", "v", "ş", "s", 687 "g", "đ", "d", "b", "gh", "đh", "dh", "bh", "n", "m", "v", "s", 688 "g", "đ", "d", "b", "g", "d", "b", "dh", "bh", "n", "m", "v", 689 "g", "đ", "d", "b", "g", "d", "b", "dh", "bh", "n", "m", "v", 690 }, 691 new String[]{ 692 "k", "k", "k", "k", "k", "nk", "rk", 693 "k", "k", "k", "k", "k", "nk", "rk", 694 "k", "k", "k", "k", "k", "nk", "rk", 695 "k", "k", "k", "k", "k", "nk", "rk", 696 "k", "k", "k", "k", "k", "nk", "rk", 697 "k", "k", "k", "k", "k", "nk", "rk", 698 "k", "k", "k", "k", "k", "nk", "rk", 699 "k", "k", "k", "k", "k", "nk", "rk", 700 "kŗ", "kŗ", "kŗ", "kŗ", "kŗ", "nkŗ", "rkŗ", 701 "kŕ", "kŕ", "kŕ", "kŕ", "kŕ", "nkŕ", "rkŕ", 702 "kļ", "kļ", "kļ", "kļ", "kļ", "nkļ", "rkļ", 703 704 "c", "c", "c", "c", "c", "c", "cŗ", "cŕ", "cļ", 705 "ţ", "t", "t", "t", "t", "t", "nt", "rt", 706 "ţ", "t", "t", "t", "t", "nt", "rt", 707 "ţ", "t", "t", "t", "t", "nt", "rt", 708 "ţ", "t", "t", "t", "t", "nt", "rt", 709 "ţ", "t", "t", "t", "t", "nt", "rt", 710 "ţ", "t", "t", "t", "t", "nt", "rt", 711 "ţ", "t", "t", "t", "t", "nt", "rt", 712 "ţ", "t", "t", "t", "t", "nt", "rt", 713 "ţ", "t", "t", "t", "t", "nt", "rt", 714 "tŗ", "tŗ", "tŗ", "tŗ", "tŗ", "ntŗ", "rtŗ", 715 "tŕ", "tŕ", "tŕ", "tŕ", "tŕ", "ntŕ", "rtŕ", 716 "tŗ", "tŗ", "tŗ", "tŗ", "tŗ", "ntŗ", "rtŗ", 717 "tŕ", "tŕ", "tŕ", "tŕ", "tŕ", "ntŕ", "rtŕ", 718 719 "p", "p", "p", "p", "p", "np", "rp", 720 "p", "p", "p", "p", "p", "np", "rp", 721 "p", "p", "p", "p", "p", "np", "rp", 722 "p", "p", "p", "p", "p", "np", "rp", 723 "p", "p", "p", "p", "p", "np", "rp", 724 "p", "p", "p", "p", "p", "np", "rp", 725 "p", "p", "p", "p", "p", "np", "rp", 726 "p", "p", "p", "p", "p", "np", "rp", 727 "p", "p", "p", "p", "p", "np", "rp", 728 "p", "p", "p", "p", "p", "np", "rp", 729 "pŗ", "pŗ", "pŗ", "pŗ", "pŗ", "npŗ", "rpŗ", 730 "pŕ", "pŕ", "pŕ", "pŕ", "pŕ", "npŕ", "rpŕ", 731 "pļ", "pļ", "pļ", "pļ", "pļ", "npļ", "rpļ", 732 "pĺ", "pĺ", "pĺ", "pĺ", "pĺ", "npĺ", "rpĺ", 733 "pŗ", "pŗ", "pŗ", "pŗ", "pŗ", "npŗ", "rpŗ", 734 "pŕ", "pŕ", "pŕ", "pŕ", "pŕ", "npŕ", "rpŕ", 735 "p", "p", "p", "p", "p", "np", "rp", 736 "p", "p", "p", "p", "p", "np", "rp", 737 738 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 739 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 740 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 741 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 742 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 743 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 744 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 745 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 746 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 747 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 748 "khŗ", "khŗ", "khŗ", "khŗ", "khŗ", "nkhŗ", "rkhŗ", 749 "khŕ", "khŕ", "khŕ", "khŕ", "khŕ", "nkhŕ", "rkhŕ", 750 "khļ", "khļ", "khļ", "khļ", "khļ", "nkhļ", "rkhļ", 751 "khĺ", "khĺ", "khĺ", "khĺ", "khĺ", "nkhĺ", "rkhĺ", 752 753 "ch", "ch", "ch", "ch", "ch", "ch", "ch", "ch", "ch", "chŗ", "chŕ", "chļ", "chĺ", 754 "ţh", "th", "th", "th", "th", "th", "nth", "rth", 755 "th", "th", "th", "th", "th", "nth", "rth", 756 "th", "th", "th", "th", "th", "nth", "rth", 757 "th", "th", "th", "th", "th", "nth", "rth", 758 "th", "th", "th", "th", "th", "nth", "rth", 759 "th", "th", "th", "th", "th", "nth", "rth", 760 "th", "th", "th", "th", "th", "nth", "rth", 761 "th", "th", "th", "th", "th", "nth", "rth", 762 "th", "th", "th", "th", "th", "nth", "rth", 763 "thŗ", "thŗ", "thŗ", "thŗ", "thŗ", "nthŗ", "rthŗ", 764 "thŕ", "thŕ", "thŕ", "thŕ", "thŕ", "nthŕ", "rthŕ", 765 "thļ", "thļ", "thļ", "thļ", "thļ", "nthļ", "rthļ", 766 "thĺ", "thĺ", "thĺ", "thĺ", "thĺ", "nthĺ", "rthĺ", 767 768 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 769 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 770 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 771 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 772 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 773 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 774 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 775 "phŗ", "phŗ", "phŗ", "phŗ", "phŗ", "nphŗ", "rphŗ", 776 "phŕ", "phŕ", "phŕ", "phŕ", "phŕ", "nphŕ", "rphŕ", 777 "phļ", "phļ", "phļ", "phļ", "phļ", "nphļ", "rphļ", 778 "phĺ", "phĺ", "phĺ", "phĺ", "phĺ", "nphĺ", "rphĺ", 779 780 "g", "g", "g", "g", "g", "ng", "rg", 781 "j", "j", "j", "j", "j", "nj", "rj", 782 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 783 "d", "d", "d", "d", "d", "nd", "rd", 784 "b", "b", "b", "b", "b", "nb", "rb", 785 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 786 "jh", "đh", "đh", "đh", "đh", "đh", "nđh", "rđh", 787 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 788 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 789 790 "ń", "ñ", "ņ", "n", "m", "m", "m", "m", "m", "nm", "rm", 791 "h", "y", "y", "y", "y", "y", "ny", "ry", 792 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 793 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 794 "ş", "ş", "ş", "ş", "ş", "nş", "rş", 795 "s", "s", "s", "s", "s", "ns", "rs", 796 797 "g", "g", "g", "g", "g", "ng", "rg", 798 "j", "j", "j", "j", "j", "nj", "rj", 799 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 800 "d", "d", "d", "d", "d", "nd", "rd", 801 "b", "b", "b", "b", "b", "nb", "rb", 802 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 803 "jh", "đh", "đh", "đh", "đh", "đh", "nđh", "rđh", 804 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 805 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 806 807 "ń", "ñ", "ņ", "n", "m", "m", "m", "m", "m", "nm", "rm", 808 "h", "y", "y", "y", "y", "y", "ny", "ry", 809 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 810 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 811 "ş", "ş", "ş", "ş", "ş", "nş", "rş", 812 "s", "s", "s", "s", "s", "ns", "rs", 813 814 "g", "g", "g", "g", "g", "ng", "rg", 815 "j", "j", "j", "j", "j", "nj", "rj", 816 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 817 "d", "d", "d", "d", "d", "nd", "rd", 818 "b", "b", "b", "b", "b", "nb", "rb", 819 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 820 "jh", "đh", "đh", "đh", "đh", "đh", "nđh", "rđh", 821 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 822 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 823 824 "ń", "ñ", "ņ", "n", "m", "m", "m", "m", "m", "nm", "rm", 825 "h", "y", "y", "y", "y", "y", "ny", "ry", 826 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 827 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 828 "ş", "ş", "ş", "ş", "ş", "nş", "rş", 829 "s", "s", "s", "s", "s", "ns", "rs", 830 831 "g", "g", "g", "g", "g", "ng", "rg", 832 "j", "j", "j", "j", "j", "nj", "rj", 833 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 834 "d", "d", "d", "d", "d", "nd", "rd", 835 "b", "b", "b", "b", "b", "nb", "rb", 836 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 837 "jh", "đh", "đh", "đh", "đh", "đh", "nđh", "rđh", 838 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 839 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 840 841 "ń", "ñ", "ņ", "n", "m", "m", "m", "m", "m", "nm", "rm", 842 "h", "y", "y", "y", "y", "y", "ny", "ry", 843 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 844 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 845 "ş", "ş", "ş", "ş", "ş", "nş", "rş", 846 "s", "s", "s", "s", "s", "ns", "rs", 847 848 "g", "g", "g", "g", "g", "ng", "rg", 849 "j", "j", "j", "j", "j", "nj", "rj", 850 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 851 "d", "d", "d", "d", "d", "nd", "rd", 852 "b", "b", "b", "b", "b", "nb", "rb", 853 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 854 "jh", "đh", "đh", "đh", "đh", "đh", "nđh", "rđh", 855 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 856 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 857 858 "ń", "ñ", "ņ", "n", "m", "m", "m", "m", "m", "nm", "rm", 859 "h", "y", "y", "y", "y", "y", "ny", "ry", 860 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 861 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 862 "ş", "ş", "ş", "ş", "ş", "nş", "rş", 863 "s", "s", "s", "s", "s", "ns", "rs", 864 865 "g", "g", "g", "g", "g", "ng", "rg", 866 "j", "j", "j", "j", "j", "nj", "rj", 867 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 868 "d", "d", "d", "d", "d", "nd", "rd", 869 "b", "b", "b", "b", "b", "nb", "rb", 870 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 871 "jh", "đh", "đh", "đh", "đh", "đh", "nđh", "rđh", 872 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 873 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 874 875 "ń", "ñ", "ņ", "n", "m", "m", "m", "m", "m", "nm", "rm", 876 "h", "y", "y", "y", "y", "y", "ny", "ry", 877 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 878 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 879 "ş", "ş", "ş", "ş", "ş", "nş", "rş", 880 "s", "s", "s", "s", "s", "ns", "rs", 881 882 "g", "g", "g", "g", "g", "ng", "rg", 883 "j", "j", "j", "j", "j", "nj", "rj", 884 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 885 "d", "d", "d", "d", "d", "nd", "rd", 886 "b", "b", "b", "b", "b", "nb", "rb", 887 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 888 "jh", "đh", "đh", "đh", "đh", "đh", "nđh", "rđh", 889 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 890 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 891 892 "ń", "ñ", "ņ", "n", "m", "m", "m", "m", "m", "nm", "rm", 893 "h", "y", "y", "y", "y", "y", "ny", "ry", 894 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 895 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 896 "ş", "ş", "ş", "ş", "ş", "nş", "rş", 897 "s", "s", "s", "s", "s", "ns", "rs", 898 899 "g", "g", "g", "g", "g", "ng", "rg", 900 "j", "j", "j", "j", "j", "nj", "rj", 901 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 902 "d", "d", "d", "d", "d", "nd", "rd", 903 "b", "b", "b", "b", "b", "nb", "rb", 904 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 905 "đh", "đh", "đh", "đh", "đh", "nđh", "rđh", 906 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 907 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 908 909 "ń", "ñ", "ņ", "n", "m", "m", "m", "m", "m", "nm", "rm", 910 "h", "y", "y", "y", "y", "y", "ny", "ry", 911 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 912 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 913 "ş", "ş", "ş", "ş", "ş", "nş", "rş", 914 "s", "s", "s", "s", "s", "ns", "rs", 915 916 "g", "g", "g", "g", "g", "ng", "rg", 917 "j", "j", "j", "j", "j", "nj", "rj", 918 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 919 "d", "d", "d", "d", "d", "nd", "rd", 920 "b", "b", "b", "b", "b", "nb", "rb", 921 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 922 "đh", "đh", "đh", "đh", "đh", "nđh", "rđh", 923 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 924 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 925 926 "ń", "ņ", "n", "m", "m", "m", "m", "m", "nm", "rm", 927 "h", "y", "y", "y", "y", "y", "ny", "ry", 928 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 929 "ş", "ş", "ş", "ş", "ş", "nş", "rş", 930 "s", "s", "s", "s", "s", "ns", "rs", 931 932 "g", "g", "g", "g", "g", "ng", "rg", 933 "j", "j", "j", "j", "j", "nj", "rj", 934 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 935 "d", "d", "d", "d", "d", "nd", "rd", 936 "b", "b", "b", "b", "b", "nb", "rb", 937 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 938 "đh", "đh", "đh", "đh", "đh", "nđh", "rđh", 939 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 940 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 941 942 "ń", "ņ", "n", "m", "m", "m", "m", "m", "nm", "rm", 943 "h", "y", "y", "y", "y", "y", "ny", "ry", 944 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 945 "ş", "ş", "ş", "ş", "ş", "nş", "rş", 946 "s", "s", "s", "s", "s", "ns", "rs", 947 948 "g", "g", "g", "g", "g", "ng", "rg", 949 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 950 "d", "d", "d", "d", "d", "nd", "rd", 951 "b", "b", "b", "b", "b", "nb", "rb", 952 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 953 "đh", "đh", "đh", "đh", "đh", "nđh", "rđh", 954 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 955 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 956 "n", "m", "m", "m", "m", "m", "nm", "rm", 957 "v", "v", "v", "v", "v", "nv", "rv", 958 "s", "s", "s", "s", "s", "ns", "rs", 959 960 "g", "g", "g", "g", "g", "ng", "rg", 961 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 962 "d", "d", "d", "d", "d", "nd", "rd", 963 "b", "b", "b", "b", "b", "nb", "rb", 964 "g", "g", "g", "g", "g", "ng", "rg", 965 "d", "d", "d", "d", "d", "nd", "rd", 966 "b", "b", "b", "b", "b", "nb", "rb", 967 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 968 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 969 "n", "m", "m", "m", "m", "m", "nm", "rm", 970 "v", "v", "v", "v", "v", "nv", "rv", 971 972 "g", "g", "g", "g", "g", "ng", "rg", 973 "đ", "đ", "đ", "đ", "đ", "nđ", "rđ", 974 "d", "d", "d", "d", "d", "nd", "rd", 975 "b", "b", "b", "b", "b", "nb", "rb", 976 "g", "g", "g", "g", "g", "ng", "rg", 977 "d", "d", "d", "d", "d", "nd", "rd", 978 "b", "b", "b", "b", "b", "nb", "rb", 979 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 980 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 981 "n", "m", "m", "m", "m", "m", "nm", "rm", 982 "v", "v", "v", "v", "v", "nv", "rv", 983 }, 984 new String[]{"t", "d", "m", "r", "dh", "b", "t", "d", "m", "r", "dh", "bh", "nt", "nt", "nk", "ş"}, 985 new String[]{"it", "it", "ati", "adva", "aş", "arma", "ardha", "abi", "ab", "aya"}, 986 new String[]{}, new int[]{1, 2, 3, 4, 5}, new double[]{1, 2, 3, 3, 1}, 0.15, 0.75, 0.0, 0.12, null, true); 987 988 989 /** 990 * Imitation Hindi, romanized to use the Latin alphabet using accented glyphs from the IAST standard, which are not 991 * typically printable with many fonts but are more likely to seem like samples of Hindi from, say, Wikipedia. 992 * There is also HINDI_ROMANIZED, which changes the IAST standard glyphs {@code "ṛṝḷḹḍṭṅṇṣṃḥ"} to 993 * {@code "ŗŕļĺđţńņşĕĭ"}, with the nth glyph in the first string being substituted with the nth glyph in the second 994 * string. Using HINDI_ROMANIZED is recommended if you use the fonts known by SquidLib's display module. 995 * <br> 996 * Datṝo thīndoṇa, oḍītad; ḍhivīvidh beśībo ru'markiḍaibhit. 997 */ 998 public static final FakeLanguageGen HINDI_IAST = new FakeLanguageGen( 999 new String[]{ 1000 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "ī", 1001 "u", "u", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 1002 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "ī", 1003 "u", "u", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 1004 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "ī", 1005 "u", "u", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 1006 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "ī", 1007 "u", "u", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 1008 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "i", "i", "ī", "ī", 1009 "u", "u", "u", "ū", "u", "ū", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 1010 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "i", "i", "ī", "ī", 1011 "u", "u", "u", "ū", "u", "ū", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 1012 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "i", "i", "ī", "ī", 1013 "u", "u", "u", "ū", "u", "ū", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 1014 "a", "a", "a", "a", "a", "a", "ā", "ā", "i", "i", "i", "i", "ī", "i", "i", "ī", "ī", 1015 "u", "u", "u", "ū", "u", "ū", "u", "ū", "e", "ai", "ai", "o", "o", "o", "au", 1016 "aṃ", "aṃ", "aṃ", "aṃ", "aṃ", "āṃ", "āṃ", "iṃ", "iṃ", "iṃ", "īṃ", "īṃ", 1017 "uṃ", "uṃ", "ūṃ", "aiṃ", "aiṃ", "oṃ", "oṃ", "oṃ", "auṃ", 1018 //"aḥ", "aḥ", "aḥ", "aḥ", "aḥ", "āḥ", "āḥ", "iḥ", "iḥ", "iḥ", "īḥ", "īḥ", 1019 //"uḥ", "uḥ", "ūḥ", "aiḥ", "aiḥ", "oḥ", "oḥ", "oḥ", "auḥ", 1020 }, 1021 new String[]{"a'","i'","u'", "o'", "a'","i'","u'", "o'", 1022 }, 1023 new String[]{ 1024 "k", "k", "k", "k", "k", "k", "k", "k", "kṛ", "kṝ", "kḷ", 1025 "c", "c", "c", "c", "c", "c", "cṛ", "cṝ", "cḷ", 1026 "ṭ", "t", "t", "t", "t", "t", "t", "t", "t", "t", "tṛ", "tṝ", "tṛ", "tṝ", 1027 "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "pṛ", "pṝ", "pḷ", "pḹ", "pṛ", "pṝ", "p", "p", 1028 "kh", "kh", "kh", "kh", "kh", "kh", "kh", "kh", "kh", "kh", "khṛ", "khṝ", "khḷ", "khḹ", 1029 "ch", "ch", "ch", "ch", "ch", "ch", "ch", "ch", "ch", "chṛ", "chṝ", "chḷ", "chḹ", 1030 "ṭh", "th", "th", "th", "th", "th", "th", "th", "th", "th", "thṛ", "thṝ", "thḷ", "thḹ", 1031 "ph", "ph", "ph", "ph", "ph", "ph", "ph", "phṛ", "phṝ", "phḷ", "phḹ", 1032 "g", "j", "ḍ", "d", "b", "gh", "jh", "ḍh", "dh", "bh", 1033 "ṅ", "ñ", "ṇ", "n", "m", "h", "y", "r", "l", "v", "ś", "ṣ", "s", 1034 "g", "j", "ḍ", "d", "b", "gh", "jh", "ḍh", "dh", "bh", 1035 "ṅ", "ñ", "ṇ", "n", "m", "h", "y", "r", "l", "v", "ś", "ṣ", "s", 1036 "g", "j", "ḍ", "d", "b", "gh", "jh", "ḍh", "dh", "bh", 1037 "ṅ", "ñ", "ṇ", "n", "m", "h", "y", "r", "l", "v", "ś", "ṣ", "s", 1038 "g", "j", "ḍ", "d", "b", "gh", "jh", "ḍh", "dh", "bh", 1039 "ṅ", "ñ", "ṇ", "n", "m", "h", "y", "r", "l", "v", "ś", "ṣ", "s", 1040 "g", "j", "ḍ", "d", "b", "gh", "jh", "ḍh", "dh", "bh", 1041 "ṅ", "ñ", "ṇ", "n", "m", "h", "y", "r", "l", "v", "ś", "ṣ", "s", 1042 "g", "j", "ḍ", "d", "b", "gh", "jh", "ḍh", "dh", "bh", 1043 "ṅ", "ñ", "ṇ", "n", "m", "h", "y", "r", "l", "v", "ś", "ṣ", "s", 1044 "g", "j", "ḍ", "d", "b", "gh", "jh", "ḍh", "dh", "bh", 1045 "ṅ", "ñ", "ṇ", "n", "m", "h", "y", "r", "l", "v", "ś", "ṣ", "s", 1046 "g", "j", "ḍ", "d", "b", "gh", "ḍh", "dh", "bh", 1047 "ṅ", "ñ", "ṇ", "n", "m", "h", "y", "r", "l", "v", "ś", "ṣ", "s", 1048 "g", "j", "ḍ", "d", "b", "gh", "ḍh", "dh", "bh", 1049 "ṅ", "ṇ", "n", "m", "h", "y", "r", "l", "v", "ṣ", "s", 1050 "g", "j", "ḍ", "d", "b", "gh", "ḍh", "dh", "bh", 1051 "ṅ", "ṇ", "n", "m", "h", "y", "r", "l", "v", "ṣ", "s", 1052 "g", "ḍ", "d", "b", "gh", "ḍh", "dh", "bh", "n", "m", "v", "s", 1053 "g", "ḍ", "d", "b", "g", "d", "b", "dh", "bh", "n", "m", "v", 1054 "g", "ḍ", "d", "b", "g", "d", "b", "dh", "bh", "n", "m", "v", 1055 }, 1056 new String[]{ 1057 "k", "k", "k", "k", "k", "nk", "rk", 1058 "k", "k", "k", "k", "k", "nk", "rk", 1059 "k", "k", "k", "k", "k", "nk", "rk", 1060 "k", "k", "k", "k", "k", "nk", "rk", 1061 "k", "k", "k", "k", "k", "nk", "rk", 1062 "k", "k", "k", "k", "k", "nk", "rk", 1063 "k", "k", "k", "k", "k", "nk", "rk", 1064 "k", "k", "k", "k", "k", "nk", "rk", 1065 "kṛ", "kṛ", "kṛ", "kṛ", "kṛ", "nkṛ", "rkṛ", 1066 "kṝ", "kṝ", "kṝ", "kṝ", "kṝ", "nkṝ", "rkṝ", 1067 "kḷ", "kḷ", "kḷ", "kḷ", "kḷ", "nkḷ", "rkḷ", 1068 1069 "c", "c", "c", "c", "c", "c", "cṛ", "cṝ", "cḷ", 1070 "ṭ", "t", "t", "t", "t", "t", "nt", "rt", 1071 "ṭ", "t", "t", "t", "t", "nt", "rt", 1072 "ṭ", "t", "t", "t", "t", "nt", "rt", 1073 "ṭ", "t", "t", "t", "t", "nt", "rt", 1074 "ṭ", "t", "t", "t", "t", "nt", "rt", 1075 "ṭ", "t", "t", "t", "t", "nt", "rt", 1076 "ṭ", "t", "t", "t", "t", "nt", "rt", 1077 "ṭ", "t", "t", "t", "t", "nt", "rt", 1078 "ṭ", "t", "t", "t", "t", "nt", "rt", 1079 "tṛ", "tṛ", "tṛ", "tṛ", "tṛ", "ntṛ", "rtṛ", 1080 "tṝ", "tṝ", "tṝ", "tṝ", "tṝ", "ntṝ", "rtṝ", 1081 "tṛ", "tṛ", "tṛ", "tṛ", "tṛ", "ntṛ", "rtṛ", 1082 "tṝ", "tṝ", "tṝ", "tṝ", "tṝ", "ntṝ", "rtṝ", 1083 1084 "p", "p", "p", "p", "p", "np", "rp", 1085 "p", "p", "p", "p", "p", "np", "rp", 1086 "p", "p", "p", "p", "p", "np", "rp", 1087 "p", "p", "p", "p", "p", "np", "rp", 1088 "p", "p", "p", "p", "p", "np", "rp", 1089 "p", "p", "p", "p", "p", "np", "rp", 1090 "p", "p", "p", "p", "p", "np", "rp", 1091 "p", "p", "p", "p", "p", "np", "rp", 1092 "p", "p", "p", "p", "p", "np", "rp", 1093 "p", "p", "p", "p", "p", "np", "rp", 1094 "pṛ", "pṛ", "pṛ", "pṛ", "pṛ", "npṛ", "rpṛ", 1095 "pṝ", "pṝ", "pṝ", "pṝ", "pṝ", "npṝ", "rpṝ", 1096 "pḷ", "pḷ", "pḷ", "pḷ", "pḷ", "npḷ", "rpḷ", 1097 "pḹ", "pḹ", "pḹ", "pḹ", "pḹ", "npḹ", "rpḹ", 1098 "pṛ", "pṛ", "pṛ", "pṛ", "pṛ", "npṛ", "rpṛ", 1099 "pṝ", "pṝ", "pṝ", "pṝ", "pṝ", "npṝ", "rpṝ", 1100 "p", "p", "p", "p", "p", "np", "rp", 1101 "p", "p", "p", "p", "p", "np", "rp", 1102 1103 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 1104 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 1105 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 1106 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 1107 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 1108 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 1109 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 1110 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 1111 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 1112 "kh", "kh", "kh", "kh", "kh", "nkh", "rkh", 1113 "khṛ", "khṛ", "khṛ", "khṛ", "khṛ", "nkhṛ", "rkhṛ", 1114 "khṝ", "khṝ", "khṝ", "khṝ", "khṝ", "nkhṝ", "rkhṝ", 1115 "khḷ", "khḷ", "khḷ", "khḷ", "khḷ", "nkhḷ", "rkhḷ", 1116 "khḹ", "khḹ", "khḹ", "khḹ", "khḹ", "nkhḹ", "rkhḹ", 1117 1118 "ch", "ch", "ch", "ch", "ch", "ch", "ch", "ch", "ch", "chṛ", "chṝ", "chḷ", "chḹ", 1119 "ṭh", "th", "th", "th", "th", "th", "nth", "rth", 1120 "th", "th", "th", "th", "th", "nth", "rth", 1121 "th", "th", "th", "th", "th", "nth", "rth", 1122 "th", "th", "th", "th", "th", "nth", "rth", 1123 "th", "th", "th", "th", "th", "nth", "rth", 1124 "th", "th", "th", "th", "th", "nth", "rth", 1125 "th", "th", "th", "th", "th", "nth", "rth", 1126 "th", "th", "th", "th", "th", "nth", "rth", 1127 "th", "th", "th", "th", "th", "nth", "rth", 1128 "thṛ", "thṛ", "thṛ", "thṛ", "thṛ", "nthṛ", "rthṛ", 1129 "thṝ", "thṝ", "thṝ", "thṝ", "thṝ", "nthṝ", "rthṝ", 1130 "thḷ", "thḷ", "thḷ", "thḷ", "thḷ", "nthḷ", "rthḷ", 1131 "thḹ", "thḹ", "thḹ", "thḹ", "thḹ", "nthḹ", "rthḹ", 1132 1133 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 1134 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 1135 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 1136 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 1137 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 1138 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 1139 "ph", "ph", "ph", "ph", "ph", "nph", "rph", 1140 "phṛ", "phṛ", "phṛ", "phṛ", "phṛ", "nphṛ", "rphṛ", 1141 "phṝ", "phṝ", "phṝ", "phṝ", "phṝ", "nphṝ", "rphṝ", 1142 "phḷ", "phḷ", "phḷ", "phḷ", "phḷ", "nphḷ", "rphḷ", 1143 "phḹ", "phḹ", "phḹ", "phḹ", "phḹ", "nphḹ", "rphḹ", 1144 1145 "g", "g", "g", "g", "g", "ng", "rg", 1146 "j", "j", "j", "j", "j", "nj", "rj", 1147 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1148 "d", "d", "d", "d", "d", "nd", "rd", 1149 "b", "b", "b", "b", "b", "nb", "rb", 1150 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 1151 "jh", "ḍh", "ḍh", "ḍh", "ḍh", "ḍh", "nḍh", "rḍh", 1152 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1153 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1154 1155 "ṅ", "ñ", "ṇ", "n", "m", "m", "m", "m", "m", "nm", "rm", 1156 "h", "y", "y", "y", "y", "y", "ny", "ry", 1157 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 1158 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 1159 "ṣ", "ṣ", "ṣ", "ṣ", "ṣ", "nṣ", "rṣ", 1160 "s", "s", "s", "s", "s", "ns", "rs", 1161 1162 "g", "g", "g", "g", "g", "ng", "rg", 1163 "j", "j", "j", "j", "j", "nj", "rj", 1164 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1165 "d", "d", "d", "d", "d", "nd", "rd", 1166 "b", "b", "b", "b", "b", "nb", "rb", 1167 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 1168 "jh", "ḍh", "ḍh", "ḍh", "ḍh", "ḍh", "nḍh", "rḍh", 1169 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1170 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1171 1172 "ṅ", "ñ", "ṇ", "n", "m", "m", "m", "m", "m", "nm", "rm", 1173 "h", "y", "y", "y", "y", "y", "ny", "ry", 1174 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 1175 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 1176 "ṣ", "ṣ", "ṣ", "ṣ", "ṣ", "nṣ", "rṣ", 1177 "s", "s", "s", "s", "s", "ns", "rs", 1178 1179 "g", "g", "g", "g", "g", "ng", "rg", 1180 "j", "j", "j", "j", "j", "nj", "rj", 1181 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1182 "d", "d", "d", "d", "d", "nd", "rd", 1183 "b", "b", "b", "b", "b", "nb", "rb", 1184 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 1185 "jh", "ḍh", "ḍh", "ḍh", "ḍh", "ḍh", "nḍh", "rḍh", 1186 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1187 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1188 1189 "ṅ", "ñ", "ṇ", "n", "m", "m", "m", "m", "m", "nm", "rm", 1190 "h", "y", "y", "y", "y", "y", "ny", "ry", 1191 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 1192 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 1193 "ṣ", "ṣ", "ṣ", "ṣ", "ṣ", "nṣ", "rṣ", 1194 "s", "s", "s", "s", "s", "ns", "rs", 1195 1196 "g", "g", "g", "g", "g", "ng", "rg", 1197 "j", "j", "j", "j", "j", "nj", "rj", 1198 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1199 "d", "d", "d", "d", "d", "nd", "rd", 1200 "b", "b", "b", "b", "b", "nb", "rb", 1201 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 1202 "jh", "ḍh", "ḍh", "ḍh", "ḍh", "ḍh", "nḍh", "rḍh", 1203 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1204 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1205 1206 "ṅ", "ñ", "ṇ", "n", "m", "m", "m", "m", "m", "nm", "rm", 1207 "h", "y", "y", "y", "y", "y", "ny", "ry", 1208 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 1209 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 1210 "ṣ", "ṣ", "ṣ", "ṣ", "ṣ", "nṣ", "rṣ", 1211 "s", "s", "s", "s", "s", "ns", "rs", 1212 1213 "g", "g", "g", "g", "g", "ng", "rg", 1214 "j", "j", "j", "j", "j", "nj", "rj", 1215 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1216 "d", "d", "d", "d", "d", "nd", "rd", 1217 "b", "b", "b", "b", "b", "nb", "rb", 1218 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 1219 "jh", "ḍh", "ḍh", "ḍh", "ḍh", "ḍh", "nḍh", "rḍh", 1220 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1221 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1222 1223 "ṅ", "ñ", "ṇ", "n", "m", "m", "m", "m", "m", "nm", "rm", 1224 "h", "y", "y", "y", "y", "y", "ny", "ry", 1225 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 1226 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 1227 "ṣ", "ṣ", "ṣ", "ṣ", "ṣ", "nṣ", "rṣ", 1228 "s", "s", "s", "s", "s", "ns", "rs", 1229 1230 "g", "g", "g", "g", "g", "ng", "rg", 1231 "j", "j", "j", "j", "j", "nj", "rj", 1232 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1233 "d", "d", "d", "d", "d", "nd", "rd", 1234 "b", "b", "b", "b", "b", "nb", "rb", 1235 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 1236 "jh", "ḍh", "ḍh", "ḍh", "ḍh", "ḍh", "nḍh", "rḍh", 1237 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1238 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1239 1240 "ṅ", "ñ", "ṇ", "n", "m", "m", "m", "m", "m", "nm", "rm", 1241 "h", "y", "y", "y", "y", "y", "ny", "ry", 1242 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 1243 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 1244 "ṣ", "ṣ", "ṣ", "ṣ", "ṣ", "nṣ", "rṣ", 1245 "s", "s", "s", "s", "s", "ns", "rs", 1246 1247 "g", "g", "g", "g", "g", "ng", "rg", 1248 "j", "j", "j", "j", "j", "nj", "rj", 1249 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1250 "d", "d", "d", "d", "d", "nd", "rd", 1251 "b", "b", "b", "b", "b", "nb", "rb", 1252 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 1253 "jh", "ḍh", "ḍh", "ḍh", "ḍh", "ḍh", "nḍh", "rḍh", 1254 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1255 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1256 1257 "ṅ", "ñ", "ṇ", "n", "m", "m", "m", "m", "m", "nm", "rm", 1258 "h", "y", "y", "y", "y", "y", "ny", "ry", 1259 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 1260 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 1261 "ṣ", "ṣ", "ṣ", "ṣ", "ṣ", "nṣ", "rṣ", 1262 "s", "s", "s", "s", "s", "ns", "rs", 1263 1264 "g", "g", "g", "g", "g", "ng", "rg", 1265 "j", "j", "j", "j", "j", "nj", "rj", 1266 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1267 "d", "d", "d", "d", "d", "nd", "rd", 1268 "b", "b", "b", "b", "b", "nb", "rb", 1269 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 1270 "ḍh", "ḍh", "ḍh", "ḍh", "ḍh", "nḍh", "rḍh", 1271 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1272 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1273 1274 "ṅ", "ñ", "ṇ", "n", "m", "m", "m", "m", "m", "nm", "rm", 1275 "h", "y", "y", "y", "y", "y", "ny", "ry", 1276 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 1277 "ś", "ś", "ś", "ś", "ś", "nś", "rś", 1278 "ṣ", "ṣ", "ṣ", "ṣ", "ṣ", "nṣ", "rṣ", 1279 "s", "s", "s", "s", "s", "ns", "rs", 1280 1281 "g", "g", "g", "g", "g", "ng", "rg", 1282 "j", "j", "j", "j", "j", "nj", "rj", 1283 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1284 "d", "d", "d", "d", "d", "nd", "rd", 1285 "b", "b", "b", "b", "b", "nb", "rb", 1286 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 1287 "ḍh", "ḍh", "ḍh", "ḍh", "ḍh", "nḍh", "rḍh", 1288 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1289 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1290 1291 "ṅ", "ṇ", "n", "m", "m", "m", "m", "m", "nm", "rm", 1292 "h", "y", "y", "y", "y", "y", "ny", "ry", 1293 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 1294 "ṣ", "ṣ", "ṣ", "ṣ", "ṣ", "nṣ", "rṣ", 1295 "s", "s", "s", "s", "s", "ns", "rs", 1296 1297 "g", "g", "g", "g", "g", "ng", "rg", 1298 "j", "j", "j", "j", "j", "nj", "rj", 1299 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1300 "d", "d", "d", "d", "d", "nd", "rd", 1301 "b", "b", "b", "b", "b", "nb", "rb", 1302 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 1303 "ḍh", "ḍh", "ḍh", "ḍh", "ḍh", "nḍh", "rḍh", 1304 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1305 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1306 1307 "ṅ", "ṇ", "n", "m", "m", "m", "m", "m", "nm", "rm", 1308 "h", "y", "y", "y", "y", "y", "ny", "ry", 1309 "r", "l", "v", "v", "v", "v", "v", "nv", "rv", 1310 "ṣ", "ṣ", "ṣ", "ṣ", "ṣ", "nṣ", "rṣ", 1311 "s", "s", "s", "s", "s", "ns", "rs", 1312 1313 "g", "g", "g", "g", "g", "ng", "rg", 1314 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1315 "d", "d", "d", "d", "d", "nd", "rd", 1316 "b", "b", "b", "b", "b", "nb", "rb", 1317 "gh", "gh", "gh", "gh", "gh", "ngh", "rgh", 1318 "ḍh", "ḍh", "ḍh", "ḍh", "ḍh", "nḍh", "rḍh", 1319 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1320 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1321 "n", "m", "m", "m", "m", "m", "nm", "rm", 1322 "v", "v", "v", "v", "v", "nv", "rv", 1323 "s", "s", "s", "s", "s", "ns", "rs", 1324 1325 "g", "g", "g", "g", "g", "ng", "rg", 1326 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1327 "d", "d", "d", "d", "d", "nd", "rd", 1328 "b", "b", "b", "b", "b", "nb", "rb", 1329 "g", "g", "g", "g", "g", "ng", "rg", 1330 "d", "d", "d", "d", "d", "nd", "rd", 1331 "b", "b", "b", "b", "b", "nb", "rb", 1332 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1333 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1334 "n", "m", "m", "m", "m", "m", "nm", "rm", 1335 "v", "v", "v", "v", "v", "nv", "rv", 1336 1337 "g", "g", "g", "g", "g", "ng", "rg", 1338 "ḍ", "ḍ", "ḍ", "ḍ", "ḍ", "nḍ", "rḍ", 1339 "d", "d", "d", "d", "d", "nd", "rd", 1340 "b", "b", "b", "b", "b", "nb", "rb", 1341 "g", "g", "g", "g", "g", "ng", "rg", 1342 "d", "d", "d", "d", "d", "nd", "rd", 1343 "b", "b", "b", "b", "b", "nb", "rb", 1344 "dh", "dh", "dh", "dh", "dh", "ndh", "rdh", 1345 "bh", "bh", "bh", "bh", "bh", "nbh", "rbh", 1346 "n", "m", "m", "m", "m", "m", "nm", "rm", 1347 "v", "v", "v", "v", "v", "nv", "rv", 1348 }, 1349 new String[]{"t", "d", "m", "r", "dh", "b", "t", "d", "m", "r", "dh", "bh", "nt", "nt", "nk", "ṣ"}, 1350 new String[]{"it", "it", "ati", "adva", "aṣ", "arma", "ardha", "abi", "ab", "aya"}, 1351 new String[]{}, new int[]{1, 2, 3, 4, 5}, new double[]{1, 2, 3, 3, 1}, 0.15, 0.75, 0.0, 0.12, null, true); 1352 1353 /** 1354 * Imitation Arabic, using mostly the Latin alphabet but with some Greek letters for tough transliteration topics. 1355 * It's hard to think of a more different (widely-spoken) language to romanize than Arabic. Written Arabic does not 1356 * ordinarily use vowels (the writing system is called an abjad, in contrast to an alphabet), and it has more than a 1357 * few sounds that are very different from those in English. This version, because of limited support in fonts and 1358 * the need for separate words to be distinguishable with regular expressions, uses Greek letters in place of hamzah 1359 * and 'ayin (the second of the two isn't entered correctly here since it wouldn't be printed with most fonts; you 1360 * can see https://en.wikipedia.org/wiki/Ayin for more details). Hamzah is represented with Greek delta, 'δ', and 1361 * 'ayin is represented with Greek xi, 'ξ', both picked because of similarity to some forms of the glyphs in the 1362 * Arabic script. Many other letters are mapped to alternate representations because the common romanizations use 1363 * rare glyphs that SquidLib's fonts in the display module can't support. Using the conventions this FakeLanguageGen 1364 * does for writing the Arabic glyph names, these are: ţāδ becomes ţ, ĥāδ becomes ĥ, ħāδ becomes ħ, đāl becomes 1365 * đ, šīn becomes š, şād becomes ş, ďād becomes ď, ťāδ becomes ť, żāδ becomes ż, gain becomes g, wāw becomes ū, and 1366 * yāδ becomes ī. 1367 * <br> 1368 * Please try to be culturally-sensitive about how you use this generator. Classical Arabic (the variant that 1369 * normally marks vowels explicitly and is used to write the Qur'an) has deep religious significance in Islam, and 1370 * if you machine-generate text that (probably) isn't valid Arabic, but claim that it is real, or that it has 1371 * meaning when it actually doesn't, that would be an improper usage of what this generator is meant to do. In a 1372 * fantasy setting, you can easily confirm that the language is fictional and any overlap is coincidental; an 1373 * example of imitation Arabic in use is the Dungeons and Dragons setting, Al-Qadim, which according to one account 1374 * sounds similar to a word in real Arabic (that does not mean anything like what the designer was aiming for). In a 1375 * historical setting, FakeLanguageGen is probably "too fake" to make a viable imitation for any language, and may 1376 * just sound insulting if portrayed as realistic. You may want to mix ARABIC_ROMANIZED with a very different kind 1377 * of language, like GREEK_ROMANIZED or RUSSIAN_AUTHENTIC, to emphasize that this is not a real-world language. 1378 * <br> 1379 * Iramzā qāşi, qīqa banji, rūşiďīq ifateh! 1380 */ 1381 public static final FakeLanguageGen ARABIC_ROMANIZED = new FakeLanguageGen( 1382 new String[]{"a", "a", "a", "a", "a", "a", "ā", "ā", "ā", "ai", "au", 1383 "a", "i", "u", "a", "i", "u", 1384 "i", "i", "i", "i", "i", "ī", "ī", "ī", 1385 "u", "u", "u", "ū", "ū", 1386 }, 1387 new String[]{}, 1388 new String[]{"δ", "b", "t", "ţ", "j", "ĥ", "ħ", "d", "đ", "r", "z", "s", "š", "ş", "ď", "ť", 1389 "ż", "ξ", "g", "f", "q", "k", "l", "m", "n", "h", "w", 1390 "q", "k", "q", "k", "b", "d", "f", "l", "z", "ż", "h", "h", "ĥ", "j", "s", "š", "ş", "r", 1391 "q", "k", "q", "k", "f", "l", "z", "h", "h", "j", "s", "r", 1392 "q", "k", "f", "l", "z", "h", "h", "j", "s", "r", 1393 "al-", "al-", "ibn-", 1394 }, 1395 new String[]{ 1396 "kk", "kk", "kk", "kk", "kk", "dd", "dd", "dd", "dd", 1397 "nj", "mj", "bj", "mj", "bj", "mj", "bj", "dj", "ďj", "đj", 1398 "nz", "nż", "mz", "mż", "rz", "rż", "bz", "dz", "tz", 1399 "s-h", "š-h", "ş-h", "tw", "bn", "fq", "hz", "hl", "ĥm", 1400 "lb", "lz", "lj", "lf", "ll", "lk", "lq", "lg", "ln" 1401 }, 1402 new String[]{ 1403 "δ", "b", "t", "ţ", "j", "ĥ", "ħ", "d", "đ", "r", "z", "s", "š", "ş", "ď", "ť", 1404 "ż", "ξ", "g", "f", "q", "k", "l", "m", "n", "h", "w", 1405 "k", "q", "k", "b", "d", "f", "l", "z", "ż", "h", "h", "ĥ", "j", "s", "š", "ş", "r", 1406 "k", "q", "k", "f", "l", "z", "h", "h", "j", "s", "r", 1407 "k", "f", "l", "z", "h", "h", "j", "s", "r", 1408 "b", "t", "ţ", "j", "ĥ", "ħ", "d", "đ", "r", "z", "s", "š", "ş", "ď", "ť", 1409 "ż", "g", "f", "q", "k", "l", "m", "n", "h", "w", 1410 "k", "q", "k", "b", "d", "f", "l", "z", "ż", "h", "h", "ĥ", "j", "s", "š", "ş", "r", 1411 "k", "q", "k", "f", "l", "z", "h", "h", "j", "s", "r", 1412 "k", "f", "l", "z", "h", "h", "j", "s", "r", 1413 }, 1414 new String[]{"āδ", "āδ", "ari", "ari", "aīd", "ūq", "arīd", "adih", "ateh", "adeš", "amīt", "it", 1415 "īt", "aĥmen","aĥmed", "ani", "abīb", "īb", "ūni", "īz", "aqarī", "adīq", 1416 }, 1417 new String[]{}, new int[]{1, 2, 3, 4}, new double[]{6, 5, 5, 1}, 0.55, 0.65, 0.0, 0.15, arabicSanityChecks, true); 1418 1419 /** 1420 * A mix of four different languages, using only ASCII characters, that is meant for generating single words for 1421 * creature or place names in fantasy settings. 1422 * <br> 1423 * Adeni, Sainane, Caneros, Sune, Alade, Tidifi, Muni, Gito, Lixoi, Bovi... 1424 */ 1425 public static final FakeLanguageGen FANTASY_NAME = GREEK_ROMANIZED.mix( 1426 RUSSIAN_ROMANIZED.mix( 1427 FRENCH.removeAccents().mix( 1428 JAPANESE_ROMANIZED, 0.5), 0.85), 0.925); 1429 /** 1430 * A mix of four different languages with some accented characters added onto an ASCII base, that can be good for 1431 * generating single words for creature or place names in fantasy settings that should have a "fancy" feeling from 1432 * having unnecessary accents added primarily for visual reasons. 1433 * <br> 1434 * Askieno, Blarcīnũn, Mēmida, Zizhounkô, Blęrinaf, Zemĭ, Mónazôr, Renerstă, Uskus, Toufounôr... 1435 */ 1436 public static final FakeLanguageGen FANCY_FANTASY_NAME = FANTASY_NAME.addAccents(0.47, 0.07); 1437 1438 /** 1439 * Zero-arg constructor for a FakeLanguageGen; produces a FakeLanguageGen equivalent to FakeLanguageGen.ENGLISH . 1440 */ 1441 public FakeLanguageGen() { 1442 this( 1443 new String[]{ 1444 "a", "a", "a", "a", "o", "o", "o", "e", "e", "e", "e", "e", "i", "i", "i", "i", "u", 1445 "a", "a", "a", "a", "o", "o", "o", "e", "e", "e", "e", "e", "i", "i", "i", "i", "u", 1446 "a", "a", "a", "o", "o", "e", "e", "e", "i", "i", "i", "u", 1447 "a", "a", "a", "o", "o", "e", "e", "e", "i", "i", "i", "u", 1448 "au", "ai", "ai", "ou", "ea", "ie", "io", "ei", 1449 }, 1450 new String[]{"u", "u", "oa", "oo", "oo", "oo", "ee", "ee", "ee", "ee",}, 1451 new String[]{ 1452 "b", "bl", "br", "c", "cl", "cr", "ch", "d", "dr", "f", "fl", "fr", "g", "gl", "gr", "h", "j", "k", "l", "m", "n", 1453 "p", "pl", "pr", "qu", "r", "s", "sh", "sk", "st", "sp", "sl", "sm", "sn", "t", "tr", "th", "thr", "v", "w", "y", "z", 1454 "b", "bl", "br", "c", "cl", "cr", "ch", "d", "dr", "f", "fl", "fr", "g", "gr", "h", "j", "k", "l", "m", "n", 1455 "p", "pl", "pr", "r", "s", "sh", "st", "sp", "sl", "t", "tr", "th", "w", "y", 1456 "b", "br", "c", "ch", "d", "dr", "f", "g", "h", "j", "l", "m", "n", 1457 "p", "r", "s", "sh", "st", "sl", "t", "tr", "th", 1458 "b", "d", "f", "g", "h", "l", "m", "n", 1459 "p", "r", "s", "sh", "t", "th", 1460 "b", "d", "f", "g", "h", "l", "m", "n", 1461 "p", "r", "s", "sh", "t", "th", 1462 "r", "s", "t", "l", "n", 1463 "str", "spr", "spl", "wr", "kn", "kn", "gn", 1464 }, 1465 new String[]{"x", "cst", "bs", "ff", "lg", "g", "gs", 1466 "ll", "ltr", "mb", "mn", "mm", "ng", "ng", "ngl", "nt", "ns", "nn", "ps", "mbl", "mpr", 1467 "pp", "ppl", "ppr", "rr", "rr", "rr", "rl", "rtn", "ngr", "ss", "sc", "rst", "tt", "tt", "ts", "ltr", "zz" 1468 }, 1469 new String[]{"b", "rb", "bb", "c", "rc", "ld", "d", "ds", "dd", "f", "ff", "lf", "rf", "rg", "gs", "ch", "lch", "rch", "tch", 1470 "ck", "ck", "lk", "rk", "l", "ll", "lm", "m", "rm", "mp", "n", "nk", "nch", "nd", "ng", "ng", "nt", "ns", "lp", "rp", 1471 "p", "r", "rn", "rts", "s", "s", "s", "s", "ss", "ss", "st", "ls", "t", "t", "ts", "w", "wn", "x", "ly", "lly", "z", 1472 "b", "c", "d", "f", "g", "k", "l", "m", "n", "p", "r", "s", "t", "w", 1473 }, 1474 new String[]{"ate", "ite", "ism", "ist", "er", "er", "er", "ed", "ed", "ed", "es", "es", "ied", "y", "y", "y", "y", 1475 "ate", "ite", "ism", "ist", "er", "er", "er", "ed", "ed", "ed", "es", "es", "ied", "y", "y", "y", "y", 1476 "ate", "ite", "ism", "ist", "er", "er", "er", "ed", "ed", "ed", "es", "es", "ied", "y", "y", "y", "y", 1477 "ay", "ay", "ey", "oy", "ay", "ay", "ey", "oy", 1478 "ough", "aught", "ant", "ont", "oe", "ance", "ell", "eal", "oa", "urt", "ut", "iom", "ion", "ion", "ision", "ation", "ation", "ition", 1479 "ough", "aught", "ant", "ont", "oe", "ance", "ell", "eal", "oa", "urt", "ut", "iom", "ion", "ion", "ision", "ation", "ation", "ition", 1480 "ily", "ily", "ily", "adly", "owly", "oorly", "ardly", "iedly", 1481 }, 1482 new String[]{}, new int[]{1, 2, 3, 4}, new double[]{7, 8, 4, 1}, 0.22, 0.1, 0.0, 0.25, englishSanityChecks, true); 1483 } 1484 1485 /** 1486 * This is a very complicated constructor! Maybe look at the calls to this to initialize static members of this 1487 * class, LOVECRAFT and GREEK_ROMANIZED. 1488 * 1489 * @param openingVowels String array where each element is a vowel or group of vowels that may appear at the start 1490 * of a word or in the middle; elements may be repeated to make them more common 1491 * @param midVowels String array where each element is a vowel or group of vowels that may appear in the 1492 * middle of the word; all openingVowels are automatically copied into this internally. 1493 * Elements may be repeated to make them more common 1494 * @param openingConsonants String array where each element is a consonant or consonant cluster that can appear 1495 * at the start of a word; elements may be repeated to make them more common 1496 * @param midConsonants String array where each element is a consonant or consonant cluster than can appear 1497 * between vowels; all closingConsonants are automatically copied into this internally. 1498 * Elements may be repeated to make them more common 1499 * @param closingConsonants String array where each element is a consonant or consonant cluster than can appear 1500 * at the end of a word; elements may be repeated to make them more common 1501 * @param closingSyllables String array where each element is a syllable starting with a vowel and ending in 1502 * whatever the word should end in; elements may be repeated to make them more common 1503 * @param vowelSplitters String array where each element is a mark that goes between vowels, so if "-" is in this, 1504 * then "a-a" may be possible; elements may be repeated to make them more common 1505 * @param syllableLengths int array where each element is a possible number of syllables a word can use; closely 1506 * tied to syllableFrequencies 1507 * @param syllableFrequencies double array where each element corresponds to an element in syllableLengths and 1508 * represents how often each syllable count should appear relative to other counts; there 1509 * is no need to restrict the numbers to add up to any other number 1510 * @param vowelStartFrequency a double between 0.0 and 1.0 that determines how often words start with vowels; 1511 * higher numbers yield more words starting with vowels 1512 * @param vowelEndFrequency a double between 0.0 and 1.0 that determines how often words end with vowels; higher 1513 * numbers yield more words ending in vowels 1514 * @param vowelSplitFrequency a double between 0.0 and 1.0 that, if vowelSplitters is not empty, determines how 1515 * often a vowel will be split into two vowels separated by one of those splitters 1516 * @param syllableEndFrequency a double between 0.0 and 1.0 that determines how often an element of 1517 * closingSyllables is used instead of ending normally 1518 */ 1519 public FakeLanguageGen(String[] openingVowels, String[] midVowels, String[] openingConsonants, 1520 String[] midConsonants, String[] closingConsonants, String[] closingSyllables, String[] vowelSplitters, 1521 int[] syllableLengths, double[] syllableFrequencies, double vowelStartFrequency, 1522 double vowelEndFrequency, double vowelSplitFrequency, double syllableEndFrequency) { 1523 this(openingVowels, midVowels, openingConsonants, midConsonants, closingConsonants, closingSyllables, 1524 vowelSplitters, syllableLengths, syllableFrequencies, vowelStartFrequency, vowelEndFrequency, 1525 vowelSplitFrequency, syllableEndFrequency, englishSanityChecks, true); 1526 } 1527 1528 /** 1529 * This is a very complicated constructor! Maybe look at the calls to this to initialize static members of this 1530 * class, LOVECRAFT and GREEK_ROMANIZED. 1531 * 1532 * @param openingVowels String array where each element is a vowel or group of vowels that may appear at the start 1533 * of a word or in the middle; elements may be repeated to make them more common 1534 * @param midVowels String array where each element is a vowel or group of vowels that may appear in the 1535 * middle of the word; all openingVowels are automatically copied into this internally. 1536 * Elements may be repeated to make them more common 1537 * @param openingConsonants String array where each element is a consonant or consonant cluster that can appear 1538 * at the start of a word; elements may be repeated to make them more common 1539 * @param midConsonants String array where each element is a consonant or consonant cluster than can appear 1540 * between vowels; all closingConsonants are automatically copied into this internally. 1541 * Elements may be repeated to make them more common 1542 * @param closingConsonants String array where each element is a consonant or consonant cluster than can appear 1543 * at the end of a word; elements may be repeated to make them more common 1544 * @param closingSyllables String array where each element is a syllable starting with a vowel and ending in 1545 * whatever the word should end in; elements may be repeated to make them more common 1546 * @param vowelSplitters String array where each element is a mark that goes between vowels, so if "-" is in this, 1547 * then "a-a" may be possible; elements may be repeated to make them more common 1548 * @param syllableLengths int array where each element is a possible number of syllables a word can use; closely 1549 * tied to syllableFrequencies 1550 * @param syllableFrequencies double array where each element corresponds to an element in syllableLengths and 1551 * represents how often each syllable count should appear relative to other counts; there 1552 * is no need to restrict the numbers to add up to any other number 1553 * @param vowelStartFrequency a double between 0.0 and 1.0 that determines how often words start with vowels; 1554 * higher numbers yield more words starting with vowels 1555 * @param vowelEndFrequency a double between 0.0 and 1.0 that determines how often words end with vowels; higher 1556 * numbers yield more words ending in vowels 1557 * @param vowelSplitFrequency a double between 0.0 and 1.0 that, if vowelSplitters is not empty, determines how 1558 * often a vowel will be split into two vowels separated by one of those splitters 1559 * @param syllableEndFrequency a double between 0.0 and 1.0 that determines how often an element of 1560 * closingSyllables is used instead of ending normally 1561 * @param sane true to perform sanity checks for pronounce-able sounds to most English speakers, replacing many 1562 * words that are impossible to say; slows down generation slightly, irrelevant for non-Latin alphabets 1563 * @param clean true to perform vulgarity/obscenity checks on the word, replacing it if it is too close to a 1564 * common English vulgarity, obscenity, or slur/epithet; slows down generation slightly 1565 */ 1566 public FakeLanguageGen(String[] openingVowels, String[] midVowels, String[] openingConsonants, 1567 String[] midConsonants, String[] closingConsonants, String[] closingSyllables, String[] vowelSplitters, 1568 int[] syllableLengths, double[] syllableFrequencies, double vowelStartFrequency, 1569 double vowelEndFrequency, double vowelSplitFrequency, double syllableEndFrequency, 1570 Pattern[] sane, boolean clean) { 1571 this.openingVowels = openingVowels; 1572 this.midVowels = new String[openingVowels.length + midVowels.length]; 1573 System.arraycopy(midVowels, 0, this.midVowels, 0, midVowels.length); 1574 System.arraycopy(openingVowels, 0, this.midVowels, midVowels.length, openingVowels.length); 1575 this.openingConsonants = openingConsonants; 1576 this.midConsonants = new String[midConsonants.length + closingConsonants.length]; 1577 System.arraycopy(midConsonants, 0, this.midConsonants, 0, midConsonants.length); 1578 System.arraycopy(closingConsonants, 0, this.midConsonants, midConsonants.length, closingConsonants.length); 1579 this.closingConsonants = closingConsonants; 1580 this.vowelSplitters = vowelSplitters; 1581 this.closingSyllables = closingSyllables; 1582 1583 this.syllableFrequencies = new LinkedHashMap<>(syllableLengths.length); 1584 for (int i = 0; i < syllableLengths.length && i < syllableFrequencies.length; i++) { 1585 this.syllableFrequencies.put(syllableLengths[i], syllableFrequencies[i]); 1586 } 1587 for (Double freq : this.syllableFrequencies.values()) { 1588 totalSyllableFrequency += freq; 1589 } 1590 if (vowelStartFrequency > 1.0) 1591 this.vowelStartFrequency = 1.0 / vowelStartFrequency; 1592 else 1593 this.vowelStartFrequency = vowelStartFrequency; 1594 if (vowelEndFrequency > 1.0) 1595 this.vowelEndFrequency = 1.0 / vowelEndFrequency; 1596 else 1597 this.vowelEndFrequency = vowelEndFrequency; 1598 if (vowelSplitters.length == 0) 1599 this.vowelSplitFrequency = 0.0; 1600 else if (vowelSplitFrequency > 1.0) 1601 this.vowelSplitFrequency = 1.0 / vowelSplitFrequency; 1602 else 1603 this.vowelSplitFrequency = vowelSplitFrequency; 1604 if (closingSyllables.length == 0) 1605 this.syllableEndFrequency = 0.0; 1606 else if (syllableEndFrequency > 1.0) 1607 this.syllableEndFrequency = 1.0 / syllableEndFrequency; 1608 else 1609 this.syllableEndFrequency = syllableEndFrequency; 1610 this.clean = clean; 1611 sanityChecks = sane; 1612 modifiers = new ArrayList<>(16); 1613 } 1614 1615 private FakeLanguageGen(String[] openingVowels, String[] midVowels, String[] openingConsonants, 1616 String[] midConsonants, String[] closingConsonants, String[] closingSyllables, 1617 String[] vowelSplitters, LinkedHashMap<Integer, Double> syllableFrequencies, 1618 double vowelStartFrequency, double vowelEndFrequency, double vowelSplitFrequency, 1619 double syllableEndFrequency, Pattern[] sanityChecks, boolean clean, 1620 List<Modifier> modifiers) { 1621 this.openingVowels = copyStrings(openingVowels); 1622 this.midVowels = copyStrings(midVowels); 1623 this.openingConsonants = copyStrings(openingConsonants); 1624 this.midConsonants = copyStrings(midConsonants); 1625 this.closingConsonants = copyStrings(closingConsonants); 1626 this.closingSyllables = copyStrings(closingSyllables); 1627 this.vowelSplitters = copyStrings(vowelSplitters); 1628 this.syllableFrequencies = new LinkedHashMap<>(syllableFrequencies); 1629 this.vowelStartFrequency = vowelStartFrequency; 1630 this.vowelEndFrequency = vowelEndFrequency; 1631 this.vowelSplitFrequency = vowelSplitFrequency; 1632 this.syllableEndFrequency = syllableEndFrequency; 1633 for (Double freq : this.syllableFrequencies.values()) { 1634 totalSyllableFrequency += freq; 1635 } 1636 if (sanityChecks == null) 1637 this.sanityChecks = null; 1638 else { 1639 this.sanityChecks = new Pattern[sanityChecks.length]; 1640 System.arraycopy(sanityChecks, 0, this.sanityChecks, 0, sanityChecks.length); 1641 } 1642 this.clean = clean; 1643 this.modifiers = new ArrayList<>(modifiers); 1644 } 1645 1646 protected boolean checkAll(CharSequence testing, Pattern[] checks) 1647 { 1648 CharSequence fixed = removeAccents(testing); 1649 for (int i = 0; i < checks.length; i++) { 1650 if(checks[i].matcher(fixed).find()) 1651 return false; 1652 } 1653 return true; 1654 } 1655 /** 1656 * Generate a word from this FakeLanguageGen, using and changing the current seed. 1657 * @param capitalize true if the word should start with a capital letter, false otherwise 1658 * @return a word in the fake language as a String 1659 */ 1660 public String word(boolean capitalize) 1661 { 1662 return word(srng, capitalize); 1663 } 1664 /** 1665 * Generate a word from this FakeLanguageGen using the specified RNG. 1666 * 1667 * @param rng the RNG to use for the randomized string building 1668 * @param capitalize true if the word should start with a capital letter, false otherwise 1669 * @return a word in the fake language as a String 1670 */ 1671 public String word(RNG rng, boolean capitalize) { 1672 while(true) { 1673 StringBuilder sb = new StringBuilder(20); 1674 double syllableChance = rng.nextDouble(totalSyllableFrequency); 1675 int syllables = 1, i = 0; 1676 for (Map.Entry<Integer, Double> kv : syllableFrequencies.entrySet()) { 1677 if (syllableChance < kv.getValue()) { 1678 syllables = kv.getKey(); 1679 break; 1680 } else 1681 syllableChance -= kv.getValue(); 1682 } 1683 if (rng.nextDouble() < vowelStartFrequency) { 1684 sb.append(rng.getRandomElement(openingVowels)); 1685 sb.append(rng.getRandomElement(midConsonants)); 1686 i++; 1687 } else { 1688 sb.append(rng.getRandomElement(openingConsonants)); 1689 } 1690 1691 for (; i < syllables - 1; i++) { 1692 sb.append(rng.getRandomElement(midVowels)); 1693 if (rng.nextDouble() < vowelSplitFrequency) { 1694 sb.append(rng.getRandomElement(vowelSplitters)); 1695 sb.append(rng.getRandomElement(midVowels)); 1696 } 1697 sb.append(rng.getRandomElement(midConsonants)); 1698 } 1699 if (rng.nextDouble() < syllableEndFrequency) { 1700 String close = rng.getRandomElement(closingSyllables); 1701 if((close.contains("@1") && syllables == 1) || 1702 (close.contains("@2") && syllables == 2) || 1703 (close.contains("@3") && syllables == 3) ) 1704 { 1705 sb.append(close.replaceAll("@\\d", sb.toString())); 1706 } 1707 else if(!close.contains("@")) 1708 sb.append(close); 1709 else if (rng.nextDouble() < vowelEndFrequency) { 1710 sb.append(rng.getRandomElement(midVowels)); 1711 if (rng.nextDouble() < vowelSplitFrequency) { 1712 sb.append(rng.getRandomElement(vowelSplitters)); 1713 sb.append(rng.getRandomElement(midVowels)); 1714 } 1715 } 1716 } else { 1717 sb.append(rng.getRandomElement(midVowels)); 1718 if (rng.nextDouble() < vowelSplitFrequency) { 1719 sb.append(rng.getRandomElement(vowelSplitters)); 1720 sb.append(rng.getRandomElement(midVowels)); 1721 } 1722 if (rng.nextDouble() >= vowelEndFrequency) { 1723 sb.append(rng.getRandomElement(closingConsonants)); 1724 if (rng.nextDouble() < syllableEndFrequency) { 1725 String close = rng.getRandomElement(closingSyllables); 1726 if((close.contains("@1") && syllables == 1) || 1727 (close.contains("@2") && syllables == 2) || 1728 (close.contains("@3") && syllables == 3) ) 1729 { 1730 sb.append(close.replaceAll("@\\d", sb.toString())); 1731 } 1732 else if(!close.contains("@")) 1733 sb.append(close); 1734 } 1735 } 1736 } 1737 if(sanityChecks != null && !checkAll(sb, sanityChecks)) 1738 continue; 1739 1740 for(Modifier mod : modifiers) 1741 { 1742 sb = mod.modify(rng, sb); 1743 } 1744 1745 if (capitalize) 1746 sb.setCharAt(0, Character.toUpperCase(sb.charAt(0))); 1747 1748 if(clean && !checkAll(sb, vulgarChecks)) 1749 continue; 1750 return sb.toString(); 1751 } 1752 }/** 1753 * Generate a word from this FakeLanguageGen using the specified RNG. 1754 * 1755 * @param rng the RNG to use for the randomized string building 1756 * @param capitalize true if the word should start with a capital letter, false otherwise 1757 * @return a word in the fake language as a String 1758 */ 1759 public String word(RNG rng, boolean capitalize, int approxSyllables) { 1760 if(approxSyllables <= 0) 1761 { 1762 String finished = rng.getRandomElement(openingVowels); 1763 if(capitalize) return finished.substring(0, 1).toUpperCase(); 1764 else return finished.substring(0, 1); 1765 } 1766 while(true) { 1767 StringBuilder sb = new StringBuilder(20); 1768 int i = 0; 1769 if (rng.nextDouble() < vowelStartFrequency) { 1770 sb.append(rng.getRandomElement(openingVowels)); 1771 sb.append(rng.getRandomElement(midConsonants)); 1772 i++; 1773 } else { 1774 sb.append(rng.getRandomElement(openingConsonants)); 1775 } 1776 1777 for (; i < approxSyllables - 1; i++) { 1778 sb.append(rng.getRandomElement(midVowels)); 1779 if (rng.nextDouble() < vowelSplitFrequency) { 1780 sb.append(rng.getRandomElement(vowelSplitters)); 1781 sb.append(rng.getRandomElement(midVowels)); 1782 } 1783 sb.append(rng.getRandomElement(midConsonants)); 1784 } 1785 if (rng.nextDouble() < syllableEndFrequency) { 1786 String close = rng.getRandomElement(closingSyllables); 1787 if((close.contains("@1") && approxSyllables == 1) || (close.contains("@2") && approxSyllables == 2) || 1788 (close.contains("@3") && approxSyllables == 3) ) 1789 { 1790 sb.append(close.replaceAll("@\\d", sb.toString())); 1791 } 1792 else if(!close.contains("@")) 1793 sb.append(close); 1794 else if (rng.nextDouble() < vowelEndFrequency) { 1795 sb.append(rng.getRandomElement(midVowels)); 1796 if (rng.nextDouble() < vowelSplitFrequency) { 1797 sb.append(rng.getRandomElement(vowelSplitters)); 1798 sb.append(rng.getRandomElement(midVowels)); 1799 } 1800 } 1801 } else { 1802 sb.append(rng.getRandomElement(midVowels)); 1803 if (rng.nextDouble() < vowelSplitFrequency) { 1804 sb.append(rng.getRandomElement(vowelSplitters)); 1805 sb.append(rng.getRandomElement(midVowels)); 1806 } 1807 if (rng.nextDouble() >= vowelEndFrequency) { 1808 sb.append(rng.getRandomElement(closingConsonants)); 1809 if (rng.nextDouble() < syllableEndFrequency) { 1810 String close = rng.getRandomElement(closingSyllables); 1811 if((close.contains("@1") && approxSyllables == 1) || 1812 (close.contains("@2") && approxSyllables == 2) || 1813 (close.contains("@3") && approxSyllables == 3) ) 1814 { 1815 close = close.replaceAll("@\\d", sb.toString()); 1816 sb.append(close); 1817 } 1818 else if(!close.contains("@")) 1819 sb.append(close); 1820 } 1821 } 1822 } 1823 1824 if(sanityChecks != null && !checkAll(sb, sanityChecks)) 1825 continue; 1826 1827 for(Modifier mod : modifiers) 1828 { 1829 sb = mod.modify(rng, sb); 1830 } 1831 1832 if (capitalize) 1833 sb.setCharAt(0, Character.toUpperCase(sb.charAt(0))); 1834 1835 if(clean && !checkAll(sb, vulgarChecks)) 1836 continue; 1837 return sb.toString(); 1838 } 1839 } 1840 1841 /** 1842 * Generate a sentence from this FakeLanguageGen, using and changing the current seed. 1843 * @param minWords an int for the minimum number of words in a sentence; should be at least 1 1844 * @param maxWords an int for the maximum number of words in a sentence; should be at least equal to minWords 1845 * @return a sentence in the gibberish language as a String 1846 */ 1847 public String sentence(int minWords, int maxWords) 1848 { 1849 return sentence(srng, minWords, maxWords, new String[]{",", ",", ",", ";"}, 1850 new String[]{".", ".", ".", "!", "?", "..."}, 0.2); 1851 } 1852 1853 /** 1854 * Generate a sentence from this FakeLanguageGen, using and changing the current seed. 1855 * 1856 * @param minWords an int for the minimum number of words in a sentence; should be at least 1 1857 * @param maxWords an int for the maximum number of words in a sentence; should be at least equal to minWords 1858 * @param midPunctuation a String array where each element is a comma, semicolon, or the like that goes before a 1859 * space in the middle of a sentence 1860 * @param endPunctuation a String array where each element is a period, question mark, or the like that goes at 1861 * the very end of a sentence 1862 * @param midPunctuationFrequency a double between 0.0 and 1.0 that determines how often Strings from 1863 * midPunctuation should be inserted before spaces 1864 * @return a sentence in the gibberish language as a String 1865 */ 1866 public String sentence(int minWords, int maxWords, String[] midPunctuation, String[] endPunctuation, 1867 double midPunctuationFrequency) 1868 { 1869 return sentence(srng, minWords, maxWords, midPunctuation, endPunctuation, midPunctuationFrequency); 1870 } 1871 /** 1872 * Generate a sentence from this FakeLanguageGen using the specific RNG. 1873 * 1874 * @param rng the RNG to use for the randomized string building 1875 * @param minWords an int for the minimum number of words in a sentence; should be at least 1 1876 * @param maxWords an int for the maximum number of words in a sentence; should be at least equal to minWords 1877 * @param midPunctuation a String array where each element is a comma, semicolon, or the like that goes before a 1878 * space in the middle of a sentence 1879 * @param endPunctuation a String array where each element is a period, question mark, or the like that goes at 1880 * the very end of a sentence 1881 * @param midPunctuationFrequency a double between 0.0 and 1.0 that determines how often Strings from 1882 * midPunctuation should be inserted before spaces 1883 * @return a sentence in the gibberish language as a String 1884 */ 1885 public String sentence(RNG rng, int minWords, int maxWords, String[] midPunctuation, String[] endPunctuation, 1886 double midPunctuationFrequency) { 1887 if (minWords < 1) 1888 minWords = 1; 1889 if (minWords > maxWords) 1890 maxWords = minWords; 1891 if (midPunctuationFrequency > 1.0) { 1892 midPunctuationFrequency = 1.0 / midPunctuationFrequency; 1893 } 1894 StringBuilder sb = new StringBuilder(12 * maxWords); 1895 sb.append(word(rng, true)); 1896 for (int i = 1; i < minWords; i++) { 1897 if (rng.nextDouble() < midPunctuationFrequency) { 1898 sb.append(rng.getRandomElement(midPunctuation)); 1899 } 1900 sb.append(' '); 1901 sb.append(word(rng, false)); 1902 } 1903 for (int i = minWords; i < maxWords && rng.nextInt(2 * maxWords) > i; i++) { 1904 if (rng.nextDouble() < midPunctuationFrequency) { 1905 sb.append(rng.getRandomElement(midPunctuation)); 1906 } 1907 sb.append(' '); 1908 sb.append(word(rng, false)); 1909 } 1910 sb.append(rng.getRandomElement(endPunctuation)); 1911 return sb.toString(); 1912 } 1913 /** 1914 * Generate a sentence from this FakeLanguageGen that fits in the given length limit.. 1915 * 1916 * @param minWords an int for the minimum number of words in a sentence; should be at least 1 1917 * @param maxWords an int for the maximum number of words in a sentence; should be at least equal to minWords 1918 * @param midPunctuation a String array where each element is a comma, semicolon, or the like that goes before a 1919 * space in the middle of a sentence 1920 * @param endPunctuation a String array where each element is a period, question mark, or the like that goes at 1921 * the very end of a sentence 1922 * @param midPunctuationFrequency a double between 0.0 and 1.0 that determines how often Strings from 1923 * midPunctuation should be inserted before spaces 1924 * @param maxChars the longest string length this can produce; should be at least {@code 6 * minWords} 1925 * @return a sentence in the gibberish language as a String 1926 */ 1927 public String sentence(int minWords, int maxWords, String[] midPunctuation, String[] endPunctuation, 1928 double midPunctuationFrequency, int maxChars) { 1929 return sentence(srng, minWords, maxWords, midPunctuation, endPunctuation, midPunctuationFrequency, maxChars); 1930 } 1931 /** 1932 * Generate a sentence from this FakeLanguageGen using the specific RNG that fits in the given length limit. 1933 * 1934 * @param rng the RNG to use for the randomized string building 1935 * @param minWords an int for the minimum number of words in a sentence; should be at least 1 1936 * @param maxWords an int for the maximum number of words in a sentence; should be at least equal to minWords 1937 * @param midPunctuation a String array where each element is a comma, semicolon, or the like that goes before a 1938 * space in the middle of a sentence 1939 * @param endPunctuation a String array where each element is a period, question mark, or the like that goes at 1940 * the very end of a sentence 1941 * @param midPunctuationFrequency a double between 0.0 and 1.0 that determines how often Strings from 1942 * midPunctuation should be inserted before spaces 1943 * @param maxChars the longest string length this can produce; should be at least {@code 6 * minWords} 1944 * @return a sentence in the gibberish language as a String 1945 */ 1946 public String sentence(RNG rng, int minWords, int maxWords, String[] midPunctuation, String[] endPunctuation, 1947 double midPunctuationFrequency, int maxChars) { 1948 if (minWords < 1) 1949 minWords = 1; 1950 if (minWords > maxWords) 1951 maxWords = minWords; 1952 if (midPunctuationFrequency > 1.0) { 1953 midPunctuationFrequency = 1.0 / midPunctuationFrequency; 1954 } 1955 if(maxChars < 4) 1956 return "!"; 1957 if(maxChars <= 5 * minWords) { 1958 minWords = 1; 1959 maxWords = 1; 1960 } 1961 int frustration = 0; 1962 StringBuilder sb = new StringBuilder(maxChars); 1963 String next = word(rng, true); 1964 while (next.length() >= maxChars - 1 && frustration < 50) { 1965 next = word(rng, true); 1966 frustration++; 1967 } 1968 if(frustration >= 50) return "!"; 1969 sb.append(next); 1970 for (int i = 1; i < minWords && frustration < 50 && sb.length() < maxChars - 7; i++) { 1971 if (rng.nextDouble() < midPunctuationFrequency && sb.length() < maxChars - 3) { 1972 sb.append(rng.getRandomElement(midPunctuation)); 1973 } 1974 next = word(rng, false); 1975 while (sb.length() + next.length() >= maxChars - 2 && frustration < 50) { 1976 next = word(rng, false); 1977 frustration++; 1978 } 1979 if(frustration >= 50) break; 1980 sb.append(' '); 1981 sb.append(next); 1982 } 1983 for (int i = minWords; i < maxWords && sb.length() < maxChars - 7 && rng.nextInt(2 * maxWords) > i && frustration < 50; i++) { 1984 if (rng.nextDouble() < midPunctuationFrequency && sb.length() < maxChars - 3) { 1985 sb.append(rng.getRandomElement(midPunctuation)); 1986 } 1987 next = word(rng, false); 1988 while (sb.length() + next.length() >= maxChars - 2 && frustration < 50) { 1989 next = word(rng, false); 1990 frustration++; 1991 } 1992 if(frustration >= 50) break; 1993 sb.append(' '); 1994 sb.append(next); 1995 } 1996 next = rng.getRandomElement(endPunctuation); 1997 if(sb.length() + next.length() >= maxChars) 1998 next = "."; 1999 sb.append(next); 2000 if(sb.length() > maxChars) 2001 return "!"; 2002 return sb.toString(); 2003 } 2004 2005 protected String[] merge1000(RNG rng, String[] me, String[] other, double otherInfluence) { 2006 if(other.length <= 0 && me.length <= 0) 2007 return new String[]{}; 2008 String[] ret = new String[1000]; 2009 int otherCount = (int) (1000 * otherInfluence); 2010 int idx = 0; 2011 if (other.length > 0) { 2012 String[] tmp = new String[other.length]; 2013 rng.shuffle(other, tmp); 2014 for (idx = 0; idx < otherCount; idx++) { 2015 ret[idx] = tmp[idx % tmp.length]; 2016 } 2017 } 2018 if (me.length > 0) { 2019 String[] tmp = new String[me.length]; 2020 rng.shuffle(me, tmp); 2021 for (; idx < 1000; idx++) { 2022 ret[idx] = tmp[idx % tmp.length]; 2023 } 2024 } 2025 else 2026 { 2027 for (; idx < 1000; idx++) { 2028 ret[idx] = other[idx % other.length]; 2029 } 2030 } 2031 return ret; 2032 } 2033 2034 2035 protected String[] accentVowels(RNG rng, String[] me, double influence) { 2036 String[] ret = new String[1000]; 2037 int otherCount = (int) (1000 * influence); 2038 int idx = 0; 2039 Matcher matcher; 2040 if (me.length > 0) { 2041 String[] tmp = new String[me.length]; 2042 rng.shuffle(me, tmp); 2043 for (idx = 0; idx < otherCount; idx++) { 2044 ret[idx] = tmp[idx % tmp.length] 2045 .replace('a', accentedVowels[0][rng.nextInt(accentedVowels[0].length)]) 2046 .replace('e', accentedVowels[1][rng.nextInt(accentedVowels[1].length)]) 2047 .replace('i', accentedVowels[2][rng.nextInt(accentedVowels[2].length)]) 2048 .replace('o', accentedVowels[3][rng.nextInt(accentedVowels[3].length)]) 2049 .replace('u', accentedVowels[4][rng.nextInt(accentedVowels[4].length)]); 2050 matcher = repeats.matcher(ret[idx]); 2051 if (matcher.find()) { 2052 ret[idx] = matcher.replaceAll(rng.getRandomElement(me)); 2053 } 2054 } 2055 for (; idx < 1000; idx++) { 2056 ret[idx] = tmp[idx % tmp.length]; 2057 } 2058 } else 2059 return new String[]{}; 2060 return ret; 2061 } 2062 2063 protected String[] accentConsonants(RNG rng, String[] me, double influence) { 2064 String[] ret = new String[1000]; 2065 int otherCount = (int) (1000 * influence); 2066 int idx = 0; 2067 Matcher matcher; 2068 if (me.length > 0) { 2069 String[] tmp = new String[me.length]; 2070 rng.shuffle(me, tmp); 2071 for (idx = 0; idx < otherCount; idx++) { 2072 ret[idx] = tmp[idx % tmp.length] 2073 //0 2074 .replace('c', accentedConsonants[1][rng.nextInt(accentedConsonants[1].length)]) 2075 .replace('d', accentedConsonants[2][rng.nextInt(accentedConsonants[2].length)]) 2076 .replace('f', accentedConsonants[3][rng.nextInt(accentedConsonants[3].length)]) 2077 .replace('g', accentedConsonants[4][rng.nextInt(accentedConsonants[4].length)]) 2078 .replace('h', accentedConsonants[5][rng.nextInt(accentedConsonants[5].length)]) 2079 .replace('j', accentedConsonants[6][rng.nextInt(accentedConsonants[6].length)]) 2080 .replace('k', accentedConsonants[7][rng.nextInt(accentedConsonants[7].length)]) 2081 .replace('l', accentedConsonants[8][rng.nextInt(accentedConsonants[8].length)]) 2082 //9 2083 .replace('n', accentedConsonants[10][rng.nextInt(accentedConsonants[10].length)]) 2084 //11 2085 //12 2086 .replace('r', accentedConsonants[13][rng.nextInt(accentedConsonants[13].length)]) 2087 .replace('s', accentedConsonants[14][rng.nextInt(accentedConsonants[14].length)]) 2088 .replace('t', accentedConsonants[15][rng.nextInt(accentedConsonants[15].length)]) 2089 //16 2090 .replace('w', accentedConsonants[17][rng.nextInt(accentedConsonants[17].length)]) 2091 //18 2092 .replace('y', accentedConsonants[19][rng.nextInt(accentedConsonants[19].length)]) 2093 .replace('z', accentedConsonants[20][rng.nextInt(accentedConsonants[20].length)]); 2094 2095 matcher = repeats.matcher(ret[idx]); 2096 if (matcher.find()) { 2097 ret[idx] = matcher.replaceAll(rng.getRandomElement(me)); 2098 } 2099 } 2100 for (; idx < 1000; idx++) { 2101 ret[idx] = tmp[idx % tmp.length]; 2102 } 2103 } else 2104 return new String[]{}; 2105 return ret; 2106 } 2107 2108 protected String[] accentBoth(RNG rng, String[] me, double vowelInfluence, double consonantInfluence) { 2109 String[] ret = new String[1000]; 2110 int idx = 0; 2111 Matcher matcher; 2112 if (me.length > 0) { 2113 String[] tmp = new String[me.length]; 2114 rng.shuffle(me, tmp); 2115 for (idx = 0; idx < 1000; idx++) { 2116 boolean subVowel = rng.nextDouble() < vowelInfluence, subCon = rng.nextDouble() < consonantInfluence; 2117 if (subVowel && subCon) { 2118 ret[idx] = tmp[idx % tmp.length] 2119 .replace('a', accentedVowels[0][rng.nextInt(accentedVowels[0].length)]) 2120 .replace('e', accentedVowels[1][rng.nextInt(accentedVowels[1].length)]) 2121 .replace('i', accentedVowels[2][rng.nextInt(accentedVowels[2].length)]) 2122 .replace('o', accentedVowels[3][rng.nextInt(accentedVowels[3].length)]) 2123 .replace('u', accentedVowels[4][rng.nextInt(accentedVowels[4].length)]) 2124 2125 //0 2126 .replace('c', accentedConsonants[1][rng.nextInt(accentedConsonants[1].length)]) 2127 .replace('d', accentedConsonants[2][rng.nextInt(accentedConsonants[2].length)]) 2128 .replace('f', accentedConsonants[3][rng.nextInt(accentedConsonants[3].length)]) 2129 .replace('g', accentedConsonants[4][rng.nextInt(accentedConsonants[4].length)]) 2130 .replace('h', accentedConsonants[5][rng.nextInt(accentedConsonants[5].length)]) 2131 .replace('j', accentedConsonants[6][rng.nextInt(accentedConsonants[6].length)]) 2132 .replace('k', accentedConsonants[7][rng.nextInt(accentedConsonants[7].length)]) 2133 .replace('l', accentedConsonants[8][rng.nextInt(accentedConsonants[8].length)]) 2134 //9 2135 .replace('n', accentedConsonants[10][rng.nextInt(accentedConsonants[10].length)]) 2136 //11 2137 //12 2138 .replace('r', accentedConsonants[13][rng.nextInt(accentedConsonants[13].length)]) 2139 .replace('s', accentedConsonants[14][rng.nextInt(accentedConsonants[14].length)]) 2140 .replace('t', accentedConsonants[15][rng.nextInt(accentedConsonants[15].length)]) 2141 //16 2142 .replace('w', accentedConsonants[17][rng.nextInt(accentedConsonants[17].length)]) 2143 //18 2144 .replace('y', accentedConsonants[19][rng.nextInt(accentedConsonants[19].length)]) 2145 .replace('z', accentedConsonants[20][rng.nextInt(accentedConsonants[20].length)]); 2146 2147 matcher = repeats.matcher(ret[idx]); 2148 if (matcher.find()) { 2149 ret[idx] = matcher.replaceAll(rng.getRandomElement(me)); 2150 } 2151 } else if (subVowel) { 2152 ret[idx] = tmp[idx % tmp.length] 2153 .replace('a', accentedVowels[0][rng.nextInt(accentedVowels[0].length)]) 2154 .replace('e', accentedVowels[1][rng.nextInt(accentedVowels[1].length)]) 2155 .replace('i', accentedVowels[2][rng.nextInt(accentedVowels[2].length)]) 2156 .replace('o', accentedVowels[3][rng.nextInt(accentedVowels[3].length)]) 2157 .replace('u', accentedVowels[4][rng.nextInt(accentedVowels[4].length)]); 2158 2159 matcher = repeats.matcher(ret[idx]); 2160 if (matcher.find()) { 2161 ret[idx] = matcher.replaceAll(rng.getRandomElement(me)); 2162 } 2163 } else if (subCon) { 2164 ret[idx] = tmp[idx % tmp.length] 2165 //0 2166 .replace('c', accentedConsonants[1][rng.nextInt(accentedConsonants[1].length)]) 2167 .replace('d', accentedConsonants[2][rng.nextInt(accentedConsonants[2].length)]) 2168 .replace('f', accentedConsonants[3][rng.nextInt(accentedConsonants[3].length)]) 2169 .replace('g', accentedConsonants[4][rng.nextInt(accentedConsonants[4].length)]) 2170 .replace('h', accentedConsonants[5][rng.nextInt(accentedConsonants[5].length)]) 2171 .replace('j', accentedConsonants[6][rng.nextInt(accentedConsonants[6].length)]) 2172 .replace('k', accentedConsonants[7][rng.nextInt(accentedConsonants[7].length)]) 2173 .replace('l', accentedConsonants[8][rng.nextInt(accentedConsonants[8].length)]) 2174 //9 2175 .replace('n', accentedConsonants[10][rng.nextInt(accentedConsonants[10].length)]) 2176 //11 2177 //12 2178 .replace('r', accentedConsonants[13][rng.nextInt(accentedConsonants[13].length)]) 2179 .replace('s', accentedConsonants[14][rng.nextInt(accentedConsonants[14].length)]) 2180 .replace('t', accentedConsonants[15][rng.nextInt(accentedConsonants[15].length)]) 2181 //16 2182 .replace('w', accentedConsonants[17][rng.nextInt(accentedConsonants[17].length)]) 2183 //18 2184 .replace('y', accentedConsonants[19][rng.nextInt(accentedConsonants[19].length)]) 2185 .replace('z', accentedConsonants[20][rng.nextInt(accentedConsonants[20].length)]); 2186 2187 matcher = repeats.matcher(ret[idx]); 2188 if (matcher.find()) { 2189 ret[idx] = matcher.replaceAll(rng.getRandomElement(me)); 2190 } 2191 } else ret[idx] = tmp[idx % tmp.length]; 2192 2193 } 2194 } else 2195 return new String[]{}; 2196 return ret; 2197 } 2198 2199 public FakeLanguageGen mix(FakeLanguageGen other, double otherInfluence) { 2200 otherInfluence = Math.max(0.0, Math.min(otherInfluence, 1.0)); 2201 double myInfluence = 1.0 - otherInfluence; 2202 2203 RNG rng = new RNG((hashCode() & 0xffffffffL) | ((other.hashCode() & 0xffffffffL) << 32) 2204 ^ Double.doubleToLongBits(otherInfluence)); 2205 2206 String[] ov = merge1000(rng, openingVowels, other.openingVowels, otherInfluence), 2207 mv = merge1000(rng, midVowels, other.midVowels, otherInfluence), 2208 oc = merge1000(rng, openingConsonants, other.openingConsonants, otherInfluence * 2209 Math.max(0.0, Math.min(1.0, (1.0 - other.vowelStartFrequency + vowelStartFrequency)))), 2210 mc = merge1000(rng, midConsonants, other.midConsonants, otherInfluence), 2211 cc = merge1000(rng, closingConsonants, other.closingConsonants, otherInfluence * 2212 Math.max(0.0, Math.min(1.0, (1.0 - other.vowelEndFrequency + vowelEndFrequency)))), 2213 cs = merge1000(rng, closingSyllables, other.closingSyllables, otherInfluence * 2214 Math.max(0.0, Math.min(1.0, (other.syllableEndFrequency - syllableEndFrequency)))), 2215 splitters = merge1000(rng, vowelSplitters, other.vowelSplitters, otherInfluence); 2216 2217 LinkedHashMap<Integer, Double> freqs = new LinkedHashMap<>(syllableFrequencies); 2218 for (Map.Entry<Integer, Double> kv : other.syllableFrequencies.entrySet()) { 2219 if (freqs.containsKey(kv.getKey())) 2220 freqs.put(kv.getKey(), kv.getValue() + freqs.get(kv.getKey())); 2221 else 2222 freqs.put(kv.getKey(), kv.getValue()); 2223 } 2224 List<Modifier> mods = new ArrayList<>((int)(Math.ceil(modifiers.size() * myInfluence) + 2225 Math.ceil(other.modifiers.size() * otherInfluence))); 2226 mods.addAll(rng.randomPortion(modifiers, (int)Math.ceil(modifiers.size() * myInfluence))); 2227 mods.addAll(rng.randomPortion(other.modifiers, (int)Math.ceil(other.modifiers.size() * otherInfluence))); 2228 FakeLanguageGen finished = new FakeLanguageGen(ov, mv, oc, mc, cc, cs, splitters, freqs, 2229 vowelStartFrequency * myInfluence + other.vowelStartFrequency * otherInfluence, 2230 vowelEndFrequency * myInfluence + other.vowelEndFrequency * otherInfluence, 2231 vowelSplitFrequency * myInfluence + other.vowelSplitFrequency * otherInfluence, 2232 syllableEndFrequency * myInfluence + other.syllableEndFrequency * otherInfluence, 2233 (sanityChecks == null) ? other.sanityChecks : sanityChecks, true, mods); 2234 return finished; 2235 } 2236 2237 public FakeLanguageGen addAccents(double vowelInfluence, double consonantInfluence) { 2238 vowelInfluence = Math.max(0.0, Math.min(vowelInfluence, 1.0)); 2239 consonantInfluence = Math.max(0.0, Math.min(consonantInfluence, 1.0)); 2240 2241 RNG rng = new RNG((hashCode() & 0xffffffffL) ^ 2242 ((Double.doubleToLongBits(vowelInfluence) & 0xffffffffL) | (Double.doubleToLongBits(consonantInfluence) << 32))); 2243 String[] ov = accentVowels(rng, openingVowels, vowelInfluence), 2244 mv = accentVowels(rng, midVowels, vowelInfluence), 2245 oc = accentConsonants(rng, openingConsonants, consonantInfluence), 2246 mc = accentConsonants(rng, midConsonants, consonantInfluence), 2247 cc = accentConsonants(rng, closingConsonants, consonantInfluence), 2248 cs = accentBoth(rng, closingSyllables, vowelInfluence, consonantInfluence); 2249 2250 2251 FakeLanguageGen finished = new FakeLanguageGen(ov, mv, oc, mc, cc, cs, vowelSplitters, syllableFrequencies, 2252 vowelStartFrequency, 2253 vowelEndFrequency, 2254 vowelSplitFrequency, 2255 syllableEndFrequency, sanityChecks, clean, modifiers); 2256 return finished; 2257 } 2258 static String[] copyStrings(String[] start) 2259 { 2260 String[] next = new String[start.length]; 2261 System.arraycopy(start, 0, next, 0, start.length); 2262 return next; 2263 } 2264 public FakeLanguageGen removeAccents() { 2265 2266 String[] ov = copyStrings(openingVowels), 2267 mv = copyStrings(midVowels), 2268 oc = copyStrings(openingConsonants), 2269 mc = copyStrings(midConsonants), 2270 cc = copyStrings(closingConsonants), 2271 cs = copyStrings(closingSyllables); 2272 for (int i = 0; i < ov.length; i++) { 2273 ov[i] = removeAccents(openingVowels[i]).toString(); 2274 } 2275 for (int i = 0; i < mv.length; i++) { 2276 mv[i] = removeAccents(midVowels[i]).toString(); 2277 } 2278 for (int i = 0; i < oc.length; i++) { 2279 oc[i] = removeAccents(openingConsonants[i]).toString(); 2280 } 2281 for (int i = 0; i < mc.length; i++) { 2282 mc[i] = removeAccents(midConsonants[i]).toString(); 2283 } 2284 for (int i = 0; i < cc.length; i++) { 2285 cc[i] = removeAccents(closingConsonants[i]).toString(); 2286 } 2287 for (int i = 0; i < cs.length; i++) { 2288 cs[i] = removeAccents(closingSyllables[i]).toString(); 2289 } 2290 2291 return new FakeLanguageGen(ov, mv, oc, mc, cc, cs, vowelSplitters, syllableFrequencies, 2292 vowelStartFrequency, 2293 vowelEndFrequency, 2294 vowelSplitFrequency, 2295 syllableEndFrequency, sanityChecks, clean, modifiers); 2296 } 2297 2298 /** 2299 * Adds the specified Modifier objects from a Collection to a copy of this FakeLanguageGen and returns it. 2300 * You can obtain a Modifier with the static constants in the FakeLanguageGen.Modifier nested class, the 2301 * FakeLanguageGen.modifier() method, or Modifier's constructor. 2302 * @param mods an array or vararg of Modifier objects 2303 * @return a copy of this with the Modifiers added 2304 */ 2305 public FakeLanguageGen addModifiers(Collection<Modifier> mods) 2306 { 2307 FakeLanguageGen next = copy(); 2308 next.modifiers.addAll(mods); 2309 return next; 2310 } 2311 2312 /** 2313 * Adds the specified Modifier objects to a copy of this FakeLanguageGen and returns it. 2314 * You can obtain a Modifier with the static constants in the FakeLanguageGen.Modifier nested class, the 2315 * FakeLanguageGen.modifier() method, or Modifier's constructor. 2316 * @param mods an array or vararg of Modifier objects 2317 * @return a copy of this with the Modifiers added 2318 */ 2319 public FakeLanguageGen addModifiers(Modifier... mods) 2320 { 2321 FakeLanguageGen next = copy(); 2322 Collections.addAll(next.modifiers, mods); 2323 return next; 2324 } 2325 2326 /** 2327 * Creates a copy of this FakeLanguageGen with no modifiers. 2328 * @return a copy of this FakeLanguageGen with modifiers removed. 2329 */ 2330 public FakeLanguageGen removeModifiers() 2331 { 2332 FakeLanguageGen next = copy(); 2333 next.modifiers.clear(); 2334 return next; 2335 } 2336 2337 public static Modifier modifier(String pattern, String replacement) 2338 { 2339 return new Modifier(pattern, replacement); 2340 } 2341 public static Modifier modifier(String pattern, String replacement, double chance) 2342 { 2343 return new Modifier(pattern, replacement, chance); 2344 } 2345 2346 @Override 2347 public boolean equals(Object o) { 2348 if (this == o) return true; 2349 if (o == null || getClass() != o.getClass()) return false; 2350 2351 FakeLanguageGen that = (FakeLanguageGen) o; 2352 2353 if (clean != that.clean) return false; 2354 if (Double.compare(that.totalSyllableFrequency, totalSyllableFrequency) != 0) return false; 2355 if (Double.compare(that.vowelStartFrequency, vowelStartFrequency) != 0) return false; 2356 if (Double.compare(that.vowelEndFrequency, vowelEndFrequency) != 0) return false; 2357 if (Double.compare(that.vowelSplitFrequency, vowelSplitFrequency) != 0) return false; 2358 if (Double.compare(that.syllableEndFrequency, syllableEndFrequency) != 0) return false; 2359 // Probably incorrect - comparing Object[] arrays with Arrays.equals 2360 if (!Arrays.equals(openingVowels, that.openingVowels)) return false; 2361 // Probably incorrect - comparing Object[] arrays with Arrays.equals 2362 if (!Arrays.equals(midVowels, that.midVowels)) return false; 2363 // Probably incorrect - comparing Object[] arrays with Arrays.equals 2364 if (!Arrays.equals(openingConsonants, that.openingConsonants)) return false; 2365 // Probably incorrect - comparing Object[] arrays with Arrays.equals 2366 if (!Arrays.equals(midConsonants, that.midConsonants)) return false; 2367 // Probably incorrect - comparing Object[] arrays with Arrays.equals 2368 if (!Arrays.equals(closingConsonants, that.closingConsonants)) return false; 2369 // Probably incorrect - comparing Object[] arrays with Arrays.equals 2370 if (!Arrays.equals(vowelSplitters, that.vowelSplitters)) return false; 2371 // Probably incorrect - comparing Object[] arrays with Arrays.equals 2372 if (!Arrays.equals(closingSyllables, that.closingSyllables)) return false; 2373 if (!syllableFrequencies.equals(that.syllableFrequencies)) return false; 2374 // Probably incorrect - comparing Object[] arrays with Arrays.equals 2375 if (!Arrays.equals(sanityChecks, that.sanityChecks)) return false; 2376 return modifiers != null ? modifiers.equals(that.modifiers) : that.modifiers == null; 2377 } 2378 2379 @Override 2380 public int hashCode() { 2381 int result; 2382 long temp; 2383 result = CrossHash.hash(openingVowels); 2384 result = 31 * result + CrossHash.hash(midVowels); 2385 result = 31 * result + CrossHash.hash(openingConsonants); 2386 result = 31 * result + CrossHash.hash(midConsonants); 2387 result = 31 * result + CrossHash.hash(closingConsonants); 2388 result = 31 * result + CrossHash.hash(vowelSplitters); 2389 result = 31 * result + CrossHash.hash(closingSyllables); 2390 result = 31 * result + (clean ? 1 : 0); 2391 result = 31 * result + syllableFrequencies.hashCode(); 2392 temp = Double.doubleToLongBits(totalSyllableFrequency); 2393 result = 31 * result + (int) (temp ^ (temp >>> 32)); 2394 temp = Double.doubleToLongBits(vowelStartFrequency); 2395 result = 31 * result + (int) (temp ^ (temp >>> 32)); 2396 temp = Double.doubleToLongBits(vowelEndFrequency); 2397 result = 31 * result + (int) (temp ^ (temp >>> 32)); 2398 temp = Double.doubleToLongBits(vowelSplitFrequency); 2399 result = 31 * result + (int) (temp ^ (temp >>> 32)); 2400 temp = Double.doubleToLongBits(syllableEndFrequency); 2401 result = 31 * result + (int) (temp ^ (temp >>> 32)); 2402 result = 31 * result + (sanityChecks != null ? sanityChecks.length + 1 : 0); 2403 result = 31 * result + (modifiers != null ? modifiers.hashCode() : 0); 2404 return result; 2405 } 2406 2407 @Override 2408 public String toString() { 2409 return "FakeLanguageGen{" + 2410 "openingVowels=" + Arrays.toString(openingVowels) + 2411 ", midVowels=" + Arrays.toString(midVowels) + 2412 ", openingConsonants=" + Arrays.toString(openingConsonants) + 2413 ", midConsonants=" + Arrays.toString(midConsonants) + 2414 ", closingConsonants=" + Arrays.toString(closingConsonants) + 2415 ", vowelSplitters=" + Arrays.toString(vowelSplitters) + 2416 ", closingSyllables=" + Arrays.toString(closingSyllables) + 2417 ", clean=" + clean + 2418 ", syllableFrequencies=" + syllableFrequencies + 2419 ", totalSyllableFrequency=" + totalSyllableFrequency + 2420 ", vowelStartFrequency=" + vowelStartFrequency + 2421 ", vowelEndFrequency=" + vowelEndFrequency + 2422 ", vowelSplitFrequency=" + vowelSplitFrequency + 2423 ", syllableEndFrequency=" + syllableEndFrequency + 2424 ", sanityChecks=" + Arrays.toString(sanityChecks) + 2425 ", modifiers=" + modifiers + 2426 '}'; 2427 } 2428 2429 public FakeLanguageGen copy() 2430 { 2431 return new FakeLanguageGen(openingVowels, midVowels, openingConsonants, midConsonants, 2432 closingConsonants, closingSyllables, vowelSplitters, syllableFrequencies, vowelStartFrequency, 2433 vowelEndFrequency, vowelSplitFrequency, syllableEndFrequency, sanityChecks, clean, modifiers); 2434 } 2435 2436 public static class Modifier implements Serializable 2437 { 2438 private static final long serialVersionUID = 1734863678490422371L; 2439 public final Alteration[] alterations; 2440 public Modifier() 2441 { 2442 this("[tţťțṭ]?[sśŝşšș]+h?", "th"); 2443 } 2444 public Modifier(String pattern, String replacement) 2445 { 2446 alterations = new Alteration[]{new Alteration(pattern, replacement)}; 2447 } 2448 2449 public Modifier(String pattern, String replacement, double chance) 2450 { 2451 alterations = new Alteration[]{new Alteration(pattern, replacement, chance)}; 2452 } 2453 2454 public Modifier(Alteration... alts) 2455 { 2456 alterations = (alts == null) ? new Alteration[0] : alts; 2457 } 2458 public StringBuilder modify(RNG rng, StringBuilder sb) 2459 { 2460 Matcher m; 2461 Replacer.StringBuilderBuffer tb, working = Replacer.wrap(sb); 2462 String tmp; 2463 boolean found; 2464 for(Alteration alt : alterations) { 2465 tmp = working.toString(); 2466 tb = Replacer.wrap(new StringBuilder(tmp.length())); 2467 m = alt.replacer.getPattern().matcher(tmp); 2468 2469 found = false; 2470 while (true) { 2471 if (rng.nextDouble() < alt.chance) { 2472 if(!Replacer.replaceStep(m, alt.replacer.getSubstitution(), tb)) 2473 break; 2474 found = true; 2475 } else { 2476 if(!m.find()) 2477 break; 2478 found = true; 2479 m.getGroup(MatchResult.PREFIX, tb); 2480 m.getGroup(MatchResult.MATCH, tb); 2481 m.setTarget(m, MatchResult.SUFFIX); 2482 } 2483 } 2484 if (found) { 2485 m.getGroup(MatchResult.TARGET, tb); 2486 working = tb; 2487 } 2488 } 2489 return working.toStringBuilder(); 2490 } 2491 /** 2492 * For a character who always pronounces 's', 'ss', and 'sh' as 'th'. 2493 */ 2494 public static final Modifier LISP = new Modifier("[tţťțṭ]?[sśŝşšș]+h?", "th"); 2495 2496 /** 2497 * For a character who always lengthens 's' and 'z' sounds not starting a word. 2498 */ 2499 public static final Modifier HISS = new Modifier("(.)([sśŝşšșzźżž])+", "$1$2$2$2"); 2500 2501 /** 2502 * For a character who has a 20% chance to repeat a starting consonant or vowel. 2503 */ 2504 public static final Modifier STUTTER = new Modifier( 2505 new Alteration("^([^aàáâãäåæāăąǻǽeèéêëēĕėęěiìíîïĩīĭįıoòóôõöøōŏőœǿuùúûüũūŭůűųyýÿŷỳαοειυаеёийъыэюяоу]+)", "$1-$1", 0.2), 2506 new Alteration("^([aàáâãäåæāăąǻǽeèéêëēĕėęěiìíîïĩīĭįıoòóôõöøōŏőœǿuùúûüũūŭůűųαοειυаеёийъыэюяоу]+)", "$1-$1", 0.2)); 2507 2508 /** 2509 * For a language that has a 40% chance to repeat a single Latin vowel (a, e, o, or a variant on one of them 2510 * like å or ö, but not merged letters like æ and œ). 2511 */ 2512 public static final Modifier DOUBLE_VOWELS = new Modifier( 2513 "([^aàáâãäåæāăąǻǽeèéêëēĕėęěiìíîïĩīĭįıoòóôõöøōŏőœǿuùúûüũūŭůűųyýÿŷỳ]|^)" 2514 + "([aàáâãäåāăąǻeèéêëēĕėęěòóôõöøōŏőǿ])" 2515 + "([^aàáâãäåæāăąǻǽeèéêëēĕėęěiìíîïĩīĭįıoòóôõöøōŏőœǿuùúûüũūŭůűųyýÿŷỳ]|$)", "$1$2$2$3", 0.4); 2516 2517 2518 /** 2519 * For a language that has a 50% chance to repeat a single consonant. 2520 */ 2521 public static final Modifier DOUBLE_CONSONANTS = new Modifier("([aàáâãäåæāăąǻǽeèéêëēĕėęěiìíîïĩīĭįıoòóôõöøōŏőœǿuùúûüũūŭůűųyýÿŷỳαοειυаеёийъыэюяоу])" + 2522 "([^aàáâãäåæāăąǻǽeèéêëēĕėęěiìíîïĩīĭįıoòóôõöøōŏőœǿuùúûüũūŭůűųyýÿŷỳαοειυаеёийъыэюяоуqwhjx])" + 2523 "([aàáâãäåæāăąǻǽeèéêëēĕėęěiìíîïĩīĭįıoòóôõöøōŏőœǿuùúûüũūŭůűųyýÿŷỳαοειυаеёийъыэюяоу]|$)", "$1$2$2$3", 0.5); 2524 2525 /** 2526 * For a language that never repeats the same letter twice in a row. 2527 */ 2528 public static final Modifier NO_DOUBLES = new Modifier("(.)\\1", "$1"); 2529 2530 /** 2531 * Creates a Modifier that will replace the nth char in initial with the nth char in change. Expects initial and 2532 * change to be the same length, but will use the lesser length if they are not equal-length. Because of the 2533 * state of the text at the time modifiers are run, only lower-case letters need to be searched for. 2534 * @param initial a String containing lower-case letters or other symbols to be swapped out of a text 2535 * @param change a String containing characters that will replace occurrences of characters in initial 2536 * @return a Modifier that can be added to a FakeLanguageGen with its addModifiers() method 2537 */ 2538 public static Modifier replacementTable(String initial, String change) 2539 { 2540 Alteration[] alts = new Alteration[Math.min(initial.length(), change.length())]; 2541 for (int i = 0; i < alts.length; i++) { 2542 //literal string syntax; avoids sensitive escaping issues and also doesn't need a character class, 2543 // which is slightly slower and has some odd escaping cases. 2544 alts[i] = new Alteration("\\Q" + initial.charAt(i), change.substring(i, i+1)); 2545 } 2546 return new Modifier(alts); 2547 } 2548 2549 public static final Modifier SIMPLIFY_ARABIC = new Modifier( 2550 new Alteration("ţ", "th"), 2551 new Alteration("ĥ", "kh"), 2552 new Alteration("ħ", "khr"), 2553 new Alteration("đ", "dh"), 2554 new Alteration("ď", "dt"), 2555 new Alteration("š", "sh"), 2556 new Alteration("ş", "shw"), 2557 new Alteration("ť", "ch"), 2558 new Alteration("ż", "zh"), 2559 new Alteration("ξ", "ql"), 2560 new Alteration("δ", "qh"), 2561 new Alteration("ġ", "gh"), 2562 new Alteration("ā", "aa"), 2563 new Alteration("ū", "uu"), 2564 new Alteration("ī", "ii")); 2565 2566 @Override 2567 public boolean equals(Object o) { 2568 if (this == o) return true; 2569 if (o == null || getClass() != o.getClass()) return false; 2570 2571 Modifier modifier = (Modifier) o; 2572 2573 // Probably incorrect - comparing Object[] arrays with Arrays.equals 2574 return Arrays.equals(alterations, modifier.alterations); 2575 } 2576 2577 @Override 2578 public int hashCode() { 2579 return Arrays.hashCode(alterations); 2580 } 2581 2582 @Override 2583 public String toString() { 2584 return "Modifier{" + 2585 "alterations=" + Arrays.toString(alterations) + 2586 '}'; 2587 } 2588 } 2589 2590 public static class Alteration implements Serializable 2591 { 2592 private static final long serialVersionUID = -2138854697837563188L; 2593 public Replacer replacer; 2594 public double chance; 2595 public Alteration() 2596 { 2597 this("[tţťțṭ]?[sśŝşšș]+h?", "th"); 2598 } 2599 public Alteration(String pattern, String replacement) 2600 { 2601 replacer = Pattern.compile(pattern).replacer(replacement); 2602 chance = 1.0; 2603 } 2604 public Alteration(String pattern, String replacement, double chance) 2605 { 2606 replacer = Pattern.compile(pattern).replacer(replacement); 2607 this.chance = chance; 2608 } 2609 2610 @Override 2611 public boolean equals(Object o) { 2612 if (this == o) return true; 2613 if (o == null || getClass() != o.getClass()) return false; 2614 2615 Alteration that = (Alteration) o; 2616 2617 if (Double.compare(that.chance, chance) != 0) return false; 2618 return replacer.equals(that.replacer); 2619 2620 } 2621 2622 @Override 2623 public int hashCode() { 2624 int result; 2625 long temp; 2626 result = replacer.hashCode(); 2627 temp = Double.doubleToLongBits(chance); 2628 result = 31 * result + (int) (temp ^ (temp >>> 32)); 2629 return result; 2630 } 2631 2632 @Override 2633 public String toString() { 2634 return "Alteration{" + 2635 "replacer=" + replacer + 2636 ", chance=" + chance + 2637 '}'; 2638 } 2639 } 2640 2641}