CompSci.rocks
FRQcsapa

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

  • FrogSimulation holds:
    • private int goalDistance — how far, in inches, the frog needs to travel
    • private int maxHops — the maximum number of hops allowed
    • private 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() and runSimulations(int num).

Part (a): Writing simulate()

The Rule, Broken Down

  1. The frog starts at position 0.
  2. Each hop adjusts the frog's position by whatever hopDistance() returns that time.
  3. 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 maxHops hops without reaching the goal — stop, it failed.
  4. Return whether the final position reached or passed the goal.

Step-by-Step Approach

  1. Track two things: the frog's current position (starts at 0) and how many hops it has taken so far (hopsTaken, starts at 0).
  2. 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.
  3. Inside the loop, call hopDistance() exactly once, add it to position, and increment hopsTaken.
  4. When the loop condition finally fails — for any of the three reasons — stop looping.
  5. Return position >= goalDistance, since that expression is true only 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 to false and 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 take maxHops hops total; once hopsTaken equals maxHops, the loop must stop without taking another hop.
  • return position >= goalDistance works as the final answer without needing a separate if/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 exactly maxHops hops have been taken.
  • Calling hopDistance() more than once per iteration (e.g., once to check a condition and again to update position) — 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

  1. Track a running count of successful simulations, starting at 0.
  2. Loop num times.
  3. Each iteration, call simulate() and check its return value — if it's true, increment the success count.
  4. After the loop, divide the success count by num, as a double.

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

  • successCount and num are both ints, so successCount / num alone would perform integer division and truncate any decimal part.
  • Casting successCount to double before the division forces Java to compute the true decimal proportion.

Tracing the Example

  • The problem states: if num is 400 and 100 of the 400 calls to simulate() return true, runSimulations should return 0.25.
  • Tracing the code: the loop runs 400 times, successCount ends at 100, and (double) 100 / 400 evaluates to 0.25 — matches exactly.

Common Mistakes to Avoid

  • Writing successCount / num without the cast. 100 / 400 as pure integer division truncates to 0, not 0.25.
  • Not casting either operand. Only one side of a division needs to be a double for 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 double cast placed before the integer division happens, not after.

Related FRQs