GCSE Computer Science Paper 1: Computational Thinking and Programming Skills (Python)
A full length 8525/1B paper: algorithms in AQA pseudo-code, data types, Boolean expressions, trace tables, searching and sorting, subroutines, testing, string handling, records, 2D lists, an authentication routine and a 9 mark car park program.
Instructions
- Time allowed
- 2 hours
- Total marks
- 90
- Calculator
- You must not use a calculator.
- Answer all the questions.
- The number of marks for each question is shown in brackets. Use it as a guide to how much to write.
- The clock at the top counts down from the real time allowed. When it reaches zero the paper is locked and marked, as it would be collected in the exam hall.
- Answer the questions that ask for program code in Python, using meaningful variable names and indentation.
- Algorithms in the figures are written in AQA pseudo-code or Python, as labelled.
- Answer every question. Read each algorithm line by line, and trace it with real values before you answer. For the programming questions, run your program on the examples in the question before you move on.
Questions
Answer every question, then finish the paper to have it marked. Marking as you go teaches you far less.
Tick one box.
- LD A sequence of steps that can be followed to complete a task
An algorithm is a sequence of steps that solves a problem or completes a task. It is not tied to any language.
Tick one box.
- LA Abstraction
Abstraction keeps only the details that matter. Decomposition breaks a problem into smaller problems.
Figure 1
a ← USERINPUT
b ← USERINPUT
IF a > b THEN
c ← a - b
ELSE
c ← b - a
ENDIF
OUTPUT c| a | b | Output |
|---|---|---|
| 4 | 9 | |
| 12 | 7 | |
| 6 | 6 |
- L5
- L5
- L0
4 is not greater than 9, so c = 9 - 4 = 5. 12 is greater than 7, so c = 12 - 7 = 5. 6 is not greater than 6, so c = 6 - 6 = 0.
Tick one box.
- LB It outputs the difference between the two numbers
Whichever number is larger, the smaller is subtracted from it, so the output is always the difference.
| Integer | Real | Boolean | Character | String | |
|---|---|---|---|---|---|
| The number of goals scored in a match | |||||
| The average number of goals scored per match | |||||
| Whether the match has been played yet | |||||
| The name of the opposing team |
Tick one box in each row.
- LThe number of goals scored in a match: Integer
- LThe average number of goals scored per match: Real
- LWhether the match has been played yet: Boolean
- LThe name of the opposing team: String
Goals are whole numbers, an average can have a fractional part, played or not is true or false, and a team name is a string of characters.
Figure 2
word = "COMPUTER"- L8
- LM
- LOMP
- L3
- L2
COMPUTER has 8 characters. Indexes start at 0, so word[2] is M, and word[1:4] is the characters at indexes 1, 2 and 3: OMP. 17 // 5 is integer division, 3, and 17 % 5 is the remainder, 2.
Tick two boxes.
- LA A WHILE loop that repeats until the user enters 0
- LB A REPEAT ... UNTIL loop that repeats until a password is correct
- LNo marks if more than 2 boxes are ticked
Indefinite iteration repeats until a condition is met, so the number of repeats is not known in advance. A FOR loop that runs 10 times is definite iteration, and IF is selection.
- LIf the value changes it only needs to be updated in one place
- LThe name makes the program easier to read and understand, and the value cannot be changed by mistake while the program runs
If the VAT rate changes, the programmer only has to update the constant in one place, rather than finding every 0.2 in the program and risking missing one.
Figure 3
a = True
b = False
c = True- LTrue
- LFalse
- LTrue
a and not b is True, so the whole OR is True. not a is False and b is False, so not a or b is False. and is worked out before or: a and b is False, and False or c is True.
Figure 4
nums ← [3, 8, 2, 7]
largest ← nums[0]
total ← 0
FOR i ← 1 TO 3
IF nums[i] > largest THEN
largest ← nums[i]
ENDIF
total ← total + nums[i]
ENDFOR
OUTPUT largest
OUTPUT total| i | largest | total |
|---|---|---|
| 3 | 0 | |
| 1 | ||
| 2 | ||
| 3 |
- LRow 1: 8, 8
- LRow 2: 8, 10
- LRow 3: 8, 17
i = 1: 8 > 3, so largest becomes 8 and total becomes 8. i = 2: 2 is not larger, total becomes 10. i = 3: 7 is not larger than 8, total becomes 17.
- LThe first number, nums[0] (3), is never added to total because the loop starts at 1
- LSet total to nums[0] at the start, or make the loop run from 0 to 3
The loop starts at index 1, so nums[0], the 3, is never added: the algorithm outputs 17 instead of 20. Setting total to nums[0] instead of 0 at the start fixes it.
Tick one box.
- LC The list must be in order
A binary search discards half of the list at each step, which only works if the list is sorted.
Figure 5
| Position | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|---|
| Item | Apple | Banana | Cherry | Date | Fig | Grape | Kiwi | Lemon | Mango |
| Comparison | Item checked |
|---|---|
| 1 | |
| 2 | |
| 3 |
- LFig
- LKiwi
- LLemon
(0 + 8) DIV 2 = 4: Fig. Lemon comes after Fig, so first becomes 5. (5 + 8) DIV 2 = 6: Kiwi. Lemon comes after Kiwi, so first becomes 7. (7 + 8) DIV 2 = 7: Lemon, found.
- LEach comparison halves the number of items still to be searched
- Lso far fewer comparisons are needed, whereas a linear search may have to check every item
Every comparison in a binary search discards half of the items that are left, so even a list of a million items needs only about 20 comparisons. A linear search checks the items one at a time and may have to look at all of them.
| Position 0 | Position 1 | Position 2 | Position 3 | |
|---|---|---|---|---|
| After pass 1 | ||||
| After pass 2 |
- LRow 1: 1, 4, 2, 5
- LRow 2: 1, 2, 4, 5
Pass 1: 5 and 1 swap, 5 and 4 swap, 5 and 2 swap, giving 1, 4, 2, 5. Pass 2: 1 and 4 stay, 4 and 2 swap, 4 and 5 stay, giving 1, 2, 4, 5.
Tick one box.
- LD It is usually much faster for large lists
Merge sort is far more time efficient on large lists. It needs extra memory for the lists it merges, and it is harder to write.
Figure 6
def calculate(a, b):
result = a * 2 + b
return result
x = calculate(3, 4)
print(x)- L10
calculate(3, 4) works out 3 * 2 + 4 = 10, which is returned, stored in x and printed.
| Parameter | Local variable | Global variable | |
|---|---|---|---|
| a | |||
| result | |||
| x |
Tick one box in each row.
- La: Parameter
- Lresult: Local variable
- Lx: Global variable
a and b receive the values passed in, so they are parameters. result is created inside the subroutine, so it is local. x is assigned in the main program, so it is global.
- LA subroutine can be called many times, so code is reused rather than written again
- LEach subroutine can be written and tested on its own, or by different programmers, which makes the program easier to debug and maintain
A subroutine can be called whenever it is needed, so the code is written once and reused. Each subroutine is a small, self-contained part that can be tested on its own, or written by a different member of a team, so errors are easier to find and the program is easier to maintain.
| Syntax error | Logic error | |
|---|---|---|
| Leaving out the closing bracket of print( | ||
| Using < instead of <= in a condition | ||
| Spelling the keyword while as whlie | ||
| Adding two numbers that should have been multiplied |
Tick one box in each row.
- L1 mark for both: Leaving out the closing bracket of print(: Syntax error; Using < instead of <= in a condition: Logic error
- L1 mark for both: Spelling the keyword while as whlie: Syntax error; Adding two numbers that should have been multiplied: Logic error
Breaking the rules of the language is a syntax error, so the program will not run. A program that runs but gives the wrong result has a logic error.
| Normal | Boundary | Erroneous | |
|---|---|---|---|
| 27 | |||
| 50 | |||
| fifty |
Tick one box in each row.
- L27: Normal
- L50: Boundary
- Lfifty: Erroneous
27 is a typical valid mark, 50 is at the edge of the allowed range, and fifty is the wrong type of data, so it should be rejected.
Figure 7
01 total = 0
02 for i in range(1, 10):
03 total = total + i
04 print(total)Tick one box.
- LB 02
range(1, 10) stops before 10, so 10 is never added and the total is 45 instead of 55.
- Lfor i in range(1, 11):
for i in range(1, 11):
# Write your program here
- LGets a password from the user
- LOutputs Strong for a long password that contains a digit, such as secure123
- LOutputs Weak for a password with a digit that is too short, such as abc1
- LOutputs Weak for a long password with no digit, such as abcdefghij
- LTreats exactly 8 characters as long enough: abcdefg1 is Strong
Check every character for a digit, then test both rules together with and, using >= 8 so that a password of exactly 8 characters counts.
password = input("Enter a password: ")
hasDigit = False
for character in password:
if character.isdigit():
hasDigit = True
if len(password) >= 8 and hasDigit:
print("Strong")
else:
print("Weak")Figure 9
word ← 'algorithm'
OUTPUT LEN(word)
OUTPUT SUBSTRING(0, 2, word)
OUTPUT POSITION(word, 'r')
OUTPUT CHAR_TO_CODE('B')- L9
- Lalg
- L4
- L66
algorithm has 9 characters. SUBSTRING(0, 2, word) gives the characters at positions 0 to 2 inclusive: alg. r is at position 4, counting from 0. B comes one after A, so its code is 66.
# Write your program here
- LGets a word from the user
- LOutputs 3 for banana
- LCounts upper case vowels too: 5 for EDUCATION
- LOutputs 0 for a word with no vowels, such as rhythm
Loop through the word one letter at a time, converting each to lower case, and add one to a count whenever the letter is in "aeiou".
word = input("Enter a word: ")
count = 0
for letter in word.lower():
if letter in "aeiou":
count = count + 1
print("Number of vowels:", count)Tick one box.
- LC random.randint(1, 6)
randint includes both of its end values, so randint(1, 6) gives 1, 2, 3, 4, 5 or 6.
Figure 10
RECORD Book
title : String
author : String
pages : Integer
onLoan : Boolean
ENDRECORD- LAll the data about one book is kept together under one name
- Lso it is easier to manage: a whole book can be passed to a subroutine, or many books stored in an array of records
A record keeps all the related data about one book together under a single name. That makes the program easier to manage: a whole book can be passed to a subroutine in one go, and the library's books can be stored in a single array of Book records.
Figure 11
scores = [[12, 15, 9],
[20, 18, 22],
[7, 11, 14]]- L22
- L7
scores[1] is the row [20, 18, 22], and item 2 of it is 22. scores[2] is [7, 11, 14], and item 0 of it is 7.
def playerTotal(scores, player):
# Write the subroutine here
pass
- LDefines playerTotal with two parameters
- LReturns 36 for player 0 in Figure 11
- LWorks for any player and any number of rounds
Loop through the player's row, scores[player], adding each score to a running total, then return the total.
def playerTotal(scores, player):
total = 0
for score in scores[player]:
total = total + score
return totaldef playerTotal(scores, player):
total = 0
for score in scores[player]:
total = total + score
return total
def bestPlayer(scores):
# Write the subroutine here
pass
- LDefines bestPlayer with one parameter
- LReturns 1 for the scores in Figure 11
- LWorks when the best player is the first or the last
- LCompares each player's total over every round, for any number of players
Keep the number of the best player so far, starting with player 0. Loop through the other players and, whenever one has a higher total, remember that player instead. Return the player number, not the total.
def playerTotal(scores, player):
total = 0
for score in scores[player]:
total = total + score
return total
def bestPlayer(scores):
best = 0
for player in range(1, len(scores)):
if playerTotal(scores, player) > playerTotal(scores, best):
best = player
return bestUSERNAME = "admin"
PASSWORD = "Secret99"
# Write the rest of your program below
- LOutputs Access granted when both are correct
- LChecks both the username and the password
- LAllows a second attempt
- LAllows a third attempt
- LOutputs Account locked after three wrong attempts, without asking again
- LEnds with Access granted, not Account locked, when the third attempt is right
- LUses iteration to repeat the attempts
Count the failed attempts in a loop that stops when the details are right or after three attempts, checking the username and the password together with and. After the loop, output one message or the other.
USERNAME = "admin"
PASSWORD = "Secret99"
attempts = 0
granted = False
while attempts < 3 and not granted:
username = input("Username: ")
password = input("Password: ")
if username == USERNAME and password == PASSWORD:
granted = True
else:
attempts = attempts + 1
if granted:
print("Access granted")
else:
print("Account locked")# Write your program here
- LCharges £2.00 an hour up to 3 hours: 2 hours costs £4.00
- LRejects fewer than 1 hour and asks again
- LRejects more than 24 hours and asks again
- LCharges £1.50 for each hour after the first 3: 5 hours costs £9.00
- LGets the charge right below the maximum: 8 hours costs £13.50
- LCharges no more than £15.00: 20 hours costs £15.00
- LBlue badge holders pay nothing
- LAccepts the boundary values 1 and 24
- LUses a loop to repeat the validation
Validate the hours with a while loop. Work out the charge for the first 3 hours and the hours after that separately, cap it at 15, and set it to 0 for a blue badge holder before outputting it.
hours = int(input("Number of hours parked: "))
while hours < 1 or hours > 24:
hours = int(input("Enter a whole number of hours from 1 to 24: "))
badge = input("Blue badge (Y/N)? ")
if hours <= 3:
charge = hours * 2.00
else:
charge = 3 * 2.00 + (hours - 3) * 1.50
if charge > 15:
charge = 15.00
if badge == "Y":
charge = 0
print("Charge: £" + format(charge, ".2f"))This is an original paper modelled on the real AQA 8525/1B past papers: the same structure, the same balance of topics, the same command words and mark tariffs, 90 marks in 2 hours, exactly as the real paper allows. It is not a past paper. Real past papers are the copyright of the exam board and cannot be republished here, so links to the official papers on the board's own site are on the exam papers page.