60 minutes · Cambridge 0478/0984/2210 · Paper 2 — Algorithms, Programming and Logic
🎯 Syllabus & Goals 3 min
Cambridge 7.9 · Write and amend algorithmsPaper 2 · Algorithms, Programming and Logic
By the end of this lesson you can:
Follow the eight stages for producing an algorithm from a problem statement.
Write a complete algorithm as a structure diagram, a flowchart, pseudocode and Python, and test it.
Amend an existing algorithm to meet a new requirement, including nested loops.
Textbook: Chapter 7, §7.9 (pp. 288–292)
Recap / Warm-Up 5 min
This lesson pulls the whole unit together: decomposition, diagrams, pseudocode, standard methods, validation, test data and trace tables — all in one algorithm.
Quick starter
Which is more precise in an algorithm: "repeat until the counter is ten or over" or UNTIL Counter >= 10? Why does it matter?
Reveal the answer
UNTIL Counter >= 10. It has only one meaning, so any programmer codes it the same way — the words could be misread.
🧠 Key Concept 14 min
1 · Eight stages from problem to algorithm
Stages 7 and 8 loop: dry run, correct, dry run again, until the algorithm works for every set of test data.
Stage 2 splits almost every problem into the same five parts:
Set up
initialise totals, counters, flags
Input
with validation where needed
Process
calculate, select, repeat
Store
permanent storage, if required
Output
the results the user needs
2 · Writing it so others can read it
Meaningful names:ItemPrice, not X.
Precise conditions:Counter >= 10, not "counter ten or over".
Comments start with // and explain why, e.g. // reject prices over $50.
Indentation shows what is inside each loop and IF.
If the question says "use pseudocode" or "draw a flowchart", use that method.
3 · Amending an algorithm
To amend is to change an existing algorithm to meet a new requirement. Work out where the change belongs, add any new variables with a starting value, and change only what is needed. Then re-test with the old test data and new data for the new feature.
Real worldWhen a bus company adds a student discount to its ticket app, programmers do not rewrite the app. They amend the fare calculation, then re-run all the old tests to make sure nothing else broke.
Worked Example 12 min
Worked example 1 · Write an algorithm: a café bill
A café till inputs the price of each item in an order. A price of 0 ends the order. Each price must be from $0 to $50. If the total is over $30, the customer gets 10% off. Output the bill.
Specify. Inputs: item prices. Output: the bill. Rules: valid price 0–50; 0 ends; over $30 → 10% off.
Decompose and draw the structure diagram.each bottom box is one small, testable job.
Draw the flowchart.Two loops: the inner one validates each price; the outer one repeats until 0 is entered.
Write the pseudocode and Python.
// Café bill: total the items, then apply any discount
Total ← 0
REPEAT
// validation: re-ask until the price is 0 to 50
REPEAT
OUTPUT "Item price (0 to finish): "
INPUT Price
UNTIL Price >= 0 AND Price <= 50
Total ← Total + Price
UNTIL Price = 0
IF Total > 30
THEN
Total ← Total * 0.9
ENDIF
OUTPUT "Bill: $", Total
# Café bill: total the items, then apply any discounttotal=0price=-1whileprice!=0:price=-1# validation: re-ask until the price is 0 to 50whileprice<0orprice>50:price=float(input("Item price (0 to finish): "))total=total+priceiftotal>30:total=total*0.9print("Bill: $",round(total,2))
adding the final 0 to the total does no harm, so no extra IF is needed.
Dry run with test data 12, 8, 60, 15, 0 (60 is abnormal). Expected bill: 35 × 0.9 = 31.5.
60 fails validation and is asked for again. Prompts are left out of the OUTPUT column to save space.
Price
Total
OUTPUT
0
12
12
8
20
60
15
35
0
35
31.5
Bill: $31.5
Item price (0 to finish): 12
Item price (0 to finish): 8
Item price (0 to finish): 60
Item price (0 to finish): 15
Item price (0 to finish): 0
Bill: $ 31.5
also test 10, 20, 0 (total exactly 30 → no discount, bill 30) — a boundary.
Worked example 2 · Amend it: count the items and cap the order
New requirement: output how many items were bought and the average item price, and stop after 10 items. The closing 0 must not count as an item.
Total ← 0
// NEW: count the items bought
Count ← 0
REPEAT
REPEAT
OUTPUT "Item price (0 to finish): "
INPUT Price
UNTIL Price >= 0 AND Price <= 50
// CHANGED: only real items are added and counted
IF Price > 0
THEN
Total ← Total + Price
Count ← Count + 1
ENDIF
// CHANGED: also stop after 10 items
UNTIL Price = 0 OR Count = 10
IF Total > 30
THEN
Total ← Total * 0.9
ENDIF
OUTPUT "Bill: $", Total
// NEW: average only if something was bought
IF Count > 0
THEN
OUTPUT "Items: ", Count, " Average: $", Total / Count
ENDIF
New variable, initialised:Count ← 0 in the set-up part.
Counting goes inside an IF so the closing 0 is not counted.without it, 12, 8, 0 would report 3 items, not 2.
The loop condition gains OR Count = 10 — whichever happens first ends the order.
Guard the division. If the first input is 0, Count is 0, and dividing by 0 would crash.
Re-test: 12, 8, 15, 0 → Bill $31.5, Items 3, Average $10.5 (the average of the discounted bill). Then eleven prices of $1 → stops after 10, Bill $10, Items 10, Average $1.
Worked example 3 · Nested loops: sports-day times
Three races each have four runners. Each time (seconds) must be 5 to 60. Output each race's fastest time and average, and the fastest time of the day.
// 60 is the slowest valid time, so 999 is always beaten
OverallFastest ← 999
FOR Race ← 1 TO 3
RaceFastest ← 999
RaceTotal ← 0
FOR Runner ← 1 TO 4
REPEAT
OUTPUT "Race ", Race, " runner ", Runner
INPUT Time
UNTIL Time >= 5 AND Time <= 60
RaceTotal ← RaceTotal + Time
IF Time < RaceFastest
THEN
RaceFastest ← Time
ENDIF
NEXT Runner
IF RaceFastest < OverallFastest
THEN
OverallFastest ← RaceFastest
ENDIF
OUTPUT "Fastest ", RaceFastest
OUTPUT "Average ", RaceTotal / 4
NEXT Race
OUTPUT "Fastest of the day ", OverallFastest
# 60 is the slowest valid time, so 999 is always beatenoverall_fastest=999forraceinrange(1,4):race_fastest=999race_total=0forrunnerinrange(1,5):time=0whiletime<5ortime>60:print("Race",race,"runner",runner)time=float(input())race_total=race_total+timeiftime<race_fastest:race_fastest=timeifrace_fastest<overall_fastest:overall_fastest=race_fastestprint("Fastest",race_fastest)print("Average",race_total/4)print("Fastest of the day",overall_fastest)
Outer loop = races; inner loop = runners. Race variables are reset at the start of each race, inside the outer loop.resetting them before the outer loop would mix one race's times into the next.
Overall values are set once, before both loops, and updated after each race.
To dry run it, cut the sizes: 2 races × 2 runners. Data 14, 12 then 11, 13 → race 1 fastest 12, average 13; race 2 fastest 11, average 12; fastest of the day 11.smaller loops give a short trace that still tests every path.
Try It Yourself 12 min
🟢 Easy
Goal: Write pseudocode to input ten positive numbers and output their total and average. Say which loop you chose and why.
🟡 Medium
Goal: Amend your easy answer so that any number of positive numbers can be entered, ending when the user types −1. Explain why you changed the loop type.
🔴 Stretch
Goal: Amend the sports-day algorithm so it also outputs which race had the fastest time of the day. Dry run it with 2 races × 2 runners to prove it.
Hint
Add a variable such as FastestRace. Where OverallFastest is replaced, also store the current value of Race.
📝 Exam Practice 10 min
Write[6]
A car park charges $2 per hour for 1 to 3 hours, $1.50 per hour for 4 to 8 hours, and a flat $15 for 9 to 24 hours. Write pseudocode that inputs the number of whole hours, rejects values outside 1–24, and outputs the charge.
Mark scheme
Input of the hours inside a loop (1)
Validation: loop repeats until Hours >= 1 AND Hours <= 24 (1)
Correct test for 1–3 hours and Charge ← Hours * 2 (1)
Correct test for 4–8 hours and Charge ← Hours * 1.5 (1)
Charge ← 15 for 9–24 hours (1)
Output of the charge, with all IFs correctly closed (1)
Explain[3]
Explain how you would test your car-park algorithm. Include examples of test data.
Mark scheme
Dry run with a trace table, comparing actual and expected results (1).
Normal data with expected results, e.g. 2 → $4, 6 → $9 (1).
Abnormal data, e.g. −5 or "two" → rejected (1). Max 3.
Write[4]
Amend the café-bill pseudocode (worked example 1) so that it also outputs the most expensive item bought.
Mark scheme
New variable initialised before the loop, e.g. Highest ← 0 (1)
Comparison inside the outer loop after validation: IF Price > Highest (1)
Highest ← Price inside that IF, closed with ENDIF (1)
OUTPUT "Most expensive: $", Highest after the loop (1)
🗝️ Recap & Key Terms 3 min
Write an algorithm by specifying, decomposing, designing, constructing clearly, then dry running and correcting. Amend one by placing each change carefully, initialising any new variable, and re-testing old and new behaviour.
Algorithm
An ordered set of steps to solve a problem.
Amend
Change an existing algorithm so it meets a new or corrected requirement.
Comment
A note in pseudocode, starting with //, that explains the algorithm to a reader; it is not executed.
Nested loop
A loop placed inside another loop; the inner loop runs completely for each pass of the outer loop.
Meaningful identifier
A name that describes the data it holds, e.g. ItemPrice rather than X.
Homework 1 min
Task (≤ 15 min): A school has 5 classes of 30 students. Each student's test mark (0–100) is input. Write pseudocode that outputs the average mark for each class and the highest mark in the school. [6]
Model answer
SchoolHighest ← 0
FOR Class ← 1 TO 5
ClassTotal ← 0
FOR Student ← 1 TO 30
REPEAT
INPUT Mark
UNTIL Mark >= 0 AND Mark <= 100
ClassTotal ← ClassTotal + Mark
IF Mark > SchoolHighest
THEN
SchoolHighest ← Mark
ENDIF
NEXT Student
OUTPUT "Class ", Class, " average ", ClassTotal / 30
NEXT Class
OUTPUT "Highest mark ", SchoolHighest
Marks: nested loops with correct bounds (1); class total reset inside the outer loop (1); validation 0–100 (1); totalling (1); highest found — starting at 0 is safe as marks cannot be negative (1); both outputs in the right places (1).