← 0478 CS HubPaper 23 · Summer 20240478 / Paper 2Question 915 MARKS
15-mark question lab · start here
From match records to the league champion.
Build the solution in a sensible order: input and validate the games played, store the ten team names, collect each team's won, drawn and lost record against Played, calculate and store the points, bubble sort the table into descending order with Teams[] kept parallel, then report every team sharing the highest points. Learn the reasoning before revealing the complete program.
1D + 2D arraysParallel arraysREPEAT-UNTIL validationPoints formulaDescending bubble sort15 marks
Learning targets
By the end, you should be able to explain the algorithm before writing it.
Lesson overview
01 · Understand
Identify the two arrays, the four Results[] columns and the single Played variable — and recognise that nothing is pre-stored: this program inputs everything itself.
02 · Construct
Use REPEAT … UNTIL loops to validate the games played against the 18 maximum and each team's won + drawn + lost against Played, then store won × 3 + drawn in column 4.
03 · Complete
Bubble sort Results[] into descending points order while swapping the parallel Teams[] in step, count the teams on the highest points and output the champion(s).
!
How Cambridge awards the marks: the mark scheme gives AO2 a maximum of 9 marks and AO3 a maximum of 6 marks. It lists requirements R1–R5, but does not assign a separate fixed mark total to each R requirement. The stage-to-mark links in this guide show alignment, not invented stage marks.
Source question
Read the whole question first
Do not begin coding after the first paragraph. The 18-game maximum, the sum-must-equal-Played validation and the parallel-array sort all affect the structure of your solution.
A one-dimensional (1D) array Teams[] contains the names of 10 football teams in a local league. A two-dimensional (2D) array Results[] stores, for each team, the total number of:
games won
games drawn
games lost
points.
The position of any team’s data is the same in both arrays. For example the data in index 3 of Results[] belongs to the team in index 3 of Teams[]
The array data will be used to find the current leader of the league. The variable Played stores the number of games played by each team. Each team plays the same number of games.
Write a program that meets the following requirements:
allows the number of games played to be input and stored, with a maximum of 18 games
allows the names of the teams to be input and stored
allows the number of games won, drawn and lost to be input and stored for each team
validates the number of games played and the number of games won, drawn or lost against the number of games played
calculates and stores the number of points for each team using three points for a win and one point for a draw; there are no points for a loss
sorts the array Results[] into descending order of number of points, ensuring the corresponding parallel array Teams[] is kept in the same order
determines how many teams have the highest number of points
outputs the name(s) of the winning team(s) along with the number of points achieved.
You must use pseudocode or program code and add comments to explain how your code works.
You do not need to declare any arrays, variables or constants; you may assume that this has already been done. All inputs and outputs must contain suitable messages.
Before you move on
These are the five required techniques identified by the Cambridge mark scheme.
Mark-scheme map
R1
Input and store the number of games played with validation against the maximum of 18, then input and store the ten team names.
R2
Input each team's won, drawn and lost record and validate it against Played — the three totals must sum to Played, with a re-entry on mismatch.
R3
Calculate and store each team's points in Results[TeamCounter, 4]: three for a win, one for a draw, nothing for a loss.
R4
Bubble sort Results[] into descending order of points, swapping all four columns and the parallel Teams[] entry together.
R5
Count how many teams share the highest points and output the winning team name(s) with the points achieved.
Use the tabs along the top to work through the seven stages. The complete solution is kept in its own tab, and the interactive visualisation is the final tab.
01
Decode the requirements
Turn the question wording into a sequence of tasks.
R1 · R2 · R3 · R4 · R5
🧠 Step-by-step thinking
Spot the two input phases. Nothing is pre-stored this time: the program must input Played (maximum 18) and the ten team names first, then input each team's won, drawn and lost record row by row.
Translate each validation. “Validates the number of games played” means a REPEAT … UNTIL loop that rejects anything above 18; “validates … won, drawn or lost against the number of games played” means won + drawn + lost must equal Played, with a re-entry on mismatch.
See the sort as two arrays moving together. “Sorts the array Results[] into descending order of number of points, ensuring the corresponding parallel array Teams[] is kept in the same order” — every swap must move all four columns of a row and the team name.
Translate the scoring and the finish. “Three points for a win and one point for a draw; there are no points for a loss” is the formula points = won × 3 + drawn; “determines how many teams have the highest number of points” is a count, and “the name(s) of the winning team(s)” warns that the top spot can be shared.
Build the order. input + validate Played → input ten names → team loop (input won/drawn/lost → validate → store points) → bubble sort descending on column 4 with Teams[] parallel → count teams on the top points → output winner(s) + points.
Input + REPEAT-UNTIL validationPoints: won × 3 + drawnBubble sort with parallel arrayCounting shared champions
❓ Guiding questions – think before revealing
Which phrases tell you the data is input, not given?
What exactly must the validation check?
Why does the sort mention the parallel array so explicitly?
Reveal suggested reasoning
Which phrases tell you the data is input, not given? Every bullet says “allows … to be input and stored”. There is no “the arrays and variables have already been set up” line here — your program must fill Teams[], Results[] and Played itself.
What exactly must the validation check? Two separate checks: the games-played entry may not exceed 18, and each team's won + drawn + lost must equal Played. A team that has won 10, drawn 1 and lost 0 has played 11 games, so the entry is rejected when Played is 12.
Why does the sort mention the parallel array so explicitly? If you swapped only the points column, the leader's points would travel up the table while the name stayed behind — every later output would name the wrong team. All four columns and the name must move as one.
Reveal Cambridge pseudocode for Stage 1
CODE PLAN · STRUCTURE ONLYBuild this before filling in the details
// 1. Input + validate games played (maximum 18)
// 2. Input the ten team names
// 3. For each team: input won, drawn, lost
// 4. Validate the three totals against Played
// 5. Calculate and store points in column 4
// 6. Bubble sort Results[] descending by points,
// swapping Teams[] in step
// 7. Count the teams on the highest points
// 8. Output winner name(s) with points
📖 Detailed explanation
“Allows … to be input and stored” appears three times — for Played, for the names and for each team's record. Three input sections, each storing into the given structures.
“Validates … against” means comparing one entry with another known value, then repeating the input until it is consistent. Post-test REPEAT … UNTIL loops are the natural shape because the user must be asked at least once.
“Descending order of number of points” points at column 4 of Results[] as the sort key — but that value lives beside won, drawn and lost, so whole rows have to move.
“The name(s) of the winning team(s)” uses plurals deliberately: after sorting, every row equal to the top points is a champion, so a count must run before the output.
⚠️ Common mistakes
Starting with the sort because it looks like the hard part — the sort is only correct once the points column has been calculated and stored.
Sorting only the points column, which strands each team's name beside another team's record.
Validating won, drawn and lost one at a time instead of against each other and against Played.
Outputting just one winning team before counting how many teams share the top points.
💡 Exam hack / tip
Underline “maximum of 18”, “against the number of games played”, “parallel array Teams[] is kept in the same order” and “how many teams”. Those four phrases give you the validation loop, the sum check, the whole-row swap and the champion count.
Reveal the Cambridge mark-scheme and rubric connection
This planning stage supports AO2 by identifying the full range of techniques required. It supports AO3 by establishing a logical sequence. These are alignment notes, not separately allocated marks.
02
Plan the data and identifiers
Choose variables and arrays that store exactly what the algorithm needs.
Required data structures
🧠 Step-by-step thinking
Use the given names.Teams[], Results[] and Played are supplied by the question — your program must use them exactly. Column 1 stores won, column 2 drawn, column 3 lost and column 4 points.
Remember the declaration rule. “You do not need to declare any arrays, variables or constants” — so, unlike most questions, no DECLARE block is needed here; every identifier may be used straight away.
Add the loop counters.TeamCounter walks the ten rows, PassCounter and PositionCounter drive the sort, and ColumnCounter swaps the four columns inside a row swap.
Add the swap temporaries.TempResult holds one number during a column swap and TempName holds one name during the parallel swap — without them one value would overwrite the next.
Add the champion trackers.HighestPoints, TeamCount and WinnerCounter survive after the sort to count and output every team on the top points.
Given: Teams[], Results[,], PlayedCounters: four INTEGER loop variablesTemporaries: TempResult and TempName
❓ Guiding questions – think before revealing
Why is column 4 of Results[] written by the program, not read from it?
Why do the sort and the swap need three counters between them?
Which variables must still exist after the loops end?
Reveal suggested reasoning
Why is column 4 of Results[] written by the program, not read from it? The question lists points as one of the four stored values, but the bullets say the program “calculates and stores the number of points” — columns 1 to 3 are input, and column 4 is computed from them.
Why do the sort and the swap need three counters between them? PassCounter tracks how much of the table is already settled, PositionCounter compares the adjacent pair, and ColumnCounter moves through the four columns of a row when a swap happens.
Which variables must still exist after the loops end? HighestPoints and TeamCount — the champion report reads them after the sort. Anything used only inside a loop (counters, temporaries) never needs to outlive it.
Reveal Cambridge pseudocode for Stage 2
CODE PLAN · STRUCTURE ONLYBuild this before filling in the details
// Given by the question — declarations assumed:
// Teams[10] Results[10, 4] Played
// Results columns: 1 = won, 2 = drawn, 3 = lost, 4 = points
// Working values the program needs:
// TeamCounter PassCounter PositionCounter ColumnCounter
// TempResult TempName
// HighestPoints TeamCount WinnerCounter
📖 Detailed explanation
Meaningful identifiers earn AO3 credit.TempResult versus TempName keeps the two swap temporaries impossible to confuse, and TeamCount is the count of teams, not the points.
The 2D array is addressed with two indexes.Results[TeamCounter, 4] means “the current team's points cell” — row first, then column.
Nothing needs declaring this time. The paper says declarations can be assumed, so spend the saved lines on comments — they are explicitly required (“add comments to explain how your code works”).
⚠️ Common mistakes
Writing a long DECLARE block first — the question removes that requirement, so reinvest the effort in comments.
Renaming Results[] to something like League[], which the mark scheme treats as not using the supplied structures.
Swapping with no temporaries, so the old points value is destroyed before it can be copied into the other row.
Treating Played as one value per team — every team plays the same number of games, so there is a single shared variable.
💡 Exam hack / tip
Borrow the question's own words for identifiers: TeamCounter, PositionCounter, TempName, HighestPoints. An examiner should be able to map every variable back to a phrase in the question.
Reveal the Cambridge mark-scheme and rubric connection
AO2 · appropriate data structuresR1–R5 · given names reusedAO3 · meaningful identifiers
The data plan supports AO2 because the chosen variables store exactly the required data, and AO3 because every identifier is meaningful. These are alignment notes, not separately allocated marks.
03
Input the games played and the team names
A validated REPEAT … UNTIL for Played, then a loop that fills Teams[].
R1
🧠 Step-by-step thinking
Validate Played with a post-test loop. REPEAT … UNTIL asks at least once and keeps asking until the entry is 18 or fewer (and not below 1).
Store into the variable the question names. The games count belongs in Played — every team plays the same number, so one input serves all ten rows.
Fill Teams[] with a counted loop. FOR TeamCounter ← 1 TO 10 stores each name at the same index its results will use later.
Give every prompt a message. “All inputs and outputs must contain suitable messages” — print what the user is being asked for, including the maximum.
Check the order of the two jobs. The names must be stored before the per-team prompts can echo them (“Games won by …”), so the name loop runs first.
REPEAT-UNTIL: 1 to 18FOR: ten namesMessages on every prompt
❓ Guiding questions – think before revealing
Why REPEAT … UNTIL rather than WHILE … ENDWHILE?
What should the UNTIL condition be?
Why store the names before the results?
Reveal suggested reasoning
Why REPEAT … UNTIL rather than WHILE … ENDWHILE? The entry must be requested before it can be tested. A post-test loop asks, then checks, then asks again — a WHILE loop would need the input duplicated before the loop to guarantee a first value exists.
What should the UNTIL condition be? Played >= 1 AND Played <= 18. The bullet gives the maximum of 18; the lower bound keeps a meaningless negative or zero season out of the loops that follow.
Why store the names before the results? The result prompts are better messages when they echo the team name, and the validation loop needs Teams[TeamCounter] for that — the names must already be in place.
Reveal Cambridge pseudocode for Stage 3
CODE PLAN · STRUCTURE ONLYBuild this before filling in the details
REPEAT
OUTPUT "Enter the number of games played (maximum 18): "
INPUT Played
UNTIL Played >= 1 AND Played <= 18
FOR TeamCounter ← 1 TO 10
OUTPUT "Enter the name of team ", TeamCounter, ": "
INPUT Teams[TeamCounter]
NEXT TeamCounter
📖 Detailed explanation
The maximum becomes a boundary test. “With a maximum of 18 games” translates directly into Played <= 18; anything above re-triggers the prompt.
One shared value, ten rows.Played is input once because the question says “each team plays the same number of games” — the validation later compares every team's totals against this single number.
The name loop is plain counting. Ten fixed teams means FOR 1 TO 10 with INPUT Teams[TeamCounter] — no nested structure is needed until the results phase.
⚠️ Common mistakes
Using IF to reject a bad Played entry once instead of a loop that keeps asking until the value is legal.
Accepting 25 games because the words “maximum of 18” were read but never turned into a test.
Prompting with no message, such as a bare INPUT Played — the question demands suitable messages on every input and output.
Storing the names after the results, so the result prompts cannot echo them.
💡 Exam hack / tip
Say the validation aloud as a promise: “ask, check, ask again”. If the check must happen after the first ask, the REPEAT … UNTIL shape writes itself.
Reveal the Cambridge mark-scheme and rubric connection
AO2 · input and validation loopR1 · games played + names storedAO3 · suitable messages
The input stage is the AO2 evidence for post-test validation, and the prompts support the AO3 requirement for suitable messages. These are alignment notes, not separately allocated marks.
04
Validate each team's record against Played
Won + drawn + lost must equal the games played, with a re-entry on mismatch.
R2
🧠 Step-by-step thinking
Wrap the three inputs in one loop. The REPEAT … UNTIL asks for won, drawn and lost, then tests them together — a mismatch re-asks for all three.
Write the sum test against Played.Results[TeamCounter, 1] + Results[TeamCounter, 2] + Results[TeamCounter, 3] = Played — so 10 + 1 + 0 = 11 fails when Played is 12.
Add the non-negative guards. Each of the three entries must also be >= 0; negative counts would let the sum pass while the record stays impossible.
Re-enter the whole record. Rejected values must never survive in Results[] — the loop repeats before any points are calculated.
Leave the loop before calculating. The points formula sits after UNTIL, so it only ever runs on a validated record.
Sum test: = PlayedGuards: each >= 0Re-entry: whole record
❓ Guiding questions – think before revealing
Why must the three entries be validated together?
What does the AND chain guarantee?
Why is it safe to calculate points immediately after UNTIL?
Reveal suggested reasoning
Why must the three entries be validated together? The bullet says “the number of games won, drawn or lost against the number of games played” — none of the three can be judged alone. 10 + 1 + 0 looks plausible value by value, but the total, 11, disagrees with 12 played.
What does the AND chain guarantee? Every condition must hold before the loop can end: the sum equals Played and all three counts are at least zero. One FALSE leaves the team's record rejected.
Why is it safe to calculate points immediately after UNTIL? The loop cannot be exited with an invalid record, so the values in columns 1 to 3 are consistent the moment the loop ends — the formula can trust them.
Reveal Cambridge pseudocode for Stage 4
CODE PLAN · STRUCTURE ONLYBuild this before filling in the details
REPEAT
OUTPUT "Games won by ", Teams[TeamCounter], ": "
INPUT Results[TeamCounter, 1]
OUTPUT "Games drawn by ", Teams[TeamCounter], ": "
INPUT Results[TeamCounter, 2]
OUTPUT "Games lost by ", Teams[TeamCounter], ": "
INPUT Results[TeamCounter, 3]
UNTIL Results[TeamCounter, 1] + Results[TeamCounter, 2]
+ Results[TeamCounter, 3] = Played
AND Results[TeamCounter, 1] >= 0
AND Results[TeamCounter, 2] >= 0
AND Results[TeamCounter, 3] >= 0
📖 Detailed explanation
“Validates … against” is a comparison, not a type check. The reference value is Played — the same variable that was input and validated in Stage 3.
One loop, three values, one condition. The AND-combined UNTIL keeps the three totals mutually consistent; three separate loops would re-ask for single values and lose that guarantee.
Rejected data never reaches the rest of the program. The inputs go straight into Results[], but the loop repeats before the program moves on — so by the time anything else reads the row, the record adds up.
⚠️ Common mistakes
Testing Results[TeamCounter, 1] = Played — comparing the wins alone with the games played instead of the sum of all three.
Joining the conditions with OR, which lets an impossible record through as soon as one clause happens to be TRUE.
Forgetting the >= 0 guards, so won = 14, drawn = −1, lost = −1 would pass a 12-game check.
Calculating points inside the REPEAT loop, so invalid records score points before being re-entered.
💡 Exam hack / tip
Test your own condition with the examiner's favourite: won 10, drawn 1, lost 0, Played 12. If your UNTIL rejects that entry, you have written the check the bullet asked for.
Reveal the Cambridge mark-scheme and rubric connection
AO2 · compound validation conditionR2 · record vs PlayedAO3 · correct AND logic
The validation loop supplies the AO2 evidence for selection with a compound condition, and its correctness is the AO3 evidence. These are alignment notes, not separately allocated marks.
05
Calculate and store each team's points
Three for a win, one for a draw, nothing for a loss — stored in column 4.
R3
🧠 Step-by-step thinking
Translate the scoring rule into a formula.Results[TeamCounter, 4] ← Results[TeamCounter, 1] * 3 + Results[TeamCounter, 2] — the loss column adds nothing because losses score zero.
Store, do not just output. The bullet says “calculates and stores” — the value must land in Results[TeamCounter, 4] because the sort and the champion count read it later.
Keep the formula inside the team loop. Each pass of TeamCounter fills one more points cell, so after the loop every row is complete.
Position it after the validation loop. Points from an impossible record would poison the sort — the formula only runs once UNTIL has passed.
Connect it to the next stage. Column 4 is now the sort key: descending order of Results[…, 4] is exactly what Stage 6 delivers.
Formula: won × 3 + drawnStored in Results[TeamCounter, 4]Runs once per validated row
❓ Guiding questions – think before revealing
Why is there no third term for losses?
Why must the points be stored rather than kept in a variable?
What does the sample's arithmetic look like?
Reveal suggested reasoning
Why is there no third term for losses? “There are no points for a loss” — multiplying the loss column by 0 would work but adds noise. Leaving it out, with a comment stating that losses score nothing, shows the rule was read.
Why must the points be stored rather than kept in a variable? Two later requirements consume them: the sort orders rows by column 4, and the champion count compares every row with the top value. A single variable would be overwritten ten times.
What does the sample's arithmetic look like? Brockley Rovers: 10 wins × 3 + 2 draws = 32 points. Elmwood Rangers: 5 × 3 + 5 = 20 — a different record that lands on the same total as Cranleigh City, which the sort must handle without swapping.
Reveal Cambridge pseudocode for Stage 5
CODE PLAN · STRUCTURE ONLYBuild this before filling in the details
// Three points for a win, one for a draw, none for a loss
Results[TeamCounter, 4] ←
Results[TeamCounter, 1] * 3 + Results[TeamCounter, 2]
// e.g. won 10, drawn 2 → 10 * 3 + 2 = 32 points
📖 Detailed explanation
The formula mirrors the wording. “Three points for a win and one point for a draw; there are no points for a loss” becomes one assignment — wins × 3 plus draws, losses omitted.
Storage completes the data structure. After this loop, Results[] matches the question's description exactly: won, drawn, lost and points for every team.
The placement is part of the logic. Inside the team loop, after the validation loop — one points value per validated record, never more and never earlier.
⚠️ Common mistakes
Using 2 points for a win or forgetting the draw's single point — the question fixes 3, 1 and 0.
Outputting the points but never storing them in Results[TeamCounter, 4], leaving the sort with nothing to order.
Placing the formula outside the team loop, so only the last team's points are calculated.
Appending Results[TeamCounter, 3] * 0 instead of stating the zero-loss rule in a comment.
💡 Exam hack / tip
Write the scoring line above your formula as a comment — win 3 · draw 1 · loss 0 — then point at each term and check it matches. The comment doubles as the required explanation.
Reveal the Cambridge mark-scheme and rubric connection
AO2 · arithmetic on array dataR3 · points stored in column 4AO3 · accurate formula and comment
The points calculation is the AO2 evidence for arithmetic on stored data, and its correct placement supports AO3. These are alignment notes, not separately allocated marks.
06
Sort descending by points, keeping Teams[] parallel
A bubble sort on column 4 whose swaps move whole rows and their names.
R4
🧠 Step-by-step thinking
Choose the bubble sort. Adjacent pairs are compared down the table; after each pass the smallest points value has bubbled to the bottom, so the next pass can stop one position earlier.
Test the points column only — but swap everything. The IF compares Results[PositionCounter, 4] with Results[PositionCounter + 1, 4]; the swap then moves all four columns.
Write the descending test carefully. Descending order needs a swap when the left value is smaller: <. Using > would sort the league upside down.
Move the name with the row. After the column loop, swap Teams[PositionCounter] with Teams[PositionCounter + 1] so every name stays glued to its own record.
Count the passes correctly. FOR PassCounter ← 1 TO 9 with the inner loop running to 10 − PassCounter covers every adjacent pair for ten teams — the sample trace does the same on five.
Key: Results[…, 4]Descending test: <Swap: 4 columns + name
❓ Guiding questions – think before revealing
Why must all four columns move in a swap?
What happens when two teams have equal points?
Why does the inner loop shrink each pass?
Reveal suggested reasoning
Why must all four columns move in a swap? A team's identity is its whole row. If only the points moved, row 1 could hold Brockley's 32 points beside Ashford's 7–3–2 record, and every later lookup through Teams[] would name the wrong champion.
What happens when two teams have equal points? The test is strictly <, so equal values do not swap and keep their current order. That is also why the condition is < and not <= — swapping equals would churn the table for nothing.
Why does the inner loop shrink each pass? After pass 1 the lowest points value is guaranteed to sit in the last row, so pass 2 need not compare it again. 10 − PassCounter skips the settled tail — the standard bubble-sort economy.
Reveal Cambridge pseudocode for Stage 6
CODE PLAN · STRUCTURE ONLYBuild this before filling in the details
FOR PassCounter ← 1 TO 9
FOR PositionCounter ← 1 TO 10 - PassCounter
IF Results[PositionCounter, 4] < Results[PositionCounter + 1, 4]
THEN
FOR ColumnCounter ← 1 TO 4
TempResult ← Results[PositionCounter, ColumnCounter]
Results[PositionCounter, ColumnCounter] ←
Results[PositionCounter + 1, ColumnCounter]
Results[PositionCounter + 1, ColumnCounter] ← TempResult
NEXT ColumnCounter
TempName ← Teams[PositionCounter]
Teams[PositionCounter] ← Teams[PositionCounter + 1]
Teams[PositionCounter + 1] ← TempName
ENDIF
NEXT PositionCounter
NEXT PassCounter
📖 Detailed explanation
Descending changes the operator. Ascending bubble sorts swap when the left value is greater; here the league table must read champion-first, so the swap fires when the left points value is less than the right.
The column loop makes the swap safe. Copying through TempResult column by column moves won, drawn, lost and points as a unit — a record cannot end up half-swapped.
The parallel swap is a separate, explicit step. Cambridge papers set parallel arrays precisely to test this: one swap in Results[], one matching swap in Teams[], same two positions.
⚠️ Common mistakes
Sorting ascending — the biggest trap in this question; the league table must read champion first.
Swapping only Results[…, 4], which desynchronises the points from each team's won, drawn and lost record.
Forgetting the Teams[] swap, so the final output names whichever team originally sat in row 1.
Losing a value by swapping without a temporary, or comparing a row with itself because the +1 was dropped.
💡 Exam hack / tip
Rehearse one pass by hand: 24 · 32 · 20 · 27 · 20 becomes 32 · 24 · 27 · 20 · 20 after three swaps — and the equal 20s never swap. If your trace disagrees, your operator or your swap set is wrong.
Reveal the Cambridge mark-scheme and rubric connection
AO2 · bubble sort with parallel arraysR4 · descending on pointsAO3 · complete row and name swaps
The sort is the AO2 evidence for a standard algorithm adapted to the scenario, and the parallel swap is the AO3 accuracy evidence. These are alignment notes, not separately allocated marks.
07
Count the champions and output the winner(s)
Read the top points from row 1, count the rows that match, then report.
R5
🧠 Step-by-step thinking
Harvest the sort. After the sort, Results[1, 4] is the highest points total — no scanning loop is needed to find it.
Count with an equality test. One pass compares every row's column 4 with HighestPoints; each match increments TeamCount. Equality (=), not >= — only the top value counts.
Output through the parallel array.Teams[WinnerCounter] turns the winning rows back into names — the payoff for keeping the arrays in step.
Loop the output for shared titles. FOR WinnerCounter ← 1 TO TeamCount prints one line per champion — one line when the title is outright, several when it is shared.
Report the count too. “Determines how many teams” is done once TeamCount is final — printing it with a message proves the determination and keeps every output suitably worded.
Top points: Results[1, 4]Count test: =Output: names + points
❓ Guiding questions – think before revealing
Why is no search needed for the highest points?
What does the count loop actually compare?
Why loop the output rather than print row 1?
Reveal suggested reasoning
Why is no search needed for the highest points? The sort has just ordered the table. The largest value must be in row 1, so HighestPoints ← Results[1, 4] reads it directly — a second maximum-tracking loop would be wasted work.
What does the count loop actually compare? Results[TeamCounter, 4] = HighestPoints — pure equality. Teams below the top fail it immediately; every team on the top increments TeamCount.
Why loop the output rather than print row 1? “The name(s) of the winning team(s)” is plural on purpose. If TeamCount is 2, two teams share the title and both names must be printed with the shared points.
Reveal Cambridge pseudocode for Stage 7
CODE PLAN · STRUCTURE ONLYBuild this before filling in the details
HighestPoints ← Results[1, 4] // the sort put the leader in row 1
TeamCount ← 0
FOR TeamCounter ← 1 TO 10
IF Results[TeamCounter, 4] = HighestPoints
THEN
TeamCount ← TeamCount + 1
ENDIF
NEXT TeamCounter
FOR WinnerCounter ← 1 TO TeamCount
OUTPUT "Winning team: ", Teams[WinnerCounter], " with ",
HighestPoints, " points"
NEXT WinnerCounter
OUTPUT "Number of teams sharing the highest points: ", TeamCount
📖 Detailed explanation
The sort does the finding; the count does the deciding. Sorting reduces “find the highest” to reading row 1, and reduces “who is champion” to “who equals row 1”.
Shared titles need no special case. A single champion gives TeamCount = 1 and the output loop runs once; two champions give 2 and it runs twice — the same code handles both.
Names come from Teams[], points from Results[]. The champion line needs both arrays: the name lookup through Teams[WinnerCounter] and the points through HighestPoints.
⚠️ Common mistakes
Printing Teams[1] unconditionally and ignoring the count, so a shared title reports only one champion.
Counting with >= instead of =, which counts every team in the league.
Searching for the maximum with an extra loop, having forgotten the sort already placed it in row 1.
Outputting the points or the count without a message — both need suitable wording.
💡 Exam hack / tip
End-of-question checklist: top value read from row 1, count complete, name(s) printed with points, messages on every line. Four ticks and the final marks are protected.
Reveal the Cambridge mark-scheme and rubric connection
AO2 · counting and reportingR5 · champion count + outputsAO3 · messages and lookup
The summary delivers the R5 outputs and demonstrates AO3 through the name lookups and complete messages. These are alignment notes, not separately allocated marks.
Cambridge assessment criteria
What does a high-level response look like?
The mark scheme assesses the answer across AO2 and AO3. Use these descriptors to check the whole program, not just one isolated code section.
9 AO2 + 6 AO3 = 15
AO2 · Apply knowledge and understandingMaximum 9 marks · programming techniques and data structures
Band
What the descriptor means
0
No creditable response.
1–3
At least one programming technique is used. Some data is stored, but not appropriately. Any use of iteration, selection, counting, totalling, input or output may be credited.
4–6
Some programming techniques are appropriate to the problem, with more than one technique applied. Some data structures are appropriate and store some of the required data.
7–9
The full range of techniques needed by the scenario is used appropriately. The chosen data structures are appropriate and store all the required data.
AO3 · Provide solutions to problemsMaximum 6 marks · comments, identifiers, logic and accuracy
Band
What the descriptor means
0
No creditable response.
1–2
Program seen without relevant comments. Some identifier names and some data-structure names are appropriate. The solution may be illogical or inaccurate in many places, but attempts at least one requirement.
3–4
Program seen with some relevant comments. The majority of identifiers and most data-structure names are meaningful. Parts may be illogical or inaccurate, but most requirements are met.
5–6
The program is fully commented. Suitable identifiers are meaningful throughout, and all data structures have meaningful names. The program is logical and accurate and meets all requirements; minor syntax errors are ignored.
How the seven stages contribute
These are links to the assessment criteria, not separate mark allocations.
R1–R5
Stage
Mark-scheme link
AO2 evidence
AO3 evidence
1 · Decode
R1–R5
Two input phases, two validations, points formula, parallel sort and champion count identified.
Logical build order established; comments planned.
2 · Data
Required data structures
Teams[], Results[,] columns 1–4 and Played used as given; counters, temporaries and trackers added.
Meaningful identifiers; no declarations needed (assumed).
3 · Input
R1
REPEAT … UNTIL validates Played against the 18 maximum; FOR loop stores the ten names.
Every prompt carries a suitable message.
4 · Validate
R2
Won + drawn + lost tested against Played with non-negative guards; whole record re-entered.
Correct AND-combined UNTIL condition.
5 · Points
R3
won × 3 + drawn calculated and stored in Results[TeamCounter, 4] for every team.
Formula matches the 3–1–0 rule; placed after validation.
6 · Sort
R4
Bubble sort compares column 4 descending and swaps all four columns plus the parallel name.
Strict < test; temporaries protect both arrays.
7 · Summary
R5
Top points read from row 1, matching rows counted, winner name(s) + points output.
Equality count; name lookup through Teams[] after the loops.
Final self-check
Tick each statement only when it is present and correct in your answer.
Student checklist
0 of 10 completed
✓
Target: to reach the top AO2 and AO3 bands, the solution needs to be appropriate, logical, accurate, commented, and complete. A long answer alone does not guarantee full marks.
Consolidated Cambridge pseudocode
Complete solution
The full answer is presented in one place after the seven stages. Try to construct it yourself before opening this tab during revision.
15-mark exemplar style
Read this carefully: this follows the structure and techniques of the specimen mark scheme. Nothing is pre-stored in this question, so the program inputs and validates Played and the ten names first, then each team's record. The sort swaps whole rows and the parallel names together, and the champion report reads its answers straight off the sorted table. The visualisation below runs the same algorithm on five of the ten teams.
QUESTION 9 · FULL PSEUDOCODECambridge 0478 style · 1-based indexing
// Teams[10], Results[10, 4] and Played are assumed declared:
// Results columns: 1 = won, 2 = drawn, 3 = lost, 4 = points
// Input games played and validate against the maximum of 18
REPEAT
OUTPUT "Enter the number of games played by each team (maximum 18): "
INPUT Played
UNTIL Played >= 1 AND Played <= 18
// Input the name of each of the ten teams
FOR TeamCounter ← 1 TO 10
OUTPUT "Enter the name of team ", TeamCounter, ": "
INPUT Teams[TeamCounter]
NEXT TeamCounter
// Input and validate won, drawn, lost for each team, then store its points
FOR TeamCounter ← 1 TO 10
REPEAT
OUTPUT "Games won by ", Teams[TeamCounter], ": "
INPUT Results[TeamCounter, 1]
OUTPUT "Games drawn by ", Teams[TeamCounter], ": "
INPUT Results[TeamCounter, 2]
OUTPUT "Games lost by ", Teams[TeamCounter], ": "
INPUT Results[TeamCounter, 3]
UNTIL Results[TeamCounter, 1] + Results[TeamCounter, 2] + Results[TeamCounter, 3] = Played
AND Results[TeamCounter, 1] >= 0
AND Results[TeamCounter, 2] >= 0
AND Results[TeamCounter, 3] >= 0
// Points: three for a win, one for a draw, none for a loss
Results[TeamCounter, 4] ← Results[TeamCounter, 1] * 3 + Results[TeamCounter, 2]
NEXT TeamCounter
// Bubble sort Results[] into descending points order, keeping Teams[] parallel
FOR PassCounter ← 1 TO 9
FOR PositionCounter ← 1 TO 10 - PassCounter
IF Results[PositionCounter, 4] < Results[PositionCounter + 1, 4]
THEN
FOR ColumnCounter ← 1 TO 4 // swap all four columns of the row
TempResult ← Results[PositionCounter, ColumnCounter]
Results[PositionCounter, ColumnCounter] ← Results[PositionCounter + 1, ColumnCounter]
Results[PositionCounter + 1, ColumnCounter] ← TempResult
NEXT ColumnCounter
TempName ← Teams[PositionCounter] // swap the parallel name too
Teams[PositionCounter] ← Teams[PositionCounter + 1]
Teams[PositionCounter + 1] ← TempName
ENDIF
NEXT PositionCounter
NEXT PassCounter
// After the sort the leader is in row 1; count the teams equal to it
HighestPoints ← Results[1, 4]
TeamCount ← 0
FOR TeamCounter ← 1 TO 10
IF Results[TeamCounter, 4] = HighestPoints
THEN
TeamCount ← TeamCount + 1
ENDIF
NEXT TeamCounter
// Output the winning team(s) with their points
FOR WinnerCounter ← 1 TO TeamCount
OUTPUT "Winning team: ", Teams[WinnerCounter], " with ", HighestPoints, " points"
NEXT WinnerCounter
OUTPUT "Number of teams sharing the highest points: ", TeamCount
Why this is a complete response
It covers the mark-scheme requirements: input and validation of the games played against the maximum of 18 plus the ten team names (R1), per-team won/drawn/lost entry validated against Played with a re-entry loop (R2), the three-one-zero points calculation stored in column 4 (R3), the descending bubble sort that swaps all four columns and keeps Teams[] parallel (R4), and the count of teams sharing the highest points with the winning team(s) and their points output (R5).
What to check before submitting
Check the two REPEAT … UNTIL conditions, the points formula, that every swap moves all four columns and the parallel name, that the descending test uses <, and the comments explaining the program.
!
Remember: the AO2 and AO3 marks are awarded by judging the whole response. The individual R1–R5 labels are the technique requirements, not a fixed per-item mark split.
Interactive execution trace
Visualisation: watch the program work.
Step through a sample league season. Watch the 20-game entry bounce off the 18 maximum, a 10 + 1 + 0 record fail the sum check and get re-entered, the points column fill up, the bubble sort swap whole rows down the table, and the champion take row 1.
Last tab · Trace player
Sample input → expected results
Five sample teams — five of the real ten — are entered with Played = 12 games (the maximum is 18). The sample deliberately tests a first entry of 20 games that breaks the 18 maximum, a first record of 10 + 1 + 0 = 11 that fails the sum-equals-Played check and is re-entered, two teams level on 20 points that exercise the equal-points comparison during the sort, and a clear champion on 32 points. The Points column shows the values the program calculates and stores into Results[i, 4]. These are illustrative values, not data supplied by the examination question.
Input arrays Teams[] and Results[,]
Team
Won
Drawn
Lost
Points
The row number is the team position used by both arrays; column 4 stores the points calculated by the program. Played = 12 for every team.
Reveal expected league table and champion summary
Expected league table After the descending sort
Team
Won
Drawn
Lost
Points
Final position
Execution trace
Step 1 of 1
Initialisation
Initialisation
The program begins.
Program output so far
(No output yet)
Live variable values
League counters
Ready
Tip: use Next step slowly and watch PassCounter and PositionCounter during the sort — the amber cell shows the points value on the left of each comparison, and every swap moves a whole row together with its team name.
Trace colours: blue row = current team; amber cell = current value being entered or compared; green cells = data already entered or compared.
Boundary examples: the first entry for games played, 20, fails 20 <= 18 and is re-entered as 12; the first record for Brockley Rovers, 10 + 1 + 0 = 11, fails 11 = Played and is re-entered as 10 + 2 + 0 = 12; Cranleigh City and Elmwood Rangers finish level on 20 points, so the strict < test never swaps them; the champion is read from row 1 after the sort.