AP · thinka-original Practice Paper

2025 AP AP Computer Science A Practice Paper with Answers

Thinka May 2025 AP-Style Mock — AP Computer Science A

36 marks90 mins2025
An original Thinka practice paper modelled on the structure and difficulty of the May 2025 AP AP Computer Science A paper. Not affiliated with or reproduced from AP.

Section II: Free-Response Questions

Answer all 4 questions in Java. Credit for partial solutions will be given. Write method implementations and complete classes according to provided specifications.
4 Question · 36 marks
Question 1 · free_response
9 marks
This question involves a bicycle tour organizer who coordinates group rentals from different bike hubs throughout a city. A network of bike hubs is represented by the BikeHubNetwork class.

public class BikeHubNetwork
{
/**
* Returns the number of functional bikes, always greater than 0, available
* at the hub specified by hubId
* Precondition: 0 <= hubId <= 50
/
public int numAvailableBikes(int hubId)
{ /
implementation not shown */ }

/**
* Decreases the inventory of available bikes at hubId by bikesTaken
* Preconditions: 0 <= hubId <= 50
* bikesTaken > 0
/
public void checkoutBikes(int hubId, int bikesTaken)
{ /
implementation not shown / }

/
There may be instance variables, constructors,
and methods that are not shown. */
}

A tour guide leads excursions and is represented by the TourGuide class. You will write two methods of the TourGuide class.

public class TourGuide
{
/** The maximum group capacity this guide can supervise per tour stop */
private int maxCapacity;

/** The hub network this guide operates within */
private BikeHubNetwork network;

/**
* Assigns max to maxCapacity and net to network
* Precondition: max > 0
/
public TourGuide(int max, BikeHubNetwork net)
{ /
implementation not shown */ }

/**
* Reserves and retrieves bikes for a tour stop at the hub specified by hubId,
* as described in part (a)
* Preconditions: 0 <= hubId <= 50
* maxCapacity > 0
/
public int organizeTour(int hubId)
{ /
to be implemented in part (a) */ }

/**
* Leads a sequence of tours from startHubId to endHubId, inclusive,
* and returns the total compensation earned, as described in part (b)
* Preconditions: 0 <= startHubId <= endHubId <= 50
* maxCapacity > 0
/
public int guideShift(int startHubId, int endHubId)
{ /
to be implemented in part (b) / }

/
There may be instance variables, constructors,
and methods that are not shown. */
}



Part (a)

Write the organizeTour method, which updates hub inventory and returns the number of bikes reserved by the tour guide for the hub specified by hubId.

The helper method numAvailableBikes in BikeHubNetwork returns the number of bikes currently ready at a given hub. The tour guide takes as many bikes as are available at the hub, up to a maximum of maxCapacity.

The helper method checkoutBikes in BikeHubNetwork must be invoked to deduct the reserved bikes from the hub's inventory so that other guides cannot claim the same bikes.

Complete method organizeTour below. You must use numAvailableBikes and checkoutBikes appropriately to receive full credit.

/**
* Reserves and retrieves bikes for a tour stop at the hub specified by hubId,
* as described in part (a)
* Preconditions: 0 <= hubId <= 50
* maxCapacity > 0
*/
public int organizeTour(int hubId)



Part (b)

Write the guideShift method, which processes a series of tour stops across consecutive hub IDs from startHubId through endHubId, inclusive, and returns the total payment earned in dollars.

For each hub visited during the shift:

  • The base compensation is $8 per bike organized at that hub.

  • An additional bonus of $5 is awarded for that hub stop if at least one of the following is true:

    • The number of bikes organized equals maxCapacity.

    • The hubId falls within the downtown zone of 10 through 20, inclusive.





For example, if maxCapacity is 4, and the guide visits hubs 8 through 11 with the following bike counts:

  • Hub 8: 4 bikes organized → \(4 \times 8 + 5 = 37\) dollars (capacity reached)

  • Hub 9: 2 bikes organized → \(2 \times 8 = 16\) dollars

  • Hub 10: 2 bikes organized → \(2 \times 8 + 5 = 21\) dollars (downtown zone)

  • Hub 11: 4 bikes organized → \(4 \times 8 + 5 = 37\) dollars (both conditions met, bonus applied once)


