2023 AP® Computer Science A FRQ 1 — AppointmentBook (Methods & Control Structures)

2023 AP® Computer Science A FRQ 1 — AppointmentBook (Methods & Control Structures)

Topic: Nested loops, boolean logic, method decomposition
2025 Curriculum Alignment: Unit 2 (Selection & Iteration) + Unit 1 (Methods)


Question

This question involves the AppointmentBook class, which provides methods for students to schedule appointments with their teacher. Appointments can be scheduled during one of eight class periods during the school day, numbered 1 through 8. A requested appointment has a duration, which is the number of minutes the appointment will last. The 60 minutes within a period are numbered 0 through 59.

In order for an appointment to be scheduled, the teacher must have a block of consecutive, available minutes that contains at least the requested number of minutes in a requested period. Scheduled appointments must start and end within the same period.

Provided Class

public class AppointmentBook {
    /**
     * Returns true if minute in period is available for an appointment 
     * and returns false otherwise
     * Preconditions: 1 <= period <= 8; 0 <= minute <= 59
     */
    private boolean isMinuteFree(int period, int minute) {
        /* implementation not shown */
    }

    /**
     * Marks the block of minutes that starts at startMinute in period 
     * and is duration minutes long as reserved for an appointment
     * Preconditions: 1 <= period <= 8; 0 <= startMinute <= 59;
     *                1 <= duration <= 60
     */
    private void reserveBlock(int period, int startMinute, int duration) {
        /* implementation not shown */
    }

    /**
     * Searches for the first block of duration free minutes during period.
     * Returns the first minute in the block if such a block is found or 
     * returns -1 if no such block is found.
     * Preconditions: 1 <= period <= 8; 1 <= duration <= 60
     */
    public int findFreeBlock(int period, int duration) {
        /* to be implemented in part (a) */
    }

    /**
     * Searches periods from startPeriod to endPeriod, inclusive, for a block
     * of duration free minutes. If such a block is found, calls reserveBlock 
     * to reserve the block of minutes and returns true; otherwise returns false.
     * Preconditions: 1 <= startPeriod <= endPeriod <= 8; 1 <= duration <= 60
     */
    public boolean makeAppointment(int startPeriod, int endPeriod, 
                                     int duration) {
        /* to be implemented in part (b) */
    }
}

Part (a)

Write the findFreeBlock method, which searches period for the first block of free minutes that is duration minutes long. If such a block is found, findFreeBlock returns the first minute in the block. Otherwise, findFreeBlock returns -1.

The findFreeBlock method uses the helper method isMinuteFree, which returns true if a particular minute is available to be included in a new appointment and returns false if the minute is unavailable.

Example: Consider the following list of unavailable and available minutes in period 2:

Minutes in Period 2 Available?
0–9 (10 minutes) No
10–14 (5 minutes) Yes
15–29 (15 minutes) No
30–44 (15 minutes) Yes
45–49 (5 minutes) No
50–59 (10 minutes) Yes
  • findFreeBlock(2, 15) would return 30 (a 15-minute block starting at minute 30 is available)
  • findFreeBlock(2, 9) would also return 30 (whenever there are multiple blocks, return the earliest)
  • findFreeBlock(2, 20) would return -1 (no 20-minute block exists)

Complete method findFreeBlock. You must use isMinuteFree appropriately to receive full credit.

Part (b)

Write the makeAppointment method, which searches the periods from startPeriod to endPeriod, inclusive, for the earliest block of duration available minutes in the lowest-numbered period.

If such a block is found, the makeAppointment method calls the helper method reserveBlock to mark the minutes in the block as unavailable and returns true. If no such block is found, the makeAppointment method returns false.

Example: Consider the following list of unavailable and available minutes in periods 2, 3, and 4:

