This page contains exercise answers and teaching guidance for
Step 3 — Direction & Movement.
Not linked from the student pages.
Students: please go back and try the activities first.
STEP 3 OF 10 · FACILITATOR NOTES
What students will be able to do after Step 3:
if / elif / else chains to handle mutually exclusive conditionspygame.KEYDOWN and pygame.K_UP etc.# Direction as dx, dy offset
dx, dy = 1, 0 # start moving right
# --- Inside the event loop ---
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP and dy != 1: # reverse guard
dx, dy = 0, -1
elif event.key == pygame.K_DOWN and dy != -1:
dx, dy = 0, 1
elif event.key == pygame.K_LEFT and dx != 1:
dx, dy = -1, 0
elif event.key == pygame.K_RIGHT and dx != -1:
dx, dy = 1, 0
# --- Update step ---
head_x += dx
head_y += dy
(dx, dy) = (1, 0) means "move 1 cell right, 0 cells up/down." This is cleaner than storing a direction string like "right" — addition gives the new position directly without a lookup table.
pygame.KEYDOWNFired once when a key is first pressed (not held). Using pygame.KEYDOWN for direction changes is correct — pygame.key.get_pressed() returns True every frame while the key is held, which would fire too often.
and dy != 1Prevents UP being pressed when already going DOWN (which would move the head into the neck). Without this guard, the snake can immediately eat itself on the very next frame.
elif not ifWe want only ONE direction change per frame. If all branches were if, pressing two keys simultaneously could cause the snake to process both and end up moving diagonally — which is not possible on a grid.
| Question | Accepted answer |
|---|---|
1. What does dx, dy = 1, 0 mean? |
Move 1 grid cell right per frame, 0 cells vertically. |
2. Why elif instead of if for each direction? |
We want only one direction to change per frame. Multiple if statements could fire simultaneously, causing diagonal movement. |
3. What does the reverse guard and dy != 1 prevent? |
Pressing UP when already moving DOWN would move the snake's head into its own neck — instant death. |
| 4. What event type fires when a key is pressed? | pygame.KEYDOWN |
if event.key == pygame.K_UP and dy == 1: (wrong guard — == instead of !=)
Effect: You can ONLY press UP when already going down — the controls are inverted and broken.
Fix: Change == to !=: and dy != 1
elif event.key == pygame.K_w and dy != 1:
dx, dy = 0, -1
elif event.key == pygame.K_s and dy != -1:
dx, dy = 0, 1
elif event.key == pygame.K_a and dx != 1:
dx, dy = -1, 0
elif event.key == pygame.K_d and dx != -1:
dx, dy = 1, 0
paused = False
# Inside event loop:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
paused = not paused # toggle
# In update section:
if not paused:
head_x += dx
head_y += dy
| Prompt | Key ideas a strong answer contains |
|---|---|
| 1. What is a coordinate? | A pair of numbers (x, y) that specify a position on a grid. In pygame, x increases to the right and y increases downward. |
| 2. Difference between KEYDOWN and key held? | KEYDOWN fires once when the key is first pressed. get_pressed() returns True every frame while the key is held down. |
| 3. Why can't a snake reverse? | The head would move into the neck — instant collision. The reverse guard prevents physically impossible moves. |
4. What does elif mean in English? |
"Otherwise, if this condition is true..." — part of a chain where only the first matching condition executes. |
| 5. Explain to a classmate? | Should cover: arrow key changes dx,dy; each frame adds dx,dy to head position; reverse guard stops illegal moves. |
| What they did | What they see | What to say |
|---|---|---|
Used if instead of elif for directions |
Snake moves diagonally when two keys pressed | "Only one direction change per frame. elif means only the first matching branch fires." |
dy == 1 instead of dy != 1 in guard |
Controls seem inverted or broken | "The guard should prevent reversal. != means 'not equal to the opposite direction'." |
head_x = dx instead of head_x += dx |
Snake teleports to (1, 0) every frame | "= replaces the value; += adds to it. The snake position accumulates over time." |
Used pygame.K_UP with get_pressed() |
Direction changes every frame the key is held — too fast | "KEYDOWN fires once; get_pressed() fires every frame. For direction changes, use the event." |
| Forgot to update position inside the loop | Snake never moves | "The update step (head_x += dx) must be inside the while loop, not before it." |
"What information does your brain use to move your hand? Direction and distance — the same two things as dx and dy."
Draw a snake on the board. Mark the head and neck. Ask: "If the head is moving right and you press LEFT, where does the head go?" Students will see it moves into the neck. This makes the guard intuitive rather than a mysterious rule to memorise.
The if/elif chain decomposes the key-handling problem into four mutually exclusive cases. Ask students: "What is the algorithm for deciding which direction to move?" This surfaces the idea that conditionals are a tool for expressing decisions.
Watch for: Students who make direction work but forgot pygame.display.flip() from Step 2 — nothing will appear to move. Check this first before debugging direction logic.
If students finish early, ask them to try making the snake start moving UP instead of RIGHT — this surfaces the guard logic because they need to adjust the initial dx, dy values and think through which guards change.
These 5 questions appear in the activity page after Tier 4 (post-calibration gate). Pass mark is 4 of 5 (80%). Students who fail may retry; the system records attempts and final score in Google Sheets.
| Question (displayed to student) | Correct Answer |
|---|---|
| Q1: How is the snake's current direction typically stored? | ✓ As a string like 'UP' or a tuple like (0,-1) |
| Q2: What condition prevents the snake from reversing directly? | ✓ Comparing the requested direction to the opposite of the current one |
| Q3: if event.type == pygame.KEYDOWN: — what does this test? | ✓ Whether a keyboard key was pressed this frame |
| Q4: Which direction vector moves the snake one cell to the RIGHT? | ✓ (1, 0) |
| Q5: What should happen if the player presses LEFT while snake moves RIGHT? | ✓ The input is ignored — opposite direction blocked |
Recorded in Google Sheet (Act_3 tab):
concept_q1–concept_q5 (student’s 0-based answer index),
concept_score_pct, concept_passed (1 = pass, 0 = fail),
concept_attempts (retry count).
Every submission to this step writes one row to the Act_3 tab in the research spreadsheet. All 13 tabs (Student_Reg, Pre_Test, Post_Test, Act_1–Act_10) share the same student identity columns.
| Column | Description |
|---|---|
| STUDENT IDENTITY (10 fields) | |
matric | Matric / student ID |
name | Full name |
gender | Gender (Female / Male / Other) |
age | Age in years |
mykid | MyKid / IC number |
home_state | Home state in Malaysia |
class | Class or cohort code |
school_code | School or programme code |
phone | Phone number |
email | Email address |
| SUBMISSION | |
step | Step number (3) |
submitted_iso | KL timestamp (UTC+8, ISO 8601) |
| PRE-CALIBRATION | |
cal_confidence | Self-confidence before activity (1–5 scale) |
cal_predicted | Predicted score before activity (%) |
cal_reflection | Free-text: what will be hard? |
| ACTIVITY TIERS | |
t1_score_pct | Tier 1 Fill-in-Blanks score (%) |
t2_attempts | Tier 2 Debug — number of attempts |
refl2_text | Tier 2 reflection free text |
t3_attempts | Tier 3 Complete-Code attempts |
t4_attempts | Tier 4 New Task attempts |
| CONCEPT CHECK | |
concept_q1–concept_q5 | Student answer index (0-based) per question |
concept_score_pct | Percentage correct (0–100) |
concept_passed | 1 = passed (≥80%), 0 = failed |
concept_attempts | Total retries |
| REFLECTIVE JOURNAL | |
jr1–jr5 | Journal prompts 1–5 free-text responses |
| POST-CALIBRATION | |
post_confidence | Confidence rating after activity (1–5) |
post_actual | Self-reported actual score (%) |
post_r1 | Reflection: how accurate was the prediction? |
post_r2 | Reflection: what would you do differently? |
calibration_index | post_actual − cal_predicted (negative = overconfident) |