Total compensation returned would be \(37 + 16 + 21 + 37 = 111\) dollars.

Complete method guideShift below. Assume that organizeTour works as specified, regardless of what you wrote in part (a). You must use organizeTour appropriately to receive full credit.

/**
* Leads a sequence of tours from startHubId to endHubId, inclusive,
* and returns the total compensation earned, as described in part (b)
* Preconditions: 0 <= startHubId <= endHubId <= 50
* maxCapacity > 0
*/
public int guideShift(int startHubId, int endHubId)
Show answer & marking scheme

Worked solution

Part (a) Solution


public int organizeTour(int hubId)
{
int available = network.numAvailableBikes(hubId);
int toTake = available;
if (toTake > maxCapacity)
{
toTake = maxCapacity;
}
network.checkoutBikes(hubId, toTake);
return toTake;
}

Part (b) Solution


public int guideShift(int startHubId, int endHubId)
{
int totalEarned = 0;
for (int hub = startHubId; hub <= endHubId; hub++)
{
int bikes = organizeTour(hub);
int stopPay = bikes * 8;
if (bikes == maxCapacity || (hub >= 10 && hub <= 20))
{
stopPay += 5;
}
totalEarned += stopPay;
}
return totalEarned;
}

Marking scheme

Part (a): organizeTour (4 Points)



  • Point 1: Calls BikeHubNetwork method(s) on network (1 pt)

    • Do not award if: calls methods without a reference object or on something other than network.



  • Point 2: Compares available bikes and maxCapacity to determine the number of bikes to organize (1 pt)

  • Point 3: Calls numAvailableBikes with hubId and checkoutBikes with hubId and correct number of bikes to take (1 pt)

  • Point 4: Returns calculated integer number of bikes organized (1 pt)



Part (b): guideShift (5 Points)



  • Point 5: Iterates through all hub IDs from startHubId to endHubId, inclusive (1 pt)

  • Point 6: Calls organizeTour with int parameter inside the loop (1 pt)

    • Do not award if: called multiple times per iteration, which would cause unintended multiple inventory deductions.



  • Point 7: Calculates base compensation ($8 per bike organized) for each hub stop (1 pt)

  • Point 8: Correctly determines bonus condition (evaluates whether bikes organized equals maxCapacity OR current hub ID is between 10 and 20 inclusive, adding $5 at most once) (1 pt)

  • Point 9: Accumulates total pay across all iterations and returns the accumulated total (1 pt)

Question 2 · free-response
9 marks
This question involves the `SecurityPass` class, which is used to manage access credentials for a secured facility. You will write the complete `SecurityPass` class, which contains a constructor and two methods.

The `SecurityPass` constructor takes two parameters: a `String` representing the pass ID and an `int` representing the access level. The length of the pass ID parameter is always greater than or equal to 2, and the access level is always greater than or equal to 1.

The `getCode` method takes no parameters and returns a formatted credential code string constructed from the pass ID and access level according to the following rules:
- If `accessLevel` is greater than or equal to 5, the returned code consists of the first two characters of `passId`, followed by `"-PRIORITY-"`, followed by the remainder of `passId`.
- If `accessLevel` is less than 5, the returned code consists of `passId`, followed by `"-"`, followed by `accessLevel`.

The `updatePass` method takes a `String` parameter `newId` and an `int` parameter `levelBoost`. The method updates the pass according to the following rules:
- If `newId` contains `passId` as a substring, then `passId` is updated to `newId`, `accessLevel` is increased by `levelBoost`, and the method returns `true`.
- If `newId` does not contain `passId` as a substring, no changes are made to the object's instance variables, and the method returns `false`.

The following table contains a sample code execution sequence and the corresponding results.

