Campus Parking Allocation
Problem
A university parking office manages several zones with different priorities, space restrictions, and hourly prices. When a vehicle arrives, the office must choose the same best compatible space regardless of configuration order. When it leaves, the office releases that space, charges for started hours, and keeps the completed stay for later lookup.
Design CampusParking to manage this entry-to-exit lifecycle and report current occupancy. Calls are sequential, and the service owns a fixed snapshot of its configuration.
Requirements
- Valid configuration. The constructor accepts 1 to 100 zones, 1 to 200 spaces per zone, and at most 5,000 spaces in total. Zone priorities are integers from 0 to 1,000. A zone ID is unique globally, and a space ID is unique within its zone.
- Configured compatibility. Every space accepts 1 to 16 distinct vehicle types. Each zone has exactly one positive hourly rate for every vehicle type accepted by any of its spaces, and no rate for another type.
- Identifiers. Zone and space IDs contain 1 to 32 ASCII characters and match
[A-Za-z0-9][A-Za-z0-9_-]*. Vehicle IDs contain 1 to 64 ASCII characters and use the same pattern. Vehicle types contain 1 to 32 ASCII characters and match[a-z][a-z0-9-]*. - Configuration failures. Any invalid constructor value raises
ParkingErrorwith codeINVALID_CONFIGURATION. Construction does not retain references to caller-owned arrays or objects. - Entry arguments.
entryMinuteis an integer from 0 to 10,000,000, andvehicleTypemust occur in the configured global vehicle-type set. Invalid values raiseINVALID_ARGUMENT. - Event order. Each successful
enterorexitminute must be greater than or equal to the latest successful mutation minute. Equality is allowed. An earlier minute raisesTIME_REVERSED. - One active stay.
enterraisesALREADY_ACTIVEwhen the vehicle already has an active stay. A vehicle may enter again after exit. - Compatibility. A space is compatible only when its accepted vehicle types contain the requested type exactly.
- Deterministic allocation. Among compatible free spaces,
enterchooses the minimum tuple(zone priority, zone ID, accepted vehicle-type count, space ID). IDs use ASCII lexicographic order, and configuration input order has no effect. - Capacity.
enterraisesNO_SPACE_AVAILABLEwhen no compatible free space exists. A space holds at most one active vehicle, and each active vehicle occupies exactly one space. - Stay IDs. Successful entries receive consecutive IDs starting at 1. Rejected calls consume no ID.
- Captured price. Entry records the hourly rate configured for the allocated zone and vehicle type. Later operations use this captured integer-cent rate.
- Exit.
exitcompletes only the vehicle's current active stay, releases its space, and raisesNOT_ACTIVEwhen no active stay exists. - Charge. Let elapsed minutes be
exitMinute - entryMinute. The charge is 0 when elapsed is 0; otherwise it ishourlyRateCents * ceil(elapsed / 60). Charges use nonnegative integer cents. - History. Completed stays are immutable and remain queryable for the service lifetime. An active stay is absent from completed lookup, and a completed stay is absent from active lookup.
- Occupancy. A zone reports fixed total spaces, occupied spaces equal to its active stays, and available spaces equal to total minus occupied. A valid but unknown zone raises
UNKNOWN_ZONE. - Lookup absence. A valid unknown vehicle ID or stay ID returns absence. A stay ID argument must be an integer from 1 to 20,000; otherwise lookup raises
INVALID_ARGUMENT. - Snapshots. All returned stay and occupancy objects are snapshots. Mutating a returned object cannot change service state.
- Failure atomicity. A rejected call changes no stay, occupancy, next ID, or latest successful event minute. Validation order is scalar format and range, event time for mutations, lifecycle, then availability.
- Queries. Occupancy and lookup calls do not change state, IDs, or event ordering.
API
| Signature | Returns | Behavior |
|---|---|---|
CampusParking(zones: array<ZoneConfig>) | Not applicable | Snapshots a valid fixed configuration and creates an empty service; otherwise raises INVALID_CONFIGURATION. |
enter(vehicleId: string, vehicleType: string, entryMinute: integer) | ActiveStay | Allocates the deterministic compatible space and records an active stay, or raises INVALID_ARGUMENT, TIME_REVERSED, ALREADY_ACTIVE, or NO_SPACE_AVAILABLE according to the stated validation order. |
exit(vehicleId: string, exitMinute: integer) | CompletedStay | Completes the current stay, calculates its charge, and releases its space, or raises INVALID_ARGUMENT, TIME_REVERSED, or NOT_ACTIVE. |
getOccupancy(zoneId: string) | Occupancy | Returns a snapshot for the zone, or raises INVALID_ARGUMENT before UNKNOWN_ZONE. |
findActiveStay(vehicleId: string) | ActiveStay or absence | Returns the vehicle's current active stay snapshot, or absence for a valid unknown or completed vehicle; invalid input raises INVALID_ARGUMENT. |
findCompletedStay(stayId: integer) | CompletedStay or absence | Returns the completed stay snapshot, or absence for an active or never-issued valid ID; invalid input raises INVALID_ARGUMENT. |
ZoneConfig has zoneId: string, priority: integer, spaces: array<SpaceConfig>, and pricingRules: array<PricingRule>. SpaceConfig has spaceId: string and acceptedVehicleTypes: array<string>. PricingRule has vehicleType: string and hourlyRateCents: integer from 1 to 1,000,000.
ActiveStay has stayId, vehicleId, vehicleType, zoneId, spaceId, entryMinute, and hourlyRateCents. CompletedStay adds exitMinute and chargeCents. Occupancy has zoneId, totalSpaces, occupiedSpaces, and availableSpaces.
Every ParkingError exposes its exact code through a public code property or accessor.
Examples
Given zone east at priority 1 with E1 accepting car and motorcycle, E2 accepting car, a car rate of 200 cents, and a motorcycle rate of 100 cents, plus zone west at priority 1 with W1 accepting car at 250 cents:
| Step | Operation | Result |
|---|---|---|
| 1 | enter("V1", "car", 100) | Stay 1 in east/E2 at 200 cents per hour. |
| 2 | enter("V2", "car", 100) | Stay 2 in east/E1. |
| 3 | getOccupancy("east") | 2 total, 2 occupied, 0 available. |
| 4 | exit("V1", 161) | Stay 1 completes with a 400-cent charge and releases E2. |
| 5 | findActiveStay("V1") | Absence. |
| 6 | findCompletedStay(1) | The completed stay from step 4. |
Constraints
- At most 50,000 calls are made to one instance.
- At most 20,000 entries succeed.
- Event minutes are at most 10,000,000, and the maximum valid charge is less than 167,000,000,000 cents.
- The configuration is fixed after construction.
Notes
Calls are sequential. Allocation and point lookup results have no collection ordering contract. Cancellation, deletion, reopening, reservations, waiting, dynamic configuration, external persistence, and real calendar time are outside scope.