/* テスト */
/*
 * File: randname.c
 * Purpose: Random name generation
 *
 * Copyright (c) 2007 Antony Sidwell, Sheldon Simms
 *
 * This work is free software; you can redistribute it and/or modify it
 * under the terms of either:
 *
 * a) the GNU General Public License as published by the Free Software
 *    Foundation, version 2, or
 *
 * b) the "Angband licence":
 *    This software may be copied and distributed for educational, research,
 *    and not for profit purposes provided that this copyright and statement
 *    are included in all such copies.  Other copyrights may also apply.
 */
#include "angband.h"
#include "randname.h"

/* 
 * Arrays of purely alphabetical, lower-case strings to teach 
 * the name generator with. 
 */
static const _TCHAR *tolkien_names[] =
{
	L"adanedhel", L"adurant", L"aeglos", L"aegnor", L"aelin", L"aeluin",
	L"aerandir", L"aerin", L"agarwaen", L"aglareb", L"aglarond", L"aglon",
	L"ainulindale", L"ainur", L"alcarinque", L"aldaron", L"aldudenie",
	L"almaren", L"alqualonde", L"aman", L"amandil", L"amarie", L"amarth",
	L"amlach", L"amon", L"amras", L"amrod", L"anach", L"anar", L"anarion",
	L"ancalagon", L"ancalimon", L"anarrima", L"andor", L"andram", L"androth",
	L"anduin", L"andunie", L"anfauglir", L"anfauglith", L"angainor", L"angband",
	L"anghabar", L"anglachel", L"angrenost", L"angrim", L"angrist", L"angrod",
	L"anguirel", L"annael", L"annatar", L"annon", L"annuminas", L"apanonar",
	L"aradan", L"aragorn", L"araman", L"aranel", L"aranruth", L"aranwe", L"aras",
	L"aratan", L"aratar", L"arathorn", L"arda", L"ardgalen", L"aredhel",
	L"arfeiniel", L"argonath", L"arien", L"armenelos", L"arminas", L"arnor",
	L"aros", L"arossiach", L"arthad", L"arvernien", L"arwen", L"ascar",
	L"astaldo", L"atalante", L"atanamir", L"atanatari", L"atani", L"aule",
	L"avallone", L"avari", L"avathar", L"balan", L"balar", L"balrog", L"barad",
	L"baragund", L"barahir", L"baran", L"baranduin", L"bar", L"bauglir",
	L"beleg", L"belegaer", L"belegost", L"belegund", L"beleriand", L"belfalas",
	L"belthil", L"belthronding", L"beor", L"beraid", L"bereg", L"beren",
	L"boromir", L"boron", L"bragollach", L"brandir", L"bregolas", L"bregor",
	L"brethil", L"brilthor", L"brithiach", L"brithombar", L"brithon", L"cabed",
	L"calacirya", L"calaquendi", L"calenardhon", L"calion", L"camlost",
	L"caragdur", L"caranthir", L"carcharoth", L"cardolan", L"carnil",
	L"celeborn", L"celebrant", L"celebrimbor", L"celebrindal", L"celebros",
	L"celegorm", L"celon", L"cirdan", L"cirith", L"cirth", L"ciryatan",
	L"ciryon", L"coimas", L"corollaire", L"crissaegrim", L"cuarthal",
	L"cuivienen", L"culurien", L"curufin", L"curufinwe", L"curunir",
	L"cuthalion", L"daedeloth", L"daeron", L"dagnir", L"dagor", L"dagorlad",
	L"dairuin", L"danwedh", L"delduwath", L"denethor", L"dimbar", L"dimrost",
	L"dinen", L"dior", L"dirnen", L"dolmed", L"doriath", L"dorlas",
	L"dorthonion", L"draugluin", L"drengist", L"duath", L"duinath", L"duilwen",
	L"dunedain", L"dungortheb", L"earendil", L"earendur", L"earnil", L"earnur",
	L"earrame", L"earwen", L"echor", L"echoriath", L"ecthelion", L"edain",
	L"edrahil", L"eglador", L"eglarest", L"eglath", L"eilinel", L"eithel",
	L"ekkaia", L"elbereth", L"eldalie", L"eldalieva", L"eldamar", L"eldar",
	L"eledhwen", L"elemmire", L"elende", L"elendil", L"elendur", L"elenna",
	L"elentari", L"elenwe", L"elerrina", L"elleth", L"elmoth", L"elostirion",
	L"elrond", L"elros", L"elu", L"eluchil", L"elured", L"elurin", L"elwe",
	L"elwing", L"emeldir", L"endor", L"engrin", L"engwar", L"eol", L"eonwe",
	L"ephel", L"erchamion", L"ereb", L"ered", L"erech", L"eregion", L"ereinion",
	L"erellont", L"eressea", L"eriador", L"eru", L"esgalduin", L"este", L"estel",
	L"estolad", L"ethir", L"ezellohar", L"faelivrin", L"falas", L"falathar",
	L"falathrim", L"falmari", L"faroth", L"fauglith", L"feanor", L"feanturi",
	L"felagund", L"finarfin", L"finduilas", L"fingolfin", L"fingon", L"finwe",
	L"firimar", L"formenos", L"fornost", L"frodo", L"fuin", L"fuinur",
	L"gabilgathol", L"galad", L"galadriel", L"galathilion", L"galdor", L"galen",
	L"galvorn", L"gandalf", L"gaurhoth", L"gelion", L"gelmir", L"gelydh", L"gil",
	L"gildor", L"giliath", L"ginglith", L"girith", L"glaurung", L"glingal",
	L"glirhuin", L"gloredhel", L"glorfindel", L"golodhrim", L"gondolin",
	L"gondor", L"gonnhirrim", L"gorgoroth", L"gorlim", L"gorthaur", L"gorthol",
	L"gothmog", L"guilin", L"guinar", L"guldur", L"gundor", L"gurthang",
	L"gwaith", L"gwareth", L"gwindor", L"hadhodrond", L"hador", L"haladin",
	L"haldad", L"haldan", L"haldar", L"haldir", L"haleth", L"halmir", L"handir",
	L"harad", L"hareth", L"hathaldir", L"hathol", L"haudh", L"helcar",
	L"helcaraxe", L"helevorn", L"helluin", L"herumor", L"herunumen",
	L"hildorien", L"himlad", L"himring", L"hirilorn", L"hisilome",
	L"hithaeglir", L"hithlum", L"hollin", L"huan", L"hunthor", L"huor", L"hurin",
	L"hyarmendacil", L"hyarmentir", L"iant", L"iaur", L"ibun", L"idril",
	L"illuin", L"ilmare", L"ilmen", L"iluvatar", L"imlach", L"imladris", L"indis",
	L"ingwe", L"irmo", L"isil", L"isildur", L"istari", L"ithil", L"ivrin",
	L"kelvar", L"kementari", L"ladros", L"laiquendi", L"lalaith", L"lamath",
	L"lammoth", L"lanthir", L"laurelin", L"leithian", L"legolin", L"lembas",
	L"lenwe", L"linaewen", L"lindon", L"lindorie", L"loeg", L"lomelindi",
	L"lomin", L"lomion", L"lorellin", L"lorien", L"lorindol", L"losgar",
	L"lothlann", L"lothlorien", L"luin", L"luinil", L"lumbar", L"luthien",
	L"mablung", L"maedhros", L"maeglin", L"maglor", L"magor", L"mahanaxar",
	L"mahtan", L"maiar", L"malduin", L"malinalda", L"mandos", L"manwe", L"mardil",
	L"melian", L"melkor", L"menegroth", L"meneldil", L"menelmacar",
	L"meneltarma", L"minas", L"minastir", L"mindeb", L"mindolluin", L"mindon",
	L"minyatur", L"mirdain", L"miriel", L"mithlond", L"mithrandir", L"mithrim",
	L"mordor", L"morgoth", L"morgul", L"moria", L"moriquendi", L"mormegil",
	L"morwen", L"nahar", L"naeramarth", L"namo", L"nandor", L"nargothrond",
	L"narog", L"narsil", L"narsilion", L"narya", L"nauglamir", L"naugrim",
	L"ndengin", L"neithan", L"neldoreth", L"nenar", L"nenning", L"nenuial",
	L"nenya", L"nerdanel", L"nessa", L"nevrast", L"nibin", L"nienna", L"nienor",
	L"nimbrethil", L"nimloth", L"nimphelos", L"nimrais", L"nimras",
	L"ningloron", L"niniel", L"ninniach", L"ninquelote", L"niphredil",
	L"nirnaeth", L"nivrim", L"noegyth", L"nogrod", L"noldolante", L"noldor",
	L"numenor", L"nurtale", L"obel", L"ohtar", L"oiolosse", L"oiomure", L"olorin",
	L"olvar", L"olwe", L"ondolinde", L"orfalch", L"ormal", L"orocarni",
	L"orodreth", L"orodruin", L"orome", L"oromet", L"orthanc", L"osgiliath",
	L"osse", L"ossiriand", L"palantir", L"pelargir", L"pelori", L"periannath",
	L"quendi", L"quenta", L"quenya", L"radagast", L"radhruin", L"ragnor",
	L"ramdal", L"rana", L"rathloriel", L"rauros", L"region", L"rerir",
	L"rhovanion", L"rhudaur", L"rhun", L"rhunen", L"rian", L"ringil", L"ringwil",
	L"romenna", L"rudh", L"rumil", L"saeros", L"salmar", L"saruman", L"sauron",
	L"serech", L"seregon", L"serinde", L"shelob", L"silmarien", L"silmaril",
	L"silpion", L"sindar", L"singollo", L"sirion", L"soronume", L"sul", L"sulimo",
	L"talath", L"taniquetil", L"tar", L"taras", L"tarn", L"tathren", L"taur",
	L"tauron", L"teiglin", L"telchar", L"telemnar", L"teleri", L"telperion",
	L"telumendil", L"thalion", L"thalos", L"thangorodrim", L"thargelion",
	L"thingol", L"thoronath", L"thorondor", L"thranduil", L"thuringwethil",
	L"tilion", L"tintalle", L"tinuviel", L"tirion", L"tirith", L"tol", L"tulkas",
	L"tumhalad", L"tumladen", L"tuna", L"tuor", L"turambar", L"turgon", L"turin",
	L"uial", L"uilos", L"uinen", L"ulairi", L"ulmo", L"ulumuri", L"umanyar",
	L"umarth", L"umbar", L"ungoliant", L"urthel", L"uruloki", L"utumno", L"vaire",
	L"valacirca", L"valandil", L"valaquenta", L"valar", L"valaraukar",
	L"valaroma", L"valier", L"valimar", L"valinor", L"valinoreva", L"valmar",
	L"vana", L"vanyar", L"varda", L"vasa", L"vilya", L"vingilot", L"vinyamar",
	L"voronwe", L"wethrin", L"wilwarin", L"yavanna",
	NULL
};

