package squidpony; import regexodus.*; import squidpony.squidmath.*; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import static squidpony.Maker.makeList; import static squidpony.Maker.makeOM; /** * A text processing class that can swap out occurrences of words and replace them with their synonyms. * Created by Tommy Ettinger on 5/23/2016. */ public class Thesaurus implements Serializable{ private static final long serialVersionUID = 3387639905758074640L; protected static final Pattern wordMatch = Pattern.compile("([\\pL`]+)"), similarFinder = Pattern.compile(".*?\\b(\\w\\w\\w\\w).*?{\\@1}.*$", "ui"); public OrderedMap<String, GapShuffler<String>> mappings; protected StatefulRNG rng; public transient ArrayList<FakeLanguageGen> randomLanguages = new ArrayList<>(2); /** * Constructs a new Thesaurus with an unseeded RNG used to shuffle word order. */ public Thesaurus() { mappings = new OrderedMap<>(256); rng = new StatefulRNG(); } /** * Constructs a new Thesaurus, seeding its RNG (used to shuffle word order) with the next long from the given RNG. * @param rng an RNG that will only be used to get one long (for seeding this class' RNG) */ public Thesaurus(RNG rng) { mappings = new OrderedMap<>(256); this.rng = new StatefulRNG(rng.nextLong()); } /** * Constructs a new Thesaurus, seeding its RNG (used to shuffle word order) with shuffleSeed. * @param shuffleSeed a long for seeding this class' RNG */ public Thesaurus(long shuffleSeed) { mappings = new OrderedMap<>(256); this.rng = new StatefulRNG(shuffleSeed); } /** * Constructs a new Thesaurus, seeding its RNG (used to shuffle word order) with shuffleSeed. * @param shuffleSeed a String for seeding this class' RNG */ public Thesaurus(String shuffleSeed) { mappings = new OrderedMap<>(256); this.rng = new StatefulRNG(shuffleSeed); } /** * Allows this Thesaurus to find the exact words in synonyms and, when requested, replace each occurrence with a * different word from the same Collection. Each word in synonyms should have the same part of speech, so "demon" * and "devils" should not be in the same list of synonyms (singular noun and plural noun), but "demon" and "devil" * could be (each is a singular noun). The Strings in synonyms should all be lower-case, since case is picked up * from the text as it is being replaced and not from the words themselves. Proper nouns should normally not be used * as synonyms, since this could get very confusing if it changed occurrences of "Germany" to "France" at random and * a character's name, like "Dorothy", to "Anne", "Emily", "Cynthia", etc. in the middle of a section about Dorothy. * The word matching pattern this uses only matches all-letter words, not words that contain hyphens, apostrophes, * or other punctuation. * @param synonyms a Collection of lower-case Strings with similar meaning and the same part of speech * @return this for chaining */ public Thesaurus addSynonyms(Collection<String> synonyms) { if(synonyms.isEmpty()) return this; long prevState = rng.getState(); rng.setState(CrossHash.hash64(synonyms)); GapShuffler<String> shuffler = new GapShuffler<>(synonyms, rng); for(String syn : synonyms) { mappings.put(syn, shuffler); } rng.setState(prevState); return this; } /** * Allows this Thesaurus to replace a specific keyword, typically containing multiple backtick characters ('`') so * it can't be confused with a "real word," with one of the words in synonyms (chosen in shuffled order). The * backtick is the only punctuation character that this class' word matcher considers part of a word, both for this * reason and because it is rarely used in English text. * @param keyword a word (typically containing backticks, '`') that will be replaced by a word from synonyms * @param synonyms a Collection of lower-case Strings with similar meaning and the same part of speech * @return this for chaining */ public Thesaurus addCategory(String keyword, Collection<String> synonyms) { if(synonyms.isEmpty()) return this; long prevState = rng.getState(); rng.setState(CrossHash.hash64(synonyms)); GapShuffler<String> shuffler = new GapShuffler<>(synonyms, rng); mappings.put(keyword, shuffler); rng.setState(prevState); return this; } /** * Adds several pre-made categories to this Thesaurus' known categories, but won't cause it to try to replace normal * words with synonyms (only categories, which contain backticks in the name). The keywords this currently knows, * and the words it will replace those keywords with, are: * <br> * <ul> * <li>"calm`adj`": harmonious, peaceful, pleasant, serene, placid, tranquil, calm</li> * <li>"calm`noun`": harmony, peace, kindness, serenity, tranquility, calm</li> * <li>"org`noun`": fraternity, brotherhood, order, group, foundation, association, guild, fellowship, partnership</li> * <li>"org`nouns`": fraternities, brotherhoods, orders, groups, foundations, associations, guilds, fellowships, partnerships</li> * <li>"empire`adj`": imperial, prince's, king's, sultan's, regal, dynastic, royal, hegemonic, monarchic, ascendant, emir's, lordly</li> * <li>"empire`noun`": empire, emirate, kingdom, sultanate, dominion, dynasty, imperium, hegemony, triumvirate, ascendancy, monarchy, commonwealth</li> * <li>"empire`nouns`": empires, emirates, kingdoms, sultanates, dominions, dynasties, imperia, hegemonies, triumvirates, ascendancies, monarchies, commonwealths</li> * <li>"union`adj`": united, allied, people's, confederated, federated, congressional, independent, associated, unified, democratic</li> * <li>"union`noun`": union, alliance, coalition, confederation, federation, congress, confederacy, league, faction, republic</li> * <li>"union`nouns`": unions, alliances, coalitions, confederations, federations, congresses, confederacies, leagues, factions, republics</li> * <li>"militia`noun`": rebellion, resistance, militia, liberators, warriors, fighters, militants, front, irregulars</li> * <li>"militia`nouns`": rebellions, resistances, militias, liberators, warriors, fighters, militants, fronts, irregulars</li> * <li>"gang`noun`": gang, syndicate, mob, crew, posse, mafia, cartel</li> * <li>"gang`nouns`": gangs, syndicates, mobs, crews, posses, mafias, cartels</li> * <li>"duke`noun`": duke, earl, baron, fief, lord, shogun</li> * <li>"duke`nouns`": dukes, earls, barons, fiefs, lords, shoguns</li> * <li>"duchy`noun`": duchy, earldom, barony, fiefdom, lordship, shogunate</li> * <li>"duchy`nouns`": duchies, earldoms, baronies, fiefdoms, lordships, shogunates</li> * <li>"magical`adj`": arcane, enchanted, sorcerous, ensorcelled, magical, mystical</li> * <li>"holy`adj`": auspicious, divine, holy, sacred, prophetic, blessed, godly</li> * <li>"unholy`adj`": bewitched, occult, unholy, macabre, accursed, profane, vile</li> * <li>"forest`adj`": natural, primal, verdant, lush, fertile, bountiful</li> * <li>"forest`noun`": nature, forest, greenery, jungle, woodland, grove, copse</li> * <li>"fancy`adj`": grand, glorious, magnificent, magnanimous, majestic, great, powerful</li> * <li>"evil`adj`": heinous, scurrilous, terrible, horrible, debased, wicked, evil, malevolent, nefarious, vile</li> * <li>"good`adj`": righteous, moral, good, pure, compassionate, flawless, perfect</li> * <li>"sinister`adj`": shadowy, silent, lethal, deadly, fatal, venomous, cutthroat, murderous, bloodstained, stalking</li> * <li>"sinister`noun`": shadow, silence, assassin, ninja, venom, poison, snake, murder, blood, razor, tiger</li> * <li>"blade`noun`": blade, knife, sword, axe, stiletto, katana, scimitar, hatchet, spear, glaive, halberd, * hammer, maul, flail, mace, sickle, scythe, whip, lance, nunchaku, saber, cutlass, trident</li> * <li>"bow`noun`": bow, longbow, shortbow, crossbow, sling, atlatl, bolas, javelin, net, shuriken, dagger</li> * <li>"weapon`noun`": blade, knife, sword, axe, stiletto, katana, scimitar, hatchet, spear, glaive, halberd, * hammer, maul, flail, mace, sickle, scythe, whip, lance, nunchaku, saber, cutlass, trident, * bow, longbow, shortbow, crossbow, sling, atlatl, bolas, javelin, net, shuriken, dagger</li> * <li>"musket`noun`": arquebus, blunderbuss, musket, matchlock, flintlock, wheellock, cannon</li> * <li>"grenade`noun`": rocket, grenade, missile, bomb, warhead, explosive, flamethrower</li> * <li>"rifle`noun`": pistol, rifle, handgun, firearm, longarm, shotgun</li> * <li>"blade`nouns`": blades, knives, swords, axes, stilettos, katana, scimitars, hatchets, spears, glaives, halberds, * hammers, mauls, flails, maces, sickles, scythes, whips, lances, nunchaku, sabers, cutlasses, tridents</li> * <li>"bow`nouns`": bows, longbows, shortbows, crossbows, slings, atlatls, bolases, javelins, nets, shuriken, daggers</li> * <li>"weapon`nouns`": blades, knives, swords, axes, stilettos, katana, scimitars, hatchets, spears, glaives, halberds, * hammers, mauls, flails, maces, sickles, scythes, whips, lances, nunchaku, sabers, cutlasses, tridents, * bows, longbows, shortbows, crossbows, slings, atlatls, bolases, javelins, nets, shuriken, daggers</li> * <li>"musket`nouns`": arquebusses, blunderbusses, muskets, matchlocks, flintlocks, wheellocks, cannons</li> * <li>"grenade`nouns`": rockets, grenades, missiles, bombs, warheads, explosives, flamethrowers</li> * <li>"rifle`nouns`": pistols, rifles, handguns, firearms, longarms, shotguns</li> * <li>"tech`adj`": cyber, digital, electronic, techno, hacker, crypto, turbo, mechanical, servo</li> * <li>"sole`adj`": sole, true, singular, total, ultimate, final, last</li> * <li>"light`adj`": bright, glowing, solar, stellar, lunar, radiant, luminous, shimmering</li> * <li>"light`noun`": light, glow, sun, star, moon, radiance, dawn, torch</li> * <li>"light`nouns`": lights, glimmers, suns, stars, moons, torches</li> * <li>"smart`adj`": brilliant, smart, genius, wise, clever, cunning, mindful, aware</li> * <li>"smart`noun`": genius, wisdom, cunning, awareness, mindfulness, acumen, smarts, knowledge</li> * <li>"bandit`noun`": thief, raider, bandit, rogue, brigand, highwayman, pirate</li> * <li>"bandit`nouns`": thieves, raiders, bandits, rogues, brigands, highwaymen, pirates</li> * <li>"guard`noun`": protector, guardian, warden, defender, guard, shield, sentinel, watchman, knight</li> * <li>"guard`nouns`": protectors, guardians, wardens, defenders, guards, shields, sentinels, watchmen, knights</li> * <li>"rage`noun`": rage, fury, anger, wrath, frenzy, vengeance</li> * </ul> * Capitalizing the first letter in the keyword where it appears in text you call process() on will capitalize the * first letter of the produced fake word. Capitalizing the second letter will capitalize the whole produced fake * word. This applies only per-instance of each keyword; it won't change the internally-stored list of words. * @return this for chaining */ public Thesaurus addKnownCategories() { for(Map.Entry<String, ArrayList<String>> kv : categories.entrySet()) { addCategory(kv.getKey(), kv.getValue()); } return this; } /** * Adds a large list of words pre-generated by FakeLanguageGen and hand-picked for fitness, and makes them * accessible with a keyword based on the language and any tweaks made to it. The keywords this currently knows: * <br> * <ul> * <li>"jp`gen`": Imitation Japanese</li> * <li>"fr`gen`": Imitation French; contains some accented chars</li> * <li>"gr`gen`": Imitation Greek (romanized)</li> * <li>"ru`gen`": Imitation Russian (romanized)</li> * <li>"sw`gen`": Imitation Swahili</li> * <li>"so`gen`": Imitation Somali</li> * <li>"en`gen`": Imitation English (not very good on its own)</li> * <li>"ar`gen`": Imitation Arabic (better); doesn't have accents and should be more readable</li> * <li>"ar`acc`gen`": Imitation Arabic (worse); has special accents and uses two Greek letters as well</li> * <li>"hi`gen`": Imitation Hindi (romanized and with accents removed)</li> * <li>"fn`gen`": Fantasy Names; styled after the possibly-Europe-like names common in fantasy books</li> * <li>"fn`acc`gen`": Fancy Fantasy Names; the same as "fn`gen`", but with lots of accented chars</li> * <li>"lc`gen`": Lovecraft; styled after the names of creatures from H.P. Lovecraft's Cthulhu Mythos</li> * <li>"ru`so`gen`": Mix of imitation Russian (75%) and Somali (25%)</li> * <li>"gr`hi`gen`": Mix of imitation Greek (50%) and Hindi (accents removed, 50%)</li> * <li>"sw`fr`gen`": Mix of imitation Swahili (70%) and French (30%)</li> * <li>"ar`jp`gen`": Mix of imitation Arabic (accents removed, 60%) and Japanese (40%)</li> * <li>"sw`gr`gen`": Mix of imitation Swahili (60%) and Greek (40%)</li> * <li>"gr`so`gen`": Mix of imitation Greek (60%) and Somali (40%)</li> * <li>"en`hi`gen`": Mix of imitation English (60%) and Hindi (accents removed, 40%)</li> * <li>"en`jp`gen`": Mix of imitation English (60%) and Japanese (40%)</li> * <li>"so`hi`gen`": Mix of imitation Somali (60%) and Hindi (accents removed, 40%)</li> * <li>"ru`gr`gen`": Mix of imitation Russian (60%) and Greek (40%)</li> * <li>"lc`gr`gen`": Mix of Lovecraft-styled names (60%) and imitation Russian (40%)</li> * <li>"fr`mod`gen`": Imitation French; modified to replace doubled consonants like "gg" with "gsh" or similar</li> * <li>"jp`mod`gen`": Imitation Japanese; modified to sometimes double vowels from "a" to "aa" or similar</li> * <li>"so`mod`gen`": Imitation Somali (not really); modified beyond recognition and contains accents</li> * </ul> * Capitalizing the first letter in the keyword where it appears in text you call process() on will capitalize the * first letter of the produced fake word, which is often desirable for things like place names. Capitalizing the * second letter will capitalize the whole produced fake word. This applies only per-instance of each keyword; it * won't change the internally-stored list of words. * @return this for chaining */ public Thesaurus addFakeWords() { long state = rng.getState(); for(Map.Entry<String, FakeLanguageGen> kv : languages.entrySet()) { ArrayList<String> words = new ArrayList<>(16); for (int i = 0; i < 16; i++) { words.add(kv.getValue().word(rng, false, rng.between(2, 4))); } addCategory(kv.getKey().replace("gen", "pre"), words); } rng.setState(state); return this; } /** * Given a String, StringBuilder, or other CharSequence that should contain words this knows synonyms for, this * replaces each occurrence of such a known word with one of its synonyms, leaving unknown words untouched. Words * that were learned together as synonyms with addSynonyms() will be replaced in such a way that an individual * replacement word should not occur too close to a previous occurrence of the same word; that is, replacing the * text "You fiend! You demon! You despoiler of creation; devil made flesh!", where "fiend", "demon", and "devil" * are all synonyms, would never produce a string that contained "fiend" as the replacement for all three of those. * @param text a CharSequence, such as a String, that contains words in the source language * @return a String of the translated text. */ public String process(CharSequence text) { Replacer rep = wordMatch.replacer(new SynonymSubstitution()); return rep.replace(text); } public String lookup(String word) { if(word.isEmpty()) return word; String word2 = word.toLowerCase(); if(mappings.containsKey(word2)) { String nx = mappings.get(word2).next(); if(nx.isEmpty()) return nx; if(word.length() > 1 && Category.Lu.contains(word.charAt(1))) return nx.toUpperCase(); if(Category.Lu.contains(word.charAt(0))) { return Character.toUpperCase(nx.charAt(0)) + nx.substring(1, nx.length()); } return nx; } else if(languages.containsKey(word2)) { if(word.length() > 1 && Category.Lu.contains(word.charAt(1))) return languages.get(word2).word(rng, false, rng.between(2, 4)).toUpperCase(); if(Category.Lu.contains(word.charAt(0))) { return languages.get(word2).word(rng, true, rng.between(2, 4)); } return languages.get(word2).word(rng, false, rng.between(2, 4)); } return word; } private class SynonymSubstitution implements Substitution { @Override public void appendSubstitution(MatchResult match, TextBuffer dest) { dest.append(lookup(match.group(0))); } } private class RandomLanguageSubstitution implements Substitution { @Override public void appendSubstitution(MatchResult match, TextBuffer dest) { FakeLanguageGen lang = FakeLanguageGen.randomLanguage(rng.nextLong()); randomLanguages.add(lang); dest.append(lang.word(rng, true)); } } /** * Generates a random possible name for a nation, such as "Iond-Gouccief Alliance" or "The Last Drayo Commonwealth". * Needs {@link #addKnownCategories()} to be called on this Thesaurus first. May use accented characters, as in * "Thùdshù-Hyóttiálb Hegemony" or "The Glorious Chô Empire"; if you want to strip these out and replace accented * chars with their un-accented counterparts, you can use {@link FakeLanguageGen#removeAccents(CharSequence)}, which * returns a CharSequence that can be converted to String if needed. Shortly after calling this method, but before * calling it again, you can retrieve the generated random languages, if any were used while making nation names, by * getting the FakeLanguageGen elements of this class' {@link #randomLanguages} field. Using one of these * FakeLanguageGen objects, you can produce many more words with a similar style to the nation name, like "Drayo" in * "The Last Drayo Commonwealth". If more than one language was used in the nation name, as in "Thùdshù-Hyóttiálb * Hegemony", you will have two languages in randomLanguages, so here "Thùdshù" would be generated by the first * language, and "Hyóttiálb" by the second language. Calling this method replaces the current contents of * randomLanguages, so if you want to use those languages, get them while you can. * * @return a random name for a nation or a loose equivalent to a nation, as a String */ public String makeNationName() { String working = process(rng.getRandomElement(nationTerms)); int frustration = 0; while (frustration++ < 8 && similarFinder.matches(working)) working = process(rng.getRandomElement(nationTerms)); randomLanguages.clear(); RandomLanguageSubstitution sub = new RandomLanguageSubstitution(); Replacer replacer = Pattern.compile("@").replacer(sub); return replacer.replace(working); } private static final String[] nationTerms = new String[]{ "Union`adj` Union`noun` of @", "Union`adj` @ Union`noun`", "@ Union`noun`", "@ Union`noun`", "@-@ Union`noun`", "Union`adj` Union`noun` of @", "Union`adj` Duchy`nouns` of @", "The @ Duchy`noun`", "The Fancy`adj` @ Duchy`noun`", "The Sole`adj` @ Empire`noun`", "@ Empire`noun`", "@ Empire`noun`", "@ Empire`noun`", "@-@ Empire`noun`", "The Fancy`adj` @ Empire`noun`", "The Fancy`adj` @ Empire`noun`", "The Holy`adj` @ Empire`noun`",}; public static final OrderedMap<String, ArrayList<String>> categories = makeOM( "calm`adj`", makeList("harmonious", "peaceful", "pleasant", "serene", "placid", "tranquil", "calm"), "calm`noun`", makeList("harmony", "peace", "kindness", "serenity", "tranquility", "calm"), "org`noun`", makeList("fraternity", "brotherhood", "order", "group", "foundation", "association", "guild", "fellowship", "partnership"), "org`nouns`", makeList("fraternities", "brotherhoods", "orders", "groups", "foundations", "associations", "guilds", "fellowships", "partnerships"), "empire`adj`", makeList("imperial", "prince's", "king's", "sultan's", "regal", "dynastic", "royal", "hegemonic", "monarchic", "ascendant", "emir's", "lordly"), "empire`noun`", makeList("empire", "emirate", "kingdom", "sultanate", "dominion", "dynasty", "imperium", "hegemony", "triumvirate", "ascendancy", "monarchy", "commonwealth"), "empire`nouns`", makeList("empires", "emirates", "kingdoms", "sultanates", "dominions", "dynasties", "imperia", "hegemonies", "triumvirates", "ascendancies", "monarchies", "commonwealths"), "union`adj`", makeList("united", "allied", "people's", "confederated", "federated", "congressional", "independent", "associated", "unified", "democratic"), "union`noun`", makeList("union", "alliance", "coalition", "confederation", "federation", "congress", "confederacy", "league", "faction", "republic"), "union`nouns`", makeList("unions", "alliances", "coalitions", "confederations", "federations", "congresses", "confederacies", "leagues", "factions", "republics"), "militia`noun`", makeList("rebellion", "resistance", "militia", "liberators", "warriors", "fighters", "militants", "front", "irregulars"), "militia`nouns`", makeList("rebellions", "resistances", "militias", "liberators", "warriors", "fighters", "militants", "fronts", "irregulars"), "gang`noun`", makeList("gang", "syndicate", "mob", "crew", "posse", "mafia", "cartel"), "gang`nouns`", makeList("gangs", "syndicates", "mobs", "crews", "posses", "mafias", "cartels"), "duke`noun`", makeList("duke", "earl", "baron", "fief", "lord", "shogun"), "duke`nouns`", makeList("dukes", "earls", "barons", "fiefs", "lords", "shoguns"), "duchy`noun`", makeList("duchy", "earldom", "barony", "fiefdom", "lordship", "shogunate"), "duchy`nouns`", makeList("duchies", "earldoms", "baronies", "fiefdoms", "lordships", "shogunates"), "magical`adj`", makeList("arcane", "enchanted", "sorcerous", "ensorcelled", "magical", "mystical"), "holy`adj`", makeList("auspicious", "divine", "holy", "sacred", "prophetic", "blessed", "godly"), "unholy`adj`", makeList("bewitched", "occult", "unholy", "macabre", "accursed", "profane", "vile"), "forest`adj`", makeList("natural", "primal", "verdant", "lush", "fertile", "bountiful"), "forest`noun`", makeList("nature", "forest", "greenery", "jungle", "woodland", "grove", "copse"), "fancy`adj`", makeList("grand", "glorious", "magnificent", "magnanimous", "majestic", "great", "powerful"), "evil`adj`", makeList("heinous", "scurrilous", "terrible", "horrible", "debased", "wicked", "evil", "malevolent", "nefarious", "vile"), "good`adj`", makeList("righteous", "moral", "good", "pure", "compassionate", "flawless", "perfect"), "sinister`adj`", makeList("shadowy", "silent", "lethal", "deadly", "fatal", "venomous", "cutthroat", "murderous", "bloodstained", "stalking"), "sinister`noun`", makeList("shadow", "silence", "assassin", "ninja", "venom", "poison", "snake", "murder", "blood", "razor", "tiger"), "blade`noun`", makeList("blade", "knife", "sword", "axe", "stiletto", "katana", "scimitar", "hatchet", "spear", "glaive", "halberd", "hammer", "maul", "flail", "mace", "sickle", "scythe", "whip", "lance", "nunchaku", "saber", "cutlass", "trident"), "bow`noun`", makeList("bow", "longbow", "shortbow", "crossbow", "sling", "atlatl", "bolas", "javelin", "net", "shuriken", "dagger"), "weapon`noun`", makeList("blade", "knife", "sword", "axe", "stiletto", "katana", "scimitar", "hatchet", "spear", "glaive", "halberd", "hammer", "maul", "flail", "mace", "sickle", "scythe", "whip", "lance", "nunchaku", "saber", "cutlass", "trident", "bow", "longbow", "shortbow", "crossbow", "sling", "atlatl", "bolas", "javelin", "net", "shuriken", "dagger"), "musket`noun`", makeList("arquebus", "blunderbuss", "musket", "matchlock", "flintlock", "wheellock", "cannon"), "grenade`noun`", makeList("rocket", "grenade", "missile", "bomb", "warhead", "explosive", "flamethrower"), "rifle`noun`", makeList("pistol", "rifle", "handgun", "firearm", "longarm", "shotgun"), "blade`nouns`", makeList("blades", "knives", "swords", "axes", "stilettos", "katana", "scimitars", "hatchets", "spears", "glaives", "halberds", "hammers", "mauls", "flails", "maces", "sickles", "scythes", "whips", "lances", "nunchaku", "sabers", "cutlasses", "tridents"), "bow`nouns`", makeList("bows", "longbows", "shortbows", "crossbows", "slings", "atlatls", "bolases", "javelins", "nets", "shuriken", "daggers"), "weapon`nouns`", makeList("blades", "knives", "swords", "axes", "stilettos", "katana", "scimitars", "hatchets", "spears", "glaives", "halberds", "hammers", "mauls", "flails", "maces", "sickles", "scythes", "whips", "lances", "nunchaku", "sabers", "cutlasses", "tridents", "bows", "longbows", "shortbows", "crossbows", "slings", "atlatls", "bolases", "javelins", "nets", "shuriken", "daggers"), "musket`nouns`", makeList("arquebusses", "blunderbusses", "muskets", "matchlocks", "flintlocks", "wheellocks", "cannons"), "grenade`nouns`", makeList("rockets", "grenades", "missiles", "bombs", "warheads", "explosives", "flamethrowers"), "rifle`nouns`", makeList("pistols", "rifles", "handguns", "firearms", "longarms", "shotguns"), "tech`adj`", makeList("cyber", "digital", "electronic", "techno", "hacker", "crypto", "turbo", "mechanical", "servo"), "sole`adj`", makeList("sole", "true", "singular", "total", "ultimate", "final", "last"), "light`adj`", makeList("bright", "glowing", "solar", "stellar", "lunar", "radiant", "luminous", "shimmering"), "light`noun`", makeList("light", "glow", "sun", "star", "moon", "radiance", "dawn", "torch"), "light`nouns`", makeList("lights", "glimmers", "suns", "stars", "moons", "torches"), "smart`adj`", makeList("brilliant", "smart", "genius", "wise", "clever", "cunning", "mindful", "aware"), "smart`noun`", makeList("genius", "wisdom", "cunning", "awareness", "mindfulness", "acumen", "smarts", "knowledge"), "bandit`noun`", makeList("thief", "raider", "bandit", "rogue", "brigand", "highwayman", "pirate"), "bandit`nouns`", makeList("thieves", "raiders", "bandits", "rogues", "brigands", "highwaymen", "pirates"), "guard`noun`", makeList("protector", "guardian", "warden", "defender", "guard", "shield", "sentinel", "watchman", "knight"), "guard`nouns`", makeList("protectors", "guardians", "wardens", "defenders", "guards", "shields", "sentinels", "watchmen", "knights"), "rage`noun`", makeList("rage", "fury", "anger", "wrath", "frenzy", "vengeance") ); public static final OrderedMap<String, FakeLanguageGen> languages = makeOM( "lc`gen`", FakeLanguageGen.LOVECRAFT, "jp`gen`", FakeLanguageGen.JAPANESE_ROMANIZED, "fr`gen`", FakeLanguageGen.FRENCH, "gr`gen`", FakeLanguageGen.GREEK_ROMANIZED, "ru`gen`", FakeLanguageGen.RUSSIAN_ROMANIZED, "sw`gen`", FakeLanguageGen.SWAHILI, "so`gen`", FakeLanguageGen.SOMALI, "en`gen`", FakeLanguageGen.ENGLISH, "fn`gen`", FakeLanguageGen.FANTASY_NAME, "fn`acc`gen`", FakeLanguageGen.FANCY_FANTASY_NAME, "ar`acc`gen`", FakeLanguageGen.ARABIC_ROMANIZED.addAccents(0.15, 0.0), "ar`gen`", FakeLanguageGen.ARABIC_ROMANIZED, "hi`gen`", FakeLanguageGen.HINDI_ROMANIZED, "in`gen`", FakeLanguageGen.INUKTITUT, "nr`gen`acc`", FakeLanguageGen.NORSE, "nr`gen`", FakeLanguageGen.NORSE.addModifiers(FakeLanguageGen.Modifier.SIMPLIFY_NORSE), "na`gen`", FakeLanguageGen.NAHUATL, "ru`so`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.RUSSIAN_ROMANIZED, 3, FakeLanguageGen.SOMALI, 2), "gr`hi`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.GREEK_ROMANIZED, 3, FakeLanguageGen.HINDI_ROMANIZED, 2), "sw`fr`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.SWAHILI, 3, FakeLanguageGen.FRENCH, 2), "ar`jp`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.ARABIC_ROMANIZED, 3, FakeLanguageGen.JAPANESE_ROMANIZED, 2), "sw`gr`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.SWAHILI, 3, FakeLanguageGen.GREEK_ROMANIZED, 2), "gr`so`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.GREEK_ROMANIZED, 3, FakeLanguageGen.SOMALI, 2), "en`hi`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.ENGLISH, 3, FakeLanguageGen.HINDI_ROMANIZED, 2), "en`jp`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.ENGLISH, 3, FakeLanguageGen.JAPANESE_ROMANIZED, 2), "so`hi`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.SOMALI, 3, FakeLanguageGen.HINDI_ROMANIZED, 2), "fr`mod`gen`", FakeLanguageGen.FRENCH.addModifiers(FakeLanguageGen.modifier("([^aeiou])\\1", "$1ph", 0.3), FakeLanguageGen.modifier("([^aeiou])\\1", "$1ch", 0.4), FakeLanguageGen.modifier("([^aeiou])\\1", "$1sh", 0.5), FakeLanguageGen.modifier("([^aeiou])\\1", "$1", 0.9)), "jp`mod`gen`", FakeLanguageGen.JAPANESE_ROMANIZED.addModifiers(FakeLanguageGen.Modifier.DOUBLE_VOWELS), "so`mod`gen`", FakeLanguageGen.SOMALI.addModifiers(FakeLanguageGen.modifier("([kd])h", "$1"), FakeLanguageGen.modifier("([pfsgkcb])([aeiouy])", "$1l$2", 0.35), FakeLanguageGen.modifier("ii", "ai"), FakeLanguageGen.modifier("uu", "ia"), FakeLanguageGen.modifier("([aeo])\\1", "$1"), FakeLanguageGen.modifier("^x", "v"), FakeLanguageGen.modifier("([^aeiou]|^)u([^aeiou]|$)", "$1a$2", 0.6), FakeLanguageGen.modifier("([aeiou])[^aeiou]([aeiou])", "$1v$2", 0.06), FakeLanguageGen.modifier("([aeiou])[^aeiou]([aeiou])", "$1l$2", 0.07), FakeLanguageGen.modifier("([aeiou])[^aeiou]([aeiou])", "$1n$2", 0.07), FakeLanguageGen.modifier("([aeiou])[^aeiou]([aeiou])", "$1z$2", 0.08), FakeLanguageGen.modifier("([^aeiou])[aeiou]+$", "$1ia", 0.35), FakeLanguageGen.modifier("([^aeiou])[bpdtkgj]", "$1"), FakeLanguageGen.modifier("[jg]$", "th"), FakeLanguageGen.modifier("g", "c", 0.92), FakeLanguageGen.modifier("([aeiou])[wy]$", "$1l", 0.6), FakeLanguageGen.modifier("([aeiou])[wy]$", "$1n"), FakeLanguageGen.modifier("[qf]$", "l", 0.4), FakeLanguageGen.modifier("[qf]$", "n", 0.65), FakeLanguageGen.modifier("[qf]$", "s"), FakeLanguageGen.modifier("cy", "sp"), FakeLanguageGen.modifier("kl", "sk"), FakeLanguageGen.modifier("qu+", "qui"), FakeLanguageGen.modifier("q([^u])", "qu$1"), FakeLanguageGen.modifier("cc", "ch"), FakeLanguageGen.modifier("[^aeiou]([^aeiou][^aeiou])", "$1"), FakeLanguageGen.Modifier.NO_DOUBLES), "ru`gr`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.RUSSIAN_ROMANIZED, 3, FakeLanguageGen.GREEK_ROMANIZED, 2), "lc`gr`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.LOVECRAFT, 3, FakeLanguageGen.GREEK_ROMANIZED, 2), "in`so`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.INUKTITUT, 3, FakeLanguageGen.SOMALI, 2), "ar`in`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.ARABIC_ROMANIZED, 3, FakeLanguageGen.INUKTITUT, 2), "na`lc`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.NAHUATL, 3, FakeLanguageGen.LOVECRAFT, 2), "na`sw`gen`", FakeLanguageGen.mixAll(FakeLanguageGen.NAHUATL, 3, FakeLanguageGen.SWAHILI, 2), "nr`ru`gen`", FakeLanguageGen.mixAll( FakeLanguageGen.NORSE.addModifiers(FakeLanguageGen.Modifier.SIMPLIFY_NORSE), 3, FakeLanguageGen.RUSSIAN_ROMANIZED, 2), "nr`in`gen`", FakeLanguageGen.mixAll( FakeLanguageGen.NORSE.addModifiers(FakeLanguageGen.Modifier.SIMPLIFY_NORSE), 3, FakeLanguageGen.INUKTITUT, 2) ); }