Skip to content

Instantly share code, notes, and snippets.

@shawna-p
Last active February 16, 2022 04:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shawna-p/ff0c466358b676969a0ccea0674bb707 to your computer and use it in GitHub Desktop.
Save shawna-p/ff0c466358b676969a0ccea0674bb707 to your computer and use it in GitHub Desktop.

Conditionals and Comparisons in Ren'Py, Part 1

Building off of the information in the previous tutorial on variables, this guide will walk you through comparing variables and using conditional statements in your game to do things like change dialogue, customize menu choices, and branch the game down different paths. A quiz at the end will test your knowledge of how to use conditionals.

It's recommended that you first look over the Complete Guide to Ren'Py Variables. This guide also assumes you have a basic idea of how to write choice menus. If you need a quick refresher, you can check out the section on Menus, Labels, and Jumps in the Ren'Py quickstart.

Since there's a lot to cover, this guide has been split into four parts. The first part will cover conditional statements. The second and third parts will cover the different kinds of comparisons you can use to compare variables and do things like change your game dialogue or branch into entirely separate story paths. A fourth part will combine all the things you've learned and test your knowledge of these new tools.

Conditionals and Comparisons in Ren'Py

Part 1 - Conditional Statements (You are here!)

Part 2 - Equality and Truthy/Falsey

Part 3 - Numerical Comparison & Combining Comparisons

Part 4 - Combining Everything (Coming soon!)

Conditionals

What's a Conditional?

A conditional, or a conditional statement, is code that tells the computer whether to do something based on the outcome of a particular expression.

In simpler terms, sometimes in your day-to-day life you need to make decisions like "if I finish my work early, then I can play video games" (and if you don't finish your work early, then you won't play video games). This if/then-style of decision making is called a conditional.

In code, a conditional allows you to change what code is executed (run by the computer, so it shows in-game) based on some kind of condition (like "if I finish my work early"). The condition itself ("if I finish my work early") is known as an expression, which is evaluated, or checked, to determine if it's True or False. If the expression evaluates to True, then the code associated with it will run. If it evaluates to False, then it is skipped.

For example, the process of evaluating the expression "if I finish my work early" would involve checking if the work is done at an early enough time. If so, then the expression is True, as in, yes, it is True that the work is done and it is still early. As a result, you can now play video games (since "if I finish my work early" (True) "then I can play video games").

Term list:

  • expression - things like "if I finish my work early" or "if I have two cookies and three apples" which you'll check to see whether they're true or not (as in, do you have two cookies and three apples?)
  • evaluate - the act of checking or figuring out the result of an expression. For something like "if I have two cookies and three apples", this would involve counting exactly how many cookies and apples you have.
  • conditional - code that tells the computer to do something based on the outcome of evaluating a particular expression
  • execute - as in, to execute code. This just means to "run" the code, such that you see the associated line of dialogue, display an image, etc. Code executes sequentially, which means that it will play out in the order it's written (aka things located earlier in a file get run before things located later) unless you use things like conditionals or jumps to change the order or skip certain lines.

The if Statement

The if statement is the most basic way of writing conditionals in Ren'Py. In its simplest form, it looks like the following:

if <expression>:
    <result>

An in-game example of this might look like:

if went_to_store:
    "You didn't buy anything, though."

You might recognize this from the previous tutorial on variables. went_to_store is a Boolean, that is, it is either True or False. If it is True, then the line below it should play. If it's False, then this line should be skipped over so the player doesn't see it.

In Ren'Py and Python, spacing is crucial to tell the computer what code belongs together. You might notice that in the above example, the line underneath if went_to_store: is four spaces to the right. This is called indentation. By default, Ren'Py uses four spaces for each level of indentation. So, the line "You didn't buy anything, though." is indented one level to the right, because it is 4 spaces (one level) to the right of the line above it.

This indentation tells Ren'Py that the line "You didn't buy anything, though." belongs to the line before it, if went_to_store:. Anything that is indented underneath if went_to_store: will only be seen in the case that went_to_store is True.

This is important because it forms something known as a block, which is what we call a chunk of code indented under a line with a colon. So, for example, all of these lines are part of the same block:

if watched_tv:
    "You turned on the TV and browsed through some shows."
    "You found one that seemed interesting and watched the first episode."
    "Then you went to sleep."
    jump went_to_sleep

