Walkthrough 2023 FRQ #4

Part A:

Goal:

  • Move a piece of candy to the first row of a given column if possible.

Steps:

  • Check if the first row already has candy → If yes, return true.
  • Search for candy in the column starting from the second row.
  • If found, move it to row 0 and set the original position to null, then return true.
  • If no candy is found, return false.

The Code

public class BoxOfCandy {
    private Candy[][] box;

    // Part A: Buggy version of moveCandyToFirstRow
    public boolean moveCandyToFirstRow(int col) {
        if (box[0][col] != null) { // Check if candy is already in the first row
            return true;
        }
        
        for (int row = 1; row <= box.length; row++) { // BUG: Should be '<', not '<='
            if (box[row][col] != null) { // BUG: Can go out of bounds
                box[0][col] = box[row][col]; // Move candy to the first row
                box[row][col] = null; // Clear the original position
                return true;
            }
        }
        return false; // No candy found in the column
    }

    // Part A: Corrected version of moveCandyToFirstRow
    public boolean moveCandyToFirstRow(int col) {
        if (box[0][col] != null) { // Check if first row already has candy
            return true;
        }
        
        for (int row = 1; row < box.length; row++) { // Fixed '<=' to '<'
            if (box[row][col] != null) { // Find the first candy in the column
                box[0][col] = box[row][col]; // Move it to the top
                box[row][col] = null; // Remove candy from the original spot
                return true;
            }
        }
        return false; // No candy found to move
    }
}

Bug Explanations

  • The loop condition row <= box.length causes it to go one row past the array bounds, which leads to an ArrayIndexOutOfBoundsException.
  • If the loop goes out of bounds, trying to access box[row][col] crashes the program.

Part B:

Goal:

  • Find and remove the first candy (bottom-up, left-to-right) with the given flavor.

Steps:

  • Start from the last row and go up.
  • Within each row, check columns from left to right.
  • If a candy with the given flavor is found, remove it (set to null) and return it.
  • If no matching candy is found, return null.

Code:

public class BoxOfCandy {

    // Part B: Buggy version of removeNextByFlavor
    public Candy removeNextByFlavor(String flavor) {
        for (int row = box.length - 2; row >= 0; row--) { // BUG: Skips the last row
            for (int col = 0; col < box[row].length; col++) {
                if (box[row][col].getFlavor().equals(flavor)) { // BUG: Might cause NullPointerException
                    Candy removedCandy = box[row][col]; // Store the candy to return later
                    box[row][col] = null; // Remove the candy
                    return removedCandy; // Return the removed candy
                }
            }
        }
        return null; // No matching candy found
    }

    // Part B: Corrected version of removeNextByFlavor
    public Candy removeNextByFlavor(String flavor) {
        for (int row = box.length - 1; row >= 0; row--) { // Start searching from the last row
            for (int col = 0; col < box[row].length; col++) { // Check each column from left to right
                if (box[row][col] != null && box[row][col].getFlavor().equals(flavor)) { // Fixed NullPointerException
                    Candy removedCandy = box[row][col]; // Store the candy to return later
                    box[row][col] = null; // Remove candy from the box
                    return removedCandy; // Return the removed candy
                }
            }
        }
        return null; // No candy with matching flavor found
    }
}

Bug Explanations

  • The loop starts from box.length - 2, which means it never checks the last row, potentially missing a candy that should be removed.
  • The code calls .getFlavor() without first checking if box[row][col] is null, which can cause an error if there’s an empty spot in the grid.