3.09 Developing Algorithms

Source lesson: csp/python/developing-algorithms

Learning Objective: Decide whether two algorithms are equivalent by testing and tracing, and build new algorithms by modifying and combining known patterns.

Submission notes

  • Lesson: CSP 3.09 Developing Algorithms
  • Notebook: https://jupiterian.opencodingsociety.com/python/developing-algorithms-hw
  • MCQ 3.09: 4/4 answers: C,B,C,B
  • Popcorn Hacks 1-3 completed in class and copied to notebook: yes
  • Homework output: Restock needed: / Blankets: need 12 / Shampoo: need 10 / Total items needed: 22 / Most urgent: Blankets (short by 12)

Popcorn

Popcorn Hack 1: Translate pseudocode to Python

Prediction: 3 + 5 + 2 + 4 = 14, and 14 / 4 = 3.5

Code Runner Challenge

3.09 Popcorn 1 - Translate the pseudocode into Python

View IPYNB Source
# CODE_RUNNER: 3.09 Popcorn 1 - Translate the pseudocode into Python
# Step 1: make the hours list
hours = [3, 5, 2, 4]

# Step 2: start total at 0
total = 0

# Step 3: FOR EACH -> for loop, add each h to total
for h in hours:
    total = total + h

# Step 4: LENGTH(hours) -> len(hours), compute the average
average = total / len(hours)

# Step 5: print total, then average
print(total)
print(average)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Actual output: 14 and 3.5. FOR EACH h IN hours turns into for h in hours:, and LENGTH turns into len.

Popcorn Hack 2: Predict, then fix

Prediction (before running the original): 1. With count > capacity, 12 isn’t greater than 12, so Self-Defense doesn’t get counted and only Fitness (15) does.

Fix: changed > to >= so a workshop at exactly 12 counts as full.

Code Runner Challenge

3.09 Popcorn 2 - Predict, then fix the full-workshop counter

View IPYNB Source
# CODE_RUNNER: 3.09 Popcorn 2 - Predict, then fix the full-workshop counter
signed_up = [12, 7, 15, 9]   # Self-Defense, Parenting Skills, Fitness, Self-Sufficiency
capacity = 12

full = 0
for count in signed_up:
    if count >= capacity:    # was >, which skipped the workshop at exactly 12
        full = full + 1

print("Full workshops:", full)
# My prediction before running: 1 (the original > misses Self-Defense at 12)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Actual output: Full workshops: 2 after the fix (the original printed 1, same as my prediction). It’s a one-character bug that doesn’t cause any error, it just gives the wrong count at the boundary.

Popcorn Hack 3: Modify the counter into a collector

Code Runner Challenge

3.09 Popcorn 3 - Modify the counter into a collector

View IPYNB Source
# CODE_RUNNER: 3.09 Popcorn 3 - Modify the counter into a collector
workshops = ["Self-Defense", "Parenting Skills", "Fitness", "Self-Sufficiency"]
signed_up = [12, 7, 15, 9]     # signed_up[0] goes with workshops[0], and so on
capacity = 12

# collect names instead of counting
open_workshops = []
for i in range(len(workshops)):
    if signed_up[i] < capacity:
        open_workshops.append(workshops[i])

# print how many, then the list
print("Workshops with open seats:", len(open_workshops))
print(open_workshops)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Actual output: Workshops with open seats: 2 and ['Parenting Skills', 'Self-Sufficiency']. Self-Defense is at exactly 12 so < 12 leaves it out. The loop and the if are the same as a counter, the only thing that changed is count = count + 1 became open_workshops.append(...).

MCQ

**MCQ 3.09: 4/4 answers: C,B,C,B**

1. What does this code print?

Code Runner Challenge

3.09 Homework - Safe Passage Heals supply restock report

View IPYNB Source
gifts = [20, 120, 60]
count = 0
for g in gifts:
    if g >= 100:
        count = count + 1
    count = count + 1
print(count)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

A 1 · B 3 · C 4 · D 2

