# Decisions & loops

> Make programs choose what to do with if, elif and else, and repeat work with while and for loops, break and continue.

Learn to Code roadmap · The building blocks · 17 min read · https://levelcode.org/roadmaps/learn-to-code/conditions-and-loops

So far your programs have run every line once, top to bottom. Real programs make decisions ("if the password is wrong, ask again") and repeat work ("for every item in the cart, add up the price"). These two ideas, **conditions** and **loops**, are called control flow, and with them you can write any computation there is. This lesson covers both, plus the patterns you'll use with them every day.

## if: running code only sometimes

An `if` statement runs a block of code only when a condition is true:

```python
temperature = int(input("Temperature in °C: "))

if temperature > 30:
    print("It's hot. Drink water.")
    print("Maybe stay inside.")

print("Have a nice day.")
```

Three details matter:

- The condition is any expression that's `True` or `False`, usually a comparison.
- The line ends with a colon `:`.
- The lines that belong to the `if` are **indented**, by four spaces. Indentation isn't decoration in Python: it's how Python knows which lines are inside the block. The unindented `print` runs either way.

Getting indentation wrong is the most common beginner error:

```text
IndentationError: expected an indented block after 'if' statement on line 3
```

Your editor indents automatically after a colon; let it.

## else and elif: choosing between options

`else` runs when the condition is false:

```python
age = int(input("Age: "))

if age >= 18:
    print("You can vote.")
else:
    print(f"You can vote in {18 - age} years.")
```

For more than two options, chain conditions with `elif` ("else if"). Python checks them in order and runs **only the first** block whose condition is true:

```python
score = int(input("Score (0-100): "))

if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
else:
    grade = "F"

print(f"Grade: {grade}")
```

A score of 95 is also `>= 80`, but it gets an A because the first true branch wins and the rest are skipped. Order your conditions from most specific to least.

Conditions can be combined:

```python
if age >= 18 and has_id:
    print("Welcome in.")

if day == "Saturday" or day == "Sunday":
    print("Weekend!")
```

## while: repeat as long as something is true

A `while` loop repeats its block for as long as its condition stays true. It checks the condition before every round:

```python
count = 3
while count > 0:
    print(count)
    count -= 1
print("Lift off!")
```

```text
3
2
1
Lift off!
```

Something inside the loop must eventually make the condition false. If you forget `count -= 1`, the condition stays true forever and the program never stops: an **infinite loop**. Press Ctrl+C in the terminal to stop it.

`while` is the right tool when you don't know in advance how many times to repeat, such as asking until the user gives a valid answer:

```python
answer = input("Continue? (yes/no) ").lower()
while answer != "yes" and answer != "no":
    answer = input("Please type yes or no: ").lower()
print(f"You chose {answer}.")
```

## for: repeat for each item

A `for` loop runs its block once for **each item** in a sequence. The loop variable takes each value in turn:

```python
for letter in "cat":
    print(letter)
```

```text
c
a
t
```

To repeat a fixed number of times, loop over `range`:

```python
for i in range(5):        # 0, 1, 2, 3, 4
    print(i)

for i in range(1, 6):     # 1 to 5 (the end is never included)
    print(i)

for i in range(0, 20, 5): # 0, 5, 10, 15 (a step of 5)
    print(i)
```

`range(5)` produces five numbers starting at 0, and the end value is always excluded. That's the same "up to but not including" rule as string slicing. It feels odd for a day, then becomes natural.

In the next lessons you'll loop over lists of things (orders, names, lines in a file), which is where `for` really shines.

## Common loop patterns

A handful of patterns cover most loops you'll write.

**Accumulate** a total:

```python
total = 0
for n in range(1, 101):
    total += n
print(total)    # 5050
```

**Count** things that match a condition:

```python
sentence = "the quick brown fox jumps over the lazy dog"
vowels = 0
for ch in sentence:
    if ch in "aeiou":
        vowels += 1
print(vowels)   # 11
```

**Find** something and stop early with `break`, which exits the loop immediately:

```python
for n in range(2, 100):
    if n % 7 == 0 and n % 5 == 0:
        print(f"First number divisible by 5 and 7: {n}")
        break
```

**Skip** some items with `continue`, which jumps straight to the next round:

```python
for n in range(1, 11):
    if n % 2 == 0:
        continue          # skip even numbers
    print(n)              # prints 1, 3, 5, 7, 9
```

A `while True` loop with `break` is a clean way to write "keep going until something happens", especially for menus and input:

```python
while True:
    command = input("> ").strip().lower()
    if command == "quit":
        break
    print(f"You typed: {command}")
print("Bye!")
```

