Comment on page
Parking Lot
Design a parking system.
Purposefully vague. Discuss the exact requirement with your interviewer.
Some questions we can ask:
- How should accessibility be taken care of? Do we need to prioritize handcap parking areas, for example?
- Is this a ground parking lot, or a monitored system?
- How many entrances are in the parking lot? (Do we have to deal with any issues of concurancy?)
- Should there by any pricing strategies in place? Do we offer premium services (reserved parking areas) to customers?
- Do we need to support different types of spots for different type of vehicles?
Assumptions:
- Design a monitored system for support for 4 different type of vehicles (S,M,L,XL). The parking lot supports 150 small vehicles, 100 medium vehicles, 50 large vehicles, and 25 extra large vehicles.
- A smaller vehicle can only be parked in a spot that is designated to be equal or large than itself. That is a L vehicle cannot park to M spot, but can park to an L to XL spot.
Implementation:
- Build an interface and support efficient implementation for the following methods:
Spot placeVehicle(Vehicle):
return a spot for a Vehicle spot.- This method must return an available spot prioritized by its type. For example, a small vehicle can only be parked in a mediumed sized parking spot iff there are no small vehicle spots available.
- If there are no spots available, throw an exception.
void removeVehicle(Vehicle):
remove a vehicle from the parking lot.
from enum import IntEnum
import queue, copy
class Size(IntEnum):
S = 0,
M = 1,
L = 2,
XL = 3
class Vehicle:
def __init__(self, id, size):
"""
:param id: [int]
:param size: [Size]
"""
self.drivers_lic = id
self.size = size
def __hash__(self):
return hash(self.drivers_lic)
def __eq__(self, other):
return self.drivers_lic == other.drivers_lic
def __str__(self):
return str(self.drivers_lic) + " " + str(self.size)
class Car(Vehicle):
def __init__(self, id):
"""
:param id: [int]
"""
super().__init__(id, Size.M)
def __hash__(self):
return super().__hash__()
def __eq__(self, other):
return super().__eq__(other)
def __str__(self):
return super().__str__()
class MotorCycle(Vehicle):
def __init__(self, id):
"""
:param id: [int]
"""
super().__init__(id, Size.S)
def __hash__(self):
return super().__hash__()
def __eq__(self, other):
return super().__eq__(other)
def __str__(self):
return super().__str__()
class Bus(Vehicle):
def __init__(self, id):
"""
:param id: [int]
"""
super().__init__(id, Size.XL)
def __hash__(self):
return super().__hash__()
def __eq__(self, other):
return super().__eq__(other)
def __str__(self):
return super().__str__()
class Truck(Vehicle):
def __init__(self, id):
"""
:param id: [int]
"""
super().__init__(id, Size.L)
def __hash__(self):
return super().__hash__()
def __eq__(self, other):
return super().__eq__(other)
def __str__(self):
return super().__str__()
class Spot:
def __init__(self, id, size):
"""
:param id: [int]
:param size: [Size]
"""
self.id = id
self.size = size
def __eq__(self, other):
return self.id == other.id
class ParkingLot:
def __init__(self, zipcode, size_class):
"""
:param zipcode: [int]
:param size_class: List[int]
"""
self.zipcode = zipcode
self.capacities = size_class
self.counts = [0] * 4
# main datastructure to hold are parking cars
self.Park_DB = {Size.S: {}, Size.M: {}, Size.L: {}, Size.XL: {}}
# using a priority queue will ensure that when a car gets
# removed from the lot, the next available spot will be the
# next 'closest' spot to the next user.
self.spot_ids = queue.PriorityQueue()
for id in range(sum(self.capacities)):
self.spot_ids.put(id)
def place_vehicle(self, vehicle):
"""
Identifies and stores the next available parking spot
:param vehicle: [Vehicle]
:return: [Spot]
"""
# check if vehicle already exists in the lot
if any(vehicle in self.Park_DB[size] for size in Size):
raise ValueError("Duplicate Vehicle ID identified.")
# find the first available spot starting from current size
for size in range(int(vehicle.size), len(self.counts)):
if self.counts[size] < self.capacities[size]:
# a spot was found, so add the spot to the hash table
next_spot = Spot(self.spot_ids.get(), Size(size))
self.Park_DB[Size(size)][vehicle] = next_spot
self.counts[size] += 1
return next_spot
raise OverflowError("All vehicle capacities are full.")
def remove_vehicle(self, vehicle):
"""
Removes an identified vehicle from the parking lot
:param vehicle: [vehicle]
:return: [Spot]
"""
for size in range(int(vehicle.size), len(self.counts)):
if vehicle in self.Park_DB[Size(size)]:
# the vehicle was found - copy and return its spot
spot = copy.copy(self.Park_DB[Size(size)][vehicle])
# put back the available parking id spot back into queue
self.spot_ids.put(spot.id)
# remove the vehicle from the lot
del self.Park_DB[Size(size)][vehicle]
self.counts[size] -= 1
return spot
# vehicle was not found
raise LookupError("Vehicle id was unidentified in the ParkingLot")
def __str__(self):
strings = []
for size, vehicles in self.Park_DB.items():
strings.append(str(size) + ": " + "\n")
for vehicle in vehicles:
strings.append("\t" + str(vehicle) + "\n")
return ''.join(strings)
Testing
PL = ParkingLot(95616, [0, 2, 3, 1])
PL.place_vehicle(Car(0))
try:
PL.place_vehicle(Car(0))
except ValueError:
print("Duplicate identified")
PL.place_vehicle(Car(1))
spot1 = PL.place_vehicle(Car(2))
print(PL)
spot2 = PL.remove_vehicle(Car(2))
print(PL)
assert(spot1 == spot2)
try:
PL.remove_vehicle(Car(2))
except LookupError:
print("Vehicle doesnt Exist")
spot3 = PL.place_vehicle(Car(3))
assert(spot1 == spot3 == spot2)
PL.place_vehicle(Bus(20))
try:
PL.place_vehicle(Bus(21))
except OverflowError:
print("No more bus spots available")
print(PL)
Output
Duplicate identified
Size.S:
Size.M:
0 Size.M
1 Size.M
Size.L:
2 Size.M
Size.XL:
Size.S:
Size.M:
0 Size.M
1 Size.M
Size.L:
Size.XL:
Vehicle doesnt Exist
No more bus spots available
Size.S:
Size.M:
0 Size.M
1 Size.M
Size.L:
3 Size.M
Size.XL:
20 Size.XL
Last modified 4yr ago