Unit 9 – Teachers Guide
Unit 9 · Code That Thinks — Algorithms & CS Foundations
Your day-to-day companion for delivering Unit 9 — pacing, standards, lesson plans, misconceptions, differentiation, and a Python error appendix. Unit 9 is the curriculum's conceptual pivot. Earlier units taught the tools; Unit 9 teaches the mindset — computational thinking, comparing algorithms (linear vs binary search, bubble vs selection sort), the math beneath the code (binary numbers, logic gates, sets). The capstone — Algorithm Playground — is a benchmark tool that races algorithms head-to-head with real timing measurements, turning "I think this is faster" into "I measured, and here's the proof."
👋 Welcome — How to Use This Guide
This Teacher's Guide is your day-to-day companion for delivering Unit 9 of the Code Quest curriculum. Unit 9 is the curriculum's conceptual pivot — earlier units taught the tools, this one teaches the mindset. Students learn to NAME computational thinking (decomposition, pattern recognition, abstraction, algorithmic design), COMPARE algorithms with both step counts AND wall-clock time (linear vs binary search, bubble vs selection vs sorted()), and meet the math beneath the code (binary numbers, logic gates AND/OR/NOT/XOR, sets and set operations). The capstone — Algorithm Playground — is a 3-file CLI benchmark tool that races algorithms head-to-head with real timing. It picks up after Unit 8 and assumes students are fluent with classes, file I/O, JSON, modules, and multi-file architecture.
What this guide contains
- A pacing guide showing how Unit 9 maps to roughly 9–11 class periods. Lessons 1–3 are 50 minutes, Lesson 4 is 55 (math-heavy), Lesson 5 is a 90–120 minute capstone split across 2–3 days.
- A standards & exam crosswalk. Unit 9 is the home of Florida CTE standards 02.03 (binary, logic gates, sets) and 05.06 (multiple algorithms for the same problem), and provides full depth on 07.02 (algorithms).
- A unit vocabulary glossary with all 22 key terms — most are conceptual (computational thinking pillars, Big O, scaling) plus the math-meets-code terminology of Lesson 4 (bit, byte, gate, set, union, intersection).
- Five detailed lesson plans using the same 7-section format from prior guides.
- An appendix covering algorithm-specific Python errors: in-place mutation surprises (bubble sort modifying the input),
time.perf_counter()measurement bugs, off-by-one errors in binary search bounds, the silent bug of comparing different-shape inputs, set vs list confusion, and the dreaded "I optimized the wrong thing" lesson.
How each lesson plan is structured
Same 7-section format used in prior units:
- At-a-Glance — objective, time, materials, vocabulary, standards box
- Lesson Flow — a 50–55 minute breakdown: warm-up, instruction, guided practice, lab, exit ticket
- Watch For — the 3–5 most common student misconceptions and how to address each
- Differentiation — early finishers and struggling students
- Discussion Prompts — questions to spark whole-class conversation
- Real-World Connections — answering "why does this matter?"
- Lesson-Specific Vocabulary — terms introduced or reinforced
How to read this in conjunction with the student lessons
- Before class: read this lesson plan (5–10 min) and skim the student HTML. Unit 9's interactive widgets are particularly important — the Pillar Identifier in L1, the Search Race in L2, the Sort Race in L3, the Binary Converter + Logic Gate Playground in L4 — they make abstract ideas tangible
- During class: follow the lesson flow; the student HTML is the textbook + lab
- After class: grade Knowledge Checks and labs against this guide's expectations
🗺️ Unit 9 Overview
The big picture
Unit 9 is "Code That Thinks." Lesson 1 names the four pillars of computational thinking — students get vocabulary for what they've been doing all year. Lesson 2 compares two search algorithms (linear vs binary) — same problem, two solutions, different scaling. Lesson 3 does the same for sorting (bubble vs selection vs sorted()) — and reveals that Python's built-in is dramatically faster than what students wrote in Unit 3. Lesson 4 covers the math beneath the code: binary numbers, logic gates (AND/OR/NOT/XOR), and Python's set data type with set operations. Lesson 5 culminates in Algorithm Playground — a 3-file CLI tool with pure algorithm functions, a benchmarking harness using time.perf_counter(), and a menu that races algorithms head-to-head with side-by-side reports.
What students learn
- Name the four pillars of computational thinking: decomposition, pattern recognition, abstraction, algorithmic design
- Identify which pillar(s) apply to a given coding decision
- Implement linear search (check every item) — O(n) — and recognize when it's appropriate
- Implement binary search (cut the list in half each step) — O(log n) — and recognize that it requires sorted input
- Compare algorithms by step count — count comparisons made, not just time elapsed
- Understand Big O notation at an intuitive level: O(1) constant, O(log n) logarithmic, O(n) linear, O(n²) quadratic
- Implement selection sort — pick the minimum, swap to front, repeat
- Recognize that Python's
sorted()is dramatically faster than student-written sorts (Timsort: O(n log n)) - Apply the rule: don't write what's already optimized; use the built-in
- Convert between decimal and binary; understand bits, bytes, place values
- Apply the four logic gates: AND, OR, NOT, XOR — and recognize them in Python (
and,or,not,!=or^) - Use Python's
settype for unique items + fast membership tests - Apply set operations: union (
|), intersection (&), difference (-), symmetric difference (^) - Measure wall-clock time with
time.perf_counter() - Run benchmarks correctly: same input, multiple runs, average, no print() inside the timed section
- Build a 3-file CLI tool that races algorithms with both step counts AND time measurements
Prerequisites
Units 1–8. Students must be fluent with: variables, control flow, all four data structures, functions with parameters & returns, the SDLC, file I/O, JSON, classes, modules, and multi-file architecture. Unit 9 doesn't introduce new SYNTAX so much as new MENTAL FRAMEWORKS. The capstone reuses the modular architecture from Units 6–8.
What comes next
Unit 10 introduces databases (SQLite) — students will learn how data is stored, queried, and persisted at scale. The same algorithm thinking from Unit 9 carries directly: B-tree indexes are binary search; query optimization is "which algorithm should I use?"; database normalization is decomposition. The course capstone — Contact Vault SQL Edition — is the culmination of every skill from Units 1–10, with an ETHICS.md document covering IP, privacy, responsible tech, and security.
Materials you'll need
- Computers with web browser access (one per student, or pairs)
- Knowledge Pillars CodeSkills Lab access
- Projector or large screen — Unit 9's interactive widgets (Pillar Identifier, Search Race, Sort Race, Binary Converter, Logic Gate Playground) are the unit's pedagogical anchors
- Whiteboard with multiple colors — heavily used in Lesson 2 (showing search bisection on a number line), Lesson 3 (animating a bubble-sort pass), Lesson 4 (binary place-value tables, truth tables), Lesson 5 (3-file architecture diagram)
- Optional: printed Big O chart (the famous "growth rates" graphic) — pin to wall throughout unit
- Optional: printed truth-table reference card for Lesson 4
- Optional: a deck of playing cards (one per pair) — physical demonstration of bubble vs selection sort by sorting cards by hand. High-impact teaching for Lesson 3
⏱️ Pacing Guide
Unit 9 is designed for 9–11 class periods. Lessons 1–3 are 50 minutes; Lesson 4 (math-heavy) is 55 minutes; Lesson 5 is a 90–120 minute capstone split across 2–3 days. Unit 9's pacing is forgiving — most lessons fit comfortably in their time. The pivot lesson is L1 (computational thinking), which can feel abstract and benefits from generous discussion time.
Recommended pacing — 10-day plan
| Day | Lesson | Focus | Homework |
|---|---|---|---|
| Day 1 | L1: Computational Thinking | Meet the four pillars. Worked example (smart shopping list). Pillar Identifier widget. Why vocabulary matters. Lab 9.1A. | Read L2 Sections 1–3 (linear search) |
| Day 2 | L2: Searching (pt 1) | The search problem. Linear search code. Step counting. Lab 9.2A. | Read L2 Sections 4–6 (binary search + tradeoffs) |
| Day 3 | L2: Searching (pt 2) | Binary search code. Search Race widget. Big O intuition. Tradeoffs (sorted requirement). Knowledge check. | Read L3 Sections 1–4 (sorting) |
| Day 4 | L3: Sorting | Bubble sort refresher (Unit 3 callback). Selection sort. Sort Race widget. The sorted() punchline. Lab 9.3A. | Read L4 Part 1 (binary numbers) |
| Day 5 | L4: Binary & Gates (pt 1) | Binary numbers. Place values. Binary Converter. bin()/int(_, 2) in Python. Logic gates intro. Truth tables. | Read L4 Part 2 (logic gates) |
| Day 6 | L4: Gates & Sets (pt 2) | Logic Gate Playground. XOR's special powers. Sets and set operations. Lab 9.4A. Knowledge check. | Plan Algorithm Playground architecture |
| Day 7 | L5: Algorithm Playground (pt 1) | Benchmarking intro. Pitfalls. Plan stage (3-file architecture). Code algorithms.py first. | Continue building algorithms.py |
| Day 8 | L5: Capstone (pt 2) | Code bench.py. Code main.py. Wire it together. Run first benchmark. | Continue building, prepare to test |
| Day 9 | L5: Capstone (pt 3) | Test (10 cases) + Fix + Maintain. Especially: mutation bugs, repeated-runs stability. Showcase. Submit. | — |
Compressed 9-day pacing
If you need to compress: combine Day 5 and Day 6 (cover all of Lesson 4 in one period). This works for stronger groups — but Lesson 4 is the densest single lesson of the unit (3 distinct topics: binary, gates, sets). Recommended only if your class found Unit 9's earlier lessons easy.
Extended 11-day pacing
If your class needs more time: split Lesson 4 into two days but ALSO split Lesson 5 across 4 days. Day 7 = algorithms.py only (pure functions). Day 8 = bench.py only (timing harness). Day 9 = main.py + integration. Day 10 = test/fix/maintain/showcase. This is the gentlest possible pacing for the capstone.
Suggested grading weights for Unit 9
| Component | Weight | Notes |
|---|---|---|
| Lesson Knowledge Checks (×4) | 15% | 3 questions each, completed in-platform |
| Lab Exercises (×8) | 30% | CodeSkills Lab — heavy algorithm-implementation practice |
| Algorithm Playground Final Project | 45% | Capstone — 100-pt rubric in Lesson 5 plan |
| Class participation | 10% | Whiteboard work, Search/Sort Race demos, peer code reviews |
Note: Algorithm Playground is the sixth 45%-weighted capstone in a row. It integrates the algorithm thinking of Unit 9 with the multi-file architecture of Units 6–8. The unit produces a tool computer science professors actually use — students see their code race, measure, and produce real data. That's a memorable artifact.
🎓 Standards & Exam Crosswalk
This crosswalk shows exactly which Florida CTE standards and Coding Fundamentals exam objectives each lesson addresses. Unit 9 is the home of 02.03 (binary, logic gates, sets) and 05.06 (multiple algorithms for the same problem), and provides the deepest coverage of 07.02 (algorithms) in the course. The capstone covers the broadest set of standards in the unit and is the unit's culminating performance task.
Florida CTE Standards — Course #9009200
Standards from the Florida Department of Education Coding Fundamentals curriculum framework that Unit 9 addresses:
| Standard | Description | Lessons |
|---|---|---|
| 01.01 | Use specialized computer coding software to solve problems. | All (CodeSkills Lab) |
| 01.02 | Demonstrate proficiency using specialized computer software (e.g., Python). | All |
| 02.02 | Explain the components of programming languages. | L4 (set type, operators), L5 (modules) |
| 02.03 | Recognize binary numbers, logic gates, and set operations. | L4 — primary unit standard (the home of this standard) |
| 04.03 | Demonstrate sorting and filtering of data sets. | L3 (sorting), L5 (capstone uses sort) |
| 05.06 | Recognize that more than one algorithm can solve a given problem. | L1, L2, L3, L5 — primary unit standard (the unit's central thesis) |
| 05.07 | Create a program that implements an algorithm to achieve a given goal. | L2, L3, L5 (capstone) |
| 06.02 | Apply troubleshooting techniques within the SDLC. | L5 (benchmark stability) |
| 06.03 | Apply iterative debugging within the SDLC. | L5 |
| 07.01 | Describe the structure of a simple program. | L5 (3-file architecture) |
| 07.02 | Compare and contrast different algorithms (e.g., search, sort). | L1, L2, L3 — full depth |
| 07.05 | Explain the types and use of variables in programming. | L4 (set type, binary) |
| 07.07 | Troubleshoot and debug errors in code. | L2 (off-by-one), L3 (mutation), L5 |
Coding Fundamentals Exam Objectives
Exam objectives that Unit 9 prepares students for. Objective 3 (algorithm understanding & design) is the unit's flagship — the entire unit is built around comparing algorithms and reasoning about their behavior.
| Obj | Title | Coverage in Unit 9 | Lessons |
|---|---|---|---|
| 1 | Core programming concepts | Continued — algorithms ARE core | L1, L2, L3, L4 |
| 2 | Analyze and predict code behavior | Reinforced — predict step counts, predict scaling | L2, L3 |
| 3 | Algorithm understanding & design | Full coverage — primary objective for the unit | L1, L2, L3, L5 |
| 4 | Write and debug simple programs | Reinforced through the capstone | L5 |
| 5 | Data manipulation | Set operations, sorting | L3, L4 |
Lesson-by-lesson alignment
| Lesson | Florida Standards | Exam Objectives |
|---|---|---|
| L1: Computational Thinking | 01.01, 01.02, 05.06, 07.02 | 1, 3 (primary) |
| L2: Searching | 01.01, 01.02, 05.06, 05.07, 07.02, 07.07 | 2, 3 (primary), 4 |
| L3: Sorting | 01.01, 01.02, 04.03, 05.06, 05.07, 07.02, 07.07 | 2, 3 (primary), 4, 5 |
| L4: Binary, Logic Gates & Sets | 01.01, 01.02, 02.02, 02.03, 07.05 | 1, 5 (primary) |
| L5: Algorithm Playground Capstone | 01.01, 01.02, 02.02, 04.03, 05.06, 05.07, 06.02, 06.03, 07.01, 07.02, 07.07 | 2, 3, 4 (primary), 5 |
📖 Unit 9 Vocabulary Glossary
All 22 key terms students will encounter in Unit 9. The "Intro" column shows the lesson where each term first appears. Each lesson plan also includes its own focused vocabulary list. Most of Unit 9's vocabulary is conceptual rather than syntactic; students should be able to explain these terms out loud, not just recognize them.
| Term | Definition | Example | Intro |
|---|---|---|---|
| Computational Thinking | The systematic mindset for solving problems with code. Has four pillars: decomposition, pattern recognition, abstraction, algorithmic design. | The "thinking style" of programmers | L1 |
| Decomposition | Breaking a big problem into smaller, named pieces. Every function is decomposition. | plan(), code(), test() functions | L1 |
| Pattern Recognition | Spotting repeated shapes. The "filter pattern," the "loop+counter pattern," the "API+cache pattern." | "Loop, accumulator, return total" | L1 |
| Abstraction | Hiding messy details behind a clean interface. requests.get() hides hundreds of lines of network code. | A class wraps raw data | L1 |
| Algorithmic Design | Designing the steps to solve a problem before writing code. Plan first, code second. | "For each item: check, if match, return" | L1 |
| Linear Search | Algorithm that checks every item in order until found (or list ends). O(n). | "Find Sam in a contact list" | L2 |
| Binary Search | Algorithm that cuts a SORTED list in half each step. O(log n). Requires sorted input. | Find a word in a dictionary | L2 |
| Step Count | Number of comparisons (or operations) an algorithm performs. The objective measure. | 20 items → linear ~20 steps; binary ~5 steps | L2 |
| Big O Notation | Shorthand for an algorithm's growth rate. O(1) constant, O(log n) logarithmic, O(n) linear, O(n²) quadratic. | O(n) linear search · O(log n) binary | L2 |
| Selection Sort | Sorting algorithm: find smallest, swap to front, repeat on rest. O(n²). | Like sorting cards by repeatedly grabbing the smallest | L3 |
sorted() | Python's built-in sort. Uses Timsort — O(n log n). Dramatically faster than student-written sorts. | sorted(my_list) | L3 |
| In-place vs new list | list.sort() mutates; sorted(list) returns a new list. Different patterns for different needs. | Sort race needs .copy() to avoid mutation | L3 |
| Binary Number | A number written in base 2 — only 0s and 1s. The native language of computers. | decimal 5 = binary 101 | L4 |
| Bit / Byte | Bit = a single 0 or 1. Byte = 8 bits. Smallest units of computer data. | 8 bits = 1 byte = 256 possible values | L4 |
| Logic Gate | A circuit that takes binary inputs and produces a binary output. Four basic: AND, OR, NOT, XOR. | AND(1,1)=1; OR(0,1)=1 | L4 |
| AND / OR / NOT | The three basic logic operators. Same as Python's and, or, not. | if age >= 18 and has_id: | L4 |
| XOR | "Exclusive OR" — true when EXACTLY ONE input is true. Powers encryption, image masks, parity checks. | 5 ^ 3 = 6 | L4 |
Set (Python set) | An unordered collection of UNIQUE items. Lightning-fast membership tests. | {1, 2, 3}, "x" in my_set | L4 |
| Set Operations | Math operations on sets: union (|), intersection (&), difference (-), symmetric difference (^). | a | b, a & b, a - b | L4 |
| Benchmark | A measured comparison. Usually counts steps OR measures wall-clock time. | Race two algorithms on same input | L5 |
time.perf_counter() | Python's high-precision stopwatch. Returns seconds (float). Subtract start from end to get elapsed. | elapsed = end - start | L5 |
| Algorithm | (From Unit 3) A clear, ordered, finite set of steps that solves a problem. | Recipe; commute directions | L1 (recap) |
🏛️ Lesson 1 · Computational Thinking
Lesson 1 · Computational Thinking
Lesson PlanAt-a-Glance
Lesson Flow (50 minutes)
🔥 Warm-Up (5 min)
- Project a Unit 5 Contact Vault, a Unit 6 Persistent Vault, a Unit 7 Quest Heroes, a Unit 8 Weather Dashboard. Ask: "What did you do INTERNALLY across all four projects?" Take answers — break problems down, build on patterns, hide details, design steps.
- Reveal: those four answers have NAMES. Today is the day we give names to what you've already been doing — the four pillars of computational thinking.
🎤 Direct Instruction (18 min)
- Open Lesson 9.1 on the projector. Walk through Section 1 ("Meet the Four Pillars"). On the whiteboard, draw a 2×2 grid:
- 🧩 Decomposition — Breaking a big problem into smaller, named pieces. Every function is decomposition. Every multi-file architecture is decomposition at the file level.
- 🔍 Pattern Recognition — Spotting that the same shape repeats. The "filter pattern," the "API+cache pattern," the "validate input loop." Once you see a pattern, you can apply it to new problems.
- 🎭 Abstraction — Hiding messy details behind a clean interface.
requests.get()hides hundreds of lines of network code. YourWeatherReportclass hid raw JSON.sorted()hides Timsort. - 📐 Algorithmic Design — Designing the STEPS to solve a problem before writing code. Plan first, code second. The SDLC's "plan" stage is algorithmic design.
- Walk through Section 2 ("Worked Example — A Smart Shopping List"). Live-design a small program together. For each design choice, NAME the pillar:
- "Split into
add_item,remove_item,list_itemsfunctions" → DECOMPOSITION - "Each function follows the same input → validate → modify shape" → PATTERN RECOGNITION
- "User doesn't know we use a dict internally — could be JSON later" → ABSTRACTION
- "Order: get input, validate, then update" → ALGORITHMIC DESIGN
- "Split into
- Walk through Section 3 ("The Pillar Identifier"). Use the widget. Project. Walk through 3–4 code snippets with the class. For each, identify the pillar(s) at play.
- Walk through Section 4 ("Why the Vocabulary Matters"). Three reasons:
- It TRAVELS to other CS classes — every CS curriculum names these pillars.
- It UNIFIES what feels like disparate skills — file I/O, classes, and APIs all use the same four pillars.
- It guides design CHOICES — when stuck, ask "which pillar am I missing?"
🤝 Guided Practice (10 min)
- On the whiteboard, project a list of 6 design decisions from past projects. As a class, identify the pillar each represents:
- "Splitting Persistent Vault into contact_vault.py + vault_io.py" → Decomposition
- "Putting
save_vaultafter every change in the Vault" → Pattern Recognition - "Building a
WeatherReportclass that hides JSON" → Abstraction - "Designing the data shape BEFORE writing the Vault" → Algorithmic Design
- "Realizing a Quest Heroes capstone needs to/from_dict" → Pattern Recognition (saw the JSON pattern)
- "Using
sorted()instead of writing your own sort" → Abstraction (someone else hid the details)
- Discuss any class disagreements — multiple pillars often apply.
💻 Independent Lab (12 min)
- Lab 9.1A — "Pillar Tagger": students get 8 short code snippets and label each with the pillar(s) it represents. Some snippets use multiple pillars. The lab is conceptual rather than coding — focus on JUSTIFYING each label.
- Lab 9.1B — "Apply Four Pillars": students design (in writing, no code) a "study buddy app" using all four pillars explicitly. Required: at least one decomposition decision, one pattern they're reusing, one abstraction, one algorithmic design choice.
- Circulate. Common bugs: over-applying decomposition (any function call is "decomposition" but the framework is about CONSCIOUS design); confusing abstraction with simply "using a function" (abstraction specifically HIDES complexity); claiming "I'm using algorithmic design" without articulating the steps.
🚪 Exit Ticket (5 min)
- On paper: "Name the four pillars of computational thinking. For each, give one example from a project you've already built."
- Looking for: all four named correctly (Decomposition, Pattern Recognition, Abstraction, Algorithmic Design), each with a concrete prior-project example. Common acceptable examples: function splits = decomposition; JSON load/save pattern = pattern recognition; classes wrapping data = abstraction; SDLC plan stage = algorithmic design.
⚠️ Watch For — Common Misconceptions
print(), that's abstraction." Technically true but trivial.requests.get() hides networking. A class hides data shape decisions. print() hides character encoding — but at this level, "abstraction" usually means YOU made something cleaner for someone else (or future-you).🎯 Differentiation
For early finishers
Challenge: pick ONE prior project (their choice) and write a short "design retrospective" — one paragraph for each pillar describing exactly how they used it. Demonstrates self-reflection. Stretch: research Jeannette Wing's 2006 paper "Computational Thinking" — the academic origin of these pillars. What was Wing's argument?For struggling students
Stay on Lab 9.1A. Skip 9.1B. Pair them with a stronger partner for the labels. The win: identifying the pillar in 6+ of 8 snippets correctly. Designing-from-pillars (Lab 9.1B) can be revisited later.💬 Discussion Prompts
- If you took ONE pillar away, which would hurt the most? (Decomposition — without it, every program is one giant function. The other three help; decomposition is the foundation. Pros agree: making things smaller is the most important habit.)
- Are these pillars unique to programming? (No! Engineers, designers, even chefs use them. Decomposition is "break the dinner into appetizer/main/dessert." Pattern recognition is "the same sauce works on lots of dishes." Abstraction is "the menu hides the kitchen complexity." Algorithmic design is "the recipe order matters." The pillars name how careful thinkers approach any complex problem.)
- How is "abstraction" different from "lying" or "hiding bugs"? (Good abstractions hide COMPLEXITY but keep the BEHAVIOR honest.
sorted()always returns a sorted list — you don't need to know HOW. A bad abstraction promises one thing but does another. The line is clarity: a good abstraction's documentation tells you exactly what to expect; the rest is hidden by design, not by deception.)
🌍 Real-World Connections
- Engineering disciplines. Civil engineers, electrical engineers, biomedical engineers — all teach the same four pillars under different names. The framework is generalizable to ANY complex-problem-solving job.
- Tech interviews. "Tell me about a time you broke down a big problem" → decomposition. "Have you noticed any patterns in our codebase?" → pattern recognition. Every tech interview implicitly tests these pillars.
- K-12 CS standards. Almost every state CS standards document worldwide names these four pillars (or close variants). Students who know them have a head start in any CS course.
- Architecture & software design. Microservices = decomposition at the system level. Design patterns (e.g., Observer, Factory) = pattern recognition formalized. APIs = abstraction. System diagrams = algorithmic design.
📖 Lesson-Specific Vocabulary
🔍 Lesson 2 · Searching — Linear vs Binary
Lesson 2 · Searching — Linear vs Binary
Lesson PlanAt-a-Glance
Lesson Flow (50 minutes)
🔥 Warm-Up (5 min)
- Project a list of 100 sorted numbers. Pick a number from the middle. Ask: "How would you find it?" Take answers — most will say "loop through each one."
- Reveal: that's linear search. Today we meet binary search — a SMARTER way that finds it in roughly 7 steps instead of 50. Same problem, two solutions, dramatically different scaling.
🎤 Direct Instruction (18 min)
- Open Lesson 9.2 on the projector. Walk through Section 1 ("The Problem — Find an Item in a List"). The setup: a list of items + a target. Goal: return the index, or -1 if not found.
- Walk through Section 2 ("Linear Search — The Honest, Plodding Approach"). Live-code:
def linear_search(items, target): steps = 0 for i, item in enumerate(items): steps += 1 if item == target: return i, steps return -1, steps - Drill: every item gets checked. Worst case: target is at the end (or not present). Step count = list size. O(n) — linear in list size.
- Walk through Section 3 ("Binary Search — Cut the List in Half"). On the whiteboard, draw a sorted list 1–20. Search for 14:
- Look at middle (10). Too small. Throw away left half.
- New range 11–20. Middle is 15. Too big. Throw away right half.
- New range 11–14. Middle is 12. Too small. Right half.
- New range 13–14. Middle is 13. Too small. Right half.
- Range 14–14. Found! 5 steps for 20 items.
- Live-code:
def binary_search(items, target): lo, hi = 0, len(items) - 1 steps = 0 while lo <= hi: steps += 1 mid = (lo + hi) // 2 if items[mid] == target: return mid, steps if items[mid] < target: lo = mid + 1 else: hi = mid - 1 return -1, steps - Drill the precondition: list must be SORTED. If it's not, binary search returns wrong answers. Always.
- Walk through Section 4 ("Search Race — Watch Them Side by Side"). Use the widget. Project. Race them on lists of 10, 100, 1000 items.
- Walk through Section 5 ("How They Scale — The Growth Rate Story"). The KEY insight:
- List of 10 items: linear ~10 steps, binary ~4 steps
- List of 100: linear ~100, binary ~7
- List of 1,000: linear ~1,000, binary ~10
- List of 1,000,000: linear ~1,000,000, binary ~20
- Linear grows LINEARLY (10× more items = 10× more work). Binary grows LOGARITHMICALLY (10× more items = ~3 more steps). The Big O difference is the WHOLE STORY.
- Walk through Section 6 ("Picking Between Them — The Tradeoffs"):
- Use LINEAR when: list is small, or unsorted, or you're searching once
- Use BINARY when: list is sorted (or you'll sort it anyway), large, and searched often
- SORTING costs O(n log n). If you'll search just once, the sort cost defeats the gain.
🤝 Guided Practice (8 min)
- Live-trace binary search for "find 7 in [1, 3, 5, 7, 9, 11, 13]" on the whiteboard:
- lo=0, hi=6, mid=3, items[3]=7 → FOUND. 1 step.
- Now trace "find 11 in [1, 3, 5, 7, 9, 11, 13]":
- lo=0, hi=6, mid=3, items[3]=7 < 11 → lo=4
- lo=4, hi=6, mid=5, items[5]=11 → FOUND. 2 steps.
- Drill: roughly log₂(n) steps. log₂(7) ≈ 2.8 → up to 3 steps in worst case. That's the magic.
💻 Independent Lab (15 min)
- Lab 9.2A — "Implement Both": students implement
linear_searchandbinary_search, both returning(index, steps)tuples. Test on the same sorted list. Print step counts. - Lab 9.2B — "Verify the Scaling": students run both algorithms on lists of size 10, 100, 1000. Make a table of step counts. Confirm: linear grows linearly; binary grows roughly log₂(n).
- Circulate. Common bugs: off-by-one in binary search bounds (using
lo < hiinstead oflo <= hi— misses the last item); forgetting binary search needs sorted input; not handling "not found" case (infinite loop or wrong return). The most common silent bug: returning the WRONG index becausemidwas rounded incorrectly.
🚪 Exit Ticket (5 min)
- On paper: "You have a sorted list of 1 million items. Roughly how many steps does linear search take? Binary search? Why are they so different?"
- Looking for: linear ~1,000,000 (worst case); binary ~20 (log₂(1,000,000) ≈ 20). Different because linear grows ONE-FOR-ONE with list size; binary HALVES the search space each step. With each step, binary throws away half — that exponential decay = logarithmic growth in steps.
⚠️ Watch For — Common Misconceptions
while lo < hi: instead of lo <= hi:. Misses items at the boundaries. OR hi = mid instead of hi = mid - 1. Infinite loop or wrong answer.while lo <= hi: mid = (lo + hi) // 2; ...; lo = mid + 1 or hi = mid - 1. Drill it. Have students trace by hand. Different "flavors" exist; for this course, stick with the canonical.(lo + hi) // 2 can overflow."lo + hi with very large lists would overflow. In Python, integers are arbitrary-precision so this isn't a real issue.(lo + hi) // 2. In C/Java/Go you'd write lo + (hi - lo) // 2 to avoid overflow. Mention as advanced trivia; not required for the course.🎯 Differentiation
For early finishers
Challenge: writerecursive_binary_search — same algorithm, recursive instead of iterative. Stretch: research interpolation search (binary search with a smarter midpoint guess). Implement it for sorted lists of evenly-distributed integers. Compare step counts to plain binary search.
For struggling students
Stay on Lab 9.2A with linear search ONLY. The win: linear search returns the right index AND counts steps correctly. Binary search can be revisited the next day with extra whiteboard tracing.💬 Discussion Prompts
- How does your phone find a contact when you start typing a name? (Modern phones index your contacts. Typing "S" filters to S-names instantly — much faster than scanning all contacts. Behind the scenes, sorted indexes plus binary-search-like lookups make it feel instant. Same algorithm we just learned.)
- Why don't search engines use binary search? (Web pages aren't a sorted list — they're billions of documents with words. Search engines use INVERTED INDEXES — different algorithm class. But: the underlying B-tree indexes Google uses are extensions of binary search ideas. The principle scales; the specific algorithm gets fancier.)
- If linear and binary both find the answer, why does it matter which you use? (Time. On a list of 1 billion items, linear takes minutes; binary takes microseconds. Real systems have huge data — speed matters. Plus: the EFFICIENCY thinking transfers to every problem you'll solve. "How many steps?" is the question pros ask constantly.)
🌍 Real-World Connections
- Database indexes. When you query a database with a WHERE clause, the index is essentially binary search through a B-tree. Same idea: cut the search space in half each step.
- Git's bisect command. When a bug appears,
git bisectuses binary search through commit history to find which commit introduced it. Halving the suspect commits each step. - Phone book. Looking up "Smith" — you don't read every name. You open in the middle, see "M," skip to the back half. Binary search by hand.
- Guess-the-number game. Optimal strategy = binary search. "Higher or lower?" = "left half or right half?" Most games of this type are binary search in disguise.
📖 Lesson-Specific Vocabulary
📊 Lesson 3 · Sorting — Bubble, Selection & Beyond
Lesson 3 · Sorting — Bubble, Selection & Beyond
Lesson PlanAt-a-Glance
sorted() dramatically outperform both at scale (Timsort O(n log n)), apply the rule "use the built-in unless you have a reason not to," and understand the in-place vs new-list distinction.sorted(), In-place vs new listLesson Flow (50 minutes)
🔥 Warm-Up (5 min)
- If using cards: distribute a 7-card hand to each pair. "Sort it ascending — by hand. Do it the way that feels natural." Watch them. Most pairs will use selection sort intuitively (find smallest, swap to front).
- Reveal: today we name what your hands just did. Plus: we meet bubble sort (from Unit 3) again, and discover Python's built-in sort is way faster than either.
🎤 Direct Instruction (18 min)
- Open Lesson 9.3 on the projector. Walk through Section 1 ("Why Sorting Matters"). Sorting enables binary search (Lesson 2). Sorting is the most-used algorithm operation in real systems.
- Walk through Section 2 ("Bubble Sort — A Quick Refresher"). Unit 3 callback. Live-trace bubble sort on 5 numbers. Drill: O(n²). Many comparisons.
- Walk through Section 3 ("Selection Sort — A Different Strategy"). Live-code:
def selection_sort(items): items = items.copy() # don't mutate input n = len(items) comparisons = 0 for i in range(n): min_idx = i for j in range(i + 1, n): comparisons += 1 if items[j] < items[min_idx]: min_idx = j items[i], items[min_idx] = items[min_idx], items[i] return items, comparisons - Walk through what happens. Pass 1: find smallest in [0:n], swap to position 0. Pass 2: find smallest in [1:n], swap to position 1. And so on. Same n²/2 comparisons.
- Walk through Section 4 ("The Sort Race"). Use the widget. Project. Race bubble vs selection on 10, 100, 1000 items. Show step counts grow QUADRATICALLY.
- Walk through Section 5 ("The Punchline — Just Use
sorted()"). Live-demo:import time big_list = [random.randint(1, 1000) for _ in range(10000)] start = time.perf_counter() result = bubble_sort(big_list) # ~5 seconds print(time.perf_counter() - start) start = time.perf_counter() result = sorted(big_list) # ~0.005 seconds print(time.perf_counter() - start)
- The reveal: 1000× faster. Python's
sorted()uses TIMSORT — O(n log n) hybrid algorithm. Don't write your own sort in production. - Walk through Section 6 ("Comparing the Three"):
- List of 10: bubble ~50, selection ~50, sorted() ~30 — all close
- List of 100: bubble ~5,000, selection ~5,000, sorted() ~500
- List of 1,000: bubble ~500,000, selection ~500,000, sorted() ~10,000
- O(n²) is fine for small lists. For anything beyond ~1000 items, use
sorted()or you'll regret it. - Walk through Section 7 ("In-place vs New List"). Two patterns:
list.sort()— modifies in place. Returns None.sorted(list)— returns a NEW list. Original unchanged.
- Drill:
x = my_list.sort()assigns None — common bug.x = sorted(my_list)assigns the sorted list — correct.
🤝 Guided Practice (5 min)
- Quick whiteboard trace: selection sort on [3, 1, 4, 1, 5]:
- Pass 1: find min in [3,1,4,1,5] → idx 1 (value 1). Swap pos 0 ↔ 1. List: [1,3,4,1,5].
- Pass 2: find min in [3,4,1,5] → idx 3 (value 1). Swap pos 1 ↔ 3. List: [1,1,4,3,5].
- Pass 3: find min in [4,3,5] → idx 3. Swap pos 2 ↔ 3. List: [1,1,3,4,5].
- Pass 4: find min in [4,5] → idx 3. No swap. List: [1,1,3,4,5].
💻 Independent Lab (17 min)
- Lab 9.3A — "Implement Selection Sort": students write
selection_sort(items)returning(sorted_list, comparisons). Use.copy()to avoid mutating input. Test on a small list; verify output and comparison count. - Lab 9.3B — "Time the Three": students take their bubble sort from Unit 3 + their new selection sort +
sorted(). Time all three on lists of size 100, 1000, and 5000. Print a table. Verifysorted()is dramatically faster. - Circulate. Common bugs: forgetting
.copy()(mutating the input — second test runs on already-sorted data); off-by-one in the inner loop range (range(i, n)instead ofrange(i + 1, n)— wastes a comparison but still works); confusinglist.sort()withsorted(list)— one returns None.
🚪 Exit Ticket (5 min)
- On paper: "You're sorting a list of 10,000 items. Why should you use
sorted()instead of bubble sort?" - Looking for:
sorted()is O(n log n) — roughly 130,000 comparisons. Bubble sort is O(n²) — roughly 50,000,000 comparisons. ~400× faster. Plus:sorted()is well-tested by thousands of developers; your hand-written sort might have bugs. Use the built-in.
⚠️ Watch For — Common Misconceptions
list.sort() returns the sorted list."x = my_list.sort(). x is None. Then print(x) shows None and student is confused.list.sort() sorts IN PLACE and returns None. Like list.append() — modifies, doesn't return. To get a sorted COPY: use sorted(my_list). The two have different semantics. Drill the distinction..copy() in benchmarks."list.copy() to each algorithm. Or build a fresh shuffled list per algorithm. The capstone's algorithms.py uses .copy() at the top of each sort to enforce this.sorted()."sorted() is implemented in C, decades-tuned, hybrid algorithm (Timsort — combines merge sort and insertion sort optimally). NO student-written Python sort beats it. Ever. Use the built-in. The exception: writing your own for LEARNING purposes (which is exactly what Unit 3 and Unit 9 do).🎯 Differentiation
For early finishers
Challenge: research insertion sort. How does it differ from selection sort? Implement it. Stretch: read the Wikipedia entry on Timsort. What makes Timsort hybrid? Why does it adapt to partially-sorted data? Write a 3-sentence summary.For struggling students
Stay on Lab 9.3A. Skip the timing comparison. The win: a working selection sort that handles a list of 5 items correctly. The Big O scaling discussion can be revisited.💬 Discussion Prompts
- If
sorted()is so much better, why teach bubble and selection at all? (LEARNING. Understanding HOW sorting works helps you understand WHYsorted()exists. You'll meet sorting algorithms throughout your CS career — the basic ones are stepping stones to the fancier ones (merge, quick, heap, Timsort). Plus: in interviews, you might be asked to implement one. Pros know how it works even when they use the built-in.) - What if your data is "almost sorted"? (Bubble sort with the early-exit optimization is FAST on near-sorted data — close to O(n). Insertion sort is similar. Timsort actively detects partially-sorted runs and merges them — that's why it dominates real-world data, which is rarely random.)
- Could you ever beat Timsort? (For SPECIAL CASES yes. If you know your data's shape (e.g., integers in 0–100), counting sort is O(n) — faster than O(n log n). For general comparison-based sorting on unknown data, no, you won't beat it. The lesson: use built-ins for general work, write custom only when you know your data's structure.)
🌍 Real-World Connections
- Search engine results. Google sorts billions of pages by relevance score. Even at that scale, sorting is the bottleneck — and elaborate sorting algorithms make Google fast.
- Excel/Google Sheets. Click "Sort A→Z" on a column. Behind the scenes: Timsort or similar. Fast on huge spreadsheets.
- Database query optimization. ORDER BY uses B-tree indexes (binary-search-like) plus efficient merge sorts. Slow ORDER BY = missing index. The DB engine picks the right algorithm.
- Game leaderboards. Top 100 players sorted by score. With millions of players, bubble sort would be impossibly slow. Game backends use Timsort or quicksort variants.
📖 Lesson-Specific Vocabulary
list.sort() mutates and returns None; sorted(list) returns a new list.🔢 Lesson 4 · Binary, Logic Gates & Sets
Lesson 4 · Binary, Logic Gates & Sets
Lesson PlanAt-a-Glance
and, or, not, != or ^), use Python's set type for unique items + fast membership, and apply set operations (union, intersection, difference, symmetric difference).Lesson Flow (55 minutes)
🔥 Warm-Up (5 min)
- Project a photo. Ask: "What is this REALLY, inside the computer?" Take answers. Walk back: "It's a grid of pixels. Each pixel is a number. Each number is bits." Project:
1010 0101 1100 0011...Reveal: every photo, every game, every Python program — JUST BITS. - Reveal: today we peek under Python's hood. Three topics that look like math class — binary, logic gates, sets — that are actually the foundation EVERY program runs on.
🎤 Direct Instruction — Binary (12 min)
- Open Lesson 9.4 on the projector. Walk through Section 1 ("Binary Numbers"). On the whiteboard, draw the place-value table:
128 64 32 16 8 4 2 1 1 0 1 1 0 0 1 1 → 128+32+16+2+1 = 179
- Drill: each binary place is a power of 2, just like decimal places are powers of 10. Convert 179 to binary by figuring out which powers of 2 add up to 179.
- Walk through Section 2 ("Binary Converter"). Use the widget. Project. Convert 5, 13, 100, 255 to binary. Have students predict before reveal.
- Walk through Section 3 ("Binary in Python"). Live-code:
print(bin(5)) # '0b101' print(int("101", 2)) # 5 print(0b1011) # 11 (Python supports binary literals) - Drill:
bin()andint(_, 2)are the conversion functions. The0bprefix means "binary literal."
🎤 Direct Instruction — Logic Gates (12 min)
- Walk through Section 4 ("Logic Gates"). On the whiteboard, draw the truth tables for all 4:
A B │AND OR NOT(A) XOR 0 0 │ 0 0 1 0 0 1 │ 0 1 1 1 1 0 │ 0 1 0 1 1 1 │ 1 1 0 0
- Drill the four:
- AND: 1 only when BOTH are 1. Python
and. - OR: 1 when EITHER is 1. Python
or. - NOT: flips the input. Python
not. - XOR: 1 when EXACTLY ONE is 1. Python
!=or^(bitwise).
- AND: 1 only when BOTH are 1. Python
- Walk through Section 5 ("Logic Gate Playground"). Use the widget. Project. Click through inputs; watch the gates respond.
- Walk through Section 6 ("Why XOR Is Special"). Three special powers:
- Encryption: XOR a message with a key, XOR with the same key again → get the message back. Foundation of one-time pads.
- Image masks: Photoshop layer combinations.
- Error detection: Parity bits use XOR.
- Live-demo the encryption trick:
secret = 42 key = 99 encrypted = secret ^ key # 73 decrypted = encrypted ^ key # 42 — magic!
🎤 Direct Instruction — Sets (12 min)
- Walk through Section 7 ("Sets"). Sets in math = collections of unique items, no order. Python's
settype captures the same idea + adds blazingly fast membership. - Live-code the basics:
my_set = {1, 2, 3} my_set.add(4) my_set.add(2) # already in; ignored print(2 in my_set) # True (very fast) print(len(my_set)) # 4 - Walk through Section 8 ("Set Operations"). Math meets code:
a | b— UNION (everything from both)a & b— INTERSECTION (only in both)a - b— DIFFERENCE (in a, not in b)a ^ b— SYMMETRIC DIFFERENCE (in either, not both)
- Walk through Section 9 ("Study Buddies Problem"). Worked example tying it all together:
my_subjects = {"math", "english", "history"} their_subjects = {"english", "math", "art"} shared = my_subjects & their_subjects # {math, english}
💻 Independent Lab (10 min)
- Lab 9.4A — "Binary & Gates": students implement four functions
AND,OR,NOT,XORthat take 0/1 inputs. Print all four truth tables. Bonus: verify the double-XOR-cancels property. - Lab 9.4B — "Set Operations Practice": students get two sets of skills (their own + a job posting). Use set operations to find: skills they have that match (intersection), skills they're missing (difference), all skills involved (union).
- Circulate. Common bugs: writing
NOTas!a(Python usesnot); using{}for an empty set (that's an empty DICT — useset()); confusing|withor(the operator vs keyword).
🚪 Exit Ticket (4 min)
- On paper: "Convert decimal 13 to binary. Then write the truth table for AND. Finally, what does
{1, 2, 3} & {2, 3, 4}return?" - Answers: 13 = 1101 (8+4+1). AND truth table: 0 0 → 0; 0 1 → 0; 1 0 → 0; 1 1 → 1. Set intersection =
{2, 3}.
⚠️ Watch For — Common Misconceptions
{} is an empty set."my_set = {} — but that's an empty DICT. type(my_set) shows dict.set() (the constructor). Non-empty: {1, 2, 3} works. The brace ambiguity: {} defaults to dict. Drill: empty set ALWAYS uses set().my_set[0]. Crashes — sets don't support indexing.[0], no slicing. To get an item by position, convert to list: list(my_set)[0]. Or use a different structure (list, tuple) if order matters.and with &."True & False works (returns False) but conflates two different operators.and / or / not are LOGICAL operators (booleans). & / | / ^ are BITWISE / SET operators. They're related but distinct. For if-statements: use and. For sets: use &. For bit manipulation: use &.🎯 Differentiation
For early finishers
Challenge: implement a functionencrypt(text, key) that XORs each character of a string with a numeric key. Decrypt the same way. Stretch: research bitwise operators (<<, >>) and explain how to multiply by 2 without using *.
For struggling students
Stay on Lab 9.4A's binary section only. Skip the gates and sets. The win: converting decimal 13 and 25 to binary by hand correctly. Logic gates and sets can be revisited the next day.💬 Discussion Prompts
- Why don't computers use decimal directly — why bother with binary? (Hardware. Transistors are like switches: ON or OFF, two states. Binary maps directly to that. Decimal would need 10 distinguishable voltage levels per "digit" — way harder to build reliably. Binary won because it matches the physics of digital circuits.)
- If sets ignore order and duplicates, when SHOULDN'T you use a set? (When order matters — to-do lists, music playlists, conversation logs. When duplicates matter — counts of words, repeated events. When you need indexing — sets don't support
[0]. Use lists for ordered/duplicate-friendly data; sets for unique-membership data.) - Why is
x in my_setfaster thanx in my_list? (Sets use HASH TABLES internally — Python computes a hash of x and jumps to a specific bucket. O(1) average. Lists check items one by one. O(n). For membership tests on large data, sets are dramatically faster. The "in" operator looks the same; the underlying mechanics differ wildly.)
🌍 Real-World Connections
- Image files. A 1080p photo is ~6 megabytes — tens of millions of bits. Each pixel = 24 bits (8 each for red/green/blue). Compression algorithms reduce this dramatically; binary thinking underlies them all.
- CPU instructions. Every CPU instruction is binary. Add two numbers? AND/OR/XOR gates implement the addition circuit. Modern CPUs have billions of gates.
- Network protocols. Internet packets are sequences of bits with specific structures. The IP header has flags that are individual bits — checked with bitwise operators.
- SQL DISTINCT and JOIN. Database operations like DISTINCT (find unique rows) and INTERSECT (find rows in both queries) are set operations. Same math as Python sets, applied to billions of rows.
📖 Lesson-Specific Vocabulary
|), intersection (&), difference (-), symmetric difference (^).⚡ Lesson 5 · Algorithm Playground Capstone
Lesson 5 · Algorithm Playground Capstone
Project PlanAt-a-Glance
time.perf_counter(), and a menu-driven main file. The tool races algorithms head-to-head, measuring step counts AND wall-clock time, with side-by-side reports. Students apply benchmark hygiene (run multiple times, average, same input, no print() inside timed sections) and integrate every Unit 9 idea into one working tool.time.perf_counter(), plus all prior Unit 9 vocabularyalgorithms.py + bench.py + main.py) is smaller than Unit 8's 4-file Weather Dashboard, but the BENCHMARK HYGIENE is the unique skill — students learn that bad benchmarks produce wrong answers. Day 1 = Plan + Code algorithms.py. Day 2 = Code bench.py + main.py. Day 3 = Test + Fix + Maintain + Showcase.
Project Flow (90+ min across 2–3 days)
📅 Day 1 — Benchmark Theory + Plan + Code algorithms.py (45 min)
- Warm-up (5 min): Project the Lesson 3 timing demo. "How could we make a TOOL that runs comparisons reliably?" Take answers. Reveal: today we build that tool. Three files. Each does one thing.
- Benchmark theory (10 min): Walk through Lesson 9.5 Section 1 (Benchmarking) and Section 2 (Pitfalls). The three rules:
- Run multiple times and AVERAGE (single measurements are noisy)
- Use the SAME input data for all algorithms (apples to apples)
- Don't measure
print()(printing is slow; dominates the measurement)
- Plus the bonus pitfall: sorts MUTATE inputs. Always pass
list.copy()to each. - SDLC Stage 1 — Plan (5 min): Distribute paper. 6-question planning checklist:
- Three files in same folder: algorithms.py, bench.py, main.py
- List sizes: 100, 1,000, 10,000 (small enough to finish; big enough to see scaling)
- Number of timing runs: 5 (averages out noise)
- Data: random integers from 1 to
list_size × 10 - Menu actions: 1 Compare searches, 2 Compare sorts, 3 Change list size, 4 Quit
- Output: aligned table with Algorithm / Steps / Avg Time (ms) / Speedup vs slowest
- SDLC Stage 2 — Code (25 min) — algorithms.py: Pure functions, no I/O. Copy linear_search and binary_search from Lab 9.2; copy bubble_sort from Unit 3 + selection_sort from Lab 9.3. Each returns a tuple
(result, count). Sorts use.copy()at the top to avoid mutation. NO print() statements. Each function gets a docstring. Test each in isolation.
📅 Day 2 — Code bench.py + main.py + Run First Benchmark (45 min)
- Code bench.py (15 min): Imports algorithms.py. Two functions:
bench_search(fn, items, target)→ dict with name/found_at/steps/avg_time_ms. Run RUNS=5 times withtime.perf_counter(). Average.bench_sort(fn, items)→ dict with name/comparisons/avg_time_ms. Same pattern but passitems.copy()on each run.
- Drill: timing block is JUST the algorithm call. Nothing else inside
start = time.perf_counter() ... end = time.perf_counter(). - Code main.py (15 min): Imports bench.py. The orchestrator:
- Menu loop with 4 options
- Build random list (use
random.randint, callback to Unit 6) - For "Compare searches": pick a target, call bench_search for both linear and binary, print report
- For "Compare sorts": call bench_sort for bubble, selection, sorted; print report
- print_report(results) prints aligned columns: Algorithm / Steps / Time (ms) / Speedup
- Run first benchmark (15 min): Pick list size 1,000. Run "Compare searches." See linear ~500 steps avg, binary ~10 steps. Run "Compare sorts." See bubble/selection ~250,000 comparisons, sorted() in microseconds. Audible "whoa" from class. Real data confirms predictions.
📅 Day 3 — Test + Fix + Maintain + Showcase (45 min)
- SDLC Stage 3 — Test (15 min): Run all 10 test cases:
- Algorithms work on small lists (size 10) — known correct results
- Search returns -1 on missing target
- Search returns correct index when target is present
- Sort returns sorted list (verify with assertion)
- Step counts match predictions: linear ≈ list size when target at end; binary ≈ log₂(size); bubble/selection ≈ n²/2
- Bench harness runs RUNS=5 times
- Timings are stable across runs (within ~10%)
- Menu invalid input doesn't crash
- Sorts don't MUTATE the input (test #9 — the mutation hygiene check)
- Repeated runs of "Compare sorts" produce stable timings (test #10)
- SDLC Stage 4 — Fix (10 min): Common Day 3 bugs: forgetting
.copy()on sorts (test #9 catches this); mutating the input by accident; printing inside timed section (timings dominated by print); off-by-one in binary search (test #5 catches); wrong step counts in selection sort. - SDLC Stage 5 — Maintain (10 min): Polish. Docstring on every function. Constants in ALL_CAPS (RUNS, SIZES). Organized imports. README.md describing how to run.
- Showcase & Submit (10 min): Pick 3–5 volunteers. Run their playground. Compare searches at size 10,000 — watch binary destroy linear. Compare sorts — watch
sorted()destroy bubble. Different students' formatted output — different speedup columns, different visual styles. Standard 05.06 (multiple algorithms) made literal: this tool LITERALLY shows multiple algorithms running.
⚠️ Watch For — Common Project Pitfalls
print() inside the timed block."print("checking item", i) inside the algorithm. Timings are dominated by print speed (microseconds → milliseconds)..copy() on sorts."items = items.copy(). The capstone's algorithms.py functions all do this. Mark it on the rubric — 15 of 100 points.sum(times) / len(times). Drill: averaging is what makes benchmarks reliable..copy() for sorts) to every algorithm. Apples to apples. Drill: same input, all algorithms.while lo <= hi, mid = (lo + hi) // 2, lo = mid + 1 or hi = mid - 1. Drill it. Test on the boundaries.🎯 Differentiation
For students who finish early
Direct them to stretch goals: add insertion sort and benchmark the three n²-sorts (bubble vs insertion vs selection). Save results to JSON (Unit 6 callback) and build a separateview_log.py. Add ASCII bar charts to print_report. Add multiple list sizes at once (scaling test). String data benchmarks. The big one: real-data benchmark from a CSV file. Each adds +5 pts (max +25).
For struggling students
It's OK if their version handles ONLY one comparison (searches OR sorts, not both). They still demonstrate the 3-file architecture, benchmark hygiene, and Big O scaling. Partial credit for genuine algorithm comparison — the working pipeline (build data → run algorithms → print report) is the core demonstration.💬 Discussion Prompts
- Why three files instead of one? (Three concerns: algorithms (no I/O), benchmarking (timing harness), UI (menu). Each file does ONE thing. Want to add an algorithm? Edit algorithms.py only. Want to change timing approach? bench.py only. Want a different menu? main.py. The same modular thinking that made Quest Heroes and Weather Dashboard maintainable.)
- What does the "speedup" column tell you that step counts don't? (Step counts tell the THEORETICAL story — what the algorithm does in pure terms. Wall-clock time tells the PRACTICAL story — what actually happens on a real CPU with real cache effects, function-call overhead, memory access patterns. Sometimes step count is identical but timing differs: Python list.append is slower than tuple creation; cache-friendly algorithms beat algorithms with random access. Real engineers measure both.)
- If you ran your benchmark on a different computer, would the times match? (NO. Different CPUs, different cache sizes, different OSs — timings vary. But the RATIOS and the ORDER are stable: linear is always slower than binary; bubble is always slower than sorted(). The Big O comparisons are universal; the specific milliseconds aren't. That's why we report ratios (speedup) — they're portable.)
🌍 Real-World Connections
- Database query planners. When you write SQL, the database PLANS multiple ways to execute it, ESTIMATES the cost of each, picks the cheapest. Same idea: race the algorithms, pick the winner.
- Compiler optimization. Modern compilers benchmark different code-generation strategies and pick the fastest. They run mini-benchmarks at compile time.
- JIT (Just-In-Time) compilers. JavaScript engines (V8) and Java JVMs profile your code at runtime, identifying hot loops, then re-compile them with optimized algorithms.
- Resume bullet point. "Built a 3-file Python benchmark tool measuring algorithm performance with step counts and wall-clock timings." Real software engineering. Real data.
📋 Algorithm Playground Project Rubric (100 points)
The rubric matches the one in the student lesson exactly. Share with students at the start of Day 1.
| Category | What to look for | Pts |
|---|---|---|
| Three-File Architecture | Code split across algorithms.py + bench.py + main.py. Imports work cleanly. Each file has a single concern. | 10 |
| Pure Algorithm Functions | All four algorithms (linear search, binary search, bubble sort, selection sort) implemented correctly. No printing inside them. Sorts use .copy() so they don't mutate input. | 15 |
| Step / Comparison Counters | Every algorithm returns a tuple (result, count). Counts match expected values: linear ≈ list size when target is at end, binary ≈ log₂(size), bubble/selection ≈ n²/2. | 15 |
| Benchmark Harness | bench.py uses time.perf_counter() correctly, runs each algorithm RUNS=5 times, averages the timings, and returns clean dicts. | 15 |
| Menu & Reports | CLI menu loop with 4 options. Compare-searches and compare-sorts both work. Reports print as aligned tables with Algorithm/Steps/Time/Speedup columns. | 15 |
| Performance Predictions | Output matches Lesson 9.2/9.3 predictions: binary much faster than linear; sorted() much faster than bubble/selection. Speedup column makes the difference visible. | 10 |
| Robustness | Invalid menu input doesn't crash. Letters at the size prompt are handled. Searches for nonexistent targets cleanly return -1. | 10 |
| Clean Code Style | Docstrings on every function, organized imports, snake_case naming, ALL_CAPS for constants, no global state, no print() inside algorithms. | 5 |
| Works Correctly | All 10 test cases from Stage 3 pass. Especially: no mutation bugs (test #9), repeated runs are stable (test #10). | 5 |
| TOTAL | 100 | |
🎁 Stretch Goals (extra credit)
- Add insertion sort + benchmark all three n²-sorts: +5 pts
- Save benchmark results to JSON (with timestamp, Unit 6 callback): +5 pts
- Text-based ASCII bar chart in print_report: +5 pts
- Multi-size scaling test (run sizes 100, 1k, 10k in one go): +5 pts
- String-data benchmarks (sort/search lists of names): +5 pts
- Real-data benchmark from a CSV file (10,000 names, Unit 6 callback): +5 pts
Maximum stretch credit: +25 points. Document each stretch in a README.md with what you built and how it changes the tool.
sorted() is 1000× faster than bubble" moment. Project several students' reports back to back. Same algorithms, slightly different timings (different machines), but always the same RATIOS — the Big O ordering is universal. This is exactly the experience a CS professor's algorithm class produces — your students built that tool.
📖 Lesson-Specific Vocabulary
🛠️ Appendix · Common Python Errors in Unit 9
This appendix lists the most common Python error messages students will see in Unit 9. Algorithm-specific bugs include in-place mutation surprises, off-by-one errors in binary search bounds, the silent bug of comparing different-shape inputs, set vs dict literal confusion, and the dreaded "I optimized the wrong thing" lesson. Apply Unit 4's 4-step strategy: Reproduce → Read → Hypothesize → Fix & Verify, ONE change at a time.
What it usually means in Unit 9: Student wrote x = my_list.sort(). list.sort() mutates in place and returns None. Then for item in x or x[0] crashes.
How to fix: Use sorted(my_list) when you want a returned sorted COPY. Use my_list.sort() only when you want the in-place mutation and don't need the return value. Drill the distinction.
What it usually means: Off-by-one in binary search bounds. hi = len(items) instead of len(items) - 1. Then items[hi] on the last comparison crashes.
How to fix: Canonical form: lo, hi = 0, len(items) - 1 with while lo <= hi. Drill the canonical pattern; trace boundary cases by hand.
What it usually means: Tried to sort or search a list with mixed types. sorted([1, "two", 3]) crashes — Python won't compare ints to strings.
How to fix: Ensure list items are comparable. Convert to strings (sorted(items, key=str)) or filter to one type. Or use key= with a custom function.
What it usually means: 0b102 (digit other than 0 or 1 in binary literal) or {1: 2, 3} (mixed dict and set syntax in one literal).
How to fix: Binary literals only have 0s and 1s. Set literals are {1, 2, 3}; dict literals are {"key": value}. The presence of a colon makes it a dict; commas alone make it a set.
{} creates a dict, not a set)What it usually means: my_set = {}. Student expected an empty set; got an empty dict. my_set.add(1) crashes with AttributeError.
How to fix: Empty set: set(). Drill: empty curly braces are dict; empty parens with set keyword are set.
What it usually means: Bench function passed the same list to bubble and selection sequentially. Bubble sorted it. Selection ran on already-sorted data. Timings are wrong.
How to fix: Pass items.copy() on every algorithm call in the bench harness. The capstone's algorithms.py also does items = items.copy() as the first line of each sort. Belt and suspenders.
print() inside timed block dominates measurement)What it usually means: print() takes microseconds; algorithms might take nanoseconds. The print swamps the actual measurement.
How to fix: NO print() inside the timed section. Algorithms should be silent. Only main.py prints reports.
What it usually means: Student wrote hi = mid instead of hi = mid - 1 (or lo = mid instead of lo = mid + 1). Bounds never shrink past mid.
How to fix: Always lo = mid + 1 or hi = mid - 1. The mid index has been checked; exclude it from the next iteration. Drill the canonical pattern.
What it usually means: Bench function ran each algorithm ONCE. Timings hopping around. Comparisons unreliable.
How to fix: Run RUNS=5 (or 10). Average the times. sum(times) / len(times). Drill: average is what makes benchmarks stable.
Watch list — these still happen in Unit 9 capstones:
- Bare
except:— Unit 6 anti-pattern. Always name the exception. - Forgetting
selfin method def lines — Unit 7 carryover. - Missing
timeout=on requests calls — but Unit 9 doesn't use requests, so not common here. - Indentation errors when functions and loops nest deeply.
- Circular imports — keep dependencies one-way: main.py imports bench.py imports algorithms.py. algorithms.py imports nothing project-local.
.copy(). (B) "Is the timing stable across multiple runs?" Run the same benchmark 3 times. If timings vary by >20%, increase RUNS, close other apps, or use a quieter test environment. Stable measurement is what separates real benchmarks from anecdotes.
— End of Unit 9 Teacher's Guide —