| Statement | Method Call Return Value (blank if none) | Explanation |
| :--- | :--- | :--- |
| `SecurityPass sp1 = new SecurityPass("AB123", 6);` | | The `SecurityPass` object `sp1` has `passId` `"AB123"` and `accessLevel` 6. |
| `String c1 = sp1.getCode();` | `"AB-PRIORITY-123"` | `accessLevel` is 6 (\(\ge 5\)). The first 2 characters (`"AB"`) are followed by `"-PRIORITY-"` and the remainder (`"123"`). |
| `SecurityPass sp2 = new SecurityPass("SEC99", 2);` | | The `SecurityPass` object `sp2` has `passId` `"SEC99"` and `accessLevel` 2. |
| `String c2 = sp2.getCode();` | `"SEC99-2"` | `accessLevel` is 2 (< 5). `passId` is followed by `"-"` and `accessLevel`. |
| `boolean b1 = sp2.updatePass("SEC99X", 2);` | `true` | `"SEC99X"` contains `"SEC99"`. `passId` becomes `"SEC99X"` and `accessLevel` becomes 4 (\(2 + 2\)). |
| `String c3 = sp2.getCode();` | `"SEC99X-4"` | `accessLevel` is 4 (< 5). |
| `boolean b2 = sp1.updatePass("ADMIN", 3);` | `false` | `"ADMIN"` does not contain `"AB123"`. No instance variables are changed. |

Write the complete `SecurityPass` class. Your implementation must meet all specifications and conform to the examples in the table.
Show answer & marking scheme

Worked solution

### Complete Class Implementation

```java
public class SecurityPass
{
private String passId;
private int accessLevel;

public SecurityPass(String id, int level)
{
passId = id;
accessLevel = level;
}

public String getCode()
{
if (accessLevel >= 5)
{
return passId.substring(0, 2) + "-PRIORITY-" + passId.substring(2);
}
else
{
return passId + "-" + accessLevel;
}
}

public boolean updatePass(String newId, int levelBoost)
{
if (newId.indexOf(passId) != -1)
{
passId = newId;
accessLevel += levelBoost;
return true;
}
return false;
}
}
```

Marking scheme

### Scoring Guidelines (9 Points Total)

1. Class Header (1 point)
- Declares `public class SecurityPass`.
- Do not award point if declared private, contains extraneous code outside class, or includes parentheses `()` in class header.

2. Instance Variables (1 point)
- Declares appropriate `private` instance variables: `private String passId;` and `private int accessLevel;`.
- Do not award point if `private` is omitted, or if variables are declared `static` or inside a constructor/method.

3. Constructor Header & Initialization (1 point)
- Declares constructor header `public SecurityPass(String id, int level)` (or equivalent parameter names).
- Correctly initializes instance variables using the constructor parameters.

4. Method Headers (1 point)
- Declares `public String getCode()` and `public boolean updatePass(String newId, int levelBoost)` with correct access modifier, return types, names, and parameter types.

5. `getCode` Conditional Check (1 point)
- Correctly compares `accessLevel` against `5` (e.g., `accessLevel >= 5` or `accessLevel < 5`).

6. `getCode` Return Algorithm (1 point)
- Uses `substring(0, 2)` and `substring(2)` to construct and return the priority code when `accessLevel >= 5`, and concatenates `passId + "-" + accessLevel` otherwise.

7. `updatePass` Substring Check (1 point)
- Calls `newId.indexOf(passId)` and compares the result to `-1` (or `>= 0`) to determine if `newId` contains `passId`.

8. `updatePass` State Update (1 point)
- Assigns `newId` to `passId` and increments `accessLevel` by `levelBoost` when the substring condition is satisfied.

9. `updatePass` Return Logic (1 point)
- Returns `true` when updated and `false` when no update occurs without side-effects or improper modifications when condition is false.
Question 3 · free-response
9 marks
This question involves organizing chemical specimens in a laboratory into paired testing groups. Specimen data, paired tests, and batch processing are represented by the `Specimen`, `TestPair`, and `BatchProcessor` classes.