## Loops inside loops

A loop can contain another loop. The inner loop runs completely for every round of the outer one:

```python
for row in range(1, 4):
    line = ""
    for col in range(1, 4):
        line += f"{row * col:4}"
    print(line)
```

```text
   1   2   3
   2   4   6
   3   6   9
```

Nested loops are natural for grids and tables. Watch out for how quickly the work grows: two nested loops over 1,000 items each run the inner block a million times.

## Tracing code by hand

When a loop doesn't do what you expect, **trace** it: go line by line on paper, writing down each variable's value after each step.

```python
total = 0
for n in range(1, 4):
    total += n * n
```

| Step | `n` | `total` after |
|---|---|---|
| start | – | 0 |
| round 1 | 1 | 1 |
| round 2 | 2 | 5 |
| round 3 | 3 | 14 |

It feels slow, and it's the single most effective way to understand code, yours or anyone else's. You'll learn faster ways to watch a running program in the debugging lesson, but they're the same idea.

## Practice

Write `guess.py`, a number-guessing game:

1. The program picks a secret whole number from 1 to 100. Use these two lines to get a random one:

   ```python
   import random
   secret = random.randint(1, 100)
   ```

2. The player has at most 7 guesses. After each guess, say "Too low", "Too high" or "Correct!".
3. If the player guesses correctly, say how many guesses it took and stop. If they run out, reveal the number.
4. Bonus: if the player types something that isn't a number, or a number outside 1 to 100, tell them and don't count it as a guess. (Hint: `"42".isdigit()` is `True`, `"abc".isdigit()` is `False`.)

**Solution**

```python
# guess.py
import random

secret = random.randint(1, 100)
max_guesses = 7
guesses = 0

print("I'm thinking of a number from 1 to 100.")

while guesses < max_guesses:
    text = input(f"Guess {guesses + 1} of {max_guesses}: ").strip()
    if not text.isdigit():
        print("Please type a whole number.")
        continue
    guess = int(text)
    if guess < 1 or guess > 100:
        print("The number is between 1 and 100.")
        continue

    guesses += 1
    if guess < secret:
        print("Too low.")
    elif guess > secret:
        print("Too high.")
    else:
        print(f"Correct! You got it in {guesses} guesses.")
        break
else:
    print(f"Out of guesses. The number was {secret}.")
```

Invalid input hits `continue` *before* `guesses += 1`, so it doesn't use up a turn. The `else` attached to the `while` is a Python feature you may not have seen: a loop's `else` block runs only if the loop ended without `break`, which here means the player ran out of guesses. Writing a flag variable such as `won = False` and checking it after the loop is an equally good solution.

Seven guesses is enough to always win with the best strategy: guess the middle of the remaining range each time, which halves the possibilities on every guess (100 → 50 → 25 → 13 → 7 → 4 → 2 → 1). That strategy is called binary search, and you'll meet it again.

## Key takeaways

- `if`, `elif` and `else` choose which block runs; only the first true branch runs, and indentation defines the blocks.
- `while` repeats as long as a condition is true; make sure something eventually makes it false.
- `for` runs once per item; `range(start, stop, step)` excludes the stop value.
- `break` leaves a loop, `continue` skips to the next round, and `while True` plus `break` handles "until" loops cleanly.
- Accumulate, count, find and skip are the core loop patterns; trace by hand when a loop surprises you.

## Quiz

1. score = 85. Which grade does this assign? if score >= 70: grade = "C" / elif score >= 80: grade = "B" / else: grade = "F"

   A. B
   B. C
   C. F
   D. Both B and C

   **Answer: B.** Python takes the first true branch. 85 >= 70 is true, so grade becomes C and the elif is never checked. Put the most specific condition first.

2. How many times does this print? for i in range(2, 8): print(i)

   A. 8
   B. 7
   C. 5
   D. 6

   **Answer: D.** range(2, 8) produces 2, 3, 4, 5, 6, 7: six numbers, because the stop value is excluded.

3. What's wrong with this loop? n = 10 / while n > 0: print(n)

   A. Nothing changes n inside the loop, so it runs forever
   B. while can't compare numbers
   C. It should use for instead of while
   D. print can't be used in a loop

   **Answer: A.** The condition is checked every round, but n stays 10, so it's always true. Something like n -= 1 inside the loop fixes it.

4. What does continue do inside a for loop?

   A. Exits the loop completely
   B. Restarts the loop from the first item
   C. Skips the rest of this round and moves on to the next item
   D. Pauses the program

   **Answer: C.** continue jumps to the next iteration. break is the one that exits the loop entirely.