This is because they are all indented one level to the right underneath the if watched_tv: line.

If the player didn't watch TV, they won't see any of these lines, nor will they jump to the label went_to_sleep, because all those lines are indented under the if watched_tv: statement, and the player did not watch TV.

If we wanted both players who watched TV and those who didn't to eventually end up at the same went_to_sleep label, we could do something like:

if watched_tv:
    "You turned on the TV and browsed through some shows."
    "You found one that seemed interesting and watched the first episode."
    "Then you went to sleep."
jump went_to_sleep

In this case, the last line jump went_to_sleep is not part of the previous block, because it is no longer indented underneath it. So, a player who chose to watch TV will see all three lines of dialogue and then jump to the label went_to_sleep, but a player who doesn't watch TV will immediately jump to the label went_to_sleep, since jump went_to_sleep isn't part of the if watched_tv: condition block, and watched_tv is False, so the lines indented after if watched_tv: will be skipped.

You've actually already seen blocks before if you've been using menus. This is because menus look like:

"At the mall, you decided you wanted to buy Ashwin something."
menu:
    "Buy them a bath bomb.":
        $ gift = "bath bomb"
    "Buy them a self-help book.":
        $ gift = "self-help book"
    "Buy them a digital camera.":
        $ gift = "digital camera"

Everything is indented at least one level underneath the menu: line to indicate that the next lines are part of a particular choice menu. Then, each choice ends with a : and has its own block as well to indicate what should happen if the player chooses that choice. So, the things that should happen if the player makes a particular choice are indented one level further underneath the choice itself.

Term list:

  • indentation - empty space at the start of a line that helps indicate the relationship between lines of code. By default, one level of indentation in Ren'Py consists of 4 spaces.
  • block - what we call a chunk of code where the first line ends with a colon : and one or more lines underneath it are indented an extra level to the right.

else and elif

else

When making a decision, sometimes there are several options. For example, consider the following situation:

You're deciding what to wear today. If it's warm outside, you'll wear a t-shirt. Otherwise, you'll wear a sweater.

