32. Drawing on screen — Homework solutions
Each solution is a complete, runnable pygame program. Run with:
python exercises/32/homework/solutions/01-flag.py
Problem 1 — Flag
Problem. Draw a three-stripe flag filling most of the window.
How to think about it. Divide the window height by 3. Each stripe is a rectangle spanning the full width at a different y position.
Worked solution.
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Flag")
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((255, 255, 255))
stripe_height = 600 // 3
pygame.draw.rect(screen, (0, 57, 166), (0, 0, 800, stripe_height))
pygame.draw.rect(screen, (255, 255, 255),(0, stripe_height, 800, stripe_height))
pygame.draw.rect(screen, (255, 0, 0), (0, stripe_height * 2, 800, stripe_height))
pygame.display.flip()
clock.tick(60)
pygame.quit()Any three colours are acceptable. The key is computing the y offset
of each stripe as stripe_height * stripe_index.
Common mistakes.
- Hard-coding pixel positions like
0, 200, 400instead of computing from600 // 3. If the window size changes, hard-coded positions break; computed positions adapt.
Problem 2 — Target
Problem. Three concentric circles in alternating colours.
How to think about it. Draw the largest circle first, then the medium one on top, then the smallest. They all share the same centre. Using different radii with the same centre produces concentric rings.
Worked solution.
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Target")
clock = pygame.time.Clock()
cx, cy = 400, 300 # centre
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((200, 200, 200))
pygame.draw.circle(screen, (220, 0, 0), (cx, cy), 150)
pygame.draw.circle(screen, (255, 255, 255), (cx, cy), 100)
pygame.draw.circle(screen, (220, 0, 0), (cx, cy), 50)
pygame.display.flip()
clock.tick(60)
pygame.quit()Common mistakes.
- Drawing smallest first. The largest circle will paint over the smaller ones, leaving only a single filled circle. Always draw back-to-front.
Problem 3 — Grid
Problem. A 4x4 grid of outlined squares using nested loops.
How to think about it. Divide the window into 4
equal columns and 4 equal rows. Each cell's top-left corner is at
(col * cell_w, row * cell_h).
Worked solution.
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Grid")
clock = pygame.time.Clock()
cols = 4
rows = 4
cell_w = 800 // cols
cell_h = 600 // rows
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((30, 30, 30))
for row in range(rows):
for col in range(cols):
x = col * cell_w
y = row * cell_h
pygame.draw.rect(screen, (180, 180, 180), (x, y, cell_w, cell_h), 2)
pygame.display.flip()
clock.tick(60)
pygame.quit()The thickness argument 2 draws only the border. Setting
it to 0 would fill each cell.
Common mistakes.
- Using
range(1, 5)instead ofrange(4). Both produce four values butrange(4)starts at 0, which correctly maps to pixel positions via multiplication.
Challenge — Chessboard
Problem. An 8x8 chessboard where
(row + col) % 2 == 0 is white and the rest is dark.
How to think about it. Same structure as the grid,
but the fill colour depends on (row + col) % 2. Use filled
rectangles (thickness 0).
Worked solution.
import pygame
pygame.init()
SIZE = 600
screen = pygame.display.set_mode((SIZE, SIZE))
pygame.display.set_caption("Chessboard")
clock = pygame.time.Clock()
LIGHT = (240, 217, 181)
DARK = (181, 136, 99)
CELLS = 8
cell = SIZE // CELLS
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((0, 0, 0))
for row in range(CELLS):
for col in range(CELLS):
color = LIGHT if (row + col) % 2 == 0 else DARK
x = col * cell
y = row * cell
pygame.draw.rect(screen, color, (x, y, cell, cell))
pygame.display.flip()
clock.tick(60)
pygame.quit()Using a square window (600x600) and dividing by 8 gives
equal cells with no rounding error (600 / 8 = 75
exactly).
Common mistakes.
- Using a non-square window (e.g., 800x600).
800 / 8 = 100but600 / 8 = 75, so cells would be rectangular rather than square. Either use a square window or use separatecell_wandcell_h.
Done?
Chapter 33 adds keyboard and mouse input so the program can react to what the player does.