7 Loops and Iteration
In This Chapter
So far, our “programs” have been very short. The computer reads from top to bottom, makes a few decisions, and then the program ends. But games don’t usually end after one turn. They keep running, waiting for your next move, until you win or lose.
This continuous cycle is called a Main Loop or sometimes the Game Loop, and it is the heartbeat of all modern software. In this chapter, we will learn how to keep our programs alive. We will cover:
- The DRY Principle: Don’t Repeat Yourself.
- The
whileLoop: How to make code repeat itself automatically. - The Infinite Loop: How to avoid getting stuck in a loop forever.
- The
forLoop: - Defensive Programming: How to protect your application from unpredictable players.
- Modules: Borrowing code written by other people to generate randomness.
- The Project: Building a complete “Guess the Number” game.
7.1 The DRY Principle
Although a programmer has to tell the computer exactly what to do, that doesn’t mean we need to write the same code over and over. There is a rule called the DRY Principle. It stands for Don’t Repeat Yourself.
Let me show you the power of the DRY Principle. If you had a private program and the user needs to enter a password, you could write a script that gives them three chances using if statements:
password = "mysecret"
guess = input("Guess the password: ")
if guess != password:
guess = input("Wrong! Guess again: ")
if guess != password:
guess = input("Wrong! Last chance: ")
if guess != password:
print("Sorry, you are locked out!")This code is hard to read. We get lost in the repeted if statements and it clearly violates the DRY principle. We are repeating the exact same input() command over and over. What if we wanted to give the user 5 chances instead of 3? We would have to add two more if statements, and things would really get out of hand!
For programs that have a lot of repetition, programming has a powerful tool called a loop. A loop is a block of code that automatically repeats itself until a certain condition is met. Loops are the foundation of all games and interactive software.
7.2 The while Loop
To make code repeat, we use a while loop.
You can think of a while loop as an if statement that automatically repeats itself. When the computer reaches an if statement, it checks if the condition is True, runs the code block once, and moves on. When the computer reaches a while loop, it checks if the condition is True, runs the code block, and then jumps back up to the top to check the condition again.
player_health = 3
# While the player_health is greater than 0,
# keep running this code over and over again!
while player_health > 0:
print(f"You are still alive! Health: {player_health}")
player_health -= 1
# This code will not run until the while loop is finished!
print("GAME OVER")If you run this code, it will print the “alive” message three times. Every time it hits the bottom of the indented block, it jumps back to the while statement to ask: “Is player_health still greater than 0?” Once the health reaches 0, the condition becomes False, and the while loop finally stops. Only then will the computer move on to print “GAME OVER”.
7.3 The Infinite Loop
When you build loops, you have an incredible amount of power. But with great power comes great responsibility. What happens if you forget to subtract 1 from the player’s health in the code above?
The condition player_health > 0 will always be True. The computer will loop forever. This is called an Infinite Loop.
Let’s look at an infinite loop. What if we set the while condition to True? Then the computer will never stop looping, because True is always True.
while True:
print("AHHHHHHHHH!")Now if you actually run a program like this, the computer will instantly start printing text so fast your screen might freeze.
How to Escape: If you are ever trapped in an infinite loop or your program won’t turn off, there is still a way to stop it. Click on your IDLE Interactive Shell window and press the Keyboard Interrupt.
- On Windows: Hold down the
Ctrlkey and pressC. - On Mac: Hold down the
Commandkey and press.(period).
This will stop the program immediately. The Keyboard Interrupt is the emergency off switch for programmers. It forcefully kills the program and stops the loop.
The break Keyword
Sometimes, you want to use while True: to keep a game running indefinitely, but you want a specific way out. You can smash out of a loop from the inside using the break keyword.
while True:
command = input("Type 'quit' to exit the game: ")
if command == "quit":
break
print("You have escaped the loop!")When Python reads the word break, it instantly destroys the loop and moves on to the rest of the script.
The continue Keyword
What if you don’t want to destroy the whole loop, but you just want to skip the current turn and jump straight back to the top? You use the continue keyword.
# A countdown timer that skips the number 3
timer = 5
while timer > 0:
timer -= 1
if timer == 3:
continue # Skip printing and jump back to the top!
print(timer)When the computer gets to the continue block, it skips the rest of the loop block it is in and goes back to the top of the loop. What do you think would happen if the timer -= 1 happened after the continue instruction?
7.4 The for Loop
In programming we often need to loop through the items in a list, and while this can be done using while loops Python has a better tool: the for loop. The for loop is a specialized tool designed specifically to travel through a list. It automatically visits every single item, one by one, starting at index 0 and stopping perfectly at the end. Traveling through data like this is called Iteration.
Lets look at a simple example. We have a backpack with three items, and we want to print them all out one at a time for some reason.
backpack = ["sword", "gold", "rope"]
print("-- STUFF IN MY BACKPACK --")
for item in backpack:
print(" * " + item)
print("--------------------------")How it works:
- Python looks at the
backpacklist. - It grabs the first thing (
"sword") and temporarily names ititem. - It runs the indented code:
print(" * " + item)which prints* sword. - It loops back to the top, grabs the next thing (
"gold"), names ititem, and runs the code again. - It does this for every element until the list is empty.
Lets see what the output looks like when we run this script:
-- STUFF IN MY BACKPACK --
* sword
* gold
* rope
--------------------------How did I know to use the term item? item is not a special Python keyword; it is just a temporary variable name. We could have called it banana or x. The computer doesn’t care. The important part is that it is a temporary variable that holds the current item in the list while the loop runs.
We can do more powerful stuff with for loops. Like what if we wanted to print the index of each item as well? We can use Python’s built-in range() function to generate a list of numbers that we can loop through.
backpack = ["sword", "gold", "rope"]
for i in range(len(backpack)):
print(str(i) + ": " + backpack[i])This would output:
0: sword
1: gold
2: ropeHow does range() work? Range is a function that generates a list of numbers. In this case, we are asking it to generate a list of numbers from 0 up to (but not including) the length of the backpack. The length of the backpack is 3, so range(3) generates [0, 1, 2].
Then our for loop is actually looping through this new list of numbers. So i = 0 for the first loop, then i = 1, and finally i = 2. We can then use i to access the items in the backpack by their index.
In programming, we often use i as a variable name for the loop index. You could use any other name, but i is a common convention so we know its supposed to be an index.
7.5 Defensive Programming: Trapping the Input
When you make software, you know exactly how it is supposed to be used. But users are chaotic.
If you ask the user to type a number so you can cast it into an integer (int(guess)), what happens if they type the word "five" instead of the number "5"? The computer crashes with a ValueError.
Defensive Programming is the practice of protecting your code from unpredictable users. We can do this by using a while True loop to trap the user until they type exactly what we need!
We can use a new string method called .isdigit(). This method checks a string and returns True only if every single character is a number.
# The Input Trap!
while True:
guess_text = input("Pick a number between 1 and 10: ")
# Check if they actually typed numbers
if guess_text.isdigit() == True:
# It is safe! Cast it to an integer and break the trap.
clean_number = int(guess_text)
break
else:
print("ERROR: Please type a number, not a word!")
print(f"You safely selected {clean_number}.")Now your program is bulletproof! If they type "apple", it prints the error and the while loop forces them to try again.
7.6 Random and Modules
For our project, we will need the computer to pick a random number. But calculating true randomness is incredibly difficult mathematically.
Thankfully, Python comes with a massive library of pre-written tools. However, to save memory, Python keeps these tools packed away in boxes. If you want to use them, you have to explicitly tell Python to unpack them. These boxes of tools are called Modules.
To unpack a module, we use the import keyword at the very top of our script.
import random
# Now we can use the tools inside the 'random' module!
dice_roll = random.randint(1, 6)
print(f"You rolled a {dice_roll}")The random.randint() function is a tool we borrowed from the random module. In this example we used it to generate a random integer between 1 and 6.
We will learn more about using modules in later chapters, but for now lets take our new random and loop powers to make a game.
7.7 The Project: Guess the Number
We now have all the pieces to build a complete game. We will use the random module to pick a secret number, a while loop to keep the game going, and if/elif/else statements to give the player hints.
Open a new file, type this out, and save it as guesser.py.
import random
print("Welcome to GUESS THE NUMBER!")
print("I am thinking of a number between 1 and 20.")
# 1. Setup the Game State
secret_number = random.randint(1, 20)
game_is_running = True
# 2. Start the Game Loop
while game_is_running == True:
# Get the player's guess and cast it to an integer
guess_text = input("\nTake a guess: ")
guess = int(guess_text)
# 3. Check the guess using conditional logic
if guess < secret_number:
print("Too low! Try again.")
elif guess > secret_number:
print("Too high! Try again.")
else:
# If it isn't too low or too high, it must be the exact number!
print("CONGRATULATIONS! You guessed my secret number!")
game_is_running = False # This breaks the loop!
print("Thanks for playing!")Run the program and try to beat the computer! Notice how the while loop cleanly replaces the need to write dozens of repetitive if statements. The code is DRY, efficient, and fun!
Challenges
Ready to level up? Try to add these features to your “Guess the Number” game.
Challenge 1: The Guesses Counter
Right now, the player can guess as many times as they want.
- Create a variable called
guess_count = 0at the top of your script. - Every time the
whileloop runs, add1toguess_count. - When the player finally wins, modify the congratulations message to tell them exactly how many tries it took! (Hint: Don’t forget you have to cast
guess_countto astr()to print it in a sentence!)
Challenge 2: The Turn Limit
Can you make the game harder? Modify your while loop so that the player only gets 6 guesses.
- Hint: There are two ways to do this. You can change the
whileloop condition to check both if the game is runningandif theguess_countis less than 6. Alternatively, you can use anifstatement inside the loop and use thebreakkeyword if they run out of turns!