Victor Tombs wrote:Talvieno wrote:Huh, I wrote code for something like this. I may post it later. It allows you to "theme" names to different systems, so that, for instance, one system will sound Greek, the next might sound Norse, etc, but all procedurally generated.
That sounds impressive Talvieno.
Thank you.
I certainly hope it lives up to how I hyped it.
Okay, decided to scrounge it up. It was for a different project, but it never got used, so. I don't see any reason not to copy-paste it here. Who knows, maybe Josh can use it to fix some of his wierd "lll" planet names. XD (I remember seeing a name with a triple consonant in one of his videos.)
The main drawback is... it's in java. as I understand it, Limit Theory is coded in C++. A conversion would be fine by me, I wouldn't object. Anybody who wants my code can use it.. Linguistics has always been a hobby of mine.
Very simple to use... it includes a main class so you can see how to call it properly.
Features:
- Essentially infinite name generation
- Generated names can be "themed" to a particular area such as a star system
- All generated names are pronounceable (provided the input words are pronounceable)
- Names generated match the average size and structure of the input word list, so you can control the length of the name you generate
- Will accept any length of input string (although I recommend AT LEAST five words total)
- Returns "Error" when there is no possible way to generate a unique name (but that shouldn't come up unless you're trying to generate 10,000 + names in one go with a tiny (less than 8 words) input string)
- Can handle spaces, commas, and dashes if required, and has the capability of easily being coded for other similar characters.
Examples:
Examples (each example is "planet,star,satellite,nebula,system,galaxy,asteroid" translated into the language indicated):
English: (input: "planet,star,satellite,nebula,system,galaxy,asteroid")
atister
anastate
atebella
atabibud
senerar
plalerer
allilat
stelalet
atatale
niretile
Chinese: (input: "Xingxing,hengxing,weixing,xingyun,xitong,xingxi,xiao,xingxing")
xixixuxi
xingxiao
xititing
xingxing
hungxiao
wingxin
xeiting
hingyixi
xingxixi
wungxing
Spanish: (input: "estrella,nebulosa,planeta,satelite,sistema,asteroide,galaxia")
pleleroxe
sumoisa
etastele
astonase
nalasia
goibesase
asterete
etadilesa
aterene
sutematia
Hindi: (input: "graha,sitara,upagraha,niharika,pranali,akasaganga,ksudragraha")
ksigara
ksipatiga
nalatala
urapaka
agragaka
arasarura
aharakaha
akingasa
nagarina
ahitahiha
Russian: (input: "planety,zvezdy,tumannosti,sputnikovoy,sistemy,Galaktika,asteroidom")
selamoiki
plekodidi
gakoikuka
zveruruda
tektoika
amakatnara
astilakamy
spanekezdy
sistiketni
plodavoy
Japanese: (input: "Wakusei,no,hoshi,no,eisei,seiun,shisutemu,ginga,showakusei,hoshi")
wekosi
sosuku
eisowu
hiwoku
wusaki
wasasi
gitota
wusoti
husowa
sitaka
Code: Select all
package game;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
int i;
ArrayList<String> testArray = new ArrayList <String>();
for (i = 0;i < 10;i++){
testArray.add(NameScript.GetName(testArray,"Wakusei,no,hoshi,no,eisei,seiun,shisutemu,ginga,showakusei,hoshi"));
System.out.println(testArray.get(testArray.size() - 1));
}
}
}
Code: Select all
package game;
/* AUTHOR: Talvieno. Feels so good to finally put my name somewhere.
*
* This code was originally used for a Dwarf Fortress script I made, and used to generate an entire language.
* There, I also had it create word roots (the same idea as "hydro-" or "tele-"), so that words with a similar
* meaning also had a similar prefix/suffix. We don't really need that here, as far as I know, so I took it out.
* It added a whole new level of complexity all by itself.
*/
import java.util.ArrayList;
class NameScript {
static ArrayList<String> consonantStart = new ArrayList<String>();
static ArrayList<String> consonantMiddle = new ArrayList<String>();
static ArrayList<String> consonantEnd = new ArrayList<String>();
static ArrayList<String> vowelStart = new ArrayList<String>();
static ArrayList<String> vowelMiddle = new ArrayList<String>();
static ArrayList<String> vowelEnd = new ArrayList<String>();
static double totalLength = 0.0;
static double totalParts = 0.0;
static ArrayList<Character> vowelList = new ArrayList<Character>();
static ArrayList<Character> consonantList = new ArrayList<Character>();
static ArrayList<Character> swapList = new ArrayList<Character>();
static boolean repeat = true;
static int fails = 0;
static int lengthAdd = 0;
static double regularParts;
static double regularLength;
static ArrayList<String> parentArray = new ArrayList<String>();
static String GetName(ArrayList <String> dadArray,String inputList){
/*This calls a method that sets up all the consonants and vowels - and space characters - in the
* usable language.*/
ConsonantOrVowel();
parentArray = dadArray;//just setting the field.
String inputWords[] = inputList.split(",");
totalLength = 0;
totalParts = 0;
/*Now we run through all the words you put in when you called NameScript, and chop everything
* up into teeny tiny bits.*/
for (int i = 0; i < inputWords.length; i++){
SplitWord(inputWords[i]);//We split the names up,
totalLength += inputWords[i].length(); //count the length of the words,
totalParts += FindParts(inputWords[i]);//and then count the parts in them (part = p a rt/ c ou nt).
}
/* Here we get the average length and average parts for all input words. This helps us create new words
* that are as close in length and composition to the words that are input. It's a little thing, but
* it makes a big difference.*/
regularLength = totalLength / inputWords.length;
regularParts = totalParts / inputWords.length;
/*Were you stupid and didn't input enough words? If so, this is the function that you've been waiting
* for! Call now and we'll double the offer, and you get a set of limited edition steak knives,
* absolutely free! (plus shipping and handling)*/
Crashkill();
String finalName = NameCrafter(); //Yes, I shoved the call to the big method here like it's of little importance.
ResetClass();//Reset everything. Java annoys me sometimes.
return finalName;
}
private static void ResetClass() {
consonantStart.clear();
consonantMiddle.clear();
consonantEnd.clear();
vowelStart.clear();
vowelMiddle.clear();
vowelEnd.clear();
vowelList.clear();
consonantList.clear();
swapList.clear();
}
private static void ConsonantOrVowel(){
//I'm including 'y' and some other characters in both lists... just because it makes things easier.
//You would not believe how hard it is to accurately split words into little bits.
vowelList.add ('a');
vowelList.add ('e');
vowelList.add ('i');
vowelList.add ('o');
vowelList.add ('u');
vowelList.add ('y');
vowelList.add (' ');
vowelList.add ('-');
vowelList.add ('\'');
swapList.add (' ');
swapList.add ('-');
swapList.add ('\'');
consonantList.add ('b');
consonantList.add ('c');
consonantList.add ('d');
consonantList.add ('f');
consonantList.add ('g');
consonantList.add ('h');
consonantList.add ('j');
consonantList.add ('k');
consonantList.add ('l');
consonantList.add ('m');
consonantList.add ('n');
consonantList.add ('p');
consonantList.add ('q');
consonantList.add ('r');
consonantList.add ('s');
consonantList.add ('t');
consonantList.add ('v');
consonantList.add ('w');
consonantList.add ('x');
consonantList.add ('y');
consonantList.add ('z');
consonantList.add (' ');
consonantList.add ('-');
consonantList.add ('\'');
}
private static void SplitWord(String word){
word = word.toLowerCase();
boolean okay = true;
if (word.length() < 3){
okay = false;
}
if (okay == true){
boolean consonantNow = false;
String current = "";
int i = 0;
int lastPoint = 0;
current = word.substring(0, 1);
//First, decide if the first character is a consonant, or a vowel
if (consonantList.contains(current.charAt(0))){
//If it's a consonant, start checking the letters after it as to whether they're consonants too
for (i = 1; i < word.length() + 1; i++){
//Keep adding the consonants to the "current" string
if (consonantList.contains (word.charAt(i))){
current += (word.substring(i, i + 1));
} else {
/*When it hits a letter that isn't a consonant, it spits it back out and breaks to the
* next part.*/
if (!consonantStart.contains(current) || repeat == true){
if (swapList.contains(word.charAt(i-1))){
current += "%";
}
consonantStart.add(current);
}
lastPoint = i;
current = "";
break;
}
}
} else {
for (i = 1; i < word.length() + 1; i++){
if (vowelList.contains (word.charAt(i))){
current += (word.substring(i, i + 1));
} else {
if (!vowelStart.contains(current) || repeat == true){
if (swapList.contains(word.charAt(i-1))){
current += "%";
}
vowelStart.add(current);
}
lastPoint = i;
current = "";
break;
}
}
consonantNow = true;
}
int startPoint = lastPoint;
for (i = startPoint; i < word.length(); i++){
if (consonantNow == true){
for (i = lastPoint; i < word.length(); i++){
if (consonantList.contains(word.charAt(i))){
current += word.substring(i, i + 1);
} else {
if (i == lastPoint){
if (swapList.contains(word.charAt(i))){
current += word.substring(i,i+1);
lastPoint = i + 1;
}
consonantNow = false;
break;
}
if (!consonantMiddle.contains(current) || repeat == true){
if (swapList.contains(word.charAt(i-1))){
current = current + "%";
}
consonantMiddle.add(current);
}
consonantNow = false;
lastPoint = i;
current = "";
break;
}
}
} else {
for (i = lastPoint; i < word.length(); i++){
if (vowelList.contains(word.charAt(i))){
current += word.substring(i, i + 1);
} else {
if (i == lastPoint){
if (swapList.contains(word.charAt(i))){
current += word.substring(i,i+1);
lastPoint = i + 1;
}
consonantNow = true;
break;
}
if (!vowelMiddle.contains(current) || repeat == true){
if (swapList.contains(word.charAt(i-1))){
current = current + "%";
}
vowelMiddle.add(current);
}
consonantNow = true;
lastPoint = i;
current = "";
break;
}
}
}
}
if (consonantNow == true) {
if (!consonantEnd.contains(word.substring(lastPoint,word.length())) || repeat == true) {
consonantEnd.add(word.substring(lastPoint,word.length()));
}
} else {
if (!vowelEnd.contains(word.substring(lastPoint,word.length())) || repeat == true){
vowelEnd.add(word.substring(lastPoint,word.length()));
}
}
}
}
private static int FindParts(String word){
word = word.toLowerCase();
int parts = 0;
boolean consonantNow = false;
String current = "";
int i = 0;
int lastPoint = 0;
current = word.substring(0,1);
if (consonantList.contains(current.charAt(0))){
for (i = 1; i < word.length(); i++){
if (consonantList.contains(word.charAt(i))){
current += word.substring(i,i+1);
} else {
parts += 1;
lastPoint = i;
break;
}
}
} else {
for (i = 1; i < word.length(); i++){
if (vowelList.contains(word.charAt(i))){
current += word.substring(i,i+1);
} else {
parts += 1;
lastPoint = i;
break;
}
}
consonantNow = true;
}
int startPoint = lastPoint;
for (i = startPoint; i < word.length() + 1; i++){
if (consonantNow == true){
for (i = lastPoint; i < word.length(); i++){
if (consonantList.contains(word.charAt(i))){
current += word.substring(i, i + 1);
} else {
if (i == lastPoint){
if (swapList.contains(word.charAt(i))){
current += word.substring(i, i + 1);
lastPoint = i + 1;
}
consonantNow = false;
break;
}
parts += 1;
consonantNow = false;
lastPoint = i;
current = "";
break;
}
}
} else {
for (i = lastPoint; i < word.length(); i++){
if (vowelList.contains(word.charAt(i))){
current += word.substring(i, i + 1);
} else {
if (i == lastPoint){
if (swapList.contains(word.charAt(i))){
current += word.substring(i, i + 1);
lastPoint = i + 1;
}
consonantNow = true;
break;
}
parts += 1;
consonantNow = true;
lastPoint = i;
current = "";
break;
}
}
}
}
parts += 1;
return parts;
}
private static String NameCrafter(){
String thisName = null;
boolean okay = false;
while (okay == false){
//double stringLength = RndX(3.0,8.0);
//double stringParts = RndX(2.0,8.0);
thisName = "";
double minLength = Math.max(3, regularLength * 0.8);
double maxLength = Math.max(5 + lengthAdd, regularLength * 1.25);
double lThis = regularParts * RndX(0.8,1.25);
String consonantVowel = "";
if (RndX(1,consonantStart.size() + vowelStart.size()) < consonantStart.size()){
consonantVowel = "c";
} else {
consonantVowel = "v";
}
if (consonantVowel == "c"){
thisName = consonantStart.get(RndX(1,consonantStart.size()) - 1);
consonantVowel = "v";
} else {
thisName = vowelStart.get(RndX(1,vowelStart.size()) - 1);
consonantVowel = "c";
}
if (thisName.contains("%") == true){
thisName = thisName.replace("%", "");
if (RndX(1,consonantStart.size() - 1) <= consonantStart.size()){
consonantVowel = "c";
thisName = vowelStart.get(RndX(1,vowelStart.size()) - 1);
} else {
consonantVowel = "v";
thisName = consonantStart.get(RndX(1,consonantStart.size()) - 1);
}
}
int i = 0;
int lastResort = RndX(0,2);
if (lastResort < lThis){
for (i = 0; i < lThis - lastResort;i++){
if (consonantVowel == "c"){
consonantVowel = "v";
thisName += consonantMiddle.get(RndX(1,consonantMiddle.size()) - 1);
} else {
consonantVowel = "c";
thisName += vowelMiddle.get(RndX(1,vowelMiddle.size()) - 1);
}
if (thisName.contains("%")){
thisName.replace("%", "");
if (RndX(1,consonantStart.size() + vowelStart.size()) < consonantStart.size()){
consonantVowel = "c";
while (true) {
String addIt = vowelStart.get (RndX(1,vowelStart.size()) - 1);
int j;
for (j = 0; j < swapList.size();j++){
if (addIt.contains(swapList.get(j).toString())){
addIt = "";
}
}
if (addIt != ""){
thisName += addIt;
break;
}
}
} else {
consonantVowel = "v";
while (true) {
String addIt = consonantStart.get (RndX(1,consonantStart.size()) - 1);
int j;
for (j = 0; j < swapList.size();j++){
if (addIt.contains(swapList.get(j).toString())){
addIt = "";
}
}
if (addIt != ""){
thisName += addIt;
break;
}
}
i ++;
}
}
}
}
if (RndX(1,consonantEnd.size() + vowelEnd.size()) < consonantEnd.size()){
if (consonantVowel == "c"){
thisName += consonantEnd.get(RndX(1,consonantEnd.size()) - 1);
} else {
thisName += vowelMiddle.get(RndX(1,vowelMiddle.size()) - 1);
if (thisName.contains("%")){
if (RndX(1,consonantStart.size() + vowelStart.size()) < consonantStart.size()){
consonantVowel = "c";
while (true){
String addIt = vowelStart.get(RndX(1,vowelStart.size()) - 1);
int j;
for (j = 0;j < swapList.size();j++){
if (addIt.contains(swapList.get(j).toString())){
addIt = "";
}
}
if (addIt != ""){
thisName += addIt;
break;
}
}
i++;
} else {
consonantVowel = "v";
while (true){
String addIt = consonantStart.get(RndX(1,consonantStart.size()) - 1);
int j;
for (j = 0;j < swapList.size();j++){
if (addIt.contains(swapList.get(j).toString())){
addIt = "";
}
}
if (addIt != ""){
thisName += addIt;
break;
}
}
i++;
}
}
thisName += consonantEnd.get(RndX(1,consonantEnd.size()) - 1);
}
} else {
if (consonantVowel == "c"){
thisName += consonantMiddle.get(RndX(1,consonantMiddle.size()) - 1);
if (thisName.contains("%")){
if (RndX(1,consonantStart.size() + vowelStart.size()) < consonantStart.size()){
consonantVowel = "c";
while (true){
String addIt = vowelStart.get(RndX(1,vowelStart.size()) - 1);
int j;
for (j = 0; j < swapList.size();j++){
if (addIt.contains(swapList.get(j).toString())){
addIt = "";
}
}
if (addIt != ""){
thisName += addIt;
break;
}
}
i++;
} else {
consonantVowel = "v";
while (true){
String addIt = consonantStart.get(RndX(1,consonantStart.size()) - 1);
int j;
for (j = 0; j < swapList.size();j++){
if (addIt.contains(swapList.get(j).toString())){
addIt = "";
}
}
if (addIt != ""){
thisName += addIt;
break;
}
}
i++;
}
}
thisName += vowelEnd.get(RndX(1,vowelEnd.size()) - 1);
} else {
thisName += vowelEnd.get(RndX(1,vowelEnd.size()) - 1);
}
}
if (thisName.length() > 1 && thisName.length() >= minLength && thisName.length() <= maxLength && ParentContains(thisName) == false){
okay = true;
} else {
thisName = "";
fails ++;
if (fails > 100000){
System.out.println("Too many failed names.");
thisName = "Error";
break;
}
}
}
return thisName;
}
//These are because I'm lazy and like to have one of these in all my programs.
private static double RndX(double a, double b){
return ((Math.random() * ((b - a) + 1)) + a);
}
//And I do so love Java for this. Multiple function with the same name.
private static int RndX(int a, int b){
return (int)((Math.random() * ((b - a) + 1)) + a);
}
private static void Crashkill(){
/*Just a bunch of arbitrary values, designed to match the most common letter combos in our very own solar
* system. These keep the program from crashing when it comes up with a major issue with there
* NOT BEING ENOUGH WORDS. >.> But it happens sometimes. And this breaks the possibility of my script
* crashing your code.*/
if (consonantStart.size() == 0) { consonantStart.add("m"); }
if (consonantMiddle.size() == 0) { consonantMiddle.add("n"); }
if (consonantEnd.size() == 0) { consonantEnd.add("s"); }
if (vowelStart.size() == 0) { vowelStart.add("ea"); }
if (vowelMiddle.size() == 0 ) { vowelMiddle.add("e"); }
if (vowelEnd.size() == 0) { vowelEnd.add("u"); }
}
//check the parent list to make sure name isn't a duplicate.
private static boolean ParentContains(String name){
return parentArray.contains(name);
}
}
How it would work
Basically, what you'd do is take a long list (I guess from a *.txt) full of random names, and pull six to eight different names from it. You would then use this list for absolutely everything within that particular star system that needs a name. That would "theme" names to that particular star system, so that if you saw a ship, you might be able to easily say, "Oh, that ship is from the ______ system," provided you were familiar enough with the name scheme for that star system. Even if not, it would make it seem as if there was a specific "language" generated with that system.
Even better, you could attach certain names to factions. For example, say Faction A includes, as a string: "Ulysses,Missile,Sassafras,Carcass" And, then, System A includes the string "Quintet,Laquer,Queenly,Croquet". Anything created by that faction would use the inputs for the faction, while it would
also include the four names in the string for that particular star system. This added bit of flavor would be able to theme names not only for the star system, but for factions as well, and while it might not be immediately noticeable, you might eventually recognize that the "ss" is far more common with faction A, and the "qu" is far more common with System A. It's a noticeable difference, but subtle, so it wouldn't be like it was hitting you over the head with it.