/* These are (mostly) picked at random from a Latin word list. */
static const _TCHAR *scroll_names[] =
{
	L"abracadabra", L"piffpaffpouf", L"izzy", L"wizzy", L"letsgetsbusy",
	L"justlikethat", L"hocus", L"pocus", L"shazam", L"please", L"abduco",
	L"absorbeo", L"abutor", L"accipio", L"acerbus", L"adamo", L"adeo", L"adficio",
	L"adinventitias", L"admitto", L"adsidue", L"adsumo", L"advenio", L"aeger",
	L"aegrus", L"aestivus", L"aggero", L"ago", L"alioqui", L"aliquantum",
	L"aliquot", L"alter", L"ambianis", L"amissio", L"amoveo", L"andegavense",
	L"animus", L"antepono", L"appareo", L"appropinquo", L"ara", L"arca", L"arguo",
	L"articulus", L"ascit", L"astrum", L"atrebatum", L"attonbitus", L"audax",
	L"aureus", L"autus", L"averto", L"bardus", L"bene", L"bibo", L"bonus",
	L"breviter", L"calamitas", L"callidus", L"canonus", L"caput", L"caritas",
	L"casso", L"catervatim", L"causa", L"cedo", L"celeriter", L"centum",
	L"certus", L"charisma", L"cimentarius", L"cito", L"clamor", L"claustrum",
	L"coerceo", L"cogo", L"colloco", L"coma", L"cometissa", L"commeo",
	L"commissum", L"commoneo", L"compatior", L"compes", L"compositio",
	L"comprovincialis", L"concido", L"conculco", L"condico", L"confiteor",
	L"conicio", L"conor", L"conservo", L"consisto", L"constans", L"construo",
	L"consueta", L"consulto", L"consuo", L"contamino", L"contemptio",
	L"contentus", L"contineo", L"contradictio", L"conventus", L"copiose",
	L"corrigo", L"corturiacum", L"crastinus", L"creo", L"cribrum", L"cruentus",
	L"cubicularius", L"cui", L"culpa", L"cum", L"cunctus", L"cur", L"curiosus",
	L"currus", L"curto", L"custodiae", L"debeo", L"decimus", L"decumbo",
	L"defendo", L"defleo", L"degenero", L"delego", L"delinquo", L"demonstro",
	L"dens", L"depono", L"deprecor", L"derelinquo", L"desino", L"despero",
	L"detego", L"devito", L"diabolus", L"didicerat", L"differo", L"dignitas",
	L"dilabor", L"diluculo", L"diripio", L"disco", L"dissimilis", L"districtus",
	L"diutius", L"divitiae", L"dolens", L"domesticus", L"donec", L"duco",
	L"dulcidine", L"duro", L"ecclesia", L"edo", L"efficio", L"ego", L"elemosina",
	L"eluvies", L"emineo", L"emptio", L"epistula", L"equus", L"erogo", L"erudio",
	L"etsi", L"ex", L"excito", L"excuso", L"exesto", L"exhorresco", L"eximo",
	L"exorior", L"experior", L"expiscor", L"explico", L"exsequor", L"exstinguo",
	L"extra", L"fabula", L"facio", L"faenum", L"famulus", L"fautor", L"felix",
	L"ferme", L"festinus", L"fides", L"fines", L"flamma", L"fluo", L"formo",
	L"fortiter", L"foveo", L"frequentia", L"frugalitas", L"fuga", L"fultus",
	L"furor", L"galea", L"genus", L"glacialis", L"gratia", L"gravatus",
	L"gregatim", L"hactenus", L"harum", L"heniis", L"hic", L"his", L"hoc",
	L"honorabilis", L"horum", L"huic", L"humanitas", L"hunnam", L"iam", L"idem",
	L"ignavus", L"illa", L"illarum", L"illi", L"illis", L"illius", L"illorum",
	L"illum", L"imitor", L"immortalis", L"impedito", L"impendo", L"imperium",
	L"importunus", L"ex", L"in", L"incertus", L"includo", L"incorruptus", L"inda",
	L"indignatio", L"induco", L"inexpugnabilis", L"infecunditas", L"infenso",
	L"infero", L"inficio", L"infigo", L"infirmitas", L"infitior", L"inflatus",
	L"infligo", L"infortunatus", L"ingemuo", L"inicio", L"innotesco", L"inquis",
	L"insciens", L"insidiae", L"insperatus", L"instructus", L"insurgo",
	L"intentio", L"interdum", L"intueor", L"invado", L"invetero", L"invisus",
	L"ipsemet", L"irritus", L"ita", L"iucunditas", L"iugis", L"iussu", L"jaculum",
	L"juventus", L"labiosus", L"laboriose", L"labruscum", L"lacertosus",
	L"lacrimo", L"lacto", L"laedo", L"laetificus", L"laevus", L"lamentatio",
	L"laqueus", L"laudo", L"lectus", L"lemiscus", L"lenitas", L"lentesco", L"leo",
	L"lesciense", L"leto", L"levidensis", L"levo", L"liber", L"libere", L"licet",
	L"lino", L"loci", L"longe", L"lucerna", L"ludio", L"lupus", L"macero",
	L"maculo", L"maero", L"magus", L"malmundarium", L"mandatum", L"manus",
	L"matera", L"me", L"mei", L"memor", L"mensa", L"meridianus", L"mica",
	L"millies", L"minuo", L"miser", L"mitigo", L"modio", L"molestia",
	L"monasteriense", L"monstrum", L"morior", L"moveo", L"multo", L"mundus",
	L"munus", L"mutuo", L"nascor", L"navigo", L"necesse", L"nemo", L"neque",
	L"niger", L"nisi", L"nivellensem", L"noceo", L"non", L"nos", L"nota", L"novus",
	L"nunc", L"nusquam", L"obdormio", L"oblivio", L"obviam", L"occupo", L"odium",
	L"omitto", L"onus", L"oporotheca", L"opportunitatus", L"ops", L"orator",
	L"orior", L"ostium", L"pactum", L"palam", L"par", L"parens", L"paro",
	L"passer", L"patiens", L"patruus", L"pax", L"pecus", L"penitus", L"per",
	L"percutio", L"perfectus", L"periclitatus", L"periurium", L"perpetro",
	L"perseverantia", L"persuadeo", L"pertineo", L"peruro", L"pessimus",
	L"pestis", L"phasma", L"pictoratus", L"pirus", L"placide", L"plagiarius",
	L"plecto", L"plico", L"pluma", L"plures", L"pluvia", L"polenta", L"pomum",
	L"porta", L"postea", L"postulo", L"potius", L"praebeo", L"praecido",
	L"praeda", L"praefinio", L"praenuntio", L"praesentia", L"praesto",
	L"praetereo", L"pravitas", L"premo", L"primitus", L"principatus", L"prius",
	L"pro", L"procedo", L"procurator", L"proficio", L"profor", L"progenero",
	L"progressio", L"proinde", L"prolecto", L"proloquor", L"prominens",
	L"promitto", L"promptu", L"promus", L"propello", L"propositum", L"prorsus",
	L"prosum", L"proveho", L"prudens", L"pudendus", L"puerilis", L"pugnax",
	L"pulex", L"pulpa", L"pumilius", L"punitor", L"purgatio", L"puteo",
	L"pyropus", L"quadrigae", L"quae", L"quaesitio", L"qualiscumque", L"quam",
	L"quando", L"quantum", L"quantuslibet", L"quas", L"quater", L"quercus",
	L"queror", L"quibus", L"quicquid", L"quin", L"quisnam", L"quo", L"quodammodo",
	L"quorum", L"radicitus", L"recedo", L"recolo", L"rectum", L"redarguo",
	L"redeo", L"refectorium", L"rego", L"relinquo", L"remaneo", L"rependo",
	L"repeto", L"reprehendo", L"resisto", L"retraho", L"revoco", L"rigor",
	L"rotomagense", L"rursus", L"sacrilegus", L"saeta", L"saluto",
	L"sanctimonialis", L"sanitas", L"sapienter", L"satis", L"scaldus", L"scelus",
	L"scio", L"se", L"secundum", L"secus", L"seductor", L"sententia",
	L"sepulchrum", L"sermo", L"servus", L"siccus", L"silens", L"silva",
	L"simulatio", L"singultus", L"sive", L"soleo", L"sollicitudo", L"solum",
	L"somnio", L"sopor", L"speciosus", L"spero", L"spolium", L"statim", L"stipes",
	L"studio", L"sub", L"subseco", L"succendo", L"suggero", L"summissus",
	L"super", L"superne", L"suppellex", L"suppono", L"suscito", L"tabellae",
	L"tactus", L"tam", L"tandem", L"taruennam", L"tempero", L"templum", L"tendo",
	L"tenus", L"teres", L"tergum", L"tero", L"tertius", L"textor", L"thema",
	L"thymbra", L"titulus", L"torqueo", L"toties", L"traiectum", L"trellum",
	L"tricesimus", L"tristis", L"tubineus", L"tungris", L"turpe", L"ubi",
	L"ultra", L"undique", L"unus", L"usque", L"ut", L"utilitas", L"utroque",
	L"vado", L"validus", L"vehementer", L"vendolius", L"ventus", L"verecundia",
	L"versus", L"vesica", L"vestio", L"vicissitudo", L"video", L"vilicus",
	L"vindico", L"virga", L"vis", L"vivo", L"voco", L"volo", L"voluntas", L"volva",
	L"voro", L"vulariter", L"vulnus", L"vultus",
	NULL
};