The `Specimen` class represents an individual chemical specimen with a unique identifier and a concentration level.

```java
public class Specimen
{
private String sampleId;
private double concentration;

/**
* Constructs a Specimen with given id and conc.
* Preconditions: id is not null; conc > 0
/
public Specimen(String id, double conc)
{ /
implementation not shown */ }

/** Returns the concentration of this specimen /
public double getConcentration()
{ /
implementation not shown */ }

/** Returns the identifier of this specimen /
public String getId()
{ /
implementation not shown / }

/
There may be instance variables, constructors,
and methods that are not shown. */
}
```

The `TestPair` class represents two specimens paired for combined testing.

```java
public class TestPair
{
/** Constructs a TestPair with two specimens /
public TestPair(Specimen first, Specimen second)
{ /
implementation not shown / }

/
There may be instance variables, constructors,
and methods that are not shown. */
}
```

The `BatchProcessor` class manages a collection of specimens and organizes them into pairs.

```java
public class BatchProcessor
{
/** The list of specimens in this batch */
private ArrayList specimenList;

/** Initializes specimenList, as described in part (a) /
public BatchProcessor(String[] ids, double[] concs)
{ /
to be implemented in part (a) */ }

/**
* Evaluates specimens paired from the outside inwards and returns
* a list of valid TestPair objects, as described in part (b).
* Preconditions: specimenList.size() >= 2;
* specimenList is ordered from lowest to highest concentration.
* Postcondition: specimenList is unchanged.
/
public ArrayList createBalancedPairs(double targetSum, double tolerance)
{ /
to be implemented in part (b) / }

/
There may be instance variables, constructors,
and methods that are not shown. */
}
```

---

### Part (a)

Write the constructor for the `BatchProcessor` class. The constructor should initialize the instance variable `specimenList` to contain one `Specimen` object for each corresponding pair of elements in the `ids` and `concs` arrays.

The `Specimen` objects must appear in `specimenList` in the same order as their corresponding elements appear in the parameter arrays. You may assume `ids` and `concs` have the same non-zero length.

Complete the `BatchProcessor` constructor:

```java
/** Initializes specimenList, as described in part (a) */
public BatchProcessor(String[] ids, double[] concs)
```

---

### Part (b)

Write the `BatchProcessor` method `createBalancedPairs`. This method creates and returns an `ArrayList` by evaluating potential pairings of specimens from `specimenList`.

Potential pairings are formed by pairing the specimen with the lowest concentration (at index `0`) with the specimen with the highest concentration (at the last index), the specimen with the second-lowest concentration with the specimen with the second-highest concentration, and so on, moving inward towards the center of the list.

For each potential pair:
- Compute the sum of the concentrations of the two specimens.
- If the absolute difference between the combined concentration sum and `targetSum` is less than or equal to `tolerance`, construct a new `TestPair` object containing the two specimens and add it to the list to be returned.
- If the absolute difference is greater than `tolerance`, the pair is considered unbalanced and no `TestPair` is created for those two specimens.

If `specimenList` contains an odd number of elements, the single middle element is not paired with anything and is ignored. The original `specimenList` must not be modified.

Complete the `createBalancedPairs` method:

```java
/**
* Evaluates specimens paired from the outside inwards and returns
* a list of valid TestPair objects, as described in part (b).
* Preconditions: specimenList.size() >= 2;
* specimenList is ordered from lowest to highest concentration.
* Postcondition: specimenList is unchanged.
*/
public ArrayList createBalancedPairs(double targetSum, double tolerance)
```
Show answer & marking scheme

Worked solution

### Canonical Solution

#### Part (a)
```java
public BatchProcessor(String[] ids, double[] concs)
{
specimenList = new ArrayList();
for (int i = 0; i < ids.length; i++)
{
Specimen s = new Specimen(ids[i], concs[i]);
specimenList.add(s);
}
}
```