Answer: C. The last line is outside the if so it runs for all 3 gifts, plus 1 more for the $120 gift. 3 + 1 = 4.

2. Both return 60. Which one has a side effect on the list passed in? (top_a returns max(amounts), top_b does amounts.sort() then returns amounts[-1])

A top_a · B top_b · C Both · D Neither

Answer: B. max() only reads the list, sort() rearranges the original list.

3. A workshop holds 10. A checks signed_up < 10, B checks signed_up <= 10. Which input proves they are NOT equivalent?

A 5 · B 9 · C 10 · D 15

Answer: C. At exactly 10 they disagree. Every other input gives the same answer.

4. You change a working count-low-supplies algorithm so it appends each low item to a list and returns the list. In College Board terms, you:

A Created one from scratch · B Modified an existing algorithm · C Combined two algorithms · D Made them equivalent

Answer: B. The loop and condition stayed the same, only what it tracks changed.

Homework

Homework Hack: Supply closet restock report

Combines three patterns: collect the items below target, sum the shortages, and find the max shortage, then picks between “Fully stocked!” and the report.

Prediction:

  • Toothbrushes 40/30 and Notebooks 30/30 aren’t short
  • Socks is 25/25, exactly at target, so 25 < 25 is False and it’s not short either
  • Blankets needs 20 - 8 = 12, Shampoo needs 15 - 5 = 10
  • Total 22, most urgent is Blankets (12)

Code Runner Challenge

3.09 Homework - Test 2: fully stocked

View IPYNB Source
# CODE_RUNNER: 3.09 Homework - Safe Passage Heals supply restock report
items    = ["Toothbrushes", "Blankets", "Socks", "Shampoo", "Notebooks"]
in_stock = [40, 8, 25, 5, 30]      # in the closet now
target   = [30, 20, 25, 15, 30]    # what staff want on hand

# Step 1: COLLECT items below target, and how many of each are needed
short_items = []
short_amounts = []
for i in range(len(items)):
    if in_stock[i] < target[i]:
        short_items.append(items[i])
        short_amounts.append(target[i] - in_stock[i])

# Step 2: SUM the shortages with a loop (no sum())
total_needed = 0
for amount in short_amounts:
    total_needed = total_needed + amount

# Step 3: FIND THE MAX shortage (track its position so you know the item's name)
most_urgent = 0
for i in range(len(short_amounts)):
    if short_amounts[i] > short_amounts[most_urgent]:
        most_urgent = i

# Step 4: COMBINE: print "Fully stocked!" if nothing is short, otherwise the report
if len(short_items) == 0:
    print("Fully stocked!")
else:
    print("Restock needed:")
    for i in range(len(short_items)):
        print(f"{short_items[i]}: need {short_amounts[i]}")
    print("Total items needed:", total_needed)
    print(f"Most urgent: {short_items[most_urgent]} (short by {short_amounts[most_urgent]})")
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Actual output:

Code Runner Challenge

3.09 Homework - Test 3: Shampoo most urgent

View IPYNB Source
Restock needed:
Blankets: need 12
Shampoo: need 10
Total items needed: 22
Most urgent: Blankets (short by 12)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Matches the expected output exactly.

For the max I track the position (most_urgent) instead of the amount, since short_items and short_amounts line up by index, so the position gives me both the name and the number.

Tests

Each test is a fresh run where only in_stock changes.

Test 1: Main: the homework cell above. Blankets 12, Shampoo 10, total 22, most urgent Blankets.

Test 2: Nothing is short

Prediction: every item is at or above target, so it should print Fully stocked! and nothing else.

# CODE_RUNNER: 3.09 Homework - Test 2: fully stocked
items    = ["Toothbrushes", "Blankets", "Socks", "Shampoo", "Notebooks"]
in_stock = [40, 20, 25, 15, 30]      # in the closet now
target   = [30, 20, 25, 15, 30]    # what staff want on hand

