Design Patterns and Video Games

Discover Python and Patterns (5): Integers

In previous posts, I only used strings and booleans. In this one, I use a new data type called "int" (for integer) that allows the storage and computation of natural numbers (numbers without a decimal part). I use them to create the famous "guess the number" game!

This post is part of the Discover Python and Patterns series

Integers

You can create a variable with an integer value in the following way:

magicNumber = 3

Python understands that magicNumber is an int: there are only digits, and there is no dot. If we use quotes, then it becomes a string:

magicNumber = "3"

Variable types change the behavior of operators. For instance, if you run the following program:

magicNumber = 3
print(2*magicNumber)

You see the value "6", because magicNumber is an int, and the result of 2 times 3 is 6.

If you run this other program:

magicNumber = "3"
print(2*magicNumber)

You see the value "33", because magicNumber is a string, and the result of 2 times "3" is "33" (Python repeats two times the string).

You can do many different computations, and we'll see examples throughout this series.

Types and comparisons

If we want to implement the game "guess the number" with an integer variable, we can try the following program:

magicNumber = 3
while True:
    playerNumber = input("What is the magic number? ")
    if playerNumber == magicNumber:
        print("This is correct! You win!")
        break
    print("This is not the magic number. Try again!")

Unfortunately, it does not work when the player enters "3": the type of the value returned by the input() function is a string. Then, when we compare playerNumber to magicNumber (line 4), Python always evaluate it as False.

You can check it yourself in the Spyder console (bottom right of the interface). Types 3 == "3" and then press Enter:

In [1]: 3 == "3"
Out[1]: False

The result after Out[1]: is False.

Type casting

If we want to compare integer values, we need to convert (or cast) the string into an int. To cast a value in Python, use the name of the type as a function. You can try it in the Spyder console:

In [2]: 3 == int("3")
Out[2]: True

The expression int("3") converts the string "3" into an int. The expression 3 == int("3") becomes 3 == 3, which evaluates as True.

Knowing this, we can correct our first program in the following way:

magicNumber = 3
while True:
    word = input("What is the magic number? ")
    playerNumber = int(word)
    if playerNumber == magicNumber:
        print("This is correct! You win!")
        break
    print("This is not the magic number. Try again!")

Now, if the player types "3", the magic number is recognized, and (s)he wins.

Exceptions

The program works fines as long as the player types a string that represents an int. If this is not the case, the program stops and a long message appears in the console:

What is the magic number? three
Traceback (most recent call last):

  File "<ipython-input-4-e4b9d606fd0c>", line 1, in <module>
    runfile('C:/dev/magicNumber.py', wdir='C:/dev')

  File "C:\dev\AnacondaBook\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 827, in runfile
    execfile(filename, namespace)

  File "C:\dev\AnacondaBook\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 110, in execfile
    exec(compile(f.read(), filename, 'exec'), namespace)

  File "C:/dev/magicNumber.py", line 4, in <module>
    playerNumber = int(word)

ValueError: invalid literal for int() with base 10: 'three'

This long message appears because the expression int(word) raised an exception. Exceptions throwing is a usual mechanism in programming languages to manage errors.

You should read the long message from bottom to top. The first line that interests us is the last one:

ValueError: invalid literal for int() with base 10: 'three'

It is the name of the exception ValueError, followed by a message that describes the problem. Thanks to this message, we understand that an int casting failed.

The lines just before tell us where the exception was raised:

  File "C:/dev/magicNumber.py", line 4, in <module>
    playerNumber = int(word)

We first see that it happens in file "C:/dev/magicNumber.py", line 4. This line is repeated after, so we may not have to look for it.

The other lines are the "execution stack trace". Each part shows you who called the next lines. For instance, the following part describes the line that calls our program:

  File "C:\dev\AnacondaBook\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 110, in execfile
    exec(compile(f.read(), filename, 'exec'), namespace)

It is no more part of our program, so you should not pay attention to it.

Manage exceptions

You can "catch" exceptions using the try...except syntax:

    word = input("What is the magic number? ")
    try:
        playerNumber = int(word)
    except ValueError:
        print("Please type a number without decimals!")
        continue

If a ValueError exception is raised in the try block, then the block execution stops, and the program flow goes directly to the except block.

If the player types a value that can't be cast to int, we display the message "Please type..." and go back to the beginning of the loop (continue statement).

Guess the number

I propose a final implementation for this post. Remember that lines starting with a hash '#' are comments, and Python ignores them. I added them to ease the understanding of the program:

# Magic number initialization
magicNumber = 3

# Main game loop
while True:
    # Player input
    word = input("What is the magic number? ")

    # Quit if the player types "quit"
    if word == "quit":
        break

    # Int casting with exception handling
    try:
        playerNumber = int(word)
    except ValueError:
        print("Please type a number without decimals!")
        continue

    # Cases that stops the game
    if playerNumber == magicNumber:
        print("This is correct! You win!")
        break

    # Wrong number, continue 
    print("This is not the magic number. Try again!")

# End of the program

You can play the game with this program, but the magic number is always the same. In the next post, I'll show you how to change it randomly.