You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

487 lines
9.8 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

function shuffled(list) {
var newlist = [];
for (var i = 0; i < list.length; i++) {
newlist.push(list[i]);
}
for (var i = list.length - 1; i > 0; i--) {
var tmp = newlist[i];
var j = randrange(i);
newlist[i] = newlist[j];
newlist[j] = tmp;
}
return newlist;
}
function choose(list, exponent) {
exponent = exponent || 1;
return list[Math.floor(Math.pow(Math.random(), exponent) * list.length)];
}
function randrange(lo, hi) {
if (hi == undefined) {
hi = lo;
lo = 0;
}
return Math.floor(Math.random() * (hi - lo)) + lo;
}
function join(list, sep) {
if (list.length == 0) return '';
sep = sep || '';
var s = list[0];
for (var i = 1; i < list.length; i++) {
s += sep;
s += list[i];
}
return s;
}
function capitalize(word) {
return word[0].toUpperCase() + word.slice(1);
}
function spell(lang, syll) {
if (lang.noortho) return syll;
var s = '';
for (var i = 0; i < syll.length; i++) {
var c = syll[i];
s += lang.cortho[c] || lang.vortho[c] || defaultOrtho[c] || c;
}
return s;
}
function makeSyllable(lang) {
while (true) {
var syll = "";
for (var i = 0; i < lang.structure.length; i++) {
var ptype = lang.structure[i];
if (lang.structure[i+1] == '?') {
i++;
if (Math.random() < 0.5) {
continue;
}
}
syll += choose(lang.phonemes[ptype], lang.exponent);
}
var bad = false;
for (var i = 0; i < lang.restricts.length; i++) {
if (lang.restricts[i].test(syll)) {
bad = true;
break;
}
}
if (bad) continue;
return spell(lang, syll);
}
}
function getMorpheme(lang, key) {
if (lang.nomorph) {
return makeSyllable(lang);
}
key = key || '';
var list = lang.morphemes[key] || [];
var extras = 10;
if (key) extras = 1;
while (true) {
var n = randrange(list.length + extras);
if (list[n]) return list[n];
var morph = makeSyllable(lang);
var bad = false;
for (var k in lang.morphemes) {
if (lang.morphemes[k].includes(morph)) {
bad = true;
break;
}
}
if (bad) continue;
list.push(morph);
lang.morphemes[key] = list;
return morph;
}
}
function makeWord(lang, key) {
var nsylls = randrange(lang.minsyll, lang.maxsyll + 1);
var w = '';
var keys = [];
keys[randrange(nsylls)] = key;
for (var i = 0; i < nsylls; i++) {
w += getMorpheme(lang, keys[i]);
}
return w;
}
function getWord(lang, key) {
key = key || '';
var ws = lang.words[key] || [];
var extras = 3;
if (key) extras = 2;
while (true) {
var n = randrange(ws.length + extras);
var w = ws[n];
if (w) {
return w;
}
w = makeWord(lang, key);
var bad = false;
for (var k in lang.words) {
if (lang.words[k].includes(w)) {
bad = true;
break;
}
}
if (bad) continue;
ws.push(w);
lang.words[key] = ws;
return w;
}
}
function makeName(lang, key) {
key = key || '';
lang.genitive = lang.genitive || getMorpheme(lang, 'of');
lang.definite = lang.definite || getMorpheme(lang, 'the');
while (true) {
var name = null;
if (Math.random() < 0.5) {
name = capitalize(getWord(lang, key));
} else {
var w1 = capitalize(getWord(lang, Math.random() < 0.6 ? key : ''));
var w2 = capitalize(getWord(lang, Math.random() < 0.6 ? key : ''));
if (w1 == w2) continue;
if (Math.random() > 0.5) {
name = join([w1, w2], lang.joiner);
} else {
name = join([w1, lang.genitive, w2], lang.joiner);
}
}
if (Math.random() < 0.1) {
name = join([lang.definite, name], lang.joiner);
}
if ((name.length < lang.minchar) || (name.length > lang.maxchar)) continue;
var used = false;
for (var i = 0; i < lang.names.length; i++) {
var name2 = lang.names[i];
if ((name.indexOf(name2) != -1) || (name2.indexOf(name) != -1)) {
used = true;
break;
}
}
if (used) continue;
lang.names.push(name);
return name;
}
}
function makeBasicLanguage() {
return {
phonemes: {
C: "ptkmnls",
V: "aeiou",
S: "s",
F: "mn",
L: "rl"
},
structure: "CVC",
exponent: 2,
restricts: [],
cortho: {},
vortho: {},
noortho: true,
nomorph: true,
nowordpool: true,
minsyll: 1,
maxsyll: 1,
morphemes: {},
words: {},
names: [],
joiner: ' ',
maxchar: 12,
minchar: 5
};
}
function makeOrthoLanguage() {
var lang = makeBasicLanguage();
lang.noortho = false;
return lang;
}
function makeRandomLanguage() {
var lang = makeBasicLanguage();
lang.noortho = false;
lang.nomorph = false;
lang.nowordpool = false;
lang.phonemes.C = shuffled(choose(consets, 2).C);
lang.phonemes.V = shuffled(choose(vowsets, 2).V);
lang.phonemes.L = shuffled(choose(lsets, 2).L);
lang.phonemes.S = shuffled(choose(ssets, 2).S);
lang.phonemes.F = shuffled(choose(fsets, 2).F);
lang.structure = choose(syllstructs);
lang.restricts = ressets[2].res;
lang.cortho = choose(corthsets, 2).orth;
lang.vortho = choose(vorthsets, 2).orth;
lang.minsyll = randrange(1, 3);
if (lang.structure.length < 3) lang.minsyll++;
lang.maxsyll = randrange(lang.minsyll + 1, 7);
lang.joiner = choose(' -');
return lang;
}
var defaultOrtho = {
'ʃ': 'sh',
'ʒ': 'zh',
'ʧ': 'ch',
'ʤ': 'j',
'ŋ': 'ng',
'j': 'y',
'x': 'kh',
'ɣ': 'gh',
'ʔ': '',
A: "á",
E: "é",
I: "í",
O: "ó",
U: "ú"
};
var corthsets = [
{
name: "Default",
orth: {}
},
{
name: "Slavic",
orth: {
'ʃ': 'š',
'ʒ': 'ž',
'ʧ': 'č',
'ʤ': 'ǧ',
'j': 'j'
}
},
{
name: "German",
orth: {
'ʃ': 'sch',
'ʒ': 'zh',
'ʧ': 'tsch',
'ʤ': 'dz',
'j': 'j',
'x': 'ch'
}
},
{
name: "French",
orth: {
'ʃ': 'ch',
'ʒ': 'j',
'ʧ': 'tch',
'ʤ': 'dj',
'x': 'kh'
}
},
{
name: "Chinese (pinyin)",
orth: {
'ʃ': 'x',
'ʧ': 'q',
'ʤ': 'j',
}
}
];
var vorthsets = [
{
name: "Ácutes",
orth: {}
},
{
name: "Ümlauts",
orth: {
A: "ä",
E: "ë",
I: "ï",
O: "ö",
U: "ü"
}
},
{
name: "Welsh",
orth: {
A: "â",
E: "ê",
I: "y",
O: "ô",
U: "w"
}
},
{
name: "Diphthongs",
orth: {
A: "au",
E: "ei",
I: "ie",
O: "ou",
U: "oo"
}
},
{
name: "Doubles",
orth: {
A: "aa",
E: "ee",
I: "ii",
O: "oo",
U: "uu"
}
}
];
var consets = [
{
name: "Minimal",
C: "ptkmnls"
},
{
name: "English-ish",
C: "ptkbdgmnlrsʃzʒʧ"
},
{
name: "Pirahã (very simple)",
C: "ptkmnh"
},
{
name: "Hawaiian-ish",
C: "hklmnpwʔ"
},
{
name: "Greenlandic-ish",
C: "ptkqvsgrmnŋlj"
},
{
name: "Arabic-ish",
C: "tksʃdbqɣxmnlrwj"
},
{
name: "Arabic-lite",
C: "tkdgmnsʃ"
},
{
name: "English-lite",
C: "ptkbdgmnszʒʧhjw"
}
];
var ssets = [
{
name: "Just s",
S: "s"
},
{
name: "s ʃ",
S: "sʃ"
},
{
name: "s ʃ f",
S: "sʃf"
}
];
var lsets = [
{
name: "r l",
L: "rl"
},
{
name: "Just r",
L: "r"
},
{
name: "Just l",
L: "l"
},
{
name: "w j",
L: "wj"
},
{
name: "r l w j",
L: "rlwj"
}
];
var fsets = [
{
name: "m n",
F: "mn"
},
{
name: "s k",
F: "sk"
},
{
name: "m n ŋ",
F: "mnŋ"
},
{
name: "s ʃ z ʒ",
F: "sʃzʒ"
}
];
var vowsets = [
{
name: "Standard 5-vowel",
V: "aeiou"
},
{
name: "3-vowel a i u",
V: "aiu"
},
{
name: "Extra A E I",
V: "aeiouAEI"
},
{
name: "Extra U",
V: "aeiouU"
},
{
name: "5-vowel a i u A I",
V: "aiuAI"
},
{
name: "3-vowel e o u",
V: "eou"
},
{
name: "Extra A O U",
V: "aeiouAOU"
}
];
var syllstructs = [
"CVC",
"CVV?C",
"CVVC?", "CVC?", "CV", "VC", "CVF", "C?VC", "CVF?",
"CL?VC", "CL?VF", "S?CVC", "S?CVF", "S?CVC?",
"C?VF", "C?VC?", "C?VF?", "C?L?VC", "VC",
"CVL?C?", "C?VL?C", "C?VLC?"];
var ressets = [
{
name: "None",
res: []
},
{
name: "Double sounds",
res: [/(.)\1/]
},
{
name: "Doubles and hard clusters",
res: [/[sʃf][sʃ]/, /(.)\1/, /[rl][rl]/]
}
];