2018 FRQ Q1

9 min read

Question Overview

This question involves simulating a frog attempting to reach a goal distance by hopping along to said distance. You will implement two methods for the FrogSimulation class.

Frog animation

FrogSimulation class Specification

  • goalDistance = (target position)

  • maxHops` = (maximum hops allowed)

  • hopDistance() = A private method that returns the distance of a single hop (can be positive, negative, or zero)

  • simulate() Returns true if the frog reaches the goal without going negative; false otherwise

  • runSimulations(int num) Runs num simulations and returns the proportion of successful attempts as a double

Key Insights

  • The frog starts at position 0
  • After each hop, check if position < 0 (fail immediately) or position >= goalDistance (succeed immediately)
  • For runSimulations, use (double) successes / num to avoid integer division

Code Runner Challenge

FrogSimulation

View IPYNB Source
// CODE_RUNNER: FrogSimulation

// This class models a frog trying to reach goalDistance in at most maxHops.
class FrogSimulation {
    private int goalDistance;
    private int maxHops;

    // Constructor stores FRQ parameters: target distance and hop limit.
    public FrogSimulation(int dist, int numHops) {
        goalDistance = dist;
        maxHops = numHops;
    }

    // Returns one random hop in the range -2 to 8 inclusive.
    private int hopDistance() {
        return (int) (Math.random() * 11) - 2; // -2 to 8
    }

    // Part (a): simulate one trial and report success/failure.
    public boolean simulate() {
        int position = 0; // Frog starts at position 0.


        for (int i = 0; i < maxHops; i++) {
            position += hopDistance(); // Update position after each hop.


            if (position < 0) {
                return false; // Immediate failure if frog goes negative.
            }


            if (position >= goalDistance) {
                return true; // Immediate success once goal is reached/passed.
            }
        }


        return false; // Used all hops without reaching goal.
    }

    // Part (b): run many trials and return success proportion.
    public double runSimulations(int num) {
        int successes = 0;


        for (int i = 0; i < num; i++) {
            if (simulate()) {
                successes++; // Count successful simulations.
            }
        }


        return (double) successes / num; // Cast to avoid integer division.
    }
}

public class Main {
    public static void main(String[] args) {
        FrogSimulation sim = new FrogSimulation(24, 5);

        System.out.println("Single simulation: " + sim.simulate());
        System.out.println("Proportion successful in 1000 runs: " + sim.runSimulations(1000));
    }
}

Main.main(null);
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Example of successful simulation

Given: goalDistance = 24, maxHops = 5, Hop sequence: 5, 7, -2, 8, 6

Hop Distance Position Negative? Goal? Result
1 5 5 No No Continue
2 7 12 No No Continue
3 -2 10 No No Continue
4 8 18 No No Continue
5 6 24 No Yes (24 >= 24) Return true

What you should see when you run the code:

  • Single simulation: true or false (varies due to randomness)
  • Proportion: approximately 0.3-0.5 (varies)

Example of failed simulation

Given: goalDistance = 24, maxHops = 5, Hop sequence: 6, -7, …

Hop Distance Position Negative? Goal? Result
1 6 6 No No Continue
2 -7 -1 Yes N/A Return false

Key Point: The simulation ends immediately when the frog goes negative. Remaining hops are not executed.


Popcorn Hack #1

Question: In the code above, why is position created inside simulate() instead of being stored as an instance variable of the class? Explain how this choice helps each simulation run behave correctly.

Show answer `position` should reset to 0 every time `simulate()` is called, because each run represents a new trial. Making it a local variable keeps each simulation independent, while an instance variable could accidentally carry position from one run into the next and produce incorrect results.

Solution Explanation

Below is the complete implementation that satisfies all 9 points on the rubric for parts (a) and (b)


Part (a): simulate() - 5 Points

Objective for Part (a):

Write the simulate() method so it models one frog run starting at position 0. The method should update the position after each hop, return false immediately if the frog goes below 0, return true immediately if the frog reaches or passes the goal, and return false if the frog uses all allowed hops without reaching the goal.

Code Runner Challenge

Solution Example Part (a) - simulate()

View IPYNB Source
// CODE_RUNNER: Solution Example Part (a) - simulate()

//Given Code
class FrogSimulation {
    private int goalDistance;
    private int maxHops;
    private int[] testHops;
    private int hopIndex;

    public FrogSimulation(int dist, int numHops, int[] hops) {
        goalDistance = dist;
        maxHops = numHops;
        testHops = hops;
        hopIndex = 0;
    }

    // Deterministic hop provider for testing instead of random hops.
    private int hopDistance() {
        if (hopIndex < testHops.length) {
            return testHops[hopIndex++];
        }
        return 0;
    }

    // Start of part (a)
    public boolean simulate() {
        int position = 0; // Start point.


        for (int i = 0; i < maxHops; i++) {
            position += hopDistance();


            if (position < 0) {
                return false; // Fail immediately if below 0.
            }


            if (position >= goalDistance) {
                return true; // Succeed immediately at/above goal.
            }
        }


        return false; // Did not reach goal within max hops.
    }
}

public class Main {
    public static void main(String[] args) {
        FrogSimulation successCase = new FrogSimulation(24, 5, new int[]{5, 7, -2, 8, 6});
        FrogSimulation failCase = new FrogSimulation(24, 5, new int[]{6, -7, 8, 8, 8});

        System.out.println("Expected true: " + successCase.simulate());
        System.out.println("Expected false: " + failCase.simulate());
    }
}

Main.main(null);
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

How It Works

  • Initialize position to 0
  • Loop exactly maxHops times
  • Update position with hopDistance()
  • Check if position < 0 and return false immediately
  • Check if position >= goalDistance and return true immediately
  • Return false after loop if goal not reached

Popcorn Hack #2

Question: Why must the method check for failure (position < 0) and success (position >= goalDistance) during each hop instead of waiting until all hops finish? Explain how this supports the simulation rules.

Show answer Part (a) models a run that can end the moment an outcome is decided. Checking each hop enforces the rules exactly: a run fails immediately when position goes negative and succeeds immediately when the goal is reached. Waiting until the end could misclassify runs by ignoring early stop conditions.

Part (b): runSimulations(int num) - 4 Points

Objective for Part (b):

Write the runSimulations(int num) method so it runs the simulation num times, counts how many runs succeed, and returns the proportion of successful runs as a double.

Code Runner Challenge

Solution Example Part (b) - runSimulations(int num)

View IPYNB Source
// CODE_RUNNER: Solution Example Part (b) - runSimulations(int num)

//Given Code
class FrogSimulation {
    private int goalDistance;
    private int maxHops;
    private int[][] trials;
    private int trialIndex;
    private int hopIndex;

    public FrogSimulation(int dist, int numHops, int[][] allTrials) {
        goalDistance = dist;
        maxHops = numHops;
        trials = allTrials;
        trialIndex = 0;
        hopIndex = 0;
    }

    private int hopDistance() {
        if (trialIndex >= trials.length) return 0;
        int[] currentTrial = trials[trialIndex];
        if (hopIndex < currentTrial.length) return currentTrial[hopIndex++];
        return 0;
    }

    // Included from part (a) to run
    public boolean simulate() {
        if (trialIndex >= trials.length) return false;

        int position = 0;
        hopIndex = 0; // Reset hop pointer for this trial.


        for (int i = 0; i < maxHops; i++) {
            position += hopDistance();
            if (position < 0) {
                trialIndex++; // Move to next trial after this run.
                return false;
            }
            if (position >= goalDistance) {
                trialIndex++; // Move to next trial after this run.
                return true;
            }
        }

        trialIndex++;
        return false;
    }

    // Start of part (b)
    public double runSimulations(int num) {
        int successes = 0;
        for (int i = 0; i < num; i++) {
            if (simulate()) successes++;
        }
        return (double) successes / num; // Decimal success rate.
    }
}

public class Main {
    public static void main(String[] args) {
        int[][] sampleTrials = {
            {5, 7, -2, 8, 6}, // success
            {6, -7, 8, 8, 8}, // fail (bc goes negative)
            {8, 8, 8, 0, 0},  // success
            {1, 1, 1, 1, 1}   // fail (dosen't reach goal in time)
        };

        FrogSimulation sim = new FrogSimulation(24, 5, sampleTrials);
        System.out.println("Expected 0.5: " + sim.runSimulations(4));
    }
}

Main.main(null);
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

How It Works

  1. simulate() tracks the frog’s position starting from 0, updating after each hop
  2. The method returns immediately when the frog goes negative or reaches the goal
  3. runSimulations(int num) calls simulate() multiple times and calculates the success rate
  4. Casting to double is essential to get a decimal proportion instead of 0

Popcorn Hack #3

Question: If two students run different numbers of trials, why is success proportion a better metric than number of successes, and why is casting to double essential for reporting that metric accurately?

Show answer Part (b) compares performance across many runs, so proportion is equal even when trial counts differ. Raw counts are not directly comparable (for example, 40/100 vs 40/200). Casting to `double` preserves decimal precision so the reported success rate reflects the true ratio instead of just integer division.

Scoring Guidelines

Points Breakdown (9 points total)

Part (a): simulate() (5 points)

  • 1 point: Initializes position variable to 0
  • 1 point: Loops exactly maxHops times
  • 1 point: Calls hopDistance() and updates position
  • 1 point: Checks if position < 0 inside loop and returns false immediately
  • 1 point: Checks if position >= goalDistance inside loop and returns true; returns false after loop

Part (b): runSimulations(int num) (4 points)

  • 1 point: Initializes counter to 0
  • 1 point: Loops num times
  • 1 point: Calls simulate() and increments counter when true
  • 1 point: Returns (double) successes / num

Common Mistakes to Avoid

  • Checking conditions outside the loop instead of inside
  • Using == instead of >= for goal check
  • Using position <= 0 instead of position < 0
  • Not casting to double: successes / num gives 0 instead of proportion
  • Not returning immediately when conditions are met

Homework FRQ 2017 Q1!

Course Timeline