Period Minutes Available?
2 0–24 (25 minutes) No
2 25–29 (5 minutes) Yes
2 30–59 (30 minutes) No
3 0–14 (15 minutes) Yes
3 15–40 (26 minutes) No
3 41–59 (19 minutes) Yes
4 0–4 (5 minutes) No
4 5–29 (25 minutes) Yes
4 30–43 (14 minutes) No
4 44–59 (16 minutes) Yes
  • makeAppointment(2, 4, 22) returns true and reserves minutes 5–26 in period 4
  • makeAppointment(3, 4, 3) returns true and reserves minutes 0–2 in period 3
  • makeAppointment(2, 4, 30) returns false (no 30-minute block exists in periods 2, 3, or 4)

Complete method makeAppointment. Assume that findFreeBlock works as intended, regardless of what you wrote in part (a). You must use findFreeBlock and reserveBlock appropriately to receive full credit.


Solution & Explanation

Part (a) Solution

public int findFreeBlock(int period, int duration) {
    for (int startMinute = 0; startMinute <= 59; startMinute++) {
        int endMinute = startMinute + duration - 1;
        
        if (endMinute > 59) {
            return -1;
        }
        
        boolean isFree = true;
        for (int minute = startMinute; minute <= endMinute; minute++) {
            if (!isMinuteFree(period, minute)) {
                isFree = false;
                break;
            }
        }
        
        if (isFree) {
            return startMinute;
        }
    }
    
    return -1;
}

Part (a) Explanation

Algorithm Logic:

  1. Outer loop iterates through all possible starting minutes (0–59)
  2. Calculate end minute of the potential block: startMinute + duration - 1
  3. Check if block extends past minute 59 — if so, no valid block can start here, return -1
  4. Inner loop checks if all minutes in the block are free using isMinuteFree
  5. If entire block is free, return the starting minute
  6. If no block found, return -1

Key Points:

  • Uses nested loops correctly to check consecutive minutes
  • Properly uses the isMinuteFree helper method
  • Returns the first valid block found (earliest starting minute)
  • Handles edge case where requested duration extends past minute 59
  • Uses a boolean flag to track whether entire block is free

Alternative Approach: You could also track consecutive free minutes in one pass through the 60 minutes, but the nested loop approach is clearer and easier to verify for correctness.

Part (b) Solution

public boolean makeAppointment(int startPeriod, int endPeriod, int duration) {
    for (int period = startPeriod; period <= endPeriod; period++) {
        int startMinute = findFreeBlock(period, duration);
        
        if (startMinute != -1) {
            reserveBlock(period, startMinute, duration);
            return true;
        }
    }
    
    return false;
}

Part (b) Explanation

Algorithm Logic:

  1. Loop through periods from startPeriod to endPeriod, inclusive
  2. For each period, call findFreeBlock to search for an available block
  3. If a block is found (return value is not -1):
    • Call reserveBlock to mark those minutes as unavailable
    • Return true to indicate success
  4. If no block found in any period, return false

Key Points:

  • Correctly uses findFreeBlock to search each period
  • Searches periods in order from lowest to highest number
  • Calls reserveBlock immediately when a suitable block is found
  • Returns true as soon as an appointment is made (doesn't continue searching)
  • Returns false only after checking all periods

Why This Works: The loop ensures we check the lowest-numbered period first. findFreeBlock already returns the earliest starting minute within a period. By combining these, we get the earliest possible appointment.


Scoring Notes

Part (a) — 5 points:

  • +1: Loops through potential starting minutes
  • +1: Determines appropriate ending minute
  • +1: Uses isMinuteFree to check if minutes are available
  • +1: Checks all minutes in potential block
  • +1: Returns correct value based on whether block is found

Part (b) — 4 points:

  • +1: Loops through periods from startPeriod to endPeriod
  • +1: Calls findFreeBlock for each period
  • +1: Calls reserveBlock when appropriate
  • +1: Returns correct boolean value

Common Mistakes to Avoid:

  • Part (a): Forgetting to check if the block extends past minute 59
  • Part (a): Not using isMinuteFree (trying to access instance variables directly)
  • Part (a): Checking only one minute instead of all minutes in the block
  • Part (b): Not calling reserveBlock to actually mark the minutes as unavailable
  • Part (b): Continuing to search after finding a suitable block (should return immediately)

College Board Resources

Contact form