SumOrSameGame: 2025 FRQ 4
A step-by-step solution to the 2025 AP CSA FRQ 4 (SumOrSameGame), covering filling a 2D array with random values and searching it for a matching pair to clear in Java.
A number-matching puzzle built on a 2D grid drives this AP Computer Science A free-response question — first filling the grid with random digits, then searching it for a second value that either matches or completes a pair summing to 10.
What This FRQ Tests
- AP CSA units: Unit 8 (2D Array) and Unit 4 (Iteration)
- Core skill: filling every cell of a 2D array with an independently random value in a fixed range
- Secondary skill: searching a 2D array in a specific, rule-constrained order and stopping at the first valid match
- Official category: "2D Array" — always FRQ 4 on the AP CSA exam
The Setup
SumOrSameGameholds:private int[][] puzzle— a grid where each cell holds a value from1to9, or0once cleared
- You're asked to write:
- The constructor
SumOrSameGame(int numRows, int numCols)— buildspuzzleand fills every cell with a random value from1to9, inclusive boolean clearPair(int row, int col)— finds another cell that can pair with(row, col)and clears both
- The constructor
Part (a): Writing the Constructor
The Rule, Broken Down
- Allocate
puzzlewith the given number of rows and columns. - Every cell, independently, gets a random value from
1to9, each equally likely.
Step-by-Step Approach
- Create the array:
puzzle = new int[numRows][numCols]. - Loop over every row, and inside that, every column.
- For each cell, generate a random whole number from
1to9and store it.
The Code
public SumOrSameGame(int numRows, int numCols)
{
puzzle = new int[numRows][numCols];
for (int r = 0; r < numRows; r++)
{
for (int c = 0; c < numCols; c++)
{
puzzle[r][c] = (int) (Math.random() * 9) + 1;
}
}
}
Why Each Piece Matters
Math.random() * 9— scalesMath.random()'s[0.0, 1.0)range into[0.0, 9.0).(int) (...)truncates that into a whole number from0to8— nine equally likely possibilities.+ 1shifts that range up to1through9, matching the required range exactly.- Nested loops, not one loop —
puzzleis two-dimensional, so every row needs its own pass across every column.
Common Mistakes to Avoid
- Off-by-one on the random range, e.g.
(int) (Math.random() * 9)without the+ 1, which produces0through8instead of1through9. - Reusing one random value for an entire row or column instead of generating a fresh one for every single cell — the rule requires each cell's value to be independently random.
- Swapping
numRowsandnumColswhen allocating the array, which silently transposes the grid's dimensions.
Part (b): Writing clearPair(int row, int col)
The Rule, Broken Down
- Look for another cell — anywhere in row
rowor any row after it — whose value either equals the value at(row, col), or sums with it to exactly10. - If more than one such cell exists, any one of them can be used.
- If a match is found, clear both cells (set them to
0) and returntrue. - If no match exists anywhere in the allowed search area, leave
puzzleunchanged and returnfalse.
Step-by-Step Approach
- Save the value at
(row, col)before anything else changes. - Loop through every row from
rowto the last row ofpuzzle. - Within each of those rows, loop through every column.
- Skip the starting cell itself — it can't pair with itself.
- At every other cell in the search area, check whether its value equals the saved value, or sums with it to
10. - The moment a match is found, clear both cells and return
trueimmediately. - If both loops finish with no match found, return
false.
The Code
public boolean clearPair(int row, int col)
{
int value = puzzle[row][col];
for (int r = row; r < puzzle.length; r++)
{
for (int c = 0; c < puzzle[r].length; c++)
{
if (!(r == row && c == col) && (puzzle[r][c] == value || puzzle[r][c] + value == 10))
{
puzzle[row][col] = 0;
puzzle[r][c] = 0;
return true;
}
}
}
return false;
}
Why Each Piece Matters
- The outer loop starts at
r = row, not0— the rule only allows pairing with cells inrowor a later row, never an earlier one. - The inner loop always runs
cfrom0, even whenr == row— the rule places no column restriction at all, only a row one, so every column in the starting row is fair game (except the starting cell itself). !(r == row && c == col)— explicitly excludes the starting cell from being considered its own match, since without this check a cell could "pair" with itself.- Already-cleared cells (value
0) never accidentally match —0can never equal a value from1to9, and0plus that value can never reach10either, so no special check is needed to skip them. - Returning immediately on the first match found — since "any one of those identified array elements can be used," the first one encountered in this row-major, starting-row-first search order is always an acceptable answer.
Tracing the Example
Using one of the question's grids — 8 1 0 5 / 0 4 3 6 / 3 4 5 8 — and the call clearPair(1, 1) (value 4):
| Cell checked | Value | Same row/later? | Match? |
|---|---|---|---|
| (1, 0) | 0 | yes | no (0 ≠ 4, 0 + 4 ≠ 10) |
| (1, 1) | 4 | (the starting cell — skipped) | — |
| (1, 2) | 3 | yes | no (3 ≠ 4, 3 + 4 ≠ 10) |
| (1, 3) | 6 | yes | yes — 6 + 4 = 10 |
The search stops at (1, 3), clearing both (1, 1) and (1, 3) and returning true — matching the question's expected result exactly, including its note that row 2's 4 "could also have been matched," since our row-major search simply happens to reach row 1's 6 first.
Common Mistakes to Avoid
- Starting the outer loop at
r = 0instead ofr = row. This would allow pairing with a cell in an earlier row, which the rule explicitly forbids. - Restricting the inner loop's starting column when
r == row(e.g., starting atc = col + 1) — the rule places no column constraint at all, only a row one, so a valid partner can be anywhere in the starting row, including beforecol. - Forgetting to exclude the starting cell itself, which would let a cell "pair" with itself and immediately return
truewithout ever really finding a second cell. - Continuing to search after a match is found instead of returning immediately — this doesn't break correctness (any valid match is acceptable), but it's unnecessary extra work once one has already been found.
Key Takeaways
- "Equal chance of being assigned" for a bounded random range always follows the same pattern: scale
Math.random()by the range's size, truncate, then shift by the range's starting value. - A search rule with a constraint on only one dimension (here, row) should only restrict the loop bound for that dimension — don't invent a matching restriction for the other dimension that the rule never asked for.
- "Find any one match and act on it" only needs a single pass with an early return — there's no need to collect every possible match before picking one, when the rule says any of them will do.
Need help preparing for the AP exam?
FRQs are one of the toughest parts of the AP CS exam. I offer 1-on-1 tutoring to help you work through practice problems, tighten up your responses, and build the confidence to earn full credit on exam day.
Book a tutoring session →