Home Artists Posts Import Register
Join the new SimpleX Chat Group!

Content

The English language is an unashamed thief of many different languages- Germanic, Romance languages, etc. We use a formal grammar and syntax, which poses some challenges to a programming-generated piece of text. Generating "natural" text is a difficult and many-headed beast, with a good deal of Natural Language Processing tech going into that sort of thing. Unfortunately, machine learning is expensive, and I don't understand very much of it. However, Eigengrau's makes do without any bulky API requests or overhead. In this post, I'll be going over how it does this in a non-tech-y sort of way, and then tell you how the rebuild will work- using some more advanced concepts. Hopefully, you'll learn a little bit, or at least understand what sort of stuff goes into making a generator.

 First, we must understand the rules of engagement- Eigengrau's Generator is very specific in how it presents the information it generates, and I take care to keep it relatively consistent to avoid confusion. The purpose is to mimic Dungeons and Dragons adventure modules, which are resources for Dungeon Masters to use to help run a pre-written campaign. These modules are usually about a hundred pages, and have to encompass the entire adventure, which typically runs for several levels. For many (very valid) reasons, they usually present towns and NPCs only in brief- this allows for DMs to customize, and keeps their word count down. Great- for published adventures. Bad for DMs that don't want to have to think about that sort of thing, and find improvising stressful, or coming up with names a chore. 

Enter Eigengrau's. Per the design document:

The Generator is a tool for the User to automate many of the dull parts of world-building; creating towns, NPCs, and events for the players automatically, it is intended to be used by the Dungeon Master, preferably as part of their session prep. Ideally, the User should be reading one sentence ahead of the Players for whatever part they are reading out, so they can omit any details which they do not feel are appropriate.

We essentially supplement the DM's brain by generating all of the things that might be needed for a town- setting the pieces up, so that they can then layer the adventure on top. This allows it to adapt not just to written modules, but also homebrew worlds which might have different racial demographics, etc.  Things that don't fit are meant to be omitted.

So, we know that the Generator should not be trying to run the show- we avoid imperatives, interrogatives, and direct addresses- "You" is only for entering buildings ("You make your way down Smith's Street..."), and passages meant to be read out directly to players (which are the white blocks, as found in adventure modules).

We can avoid the majority of the language pitfalls by using the passive voice; the text in Eigengrau's is all generated as if you were a silent, invisible observer of a scene, a moment captured and distilled to be always in the present. Think the Watcher from Marvel, but a script for your DM to read out. This allows the DM to add or remove parts wherever needed, and lets them come across as the authority, rather than having to paraphrase; declarative lists of statistics are much less useful than a descriptive list of aforementioned statistics. This is what makes up the bulk of Eigengrau's; functions which take a piece of data (whether it be a height and weight, or a percentage of the population), and turns that into something that's actually meaningful- it might be useful to know a dwarf has a BMI of 17, but it would be much more helpful to know that he's scrawny. 

So, where do we go from here, and what's the rebuild doing differently?

The rebuild will be making use of what's known as a context-free grammar library. You can think of a context free grammar as a series of rules for constructing sentences- though they don't have to be literally "sentences", you could just as easily use it to construct a series of functions to create a compass, as Scott Turner of Here Dragons Abound did in his excellent series of blog posts. 

A grammar has the advantage of being relatively easy to both learn and implement. It might end up looking something like this for us: 

But what if we want condition to be specific to the armour, I hear you say? Conditional logic inside context-free grammars is where it gets a little trickier, and I haven't found any that provides this out of the box. I'm working on extending RitaJS to allow for nesting to facilitate something similar, though; 

Using the 'default' and 'start' properties as reserved for the engine, we can develop nested grammar behaviour that can reduce the number of conditional functions that we need. If that looks much more complex, that's because I've extracted out each possibility to its own property. The inline version might look like this;

We could even pipe in context, to give our armour rules based on the culture-

By contrast, here's how you might do it without a grammar:

Note how the elf armour requires a value, even though it's the only one- this is because we are using the weightRandom function to simulate how the parser would choose the different values, and have to add in a conditional for the function to handle the leather armour, which doesn't have a condition of its own. To be clear, this isn't a bad way of doing it, and extracting out to full code makes a lot of sense a lot of the time- you get all of the benefits of IntelliSense while typing, and the developer experience is generally better, with the ability to add in extra error handling, and all the other benefits that a full code environment brings. But, do I really want a 40 line function just to create a description of some armour? This is where the parser comes in handy, because it's an easily repeatable pattern. A pattern that we find ourselves doing a lot in a generator like Eigengrau's, and without this low-friction pattern, the chances of non-coders contributing is basically nil.

Making a strong foundation for the rewrite is a slow process, but I'm confident that the benefits will be worth it- I'll have more news to talk about in a couple weeks.

Comments

Andrew Miller

Really interesting to see how the sausage is made. Thank you for the write-up!