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 updated