Skip to content
ExamSpine

Markscheme: Practice Paper 2, SL, set 1

Mark your own answers point by point. The number in brackets after each point is what it is worth. Coding parts are checked by running them against tests.

Answer all questions

Question 1[14 marks]

A cinema lets people book seats online.

1.1

The Lumen is a small cinema with one screen of 8 rows, each of 12 seats. It wants an online system that lets customers book seats for its films.

(a) Outline how decomposition could be applied to the design of this booking system. Name two sub-problems in your answer. [3]

(b) The part of the system that lets customers pick seats stores each row as a list of 0s and 1s, where 0 is a free seat and 1 is a booked seat. Identify one detail of the real cinema or its customers that this leaves out, and outline why leaving it out helps. [2]

[5]

  • p1 [1]

    (a) Says decomposition breaks the whole booking problem into smaller sub-problems that can each be designed, written and tested on their own.

  • p2 [1]

    (a) Names one sub-problem of this system, such as choosing a showing, showing the seat plan and picking seats, taking the card payment, or making and emailing the e-ticket.

  • p3 [1]

    (a) Names a second, different sub-problem of this system from the same kind of list.

  • p4 [1]

    (b) Identifies a detail the 0s and 1s leave out, such as who booked a seat, the price of a seat, what the seat looks like or is made of, or how far the seat is from the screen.

  • p5 [1]

    (b) Says leaving it out helps because the seat-picking part only needs to know whether each seat is free, so the data is smaller and the code that searches it is simpler to write and check.

Also accept

  • For p1, "splitting the problem into smaller, more manageable parts that can be worked on separately (or by different people)" earns the mark.
  • For p2 and p3, any two distinct parts of this booking system earn the marks, for example logging in or creating an account, listing films and showing times, or sending a reminder email.
  • For p4, the seat's row letter as printed on the ticket earns the mark, since only a position in a list is kept.
  • For p5, "the programmer can concentrate on the one thing that matters for picking seats" earns the mark.

No marks for

  • For p2 and p3, steps that are not parts of this system, such as "input", "process" and "output", or "build the cinema".
  • For p2 and p3, naming the same sub-problem twice in different words, such as "payment" and "taking the card details".
  • For p4, saying it leaves out whether the seat is booked. That is exactly what the 0s and 1s keep.
  • For p1, defining abstraction (removing unneeded detail) instead of decomposition.

A full-marks answer

(a) Decomposition means breaking the whole booking problem into smaller sub-problems, each of which can be designed, written and tested on its own [p1]. For the Lumen these could be: choosing a showing of a film [p2], and taking the card payment [p3]. (Others are showing the seat plan and picking seats, and making and emailing the e-ticket.)

(b) The 0s and 1s leave out who has booked each seat [p4]. That helps because picking seats only needs to know whether each seat is free, so the data is small and the code that searches it is simpler to write and to check [p5].

1.2

Complete the trace table for this Java code. The Lumen cinema stores one row of seats as an array: 0 is a free seat and 1 is a booked seat. This code goes along the row from seat 0. A cell stays empty for any variable a line leaves unchanged. Then answer the question below the table. [4]

int[] row = {1, 0, 0, 1, 0};
int free = 0;
int first = -1;
for (int i = 0; i < row.length; i++) {
    if (row[i] == 0) {
        free = free + 1;
        if (first == -1) {
            first = i;
        }
    }
}

Why does first start at -1 and not at 0?

The table, made by running the code:

ifreefirst
0
-1
0
1
1
1
2
2
3
4
3
5
  • p1 [1]

    The i column shows 0, 1, 2, 3, 4, then 5, the value that ends the loop.

  • p2 [1]

    The free column shows 0 at the start, then 1 when i is 1, 2 when i is 2, and 3 when i is 4, and does not change when i is 0 or 3.

  • p3 [1]

    The first column shows -1 at the start and changes only once, to 1 when i is 1.

  • p4 [1]

    Says 0 is a real seat position, so starting at 0 would look like seat 0 was free; -1 cannot be a seat, so it means no free seat has been found yet.

1.3

The Lumen cinema's booking system stores one row of seats as a list (an array in Java) of whole numbers: 0 is a free seat and 1 is a booked seat. Seat positions start at 0. A group wants to sit together. Write a function that returns the position of the first seat of the first block of n free seats next to each other.

