Snake: Coach notes
Goal of the challenge
A ninja has finished the challenge when:
- β Basic: the snake moves with the arrow keys, eats fruit, grows and shows the score.
- β Stretch: game over on a wall collision or a collision with itself; a game-over screen with the score; restart with R.
- π₯ Expert: speed goes up as the score rises; the high score survives a restart; fruit never spawns on the snake.
Preparation
- Give the ninja the starter code. It contains
main.pyand theimages/folder with the fruit pictures. - The controls, the window and the timing are already there. The ninja fills in
nieuw_fruit(),zet_stap()andteken(). - Check that pygame is available on the laptop (see Installing Thonny).
New concept: loading and scaling images
This is the first time ninjas load an image and scale it too. The starter code already does it, but explain it when a ninja asks about it:
surf = pygame.image.load('images/apple.png').convert_alpha()
fruit_images['apple'] = pygame.transform.scale(surf, (TILE, TILE))pygame.image.load()reads the PNG file in as a Surface..convert_alpha()makes sure the transparency works correctly.pygame.transform.scale()returns a new Surface at the size you ask for. The original does not change.screen.blit(surf, (x, y))draws the Surface at position(x, y).
Common questions
“The snake moves too fast”
clock.tick(60) runs 60 times per second. One step per frame is far too fast. The starter code uses pygame.time.get_ticks() to measure whether enough time has passed. Check that the ninja only calls zet_stap() when nu - laatste_stap >= STAP_MS.
“The snake can move backwards”
The direction may never be reversed straight away. The starter code already checks this in the event handler (if event.key == pygame.K_UP and dy == 0). If the ninja wrote the controls himself, point at that check.
“The snake doesn’t grow when it eats fruit”
Every step you remove the last element (slang.pop()). When it eats fruit you skip that pop(). Check that the ninja skips the pop() on a collision with fruit.
“Fruit appears on the snake”
The ninja spawns fruit without checking whether the position is already taken. Hint: use a while loop that repeats as long as pos in slang.
“A collision with itself isn’t detected”
nieuw_hoofd in slang also matches the current head (the first element before the move). Use nieuw_hoofd in slang[1:].
“The score text doesn’t show up”
font.render() returns a Surface. You still have to put it on the screen with screen.blit(). Many ninjas forget the second step.
Hints per level
Give these hints when a ninja gets stuck. No full code.
β Basic
- Store the direction as two numbers
(dx, dy), for example(1, 0)for right. - Every step: work out
nieuw_hoofd = (slang[0][0] + dx, slang[0][1] + dy), add it to the front, remove the last one. - Growing: skip
slang.pop()when the new head equalsfruit_pos. Then callnieuw_fruit(). - Showing text:
tekst = font.render(f"Score: {score}", True, ZWART)+screen.blit(tekst, (6, 4)).
β Stretch
- After working out the new head, check: outside the grid? In
slang[1:]? Thengame_over = Trueandreturn. - Restart: catch
pygame.K_rin the event handler whengame_overis True, then callreset().
π₯ Expert
- Speed:
STAP_MS = max(60, BASISINTERVAL - score * 10). At a score of 9 the interval is only 60 ms. Recalculate this every time before you check. - High score: keep it outside
reset(). Only update whenscore > hoogste_score. - Fruit not on the snake:
while True: pos = ...; if pos not in slang: break.