TokenPass: 2013 FRQ 2
A step-by-step solution to the 2013 AP CSA FRQ 2 (TokenPass), covering filling an array with bounded random values and distributing tokens around an array with wraparound in Java.
A circular token-passing game gives this AP Computer Science A free-response question its shape — the interesting part isn't handing out tokens one at a time, it's making that hand-out wrap back around to the start of the board once it reaches the far end.
What This FRQ Tests
- AP CSA units: Unit 6 (Array) and Unit 4 (Iteration)
- Core skill: filling an array with bounded random integers, and looping around an array's ends using the modulus operator
- Secondary skill: tracking a loop counter that's independent of the array position being modified, since one turn's "collected tokens" count has nothing to do with the array's length
- Official category: content-wise, this is "Array" work — Unit 6 territory that today's fixed FRQ order always slots at FRQ 3. 2013 predates that standardization, and the exam's own booklet prints this question second, right after an ArrayList-based first question.
The Setup
TokenPassholds:private int[] board— one element per player, holding that player's current token countprivate int currentPlayer— whose turn it currently is
- You're asked to write:
- the constructor
TokenPass(int playerCount)— fillsboardwithplayerCountrandom values from 1 to 10, and setscurrentPlayerto a random valid index distributeCurrentPlayerTokens()— collects the tokens atcurrentPlayer's position and hands them out one at a time to each following position, wrapping back to position 0 after the highest position
- the constructor
Part (a): Writing the TokenPass(int playerCount) constructor
Step-by-Step Approach
- Create
boardas a new array of sizeplayerCount. - Loop over every index of
board, assigning each a random integer from 1 to 10, inclusive. - Separately, set
currentPlayerto a random integer from 0 toplayerCount - 1, inclusive.
The Code
public TokenPass(int playerCount)
{
board = new int[playerCount];
for (int i = 0; i < board.length; i++)
{
board[i] = (int) (Math.random() * 10) + 1;
}
currentPlayer = (int) (Math.random() * playerCount);
}
Why Each Piece Matters
Math.random()returns adoublein the range[0.0, 1.0). Multiplying by 10 gives[0.0, 10.0), and casting tointtruncates that down to a whole number from 0 to 9. Adding 1 shifts the whole range to 1 through 10, matching "1 to 10, inclusive" exactly.currentPlayerskips that+ 1— multiplyingMath.random()byplayerCountand truncating gives a value from 0 toplayerCount - 1, which is preciselyboard's valid index range.- The
(int)cast has to wrap the entireMath.random() * 10expression, not justMath.random()by itself — castingMath.random()tointfirst would always produce0, sinceMath.random()alone is always less than 1.
Tracing the Example
The question doesn't give a deterministic worked example of the constructor's output — since it deliberately fills the board with random values, there's no single fixed input/output pair to trace here. The PDF's example board ([3, 2, 6, 10] with currentPlayer = 2, for a 4-player game) is presented only as one possible result of running this constructor, not a value the constructor is expected to reproduce exactly.
Common Mistakes to Avoid
- Casting
Math.random()tointbefore multiplying —((int) Math.random()) * 10 + 1always evaluates to1, since(int) Math.random()is always0. - Forgetting the
+ 1on the token counts, which produces a range of 0-9 instead of the required 1-10. - Adding
+ 1to thecurrentPlayercalculation, which would allow an out-of-bounds index ofplayerCount. - Referencing
board.lengthbeforeboardhas actually been assigned a new array.
Part (b): Writing distributeCurrentPlayerTokens()
The Rule, Broken Down
- Read and remember how many tokens are at
currentPlayer's position, then set that position to 0 — the tokens are "collected and removed." - Hand out one token at a time, starting with the very next position after
currentPlayer. - Once the highest position receives a token, wrap back around to position 0.
- Stop once every collected token has been handed out.
currentPlayeritself must not change.
Step-by-Step Approach
- Save
board[currentPlayer]as the number of tokens to distribute, then zero out that position. - Use a separate loop variable — not
currentPlayer— to track which position is currently receiving a token, starting fromcurrentPlayer. - Repeat once per collected token: advance that position by one, wrapping with
% board.length, and add one token there.
The Code
public void distributeCurrentPlayerTokens()
{
int numTokens = board[currentPlayer];
board[currentPlayer] = 0;
int position = currentPlayer;
for (int i = 0; i < numTokens; i++)
{
position = (position + 1) % board.length;
board[position] = board[position] + 1;
}
}
Why Each Piece Matters
board[currentPlayer]is read and saved before it's zeroed out — zeroing first would lose the very count needed to know how many times to loop.positionstarts as a copy ofcurrentPlayer's value, notcurrentPlayeritself, so the loop is free to move it around without ever touching the actualcurrentPlayerfield.(position + 1) % board.lengthis what makes the wraparound automatic: oncepositionreachesboard.length - 1, adding 1 givesboard.length, and% board.lengthbrings it right back to 0 — with no separateifneeded to catch the wraparound case.- The increment always happens on
position, recomputed fresh at the top of each loop iteration — never oncurrentPlayer.
Tracing the Example
Using the question's own 4-player example — board = [3, 2, 6, 10], currentPlayer = 2:
| Step | position |
board after this step |
|---|---|---|
| start | — | numTokens = 6, board[2] set to 0 → [3, 2, 0, 10] |
| 1st token | (2+1)%4 = 3 |
[3, 2, 0, 11] |
| 2nd token | (3+1)%4 = 0 |
[4, 2, 0, 11] |
| 3rd token | (0+1)%4 = 1 |
[4, 3, 0, 11] |
| 4th token | (1+1)%4 = 2 |
[4, 3, 1, 11] |
| 5th token | (2+1)%4 = 3 |
[4, 3, 1, 12] |
| 6th token | (3+1)%4 = 0 |
[5, 3, 1, 12] |
Final board: [5, 3, 1, 12] — matching the question's own result exactly, and matching the visited positions (3, 0, 1, 2, 3, 0) the question's own prose narrative describes step by step.
Common Mistakes to Avoid
- Incrementing
currentPlayerdirectly instead of a separatepositionvariable — this violates the "the current player has not changed" postcondition. - Reading
board[currentPlayer]fornumTokensafter it's already been zeroed out, instead of saving the count in a local variable first. - Using an
if-statement that only handles wrapping past the last index once, instead of the modulus operator — this can break ifnumTokensis large enough to wrap all the way around the board more than once. - Writing the wraparound as
position % board.length + 1instead of(position + 1) % board.length— these are not equivalent, and the former can produce an out-of-range index.
Key Takeaways
- Wrapping an index back to 0 after it passes the end of an array is a job for the modulus operator —
(index + 1) % array.length— not a series of manualif-checks. - When "how many times to loop" comes from a value you're about to overwrite, save that value in a local variable before changing anything.
- A method that isn't allowed to change one particular field (
currentPlayer, here) should route all of its work through a separate local variable instead of touching that field directly.