Requirements

Multiple floors: There should be multiple floors with multiple spots on each floor.

Parking spot assignment based on vehicle size: There should be different sizes of spots suitable for different types of vehicles.

Spot availability checking: We should be able to check if there spots available for new vehicles.

Fee calculation based on parking duration: We need to calculate fees based on how much time the vehicle was parked.



Define Core Objects

Based on the requirements and use cases, identify the main objects of the system...






Analyze Relationships

Determine how these objects will interact with each other to fulfill the use cases...






Establish Hierarchy

Design inheritance trees where applicable to promote code reuse and polymorphism. This step involves identifying common attributes and behaviors that can be abstracted into parent classes...






Design Patterns

Consider using design patterns (e.g., Factory, Singleton, Observer, Strategy) that fit the problem...






Define Class Members (write code)

Attributes: For each class, define the attributes (data) it will hold...

Methods: Define the methods (functions) that operate on the attributes. Ensure they align with the object's responsibilities and adhere to the principle of encapsulation.


from abc import ABCMeta, abstractmethod

from enum import Enum



class VehicleSize(Enum):


MOTORCYCLE = 0

COMPACT = 1

LARGE = 2



class Vehicle(metaclass=ABCMeta):


def __init__(self, vehicle_size, license_plate, spot_size):

self.vehicle_size = vehicle_size

self.license_plate = license_plate

self.spot_size

self.spots_taken = []


def clear_spots(self):

for spot in self.spots_taken:

spot.remove_vehicle(self)

self.spots_taken = []


def take_spot(self, spot):

self.spots_taken.append(spot)


@abstractmethod

def can_fit_in_spot(self, spot):

pass



class Motorcycle(Vehicle):


def __init__(self, license_plate):

super(Motorcycle, self).__init__(VehicleSize.MOTORCYCLE, license_plate, spot_size=1)


def can_fit_in_spot(self, spot):

return True



class Car(Vehicle):


def __init__(self, license_plate):

super(Car, self).__init__(VehicleSize.COMPACT, license_plate, spot_size=1)


def can_fit_in_spot(self, spot):

return spot.size in (VehicleSize.LARGE, VehicleSize.COMPACT)



class Bus(Vehicle):


def __init__(self, license_plate):

super(Bus, self).__init__(VehicleSize.LARGE, license_plate, spot_size=5)


def can_fit_in_spot(self, spot):

return spot.size == VehicleSize.LARGE



class ParkingLot(object):


def __init__(self, num_levels):

self.num_levels = num_levels

self.levels = [] # List of Levels


def park_vehicle(self, vehicle):

for level in self.levels:

if level.park_vehicle(vehicle):

return True

return False



class Level(object):


SPOTS_PER_ROW = 10


def __init__(self, floor, total_spots):

self.floor = floor

self.num_spots = total_spots

self.available_spots = 0

self.spots = [] # List of ParkingSpots


def spot_freed(self):

self.available_spots += 1


def park_vehicle(self, vehicle):

spot = self._find_available_spot(vehicle)

if spot is None:

return None

else:

spot.park_vehicle(vehicle)

return spot


def _find_available_spot(self, vehicle):

"""Find an available spot where vehicle can fit, or return None"""

pass


def _park_starting_at_spot(self, spot, vehicle):

"""Occupy starting at spot.spot_number to vehicle.spot_size."""

pass



class ParkingSpot(object):


def __init__(self, level, row, spot_number, spot_size, vehicle_size):

self.level = level

self.row = row

self.spot_number = spot_number

self.spot_size = spot_size

self.vehicle_size = vehicle_size

self.vehicle = None


def is_available(self):

return True if self.vehicle is None else False


def can_fit_vehicle(self, vehicle):

if self.vehicle is not None:

return False

return vehicle.can_fit_in_spot(self)


def park_vehicle(self, vehicle):

pass


def remove_vehicle(self):

pass



Adhere to SOLID Guidelines

Check and explain whether your design adheres to solid principles (Ask interviewer what SOLID principle is if you can not recall it.)...






Consider Scalability and Flexibility

Explain how your design can handle changes in scale and whether it would be easily to extend with new functionalities...






Create/Explain your diagram(s)

Try creating a class, flow, state and/or sequence diagram using the diagramming tool. Mermaid flow diagrams can be used to represent system use cases. You can ask the interviewer bot to create a starter diagram if unfamiliar with the tool. Briefly explain your diagrams if necessary...






Future improvements

Critically examine your design for any flaws or areas for future improvement...