Jul 21
2017
Length and Coding Efficiency
Posted by: Adam Strong-Morse | Comments (0)
As part of our support for the Choice of Games Contest for Interactive Novels, we will be posting an irregular series of blog posts discussing important design and writing criteria for games. We hope that these can both provide guidance for people participating in the Contest and also help people understand how we think about questions of game design and some best practices. These don’t modify the evaluation criteria for the Contest, and (except as noted) participants are not required to conform to our recommendations–but it’s probably a good idea to listen when judges tell you what they’re looking for.
If these topics interest you, be sure to sign up for our contest mailing list below! We’ll post more of our thoughts on game design leading up to the contest deadline on January 31, 2018.
One of the most consistent patterns we’ve noticed in how players receive our games is that players prefer longer games. Because of that preference, 5% of the score in the contest is based on length and coding efficiency. In today’s blog post, I’m going to discuss what we mean when we talk about length and how coding efficiency fits in to the same category.
At Choice of Games, we use two measures of a game’s length. The first measure is very straightforward—total word count. Take all of the scene files, run a word count tool, and you get a measure of the total length of the code that the author wrote. For these purposes, we don’t distinguish between pure code (e.g. *choice, *if, etc.) and the text that is displayed to the player. Total word count is a useful tool, but it’s also limited. It can’t distinguish between a mostly linear game, where every player will see most of the words in the game on every playthrough, and really bushy games where every playthrough is very different. For that, we use average playthrough length: how many words does a player read on average on a single playthrough of the game. Our standard method for measuring average playthrough length is to run about 100 randomtest playthroughs set to verbose mode—so randomtest prints out everything a player would see—and then divide the total word count of the 100 runs by 100 to produce an average.
We have a clear minimum for length based on both total word count and average playthrough length that we aim for: we aim to have all of our games have a total word count of at least 100,000 words and an average playthrough length of at least 20,000 words. That’s also the minimum length for the contest. We also find that, in terms of reader reception, the longer the better—that’s why there isn’t an upper limit or even guideline. To put those into context, in traditional fiction, a 20,000 word piece is a long short story or a novella, and 100,000 words is a reasonable length for a novel. In other words, we’re looking for works that have total word counts comparable to novels and average playthroughs similar in length to a novella.
We also look at the ratio of the average playthrough length to the total word count. Here, the sweet spot is about a ratio of 0.2 to 0.4. A ratio of 0.2 would be, for example, a 100,000 word total length game with an average playthrough of 20,000 words. If the ratio is much lower than that—for example, an average playthrough of 20,000 words for a game with a total word count of 200,000—that usually indicates that the author is spending lots of time and energy on content that only a fraction of the readers will ever see. That typically produces a game that feels very bushy, but that feels short despite representing a very large investment of the author’s time and energy. Conversely, a game with a very high ratio of average playthrough length to total word count (for example, a game with a 60,000 word average playthrough length and 100,000 total word count, a ratio of 0.6) generally is a game where player choice doesn’t affect much. Most games feel exactly the same, because a majority of each game is exactly the same regardless of player choices. That’s deadly in interactive fiction. As a result, we want to see a ratio that’s in between, that indicates that player choices matter but also that the author isn’t reinventing the wheel for every possible outcome, writing an epic novel that feels like a short story.
These length standards can’t be applied purely mechanically. Some games are written in a way where the average playthrough length given random choices is much longer than the average playthrough length a human player actually encounters. “Traps” or loops that a randomtest playthrough gets caught in that an actual human player would avoid can cause misleading average playthrough length numbers that require some adjustment. The most notable examples are games that include “are you sure?” choices, which we generally discourage as a matter of style anyway, or puzzles. For some games, we have to make an adjustment in the functional average playthrough length to take that sort of thing into account. Total word count isn’t affected by coding like that, but coding efficiency makes a big difference to total word count.
The core point of coding efficiency is that two different blocks of code can have radically different lengths, but produce the same results. For example, let’s imagine that we have a variable that records whether a character uses male pronouns (“he” etc.), female pronouns (“she” etc.), or neuter/enby pronouns (“they” etc.). The game then includes a 500 word paragraph that uses the character’s pronoun twice. One author codes this as:
*if (pronoun=”he”) Blah blah he blah. He blah blah blah… *goto NextBit *elseif (pronoun=”she”) Blah blah she blah. She blah blah blah… *goto NextBit *else Blah blah they blah. They blah blah blah… *goto NextBit
A different, more capable author codes this using the ${variable} syntax:
Blah blah ${he} blah. $!{He} blah blah blah…
These produce exactly the same results from the perspective of a player, yet the first example is 1500 words or so in length, whereas the second example is 500 words in length. The second version results in a much lower total word count but is in every practical way superior: it’s easier to read and understand, it’s less prone to error, and it allows edits to be used in each context without requiring making the same change multiple times in different places. The difference is all about coding efficiency.
Likewise, sometimes filling in a variable isn’t sufficient—but if a *if is limited to a single sentence, the rest of the paragraph doesn’t need to be copied. Compare this version of code:
*if Injured_leg You hurry across the plaza. Each step sends a shooting pain up from your knee, but you wince and force yourself to keep moving. You know that you to find and defuse the bomb soon, before the afternoon rush fills the area with innocent civilians. *goto FindtheBomb *else You hurry across the plaza. You know that you need to find and defuse the bomb soon, before the afternoon rush fills the area with innocent civilians. *goto FindtheBomb
with this version:
You hurry across the plaza. *if Injured_leg Each step sends a shooting pain up from your knee, but you wince and force yourself to keep moving. You know that you need to find and defuse the bomb soon, before the afternoon rush fills the area with innocent civilians. *goto FindtheBomb
Both versions produce the same output, but the second version is much more efficient. In general, any time you find yourself copying a large block of text and repeating it unchanged or only lightly changed, you should ask yourself whether there’s a better way.
Many other examples of coding efficiency also exist beyond filling in variables. It’s common to have text that should appear the first time the protagonist meets a character. By putting that in a *gosub structure, the text can appear once in the code for the game, but be used appropriately from multiple different possible points. The code for that might look like this:
You enter the room and see a woman in a severe black suit near the bar. *if (met_angela = false) *gosub MeetAngela Angela approaches you and blah blah blah. … As you enter the subway car, Angela Northrop catches your eye. *if (met_angela = false) *gosub MeetAngela Angela holds out a thumb drive. “You’ll want to look through this.” … *label MeetAngela *set met_angela true You recognize Angela Northrop from the photos in the case file you studied, but this is the first time you’ve actually seen her in person. The file that she is 5’6”, but she looks taller in person—something about her posture, or perhaps it’s more about her facial expression. Blah blah blah… *return
By putting the reused text in a *gosub, we reduce the number of errors, allow for faster editing, and make the ChoiceScript code easier to read and understand. In some cases, we can even use the *gosub_scene command to reuse code or text that can show up in multiple different scenes—something that’s particularly useful when there are events that can trigger in multiple scenes such as needing medical care for injuries, or finding out about a big reveal, or meeting a character who can be introduced at multiple different times.
Even efficiency has its limits. Sometimes the effort to create efficient code creates incomprehensible code and introduces errors. If efforts to make your code more efficient start making it hard to read or make you wonder what you’re trying to do, you may want to consider using a little judicious cut-and-paste instead. Nonetheless, within reason, efficient code is faster to write, faster to debug and edit, and generally smoother. As a result, when we consider the total word count of a game, we’ll adjust our evaluation based on efficiency. A really efficient 100,000 word game may contain more actual content than a really inefficient 125,000 word game, and the actual content contained is our main focus.