Robot: 2004 FRQ 4
A step-by-step solution to the 2004 AP CSA FRQ 4 (Robot), covering conditional wall-detection logic, a direction-reversing state machine, and a counting while loop in Java.
A tile-cleaning robot that reverses direction whenever it hits a wall is the subject of this AP Computer Science A free-response question — its behavior is built up in three small pieces: detecting a wall, making a single move, and running moves in a loop until the whole hallway is empty.
What This FRQ Tests
- AP CSA units: Unit 3 (Boolean Expressions and if Statements), Unit 4 (Iteration), and Unit 5 (Writing Classes)
- Core skill: tracking and updating an object's own state (its position and facing direction) correctly across repeated method calls
- Secondary skill: writing a counting
whileloop that calls other instance methods instead of duplicating their logic - Official category: "Methods and Control Structures," which on the 2004 exam was FRQ 4 — the fixed FRQ 1–4 category order used in more recent years (Methods and Control Structures, Classes, Array/ArrayList, 2D Array, always in that sequence) wasn't standardized until the 2019–2020 Course and Exam Description redesign. 2004's actual printed order put this question last, after WordList (Array/ArrayList, FRQ 1), the Pet/Cat/LoudDog/Kennel hierarchy (Classes, FRQ 2), and a Marine Biology Simulation question (FRQ 3, skipped on this site — see the note below).
The Setup
- The
Robotclass has three fields (given, not written):private int[] hall— the number of items remaining on each tileprivate int pos— the robot's current tile indexprivate boolean facingRight—truemeans facing toward higher-numbered tiles
- A move, as defined by the question, works like this:
- If there are items on the current tile, one is removed.
- If items still remain on the current tile after that, the robot stays put, facing the same way.
- If no items remain on the current tile: (a) advance forward if that direction isn't blocked by a wall; (b) otherwise, reverse direction and stay on the same tile.
hallIsClear()— already implemented, not something you write — returnstrueonce every tile is empty.- You're asked to write three methods:
forwardMoveBlocked(),move(), andclearHall().
Part (a): Writing forwardMoveBlocked()
The Rule, Broken Down
- Returns
trueonly when a wall sits immediately in the direction the robot is currently facing. - Facing right, the only blocking tile is the highest-numbered one (
hall.length - 1). - Facing left, the only blocking tile is
0.
Step-by-Step Approach
- Check
facingRight. - If it's
true, the robot is blocked exactly whenposis the last valid index. - If it's
false, the robot is blocked exactly whenposis0.
The Code
private boolean forwardMoveBlocked()
{
if (facingRight)
{
return pos == hall.length - 1;
}
else
{
return pos == 0;
}
}
Why Each Piece Matters
hall.length - 1, nothall.length— the last valid tile index is always one less than the array's length, since indices start at0.- Two separate
returns, one per direction — "immediately in front" refers to a different tile depending on which way the robot is facing, so the check has to branch onfacingRightfirst.
Common Mistakes to Avoid
- Using
hall.lengthinstead ofhall.length - 1for the right-wall check — this comparesposagainst an index that's one past the last tile, so the check never triggers, leaving the robot permanently unable to detect the right wall. - Swapping which condition belongs to which direction (checking
pos == 0while facing right, for example). - Changing
posorfacingRightinside this method. It only reports whether a wall is there — it must not alter the robot's state.
Part (b): Writing move()
The Rule, Broken Down
- Remove one item from the current tile, if any remain.
- If that leaves the tile still non-empty, stop there — nothing else about the robot's state changes.
- If that leaves the tile empty, either advance (if possible) or reverse (if blocked).
Step-by-Step Approach
- If
hall[pos] > 0, decrement it by one. - Re-check
hall[pos], after that possible decrement. - If it's now
0(no items remain), decide whether to advance or reverse usingforwardMoveBlocked(). - Not blocked → move
posone step in the current facing direction. Blocked → flipfacingRightinstead, and leaveposalone. - If
hall[pos]is still greater than0, do nothing further — the robot simply stays where it is.
The Code
private void move()
{
if (hall[pos] > 0)
{
hall[pos]--;
}
if (hall[pos] == 0)
{
if (forwardMoveBlocked())
{
facingRight = !facingRight;
}
else if (facingRight)
{
pos++;
}
else
{
pos--;
}
}
}
Why Each Piece Matters
hall[pos]--runs unconditionally first, guarded only by "if there are items" — every call tomove()touches the current tile before anything else is decided.- The second
if (hall[pos] == 0)re-checks the tile after the possible decrement, not before — this is what makes "if there are more items, stay" happen automatically: when the tile still has items left, this whole block is skipped and the method simply ends. forwardMoveBlocked()is called, not reimplemented — the original problem explicitly says solutions that reimplement its logic instead of calling it "will not receive full credit."facingRight = !facingRightflips the boolean directly instead of writing anif/elsethat assignstrueorfalse— a safe, standard shortcut for "toggle this flag."
Tracing the Example
Using the question's own hallway, hall = [1, 1, 2, 2], and its 9-move sequence — the diagrams don't label the robot's exact starting index in the extracted text, but working backward from the officially given "after move 1" result ([1, 0, 2, 2], meaning tile 1 lost an item) pins the starting position at pos = 1, facing right:
| Move | Tile acted on | hall[pos] after decrement |
Tile empty now? | Blocked? | Result |
|---|---|---|---|---|---|
| 1 | 1 | 0 | yes | no | advance to pos = 2 |
| 2 | 2 | 1 | no | — | stay at pos = 2 |
| 3 | 2 | 0 | yes | no | advance to pos = 3 |
| 4 | 3 | 1 | no | — | stay at pos = 3 |
| 5 | 3 | 0 | yes | yes (pos == hall.length - 1) |
reverse to facing left, stay at pos = 3 |
| 6 | 3 | already 0 | yes | no | advance (leftward) to pos = 2 |
| 7 | 2 | already 0 | yes | no | advance to pos = 1 |
| 8 | 1 | already 0 | yes | no | advance to pos = 0 |
| 9 | 0 | 0 | yes | yes (pos == 0) |
reverse to facing right, stay at pos = 0 |
This reproduces the hallway contents and the robot's exact position and direction shown in all 9 of the question's diagrams — including the direction flips at move 5 (hitting the right wall) and move 9 (hitting the left wall), and the fact that moves 6 through 8 never touch the array at all, since those tiles are already empty by the time the robot passes back over them.
Common Mistakes to Avoid
- Checking
forwardMoveBlocked()before decrementinghall[pos]. Whether to advance or reverse only matters once the current tile has actually been confirmed empty, which can only be known after the removal happens. - Updating both
facingRightandposin the same move by mistake. The rule is strictly either/or: advance forward and keep facing the same way, or reverse direction and don't move at all. - Forgetting that a tile can already be empty when
move()is called — this happens whenever the robot passes back over a tile it already cleared. Theif (hall[pos] > 0)guard on the decrement, followed by unconditionally re-checkinghall[pos] == 0afterward, already handles this correctly without any extra special-casing.
Part (c): Writing clearHall()
The Rule, Broken Down
- Repeatedly call
move()until the hallway has no items left. - Return however many moves that took.
Step-by-Step Approach
- Start a counter at
0. - Loop while
hallIsClear()isfalse. - Each iteration: call
move(), then increment the counter. - Once the loop ends, return the counter.
The Code
public int clearHall()
{
int numMoves = 0;
while (!hallIsClear())
{
move();
numMoves++;
}
return numMoves;
}
Why Each Piece Matters
while (!hallIsClear()), not a loop with a fixed bound — the number of moves needed isn't known ahead of time; it depends entirely on how the simulation plays out.move()andhallIsClear()are both called, not reimplemented — the same "don't duplicate provided functionality" instruction from part (b) applies here too.numMoves++runs once per call tomove(), so the final count always matches the number of times the loop body actually executed.
Tracing the Example
Using the same 9-move sequence traced in part (b): the while loop calls move() once per row of that table, incrementing numMoves each time, and hallIsClear() only returns true once the hallway reaches [0, 0, 0, 0] — which happens right after move 9. So the loop runs exactly 9 times, and clearHall() returns 9 — matching the value the question states directly ("clearHall would take the robot through the moves shown and return 9").
Common Mistakes to Avoid
- Using an
ifinstead of awhile, or omitting the loop entirely. A singlemove()call only advances the simulation by one step;clearHall()needs to keep going until the hallway is actually empty. - Incrementing
numMovesin the wrong place relative to the loop, such as before callingmove()or outside the loop altogether — the count needs to match the number of timesmove()actually ran. - Re-scanning the
hallarray directly instead of calling the already-providedhallIsClear(). This duplicates functionality the class already gives you, which the original problem specifically warns against.
Key Takeaways
- Splitting a stateful simulation into a "detect a condition" method, a "make one state change" method, and a "repeat until done" method keeps each piece small enough to verify against a worked example on its own, while keeping the top-level loop dead simple.
- Re-checking a condition immediately after acting on it (like re-testing
hall[pos] == 0right after the decrement) is a clean way to express "did that action just finish the job" without duplicating any logic. - A
whileloop bounded by a provided boolean-returning method — not a fixed count — is the right shape whenever the number of iterations needed isn't knowable in advance.
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 →