This page contains exercise answers and teaching guidance for
Step 8 — Save High Score.
Not linked from the student pages.
Students: please go back and try the activities first.
open() with modes "r" and "w" to read and write text filesFileNotFoundError with try / exceptSCORE_FILE = "high_score.txt"
# ── Load high score from file ──
try:
with open(SCORE_FILE, "r") as f:
high_score = int(f.read().strip()) # strip() removes newline
except FileNotFoundError:
high_score = 0 # first time running — file doesn't exist yet
except ValueError:
high_score = 0 # file exists but content is not an integer
# ── Save high score to file ──
def save_score(score, high_score):
if score > high_score:
high_score = score
with open(SCORE_FILE, "w") as f:
f.write(str(high_score))
return high_score
# ── f-string formatting ──
name = "Nurul"
score = 42
print(f"Player: {name} — Score: {score:04d}") # → "Player: Nurul — Score: 0042"
pygame.display.set_caption(f"Snake — Score: {score} Best: {high_score}")
# ── Leaderboard (dictionary) ──
leaderboard = {} # {"PlayerName": best_score}
def update_leaderboard(name, score):
if name not in leaderboard or score > leaderboard[name]:
leaderboard[name] = score
with open(path, mode) as f: — the with statement ensures the file is closed even if an error occurs. "r" = read, "w" = write (overwrites), "a" = append.try / except — try runs code that might fail; except ExceptionType: catches a specific error type. Always catch the most specific exception you can.FileNotFoundError — raised when open() is called on a file that doesn't exist. Common in file I/O — always handle it..strip() — removes leading/trailing whitespace including
(newline). A file read with f.read() often ends with a newline.f"..." — embed expressions directly in strings with {variable}. {score:04d} formats as a 4-digit integer with leading zeros.| Question | Accepted answer |
|---|---|
What does open(file, "w") do if the file already exists? |
Overwrites it completely — the old content is lost. |
Why use try / except FileNotFoundError? |
The file won't exist on the first run. Without the try/except, the program crashes immediately. |
What does .strip() remove? |
Whitespace at the start and end of a string — including spaces, tabs, and newlines (
). |
What does the f in f"Score: {score}" do? |
Creates an f-string — Python replaces {score} with the variable's value. |
Bug: high_score = int(f.read()) without .strip() — crashes if file has a trailing newline.
Error: ValueError: invalid literal for int() with base 10: '42
'
Fix: high_score = int(f.read().strip())
import csv
def save_leaderboard(leaderboard, filename="leaderboard.csv"):
with open(filename, "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["Name", "Score"])
for name, score in sorted(leaderboard.items(), key=lambda x: -x[1]):
writer.writerow([name, score])
def load_leaderboard(filename="leaderboard.csv"):
scores = {}
try:
with open(filename, "r") as f:
reader = csv.DictReader(f)
for row in reader:
scores[row["Name"]] = int(row["Score"])
except FileNotFoundError:
pass
return scores
import pygame
# After running = False (game over):
pygame.event.clear()
font = pygame.font.SysFont("monospace", 24)
player_name = ""
asking = True
while asking:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
asking = False
elif event.key == pygame.K_BACKSPACE:
player_name = player_name[:-1]
elif len(player_name) < 10:
player_name += event.unicode
screen.fill(BG)
prompt = font.render(f"Enter name: {player_name}_", True, WHITE)
screen.blit(prompt, (20, WINDOW_H // 2))
pygame.display.flip()
if player_name:
update_leaderboard(player_name, score)
save_leaderboard(leaderboard)
| Prompt | Key ideas a strong answer contains |
|---|---|
| 1. What happens to data when a program ends? | Variables in RAM are lost. Only data written to a file (or database) persists. |
| 2. What is a file "mode"? | The string passed to open() that specifies how to open the file: "r" = read, "w" = write, "a" = append. |
| 3. When should you use try/except? | When an operation might fail for predictable reasons — file not found, network error, invalid input. Handle specific exceptions, not bare except:. |
| 4. What is an f-string? | A string literal prefixed with f that allows Python expressions inside {} to be evaluated and embedded. |
| 5. Explain file I/O to a classmate | "Reading a file is like opening a book; writing is like printing on a page. The with statement is like using a bookmark — it keeps your place and closes the book when done." |
| What they did | What they see | What to say |
|---|---|---|
open(file, "w") to read |
File is silently overwritten with nothing — old high score lost | ""w" is write mode — it DESTROYS existing content. Use "r" to read." |
No .strip() on f.read() |
ValueError — the integer string has a trailing newline |
"Files often end with
. .strip() removes it. Always strip before converting to int." |
except: (bare) |
Catches everything including KeyboardInterrupt and SystemExit |
"Always specify the exception: except FileNotFoundError:. Bare except: is a bad habit that hides real errors." |
Forgot str() in f.write(score) |
TypeError: write() argument must be str, not int |
"f.write() takes a string. Convert first: f.write(str(high_score)) or use an f-string." |
f"Score: " + score |
TypeError: can only concatenate str (not "int") to str |
"Inside an f-string, put the variable in braces: f"Score: {score}". Don't use + with f"..." — it defeats the purpose." |
"What happens to your high score if the power goes out?" For students who've played arcade games, this is intuitive. File I/O is how software remembers things beyond a single session.
Before explaining it, ask students to delete high_score.txt (or pretend they're running for the first time) and run the code without the try/except. They'll see the crash. Now add try/except and show it works. Failure first, solution second — the most memorable teaching sequence.
Emphasise that with open(...) as f: automatically closes the file. Without it, forgetting f.close() can cause data loss or file locks. "It's like a responsible borrower — it returns the book before walking out the door."
Some students may have seen "Score: %d" % score in older tutorials. f-strings are the modern, readable standard — steer students toward them.
Ask: "What other game data might you want to persist across sessions? Player settings? Unlocked levels? Items? What file format would you use?" This opens the door to JSON and databases.
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: TypeError: 'int' and 'str' operands — usually means: | ✓ You tried to add an integer and a string directly |
| Q2: Why read a Python traceback from the bottom up? | ✓ The most specific error information appears at the bottom |
| Q3: Adding print(snake_body) inside the game loop helps because: | ✓ You can see the exact state of the list each frame |
| Q4: IndentationError means: | ✓ Python found inconsistent or unexpected indentation |
| Q5: 'Rubber-duck debugging' means: | ✓ Explaining your code line-by-line to spot logic errors |
Recorded in Google Sheet (Act_8 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_8 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 (8) |
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) |