RoboticsBuild a Robot Brain · Week 1 · Lesson 1

Where am I? Coordinates and moving on a grid

Before a robot can go anywhere, it needs a way to say where it is. Two numbers do the job. Moving becomes adding, walls become a check, and "how far?" becomes a tiny formula.

Time2–3 h
You'll needLesson 0 done, squared paper, a pencil
New wordsCoordinates, tuple, dictionary, path, Manhattan distance
Project pieceThe robot can move

Start here

Give every square a pair of numbers (x, y), and moving one step is just adding a small change to them.

The problem

You tell Robo-Helper: "the red block is near the top, a bit to the right of you." The robot has no idea what that means. "Near" how near? "Top" of what? It needs an exact address for every square, and exact rules for what "go east" does to that address. It also needs to not drive through walls.

The idea in one picture

Think of a game of Battleships, or seats in a cinema: "row F, seat 12". One number says how far across, one says which row. Once every square has an address, "move one seat right" just means "seat number + 1". The robot's room works the same way.

Words to know

Coordinates
A pair of numbers (x, y) that gives the address of a square. x = across, y = down.
Tuple
Python's way of keeping a few values together, like (2, 3). You can't change it, only make a new one.
Dictionary
A lookup table. DIRECTIONS["E"] looks up "E" and gives back (1, 0).
Path
The list of every square the robot stood on, in order.
Manhattan distance
How many steps apart two squares are if you can only move along the grid, never diagonally.

Going deeper: everything below is the full lesson. Keep squared paper next to you: you'll draw on it.

1. The problem

Here is the room again. The robot R is in the top-left area, the red block r is right next to it, and the bin B is bottom right.

##########
#Rr......#
#..##....#
#..#..b..#
#....##..#
#g.......#
#.#....B.#
##########

To drive to the bin, the robot needs answers to four questions:

  1. Where am I, exactly?
  2. If I take one step east, where will I be?
  3. Is that square a wall? If so, don't go.
  4. How far am I from the thing I want?

Each question becomes one function in today's homework.

2. First principles

Step 1: give every square an address

Number the columns from the left, starting at 0. That's x. Number the rows from the top, starting at 0. That's y. Now every square has an address (x, y):

      x: 0 1 2 3 4 5 6 7 8 9
  y = 0  # # # # # # # # # #
  y = 1  # R r . . . . . . #
  y = 2  # . . # # . . . . #
  y = 3  # . . # . . b . . #
  y = 4  # . . . . # # . . #
  y = 5  # g . . . . . . . #
  y = 6  # . # . . . . B . #
  y = 7  # # # # # # # # # #

Read it like this: go across x, then down y. The robot is at (1, 1). The red block is at (2, 1). The bin is at (7, 6).

Wait, y goes down? In maths class y usually goes up. On screens and in text files, rows are counted from the top, so y grows downwards. It's just a choice, but you must stick to it. Getting it backwards is the most common bug in this lesson.

Predict first: what are the coordinates of the blue block b? And what's at (5, 4)?

The blue block is in column 6, row 3, so (6, 3). At (5, 4), go across 5 and down 4: it's a wall #, part of the little wall in the middle.

Step 2: a direction is a small change

What does "go east" do to the address? East means one column to the right: x goes up by 1, y stays the same. So "east" is the change (+1, 0). Do the same for all four:

DirectionChange (dx, dy)Why
N (north, up)(0, −1)up a row, and y grows downwards, so y gets smaller
S (south, down)(0, +1)down a row
E (east, right)(+1, 0)one column right
W (west, left)(−1, 0)one column left

The homework file already has this table, as a Python dictionary called DIRECTIONS. ("dx" just means "change in x".)

Now moving is adding. New x = old x + dx. New y = old y + dy. By hand:

start (2, 3), go E:  change (1, 0)   →  (2 + 1, 3 + 0) = (3, 3)
start (2, 3), go N:  change (0, -1)  →  (2 + 0, 3 - 1) = (2, 2)
start (2, 3), go W:  change (-1, 0)  →  (2 - 1, 3 + 0) = (1, 3)

Why is this better than writing four separate if statements? Because it's one rule for every direction. Later you could add diagonals, like "NE": (1, -1), without changing the moving code at all.

Step 3: don't drive into walls

The adding rule doesn't know about walls. From (1, 1), going N gives (1, 0), which is a #. A real robot would crash. So we add one rule: work out the new square, then check it. If it's free, go there. If not, stay put.

