2022 FRQ 4

6 min read

2022 FRQ 4 — Grid Quest UI Game

This lesson turns AP CSA 2022 FRQ 4 into a Java UI game.

Main concept

2D array traversal

  • Part A: fill every cell in a grid with valid random values
  • Part B: scan each column and count how many are increasing

FRQ Prompt

You are given this partial class:

Code Runner Challenge

FRQ #4 (a) - repopulate()

View IPYNB Source
public class Data
{
    public static final int MAX = /* value not shown */;
    private int[][] grid;

    public void repopulate()
    { /* to be implemented in part (a) */ }

    public int countIncreasingCols()
    { /* to be implemented in part (b) */ }
}
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Part A — repopulate

Fill every element of grid with a random value such that:

  • the value is between 1 and MAX, inclusive
  • the value is divisible by 10
  • the value is not divisible by 100

All valid values must have an equal chance of being generated.

Part B — countIncreasingCols

Return the number of columns in grid that are in increasing order.

A column is increasing if every value after the first row is greater than or equal to the value above it.

AP CSA • FRQ 2022 #4 • Grid Quest
Grid Quest: The Array Core

The system is unstable. Your guide is []. Complete each mission to restore the grid.

[]
[] says: We are entering a 2D array. Each mission teaches a Java concept from the FRQ. Keep the Array Core stable by earning points and avoiding mistakes.
Score
0
Array Stability
100%
Rank
Array Rookie
2D arrays grid[r][c] nested loops modulus boolean flag counter

Mission 1 — Coordinate Lock

Objective: lock onto the correct array coordinate before stability drops.
Score: 0
[]
[] says: Target coordinate: grid[1][2]. Row 1 is the second row. Column 2 is the third column. Click the target.
Click a tile to lock the target.
Java concept highlight
grid[r][c] r = row index c = column index grid[1][2] = second row, third column

Mission 2 — Reactor Sorting

Objective: collect only valid energy values for repopulate().
Score: 0
[]
[] says: To power the grid, values must be divisible by 10, not divisible by 100, and in range. Choose the legal energy crystals.
Select all valid values, then press Check.
Official Java solution — repopulate()
public void repopulate() { Random rand = new Random(); int maxMultiple = MAX / 10; for (int r = 0; r < grid.length; r++) { for (int c = 0; c < grid[0].length; c++) { int value; do { int k = rand.nextInt(maxMultiple) + 1; value = 10 * k; } while (value % 100 == 0); grid[r][c] = value; } } }

Mission 3 — Column Sentinel Boss Fight

Objective: defeat the sentinel by counting stable columns.
Score: 0
[]
[] says: The sentinel watches for decreases. A column is safe only if each value below is greater than or equal to the value above it. How many safe columns survive?
Choose how many columns are increasing.
Official Java solution — countIncreasingCols()
public int countIncreasingCols() { int count = 0; for (int c = 0; c < grid[0].length; c++) { boolean increasing = true; for (int r = 1; r < grid.length; r++) { if (grid[r][c] < grid[r - 1][c]) { increasing = false; break; } } if (increasing) { count++; } } return count; }

Mission 4 — Traversal Dungeon

Objective: move through the dungeon in the correct algorithmic order.
Score: 0
[]
[] says: The dungeon only respects correct traversal logic. Collect the hidden runes in the order that a Java algorithm would actually visit them.
Controls:
Find the first rune. The board will punish incorrect traversal.
Phase
Row Runner
Runes Collected
0 / 3
Boolean Flag
increasing = true
What this mission teaches
Phase 1: row-major traversal Phase 2: column traversal Phase 3: increasing-column logic Wrong moves = algorithm errors Walls = bounds errors Runes = checkpoints in traversal order

Mission 5 — Final Debrief

This is how the game maps directly to the FRQ.
Final Score: 0
[]
[] says: You restored the Array Core by learning the exact Java ideas tested in the FRQ.
Concepts mastered
int[][] grid[r][c] row-major traversal column traversal modulus boolean flag counter
One-sentence summary
This FRQ is about filling a 2D array with valid random values and scanning columns to count which ones stay increasing.

Code Runner Challenge

FRQ #4 (b) - countIncreasingCols()

View IPYNB Source
// CODE_RUNNER: FRQ #4 (a) - repopulate()
import java.util.Arrays;
import java.util.Random;

public class Main {

    public static class Data {
        public static final int MAX = 500;
        private int[][] grid;

        public Data(int rows, int cols) {
            grid = new int[rows][cols];
        }

        /**
         * Fills all elements of grid with randomly generated values:
         * - between 1 and MAX inclusive
         * - divisible by 10
         * - NOT divisible by 100
         * All valid values have equal probability.
         */
        public void repopulate() {
            Random rand = new Random();

            int maxMultiple = MAX / 10;  // largest k such that 10*k <= MAX

            for (int r = 0; r < grid.length; r++) {
                for (int c = 0; c < grid[0].length; c++) {

                    int value;
                    do {
                        int k = rand.nextInt(maxMultiple) + 1; // 1..maxMultiple
                        value = 10 * k;
                    } while (value % 100 == 0);

                    grid[r][c] = value;
                }
            }
        }
    }


    public void driver() {
        Data d = new Data(3, 5);
        d.repopulate();

        System.out.println("Generated Grid:");
        for (int[] row : d.grid) {
            System.out.println(Arrays.toString(row));
        }
    }

    public static void main(String[] args) {
        Main m = new Main();
        m.driver();
    }
}

Main.main(null);

Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...
// CODE_RUNNER: FRQ #4 (b) - countIncreasingCols()
import java.util.Arrays;

public class Main {

    public static class Data {
        private int[][] grid;

        public Data(int[][] g) {
            grid = g;
        }

        /**
         * Returns the number of columns in grid that are in increasing order.
         * A column is increasing if for every row r > 0:
         *   grid[r][c] >= grid[r-1][c]
         * A column with only one row is considered increasing.
         */
        public int countIncreasingCols() {
            int rows = grid.length;
            int cols = grid[0].length;
            int count = 0;

            for (int c = 0; c < cols; c++) {
                boolean increasing = true;

                for (int r = 1; r < rows; r++) {
                    if (grid[r][c] < grid[r - 1][c]) {
                        increasing = false;
                        break;
                    }
                }

                if (increasing) {
                    count++;
                }
            }

            return count;
        }
    }


    private static void printGrid(int[][] g) {
        for (int[] row : g) System.out.println(Arrays.toString(row));
    }

    public void driver() {
        int[][] example1 = {
            {10, 50, 40},
            {20, 40, 20},
            {30, 50, 30}
        };

        int[][] example2 = {
            {10, 540, 440, 440},
            {220, 450, 440, 190}
        };

        System.out.println("Example 1 Grid:");
        printGrid(example1);
        Data d1 = new Data(example1);
        System.out.println("countIncreasingCols() = " + d1.countIncreasingCols());
        System.out.println();

        System.out.println("Example 2 Grid:");
        printGrid(example2);
        Data d2 = new Data(example2);
        System.out.println("countIncreasingCols() = " + d2.countIncreasingCols());
        System.out.println();
    }

    public static void main(String[] args) {
        Main m = new Main();
        m.driver();
    }
}

Main.main(null);

Course Timeline