#### Part (b)
```java
public ArrayList createBalancedPairs(double targetSum, double tolerance)
{
ArrayList validPairs = new ArrayList();
int left = 0;
int right = specimenList.size() - 1;

while (left < right)
{
Specimen lowSpec = specimenList.get(left);
Specimen highSpec = specimenList.get(right);
double sum = lowSpec.getConcentration() + highSpec.getConcentration();

if (Math.abs(sum - targetSum) <= tolerance)
{
validPairs.add(new TestPair(lowSpec, highSpec));
}
left++;
right--;
}
return validPairs;
}
```

(Alternate for-loop traversal for Part (b))
```java
public ArrayList createBalancedPairs(double targetSum, double tolerance)
{
ArrayList validPairs = new ArrayList();
int n = specimenList.size();
for (int i = 0; i < n / 2; i++)
{
Specimen s1 = specimenList.get(i);
Specimen s2 = specimenList.get(n - 1 - i);
double sum = s1.getConcentration() + s2.getConcentration();
if (Math.abs(sum - targetSum) <= tolerance)
{
validPairs.add(new TestPair(s1, s2));
}
}
return validPairs;
}
```

Marking scheme

### Part (a): `BatchProcessor` Constructor (4 points)

1. Initializes instance variable `specimenList` (1 point)
- Creates a new `ArrayList` and assigns it to `specimenList`.
- Decision Rule: Do not award if `specimenList` is declared locally or left uninitialized.

2. Accesses all elements of parameter arrays (1 point)
- Sets up a loop that traverses from index `0` to `ids.length - 1` (or `concs.length - 1`) with no bounds errors.

3. Constructs `Specimen` objects (1 point)
- Calls `new Specimen(ids[i], concs[i])` with corresponding elements and proper types.
- Decision Rule: Do not award if `new` is omitted or parameters are swapped/incorrect.

4. Populates `specimenList` in correct order (1 point)
- Appends each newly created `Specimen` to `specimenList` during traversal.

---

### Part (b): `createBalancedPairs` (5 points)

5. Declares and initializes local `ArrayList` (1 point)
- Declares and instantiates a new `ArrayList` to store the result.

6. Maintains two indices/pointers moving inward from ends (1 point)
- Initializes a low index at `0` and a high index at `size - 1` (or uses a single index `i` with counterpart `size - 1 - i`), advancing toward the center.

7. Retrieves concentrations and evaluates balance condition (1 point)
- Calls `getConcentration()` on both specimens, calculates their sum, and correctly checks if `Math.abs(sum - targetSum) <= tolerance` (or equivalent relational check).

8. Constructs `TestPair` and adds to list when condition is met (1 point)
- Constructs `new TestPair(first, second)` using the two `Specimen` objects and adds it to the local result list conditionally.

9. Correct traversal algorithm and return (1 point)
- Traverses exactly until `left < right` (or `i < size / 2`), correctly ignoring the middle element when size is odd, leaves `specimenList` unmodified, and returns the populated `ArrayList`.
Question 4 · frq
9 marks
This question involves reasoning about a game board represented as a two-dimensional array of positive integers called `grid`. Each integer represents the power level of a token on the grid.

You will write the constructor and one method of the `TokenGrid` class.

```java
public class TokenGrid
{
/** A 2D array representing tokens on the board */
private int[][] grid;

/**
* Creates a two-dimensional array and fills it with random integers,
* as described in part (a)
* Preconditions: numRows > 0; numCols > 0; maxValue >= 1
/
public TokenGrid(int numRows, int numCols, int maxValue)
{ /
to be implemented in part (a) */ }

/**
* Identifies and removes a matching token from the grid that can pair with
* the token at position (row, col), as described in part (b)
* Preconditions: row and col are valid row and column indices in grid.
* grid[row][col] is between 1 and maxValue, inclusive.
* @return true if a valid match was found and cleared; false otherwise
/
public boolean neutralizeMatch(int row, int col)
{ /
to be implemented in part (b) / }

/
There may be instance variables, constructors, and methods not shown. */
}
```