In this case, something happens regardless of whether the condition (it's warm outside) is true or not. If it's not warm outside, you still need to wear something. It doesn't matter if it's just cool outside or if it's freezing cold, just that it isn't warm enough to wear a t-shirt.

This is where we can use the else clause of the if statement which was explained earlier. else can be translated to "if nothing else in this statement was true, then do this". In practice, it looks like this:

if warm_outside:
    $ clothing = "t-shirt"
else:
    $ clothing = "sweater"
"You put on a [clothing] before leaving the house."

In this case, if the boolean variable warm_outside is True, then clothing will be set to "t-shirt", and the dialogue after the conditional statement will read "You put on a t-shirt before leaving the house.".

If it's not warm_outside (warm_outside is False), then clothing will be set to "sweater" and the dialogue will read "You put on a sweater before leaving the house.".

else doesn't take any more specific expressions, so there's no such thing as

# Incorrect 1
if warm_outside:
    $ clothing = "t-shirt"
else cold_outside: # Wrong! Will cause an error.
    $ clothing = "sweater"

else is just a catch-all for anything that didn't evaluate to True in the previous checks. Which leads into the next point, in that you can check for several different situations before you get to an else clause.

elif

Consider the following:

You're deciding what to eat for supper. If the local Thai restaurant is open, you want to buy food from there. If it's not, you'll try the pizza place next door. But if neither of those options work out, then you'll just make yourself a grilled cheese sandwich.

There are a few things that should happen here. First, we have to check if the Thai restaurant is open. Assuming the status of the Thai restaurant is stored in a True/False boolean like thai_restaurant_open = False, then we could start by making a statement like:

default thai_restaurant_open = False
default dinner = "grilled cheese"
label start:
    if thai_restaurant_open:
        $ dinner = "Thai food"
    "You ate some [dinner] for dinner."

If the Thai restaurant isn't open, though, we then need to check if the pizza place is open. Let's say that whether the pizza place is open or not is stored in the variable pizza_place_open = False.

Now, using the building blocks we know about so far, you might try something like this:

if thai_restaurant_open:
    $ dinner = "Thai food"
else:
    # We'll put something here?
"You ate some [dinner] for dinner."

This is on the right track! The else will happen whenever thai_restaurant_open is False. In fact, you can nest[1] conditional statements inside of each other like

default thai_restaurant_open = False
default pizza_place_open = False
default dinner = "grilled cheese"
label start:
    if thai_restaurant_open:
        $ dinner = "Thai food"
    else:
        if pizza_place_open:
            $ dinner = "pizza"
    "You ate some [dinner] for dinner."

Now if the Thai restaurant isn't open, we go to the else clause. There, we have another conditional, if pizza_place_open:. If that's True, then dinner is set to "pizza".

So in the current code, if thai_restaurant_open is True, then dinner will be set to "Thai food" and we'll skip the code that's indented under else since our initial condition, if thai_restaurant_open, is True. So, the player will see the dialogue "You ate some Thai food for dinner."

Otherwise, if thai_restaurant_open is False (the restaurant isn't open), then we'll go to the else line. There, we have a new check for if pizza_place_open:. If the pizza place is open, then dinner is set to "pizza" and the player will see the dialogue "You ate some pizza for dinner."

We're not done yet, though - currently if neither the Thai restaurant nor the pizza place are open, dinner doesn't get set anywhere, and we want to say that you ate grilled cheese if both restaurants are closed. The default statement ensures that dinner starts with a value of "grilled cheese", but it's good form to include it in this conditional for clarity (and also just in case there was some other part in the game where dinner was set to a value that's not "grilled cheese"). That can go in the else clause after the if pizza_place_open: condition:

# Solution 1
if thai_restaurant_open:
    $ dinner = "Thai food"
else:
    if pizza_place_open:
        $ dinner = "pizza"
    else:
        $ dinner = "grilled cheese"
"You ate some [dinner] for dinner."

There! Now we have a conditional statement which does what we'd outlined above - if the Thai restaurant is open, you eat Thai food. If it's not open, but the pizza place is open, then you eat pizza. If the Thai restaurant is closed and the pizza place is closed, then you eat grilled cheese.

Note also that if the Thai restaurant is open, it doesn't matter whether the pizza place is open or not. Since else translates to "do this only if nothing else before this check is True", when the Thai restaurant is open, Ren'Py doesn't even bother to look at the code under the else clause, since the first expression was True.

The else is also important to make sure this conditional flows properly. For example, consider the following:

# Incorrect 2
$ dinner = "grilled cheese"
if thai_restaurant_open:
    $ dinner = "Thai food"
if pizza_place_open:
    $ dinner = "pizza"
"You ate some [dinner] for dinner."

At first glance, this seems all right - if the Thai restaurant and the pizza place aren't open, dinner remains set to "grilled cheese". If the Thai place isn't open but the pizza place is, then dinner is set to "pizza".

However, it's important to notice that this example has two separate conditional statements. The first one is if thai_restaurant_open:, and the second is if pizza_place_open:. Since they are independent of one another, both will be checked regardless of the outcome of any previous checks.

The reason why this doesn't happen when the second if pizza_place_open: is nested inside the else clause of the if thai_restaurant_open in Solution 1 is because the else clause is part of the same conditional statement, the one which begins with if thai_restaurant_open. An else clause requires an if statement; it can't be used on its own because it's a "catch-all" for the remaining possibilities after the if statement. If the expression on the if statement before the else clause is True, as in, if thai_restaurant_open, then Ren'Py won't bother to check the code under the else clause because there was already an expression earlier that was True. In this way, we can make sure that if any earlier checks evaluated to True, then later checks are completely skipped.

For the above Incorrect 2 code with two separate conditionals, the problem happens when the Thai restaurant is open. In that case, dinner is set to "Thai food". However, since these are two separate conditional statements, the game will also check whether pizza_place_open is True. If it is, then it will overwrite the value of dinner to be "pizza". But if the Thai restaurant is open, we don't want to eat pizza! If we got Thai food, it shouldn't matter whether the pizza place is open or not, which is why you need to make it part of the same conditional via else OR elif, which is a short form for else if that we'll discuss below.

So our actual solution, which didn't have the problem earlier with the pizza place being open at the same time as the Thai restaurant, looks like this:

# Solution 1
if thai_restaurant_open:
    $ dinner = "Thai food"
else:
    if pizza_place_open:
        $ dinner = "pizza"
    else:
        $ dinner = "grilled cheese"

But of course, let's say we had more conditions - like "if the pizza place isn't open, then get ice cream from the ice cream stand. And if that's not open either, then try the sushi place." This could quickly turn into something long and ugly like:

# Temporary Solution 1
if thai_restaurant_open:
    $ dinner = "Thai food"
else:
    if pizza_place_open:
        $ dinner = "pizza"
    else:
        if ice_cream_stand_open:
            $ dinner = "ice cream"
        else:
            if sushi_place_open:
                $ dinner = "sushi"
            else:
                $ dinner = "grilled cheese"

Obviously having so many if/else conditions nested inside each other is a bit hard to follow. Luckily, there's a special clause to simplify this, known as elif. As mentioned before, it's short for else if, and will simplify the above conditional into:

# Solution 2
if thai_restaurant_open:
    $ dinner = "Thai food"
elif pizza_place_open:
    $ dinner = "pizza"
elif ice_cream_stand_open:
    $ dinner = "ice cream"
elif sushi_place_open:
    $ dinner = "sushi"
else:
    $ dinner = "grilled cheese"
"You ate some [dinner] for dinner."

Much cleaner! This also does not suffer from the problem earlier with the two separate if statements in the Incorrect 2 example, because the elif clauses are all part of the same conditional. An elif clause will only run if nothing before it evaluated to True, and like an else clause, it must come after an if statement and can't exist on its own.

The logic is as follows:

  1. If the Thai restaurant is open, set dinner to "Thai food". We found one condition in the entire conditional statement that's True already, so we skip all of the elifs and the else and show the line "You ate some Thai food for dinner."
  2. Otherwise, if the Thai restaurant isn't open, check if the pizza place is open. If it is, set dinner to "pizza" and skip all the rest of the elif/else clauses to show "You ate some pizza for dinner."
  3. Otherwise, if both the previous two places weren't open, check if the ice cream stand is open. If it is, set dinner to "ice cream", skip the rest of the elif/else clauses, and show "You ate some ice cream for dinner."
  4. Otherwise, if none of the previous three places were open, check if the sushi place is open. If it is, set dinner to "sushi" and skip the else, then show "You ate some sushi for dinner."
  5. Finally, if everything we previously checked was False (all the restaurants were closed), set dinner to "grilled cheese" and show the line "You ate some grilled cheese for dinner."

Similarly, the more succinct version of our original Solution 1 is:

# Improved Solution 1
if thai_restaurant_open:
    $ dinner = "Thai food"
elif pizza_place_open:
    $ dinner = "pizza"
else:
    $ dinner = "grilled cheese"

[1] nesting - as in, to nest code. This is what it's called when you put one programming construct, such as an if statement, inside of another, like another if statement or a menu. For example:

menu:
    "You went for a walk.":
        if owns_dog:
            "You took your dog with you on a leash."
        else:
            "You grabbed a jacket on your way out."
    "You watched some TV":
        "You ended up watching a cooking show."

In this example, the if statement is nested inside of the menu statement. Informally, you can see that this is the case because of the extra levels of indentation - the choice menu is already indented, and then the conditional/if statement is indented one further level inside of that.

Summary

All conditional statements will take one of the following forms:

if statement only, no other checks:

if <expression>:
    <result>

e.g.

"You decided to go to the park."
if owns_dog:
    "You took your dog with you on a leash."
"On such a nice day, the birds were singing brightly."

In this case, only a player who has a dog (owns_dog is True) will see the line "You took your dog with you on a leash." Players who don't will simply move on to the next line, "On such a nice day..."

if accompanied by one or more elif clauses

if <expression>:
    <result>
elif <expression>:
    <result>
# can add more elif clauses

e.g.

"You started to feel hungry."
if made_soup:
    "The soup you made earlier sounded tasty."
elif ordered_takeout:
    "You thought you might have some leftovers from yesterday's takeout."
"You walked over to your fridge to peek inside."

In this case, the choices are more-or-less flavour text; if the player didn't make soup or order takeout, then they'll still go to the fridge and look inside. There's no else clause here, so if neither of the expressions are True (they didn't make soup or order takeout), they just go to the fridge. This if/elif structure also prevents both lines of dialogue from playing one after the other; while it's possible the player both made_soup and ordered_takeout, we only want one of the flavour text variations to display, and it would sound unusual if the player saw both "The soup you made earlier sounded tasty" and "You thought you might have some leftovers from yesterday's takeout" back-to-back.