The design team wrote this plan for it:

RUN = 0
loop through the row from position 0
    if the seat is free, add 1 to RUN
    otherwise set RUN back to 0
    if RUN equals n, return the position
      of the first seat of this block
return -1
  1. A block is n free seats in positions next to each other. If there is more than one such block, return the position of the first seat of the one that comes first (the lowest position).
  2. If the row has no block of n free seats, return -1.
  3. A block may reach the last seat of the row.
  4. n is a whole number from 1 to 30. The row holds only 0s and 1s, has at most 30 seats, and can be empty.

Only the number your function returns is checked.

def first_block(row: list[int], n: int) -> int
public static int firstBlock(int[] row, int n)

Marked by running your code against tests. Open it in the runner to check your answer. The hidden tests check:

  • an empty row (rules 2 and 4)
  • the whole row is the block, starting at seat 0 (rule 1)
  • a block too short at the start, then a long enough one later (rule 1)
  • four free seats together hold more than one block of 2, and the first starts at seat 1 (rule 1)
  • one free seat, which is both the first and the last seat (rules 1 and 3)
  • the only block of 2 is at the end of the row (rule 3)
  • the group is bigger than the free seats there are (rule 2)
  • a block at the start and a longer stretch later; the first block wins (rule 1)

Run it against the tests

[5]

Question 2[15 marks]

A school weather station records the temperature every hour.

2.1

Complete the trace table for this Python code. A school weather station stores one day's hourly temperatures, in whole degrees Celsius, in temps. This code counts the hours below freezing and finds the lowest reading. Then answer the question below the table. [4]

temps = [3, 2, -1, 4, -2, -1]
below = 0
lowest = temps[0]
for t in temps:
    if t < 0:
        below = below + 1
    if t < lowest:
        lowest = t

Why does the code start lowest at temps[0] rather than at 0?

The table, made by running the code:

tbelowlowest
0
3
3
2
2
-1
1
-1
4
-2
2
-2
-1
3
  • p1 [1]

    The t column shows 3, 2, -1, 4, -2, then -1, one row for each reading in order.

  • p2 [1]

    The below column starts at 0 and then goes 1, 2, 3, changing only when t is -1, -2 and the last -1.

  • p3 [1]

    The lowest column starts at 3 and then goes 2, -1, -2, and does not change when t is the last -1.

  • p4 [1]

    States that if every reading were above 0, a lowest starting at 0 would never be replaced, so the code would report 0, which is not one of the readings; temps[0] is a real reading, so the answer is always one of the values.

2.2

A school weather station records the temperature once an hour, in whole degrees Celsius, and stores one day's readings in order in a list (an array in Java) called temps.

Write a function that returns the biggest rise in temperature from one hour to the next hour.

  1. A rise is a reading minus the reading one hour before it, such as temps[3] - temps[2].
  2. Only rises between hours next to each other count, including the rise into the last hour.
  3. If the temperature never goes up from one hour to the next, return 0. A fall is never a rise, however big it is.
  4. temps always has at least two readings, each between -60 and 60.
  5. Write the comparison yourself. The shortcuts listed with this question are not allowed.

Only the number your function returns is checked.

def biggest_rise(temps: list[int]) -> int
public static int biggestRise(int[] temps)

Paper 2 questions often ask you to find the largest value yourself, without a built-in, so practise the loop and the comparison.

Marked by running your code against tests. Open it in the runner to check your answer. The hidden tests check:

  • a big rise early, then a fall and a small rise
  • only two readings (rule 4)
  • readings below 0, and the biggest rise ends the day (rules 2 and 4)
  • a big rise late in the day, followed by a bigger fall (rule 3)
  • no change at all is not a rise (rule 3)
  • a reading well below the first one, so measuring from the first hour gives the wrong answer (rule 1)
  • a big fall first, then a small rise (rule 3)

Run it against the tests

[5]

2.3

The school weather station keeps a week of hourly readings in a two-dimensional list (a 2D array in Java) called grid. Each row is one day and each value in a row is one hourly temperature in whole degrees Celsius, so grid[2][5] is the reading for day 2, hour 5.

Write a function that returns the number of the day (the row index) whose readings add up to the highest total. Days are numbered from 0.

  1. A day's total is the sum of every reading in its row.
  2. If two or more days share the highest total, return the first of them.
  3. grid has at least one row, every row has at least one reading, and rows can have different lengths.
  4. Readings are between -60 and 60, and a row has at most 24 readings, so totals can be below 0.
  5. Write the adding and the comparing yourself. The shortcuts listed with this question are not allowed.