### Part (a)
Write the constructor for the `TokenGrid` class. The constructor initializes the instance variable `grid` to be a two-dimensional integer array with `numRows` rows and `numCols` columns. Each element of `grid` must be assigned a randomly generated integer from `1` to `maxValue`, inclusive, each with an equal probability of being selected.

Complete the constructor:
```java
/**
* Creates a two-dimensional array and fills it with random integers,
* as described in part (a)
* Preconditions: numRows > 0; numCols > 0; maxValue >= 1
*/
public TokenGrid(int numRows, int numCols, int maxValue)
```

### Part (b)
Write the `neutralizeMatch` method, which searches `grid` to find another token to pair with the token located at row `row` and column `col`. To make a valid pair, the second token must satisfy all of the following conditions:
- It is not the token at `(row, col)` itself.
- Its row index is greater than or equal to `row`.
- Its value is equal to the value of `grid[row][col]`.

If a matching token is found at position `(r, c)`:
- Both `grid[row][col]` and `grid[r][c]` are set to `0` (cleared).
- The method returns `true` immediately without modifying any other elements. (If multiple valid matching tokens exist, any one of them may be paired and cleared).

If no matching token is found:
- No elements in `grid` are modified.
- The method returns `false`.

Complete the `neutralizeMatch` method:
```java
/**
* Identifies and removes a matching token from the grid that can pair with
* the token at position (row, col), as described in part (b)
* Preconditions: row and col are valid row and column indices in grid.
* grid[row][col] is between 1 and maxValue, inclusive.
* @return true if a valid match was found and cleared; false otherwise
*/
public boolean neutralizeMatch(int row, int col)
```
Show answer & marking scheme

Worked solution

### Part (a) Canonical Solution
```java
public TokenGrid(int numRows, int numCols, int maxValue)
{
grid = new int[numRows][numCols];
for (int r = 0; r < numRows; r++)
{
for (int c = 0; c < numCols; c++)
{
grid[r][c] = (int)(Math.random() * maxValue) + 1;
}
}
}
```

### Part (b) Canonical Solution
```java
public boolean neutralizeMatch(int row, int col)
{
int targetVal = grid[row][col];
for (int r = row; r < grid.length; r++)
{
for (int c = 0; c < grid[0].length; c++)
{
if (r != row || c != col)
{
if (grid[r][c] == targetVal)
{
grid[row][col] = 0;
grid[r][c] = 0;
return true;
}
}
}
}
return false;
}
```

Marking scheme

### Part (a): 4 points
- Point 1: Constructs correctly sized 2D array of `int` (`numRows` by `numCols`) and assigns to instance variable `grid`.
- Point 2: Traverses all elements of the 2D array with nested loops and no bounds errors.
- Point 3: Generates a random integer uniformly distributed in the range `[1, maxValue]` using `(int)(Math.random() * maxValue) + 1`.
- Point 4: Assigns generated values to all elements of `grid`.

### Part (b): 5 points
- Point 5: Traverses `grid` starting at row index `row` up to `grid.length - 1` without out-of-bounds errors.
- Point 6: Guards against self-pairing (checks that `(r != row || c != col)` or equivalent).
- Point 7: Checks whether candidate element `grid[r][c]` equals `grid[row][col]`.
- Point 8: Sets both matching elements (`grid[row][col]` and `grid[r][c]`) to `0` when a match is found.
- Point 9: Returns `true` immediately after clearing the first found pair, and returns `false` if loop finishes without finding a match.

Ready to test yourself?

Turn these notes into exam-style practice. Get unlimited AI questions on this topic with instant marking and explanations.

Practise This Topic

Wondering how well you actually know this?

thinka is an AI practice app for DSE students: unlimited questions, instant auto-marking, and detailed step-by-step solutions. 100,000+ students use it to confirm they actually know it, not just think they do.

Want more questions like this? Practise unlimited on thinka, instant answers included.

Start Practising Free