Writing conditions
A loop condition can be anything you could write after if: a comparison, or several of them joined with and, or and not. With and, the loop goes on only while both parts are true, so it ends as soon as either part is false.
In this little game, a hiker walks 4 km per round and uses 3 points of energy for it. The hike ends when the hiker has walked 12 km or runs out of energy, whichever comes first:
energy = int(input("Energy: "))
distance = 0
while distance < 12 and energy > 0:
distance += 4
energy -= 3
print(f"{distance} km walked, energy {energy}")
print("The hike is over")
10Energy: 10
4 km walked, energy 7
8 km walked, energy 4
12 km walked, energy 1
The hike is overWith 10 points of energy, the hiker gets to 12 km, and distance < 12 is what ends the loop. With 5 points, the energy runs out first: after two rounds it's -1, and the hike ends at 8 km.
Make sure the loop ends
Before you trust a loop, check that its condition really becomes false, whatever the input. In this game, every hit takes 3 points from a dragon's health, and the dragon falls when its health is gone:
health = int(input("Dragon's health: "))
hits = 0
while health != 0:
health -= 3
hits += 1
print(f"The dragon falls after {hits} hits")
9Dragon's health: 9
The dragon falls after 3 hitsWith 9 health points, the health goes 6, 3, 0, and then health != 0 is false. But with 10 it goes 7, 4, 1, -2, -5 and on: it steps over 0 and is never equal to it. The loop never ends, and the program seems to freeze without printing anything. The condition says "until the health is exactly 0", but what you mean is "while there is health left": while health > 0:. That one becomes false whether the health lands on 0 or drops below it, and with 10 health points the dragon falls after 4 hits. In the same way, when you count up, < or <= stops a loop that jumps past its limit, where != might not.
Debugging a loop
When a loop misbehaves, look at its condition first. A < that should have been <= loses the last round, and a != that the variable can step over, like the dragon's, never lets the loop go. Two habits help you see what's going on:
- Fix the input while you test. Typing an answer to
inputon every test run gets tedious fast. Turn theinputline into a comment for now, and give the variable a value of your own on the line below it; to have the program ask again, swap the two over. If a check fails with some input, make that input your fixed value: then every run shows the failing case, and you can watch it go wrong. - Print the values in every round. A debugging
printin the body shows what the variables are in each round. Remove it once the program works, since the extra lines would fail the checks.
This program counts how many squares (1 * 1, 2 * 2, 3 * 3 and so on) it takes to add up to a goal. Both habits are in use:
# goal = int(input("Goal: "))
goal = 30
total = 0
count = 0
while total < goal:
count += 1
total += count * count
print("debug:", count, total)
print(f"{count} squares add up to at least {goal}")
debug: 1 1
debug: 2 5
debug: 3 14
debug: 4 30
4 squares add up to at least 30The debugging lines show every round, and that the loop stops as soon as total reaches 30.