Numerical Comparisons and Combinations in Ren’Py

Numerical Comparisons and Combinations in Ren’Py

Now that you know how to write conditional statements using if/elif/else (Conditional Statements in Ren’Py), how to check if strings or integers are the same (Equality Comparisons in Ren’Py), and the concept of truthy/falsey for non-boolean values (Truthy vs Falsey), you’re ready to learn about numerical comparisons and how to check more than one expression at once.

There is also another quiz to test your knowledge of comparisons, with additional questions combining the information in this tutorial and the earlier parts on conditionals to check your understanding of these concepts.

Difficulty Level: Beginner

As with the last tutorial, it’s recommended that you first look over Simple Variable Types in Ren’Py. 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.

Numerical Comparison

If you’re dealing with numbers like integers or floats, sometimes you might want to check whether a number is in a particular range, or if it’s over or under a threshold. From the example list in Equality Comparisons in Ren’Py, this includes things like:

  • If the player has at least 8 affection points with Xia, she’ll ask them on a date
  • If the player has 10 or more bad end points, they get the bad end. If they have less than 10 bad end points but more than 0, they get the normal end. Otherwise, they get the good end.
  • If the player has enough money, they can buy a flower.

You may already be familiar with symbols like <, >, ≤, ≥. They’re used in math like y > 5 (y is greater than 5) or x ≤ 2 (x is less than or equal to 2), or even 130 ≤ height ≤ 170 (height is between 130 and 170, inclusive of the end points).

Ren’Py uses < for “less than” and > for “greater than”, as you’d expect from above. However, in coding,  becomes <= (less than or equal to) and  becomes >= (greater than or equal to). Note that the position of the = is important; =< and => are incorrect and will cause an error. You can think of the order as following how you’d say it – “greater than” (<) “or equal to” (=) aka <=. There’s no need for double == here, since it’s accompanied by a > or < symbol. You might also remember the “not equal” comparison != did something similar – all three additional symbols (!<>) come before the = (i.e. !=<=>=).

With this knowledge, you can compare numbers:

default zoran_love_points = 0
label start():
    "Zoran shuffles awkwardly, looking down at his feet."
    menu:
        "Make a joke.":
            $ zoran_love_points += 1
            "He smiles when you finish telling the joke."
        "Tell him to get over himself.":
            $ zoran_love_points -= 1
            "He looks almost angry at you."
            "Then he sighs deeply."
    if zoran_love_points >= 1:
        "Zoran" "Yeah, maybe I needed that. Thanks."

For this statement, the game checks if the player has 1 or more love points with Zoran through their past choices (if zoran_love_points >= 1). If they do, then Zoran trusts their opinion enough to not get upset even if the player told him to get over himself.

It’s also fine to use these comparisons for floats, because they’re not checking for exact values but ranges e.g.

# This is 3.0 (float) instead of just 3 (an integer)
# so we can get a float result when we do
# correct_answers/total_answers.
# Ren'Py 8.0+ will do this automatically, but
# Ren'Py 7.x will round the answer down otherwise
define total_answers = 3.0
default correct_answers = 0
default grade = 0.0
label start:
    menu:
        "What year was Ren'Py first released?"
        "2022":
            # Wrong! Ren'Py was first released in 2004
            pass
        "2004":
            $ correct_answers += 1
    menu:
        "Why is it bad to use == to compare floats?"
        "Decimals can have rounding errors.":
            $ correct_answers += 1
        "You shouldn't compare any numbers with ==":
            # Wrong! It's fine to compare integers with ==
            # but don't use it for floats!
            pass
    menu:
        "Can you put an else clause before an elif?"
        "Yes":
            # Wrong! The `if` is required, the `elif` clauses are
            # optional, and the `else` clause, if included, must go at
            # the end as a "catch-all" for the remaining possibilities.
            pass
        "No":
            $ correct_answers += 1

    # Divide the # of correct answers by the # of total
    # answers to get a number like 0.6666667 for 2/3
    $ grade = correct_answers / total_answers
    if grade >= 0.7:
        "Amazing!"
    elif grade > 0.5:
        "Not bad!"
    elif grade > 0.3:
        "Hmm, maybe try again."
    else:
        "Study up some more next time!"

Here you can see that we have comparisons like if grade >= 0.7 (if grade is greater than or equal to 0.7) and elif grade > 0.3 (if grade is strictly greater than 0.3).

Note that this illustrates a very useful feature of if/elif/else-style conditional statements, which is that only one expression in an if/elif/else can be True, and the rest will be skipped. You’ve seen this before in some previous examples, but let’s really take a look at this and see how it works now that we’re dealing with number ranges.

More specifically, what this means is that the above conditional statement is the same as:

if grade >= 0.7:
    "Amazing!"
elif 0.7 >= grade > 0.5:
    "Not bad!"
elif 0.5 > grade > 0.3:
    "Hmm, maybe try again."
