Stories with Memory
Chapter 5: Variables and Logic
Expanding the Possibilities
In the previous chapter, we saw how the ability to assign labels to choices and gathers makes it easy for the writer to instruct Inky to track the reader’s decisions as they progress through the story. In this chapter, we will expand upon that concept.
Before proceeding with the lessons in this chapter, take a few minutes to explore the sample game, “Marbles.” As always, play through the short scene more than once. Select the choices in different orders. What differences do you notice in the text?
When you are finished, download the file: Marbles.ink and open it in Inky. We will be referencing this code throughout the lesson.
Learning Objectives
- To understand variables and how variables are assigned in Ink
- To demonstrate the different kinds of information that can be assigned to a variable
- To understand the proper command syntax and basic operations for changing the value of a variable
- To understand the basic elements of Boolean logic and how it can be used with assigned variables in Ink
Variables
A is any unit of information stored in an Ink story with a value that may change over the course of the story. Labels (which were introduced in the previous chapter) are actually a subset of variables. Variables are the broader, more general category. Therefore, as we saw in the previous chapter, a label is a variable that is attached to a specific choice or gather-point, and it stores the information of whether or not that specific choice or gather-point has been selected by the reader. Labels also track the number of times that the choices or gather-points have been activated.
However, variables need not necessarily be tied to anything that is directly displayed to the reader. They are the fundamental unit used to communicate with the story itself, allowing you to equip your playable story with the ability to perform all kinds of behaviours! In the lesson that follows, as we explain some of the basic functionality of variables in Ink, try to keep in mind that determining how to incorporate variables into a work is a part of the creative process when writing a playable story. In many cases, the writer first determines the end-effect they would like the story to present to the reader, and then, working backward from that goal, they develop the variables and conditions that will allow the story to do so.
Assigning a Variable
A variable is created by using the command syntax, “VAR”. Variables in Ink must follow the same naming convention that knots and labels are bound to, meaning that a variable name cannot contain spaces or special characters other than an underscore. A line in which a new variable is created and assigned looks like the following examples.
Each of the lines above contain three components: 1) the command syntax “VAR,” 2) the variable’s name followed by an equal sign, and 3) a value. Inky is capable of parsing different kinds of values for each variable based on how they are written. The most basic examples are numeric values (line 2 in the above illustration), strings of text (enclosed in quotation marks, as is seen in line 3 in the above illustration), or Boolean true-or-false values (line 4 in the above illustration).
Numeric values function as exactly that; they are numbers that can be combined, calculated, or evaluated. String values are sequences of alphanumeric characters—for example, words, or phone numbers. Boolean values are a concept common in programming that allow for a binary conditional check: true or false. Let’s take a closer look at these three variable types.
Consider the following example:
It produces the following output:
Signifying a contextual command, the curly brackets { } direct the Ink story to perform an action. In this case, the story is instructed (in line 5) to find the values of the variables named within the brackets. In line 7, the bracketed portion instructs Ink to perform a calculation adding together the values of the two specified variables (using the + sign). Because the variables called in line 7 both have numeric values, the output in the preview pane, shown in Illustration 40 (above) displays the sum of the two amounts.
If we change the variable assignments to read “10” and “1”, as seen in Illustration 41 (below):
Then the output changes to:
This is because by putting the assigned values in quotation marks, we have made them into strings, which are sequences of alphanumeric characters, not calculable numbers. Looking at Illustration 42 (above), the first line of output is identical in appearance to the output shown in Illustration 40. However, by looking at the second line of output, we can see that string values behave differently than numeric values. Instead of the numbers 10 and 1, the line now contains the strings composed of the numeric characters ‘10’ and ‘1’. In Ink, adding two strings together is called . Concatenation appends one string of text onto the end of another. It does not perform a calculation (in this case, addition) because a string value is not a numeric value! Because of this, in the second example, the string “1” is appended to the end of the string “10”, resulting in an output of “101”. If the string values had been written as “ten” and “one”, the output would be “tenone”.
In addition to numeric values and literal text, variables can also be Boolean values. A Boolean value is either true or false. Therefore, a variable with a Boolean value can be used with conditional expressions. For example, a line of Ink code checking for a Boolean value translates to, “if X is true, do this, if X is false, do that.”
Look at this simple example:
First, in line 1 of Illustration 43 (above), the variable yes_or_no is created and assigned a Boolean value of true. Then, in line 5, the curly bracket command checks the value of the variable, and because it is set to true, Inky prints the first (true) phrase, “It’s true”. Line 7 presents the reader with the solitary prompt, “Flip it?”. Once the prompt is selected by the reader, the flow continues. Line 8 (by a method we will explore shortly) instructs Inky to change the value of the variable yes_or_no to false. Then line 9 diverts the flow back to the top of the knot. Now, line 5 once again checks the value of yes_or_no. However, now it is set to false, so the first command is passed over and Inky moves to phrase after the vertical bar (false), which instructs it to print “It’s false” and then immediately divert the flow to END.
Inky at Work: Variables set with Boolean true/false values provide a simple, elegant method of introducing an inventory system into your playable story. By assigning a variable to an item in the story and setting the value to either true or false, you will be able to easily write text that changes based on whether or not the player possesses that item.
For example, a variable named “wallet” (i.e. VAR wallet = true) could mean the difference between text that reads, “Your dining partner smiles at you as you settle the check. The waiter expresses their gratitude,” or “You feel your brow break out in perspiration, frantically searching your pockets. Your dining partner and the waiter stare at you expectantly.”
The prompt “Flip it?” is appropriate here. When writing your playable stories, whenever you need to check a binary condition—perhaps, say, whether or not a character took an umbrella—you can use a variable with a Boolean value. Then, you can simply instruct certain choices made by the reader to “flip that switch”, meaning that the Ink flow itself will remember whether or not the character ever, say for example, picked up the umbrella. That way when you need it to start raining in your narrative, the Ink story will know whether the character has to duck into that seedy-looking bar or if they can keep strolling down the sidewalk.
Marbles
The sample Ink story, “Marbles,” is a playable story with a very thin narrative structure that allows the reader to bet their marbles against an “opponent” until one of them has all the marbles. This example is a bit light on dramatic depth, but it perfectly demonstrates the basic techniques for using variables in an Ink story.
Take a moment to play “Marbles” before downloading and opening marbles.ink, then follow along with the lesson below. (Links at the top of the chapter)
First, let’s look at the variables created.
The Ink story “Marbles” has four variables. The variables named “marbles,” “opponent,” and “wager” have each been assigned a numeric value. The variable named “outcome” has been created as a string, which is distinguished from a numeric value by quotation marks ( ” ” ). However, in this case, “outcome” is an empty string, as there is nothing within the quotation marks. We will see why this is important in a moment. For now, note that a string variable can be created with an empty value.
Note: Variables exist globally, meaning they can be checked by Ink from lines in any knot within the same Ink story. By putting the lines that create variables at the top of the Ink story, we make it easy to identify and keep track of all of the Ink story’s variables in a single convenient location. It is stylistically preferred and considered best practice to place lines that assign variables at the beginning of an Ink story’s code, regardless of where in the flow the variable is first encountered.
Once the variables are created, the Ink story diverts to the knot named “Ring.” Line 9 will print the text to the reader, replacing the variables, which have been set apart by curly brackets, with their current values. Initially, the output will look like this.
Now, let’s look at the way the Ink story creates the choices. In Illustration 45 (above), there are the numbers 10 through 1, plus an option that allows the reader to select, “All the marbles.” The lines of the Ink story that create the first few are shown in the figure below.
First of all, note that they are all created as sticky choices, determined by the plus sign (+) that begins each line. There are several other important details to note here.
Each sticky choice begins with a curly bracketed portion. These are conditional instructions. The curly bracketed text in line 13 translates to “if the variable ‘marbles’ is greater than 9 and if the variable ‘opponent’ is greater than 9, then display this choice (that is, the ‘10’ following the closing curly bracket).”
A Slight Detour: Boolean Operators
In Illustration 46 (above), lines 13 and 21 use the word “and,” and line 17 uses “&&” in the same position. They both perform the exact same function.
Conditional statements instruct Ink to perform a check whether the variables involved, for example “marbles > 7”, are true or false. Boolean operators make it possible to check for multiple variables simultaneously. Therefore, line 21, which reads,
+ {marbles > 7 and opponent > 7} 8
translates to:
Create a sticky choice that displays the text “8” if and only if the variable named “marbles” has a value greater than 7 and the variable named “opponent” has a value greater than 7.
As this translation indicates, for a conditional statement with an “and,” both variable values have to evaluate as true in order for the conditional command (display the text “8”) to be carried out.
Boolean conditional commands can include the word “or” as well. If the statement reads:
+ {marbles > 7 or opponent > 7} 8
then the line will print (that is, display the text “8”) if at least one of the variables is true (has a value greater than 7).
Boolean logic can be used to create incredibly complex conditional statements. Parentheses can be used to nest sets of terms within larger sets: for example,
{(x > 0 and y < 0) or z == 0}
is true if either
a) x is greater than 0 and y is less than 0
or
b) z equals exactly 0
evaluates as true. If x is 1 and y is 0, statement a) would evaluate as false because, in this example, x is true and y is false, and both would (because of the “and”) need to be true to evaluate as true. However, if z is 0, then statement b) would be true, and, since only statement a) or statement b) needs to be true, and b) is true, the entire statement {(x > 0 and y < 0) or z == 0} in this example evaluates as true.
As we have seen previously (see the “Contextual Commands” section in Chapter 4), the word “not” can also be used in Boolean logic.
Boolean Shorthand
The Boolean terms “and,” “or,” and “not” are all recognized by Inky when they are written out as words. However, they each have a shorthand symbol that Ink will recognize as well.
and is abbreviated to &&
or is abbreviated to || (double pipe)
not is abbreviated to !=
greater than or equal to is >=
less than or equal to is <=
Boolean: In Summary
Boolean statements take practice. For now, what is important to understand is what Boolean statements make possible when writing with Ink and Inky. They allow you to partition the content you write, separating what will be presented and when, based on the feedback from the reader. In the context of your playable story’s roadmap, conditional Boolean statements are gates. They allow you to control which elements are introduced as the Ink story moves through its flow.
As with variables, think of conditional statements as a part of the creative writing process when working with Ink and Inky. When you encounter a point in your playable story in which you must control whether or not a piece of your content will be displayed for the reader, consider the tools at your disposal. There are typically multiple methods that can be used to achieve the same desired effect. When learning how to write playable stories, practice working backwards from the effect you are seeking to create. How can you instruct Inky to produce that effect for the reader? What variables do you need to create and assign values to in order to make that happen? What conditions do the variables need to meet before the content will be displayed?
Back to Marbles
Illustration 47 (below) shows the lines from the Ink story that create the last four potential choices for the reader.
Similar to lines 13, 17, and 21 examined previously, lines 41 and 45 present conditional statements that require the values of both “marbles” and “opponent” to be greater than a certain value for the sticky choice to be made visible to the reader. What this ensures is that a wager cannot be placed if either of the players involved—represented in this case by the variables “marbles” and “opponent”—cannot afford to lose.
The sticky choice on line 48 does not require a conditional statement because if either player does not have at least one marble, the game is over. We will see why in the next section.
The sticky choice on line 52, “All the marbles,” provides a short-cut for the reader to bet the most they are allowed to within the round. Let’s look at how this is achieved.
Line 53 begins with a tilde (~). When a tilde is placed in front of the name of a previously-created variable, Ink sets a new value for that variable based on what information follows. In the case of line 53, Ink changes the value of “wager” to whatever the value of “marbles” is at that moment. What this accomplishes, on a practical level, is that the bet, “wager,” is set to an amount equal to the number of marbles the player currently has, “marbles.”
For the other lines in the figure that begin with a tilde—lines 42, 46, and 49—the value of “wager” is changed to a value equal to the number displayed in the sticky choice.
In all of the above cases, no matter which choice is selected, after the value of “wager” is changed, the flow is instructed to divert to a knot named “Play.”
Breaking Down Play
In the sample Ink story, the knot named “Play” contains the instructions which provide the foundation for the playable story, “Marbles.” The lines containing the knot are displayed in the Illustration 48 (below).
Remember at the beginning of this section, when creating and assigning the variables for the playable story, “Marbles,” we assigned the variable named “outcome” a value equalling an empty literal text string. Line 5 reads:
VAR outcome = “ ”
This is because when writing in Ink, a variable must be created with a single, static value. In order to exist, a variable must first equal… something, even if that something is an empty text string.
In this case, it is necessary for the variable named “outcome” to have been created in this fashion because of the instructions on line 58:
~ outcome = “{~won|lost}”
Think back to the section on sequences and alternative text. Inside the quotation marks to the right of the equal sign in the line above is a shuffle sequence containing the words “won” and “lost”, each word representing a potential alternative text. The variable named “outcome” could not have been created using this shuffled value because a variable must have a single, static value when it is created. However, once it has been created, as it was in line 5, we can then reassign the value by using a shuffle sequence. By doing so, we add a random element to the playable story we are writing, changing the variable’s value every time the Ink story’s flow encounters instructions to do so.
In this example, the first line that the flow encounters, after diverting to the knot “Play”, instructs Ink to change the value of the variable named “outcome” to a string value equal to either “won” or “lost”, depending on how the shuffle sequence resolves itself. Then on line 60, the instructions tell Ink to print the line, reflecting the new value of the variable, resulting in either “You won!” or “You lost!”
Conditionals Containing Multi-Line Logic
Lines 62 through 68 were created using a template available in Inky’s drop-down menu Ink>Multi-line logic>Condition. The template looks like this to start:
For comparison, here is a closeup of lines 62-68 in the example:
In line 62, the generic template’s “yourVariable” is changed to “outcome,” and a conditional is added to check whether or not the variable named “outcome” is equal to a literal text string containing “won”. The double equal sign (==) creates a condition that the value of the variable exactly matches the text or the amount shown on the right side of the equation. Lines 63 and 64 in the example replace line 10 in the template. Instead of text to be written, the lines provide instructions for Ink to follow if the condition presented on line 62 has been met. In this case, the lines give instructions for changing the values of the variables named “marbles” and “opponent”. Also note that multiple lines can be inserted with multiple instructions to be carried out if the conditional statement that precedes them is true.
If the condition presented on line 62 has not been met, then the flow passes over the instructions on lines 63 and 64. Line 65, which is left unchanged from the template’s line 11, is a gather point, denoted by the (-) syntax command. It contains the syntax “else:”, which instructs Ink to perform the following instructions only if the previous condition listed has not been met. The closing curly bracket on line 68 ends the multi-line conditional statement.
So what do the lines in the figure above accomplish? Take a moment to consider the question yourself before moving on to the explanation.
So far, we have examined two elements of the knot “Play.” First, lines 58-60 select a random value out of two potential outcomes, in this case, the literal words “won” or “lost.” Then they display a line of text that incorporates that value. Afterwards, lines 62-68 perform a background accounting of the variables “marbles” and “opponent”, increasing or decreasing their values based on the value of the wager and whether or not the reader won or lost. But what happens next?
Ending the Game
When the closing curly bracket appears on line 68, the multi-line conditional statement ends and the Ink story’s flow continues with the new values for each of the variables in place.
The figure below shows the last lines of the knot named “Play”.
Lines 70 and 71 are examples of inline conditional statements. They are useful for shorter instructions that do not necessitate using multi-line instructions like in the previous example.
Inline conditional statements can be generated by using Inky’s drop-down menu, Ink>Inline logic>Condition. It produces the following template:
Inky detects an error in the template because the current Ink story does not contain a variable named “yourVariable”. The error will resolve itself once you change the name of the variable in the template to match the name of a variable that exists in your Playable Story.
In the example Ink story, for lines 70 and 71, “yourVariable” has been changed to “marbles > 19” and “marbles == 0”. The first condition is followed by instructions to print “You won all the marbles!!!” and then immediately divert to the end of the flow. The second condition presents a losing message followed by a divert to the end of the flow. These lines demonstrate the win and loss conditions for the Ink story. If the player, represented by the variable named “marbles”, has more than 19 marbles, then that means they have 20, which is the total amount of marbles available. This is how the player “wins” the game. If the same variable, “marbles”, has a value of 0, then the player “lost”.
If neither of those conditions are true, then the flow of the Ink story continues to line 73, which diverts the flow back to the knot named “Ring”.
Returning to the top, the Ink story will print the current values for each of the variables and the player will once again be invited to select how many marbles they wish to wager. Because of the conditional statements preceding each choice, the player will not be able to select a wager higher than the lowest current value of the variables named “marbles” and “opponent.” For example, if, after one round of wagering, the player has 12 marbles and the opponent has 8 marbles, then the highest wager displayed to the player as a choice will be 8. This is because as the flow continues through the Ink story as shown in the figure above, the conditional statement on line 21 will be the first that will prove to be true.
The design of the sample Ink story “Marbles” is such that the flow continues to move back and forth between the knots “Ring” and “Play” until one of the two game-ending conditions (on lines 70 and 71) are met, at which point a final message is printed and the Ink story comes to an end.
Review
- Variables are created by using the command syntax “VAR”. Variables must be named according to Inky’s internal naming convention, therefore the name cannot contain spaces or special characters other than the underscore. A variable must be assigned a static value when it is created.
- There are three types of values that a variable can have: numeric, literal string, or Boolean true/false. A numeric value can be used in mathematical calculations. A string is an exact piece of alpha-numeric text (however, the numbers in a string cannot be used in mathematical calculations). A Boolean value of true or false can be used as a binary condition, a yes or a no.
- The command syntax instructing Inky to change the value of a variable is a tilde (~) followed by the name of the variable, an equal sign (=), and the new value.
- Conditional commands can be created using curly brackets ( { } ). Within the brackets, commands checking the value of a variable (such as greater than or less than or equal to) can be used to establish multiple potential texts and provide instructions as to which texts should be presented under which circumstances.
Putting It All Together
This chapter opens the door on many complex functions made possible when writing with Ink and Inky. Rather than attempt to provide an exhaustive list of the ways that variables can be used in an Ink story, this chapter is instead designed to illustrate how long that list would be. Variables are merely another tool in your writing tool-belt. What you are able to build with them is up to you to discover.
As stated earlier, Boolean logic and conditional commands can become incredibly complex and layered. This is no different than written text. When trying to turn a complex idea into an essay, it is important to break down that complex idea into a series of smaller, more easily digestible ideas. If you find yourself struggling to produce a certain effect or result in your Ink story, take a step back and assess, point by point, what the Ink story’s flow is calculating. Do you require an additional variable? Do you require fewer variables? Are you giving Inky the correct instructions?
Like so many things worth doing, the only way to improve is to practice. Challenge yourself to think of a complicated process your story could include and see if you can implement it. After you succeed , check again to see if there are any ways you can reduce the number of steps in the process and still achieve the same results. As you practice, you will develop your own methods and techniques.
The primary unit of an Ink story's "memory." A variable can be created to keep track of various pieces of information as the Ink story progresses along its flow.
The process of combining two alpha-numeric strings of text. The result affixes the two strings together, in order.