Week 2 of 8

Scene Planner: Output & Summary

Finish your scene planner — print the final shot list and count shots per platform

Day 10 60 minutes Build + Review

Day 10 of 40

What You'll Accomplish Today

Part 1: Finish the Scene Planner

Open scene_planner.py from yesterday. You're adding new code after the while True loop — the output section that runs once after the user types "done".

The full addition goes at the bottom of the file:

scene_planner.py — output section (add after the while loop) Python
# --- Print the final scene plan ---

print(f"\n{'=' * 40}")
print(f"  SCENE {scene_num} — SHOT LIST")
print(f"{'=' * 40}\n")

if not scene:
    print("  No shots added.")
else:
    for shot in scene:
        print(f"  {shot['number']}. [{shot['platform']}] ({shot['type']})")
        print(f"     {shot['description']}\n")

    # Count shots per platform
    platform_counts = {}
    for shot in scene:
        p = shot["platform"]
        platform_counts[p] = platform_counts.get(p, 0) + 1

    print(f"  Total: {len(scene)} shots")
    for p, c in platform_counts.items():
        print(f"    {p}: {c} shot{'s' if c != 1 else ''}")
Add this block to the end of your existing file. The indentation here is at the base level (no indentation) — this code is outside the while loop and runs after the loop ends.

Breaking It Down

The Header with String Repetition

scene_planner.py — separator lines Python
print(f"\n{'=' * 40}")
print(f"  SCENE {scene_num} — SHOT LIST")
print(f"{'=' * 40}\n")

'=' * 40 repeats the = character 40 times. In Python, the * operator works on strings too — it means "repeat." "ha" * 3 gives you "hahaha".

Inside an f-string, you can use curly braces {} to run any Python expression — not just variable names. f"{'=' * 40}" evaluates the multiplication inside the braces and inserts the result.

This is a common pattern for building divider lines in terminal output without hardcoding 40 equal signs.

Handling an Empty Scene

scene_planner.py — empty check Python
if not scene:
    print("  No shots added.")
else:
    # ... output code ...

if not scene: checks if the list is empty. An empty list [] is falsy in Python — it evaluates to False in a boolean context. So not scene is True when the list is empty.

This is the Pythonic shorthand for if len(scene) == 0:. Both work, but if not scene: is what experienced Python developers write. You saw this same pattern in yesterday's Day 7 experiments.

It's important to handle this case: if the user immediately types "done" without adding any shots, the loop ends and scene is empty. Without this check, the summary would either show nothing or crash.

The Per-Shot Output Loop

scene_planner.py — shot output Python
    for shot in scene:
        print(f"  {shot['number']}. [{shot['platform']}] ({shot['type']})")
        print(f"     {shot['description']}\n")

Two print statements per shot — one for the metadata line (number, platform, type), one for the description on the next line, followed by a blank line for readability.

Notice the single quotes around dictionary keys inside the f-string: {shot['number']}. When an f-string uses double quotes on the outside, dictionary key strings must use single quotes inside. This avoids the quote conflict.

The Platform Count — The Key Technique

scene_planner.py — platform counting Python
    platform_counts = {}
    for shot in scene:
        p = shot["platform"]
        platform_counts[p] = platform_counts.get(p, 0) + 1

platform_counts = {} starts with an empty dictionary. The keys will be platform names ("Kling", "Runway", "Veo"); the values will be counts.

platform_counts.get(p, 0) — this is the key trick. .get(key, default) looks up a key in the dictionary. If the key exists, it returns the current value. If the key doesn't exist yet, it returns the default value (0 here) instead of crashing with a KeyError.

So the first time we see "Kling", .get("Kling", 0) returns 0 (doesn't exist yet), and we store 0 + 1 = 1. The second time we see "Kling", .get("Kling", 0) returns 1 (already stored), and we store 1 + 1 = 2. This pattern — counts[key] = counts.get(key, 0) + 1 — is how you count occurrences in Python.

Key Concept: .get(key, default)

Normal dictionary access crashes if the key doesn't exist:

d = {}
d["Kling"]           # KeyError: 'Kling'
d.get("Kling")       # None (safe — no crash)
d.get("Kling", 0)    # 0 (safe, with a fallback default)

You'll use .get(key, default) constantly — any time you want a safe lookup without knowing if the key exists. It's one of the most practical dictionary methods.

Iterating with .items()

scene_planner.py — summary output Python
    print(f"  Total: {len(scene)} shots")
    for p, c in platform_counts.items():
        print(f"    {p}: {c} shot{'s' if c != 1 else ''}")

platform_counts.items() returns each key-value pair as a tuple (key, value). By writing for p, c in, we unpack each tuple into two variables: p for the platform name and c for the count. This is called tuple unpacking.

{'s' if c != 1 else ''} is a ternary expression inside an f-string — it adds an "s" to "shot" when the count is not 1, giving you "2 shots" but "1 shot". This is optional polish, but it matters for output quality.

Full Script in Action

Terminal
$ python scene_planner.py
What scene number is this? 2

=== Planning Scene 2 ===
Add shots one at a time. Type 'done' when finished.

Shot description (or 'done'): Wide establishing shot, sunrise over fairway
Platform (Kling / Runway / Veo): Kling
  Shot types: wide, medium, close-up, aerial, tracking, slow-mo
  Shot type: wide
  ✓ Shot 1 added.

Shot description (or 'done'): Aerial drone reveal, pulling back
Platform (Kling / Runway / Veo): Veo
  Shot types: wide, medium, close-up, aerial, tracking, slow-mo
  Shot type: aerial
  ✓ Shot 2 added.

Shot description (or 'done'): Close-up on ball dropping into cup
Platform (Kling / Runway / Veo): Kling
  Shot types: wide, medium, close-up, aerial, tracking, slow-mo
  Shot type: close-up
  ✓ Shot 3 added.

Shot description (or 'done'): done

========================================
  SCENE 2 — SHOT LIST
========================================

  1. [Kling] (wide)
     Wide establishing shot, sunrise over fairway

  2. [Veo] (aerial)
     Aerial drone reveal, pulling back

  3. [Kling] (close-up)
     Close-up on ball dropping into cup

  Total: 3 shots
    Kling: 2 shots
    Veo: 1 shot

Part 2: Week 2 Vocabulary Review

Cover the right column and try to define each term from memory. Then reveal and check yourself.

Term What It Means
if / elif / else Conditional branches — runs different code depending on which condition is true
comparison operator ==, !=, >, <, >=, <= — compares two values and returns True or False
logical operator and, or, not — combines or negates boolean conditions
for loop Iterates over each item in a sequence (list, string, etc.) a fixed number of times
while loop Runs as long as a condition is true — or forever with while True:
break Immediately exits the current loop, regardless of the loop condition
list An ordered, mutable collection of items in [] — items accessed by index
index The position of an item in a list — starts at 0; negative indexes count from the end
.append() Adds an item to the end of a list — the primary way to grow a list
dictionary (preview) A collection of key:value pairs in {} — items accessed by name, not position
.lower() Returns a lowercase copy of a string — used to make comparisons case-insensitive
count += 1 Shorthand for count = count + 1 — increments a variable in place

Week 2 Milestone Check

You're Ready for Week 3 If You Can...
Feeling Unsure About Dictionaries?

That's completely fine. Dictionaries were a preview in Week 2 — they're the main topic of Week 3. You used them in both build projects this week to build intuition. Next week you'll learn them properly: how to create, modify, and iterate over them, and how to save them to files so your data persists.

End of Day Checklist