FRQ 2019 #4: LightBoard

Part A constructor + Part B evaluateLight

public class LightBoardTest
{
    public static void main(String[] args)
    {
        LightBoard board = new LightBoard(5, 6);

        System.out.println("Initial Board:");
        board.printBoard();

        System.out.println("\nEvaluated Board:");
        for (int r = 0; r < board.getNumRows(); r++)
        {
            for (int c = 0; c < board.getNumCols(); c++)
            {
                System.out.print(board.evaluateLight(r, c) ? "T " : "F ");
            }
            System.out.println();
        }
    }
}

class LightBoard
{
    private boolean[][] lights;

    // Part A: Constructor
    public LightBoard(int numRows, int numCols)
    {
        lights = new boolean[numRows][numCols];

        for (int r = 0; r < numRows; r++)
        {
            for (int c = 0; c < numCols; c++)
            {
                double rnd = Math.random();
                lights[r][c] = rnd < 0.4;
            }
        }
    }

    // Part B: evaluateLight
    public boolean evaluateLight(int row, int col)
    {
        int numOn = 0;

        // Count number of true values in specified column
        for (int r = 0; r < lights.length; r++)
        {
            if (lights[r][col])
            {
                numOn++;
            }
        }

        // Rule 1: If light is on and number of on lights in column is even
        if (lights[row][col] && numOn % 2 == 0)
        {
            return false;
        }

        // Rule 2: If light is off and number of on lights in column is multiple of 3
        if (!lights[row][col] && numOn % 3 == 0)
        {
            return true;
        }

        // Rule 3: Otherwise return current state
        return lights[row][col];
    }

    // Helper method to print original board
    public void printBoard()
    {
        for (int r = 0; r < lights.length; r++)
        {
            for (int c = 0; c < lights[0].length; c++)
            {
                System.out.print(lights[r][c] ? "T " : "F ");
            }
            System.out.println();
        }
    }

    public int getNumRows()
    {
        return lights.length;
    }

    public int getNumCols()
    {
        return lights[0].length;
    }
}
run:LightBoardTest.main(null);
Initial Board:
F F T T F F 
F F F F F T 
F T F T F T 
F F F F F T 
F T F F F F 

Evaluated Board:
T F T F T T 
T F F F T T 
T F F F T T 
T F F F T T 
T F F F T T 

Scoring Guidelines Part A

Intent: Define implementation of a constructor that initializes a 2D array of lights.

  • +1 Creates a new boolean[numRows][numCols] and assigns to instance variable lights
  • +1 Accesses all elements in the created 2D array (no bounds errors)
  • +1 Computes the 40% probability
  • +1 Sets all values of 2D array based on computed probability

Part (a) LightBoard (4 points)

| Points | Rubric Criteria | Responses earn the point even if they… | Responses will not earn the point if they… | | — | — | — | — | | +1 | Creates a new boolean[numRows][numCols] and assigns to instance variable lights | initialize a local variable that is never assigned to lights | omit the keyword new or use a type other than boolean | | +1 | Accesses all elements in the created 2D array (no bounds errors) | fail to create lights but assume lights[numRows][numCols] | | | +1 | Computes the 40% probability | use Math.random() <= .4 | incorrectly cast to int | | +1 | Sets all values of 2D array based on computed probability | only assign true values or compute a single probability but use it multiple times | reverse the sense of the comparison when assigning |

Scoring Guidelines Part B

Intent: Evaluate the status of a light in a 2D array of lights.

  • +1 Accesses an element of lights as a boolean value in an expression
  • +1 Traverses specified col of a 2D array (no bounds errors)
  • +1 Counts the number of true values in the traversal
  • +1 Performs an even calculation and a multiple of three calculation
  • +1 Returns true or false according to all three rules

Part (b) evaluateLight (5 points)

| Points | Rubric Criteria | Responses earn the point even if they… | Responses will not earn the point if they… | | — | — | — | — | | +1 | Accesses an element of lights as a boolean value in an expression | | access lights as a type other than boolean | | +1 | Traverses specified col of a 2D array (no bounds errors) | | | | +1 | Counts the number of true values in the traversal | access too many or too few items in a single column; access a single row instead of a single column | count an item more than once | | +1 | Performs an even calculation and a multiple of three calculation | use / instead of % | | | +1 | Returns true or false according to all three rules | have an incorrect column count but use the correct logic | fail to return a value in some case or implement counting loop more than once with one loop that is incorrect |

Detailed Explanation

Part A: Constructor Logic

The goal is to initialize the lights 2D array so each cell is independently randomized.

  • Instantiation: Create the array with new boolean[numRows][numCols].
  • Traversal: Use nested loops to visit every row and column.
  • Probability: Use Math.random() and set the cell to true when the value is less than 0.4.

Part B: evaluateLight Logic

This method decides the state of a specific light based on the column it is in.

  • Counting lights: Traverse rows in the given column and count true values.
  • Rules:
    • If the target light is on and the column count is even, return false.
    • If the target light is off and the column count is a multiple of 3, return true.
    • Otherwise, return the current light state.

Common Mistakes

Part A

  • Forgetting new (array never created).
  • Swapping numRows and numCols in the loops.
  • Using an incorrect probability expression or integer casting.
  • Reusing a single random value for all cells.

Part B

  • Iterating across columns instead of rows when counting a column.
  • Forgetting to reset the counter at the start of the method.
  • Using / instead of % for even or multiple-of-3 checks.
  • Over-complicating the return logic and missing a case.