Tutorial 1.1 - Step 2 Solution

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

Step 2 - Solution

← Step 2 · Tutorial 1.1 · Step 3 →


Here is one way to add the Piece class and store the board and current piece. This uses simple coloured rectangles; you can swap in images later.

import pygame
import sys


class Piece:
    def __init__(self, game, p_type="L"):
        self.game = game
        x = game.game_area[0] // 2 - 1
        self.origin = [x, 0]
        self.type = p_type
        self.offset_num = 0
        # One list of offsets per rotation; for now just one (L-shape)
        if self.type == "L":
            self.offsets = [
                [(0, 0), (0, 1), (0, 2), (1, 2)],
            ]
        elif self.type == "O":
            self.offsets = [
                [(0, 0), (1, 0), (0, 1), (1, 1)],
            ]
        else:
            self.offsets = [[(0, 0), (1, 0), (1, 1), (2, 1)]]  # Z

    def render(self):
        origin_px = (
            self.game.game_location[0] * self.game.grid_size,
            self.game.game_location[1] * self.game.grid_size,
        )
        for (dx, dy) in self.offsets[self.offset_num]:
            gx = self.origin[0] + dx
            gy = self.origin[1] + dy
            px = origin_px[0] + gx * self.game.grid_size
            py = origin_px[1] + gy * self.game.grid_size
            rect = pygame.Rect(px, py, self.game.grid_size, self.game.grid_size)
            pygame.draw.rect(self.game.screen, "blue", rect)
            pygame.draw.rect(self.game.screen, "black", rect, 1)


class Game:
    def __init__(self):
        pygame.init()
        self.clock = pygame.time.Clock()
        default_grid_size = 30
        self.screen_grid = (22, 24)
        self.screen = pygame.display.set_mode(
            (self.screen_grid[0] * default_grid_size, self.screen_grid[1] * default_grid_size),
            pygame.RESIZABLE,
        )
        self.grid_size = self.screen.get_size()[0] / self.screen_grid[0]
        self.game_location = (6, 3)
        self.game_area = (10, 20)
        self.board = []
        self.pieces = [Piece(self, "L")]

    def run(self):
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()

            self.screen.fill("white")
            pygame.draw.rect(
                self.screen,
                "black",
                (
                    self.game_location[0] * self.grid_size,
                    self.game_location[1] * self.grid_size,
                    self.game_area[0] * self.grid_size,
                    self.game_area[1] * self.grid_size,
                ),
            )
            for block in self.board:
                loc = block["location"]
                px = self.game_location[0] * self.grid_size + loc[0] * self.grid_size
                py = self.game_location[1] * self.grid_size + loc[1] * self.grid_size
                pygame.draw.rect(
                    self.game.screen, "gray",
                    (px, py, self.grid_size, self.grid_size),
                )
            self.pieces[0].render()
            pygame.display.update()
            self.clock.tick(60)


if __name__ == "__main__":
    Game().run()

What’s going on:

Next step: make the piece move and lock when it hits the bottom or the board.

← Back to Step 2 · Step 3 →