A rule-based language for adventure games, part 2: text adventures

Logo

Above is a very simple text adventure game, in the style of the classic Adventure. It can be played directly in this page, and is written in Golem, a rule-based language designed especially for this purpose. Golem was described in part 1 of this series, and this game is a slightly improved version of the sample game from the previous article, where the dead ends have been fixed. The rules only describe the logic of the game, which can then be rendered in different ways; we previously saw a graphic interpretation, in this article, we have a look at a parser-based, text-only user interface which does not require any additional resources.

In this style of interface, the player enters commands at a text prompt, like take the stone or examine the fountain. Recall that our rules could describe three main actions from the player: looking at an item, taking an item, and using an item with another:

# Looking at an item
stone: "A plain looking stone that fits in the palm of your hand."

# Taking an item
stone, +You: +You [stone].

# Using an item with another item
stone, cavity: cavity+Filled.
Three kinds of rules: look, take, use.

This means that a Golem game can be played in a text interface using three verbs: look, take, and use (a few more verblike keywords are also needed, such as inventory to see what items the player currently carries, and help). A lot of modern graphical point-and-click adventure games do actually use such a small vocabulary compared to the early attempts that used a text parser (like the older Sierra games) or a grid of verbs (like the Lucasfilm classics). But these games also have graphics, animation and sound; for the purposes of a text-only game, a richer vocabulary is necessary. A simple extension to our language can require a specific verb to trigger a rule:

# Take the stone
take(+You, stone): +You [stone].

# Drink from the fountain
drink(+You, fountain): +You, fountain, "The cold water tastes delicious."

# Drop the stone in the hole
drop(stone, hole): Tunnel [stone], hole, "The stone dropped down in the
    darkness, but you can hear it hit the floor." 
Adding verbs to the rules.

Rules define a subject and an object; the verb was inferred automatically. Now, it is also possible to introduce a verb first, with its subject and object as its two arguments: Verb(Subject, Object). You (subject) take (verb) the stone (object). You drink from the fountain. The stone is dropped in the hole (actually, you drop the stone in the hole; we have to stretch the notion of subject a little bit in order to keep things simple). Another thing that we can do to keep things simple is keep verbless rules around, which is especially useful for descriptions (rules triggered by the verb look).

One common gripe about text adventure games was that their parser could be very picky about the words that could be used. In our example so far, you can look at the stone but not examine the fountain, even though that was an example command above. In order to alleviate this problem, we need a way to define synonyms for the verbs that trigger rules: examine or check for look, get or pick up for take, &c. Defining synonyms should be separated from defining game rule, since we usually want synonyms for look or take to apply to all rules triggered by that verb. Therefore, we need new syntax for synonyms. (Our user interface also has autocompletion, which can be helpful as it hints at what verbs are pertinent to the game.)

Although we have not made much progress on that front just yet (look out for a further installment in this series in the future), the original goal of defining an adventure game in terms of rules was to create a declarative language amenable to static analysis; where the logic is clearly defined so that an automatic process is able to find dead ends or other issues. Synonyms are just a presentation issue and not really part of the logic of the game: whether the player types take or get has exactly the same effect. Adding rules for synonyms would only add noise that the analyser would have to filter out. However, we could look at synonyms as metadata, describing additional properties of rules that the renderer can make use of, and that the analyser can gleefully ignore.

Medusa is sitting in a hair dresser chair while the serpents in her
    hair hiss menacingly at a hapless hair dresser.
At the movies.

Metadata is useful for our system in general. It allows the description of more facts about the game that may be useful, but again do not concern the core logic itself: the game title, its author(s), publication date(s), what (natural) language is it written in (more on that topic later), and so on. We already have comments in the language, which could be considered as a kind of metadata, but these should not have any systematic meaning. It should make no difference whatsoever if they were all stripped from the source. Our metadata should on the other hand have systematic meaning, even structured meaning in some cases; therefore some kind of markup would be useful for that, hosting both rules and data about the rules. Fortunately, we happen to have such a language in our back pocket: the Dodo 🦤 markup language!

{ golem: "The Cave" date: 2024-11-10 lang: en

    { rules
        Cave+Loc [Alice+You [rope, knife], stone, hole]: "You are in a
            mysterious cave."

        # A lot more rules...
    }

    { synonyms
        { take `{ get pick pick\ up } }
        { look `{ examine check } }
        { go `{ go\ through enter } }
        { put `{ dip shove } }
    }
}
Embedding Golem rules in a Dodo file.

Above is the source file for the game embedded in this article (with most rules omitted; we want to focus on the container, not the contents, at the moment). The root element is golem and the title of the game is given as the default attribute. Here we also have a completion date, and we declare that the language of the document, and hence the game, is English. The rules are embedded in the rules element. It is followed by a synonyms element that maps the verbs used in the rules (take, go, put) to their synonyms (with a bit of funky Dodo syntax to make lists and escape whitespace); the verb look does not appear in the rules, but it is a default verb for descriptions, so we can define some synonyms for it as well.

A bit more about the parser and the importance of natural language. Our parser is extremely simplistic and only attempts to match verbs and nouns that are part of rules of the game; so when typing “go down the hole”, all the parser really sees is the verb go and the noun hole which match the vocabulary derived from the rules. You could also type “I wonder if it is possible to go down the hole?” or “hole go!” for the same effect. Finally, defining a language for the game would be useful if the system supported proper internationalization, so that all the user interface text (the prompt placeholder, the response to commands that cannot be parsed, the proper rendering of location description, &c.) can be localized to match games written in languages other than English. But this is future work. ⚀⚂