/* Markers for the start and end of words. */
#define S_WORD 26
#define E_WORD S_WORD
#define TOTAL  27

typedef unsigned short name_probs[S_WORD+1][S_WORD+1][TOTAL+1];

/*
 * This function builds probability tables from a list of purely alphabetical
 * lower-case words, and puts them into the supplied name_probs object.
 * The array of names should have a NULL entry at the end of the list.
 * It relies on the ASCII character set (through use of A2I).
 */
static void build_prob(name_probs probs, const _TCHAR **learn)
{
	int c_prev, c_cur, c_next;
	const _TCHAR *ch;
	int i;

	/* Build raw frequencies */
	for (i = 0; learn[i] != NULL; i++)
	{
		c_prev = c_cur = S_WORD;
		ch = learn[i];

		/* Iterate over the next word */
		while (*ch != 0)
		{
			c_next = A2I(_totlower(*ch));

			probs[c_prev][c_cur][c_next]++;
			probs[c_prev][c_cur][TOTAL]++;
                        
			/* Step on */
			c_prev = c_cur;
			c_cur = c_next;
			ch++;
		}

		probs[c_prev][c_cur][E_WORD]++;
		probs[c_prev][c_cur][TOTAL]++;
	}
}

/*
 * Use W. Sheldon Simms' random name generator algorithm (Markov Chain stylee).
 * 
 * Generate a random word using the probability tables we built earlier.  
 * Relies on the A2I and I2A macros (and so the ASCII character set) and 
 * is_a_vowel (so the basic 5 English vowels).
 */
