Problemrecurring workspace calendar

Session: Sign in to solve

Solution.txt

Recurring Workspace Calendar

Problem

A team shares rooms and desks through one calendar. Design RecurringWorkspaceCalendar to register those resources, create finite recurring bookings, preserve each occurrence when it is moved or cancelled, and report occupied and free time on an integer-minute timeline. Calls are sequential, and each calendar instance owns independent state.

Requirements

  • Resource registry. addResource permanently registers a valid, previously unused resource ID.
  • Bounded recurrence. book creates one occurrence for ONCE, or a finite daily or weekly series whose duration and zero-based occurrence indices follow the declared expansion.
  • Atomic booking. book validates the complete expansion before changing state; invalid input, an unknown resource, self-overlap, or overlap with any active occurrence creates nothing and leaves the booking ID reusable.
  • Half-open conflicts. Active occurrences on the same resource conflict exactly when their half-open intervals overlap; touching endpoints do not conflict.
  • Stable identity. An occurrence keeps its booking ID, occurrence index, resource, and siblings when moved or cancelled.
  • Persistent exceptions. Moving an active occurrence replaces only its interval, while cancelling it preserves its current interval for inspection but removes it from occupancy.
  • Series cancellation. cancelBooking cancels every active occurrence in the booking and preserves all occurrence history.
  • Failure atomicity. A rejected cancellation or move leaves all state unchanged.
  • Deterministic availability. Availability contains every active occurrence that overlaps the query window, in the declared order, plus the maximal free intervals inside the window.

API

SignatureReturnsBehavior
RecurringWorkspaceCalendar()Not applicableCreates an empty calendar.
addResource(resourceId: string)stringReturns INVALID_ARGUMENT, DUPLICATE_RESOURCE, or OK, using the first applicable result. A successful ID is permanent.
book(bookingId: string, resourceId: string, startMinute: int64, endMinute: int64, frequency: string, occurrenceCount: integer)stringReturns INVALID_ARGUMENT, DUPLICATE_BOOKING, UNKNOWN_RESOURCE, CONFLICT, or OK, using the first applicable result. Successful booking IDs are permanent.
cancelBooking(bookingId: string)stringReturns INVALID_ARGUMENT, UNKNOWN_BOOKING, INVALID_STATE, or OK, using the first applicable result. OK requires at least one active child.
cancelOccurrence(bookingId: string, occurrenceIndex: integer)stringReturns INVALID_ARGUMENT, UNKNOWN_OCCURRENCE, INVALID_STATE, or OK, using the first applicable result.
moveOccurrence(bookingId: string, occurrenceIndex: integer, newStartMinute: int64, newEndMinute: int64)stringReturns INVALID_ARGUMENT, UNKNOWN_OCCURRENCE, INVALID_STATE, CONFLICT, or OK, using the first applicable result. Conflict checking excludes the occurrence's current interval.
getOccurrence(bookingId: string, occurrenceIndex: integer)OccurrenceViewReturns the current detached occurrence snapshot. A malformed or missing identity returns the sentinel described below.
queryAvailability(resourceId: string, windowStartMinute: int64, windowEndMinute: int64)AvailabilityViewReturns INVALID_ARGUMENT, UNKNOWN_RESOURCE, or OK, using the first applicable result. Non-OK results contain empty arrays.

TimeInterval has startMinute: int64 and endMinute: int64. OccurrenceView has found: boolean, bookingId: string, occurrenceIndex: integer, resourceId: string, startMinute: int64, endMinute: int64, and status: string. Existing occurrences have status ACTIVE or CANCELLED. A missing occurrence has found = false, empty strings, index -1, zero times, and status NOT_FOUND. AvailabilityView has status: string, occurrences: OccurrenceView[], and freeIntervals: TimeInterval[]. All returned views and arrays are detached.

For ONCE, the count must be 1. For DAILY and WEEKLY, the count must be from 2 through 100. Occurrence i starts at startMinute + i * 1440 for DAILY and startMinute + i * 10080 for WEEKLY; every occurrence keeps the original duration. Any generated interval outside the valid time range is invalid.

Examples

StepOperationResult
1addResource("room-a")OK
2book("standup", "room-a", 100, 160, "DAILY", 2)OK; occurrences are [100,160) and [1540,1600)
3book("review", "room-a", 160, 200, "ONCE", 1)OK; touching endpoints are allowed
4moveOccurrence("standup", 1, 180, 240)CONFLICT; occurrence 1 remains [1540,1600)
5moveOccurrence("standup", 1, 200, 260)OK; occurrence 1 keeps its identity
6queryAvailability("room-a", 90, 270)Active intervals [100,160), [160,200), [200,260); free intervals [90,100), [260,270)
7cancelOccurrence("review", 0)OK
8queryAvailability("room-a", 90, 270)Active intervals [100,160), [200,260); free intervals [90,100), [160,200), [260,270)
9getOccurrence("review", 0)Found, CANCELLED, interval [160,200)

Constraints

  • IDs are non-null, case-sensitive ASCII strings matching [A-Za-z0-9_-]{1,40}.
  • Intervals are half-open and valid only when 0 <= startMinute < endMinute <= 1_000_000_000.
  • A calendar contains at most 100 resources, 5,000 successful bookings, and 20,000 retained occurrences.
  • A testcase contains at most 20,000 actions.
  • Time calculations use signed 64-bit arithmetic.
  • Conflict checks and availability queries should avoid scanning unrelated resources; producing a query result costs at least linear time in its output size.

Notes

Active intervals [aStart,aEnd) and [bStart,bEnd) overlap exactly when aStart < bEnd and bStart < aEnd. Availability returns complete stored occurrence intervals, even when they extend beyond the query window. It sorts occurrences by startMinute, endMinute, ASCII bookingId, then occurrenceIndex. Free intervals are maximal, nonempty, clipped to the query window, and sorted by start. Calls on one instance are serialized, and separate instances share no state. Time zones, clocks, persistence, unbounded recurrence, reactivation, deletion, and whole-booking or resource movement are out of scope.

PRIVATE WORKSPACE

Checking your session…

The statement is public. The editor, editorial, submissions, and saved work are private.