Computer Science 9618/42 — October/November 2023
Cambridge A-Level · Practical · worked solutions for every part, with the mark scheme
Topics Programming Paradigms (Procedural and Object-oriented) · Algorithms and Abstract Data Types · File Processing and Exception Handling · Recursion
Open the evidence document, evidence.doc
Make sure that your name, centre number and candidate number appear on every page of this document. This document must contain your answers to each question.
Save this evidence document in your work area as:
evidence_ followed by your centre number_candidate number, for example: evidence_zz999_9999
A class declaration can be used to declare a record.
If the programming language used does not support arrays, a list can be used instead.
One source file is used to answer Question 1. The file is called StackData.txt
A program stores lower-case letters in two stacks.
One stack stores vowels (a, e, i, o, u) and one stack stores consonants (letters that are not vowels).
Each stack is implemented as a 1D array.
Write program code to declare two 1D global arrays: StackVowel and StackConsonant.
Each array needs to store up to 100 letters. The index of the first element in each array is 0.
If you are writing in Python, include declarations using comments.
Save your program as Question1_N23.
Copy and paste the program code into part 1(a)(i) in the evidence document.
Answer
# global array StackVowel[0:99]
StackVowel = [''] * 100
# global array StackConsonant[0:99]
StackConsonant = [''] * 100
See program code
Background Concept
A stack is a last-in, first-out data structure. In this question, each stack is being implemented using a 1D array. That means we reserve storage first, then use a separate pointer to keep track of where the next item should go.
In Python, there is no built-in fixed-size array in the same sense used by exam questions, so the usual exam approach is to use a list of the required size and add a comment to show the intended declaration. Because the arrays must store up to 100 letters and the first index is 0, the valid positions are 0 to 99.
Understanding the Question
This part only asks for the two global arrays, not the pointers and not any procedures yet. The key details are:
- there are two stacks
- each is a 1D array
- each must hold 100 letters
- indexing starts at 0
- Python answers should include declaration comments
So the job here is to create storage for both stacks in global scope.
Approach
The simplest Python representation is a list with 100 elements already created. That matches the exam idea of a fixed-size array. A blank string is a suitable placeholder value for each unused position.
Because the question specifically mentions global arrays, the declarations should be written outside any function or procedure.
Step-by-Step Reasoning
First, create the vowel stack storage:
- the name must be
StackVowel - it must be global
- it must have 100 positions
- a Python list of
[''] * 100gives exactly 100 string slots
Then do the same for the consonant stack:
- the name must be
StackConsonant - it must also have 100 positions
The comments are included because the paper explicitly says Python candidates should show declarations using comments. That helps show the examiner that you understand these are intended as fixed-size global arrays, not just ordinary variable-length lists.
Key Takeaways
- A stack can be implemented using a 1D array plus a pointer.
- If indexing starts at 0 and there are 100 items, the last valid index is 99.
- In Python practical papers, declaration comments are often used to show intended data structures.
Common Mistakes
- Declaring only one array instead of both arrays.
- Creating empty lists with no size, which does not match the fixed-size array requirement as clearly.
- Using 1 to 100 as the index range even though the question says the first index is 0.
- Putting the arrays inside a function, which would make them local instead of global.
Things to Be Careful About
- Use the exact names
StackVowelandStackConsonant. - Make sure each list has 100 elements, not 99 or 101.
- In Python, the comment is not a substitute for the actual list creation; you should show both the declaration comment and the usable storage.
The global variable VowelTop is a pointer that stores the index of the next free space in StackVowel.
The global variable ConsonantTop is a pointer that stores the index of the next free space in StackConsonant.
VowelTop and ConsonantTop are both initialised to 0.
Write program code to declare and initialise the two variables.
If you are writing in Python, include declarations using comments.
Save your program.
Copy and paste the program code into part 1(a)(ii) in the evidence document.
Answer
# global integer VowelTop
VowelTop = 0
# global integer ConsonantTop
ConsonantTop = 0
See program code
Background Concept
When a stack is implemented with an array, a pointer is needed to track the current top position. In this question, the pointer does not store the index of the current top item. Instead, it stores the index of the next free space. That is an important detail.
If the next free space is 0, the stack is empty because no items have been placed yet. After one push, the item is stored at index 0 and the pointer becomes 1.
Understanding the Question
This part tells you exactly what the two global variables mean:
VowelTopstores the next free position inStackVowelConsonantTopstores the next free position inStackConsonant- both start at 0
So you are not choosing a design here; you are implementing the pointer design the question gives you.
Approach
Declare each pointer as a global integer variable and set it to 0. In Python, include comments to show the declaration type, because Python itself does not require type declarations.
Step-by-Step Reasoning
VowelTop = 0 means the vowel stack is empty and the first vowel pushed will go into index 0.
ConsonantTop = 0 means the consonant stack is also empty and the first consonant pushed will go into index 0.
These variables must be global because later procedures and functions such as PushData(), PopVowel() and PopConsonant() all need to update them.
Key Takeaways
- A stack pointer can represent the next free slot rather than the current top item.
- An empty stack is often represented by pointer value 0 when using 0-based indexing and next-free-space logic.
- Global state is needed here because multiple routines share the same stacks and pointers.
Common Mistakes
- Setting the pointers to
-1, which would be a different stack design from the one described. - Forgetting that the variables must be global.
- Initialising one pointer but not the other.
Things to Be Careful About
- Use the exact variable names and casing from the question.
- Keep the meaning of the pointer consistent throughout the whole program: next free space, not current top item.
- If later code assumes a different meaning for the pointer, the push and pop logic will not match.
The procedure PushData() takes one letter as a parameter.
If the parameter is a vowel, it is pushed onto StackVowel and the relevant pointer updated.
If the stack is full, a suitable message is output.
If the parameter is a consonant, it is pushed onto StackConsonant and the relevant pointer updated.
If the stack is full, a suitable message is output.
You do not need to validate that the parameter is a letter.
Write program code for PushData().
Save your program.
Copy and paste the program code into part 1(b)(i) in the evidence document.
Answer
def PushData(Letter):
global VowelTop, ConsonantTop
if Letter in ['a', 'e', 'i', 'o', 'u']:
if VowelTop < 100:
StackVowel[VowelTop] = Letter
VowelTop += 1
else:
print('Vowel stack full')
else:
if ConsonantTop < 100:
StackConsonant[ConsonantTop] = Letter
ConsonantTop += 1
else:
print('Consonant stack full')
See program code
Background Concept
A push operation adds an item to the top of a stack. With an array-based stack, that means:
- check whether there is space
- store the item at the next free position
- move the pointer on to the next free position
Because this question has two stacks, the procedure must first decide which stack the letter belongs in. The question defines vowels as a, e, i, o, u, and everything else is treated as a consonant. It also says you do not need to validate whether the input is actually a letter.
Understanding the Question
PushData() receives one lower-case character. If it is a vowel, it must go into StackVowel. Otherwise it must go into StackConsonant.
For either stack, if it is full, the program must output a suitable message instead of writing beyond the end of the array.
The parent stem matters here because:
- both arrays are global and size 100
- both pointers start at 0
- the pointer stores the next free space
Approach
Use a membership test to decide whether the character is a vowel. Then, for the chosen stack:
- test whether the top pointer is still below 100
- if so, store the letter at that index
- increment the pointer
- otherwise output a full-stack message
This is the standard array-based push pattern.
Step-by-Step Reasoning
The procedure needs global VowelTop, ConsonantTop because those values must be changed permanently, not just inside the function.
The condition Letter in ['a', 'e', 'i', 'o', 'u'] separates vowels from consonants.
If it is a vowel:
VowelTop < 100checks whether there is room- if true, store the letter in
StackVowel[VowelTop] - then do
VowelTop += 1
That order matters. Because the pointer stores the next free space, the item goes into the current pointer position first, and only then does the pointer move up.
If VowelTop is already 100, the stack is full. The last valid index is 99, so 100 means there is no free space left.
The consonant branch is exactly the same idea but uses StackConsonant and ConsonantTop.
A strong exam answer keeps the two branches parallel so the logic is easy to follow and easy to mark.
Key Takeaways
- Push on an array-based stack means store first, then increment the next-free pointer.
- Overflow must be checked before writing to the array.
- When two similar data structures exist, it is often best to write matching logic for both.
Common Mistakes
- Incrementing the pointer before storing the letter, which skips index 0 and misplaces every later item.
- Testing
<= 100instead of< 100, which allows an attempt to write to index 100. - Forgetting the
globaldeclaration in Python, so the pointer update does not affect the real stack. - Using a vowel test that misses one of the vowels.
Things to Be Careful About
- The pointer represents the next free slot, not the current top element.
- The full condition is when the pointer reaches 100, because indices run from 0 to 99.
- The question says lower-case letters, so a lower-case vowel check is sufficient.
- You do not need input validation here, so do not waste time adding it unless you are certain it will not break the required logic.
The file StackData.txt stores 100 lower-case letters.
The procedure ReadData() reads each letter from the file and uses PushData() to push each letter onto its appropriate stack.
Use appropriate exception handling if the file does not exist.
Write program code for ReadData().
Save your program.
Copy and paste the program code into part 1(b)(ii) in the evidence document.
Answer
def ReadData():
try:
File = open('StackData.txt', 'r')
for Line in File:
Letter = Line.strip()
PushData(Letter)
File.close()
except FileNotFoundError:
print('File does not exist')
See program code
Background Concept
Sequential file processing means reading a file one item after another from start to end. Here, StackData.txt contains 100 lower-case letters, one per line. A typical routine must:
- open the file
- read each line
- convert the raw line into the required data item
- process that item
- close the file
Exception handling is used so the program does not crash if the file is missing. In Python, attempting to open a file that does not exist raises FileNotFoundError.
Understanding the Question
This part does not ask you to decide which stack to use. That logic is already inside PushData(). ReadData() only needs to:
- read the letters from
StackData.txt - pass each letter to
PushData() - use appropriate exception handling if the file does not exist
So the key idea is delegation: reading is done here, stack classification is done in the other procedure.
Approach
Put the file opening and reading inside a try block. Read each line in turn, remove the newline using strip(), then send the cleaned letter to PushData(). If opening the file fails, catch the exception and print a suitable message.
Step-by-Step Reasoning
File = open('StackData.txt', 'r') opens the source file for reading.
for Line in File: loops through every line in order. Since the file stores one lower-case letter per line, each iteration represents one letter.
Letter = Line.strip() removes the newline character. Without this, the value passed to PushData() would be something like 'a\n' rather than 'a', which would break the vowel test.
PushData(Letter) then pushes the cleaned character onto the correct stack.
File.close() closes the file once reading has finished.
If the file cannot be opened, control moves to the except FileNotFoundError: block, and the program outputs a suitable message instead of stopping with an error.
Key Takeaways
- Read sequential text files one line at a time when each line holds one item.
- Clean line-based input before processing it.
- Use exception handling to make file operations safe.
- Keep routines focused: one routine reads data, another decides where to store it.
Common Mistakes
- Forgetting to remove the newline from each line.
- Reading the file but never calling
PushData(). - Omitting exception handling, so the program crashes if the file is missing.
- Using the wrong filename or wrong file mode.
Things to Be Careful About
- The filename must match exactly:
StackData.txt. strip()is important here because each line ends with a line break.- If you use explicit
open(), remember to close the file after reading. - The question says the file stores 100 letters, but a loop that reads until the file ends is still appropriate and safe.
The function PopVowel() removes and returns the data at the top of StackVowel and updates the relevant pointer(s).
The function PopConsonant() removes and returns the data from the top of StackConsonant and updates the relevant pointer(s).
If either stack is empty, the string "No data" must be returned.
Write program code to declare PopVowel() and PopConsonant().
Save your program.
Copy and paste the program code into part 1(c) in the evidence document.
Answer
def PopVowel():
global VowelTop
if VowelTop == 0:
return 'No data'
else:
VowelTop -= 1
return StackVowel[VowelTop]
def PopConsonant():
global ConsonantTop
if ConsonantTop == 0:
return 'No data'
else:
ConsonantTop -= 1
return StackConsonant[ConsonantTop]
See program code
Background Concept
A pop operation removes and returns the top item from a stack. With the pointer design used in this question, the pointer stores the next free space, not the current top item. That changes the order of operations.
If the stack is not empty:
- move the pointer back by 1
- read and return the item at that index
If the pointer is 0, the stack is empty and a pop would cause underflow. The question tells you exactly what to return in that case: No data.
Understanding the Question
You must write two separate functions:
PopVowel()forStackVowelPopConsonant()forStackConsonant
Each must:
- remove and return the top item
- update the correct pointer
- return
No dataif the relevant stack is empty
The exact return string matters here because later code in the main program will test for it.
Approach
Use the same pattern in both functions:
- if the relevant top pointer is 0, return
No data - otherwise decrement the pointer and return the element at the new pointer position
This mirrors the push logic used earlier.
Step-by-Step Reasoning
Take PopVowel() first.
global VowelTop is needed because the function changes the actual pointer.
if VowelTop == 0: checks whether the stack is empty. Since the pointer stores the next free space, 0 means no items have ever been pushed or all pushed items have been popped.
If it is empty, return No data immediately.
Otherwise:
- do
VowelTop -= 1 - then return
StackVowel[VowelTop]
Why decrement first? Suppose there is one item in the stack. After it was pushed, VowelTop became 1. The top item is actually at index 0. So to access the top item correctly, you must move the pointer back first.
PopConsonant() is identical in structure, but it uses ConsonantTop and StackConsonant.
Key Takeaways
- With a next-free-space pointer, pop means decrement first, then access the array.
- Underflow happens when trying to pop from an empty stack.
- Returning a fixed message such as
No datalets the main program detect failure cleanly.
Common Mistakes
- Returning
StackVowel[VowelTop]before decrementing, which reads the next free slot instead of the top item. - Forgetting to return
No dataexactly as specified. - Updating the wrong pointer in one of the functions.
- Forgetting
global, so the real pointer does not change.
Things to Be Careful About
- The empty test is
== 0, not< 0. - The return string must match exactly because the main program compares against it.
- Keep the logic for the two functions separate; do not accidentally read from the vowel array using the consonant pointer or vice versa.
The program first needs to call ReadData() and then:
- prompt the user to input their choice of vowel or consonant
- take, as input, the user’s choice
- depending on the user’s choice, call
PopVowel()orPopConsonant()and store the return value.
The three steps are repeated until 5 letters have been successfully returned and stored.
If either stack is empty at any stage, an appropriate message must be output.
Once 5 letters have been successfully returned and stored, they are output on one line, for example:
abyti
Write program code for the main program.
Save your program.
Copy and paste the program code into part 1(d)(i) in the evidence document.
Answer
ReadData()
ReturnedLetters = []
while len(ReturnedLetters) < 5:
Choice = input('Enter vowel or consonant: ')
if Choice == 'vowel':
Letter = PopVowel()
if Letter == 'No data':
print('Vowel stack empty')
else:
ReturnedLetters.append(Letter)
elif Choice == 'consonant':
Letter = PopConsonant()
if Letter == 'No data':
print('Consonant stack empty')
else:
ReturnedLetters.append(Letter)
print(''.join(ReturnedLetters))
See program code
Background Concept
The main program is the control section that coordinates previously written routines. In this question, the main program does not implement stack operations directly. Instead, it:
- loads the stacks from the file
- asks the user which stack to pop from
- calls the appropriate pop function
- stores successful results
- stops only after 5 letters have been successfully returned
The phrase successfully returned is important. It means the count should only increase when a real letter is obtained, not when the function returns No data.
Understanding the Question
The order of actions is given very clearly:
- call
ReadData()first - prompt and input the user's choice
- depending on that choice, call
PopVowel()orPopConsonant()and store the returned value - repeat until 5 letters have been successfully returned and stored
- if a stack is empty, output an appropriate message
- after 5 successful letters, output them on one line
So this is a loop-control problem as much as it is a stack problem.
Approach
A good structure is:
- call
ReadData()once at the start - create a list to store returned letters
- use a
whileloop that continues until the list length is 5 - inside the loop, get the user's choice
- call the correct pop function
- if the return value is
No data, print an empty-stack message and do not store it - otherwise append the letter to the list
- after the loop, join the five letters into one string and print it
Step-by-Step Reasoning
ReadData() must happen before any popping, otherwise both stacks would still be empty.
ReturnedLetters = [] creates a place to store the successful results in order.
while len(ReturnedLetters) < 5: makes the loop continue until exactly 5 successful letters have been stored. This is better than repeating 5 times, because an empty-stack result must not count.
Choice = input('Enter vowel or consonant: ') gets the user's instruction.
If the choice is vowel, the program calls PopVowel(). The returned value is stored in Letter.
Then the program checks whether Letter == 'No data'.
- If yes, the vowel stack is empty, so a message is output.
- If no, a real letter was returned, so it is appended to
ReturnedLetters.
The consonant branch works the same way with PopConsonant().
Finally, print(''.join(ReturnedLetters)) outputs the 5 collected letters on one line with no spaces, which matches the format shown in the question.
A slightly more defensive program could also handle invalid input, but the question does not require that, so a clean if/elif answer is sufficient.
Key Takeaways
- Count successful outcomes, not just loop iterations, when failure is possible.
- Keep stack logic inside the pop functions and use the main program only for control flow.
- Build a final string by collecting characters in order and joining them.
Common Mistakes
- Using a loop that repeats exactly 5 times even if some pops return
No data. - Forgetting to call
ReadData()before the loop. - Appending
No datato the result list instead of rejecting it. - Printing each letter separately instead of one combined line at the end.
Things to Be Careful About
- Compare with the exact string
No data. - Only append when a real letter is returned.
- The final output must be one line, so joining the list is a good Python approach.
- If you use
elseinstead ofelif, be sure you are not accidentally treating every non-vowel input as consonant unless that is your intended design.
Test your program with the following inputs:
vowel
consonant
consonant
vowel
vowel
Take a screenshot of the output.
Save your program.
Copy and paste the screenshot into part 1(d)(ii) in the evidence document.
Answer
Using the inputs vowel, consonant, consonant, vowel, vowel:
Enter vowel or consonant: vowel
Enter vowel or consonant: consonant
Enter vowel or consonant: consonant
Enter vowel or consonant: vowel
Enter vowel or consonant: vowel
uxsoe
uxsoe
Background Concept
To predict the output of a stack program, you must remember that stacks are last-in, first-out. The most recently pushed item is the first one popped.
Because ReadData() reads the file from top to bottom and pushes each letter onto its appropriate stack, the top of each stack will contain the last matching letter found in the file.
Understanding the Question
This part is not asking for new code. It is asking you to run the finished program using these five choices:
vowelconsonantconsonantvowelvowel
So we must work out exactly which letters those five pop operations return after the file has been loaded.
Approach
Split the file contents into two conceptual stacks:
- all vowels in the order they are read
- all consonants in the order they are read
Then reverse your thinking for popping, because the last item pushed is on top.
Take the five choices one by one and record each returned character.
Step-by-Step Reasoning
From StackData.txt, the last few vowels read are:
... i, u, e, o, u
So after all pushes, the top of the vowel stack is the final u, then below it o, then below that e.
The last few consonants read are:
... g, j, k, n, c, s, x
So the top of the consonant stack is x, then below it s, then below that c.
Now apply the required inputs in order.
vowel→ pop from vowel stack → returnsuconsonant→ pop from consonant stack → returnsxconsonant→ pop from consonant stack again → returnssvowel→ next vowel pop → returnsovowel→ next vowel pop → returnse
So the five returned letters are:
uxsoe
Joined together on one line, the output is uxsoe.
No empty-stack message appears in this test because both stacks still contain plenty of data.
Key Takeaways
- For stack tracing, always find the last matching items read from the file.
- A mixed input sequence can alternate between two separate stacks.
- The final displayed string is the successful pop results in the order they were returned.
Common Mistakes
- Reading from the start of the file instead of from the top of the stack when predicting pops.
- Mixing vowel and consonant order together instead of treating them as separate stacks.
- Forgetting that the result is output as one combined line, not as separate letters.
Things to Be Careful About
- Use the final loaded stack contents, not the original file order, when deciding pop results.
- After one pop, the next item from that same stack becomes the new top.
- The exact output shown depends on the prompt text in your program, but the key returned string here is
uxsoe.
The rest of this paper
2 more questions- Q2Programming Paradigms (Procedural and Object-oriented) · Recursion17M
- Q3Programming Paradigms (Procedural and Object-oriented)31M