else:
    "Study up some more next time!"

Let’s look at it more closely.

So, first, we check if grade >= 0.7. If grade is equal to something like 0.9, then 0.9 >= 0.7 is True so the player will see the line “Amazing!” and the game will continue with whatever content is after the conditional statement.

However, if grade is equal to 0.6, then 0.6 >= 0.7 is False, because 0.6 is not greater than or equal to 0.7. In this case, we’ll skip the block underneath if grade >= 0.7 and move on to elif grade > 0.5.

Now we look at this line and compare it – is 0.6 > 0.5? Yes! 0.6 is greater than 0.5. So this statement is True and the player sees the line “Not bad!”.

This is the same as elif 0.7 >= grade > 0.5 seen above, because we already know that if we’re checking elif grade > 0.5 then the first if statement, grade >= 0.7, wasn’t True. If it had been True, then the player would have seen “Amazing!” and the game wouldn’t have bothered to check elif grade > 0.5. So, since it wasn’t, then the number must be less than 0.7.

You can also use this to do something like calculate which ending the player should get based on their accumulated good and bad end points:

if bad_end_points > 10:
    # The player made more than 10 bad choices
    jump super_bad_end
elif good_end_points > 10:
    # The player made more than 10 good choices
    jump excellent_end
elif bad_end_points > 5:
    # The player made 6-10 bad choices
    jump bad_end
elif good_end_points > 5:
    # The player made 6-10 good choices
    jump good_end
else:
    # The player didn't get more than 5 good or bad points
    jump normal_end

elif bad_end_points > 5 comes after the line if bad_end_points > 10, so we know that if the game got to the clause elif bad_end_points > 5, then bad_end_points is at most 10, because if it was more, then the first expression would have been True and the game wouldn’t be checking this next one. Since elif bad_end_points > 5 is looking for strictly greater than 5, and we know that it can’t be more than 10, then this statement will only be True if bad_end_points is between 6 and 10, inclusive.

Similarly, the only way the game will get to the else clause is if the player had 5 or fewer good or bad end points (so, 0-5), since if they had more than 10 one of the first two expressions would have been True, and if they had more than 5 the third or fourth expressions would have been True. Since we got to the else clause, that means that none of the previous expressions were True, so the player has between 0-5 good end points and 0-5 bad end points.

Note on Strings

Besides just numbers, you can actually use <=> etc with strings! In the case of strings, it compares them alphabetically, with a few notable caveats. This is, however, used very infrequently. You can read more on this in String Comparisons in Ren’Py.

This kind of comparison is very uncommon for most games, and it won’t be included in the quiz on numerical comparisons after this tutorial.

Combining more than one comparison

Now that you can directly compare values with == and !=, and compare numbers with <><= and >=, let’s look at combining comparisons. Remember earlier we had some statements like:

  1. If the player is carrying a life jacket or they made it to the top of the ship in time to get in a life boat, they survive.
  2. If the player gave Zoran the book Pride & Prejudice and has at least 5 trust points with Zoran, Zoran will share a story from his childhood.

Note the language used to describe these comparisons – “or” and “and” are actually Python concepts you can use directly! We’ll start with using them for booleans (True/False), since that’s the simplest to understand, and in the next part you’ll see how to combine them with all the previous things you’ve learned to create complex conditional statements.

and

Consider the following statement:

If the player went to the park and they own a dog, then we know that they took their dog to the park. The dialogue should reflect this.

So, say you have two booleans, went_to_park = True and owns_dog = True.

If you want to check that both of them are True, you can do:

if went_to_park and owns_dog:
    "Your dog was sleeping in the corner of the room, tired after your walk in the park earlier that day."

If either or both of went_to_park or owns_dog is False, then this statement won’t play. Let’s construct a more elaborate example, with some elif and else clauses to see what happens:

if went_to_park and owns_dog:
    "Your dog was sleeping in the corner of the room, tired after your walk in the park earlier that day."
elif went_to_park:
    "You sat down on the couch, tired after your walk in the park earlier that day."
elif owns_dog:
    "Your dog seemed restless after being inside all day while you went to the movies."
else:
    "You sat down on the couch, still thinking about the movie you'd seen earlier."

