Practice Exam 2 FRQ
Practice Exam 2 FRQ
- Question 1 – RobotMover
- Question 2 – LapTracker
- Question 3 – PlayerAnalysis
- Question 4 – WordGrid
- Final Reflection
Question 1 – RobotMover
This problem evaluates understanding of:
- Random number generation
- String construction
- Iterative state building
- Substring searching
- Careful loop boundary control
- Preservation of object state
The class maintains a single instance variable:
private String moveSequence;
This variable represents a chronological log of robot movements, formatted as:
move_move_move_...
Each move must be one of four options with equal probability.
Part 1A – Constructor Implementation
import java.util.Random;
public class RobotMover {
private String moveSequence;
public RobotMover(int numMoves) {
moveSequence = "";
Random rand = new Random();
for (int i = 0; i < numMoves; i++) {
int r = rand.nextInt(4);
if (r == 0) {
moveSequence += "up_";
} else if (r == 1) {
moveSequence += "down_";
} else if (r == 2) {
moveSequence += "left_";
} else {
moveSequence += "right_";
}
}
}
Constructor Design Analysis
Understanding the Core Requirement
The constructor must:
- Run exactly
numMovestimes. - Select one of four moves per iteration.
- Guarantee equal probability.
- Append each move followed by
"_".
This is not merely string building. It is state initialization driven by randomized selection.
Probability Modeling
Using:
rand.nextInt(4)
produces:
| Generated Value | Selected Move | Probability |
|---|---|---|
| 0 | up | 1/4 |
| 1 | down | 1/4 |
| 2 | left | 1/4 |
| 3 | right | 1/4 |
This ensures uniform distribution, satisfying the “equal chance” specification.
State Evolution Example
Suppose numMoves = 5 and the random sequence generated is:
| Iteration | Random Value | Appended | moveSequence After |
|---|---|---|---|
| 0 | 1 | down_ | down_ |
| 1 | 3 | right_ | down_right_ |
| 2 | 0 | up_ | down_right_up_ |
| 3 | 2 | left_ | down_right_up_left_ |
| 4 | 1 | down_ | down_right_up_left_down_ |
Final state:
down_right_up_left_down_
This shows incremental state accumulation.
Design Tradeoffs
Why not use StringBuilder?
While StringBuilder is more efficient for repeated concatenation, AP CSA FRQs prioritize clarity and correctness over micro-optimization. String concatenation is acceptable and readable.
Why not use an array of strings?
We could have stored:
String[] moves = {"up", "down", "left", "right"};
moveSequence += moves[r] + "_";
That is slightly cleaner but not required.
Part 1B – countOccurrences
public int countOccurrences(String str) {
int count = 0;
for (int i = 0; i <= moveSequence.length() - str.length(); i++) {
if (moveSequence.substring(i, i + str.length()).equals(str)) {
count++;
}
}
return count;
}
}
Algorithm Strategy Explanation
The goal is to count how many times str appears in moveSequence.
Key requirement:
- The method must not modify
moveSequence.
This means we perform read-only scanning.
Sliding Window Concept
We examine substrings of equal length to str, starting at each possible index.
Loop boundary:
i <= moveSequence.length() - str.length()
This ensures no index-out-of-bounds errors.
Detailed Trace Example
Given:
moveSequence = "right_down_left_down_right_down_"
str = "down"
Length of str = 4
We evaluate:
| Index (i) | substring(i, i+4) | Match? |
|---|---|---|
| 6 | down | Yes |
| 16 | down | Yes |
| 27 | down | Yes |
Total count = 3
Overlapping Case
moveSequence = "up_up_up_"
str = "up_up"
Matches at:
| i | substring | Match? |
|---|---|---|
| 0 | up_up | Yes |
| 3 | up_up | Yes |
Count = 2
This confirms correct handling of overlapping patterns.
Edge Case Analysis
| Case | Behavior |
|---|---|
| str longer than moveSequence | Loop does not execute → returns 0 |
| str equals full moveSequence | Returns 1 |
| str not present | Returns 0 |
| str empty | Precondition implies valid input; not required to handle |
Reflection – Question 1
This problem tested precise control over string manipulation and loop boundaries.
Strengths demonstrated:
- Proper uniform random selection
- Clean iterative state building
- Correct substring scanning
- Preservation of object state
- Accurate handling of overlapping matches
- Defensive loop boundary design
This shows a strong command of:
- Random modeling
- String immutability awareness
- Careful indexing logic
- Correct method specification compliance
Question 2 – LapTracker
This question is fundamentally about state persistence across repeated method calls.
It tests:
- Instance variable tracking
- Reset logic
- Method-call counting
- Object independence
public class LapTracker {
private int lapCount;
private int resetFrequency;
private int callCount;
public LapTracker(int n) {
lapCount = 0;
resetFrequency = n;
callCount = 0;
}
public int addLaps(int laps) {
if (callCount == resetFrequency) {
lapCount = 0;
callCount = 0;
}
lapCount += laps;
callCount++;
return lapCount;
}
}
State Model Breakdown
| Variable | Purpose |
|---|---|
| lapCount | Current total laps in this cycle |
| resetFrequency | Number of method calls before reset |
| callCount | Number of addLaps calls since last reset |
Detailed Execution Walkthrough
Assume:
LapTracker amy = new LapTracker(3);
Call 1: addLaps(8)
| Before | After |
|---|---|
| lapCount = 0 | lapCount = 8 |
| callCount = 0 | callCount = 1 |
Return = 8
Call 2: addLaps(12)
| Before | After |
|---|---|
| lapCount = 8 | lapCount = 20 |
| callCount = 1 | callCount = 2 |
Return = 20
Call 3: addLaps(10)
| Before | After |
|---|---|
| lapCount = 20 | lapCount = 30 |
| callCount = 2 | callCount = 3 |
Return = 30
Call 4: addLaps(11)
Reset occurs because callCount == resetFrequency
| Before Reset | After Reset |
|---|---|
| lapCount = 30 | lapCount = 0 |
| callCount = 3 | callCount = 0 |
Then addition:
lapCount = 11 callCount = 1
Return = 11
Why Reset Happens Before Addition
If reset occurred after addition, the cycle would be shifted incorrectly. The specification implies the next call begins a new cycle, not the previous one.
Reflection – Question 2
This question demonstrates:
- Proper state lifecycle control
- Clear separation of configuration and dynamic state
- Understanding of method-call-based logic
- Correct alignment with sample table behavior
The implementation shows careful reading of problem wording and accurate modeling of behavior over time.
Question 3 – PlayerAnalysis
This question focuses on searching through an ArrayList and selecting the element with the smallest absolute difference from a target.
import java.util.ArrayList;
public class PlayerAnalysis {
private ArrayList<Player> playerList;
public String playerWithClosestScore(int targetScore) {
Player closest = playerList.get(0);
int smallestDiff = Math.abs(closest.getScore() - targetScore);
for (int i = 1; i < playerList.size(); i++) {
Player current = playerList.get(i);
int diff = Math.abs(current.getScore() - targetScore);
if (diff < smallestDiff) {
smallestDiff = diff;
closest = current;
}
}
return closest.getID();
}
}
Logical Strategy
This is a classic linear search with minimum tracking.
Steps:
- Assume first player is closest.
- Compute difference.
- Traverse remaining list.
- Update closest when smaller difference found.
Example Walkthrough
Target = 3000
| Player | Score | Score − 3000 | Closest So Far? | ||
|---|---|---|---|---|---|
| DJK | 1090 | 1910 | Yes (initial) | ||
| CJL | 2800 | 200 | Yes (update) | ||
| JOY | 2000 | 1000 | No | ||
| BEN | 500 | 2500 | No | ||
| PTT | 3500 | 500 | No | ||
| JAY | 4500 | 1500 | No |
Final result: CJL
Reflection – Question 3
This problem demonstrates:
- Proper ArrayList traversal
- Correct initialization strategy
- Clean update condition
- No mutation of original list
- Correct tie handling
It reflects strong understanding of:
- Object method calls
- Absolute value usage
- Selection algorithms
Question 4 – WordGrid
This question evaluates:
- 2D array traversal
- Nested loops
- Logical validation of sequence ordering
public class WordGrid {
private String[][] grid;
public int countOrderedRows() {
int count = 0;
for (int row = 0; row < grid.length; row++) {
boolean ordered = true;
for (int col = 1; col < grid[row].length; col++) {
if (grid[row][col].length() < grid[row][col - 1].length()) {
ordered = false;
break;
}
}
if (ordered) {
count++;
}
}
return count;
}
}
Ordered Row Condition
A row is ordered if:
length(current) ≥ length(previous)
Example Evaluation
Row 0: cat (3), crane (5), people (6), hamster (7) Ordered → Yes
Row 1: dog (3), slate (5), bat (3) 3 < 5 → Not ordered
Row 2: blue (4), audio (5), adieu (5), snazzy (6) Ordered → Yes
Reflection – Question 4
This question shows:
- Strong control over nested iteration
- Proper use of boolean flags
- Efficient early termination
- Accurate indexing logic
It confirms proficiency in:
- 2D array manipulation
- Sequence validation
- Conditional control flow
Final Reflection
Across all four problems, I demonstrated:
- Accurate translation of requirements into code
- Strong state management
- Clean object-oriented design
- Careful boundary control
- Correct use of loops and conditionals
- Thoughtful modeling of evolving state