You don't need to write the check yourself. world.py gives you is_free(room, pos), which returns True for floor and False for walls or anywhere outside the room.

Step 4: follow a list of commands, and remember the path

A command string like "EES" means: east, east, south. Do them one at a time, and after each one, write down where you are. Start (1, 1):

start            (1, 1)
E  → (2, 1) free  (2, 1)
E  → (3, 1) free  (3, 1)
S  → (3, 2) WALL  (3, 1)   stays put
path = [(1, 1), (2, 1), (3, 1), (3, 1)]

Notice the path has 4 entries for 3 commands: the start plus one per command. And a bump into a wall still counts as an entry. The robot spent that turn standing still.

Predict first: the robot starts at (1, 1) and runs "EEEESSS". Where does it end up? Trace it on paper, then open.

E four times: (2, 1), (3, 1), (4, 1), (5, 1). S: (5, 2) free. S: (5, 3) free. S: (5, 4) is a wall, so it stays at (5, 3). That's exactly what the homework program prints at the end.

Step 5: how far away is something?

The robot is at (5, 3). The red block is at (2, 1). How far is that? You can't fly diagonally, you walk along the grid. So count the steps across and the steps down separately:

across: from x = 5 to x = 2  →  5 - 2 = 3 steps
down:   from y = 3 to y = 1  →  3 - 1 = 2 steps
total:  3 + 2 = 5

This is called the Manhattan distance, after the city where the streets form a grid and taxis can't cut through buildings. In general: |x1 − x2| + |y1 − y2|. The bars | | mean "absolute value": drop the minus sign. Why? Because if you subtract the other way round, 2 − 5 = −3, and a distance can't be negative. Python's abs(-3) gives 3.

One important thing: Manhattan distance ignores walls. It's the shortest possible distance in a perfect world. The real route can only be the same or longer. In Lesson 6 that "never too big" property is exactly what makes A* search work.

3. Play with it

Interactive: drive the robot

The real room from world.py, with the same moving rules as your Python. Click a square next to the robot, use the buttons, or type a command string and press Run. Bumps into walls leave the robot where it is.

Position
–
Path length
–
Bumps
–
To red block
–

Try: drive to the bin at (7, 6) in as few moves as you can. Manhattan says at least 11. Can you do it in 11? Then type NNNWWW and count the bumps.

4. Homework

Open homework/lesson01_moving.py. It imports the room from world.py and already has the DIRECTIONS dictionary. Write the four functions in order. Each one uses the one before.

Function 1: move(pos, direction)

What it does: returns the new (x, y) after one step. Pure maths, no wall check.

Example: move((2, 3), "E") → (3, 3), and move((2, 3), "N") → (2, 2).

Hint 1

Look up the change for this direction in DIRECTIONS, then add it to the position.

Hint 2

dx, dy = DIRECTIONS[direction] unpacks the tuple into two variables in one go. The position's parts are pos[0] (x) and pos[1] (y).

Hint 3

Return a new tuple: ( x plus dx , y plus dy ). Don't forget the brackets: you're returning one tuple, not two numbers.

Function 2: safe_move(room, pos, direction)

What it does: like move, but if the new square isn't free, return the old position.

Example: safe_move(ROOM, (1, 1), "N") → (1, 1) (wall above). safe_move(ROOM, (1, 1), "E") → (2, 1).

Hint 1

Don't redo the maths. Call your own move first.

Hint 2

Then ask is_free(room, new_pos). It's already imported at the top of the file.

Hint 3
new_pos = (the result of move)
if the new square is free: return new_pos
otherwise: return pos

Function 3: follow(room, start, commands)

What it does: runs every letter of the command string through safe_move, and returns the list of all positions, including the start.

Example: follow(ROOM, (1, 1), "EE") → [(1, 1), (2, 1), (3, 1)]. An empty string gives [(1, 1)].

Hint 1

A for loop over a string gives you one letter at a time: for c in "EES": runs with c = "E", then "E", then "S".

Hint 2

Keep two things: the list so far (it starts with the start in it) and the current position. Each loop, update the position, then add it to the list with .append.

Hint 3
path = a list containing just start
pos = start
for each letter in commands:
    pos = safe_move(room, pos, letter)
    append pos to path
return path

Function 4: manhattan(a, b)

What it does: the grid distance |x1 − x2| + |y1 − y2|.

