CompSci.rocks
FRQcsapa

Game: 2022 FRQ 1

A step-by-step solution to the 2022 AP CSA FRQ 1 (Game), covering nested if statements, chained conditions, and tracking a running maximum in Java.

A simple video game with three levels drives this AP Computer Science A free-response question — you compute a score for a single play based on which levels were reached, then find the best score across several simulated plays.

What This FRQ Tests

  • AP CSA units: Unit 3 (Boolean Expressions and if Statements), Unit 4 (Iteration), and Unit 5 (Writing Classes/methods)
  • Core skill: chaining conditional logic so one requirement depends on the one before it
  • Secondary skill: using a loop to track a running maximum across repeated trials
  • Official category: "Methods and Control Structures" — always FRQ 1 on the AP CSA exam

The Setup

  • A Level class gives you two methods to call, but not modify:
    • boolean goalReached() — was the level's goal reached?
    • int getPoints() — how many points were recorded on that level?
  • A Game class has:
    • Three Level fields: levelOne, levelTwo, levelThree
    • boolean isBonus() — is this a bonus game (triples the score)?
    • void play() — simulates one full play of the game
  • You're asked to write two methods: getScore() and playManyTimes(int num).

Part (a): Writing getScore()

The Rule, Broken Down

The scoring rule reads like a chain of dependencies:

  1. Level one's points count only if level one's goal was reached.
  2. Level two's points count only if levels one and two were both reached.
  3. Level three's points count only if all three levels were reached.
  4. If the game is a bonus game, multiply the total by 3 — after everything else is added.

Step-by-Step Approach

  1. Start a running total at 0.
  2. Check level one first. If its goal wasn't reached, nothing else can be earned — stop there.
  3. If level one was reached, add its points, then check level two the same way.
  4. If level two was also reached, add its points, then check level three.
  5. If level three was also reached, add its points too.
  6. After the base total is computed, check isBonus() separately and multiply if true.

The "only if the previous check passed" pattern is exactly what nested if statements are built for: each level's points are only reachable by getting inside the previous level's if block.

The Code

public int getScore()
{
    int score = 0;

    if (levelOne.goalReached())
    {
        score = score + levelOne.getPoints();

        if (levelTwo.goalReached())
        {
            score = score + levelTwo.getPoints();

            if (levelThree.goalReached())
            {
                score = score + levelThree.getPoints();
            }
        }
    }

    if (isBonus())
    {
        score = score * 3;
    }

    return score;
}

Why the Nesting Matters

  • The if (levelTwo.goalReached()) check is written inside the if (levelOne.goalReached()) block — not after it as a separate if.
  • If it were a separate, non-nested if, level two's points could be added even when level one failed — which breaks the rule.
  • The bonus multiplier lives outside and after all three nested checks, since it applies to whatever total was already earned, regardless of how far the player got.

Tracing the Example

  • All three goals reached, points are 200 / 100 / 500, isBonus() is true:
    • Level one reached → add 200 → running total 200
    • Level two reached → add 100 → running total 300
    • Level three reached → add 500 → running total 800
    • Bonus game → 800 × 3 = 2,400 — matches the question's table
  • Level one and two reached, level three not reached:
    • Add 200, then add 100 → running total 300
    • The if (levelThree.goalReached()) block never runs, so level three's points are skipped
    • No bonus → final score 300
  • Level one not reached:
    • The outer if never runs at all — score stays 0 regardless of what levels two and three did

Common Mistakes to Avoid

  • Using three separate if statements instead of nesting them. This lets level three's points count even if level one failed — wrong.
  • Applying the bonus multiplier inside the nested ifs. The rubric expects the multiplier applied once, to the final total — not three separate times.
  • Forgetting the bonus check runs regardless of whether any level was reached. A bonus game with a score of 0 is still 0 * 3 = 0, but the check itself must still execute.

Part (b): Writing playManyTimes(int num)

The Idea

  • You're told to call two existing helper methods: play() and getScore().
  • play() simulates one full game (assume it works correctly — you don't need to know its internals).
  • Immediately after calling play(), getScore() returns that play's score.
  • So the task becomes: play a game, check its score, remember it if it beats the current best, repeat num times.

Step-by-Step Approach

  1. Set up a variable to hold the best score found so far, starting at 0.
  2. Loop num times.
  3. Each iteration: call play(), then immediately call getScore().
  4. Compare that score to the current best — if it's higher, replace the best.
  5. After the loop finishes, return the best score found.

The Code

public int playManyTimes(int num)
{
    int highest = 0;

    for (int i = 0; i < num; i++)
    {
        play();
        int score = getScore();

        if (score > highest)
        {
            highest = score;
        }
    }

    return highest;
}

Why Starting at 0 Is Safe

  • A game's score can never be negative — points are positive integers, and tripling a non-negative number stays non-negative.
  • That means the very first score computed will always be able to overwrite the initial 0 if it's greater than zero, so no valid score gets missed.

Common Mistakes to Avoid

  • Calling getScore() before play(). The problem statement is explicit that getScore() only reflects the most recently played game — call play() first, every time.
  • Calling play() more than once per loop iteration. Each iteration should simulate exactly one game.
  • Starting highest at a value like Integer.MIN_VALUE unnecessarily. It's a valid defensive habit in general Java, but for this specific problem, 0 is provably safe and simpler to reason about — the AP graders accept either.

Notes: A Method Not on the AP CSA Quick Reference Sheet

If your class covers it, Math.max would let you skip the if block entirely:

public int playManyTimes(int num)
{
    int highest = 0;

    for (int i = 0; i < num; i++)
    {
        play();
        highest = Math.max(highest, getScore());
    }

    return highest;
}
  • Math.max isn't listed on the real exam's Java Quick Reference sheet — but that doesn't mean it's off-limits. AP CSA graders accept any correct Java, not just methods that appear on the sheet.
  • What the Quick Reference sheet actually guarantees is that you can look those specific methods up during the exam if you blank on the exact signature. Anything not listed — Math.max included — is fair game to use, you just won't have it to reference if you're unsure how it behaves. If you know it well, using it is perfectly safe; the if version above is simply the one that doesn't depend on remembering it.

Key Takeaways

  • Chained "only if the previous condition passed" rules belong inside nested if blocks, not separate sequential ones.
  • Multipliers or bonuses that apply to a final total belong outside and after the logic that builds that total.
  • "Find the best of several trials" is a two-part loop pattern: track a running best, compare and replace on each iteration.

Related FRQs