if accompanied by an else clause

if <expression>:
    <result>
else:
    <result>

e.g.

if got_food_poisoning:
    "You shook your head, unable to go anywhere while your insides felt like the center of a volcano."
    jump stay_at_home
else:
    "Fireworks sounded really fun! You nodded enthusiastically."
    jump go_to_fireworks

In this case, two very separate things should happen if the player did or didn't get food poisoning - either they have to stay at home, or they'll go out to watch some fireworks. The else clause takes care of anything that wasn't covered by the if statement, so in this case, in the case that the player didn't get food poisoning, they can go to the fireworks.

if accompanied by some elif clauses and an else

if <expression>:
    <result>
elif <expression>:
    <result>
# Can add more elif clauses
else:
    <result>

e.g.

"It was a good summer, all things considered."
if shared_ice_cream:
    "You" "Remember how I let you try some of my ice cream?"
elif went_boating:
    "You" "You almost fell overboard when we were out on the lake and saw a swan."
elif had_sleepover:
    "You" "I was so tired the day after our sleepover."
else:
    "You" "We sure made some good memories."
"Ash" "I wish summer didn't have to end."

Note that you can have as many elif clauses as you like - one, two, zero, seventy-four (though at that point you might want to consider restructuring how you're handling so many situations!), or however many you need. There's only ever one if, at the start, and one else, optionally, at the end.

In this example, the player might have done several activities over their summer vacation, and in the wrap-up, they can reminisce about one of the memories. They shouldn't be able to mention every memory that happened all in a row, just the most important one that the player completed. These events aren't mutually exclusive - all of them might have happened, or none of them - so an if/elif/else structure lets us organize which event is the most important to mention.

Now that you know how to use conditionals to direct the flow of the game, in the next part we'll look into what other kinds of things you can check besides just True/False boolean values. Before that, though, you can test your understanding of conditional statements with a quick quiz!

Quiz

Question 1

What will the last line display to the user?

default count = 0
default went_to_park = True
default owns_dog = True
default stayed_at_home = False
label start():

    if went_to_park:
        $ count += 1
        "You went to the park."
    if owns_dog:
        $ count += 1
        "You took your dog out for a walk."
    if stayed_at_home:
        $ count += 1
        "You stayed at home."
    "The value of count is [count]."
    return
  1. "The value of count is 1."
  2. "The value of count is 2."
  3. "The value of count is 3."
  4. "The value of count is 0."
  5. NameError on the line if went_to_park because went_to_park hasn't been seen before.
Click for answer

count will be equal to 2 by the end of the code, so the correct answer is 2. "The value of count is 2."

There is no NameError as in answer 5 because went_to_park, along with the other variables count, owns_dog, and stayed_at_home are set up with default before the game begins (if you need a refresher on why this is, see the Complete Guide to Ren'Py Variables).

The most important thing to recognize about this code is that it consists of three conditional statements. The first begins with if went_to_park, the second with if owns_dog, and the third with if stayed_at_home. Since they are independent of one another, Ren'Py will check all three of them regardless of the outcome of any previous conditional checks.

So, Ren'Py will first check if went_to_park:. This is True, so the line $ count += 1 is executed and the player sees the dialogue "You went to the park.". Next, if owns_dog: is checked. This is also True, so $ count += 1 is executed and the player sees the dialogue "You took your dog out for a walk.". Finally, if stayed_at_home is checked. This is False, so we don't execute the two lines in the block underneath it (the additional count line and "You stayed at home."). Since count started at 0 and two $ count += 1 lines were run, the final value of count is 2.

Question 2

What will the last line display to the user?

default count = 0
default went_to_park = True
default owns_dog = True
label start():

    if went_to_park:
        $ count += 1
        "You went to the park."
    elif owns_dog:
        $ count += 1
        "You took your dog out for a walk."
    else:
        $ count += 1
        "You stayed at home."
    "The value of count is [count]."
    return
  1. "The value of count is 1."
  2. "The value of count is 2."
  3. "The value of count is 3."
  4. "The value of count is 0."
  5. NameError on the line if went_to_park because went_to_park hasn't been seen before.
Click for answer

count will be equal to 1 by the end of the code, so the correct answer is 1. "The value of count is 1."

Like with Question 1, there is no NameError as in answer 5 because went_to_park, along with the other variables count, stayed_at_home, and owns_dog, are set up with default before the game begins (if you need a refresher on why this is, see the Complete Guide to Ren'Py Variables).

Even though both went_to_park and owns_dog are True, they are all part of the same conditional statement which begins with if went_to_park. Only one clause (or none, if there is no else block and none of the conditions are True) in a given conditional statement can be True; after that, the remaining clauses are skipped over and won't be executed (or even checked). So, since went_to_park is True, the player will see the line "You went to the park." and then the line "The value of count is 1.", and then the game will end. elif owns_dog doesn't get checked because an earlier clause, if went_to_park, was already True; same with else. Thus, the final value of count is 1.

Note that this is the preferred way of coding the situation introduced in Question 1, because the player should only see one of the three lines of dialogue.

Question 3

How many conditional statements are there in the following code?

default talked_to_xia = False
default shopping_with_ash = False
default bought_zoran_milkshake = False
label start():

    if talked_to_xia:
        "Xia looked over at you, clearly worried about how you were taking the news."
    if shopping_with_ash:
        "Ash was trying to catch your eye, and they smiled when you made eye contact."
    if bought_zoran_milkshake:
        "Zoran, beside you, offered his milkshake."
    else:
        "No one seemed to realize how this news was affecting you."
        "You felt very alone."
  1. One
  2. Two
  3. Three
  4. Four
Click for answer

The correct answer is Three. The first conditional statement begins with if talked_to_xia. There are no elif or else clauses in this statement, so it just consists of that first expression and then a line of dialogue.

The second conditional statement begins with if shopping_with_ash. It also doesn't have any elif or else clauses.

Finally, the third conditional statement is if bought_zoran_milkshake, which has an else clause, but the else is just a clause, not a separate conditional statement, so there are only three conditional statements total. If bought_zoran_milkshake is True, then the else won't be executed. Meanwhile, if talked_to_xia is True, that doesn't affect any of the checks for the statements in the next conditional, since it's a separate conditional statement.

If the goal of this code was to show only one of the characters reacting to the player based on past events, then if talked_to_xia should be part of the same conditional statement as if shopping_with_ash and if bought_zoran_milkshake, since otherwise the player might see the line "Xia looked over at you, clearly worried about how you were taking the news." followed by "No one seemed to realize how this news was affecting you.", which wouldn't make sense. This could happen if the player talked_to_xia, but didn't buy Zoran a milkshake (bought_zoran_milkshake = False), in which case the player would see the line of dialogue under Xia's conditional statement (and optionally also the line under if shopping_with_ash if they went shopping with Ashwin), but they would see the else clause of the conditional that begins with if bought_zoran_milkshake because they didn't buy him a milkshake.

The improved version, then, looks like:

# Question 3 Solution
default talked_to_xia = False
default shopping_with_ash = False
default bought_zoran_milkshake = False
label start():

    if talked_to_xia:
        "Xia looked over at you, clearly worried about how you were taking the news."
    elif shopping_with_ash:
        "Ash was trying to catch your eye, and they smiled when you made eye contact."
    elif bought_zoran_milkshake:
        "Zoran, beside you, offered his milkshake."
    else:
        "No one seemed to realize how this news was affecting you."
        "You felt very alone."

This consists of one conditional statement, the one which begins with if talked_to_xia and includes two elif clauses and an else clause.

Question 4

Consider the following situation:

If the player has mentioned they like roller coasters, they should point it out to their date. If they like scary things, they will point out the haunted house instead. However, if they're eating cotton candy at the time, they should point out a photo opportunity instead of mentioning either the roller coaster or haunted house (since they can't go on rides while eating).

The following code is intended to represent the above scenario:

label start():
    # Variables are set up here with their values below!
    if likes_roller_coasters:
        "You" "We should try the roller coaster!"
        jump ride_roller_coaster
    elif likes_scary_things:
        "You" "We should try the haunted house!"
        jump haunted_house
    elif eating_cotton_candy:
        "You" "Let's go over there and take a picture!"
        jump eating_candy
    return

What combination(s) of variables might cause an unintended result?

  1. likes_roller_coasters = True, likes_scary_things = True, eating_cotton_candy = True
  2. likes_roller_coasters = False, likes_scary_things = True, eating_cotton_candy = True
  3. likes_roller_coasters = True, likes_scary_things = False, eating_cotton_candy = True
  4. likes_roller_coasters = True, likes_scary_things = True, eating_cotton_candy = False
  5. likes_roller_coasters = False, likes_scary_things = False, eating_cotton_candy = True
  6. likes_roller_coasters = True, likes_scary_things = False, eating_cotton_candy = False
  7. likes_roller_coasters = False, likes_scary_things = True, eating_cotton_candy = False
  8. likes_roller_coasters = False, likes_scary_things = False, eating_cotton_candy = False
  9. None of the above
Click for answer

The correct answers are 1, 2, 3, and 8.

There are quite a few cases to consider here, so we'll go through them one-by-one. The simplest one to get out of the way is 8, where all the variables are False. We don't have an else clause in our conditional, so at the moment, the game just ends if none of the variables are True, which is probably not what you wanted! Perhaps you can force the player to choose one or the other out of roller coasters or haunted houses, and at least one of the variables should be True by the time they get to this statement, but otherwise it would be good to add an else which allows the player to do something else, like watch a side show, if they don't like roller coasters or scary things and aren't currently eating cotton candy.

As for cases 1, 2, and 3, they all have something in common - eating_cotton_candy is True alongside another one of the variables, either one or both of likes_roller_coasters or likes_scary_things. This in itself isn't a problem, but the order of elif eating_cotton_candy does cause a problem. Namely, if one of likes_roller_coasters or likes_scary_things is True, then the game won't even get to the elif eating_cotton_candy part! It will simply execute the code under either if likes_roller_coasters or elif likes_scary_things, depending on which is True, and we'll never even check elif eating_cotton_candy. If the player is eating cotton candy, they shouldn't be able to ride a roller coaster or enter a haunted house.

As for why the other combinations are "fine", in #4 the player isn't eating cotton candy, and since likes_roller_coasters is True they'll jump to the label ride_roller_coaster. It's fine that likes_scary_things is also True; only one expression can be True in a given conditional statement, so we won't even get to the point of checking elif likes_scary_things, however.

In #5 both likes_roller_coasters and likes_scary_things are False, so we'll actually get to the clause elif eating_cotton_candy, which is True, and the player will jump to eating_candy, which is as you'd expect since they can't go on rides anyway.

In #6 and #7, one or the other of likes_roller_coasters or likes_scary_things is True and eating_cotton_candy is False, so it's fine for them to ride the roller coaster or go to the haunted house.

None of the above isn't a valid answer because we've already seen that 1, 2, 3, and 8 would have unintended results!

So, how could we fix this code? Luckily, it's pretty simple - checking for eating_cotton_candy should be our priority, since if the player is eating cotton candy, they can't go on any rides whether they like them or not. So, we'll move that to the start of our conditional statement. We'll also add an else clause in the case that the player doesn't like haunted houses or roller coasters:

# Question 4 Solution
default likes_roller_coasters = False
default likes_scary_things = False
default eating_cotton_candy = False
label start():
    if eating_cotton_candy:
        "You" "Let's go over there and take a picture!"
        jump eating_candy
    elif likes_roller_coasters:
        "You" "We should try the roller coaster!"
        jump ride_roller_coaster
    elif likes_scary_things:
        "You" "We should try the haunted house!"
        jump haunted_house
    else:
        "You" "Can we go watch that side show?"
        jump watch_side_show
    return

Now if the player is eating cotton candy, they automatically go to take a picture instead of pointing out the roller coaster or haunted house. And, if the player isn't eating cotton candy and doesn't like roller coasters or scary things, they can go see a side show instead.

Conclusion

Thanks for reading! In the next part, we'll go over some different comparison types so you can learn to compare things other than booleans.

Conditionals and Comparisons in Ren'Py, Part 2

Further Reading

Conditional Statements in Python

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment