Learning LibraryCore Coding LibraryTeens

For Loops in Python: build a wave from one rule

Every arcade wave you've ever dodged — a row of invaders sliding into view — is a for loop. Spawn one enemy, then let the loop place the rest.

The big idea

A for loop runs the same block once for each value in a sequence, handing your code that value through a loop variable.

See it in code

1The basics

At its core, a for loop runs its body once for each value in a sequence. range(4) yields 0, 1, 2, 3 — four values, starting at zero:

python
for i in range(4):
    print(i)
Run it — the loop hands you each value in turn:
0
1
2
3

Four values in, four lines out. The loop variable i holds each one as it goes — that's the hook everything else hangs on.

2A step further

The real power is computing with the loop variable. Here we turn each index into an evenly spaced x-position — the exact formula we're about to place a wave with:

python
for column in range(6):
    x = 55 + column * 74
    print("column", column, "-> x", x)
Run it — six indexes become six positions:
column 0 -> x 55
column 1 -> x 129
column 2 -> x 203
column 3 -> x 277
column 4 -> x 351
column 5 -> x 425

55 + column * 74 maps 0…5 to 55, 129, 203 … — six positions, evenly spaced, from one line of math.

3In our world

Now feed those positions to real game objects. In the game package each Enemy(x, y) draws itself — so one loop builds the whole fleet with that same formula, and a second loop draws it:

python
from game import Stage, Enemy

screen = Stage.create()
Stage.clear(screen)

wave = []
for column in range(6):
    x = 55 + column * 74
    wave.append(Enemy(x, 90))

for enemy in wave:
    enemy.draw(screen)
Run it and a six-wide wave lines up across the top:
A row of six purple enemy sprites evenly spaced near the top of a dark play area.

Two loops, two jobs: the first builds the fleet with range(); the second draws it by iterating over the list. Bump range(6) to range(10) and the same formula spaces ten enemies just as evenly.

How for i in range(6) drives the loop A flow chart for a for loop. Start sets i to 0, then runs the loop body, then moves i to the next value, then checks whether more values remain in range(6). If yes, it loops back to the body with i = 1, 2, 3 and so on; if no, the loop ends. Below, the loop variable i takes each value 0 through 5. yes — i = 1, 2, 3 … no i = 0 run the loop body i moves to next value more in range(6)? loop ends i takes each value: 0 1 2 3 4 5
The loop variable steps through every value in the range, running the body once per value, then exits.
The same idea, everywhere

Nothing here is really about enemies. Swap Enemy for anything and the loop is identical — iterate a list of sprites each frame, walk the rows of a dataset, or step through the codons of a DNA strand. range() gives you the count; the body does the work. It's the same skill in the art, game, biotech, and quant courses alike.

Try it yourself

Change range(6) to range(10) and shrink the spacing (* 74* 44) so ten fit. Then add a second row: wrap the build in another loop over range(2) and offset y by the row number — that's your first nested loop. Reach for this pattern in any loop activity.

The common mistake

The precise gotcha is an off-by-one from misreading range. range(6) produces 0, 1, 2, 3, 4, 5 — six values, and 6 is not included. Reach for range(1, 6) expecting six enemies and you'll get five. When you want positions 0 to n − 1, range(n) is exactly right.

What it unlocks

Looping is the backbone of everything that repeats: iterate a list of entities every frame, nest loops to build grids, and reach for range() whenever you need precise counts. When you don't need the index, loop directly over the collection like the draw loop above.

Want the simpler version? Read the Kids version →