See what's going on with flipcode!




 

Generating Names Phonetically
by (12 December 2000)



Return to The Archives
Introduction


Why do we want to generate names at all? There are several uses for this technology. (a) If you're building your entire game world procedurally, then you might like a procedural way to name locations, characters, and unique items in the game. (b) Even if you're building a world by hand, coming up with names can be difficult. Using a name generator, and picking likely names from the output, can help speed up the process of name selection.

One approach to creating names is to use phonetics. Many of us were taught to read by "sounding out" the different parts of a word--we were "hooked on phonics" even before it entered pop culture. The phonetic approach is very intuitive, and is also backed by a lot of academic work. Phonetics is a branch of linguistics, and "computational phonology" is apparently a hot area of research right now.

Motivation

If you've ever tried writing a name generator, you know why we need an approach at all. The reason is, it's hard to come up with a generator that produces acceptable names. Too often, names come out that are unpronounceable. Another problem is that the naive generator (which breaks letters into two classes: consonants and vowels) doesn't give us any control over the general "feel" of the names generated.

In particular, it would be nice to generate different "types" of names for different races of creatures. Orcs should have guttural, gruff-sounding names; elves should have light, lilting names. A phonetic approach makes such distinctions possible--if still not easy.


Teach Yourself Phonetics In 14 Minutes


Phoneticians (the previous word was actually in my spelling dictionary!) have subdivided sounds, especially consonants, into various categories. This makes sense. After all, how do you earn tenure with just vowels and consonants to write about?

Primary Consonant Classes

