SeeThinkExploreMarvel

UMPSA STEM LAB · Step 8 of 10

Step 8 — Save High Score

Make your game remember the high score between sessions using file I/O, try/except error handling, f-strings, and a dictionary to store player scores.

open()read / writetry / exceptf-stringdict
Step 8 / 10

The Problem: Data Vanishes When the Program Ends

Variables live in RAM. When Python exits, they're gone. To make the high score persist, we write it to a file on disk that survives between runs.

Python program
score = 42
→ write →
highscore.txt
"42"
← read ←
Next run
best = 42

🔄 Pattern Recognition — persistence pattern

This is one of the most common patterns in software: RAM is fast but volatile (disappears on quit), disk is slow but persistent. Every app you use does this: a game saves to a save file, a browser saves bookmarks, a word processor saves documents. The pattern is always: read state from disk at start → modify in RAM → write back to disk on change.

File I/O Basics

Python's open() function opens a file. The with statement ensures the file is properly closed even if an error occurs.

1

Writing to a file

score = 42
with open("highscore.txt", "w") as f:
    f.write(str(score))
# File now contains the text "42"
# "w" mode: creates file if not exists, overwrites if it does
2

Reading from a file

with open("highscore.txt", "r") as f:
    content = f.read()        # read all text as a string
    high = int(content)       # convert "42" → 42
# "r" mode: read-only (file must exist)
print(f"High score: {high}")  # f-string!
3

File open modes

ModeMeaningFile missing?
"r"Read only❌ Error!
"w"Write (overwrite)✅ Creates it
"a"Append✅ Creates it
"r+"Read + write❌ Error!

🆕 Watch File I/O — Interactive Simulator

Press each button in order to see exactly what Python does when it writes to, and then reads from, a file. Notice how RAM is cleared between runs — but the file persists.

Python RAM
score = 0
high = 0
→
💾 highscore.txt
(empty)
→
Python RAM
(next run)
—
Press 1. Write score to begin.

try / except — Handling Errors Gracefully

What happens the first time you run the game? The highscore file doesn't exist yet. Reading it would crash the program. try/except handles this gracefully.

📋 Algorithm Design — defensive programming

Professional software assumes things will go wrong: files won't exist, networks will time out, users will enter bad data. try/except is Python's way of making code robust — it tries the risky operation and provides a fallback when it fails. This is called defensive programming, and it's what separates hobby code from production code.

try — attempt the risky operation
with open("highscore.txt", "r") as f:
    best = int(f.read())   # might fail!
except — runs only if try failed
except (FileNotFoundError, ValueError):
    best = 0   # first run, or corrupted file

FileNotFoundError — file doesn't exist (first run). ValueError — file contains invalid text (corrupted). Both are caught and handled with a sensible default of 0.

f-Strings — Formatted String Literals

f-strings embed expressions directly inside strings. They're the cleanest way to combine text and variables in Python 3.6+.

score = 42; player = "Ahmad"; best = 100

# Old way (clunky)
msg = "Player " + player + " scored " + str(score)

# f-string (clean)
msg = f"Player {player} scored {score}"

# f-strings can evaluate expressions!
msg = f"Score: {score}  Best: {best}  New best: {score > best}"
# → "Score: 42  Best: 100  New best: False"

msg = f"You scored {score/best*100:.1f}% of the high score"
# → "You scored 42.0% of the high score"
# {value:.1f} = format as float with 1 decimal place

Leaderboard with a Dictionary

Store scores for multiple players using a dictionary: player name → top score.

import json   # for saving/loading dictionaries as text

# Load leaderboard from file
def load_scores(filename="scores.json"):
    try:
        with open(filename, "r") as f:
            return json.load(f)   # JSON → Python dict
    except (FileNotFoundError, json.JSONDecodeError):
        return {}   # empty dict on first run

# Save leaderboard to file
def save_scores(scores, filename="scores.json"):
    with open(filename, "w") as f:
        json.dump(scores, f, indent=2)   # Python dict → JSON