Only the number your function returns is checked.

def warmest_day(grid: list[list[int]]) -> int
public static int warmestDay(int[][] grid)

Paper 2 questions on 2D arrays expect you to write the nested loops that add each row yourself, so practise them without the built-ins.

Marked by running your code against tests. Open it in the runner to check your answer. The hidden tests check:

  • a later day has more readings than the first day, and all of them count (rules 1 and 3)
  • one day with one reading (rule 3)
  • rows of different lengths, and a tie at the start (rules 2 and 3)
  • all totals far below 0 (rule 4)
  • each day must start its total again, not carry on from the day before (rule 1)
  • a tie between the last two days (rule 2)
  • the hottest hour is on day 2, the highest total on day 1 (rule 1)

Run it against the tests

[6]

Question 3[15 marks]

A school library program keeps track of its books with a Book class.

3.1

A school library program has a Book class. Here it is in Python and in Java.

class Book:
    def __init__(self, title, copies):
        self.title = title
        self.__available = copies

    def get_available(self):
        return self.__available

    def borrow(self):
        if self.__available > 0:
            self.__available -= 1
            return True
        return False
public class Book {
    private String title;
    private int available;

    public Book(String title, int copies) {
        this.title = title;
        this.available = copies;
    }

    public int getAvailable() {
        return available;
    }

    public boolean borrow() {
        if (available > 0) {
            available--;
            return true;
        }
        return false;
    }
}

(a) Identify the method in Book that is an accessor. [1]

(b) The number of available copies is private (in Python, its name starts with two underscores). Explain why it is private, and why code outside the class changes it only by calling borrow. [3]

(c) Another part of the program runs Book("Dune", 2) (in Java, new Book("Dune", 2)) and Book("Emma", 1). Distinguish between the class Book and the objects these lines create. [2]

[6]

  • p1 [1]

    (a) Identifies get_available (in Java, getAvailable) as the accessor.

  • p2 [1]

    (b) Says making it private hides it, so code outside the class cannot read or set it directly (encapsulation, or information hiding).

  • p3 [1]

    (b) Says borrow checks that a copy is available before taking one away, so the count can never be set to an impossible value such as a negative number.

  • p4 [1]

    (b) Says that because every change goes through the class's own methods, the class controls its data, so the way the count is stored can change, or a bug in it be found, in one place without changing the code that uses the class.

  • p5 [1]

    (c) Says the class is the template (blueprint) that defines what attributes and methods every book has, and exists once.

  • p6 [1]

    (c) Says each object is one instance made from the class, with its own values, so the Dune object has its own title and count of 2, and the Emma object its own title and count of 1.

Also accept

  • For p2, "other classes cannot access the variable directly; it can only be accessed through methods" earns the mark.
  • For p3, "borrow validates the change, so available cannot go below 0" earns the mark.
  • For p4, "it reduces the chance of other code corrupting the data by mistake, and keeps the rule for borrowing in one place" earns the mark.
  • For p6, "an object is an instantiation of the class, created by calling the constructor, and holds its own state" earns the mark.

No marks for

  • For (a), naming borrow. It changes the count, so it is a mutator, not an accessor.
  • For (a), naming __init__ or the constructor. It creates the object; it is not an accessor.
  • For (b), saying private makes the data secret from the user, or encrypted. Private controls which code can reach it, not who can see the screen.
  • For (b), saying private makes the program run faster.
  • For (c), saying the class and the object are the same thing, or that the second line changes the first object.

A full-marks answer

(a) get_available (getAvailable in Java) [p1].

(b) Making the count private hides it, so code outside the class cannot read or set it directly [p2]. The only way to change it is to call borrow, and borrow checks that a copy is available first, so the count can never become an impossible value such as -1 [p3]. Because every change goes through the class's own methods, the class keeps control of its data: the rule for borrowing is in one place, and the way the count is stored can change without changing any code that uses Book [p4].

(c) The class Book is the template that says every book has a title and a count of available copies, and the methods get_available and borrow; there is one class [p5]. Each line creates an object, an instance of the class with its own values: one object has the title "Dune" and 2 copies, the other has "Emma" and 1 copy [p6].