Consonant sounds are broken down into several primary groups, as shown here:

  • Stops (b, d, g, k, p, t)
  • Fricatives (ch, f, ph, s, sh, th, v, z)
  • Affricates (ch, dg, j)
  • Nasals (m, n, ng)
  • Liquids (l, r)
  • Glides (w, y)

    Notice that some of the sounds are represented by more than one letter. The "ch" and "th" entries are examples of this. Phonetically speaking, these two letters combine to form one sound. Getting over the "one letter = one sound" way of thinking is a key hurdle to understanding phonetics, and also to seeing how phonetics can help in controlling the structure of words we generate programmatically.

    Warning! I'm not presenting pure phonetics here. For example, in the Affricates section, I listed "dg" and "j." Phonetically speaking, these two are both a single sound, with two different spellings in English, but represented in phonetics by one of those symbols you see in the dictionary (a j with a carat over it). The word "judge" gives an example of the "j-carat" appearing twice but with two different spellings: first as "j," the second time as "dg."

    Alternate Consonant Classes

    Consonants are also divided along another axis, which is based on (a) where the tongue is when it makes the sound and (b) whether the vocal chords come into play in making the sound.

    This method of classification is independent of the "stop, fricative, affricate" approach we described above. This means that some stops are voiced (b, d, g) and others aren't voiced (p, t), with "k" being in the "almost voiced" category--at least according to me. It also means that a single alternate classification can mix together stops, nasals, liquids, and so forth.

    If you look in your handy Linguistics textbook, you'll probably find a two-dimensional table listing sounds, where the column headings are "stop, fricative," etc., and the row headings are "Alveolar, Bilabial, Paleo-dental, Interdental" and so forth. The two classifications are thus orthogonal to each other, and lead to sub-classifications like "Alveolar Stop" and "Voiced Bilabial Liquid" (which is my personal favorite group).

    Here is an incomplete list of classifications of this type:

  • Alveolar (d, l, n, r, s, t)
  • Bilabial (b, m, p )
  • Glottal (h)
  • Palatal (ch, dg, s, j, sh, y)
  • Velar (g, k, ng, w)

    Vowels

    There are fewer sub-classifications of vowels. But there is at least one sub-class, called the dipthongs (another class that's high on my list). As far as I can tell, dipthongs are "long" vowels. Anyway, here are various vowel combinations that can qualify as dipthongs, at least in some languages and under certain circumstances.

  • Dipthongs (ay, ea, ee, ei, oa, oe, ou, ow, oy, y)


  • Designing a Phonetics Name Generator


    Our goal here is to describe a name generator using our new understanding of phonetics. The obvious (naive?) approach that we will use is to simply define various phonetic groups, and then build up a set of "name templates" that make use of the phonetic groups. Of course, we want a data-driven approach, where the phonetic groups and the name templates are stored in a database, text file, or other easy-to-edit place, so that we can revise and refine our output without having to change the code base.

    Using this approach as a motivation, we define three classes: the Phoneme, NameTemplate, and NameData classes. Each Phoneme contains an array of strings, where each string represents a single sound (or sound equivalent). Each NameTemplate contains an ordered array of Phonemes that make up that name. And the NameData class manages all the Phonemes and NameTemplates.

    The algorithm used by the engine for building a single name is fairly straight-forward. Given a name template, build a string by randomly selecting one entry from each Phoneme group specified by the template. The pseudocode for this algorithm is as follows:

    
        theName = Empty String
        for each Phoneme in curTemplate
            theName += curPhoneme.GetRandomElement
        next
     


    A Simple Generator


    I've implemented a simple phonetic name generator, using the approach described above. This generator is written in JavaScript and uses an XML file (NameData.xml) to store the phonemes and name templates. (Using XML kept me from having to invent my own file format, parser, etc. And reading XML is, at the time of this writing, easier to do from JavaScript than from C++.)

    The generator currently works like this. (a) It reads in and "objectizes" the phoneme and template data. (b) It lets you select one name template at a time. (c) It lets you control how many names it will generate using the selected template.

    Every time you press the "Generate" button, you get a fresh set of names. Currently, to change the structure of the names that are generated, you have to edit the XML document by hand and then refresh the browser. (I know, I know: A nice enhancement to the generator would be a friendly UI for creating and editing templates and phonemes.)

    Name Data

    XML is a cousin to HTML. Like all XML files, "NameData.xml" starts off with a file type description, which is always "" for any XML file. The single top-level node in the file is called NameData, and it contains a PhonemeList and a NameTemplateList.

    The PhonemeList contains Phonemes (honest). Each Phoneme has a unique name and contains one or more "parts," where each part can have one or more letters in it. Here is a quick example of what the PhonemeList looks like.

    
      <PhonemeList>
          [ ... ]
          <Phoneme Name="Vowel">
              <Part>a</Part>
              <Part>e</Part>
              <Part>i</Part>
              <Part>o</Part>
              <Part>u</Part>
          </Phoneme>
      <PhonemeList>
     


    The NameTemplateList uses a similar approach. Each Template has a name attribute and is made up of "parts." Each part contains the name of a Phoneme. Also, individual parts can be marked as "Cap," which means the first character of the phoneme will be capitalized.

    
      <NameTemplateList>
          <NameTemplate Name="V, MC, V ['Erdi']">
              <Part Type="Cap">Vowel</Part>
              <Part Type="Normal">MidConsonant</Part>
              <Part Type="Normal">Vowel</Part>
          </NameTemplate>
          [...]
      <NameTemplateList>
     


    Try Out The Name Generator: NameBuilder.html
    View The XML Data File: NameData.xml

    Using the Generator

    You can modify the output of the generator by adding or modifying Phonemes and NameTemplates. The approach I typically take is to identify a name I like, reverse engineer that name into a NameTemplate, and then run the generator a few times to see what comes out the other end. If too many of the names stink, I'll modify either the name template, the phonemes, or both, until I find something that I like better.

    One simple template uses three phonemes: Vowel, MidConsonant, Vowel. The MidConsonant phoneme was one I threw together by looking at two consonants in the middle of words in English. Here's some sample output from this name template: Arda, Armi, Ipso, Ontu, Onyi, Epso, Imku, Ifti, Enfo, Ante.

    Another template was aimed at generating Orcish names. This one used eight phonemes, including three "pure hack" phonemes that I created just for this one template: a "GR" phoneme, that contained literally the single entry "gr"; an "RG" phoneme that contained "rg," "rgh," and "rgl"; and a "Separator" phoneme that contained a space, a dash, and a hyphen character. Here's some sample output from this template: Groz'Norgla, Grish'Nurghi, Graz Mirgle, Gres Murgho, Gruf'Merghe, Gruv Nirgla.

    Whether the previous examples appeal to you or not, at least you can see that using the same code base, we're able to get very different results by varying the phonemes and name templates.

    Note, however, that the more we constrain a template, so that it generates exactly the type of names we want, the fewer unique names we can squeeze out of that template. The Orcish name template, for example, quickly begins producing names that, if not identical, are at least very, very similar to each other.

    You can take some corrective action to combat this problem. For example, I expanded the "RG" and "GR" phonemes (renaming them to "OrcBegin" and "OrcMiddle"). I also created a new "OrcBegin2" for the second half of the name, rather than use just a Nasal phoneme as before. The results from this run were a little more varied (Gnith-Zargho, Zath'Hragzha, K'zoz Gnarngu, Zif'Xarghu), but the template still can only generate a limited number of truly unique names.

    For this reason, you'll want to do some additional work if you intend to generate names at runtime (rather than use the generate-and-prune-by-hand approach). Using several name templates for each target race or object type will be a good idea. In addition, you may want to assign a "frequency of use" to each name template, using more frequently those templates that have many unique permutations, and using lesser templates less frequently.

    Jim Adam (jadam@copernus.com)

     

    Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
    Please read our Terms, Conditions, and Privacy information.