Tutorial 1.1 - Step 2

Learn to code with step-by-step lessons. A place for students to work through programming fundamentals and build skills.

Step 2 - Storing the board and the current piece

← Step 1 · Tutorial 1.1 · Step 3 →


Goal

Add a Piece class and a way to store both the locked blocks (the board) and the current falling piece. By the end of this step you should have:

We’re not moving or rotating yet - we’re deciding how we represent the board and the piece so that moving and rotating are easier later.


Why this representation?


Your task

  1. In Game, ensure you have a board list (from Step 1) and a pieces list. Create one Piece and append it to pieces.
  2. Define a Piece class that takes the game (e.g. self.game) and a simple type (e.g. "L" or "O"). In __init__, set:
    • self.origin = [x, 0] (e.g. x in the middle of the game area).
    • self.offsets = [...] - one list of (dx, dy) tuples for that shape (e.g. four cells for an L or a square).
    • self.offset_num = 0 (which rotation we’re using; for now there’s only one).
  3. Add a render method on Piece that draws the piece: for each offset in self.offsets[self.offset_num], draw a cell at (origin[0] + dx, origin[1] + dy) in pixel coordinates (using self.game.grid_size and self.game.game_location).
  4. In the game loop, after drawing the game area, call self.pieces[0].render() so the current piece is visible.

Hints

Hint 1 - How do we store the board? The board is a list. Each item is a block: a dictionary like `{"location": (col, row), "image": ...}`. For now you can use a simple colour or a small surface for drawing. When we lock a piece later, we’ll append one such dict per cell of the piece. Locations are in **grid coordinates** (column, row), not pixels.
Hint 2 - What are “offsets” for a piece? Offsets describe the shape relative to the piece’s origin. For an L that looks like three in a column and one to the right at the bottom, you might have: `[(0,0), (0,1), (0,2), (1,2)]`. So the piece has four cells: at origin, origin+ (0,1), origin+(0,2), and origin+(1,2). Store them as `self.offsets = [[(0,0), (0,1), (0,2), (1,2)]]` - a list of lists, so we can add more lists later for rotation.
Hint 3 - Converting grid position to pixels A cell at grid position `(col, row)` is drawn at pixels: `x = game_location[0] * grid_size + col * grid_size` `y = game_location[1] * grid_size + row * grid_size` So for a piece at `origin` with offset `(dx, dy)`, the cell is at `(origin[0] + dx, origin[1] + dy)` in grid coords, then convert that to pixels as above. You can use `pygame.draw.rect` with that rect, or load a small image and scale it to `grid_size`.

Run it

Run your game. You should see the game area and one piece (e.g. an L or a square) drawn inside it. Once you’re happy, compare with the solution.

→ See the solution for Step 2

Then go to Step 3 - Moving pieces and collision.