3.2

The school library's Book class now also counts how many books have been created. Here it is in Python and in Java, with code that uses it. In Java the last part runs inside a main method.

class Book:
    count = 0

    def __init__(self, title, copies):
        self.title = title
        self.__available = copies
        Book.count += 1

    def get_available(self):
        return self.__available

    def borrow(self):
        if self.__available > 0:
            self.__available -= 1
            return True
        return False

b1 = Book("Dune", 1)
b2 = Book("Emma", 2)
print(b1.borrow())
print(b1.borrow())
print(b2.borrow())
print(b2.get_available())
print(Book.count)
public class Book {
    private static int count = 0;
    private String title;
    private int available;

    public Book(String title, int copies) {
        this.title = title;
        this.available = copies;
        count++;
    }

    public int getAvailable() {
        return available;
    }

    public boolean borrow() {
        if (available > 0) {
            available--;
            return true;
        }
        return false;
    }

    public static int getCount() {
        return count;
    }
}

// in main
Book b1 = new Book("Dune", 1);
Book b2 = new Book("Emma", 2);
System.out.println(b1.borrow());
System.out.println(b1.borrow());
System.out.println(b2.borrow());
System.out.println(b2.getAvailable());
System.out.println(Book.getCount());

(a) State the five lines of output, in order. [3]

(b) Explain why the last line of output is 2 and not 1. [2]

[5]

  • p1 [1]

    (a) The first two lines are True then False (true then false in Java), because Dune has only one copy.

  • p2 [1]

    (a) The third and fourth lines are True (true in Java) then 1, because Emma's borrow takes its count from 2 to 1.

  • p3 [1]

    (a) The fifth line is 2.

  • p4 [1]

    (b) Says count is a static (class) variable, so there is one copy of it shared by the class, not one per object.

  • p5 [1]

    (b) Says the constructor adds 1 to that one shared count each time an object is created, and two objects were created, so it ends at 2.

Also accept

  • For p1 and p2, writing true and false in lower case for the Python version, or True and False in title case for the Java version, earns the marks; the case is not what is being tested.
  • For p4, "count belongs to the class Book, while title and available belong to each object" earns the mark.

No marks for

  • For (a), 0 as the fourth line. Only Emma's own count changed, from 2 to 1; Dune's borrow does not affect Emma.
  • For (a), True as the second line. Dune's one copy was taken by the first borrow.
  • For (b), saying count is 2 because two borrows succeeded. count changes only in the constructor.
  • For (b), saying each object has its own count of 1. A static variable has one value for the whole class.

A full-marks answer

(a) True, False [p1], True, 1 [p2], 2 [p3]. In Java the first three are written true, false, true.

(b) count is a static (class) variable, so there is only one of it, shared by the class Book rather than stored in each object [p4]. The constructor adds 1 to it every time a Book is created. b1 and b2 were created, so it went from 0 to 1 to 2 [p5].

3.3

A school library keeps a Book object for each title. Its mutator methods refuse a change that would make the number of copies on the shelf impossible. Write a function that works out the same thing from simple data: it is given how many copies of a book the library owns, all on the shelf at the start, and a list (an array in Java) of actions, carried out in order. It returns how many copies are on the shelf after the last action.

  1. "borrow" takes one copy off the shelf, but only if at least one copy is there. Otherwise it is refused and changes nothing.
  2. "return" puts one copy back, but only if fewer than total copies are on the shelf. Otherwise it is refused and changes nothing.
  3. Any other text, such as "renew", changes nothing. Capital letters matter: "Borrow" is not "borrow".
  4. total is a whole number from 0 to 50. There are at most 50 actions, and the list can be empty.

Only the number your function returns is checked.

def copies_left(total: int, actions: list[str]) -> int
public static int copiesLeft(int total, String[] actions)

Marked by running your code against tests. Open it in the runner to check your answer. The hidden tests check:

  • no actions, so every copy is still on the shelf (rule 4)
  • a refused borrow, then a return (rules 1 and 2)
  • returns when the shelf is already full are refused (rule 2)
  • more borrows than copies (rule 1)
  • Borrow with a capital letter changes nothing (rule 3)
  • a library with no copies refuses both (rules 1 and 2)
  • the copy goes out, comes back, and goes out again (rules 1 and 2)

Run it against the tests

[4]

Back to the paper