GPT-3 Orc Simulator
Using GPT-3 as your GM
I love text adventures and other fantasy computer games. I’ve always been a bit disappointed by them, though, because of the canned dialogue. Wouldn’t it be great if you could just speak to the characters, and they could speak back to you?
With the advent of large language models, and GPT-3’s Davinci engine in particular, you can now chat with your NPCs. And, it’s amazing.
In this article I present Orc Simulator, a deceptively simple game. It’s just you, an Orc, a cave, an amulet and some chicken. Can you get the amulet?
The code is here, with an MIT license. Download it, add your OpenAPI key, and have a go: https://github.com/emlynoregan/orc-simulator
Note that you can rack up a decent bill pretty quickly — you have been warned!
Orc Simulator is a very simple text adventure game, that uses GPT-3 to generate dialogue for the Orc, and to do some simple reasoning about the game in the way that a game master might.
There are some GPT-3 based games around, but they all seem to just be stream of consciousness chats between you and the computer, with an initial prompt to get you started telling a fantasy story. I haven’t found that very compelling.
In Orc Simulator, there is a simple world model, that keeps the Orc on track. It means you can have a real objective; really play a game.
It’s easy to get GPT-3 to churn out some crazy story for you. It’s harder to make that work as a game. To do this, I’m using something I call the Data/Narrative Model:
1: Data
This is a simple world model. In the code I keep track of what items the characters have, and whether the orc is hungry.
2: Data to Narrative
Here I generate text from the data. Based on the world model, I have some canned text, some for displaying to the player, and some for sending to GPT-3 as a prompt.
Here is an example of the orc prompt, and the response returned by GPT-3. Every time around the game loop, the previous responses and events that occur are kept in an array called “history”, and included in the next prompt. That’s how the orc “remembers” what has happened so far.
The first few lines of “the human says XXXX, the orc says XXXX” are hard coded, to give GPT-3 an idea of what is expected, but the lines below “The orc is holding a shiny golden amulet” are all the history from a particular run of the game.
3: Narrative
The Narrative Domain is where I call the GPT-3 API; I pass in a prompt, and get back some response (basically, what should come next). I display GPT-3’s response (ie: the orc’s response) to the player, and add it to the history array, for next time around the loop.
4: Narrative to Data
So, this is the tricky step. Given the response from GPT-3, we need to figure out how this affects the data, the world model, and update it accordingly.
In particular, the orc can take actions, and the actions change the world model (eg: attacking the player means the player dies). But how can we decide what the orc will do? It should be based on what has happened in the game so far, on what has been said by both the player and the orc.
The problem is that determining what has been said is as difficult as generating the story in the first place; this is open dialogue. Luckily the solution is to use GPT-3 to interpret for us.
I use a technique of asking GPT-3 closed (yes/no) questions about the script so far. The questions I ask in this game are:
- “does the orc give the amulet to the human?”
- “does the orc give the sword to the human”
- “does the orc attack the human”
- “has the human asked for the amulet?”
To do this, I take the current orc prompt, with the latest history included, and then append some question asking stuff. eg: for “does the orc attack the human” I send this to the api:
<orc prompt here>q: is the orc strong? a: yes
q: is the human here? a: yes
q: does the human have an orange? a: no
q: does the orc attack the human? a:
I’m only interested in the next token, it’ll most likely be “ no” or “ yes”. This is as much parsing as I do:
return ai_msg.lower().strip() == "yes"So if I get a yes, then I can proceed with the orc attacking and killing the human. It can only actually do this when it has the sword, so I only ask when it has the sword. If I get a no or anything else, the action doesn’t occur.
The case of the orc giving the sword to the human is most interesting, because it doesn’t end the game. Instead I display a message to that effect to the player, and add the same message to the history (so the orc will “know” it did that next time around the loop), and I update the world model (the orc no longer has the sword, I wont check if it gives the sword to the player any more based on that world model information).
I notice the orc often becomes a bit sheepish or scared after it gives away the sword; GPT-3 is aware that the orc is in a bit of trouble!
So, give it a shot. It’s a surprisingly fun and challenging game; that orc is pretty volatile. Be creative to get that amulet, you need to craft a narrative to convince the orc to give you that amulet. Good luck!
