I have a snippet of code that I would like to share, get feedback on, see if
anyone else has similar ideas, etc. What it does is translate a line of
ANSI English text (it will still work on non-English text that uses the same
character set, but not quite as well) into a fake "language."
This makes it possible for a race's language to have a distinct feel to it,
so if dwarven is spoken, it is most readily identifiable as dwarven, elven
just sounds different, etc.
It works by converting each of the 26 letters of the English alphabet into
one of the ten characters that define the language. Every time an R is
typed, it is converted to the same character, however, to add some
variation, and make it harder to "read" by a player without the language
skill, certain two-letter compinations are mapped to different elements of
the ten than they would be if encountered separately.
Ex: "t h e" maps to "l u e" in the Elven that I supply below, but with "the"
the "th" is a specified combination to convert differently, and so it
becomes "fa", so "the" becomes "fae".
Here is the code I use to do this, it should all be C, but since I am using
a C++ complier, there may be sneaky bits that snuck through. In any case, I
am pretty sure that everyone will be able to understand the function. :) I
apologize for some of the lines being longer than 80 chars, but i could not
find any easy and clean ways of breaking them.
---begin code---
/* #includes here */
/* these arrays define a language by their letters and order */
/* the first two chars are common vowel sounds for the given language */
/* the next seven are consonants, and the last is an uncommon vowel */
char dwarven[10] = { 'u', 'o', 'b', 'd', 'r', 'm', 'g', 'l', 'f', 'i' };
char skaven[10] = { 'i', '\'', 's', 'k', 't', 'z', 'r', 'h', 'c', 'e' };
char fareastern[10] = { 'o', 'i', 'k', 't', 'h', 'r', 's', 'b', 'm', 'u' };
char elven[10] = { 'a', 'e', 'l', 'f', 'u', 'r', 'n', 'w', 'h', 'o' };
/*note that elven uses a fourth vowel ^ to increase its "smoothness" :)
*/
char* translateTo(char* input, char lang[10])
{
char* output;
int counter = 0;
int temp;
char letter;
/* this table defines the two-letter combinations that should map
differently */
/* the value listed is the index of the next table to use */
static char alpha[26][26] = {
/*a b c d e f g h i j k l m n o p q r s t u v w x
y z*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*a*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0 },/*b*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*c*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*d*/
{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*e*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*f*/
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*g*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*h*/
{ 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*i*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*j*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*k*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*l*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*m*/
{ 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*n*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0,
0, 0, 0 },/*o*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*p*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*q*/
{ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*r*/
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*s*/
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*t*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*u*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*v*/
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*w*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*x*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 },/*y*/
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 }};/*z*/
/* this table defines how letters and combinations should map to the ten
*/
/* the 0 column difines a non-combined letter's mapping */
/* columns 1,2 and 3,4 define combination mappings */
/* this table could easily be expanded to support more combinations per
letter, */
/* the current max is two. note that not all are currently used. */
static char convert[26][5] = {
{ 0, 1, 5, 1, 7 },/*a*/
{ 3, 2, 8, 6, 1 },/*b*/
{ 2, 0, 0, 0, 0 },/*c*/
{ 4, 0, 0, 0, 0 },/*d*/
{ 1, 9, 4, 0, 0 },/*e*/
{ 6, 0, 0, 0, 0 },/*f*/
{ 7, 5, 4, 0, 0 },/*g*/
{ 4, 0, 0, 0, 0 },/*h*/
{ 1, 9, 3, 0, 1 },/*i*/
{ 7, 0, 0, 0, 0 },/*j*/
{ 6, 0, 0, 0, 0 },/*k*/
{ 4, 0, 0, 0, 0 },/*l*/
{ 3, 0, 0, 0, 0 },/*m*/
{ 2, 8, 1, 9, 4 },/*n*/
{ 0, 1, 5, 9, 3 },/*o*/
{ 4, 0, 0, 0, 0 },/*p*/
{ 8, 0, 0, 0, 0 },/*q*/
{ 6, 5, 0, 0, 0 },/*r*/
{ 2, 3, 7, 2, 9 },/*s*/
{ 2, 3, 0, 6, 0 },/*t*/
{ 1, 0, 0, 0, 0 },/*u*/
{ 6, 0, 0, 0, 0 },/*v*/
{ 5, 7, 2, 0, 0 },/*w*/
{ 7, 0, 0, 0, 0 },/*x*/
{ 9, 0, 0, 0, 0 },/*y*/
{ 8, 0, 0, 0, 0 }};/*z*/
output = (char*)malloc(strlen(input) + 1);
do
{ /* all non-alphabetic charaters are ignored and copied unchanged */
if( isalpha(input[counter]) )
{
letter = tolower(input[counter]) - 'a';
/* this allows two-char sequences to be translated differently
*/
/* than each letter would be translated alone - adds variation
*/
if( isalpha(input[counter + 1]) )
temp = alpha[letter][tolower(input[counter + 1]) - 'a'];
else /* else next char is non-alphabetic */
temp = 0;
output[counter] = lang[ convert[letter][temp] ];
if( temp ) /* then we have a two-char sequence */
output[++counter] = lang[ convert[letter][temp + 1] ];
}
else /* else input is non-alphabetic, (punctuation, NULL, etc.)
*/
output[counter] = input[counter];
}
while( input[counter++] );
return output;
}
/*---a quick main to use the function---*/
int main(int argc, char* argv[])
{
char input[81];
char* output;
printf("Please enter a line of text to translate:\n");
fgets(input, 80, stdin);
printf("\nEnglish : %s", input);
output = translateTo(input, fareastern);
printf("FarEastern: %s", output);
free(output);
output = translateTo(input, dwarven);
printf("Dwarven : %s", output);
free(output);
output = translateTo(input, skaven);
printf("Skaven : %s", output);
free(output);
output = translateTo(input, elven);
printf("Elven : %s", output);
free(output);
return 0;
}
---end code---
I am pretty sure I got all those pesky tabs out, but... :)
Thoughts? Comments? Does anyone else have any projects along these lines?
I remember once, a long time back, KaVir had posted (on alt.mud.programming)
some pretty intense code for enforcing naming rules for PCs, making them
conform to a language. If you are listening, do you still have those (and,
more importantly, do you want to share? :) KaVir?
I everyone finds this interesting,
Silence is translated
Eli