4.9 KiB
D&D Language Generator
This package is a fantasy language generator. By defining a number of characteristics about your imagined language -- the graphemes, their relative frequency distributions, the construction of syllables, and so on -- you can generate random but internally consistent gibberish that feels distinct, evocative, and appropriate to your setting.
Quick Start
>>> from language imported supported_languages
>>> common = supported_languages['common']
>>> common.word(2)
['apsoo', 'nirtoet']
>>> common.text()
Proitsiiiy be itkif eesof detytaen. Ojaot tyskuaz apsoo nirtoet prenao.
>>> commoner = f"{common.Name}"
"Quiet" Gushi Murk Lirpusome
>>> common.Name.name()
{
name: ['Gushi', 'Murk'],
surname: ['Lirpusome'],
adjective: ["Quiet"],
}
Supported Languages
A number of D&D languages are defined, with rules built according to the conventions established by my D&D group over several years of play in our homebrew setting. You can find all supported languages in the languages submodule; each submodule contains a README that describes the basic characteristics of the language, along with examples.
Defining a Language
Layout
A language consists of several submodules:
base.py
, which contains grapheme definitions and theLanguage
subclasses;names.py
, which defines theNameGenerator
subclasses; andrules.py
, which is optional but defines the rules all words in the language must follow.
Language Construction
Let's look at a simple example, the Gnomish language. Here's the Language
subclass that would be defined in base.py
:
from language import defaults, types
from .rules import rules
consonants = types.WeightedSet(
("b", 0.5), ("d", 0.5), ("f", 0.3), ("g", 0.3),
("h", 0.5), ("j", 0.2), ("l", 1.0), ("m", 0.5),
("n", 1.0), ("p", 0.5), ("r", 1.0), ("s", 1.0),
("t", 1.0), ("v", 0.3), ("w", 0.2), ("z", 0.1),
)
suffixes = types.equal_weights(["a", "e", "i", "o", "y"], 1.0, blank=False)
Language = types.Language(
name="gnomish",
vowels=defaults.vowels,
consonants=consonants,
prefixes=None,
suffixes=suffixes,
syllables=types.SyllableSet(
(types.Syllable(template="consonant,vowel,vowel"), 1.0),
(types.Syllable(template="consonant,vowel"), 0.33),
),
rules=rules,
minimum_grapheme_count=2,
)
Defining Graphemes
A Language definition includes graphemes, the basic building blocks of any
language. We start with vowels, consonants, which are required in every
language; Gnomish also includes suffixes, but no prefixes. Each
grapheme is a WeightedSet
, which is like a regular set except its members
consist of a tuple of a string and a relative weight from 0.0 to 1.0. These
weights will be used when selecting a random grapheme.
Gnomish uses the default vowels, defined in the language.defaults submodule, but define our consonants with a subset of English consonants. By experimenting with different sets and different weights, you can generate radically different feeling text output!
Gnomish also uses suffixes, which are graphemes added to the ends of words.
Here we use the helper function types.equal_weights()
, which returns
a WeightedSet
where each member is given the same weight. Normally this
function also inserts the grapheme ("", 1.0)
into the set, but we disable
this behaviour by specifying blank=False
.
Defining Syllables
A syllable is a collection of graphemes, including at least one vowel. When we
create words, we select a random syllable template from a SyllableSet
, which
is just a WeightedSet
whose members are Syllable
instances. Each Syllable
declares a template
, and like graphemes, has a weight associated with it that
will make it more or less likely to be chosen for a word.
A syllable's template consists of a comma-separated string of grapheme names.
In Gnomish, we have two possible syllable templates, consonant,vowel,vowel
and the shorter consonant,vowel
, which will be selected one third as often.
Templates can also support randomly-selected graphemes by joining two or more
grapheme types with a vertical bar, for example vowel|consonant
would choose
one or the other; vowel|consonant,vowel
would result in a vowel or
a consonant followed by a vowel.
How Words Are Constructed:
The main interface for callers is word(), which returns a randomly-generated word in the language according to the following algorithm:
- Choose a random syllable from the syllable set
- For each grapheme in the syllable 3. Choose a random grapheme template 4. Choose a random sequence from the language for that grapheme 5. Validate the word against the language rules
- Repeat 1-5 until a valid word is generated
- Add a prefix and suffix, if they are defined
When graphemes are chosen, the following rules are applied:
- Every syllable must have at least one vowel; and
- A syllable may never have three consecutive consonants.