FrogSimulation: 2018 FRQ 1
A step-by-step solution to the 2018 AP CSA FRQ 1 (FrogSimulation), covering a while loop with three stopping conditions and calculating a proportion from repeated trials in Java.
A frog hopping toward a goal in a straight line sets up this AP Computer Science A free-response question — you simulate a single attempt with a loop that can end three different ways, then repeat that simulation many times to estimate a success rate.
What This FRQ Tests
- AP CSA units: Unit 3 (Boolean Expressions and if/while Statements) and Unit 4 (Iteration)
- Core skill: writing a loop that can stop for more than one reason, combined into a single loop condition with
&& - Secondary skill: turning a count of successes into a proportion (a
double) across repeated trials - Official category: "Methods and Control Structures" — always FRQ 1 on the AP CSA exam
The Setup
FrogSimulationholds:private int goalDistance— how far, in inches, the frog needs to travelprivate int maxHops— the maximum number of hops allowedprivate int hopDistance()— a private helper (already written) that returns the distance of the next hop; positive moves toward the goal, negative moves away from it
- You're asked to write two methods:
simulate()andrunSimulations(int num).
Part (a): Writing simulate()
The Rule, Broken Down
- The frog starts at position
0. - Each hop adjusts the frog's position by whatever
hopDistance()returns that time. - The frog keeps hopping until one of three things happens:
- It reaches or passes the goal (
position >= goalDistance) — success. - It lands at a negative position — stop, it failed.
- It has already taken
maxHopshops without reaching the goal — stop, it failed.
- It reaches or passes the goal (
- Return whether the final position reached or passed the goal.
Step-by-Step Approach
- Track two things: the frog's current
position(starts at0) and how many hops it has taken so far (hopsTaken, starts at0). - Loop while all three of these are still true: the frog hasn't reached the goal, the frog's position isn't negative, and it hasn't used up its hops.
- Inside the loop, call
hopDistance()exactly once, add it toposition, and incrementhopsTaken. - When the loop condition finally fails — for any of the three reasons — stop looping.
- Return
position >= goalDistance, since that expression istrueonly in the case where the frog actually reached (or passed) the goal.
The Code
public boolean simulate()
{
int position = 0;
int hopsTaken = 0;
while (position < goalDistance && position >= 0 && hopsTaken < maxHops)
{
position = position + hopDistance();
hopsTaken++;
}
return position >= goalDistance;
}
Why Each Piece Matters
- Three conditions joined with
&&— the loop needs to keep going only while none of the three stopping conditions has happened yet. As soon as any one of them becomes true,&&short-circuits the whole expression tofalseand the loop ends — exactly the "stop for any of three reasons" behavior the problem describes. position = position + hopDistance()runs once per iteration — calling it more than once per loop pass would use up hops that were never actually reported to the caller.hopsTaken < maxHops, not<=— the frog is only allowed to takemaxHopshops total; oncehopsTakenequalsmaxHops, the loop must stop without taking another hop.return position >= goalDistanceworks as the final answer without needing a separateif/else— it's already exactly the condition the method is supposed to report.
Tracing the Example
Using FrogSimulation sim = new FrogSimulation(24, 5); (goal is 24 inches, 5 hops max):
| Example | hopDistance() values used |
Final position | simulate() returns |
|---|---|---|---|
| 1 | 5, 7, -2, 8, 6 | 24 | true |
| 2 | 6, 7, 6, 6 | 25 | true |
| 3 | 6, -6, 31 | 31 | true |
| 4 | 4, 2, -8 | -2 | false |
| 5 | 5, 4, 2, 4, 3 | 18 | false |
Walking through Example 4 in detail: position starts at 0. After the first hop (+4), position is 4 — still less than 24, still non-negative, still under 5 hops, so the loop continues. After the second hop (+2), position is 6 — loop continues again. After the third hop (-8), position becomes -2 — now position >= 0 is false, so the loop condition fails and the loop stops immediately, having only used 3 of the possible 5 hops. position >= goalDistance is -2 >= 24, which is false — matching the expected result. Example 5 shows the opposite edge case: the frog never goes negative and never reaches the goal, so it simply runs out of hops after all 5 are used.
Common Mistakes to Avoid
- Combining the three stopping conditions with
||instead of&&. The loop should keep running only while none of the stop conditions is true yet — that's an "and" of "not yet stopped" conditions, not an "or." - Checking
hopsTaken <= maxHops. This allows one extra hop beyond the limit — the loop must stop once exactlymaxHopshops have been taken. - Calling
hopDistance()more than once per iteration (e.g., once to check a condition and again to updateposition) — each call can return a different value, so calling it twice can silently use up an extra, unaccounted-for hop. - Forgetting the negative-position stopping condition entirely, and only checking the goal and hop count. Example 4 exists specifically to test this case.
Part (b): Writing runSimulations(int num)
Step-by-Step Approach
- Track a running count of successful simulations, starting at
0. - Loop
numtimes. - Each iteration, call
simulate()and check its return value — if it'strue, increment the success count. - After the loop, divide the success count by
num, as adouble.
The Code
public double runSimulations(int num)
{
int successCount = 0;
for (int i = 0; i < num; i++)
{
if (simulate())
{
successCount++;
}
}
return (double) successCount / num;
}
Why the Cast Matters
successCountandnumare bothints, sosuccessCount / numalone would perform integer division and truncate any decimal part.- Casting
successCounttodoublebefore the division forces Java to compute the true decimal proportion.
Tracing the Example
- The problem states: if
numis400and100of the400calls tosimulate()returntrue,runSimulationsshould return0.25. - Tracing the code: the loop runs 400 times,
successCountends at100, and(double) 100 / 400evaluates to0.25— matches exactly.
Common Mistakes to Avoid
- Writing
successCount / numwithout the cast.100 / 400as pure integer division truncates to0, not0.25. - Not casting either operand. Only one side of a division needs to be a
doublefor Java to perform floating-point math — but skipping the cast entirely gives truncated integer math no matter which side you meant to fix. - Calling
simulate()more than once per loop iteration (e.g., once to check and again to "confirm") — each call runs an entirely new, independent simulation, so this could count more or fewer successes than actually occurred.
Key Takeaways
- A loop that can stop for multiple different reasons is written as one loop condition with those reasons joined by
&&(each phrased as "keep going while this hasn't happened yet"). - Helper methods that return a new random or variable result each call (like
hopDistance()) should be called exactly once per use — calling them again silently changes the outcome. - Turning a count into a proportion always needs a
doublecast placed before the integer division happens, not after.