size_t randname_make(randname_type name_type, size_t min, size_t max, _TCHAR *word_buf, size_t buflen)
{
	size_t lnum = 0;
	bool found_word = FALSE;

	static name_probs lprobs;
	static randname_type cached_type = RANDNAME_NUM_TYPES;

	assert(name_type > 0 && name_type < RANDNAME_NUM_TYPES);

	/* To allow for a terminating character */
	assert(buflen > max);

	/* We cache one set of probabilities, only regenerate when
	   the type changes.  It's as good a way as any for now.
	   Frankly, we could probably regenerate every time. */
	if (cached_type != name_type)
	{
		const _TCHAR **wordlist = NULL;

		switch (name_type)
		{
			case RANDNAME_TOLKIEN:
			{
				wordlist = tolkien_names;
				break;
			}
			case RANDNAME_SCROLL:
			{
				wordlist = scroll_names;
				break;
			}
			case RANDNAME_NUM_TYPES:
			{
				/* Unreachable - stops compiler warning */
			}
		}

		build_prob(lprobs, wordlist);
		cached_type = name_type;
	}
        
	/* Generate the actual word wanted. */
	while (!found_word)
	{
		_TCHAR *cp = word_buf;
		int c_prev = S_WORD;
		int c_cur = S_WORD;
		int tries = 0;
		bool contains_vowel = FALSE;
		lnum = 0;

		/* We start the word again if we run out of space or have
		   had to have 10 goes to find a word that satisfies the
		   minimal conditions. */
		while (tries < 10 && lnum <= max && !found_word)
		{
			/* Pick the next letter based on a simple weighting
			  of which letters can follow the previous two */
			int r = randint0(lprobs[c_prev][c_cur][TOTAL]);
			int c_next = 0;

			while (r >= lprobs[c_prev][c_cur][c_next])
			{
				r -= lprobs[c_prev][c_cur][c_next];
				c_next++;
			}
            
			if (c_next == E_WORD)
			{
				/* If we've reached the end, we check if we've
				   met the simple conditions, otherwise have
				   another go at choosing a letter for this
				   position. */
				if (lnum >= min && contains_vowel)
				{
					*cp = 0;
					found_word = TRUE;
				}
				else
				{
					tries++;
				}
			}
			else
			{
				/* Add the letter to the word and move on. */
				*cp = I2A(c_next);

				if (is_a_vowel(*cp))
					contains_vowel = TRUE;

				cp++;
				lnum++;
				c_prev = c_cur;
				c_cur = c_next;
			}
		}
	}

	return lnum;
}


/* 
 * To run standalone tests, #define RANDNAME_TESTING and link with
 *  with just z-rand.c from Angband. 
 */
#ifdef RANDNAME_TESTING

#include <stdio.h>
#include <time.h>


bool is_a_vowel(int ch)
{
	switch (ch)
	{
		case 'a':
		case 'e':
		case 'i':
		case 'o':
		case 'u':
			 return (TRUE);
	}

	return (FALSE);
}

int main(int argc, char *argv[])
{
	int i;
	_TCHAR name[256];

	Rand_value = time(NULL);

	for (i = 0; i < 20; i++)
	{
		randname_make(RANDNAME_TOLKIEN, 5, 9, name, 256);
		name[0] = _totupper(name[0]);
		printf(L"%s\n", name);
	}

	return 0;
}

#endif