# Step 1: COLLECT items below target, and how many of each are needed
short_items = []
short_amounts = []
for i in range(len(items)):
    if in_stock[i] < target[i]:
        short_items.append(items[i])
        short_amounts.append(target[i] - in_stock[i])

# Step 2: SUM the shortages with a loop (no sum())
total_needed = 0
for amount in short_amounts:
    total_needed = total_needed + amount

# Step 3: FIND THE MAX shortage (track its position so you know the item's name)
most_urgent = 0
for i in range(len(short_amounts)):
    if short_amounts[i] > short_amounts[most_urgent]:
        most_urgent = i

# Step 4: COMBINE: print "Fully stocked!" if nothing is short, otherwise the report
if len(short_items) == 0:
    print("Fully stocked!")
else:
    print("Restock needed:")
    for i in range(len(short_items)):
        print(f"{short_items[i]}: need {short_amounts[i]}")
    print("Total items needed:", total_needed)
    print(f"Most urgent: {short_items[most_urgent]} (short by {short_amounts[most_urgent]})")

Actual output: Fully stocked!

Test 3: A different item is most urgent

Prediction: with only 2 Shampoo it’s short by 13, which beats Blankets (12), so the max should switch to Shampoo. Total 12 + 13 = 25.

# CODE_RUNNER: 3.09 Homework - Test 3: Shampoo most urgent
items    = ["Toothbrushes", "Blankets", "Socks", "Shampoo", "Notebooks"]
in_stock = [40, 8, 25, 2, 30]      # in the closet now
target   = [30, 20, 25, 15, 30]    # what staff want on hand

# Step 1: COLLECT items below target, and how many of each are needed
short_items = []
short_amounts = []
for i in range(len(items)):
    if in_stock[i] < target[i]:
        short_items.append(items[i])
        short_amounts.append(target[i] - in_stock[i])

# Step 2: SUM the shortages with a loop (no sum())
total_needed = 0
for amount in short_amounts:
    total_needed = total_needed + amount

# Step 3: FIND THE MAX shortage (track its position so you know the item's name)
most_urgent = 0
for i in range(len(short_amounts)):
    if short_amounts[i] > short_amounts[most_urgent]:
        most_urgent = i

# Step 4: COMBINE: print "Fully stocked!" if nothing is short, otherwise the report
if len(short_items) == 0:
    print("Fully stocked!")
else:
    print("Restock needed:")
    for i in range(len(short_items)):
        print(f"{short_items[i]}: need {short_amounts[i]}")
    print("Total items needed:", total_needed)
    print(f"Most urgent: {short_items[most_urgent]} (short by {short_amounts[most_urgent]})")

Actual output: Blankets 12, Shampoo 13, total 25, Most urgent: Shampoo (short by 13).

Test in_stock Expected Actual Pass
Main [40, 8, 25, 5, 30] Blankets 12, Shampoo 10, total 22, most urgent Blankets same Yes
Fully stocked [40, 20, 25, 15, 30] Fully stocked! Fully stocked! Yes
Different max [40, 8, 25, 2, 30] total 25, most urgent Shampoo (13) same Yes

Socks stays at exactly 25/25 in every test and never shows up, so the boundary works. With <= it would’ve been listed as “Socks: need 0”.

Design Thinking

Step Notes
Need Before a donation drive, Safe Passage Heals staff need to know what’s missing from the supply closet and what to ask for first.
Goal One report that lists only the short items, the total to collect, and the most urgent item, or just says “Fully stocked!” if nothing’s missing.
Methods considered Built-in sum() / max() vs. writing the loops myself (the lesson wants loops), and tracking the max amount vs. tracking its position.
Prototype Three separate loops (collect, sum, max) and an if / else to combine them.
Test My first version of Step 3 tracked the biggest amount, which gave me 12 but not which item it belonged to.
Revision Switched to tracking the index (most_urgent) so I can pull the name and amount from the two lists. Then reran all 3 tests, including the Shampoo one, to make sure the max actually moves.