Intermediate — Day 2

Movement Controls

Day Schedule
Online
TimeActivity
10:00Heading System
Draw 0/90/180/270 on whiteboard; demo setheading()
10:20Direction Functions
go_up/down/left/right with direction guard
10:40Event Listeners
screen.listen(), screen.onkeypress(); order matters
10:50Game Loop (intro)
while True, screen.update, head.forward, time.sleep
11:00Break
11:10Breakout Groups
Guided coding: moving snake with arrow keys
12:20Reminders
In-Person
TimeActivity
8:00Warm-Up
Review Day 1: snake head visible for everyone?
8:20Heading System
Draw 0/90/180/270 on whiteboard; demo setheading()
8:45Direction Functions
go_up/down/left/right with direction guard
9:10Event Listeners
screen.listen(), screen.onkeypress(); order matters
9:25Game Loop (intro)
while True, screen.update, head.forward, time.sleep
9:40Break
9:50Breakout Groups
Guided coding: moving snake with arrow keys
11:00Break
11:10Extra Activity
Direction guard deep-dive: try removing guards and observe what breaks
11:50Open Coding
Catch up or experiment with speed and step size
12:20Reminders
Learning Objectives
  1. Know Turtle's heading system: 0=right, 90=up, 180=left, 270=down
  2. Write direction functions with direction-guard conditions
  3. Bind arrow keys using screen.listen() and screen.onkeypress()
  4. Understand the game loop pattern: update → move → sleep
# INSTRUCTOR — Day 2: Conditionals, Functions & Event Listeners (Intermediate)
# -----------------------------------------------
# TEACH: Event listeners are the new concept today.
# screen.listen() tells Turtle to watch the keyboard.
# screen.onkeypress(func, "Key") calls func whenever that key is pressed.
# The function runs automatically — students don't call it manually.
#
# TEACH: Turtle headings are numbers, not strings.
# 0 = right (east), 90 = up (north), 180 = left (west), 270 = down (south)
# head.setheading(90) points the turtle up. head.forward(20) moves it 20 pixels that way.

import turtle
import time
# TEACH: import time loads Python's built-in time module.
# time.sleep(n) pauses the program for n seconds — this is how we control game speed.
# Demo the difference before settling on 0.1:
#   time.sleep(1.0) — very slow, one move per second
#   time.sleep(0.05) — very fast, hard to control
# 0.1 seconds per frame ≈ 10 frames per second — a good starting speed for snake.

screen = turtle.Screen()
screen.bgcolor("black")
screen.setup(width=600, height=600)
screen.tracer(0)

head = turtle.Turtle()
head.shape("square")
head.color("white")
head.penup()
head.goto(0, 0)

# TEACH: direction guard — block the reverse direction.
# If heading UP (90), we must not allow DOWN (270) — that reverses into yourself.
def go_up():
    if head.heading() != 270:   # 270 is DOWN — the opposite of UP
        head.setheading(90)

def go_down():
    if head.heading() != 90:    # 90 is UP — the opposite of DOWN
        head.setheading(270)

def go_left():
    if head.heading() != 0:     # 0 is RIGHT — the opposite of LEFT
        head.setheading(180)

def go_right():
    if head.heading() != 180:   # 180 is LEFT — the opposite of RIGHT
        head.setheading(0)

# TEACH: order matters — listen() BEFORE binding keys
screen.listen()
screen.onkeypress(go_up,    "Up")
screen.onkeypress(go_down,  "Down")
screen.onkeypress(go_left,  "Left")
screen.onkeypress(go_right, "Right")

# One move to verify it works
screen.update()
head.forward(20)
time.sleep(1)
# INSTRUCTOR — Day 2: Project: Snake: Movement Controls (Intermediate)
# -----------------------------------------------
# TEACH: Cumulative from Day 1. Students add direction functions, key bindings,
# and a basic loop so they can actually play with the moving snake.
# Check: press all four arrow keys — head should move and respect the direction guards.
# Common mistake: forgetting head.heading() (calling it as a method, not a property).

import turtle
import time

screen = turtle.Screen()
screen.title("Snake Game")
screen.bgcolor("black")
screen.setup(width=600, height=600)
screen.tracer(0)

head = turtle.Turtle()
head.shape("square")
head.color("white")
head.penup()
head.goto(0, 0)

# --- Direction functions ---
# TEACH: each function blocks the EXACT OPPOSITE heading
# Opposite pairs: UP(90) ↔ DOWN(270),  LEFT(180) ↔ RIGHT(0)

def go_up():
    if head.heading() != 270:
        head.setheading(90)

def go_down():
    if head.heading() != 90:
        head.setheading(270)

def go_left():
    if head.heading() != 0:
        head.setheading(180)

def go_right():
    if head.heading() != 180:
        head.setheading(0)

screen.listen()
screen.onkeypress(go_up,    "Up")
screen.onkeypress(go_down,  "Down")
screen.onkeypress(go_left,  "Left")
screen.onkeypress(go_right, "Right")

# --- Game loop (minimal — no collision yet) ---
# TEACH: while True runs forever. Every frame: update screen, move head, pause.
# time.sleep(0.1) controls speed — lower = faster.
while True:
    screen.update()
    head.forward(20)    # TEACH: forward() uses the current heading automatically
    time.sleep(0.1)
# INSTRUCTOR — Day 2: Extra Activity: Direction Guard (Intermediate)
# -----------------------------------------------
# TEACH: Students fill in the four heading numbers that block a reverse.
# This reinforces the heading map: 0=right, 90=up, 180=left, 270=down.
# Common wrong answer: students put the same heading as the direction being guarded.
# Correct logic: go_up blocks 270 (DOWN), not 90 (UP).

# Headings: 0 = right, 90 = up, 180 = left, 270 = down
# Answers: go_up blocks 270, go_down blocks 90, go_left blocks 0, go_right blocks 180

# REFERENCE (complete answers):
def go_up():
    if head.heading() != 270:   # block DOWN (the reverse of UP)
        head.setheading(90)

def go_down():
    if head.heading() != 90:    # block UP (the reverse of DOWN)
        head.setheading(270)

def go_left():
    if head.heading() != 0:     # block RIGHT (the reverse of LEFT)
        head.setheading(180)

def go_right():
    if head.heading() != 180:   # block LEFT (the reverse of RIGHT)
        head.setheading(0)

# TEACH: challenge — add WASD key support
screen.onkeypress(go_up,    "w")
screen.onkeypress(go_down,  "s")
screen.onkeypress(go_left,  "a")
screen.onkeypress(go_right, "d")
# TEACH: both sets of keys call the same functions — no duplicate logic needed