Example: manhattan((1, 1), (4, 5)) → 3 + 4 = 7, and the other way round, manhattan((4, 5), (1, 1)), is also 7.

Hint 1

Work out the difference in x and the difference in y separately, then add them.

Hint 2

Each difference could come out negative. Python's abs() removes the minus sign.

Hint 3

One line: return abs(difference of the x parts) + abs(difference of the y parts). Use a[0], b[0], a[1], b[1].

Run it and see

cd homework
python3 lesson01_moving.py          # Windows: py lesson01_moving.py
cd ..

The program follows "EEEESSS" from the start and draws the path with *. Real output:

##########
#*r***...#
#..##*...#
#..#.Rb..#
#....##..#
#g.......#
#.#....B.#
##########
Ended at (5, 3) | distance to red block: 5

The red block's r covers the * at (2, 1): the robot rolled past it, since blocks aren't walls.

Check it

python3 check.py 1                 # Windows: py check.py 1

All done looks like this (real output):

Lesson 1: lesson01_moving.py
  ✓ move
  ✓ safe_move
  ✓ follow
  ✓ manhattan
  4/4 passed  🎉 lesson complete!

A ✗ comes with a hint. If you swap N and S, you'll see:

  ✗ move: move((2, 3), "N") should be (2, 2): remember y grows DOWN

And if you forget the start in follow:

  ✗ follow: follow(ROOM, (1, 1), "EE") should list 3 positions

Notice how one bug can cause several ✗: a wrong move also breaks safe_move and follow, because they use it. Always fix the first ✗ first.

Stretch

Write commands_to(start, goal) that returns a command string that walks straight to the goal, ignoring walls: first all the E or W steps, then all the N or S steps. Check that len(commands_to(a, b)) == manhattan(a, b) for a few pairs. Then run it through follow from (1, 1) to the bin at (7, 6) and count how many bumps it gets. (Not checked by check.py.)

5. Real-world challenge: map your room

  1. Pick a room at home, like your bedroom or the kitchen. Choose a step size: floor tiles if you have them, or one foot-length (heel to toe), or one big step.
  2. Draw it on squared paper, one paper square per step. Mark walls and furniture you can't walk through with #. Put (0, 0) in the top-left corner of your drawing, x to the right, y downwards, exactly like the robot's room.
  3. Label three things with their coordinates, for example the door, the bed, a lamp.
  4. Write a command string (only N, S, E, W) to get from the door to one of the things. Write down the Manhattan distance too.
  5. Be the robot. Stand at the door, then follow your string one step per letter without looking where you're going: only at the paper. Or have a friend follow it. If a step would hit furniture, stay put (and count a bump).
  6. Record: where you meant to end up, where you actually ended up, number of bumps, number of commands, and the Manhattan distance.

What it teaches: you'll find that the map and the real room don't quite agree (your steps aren't all the same size, the bed sticks out further than you drew). That gap between the map and reality is a real robotics problem: robots also drift, and that's why Lesson 2 adds sensors. You'll also see that your number of commands is never smaller than the Manhattan distance, and is bigger whenever furniture is in the way.

6. Your Robo-Helper so far

Lesson 0  ✓ the robot greets you and counts steps to a wall
Lesson 1  ✓ move, safe_move, follow, manhattan: the robot can move around the room

These four functions are the robot's legs, and later lessons import them directly:

7. Common mistakes

8. Check yourself

What change (dx, dy) does "S" mean, and why is it +1 not −1?

(0, 1). South is down the screen, and y counts rows from the top, so going down makes y bigger.

Predict: what does follow(ROOM, (2, 1), "SS") return? Use the grid in section 2.

[(2, 1), (2, 2), (2, 3)]. Both squares below (2, 1) are floor, so there are no bumps.

Predict: what does follow(ROOM, (1, 1), "NW") return?

[(1, 1), (1, 1), (1, 1)]. Both moves hit walls, so the robot stays put twice, but each turn still adds an entry to the path.

What is the Manhattan distance from the robot's start (1, 1) to the bin (7, 6)? Can the real route ever be shorter?

6 + 5 = 11. No: Manhattan distance ignores walls, so it's the best case. Walls can only make the real route the same or longer. (In Lesson 6 you'll find the real shortest route is exactly 11.)

Why is it useful that safe_move calls move instead of doing its own maths?

The maths lives in one place. If you change or fix move (or add diagonal directions), safe_move and follow get the fix for free.

9. Go deeper (optional)