So, let’s break it down.

  • Case 1 – the player has gone to the park and owns a dog
    • Both went_to_park and owns_dog are True, so the condition if went_to_park and owns_dog is also True.
    • This means that the player sees the line “Your dog was sleeping in the corner of the room, tired after your walk in the park earlier that day.”
  • Case 2 – the player has gone to the park, but doesn’t own a dog
    • went_to_park is True, but owns_dog is False. This means that if went_to_park and owns_dog is False, because the player doesn’t own a dog.
    • The next expression, elif went_to_park, is True, because the player did go to the park. So they see the line “You sat down on the couch, tired after your walk in the park earlier that day.”
  • Case 3 – the player owns a dog, but didn’t go to the park
    • owns_dog is True, but went_to_park is False, so if went_to_park and owns_dog is False because the player didn’t go to the park
    • Next, elif went_to_park is False, because the player didn’t go to the park.
    • Next, elif owns_dog is True – the player does own a dog. So they see the line “Your dog seemed restless after being inside all day while you went to the movies.”
  • Case 4 – the player didn’t go to the park, and they don’t own a dog
    • went_to_park is False and owns_dog is False, so if went_to_park and owns_dog is False, because the player neither went to the park nor owns a dog
    • elif went_to_park is False, because the player didn’t go to the park
    • elif owns_dog is False, because the player doesn’t own a dog
    • else then must execute, since everything before it was False. So the player sees the line “You sat down on the couch, still thinking about the movie you’d seen earlier.”

Basically, for andboth operands on either side of the and  operator  need to be True in order for the whole statement to be True. It’s not enough for the player to have just gone to the park, or just to own a dog – they must both own a dog and have gone to the park for the first if went_to_park and owns_dog expression to evaluate to True.

operator – special symbols or words that indicate some kind of computation should take place. You’ve seen operators in math before; they include things like +-, and /. Those math operators exist in programming languages, as well as a few other ones such as and, as you’ve seen here, and or, as you’ll see in the next section. Equality comparisons like == and != that you saw in Equality Comparisons in Ren’Py are also called operators.

operand – what we call the values the operator acts on. For example, in the expression 2 + 42 and 4 are the operands, which are acted on by the operator +. The operator, in this case, adds the two operands together and the result is the number 6 (2 + 4 = 6).

or

or is similar to and, but less strict – only one of the operands on either side of the or operator has to be True (or both). Consider the following:

If the player helped Ashwin with their groceries or mowed their lawn, then they’ll mention how the player helped them out and agree to return the favour.

if helped_ash_groceries or mowed_ash_lawn:
    "Ash" "I guess you did help me out earlier today..."
    "Ash" "So I can spare some time to help you, too."
    jump moving_day_ash
else:
    "Ash" "No, sorry, I'm just too busy."
    "Ash" "Maybe you can ask Xia or Zoran."
    jump no_help

Let’s look at what happens for the different combinations of helped_ash_groceries and mowed_ash_lawn:

  • Case 1 – the player both mowed Ashwin’s lawn and also helped them with groceries
    • mowed_ash_lawn is True and helped_ash_groceries is True. We only needed one or the other to be True, but it’s fine that they’re both True – Ashwin will agree to help and the player will jump to moving_day_ash
  • Case 2 – the player mowed Ashwin’s lawn but didn’t help them with groceries
    • mowed_ash_lawn is True, but helped_ash_groceries is False. However, we only need one of the two to be True, since we’re using or. So, Ashwin will agree to help the player and they’ll jump to the moving_day_ash label
  • Case 3 – the player didn’t mow Ashwin’s lawn, but they did help them with groceries
    • mowed_ash_lawn is False, but helped_ash_groceries is True. Again, we just need one of the two to be True, so Ashwin will agree to help and the player will jump to moving_day_ash
  • Case 4 – the player did not mow Ashwin’s lawn and didn’t help them with their groceries
    • mowed_ash_lawn is False and helped_ash_groceries is False. Neither of the two operands is True, so the whole thing is False. Ashwin says they are too busy and the player goes to the no_help label

and and or in Practice

Note that you can use as many and and or operators in a conditional statement as you like to connect many operands. The outcome of evaluating such an expression will depend on which of and or or you’re using, as well as the value (True/False) of each operand.

and:

if True and True:
    # True

if True and False:
    # False

if False and True:
    # False

if False and False:
    # False

if True and True and True and True:
    # True only if *all* operands are True

if True and False and False and False:
    # False; all operands must be True

or:

if True or True:
    # True

if True or False:
    # True

if False or True:
    # True

if False or False:
    # False

if True or True or True or True:
    # True

if True or False or False or False:
    # True; at least one True makes the whole condition True

Summary

In this tutorial, you learned about the operators <, >, <=, >= for numerical comparison, and about the operators and and or for combining multiple expressions into a single conditional statement. and requires that all its operands evaluate to True, while or only needs one of its operands to be True in order for the whole expression to evaluate to True.

Next Steps

As per usual, there is a quiz on numerical comparisons and combinations that you can use to test your knowledge: Numerical Comparisons and Combinations Quiz. If you’d like some extra information on using operators like > and < for strings, check out String Comparisons in Ren’Py, which comes with a very short quiz on the topic. When you’re ready to move on, check out Combining Comparisons in Ren’Py.

This Post Has One Comment

  1. Manu

    Hey, I just found this website and it’s super useful! It makes me want to mess around and have fun with Renpy. Thank you for explaining stuff so clearly.

Leave a Reply