# Usage:
scores = load_scores()
player = "Ahmad"
if player not in scores or score > scores[player]:
    scores[player] = score   # new high score!
    save_scores(scores)

# scores.json on disk looks like:
# {
#   "Ahmad": 42,
#   "Nurul": 87,
#   "Zafri": 15
# }

💡 Abstraction — JSON as a data format

JSON (JavaScript Object Notation) is a text format that looks almost identical to Python dictionaries and lists. It's the universal language of data exchange — REST APIs, config files, and databases all use it. Python's json module converts between Python objects and JSON text.

The Full Step 8 Code

import json   # add to imports at top

# ── New functions (add above the while loop) ───────────────────
SCORE_FILE = "highscore.txt"

def load_high_score():
    """Load high score from file. Returns 0 if file doesn't exist."""
    try:
        with open(SCORE_FILE, "r") as f:
            return int(f.read().strip())
    except (FileNotFoundError, ValueError):
        return 0

def save_high_score(score):
    """Save high score to file if it's a new record."""
    current_best = load_high_score()
    if score > current_best:
        with open(SCORE_FILE, "w") as f:
            f.write(str(score))
        return True   # new record!
    return False

# ── Startup ────────────────────────────────────────────────────
high_score = load_high_score()   # load before the loop

# ── In draw_game() — add high score to display ─────────────────
screen.blit(font.render(
    f"Score: {score}  Best: {high_score}", True, WHITE), (8, 6))

# ── After the game loop ends ───────────────────────────────────
is_new_record = save_high_score(score)
if is_new_record:
    print(f"🎉 New high score: {score}!")

Try It — Exercises

1

Verify persistence 🔄 Pattern

Run the game, get a score of 5, close it. Open highscore.txt in a text editor — what's in it? Run again, get score 3. Does the file change? Get score 10. Does it change now?

2

Display "NEW RECORD!" 📋 Algorithm

In draw_game, add a boolean parameter is_record. If True, draw a flashing "NEW RECORD!" text in gold. Alternate visibility with frame_count % 30 < 15.

3

Name entry 💡 Abstraction

Ask for the player's name at startup using name = input("Enter your name: "). Save scores as {"Ahmad":42, "Nurul":87} using the JSON approach. Print the top 3 scores on game over.

⚠️ Common Mistakes — Spot These Before You Start

These are the errors beginners make most often in Step 8. Read them now so you can recognise them in your own code.

✗ Mistake 1: Opening with "w" mode when you want to read
with open("high_score.txt", "w") as f:
    data = f.read()    # error — "w" doesn't allow reading!
🐞 Mode "w" opens for writing and immediately erases all existing content. Every run wipes the saved score even before reading it.
with open("high_score.txt", "r") as f:    # read mode
    data = f.read()
✗ Mistake 2: Comparing a string score to an integer
saved = f.read()           # saved = "42" (a string)
if score > saved:          # comparing int to str — TypeError!
🐞 Files always return strings. You must convert to int before comparing with the game's integer score.
saved = int(f.read())      # convert string to int first
if score > saved:
⚡ Mistake 3: Forgetting try/except for the first run
with open("high_score.txt", "r") as f:
    high = int(f.read())    # FileNotFoundError on first run!
⚡ The file doesn't exist until the game runs at least once. Without try/except, the program crashes on every fresh install.
try:
    with open("high_score.txt", "r") as f:
        high = int(f.read())
except FileNotFoundError:
    high = 0    # no file yet — start from zero

✅ Quick Check — Are You Ready?

Three questions — not graded. They help you spot gaps before the activities.

1 What happens to an existing file when you open it with mode "w"?
2 Why must you call int(f.read()) rather than just f.read()?
3 What does f"Score: {score}" produce when score = 42?

You've covered all the concepts for Step 8. Time to apply them.

Start Activities → Tier 1 → 2 → 3 → 4
Previous← Wrap-Around