Requirements
Parking lot that contains multiple floor and spots suitable for different size of vehicles.
Calculate fees of a vehicle using a spot depending on parking duration
-> minutes -> UNIX minutes
Find a suitable spot for a vehicle to fit, preferring an exact size spot
Questions:
Is there a time limit of a vehicle using a spot?
Define Core Objects
Enum SpotSize:
SMALL
MEDIUM
LARGE
// vehicle
// find spot and get parking ticket
// vehicle leaving and paying ticket
FeeCalculator:
MinuteFee : Map
PenaltyFee: Map
TimeLimit: int
int VehicleFee(parkingTicket)
Parking Lot:
feeCalculator: FeeCalculator
floors: Floor[]
parkingTicket FindSpotForVehicle(vehicle)
int VehicleLeaving(parkingTicket, date: Minutes UNIX)
Floor:
floorNumber
spots: Spots[]
Spot:
Size: SpotSize
Available: Bool
ParkingTicket:
EnteringDate: Int
Spot: Spot
Vehicle: Vehicle
Vehicle:
Plate: string
size: SpotSize
parkingTicket
- Motorbike:
SpotSize = SMALL
- Car:
- SpotSize = MEDIUM
- Truck:
- SpotSize = LARGE
Analyze Relationships
The inreractions are already defined
Establish Hierarchy
vehicle have already define hierarchy
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 enum import Enum
from typing import List, Dict, Tuple, Optional
from threading import Lock
from abc import ABC, abstractmethod
class SpotSize(Enum):
SMALL = 1
MEDIUM = 2
LARGE = 3
class Floor:
def init(self, floorNumber: int, spotsAvailable: Dict[SpotSize, int] ):
self.floorNumber = floorNumber
self.spotsAvailable = spotsAvailable
def isSpotForVehicleSizeAvailable(self, vehicleSize: SpotSize) -> bool:
return self.spotsAvailable[vehicleSize] > 0
def useSpot(self, vehicleSize: SpotSize) -> bool:
self.spotsAvailable[vehicleSize] -= 1
def freeSpot(self, vehicleSize: SpotSize) -> bool:
self.spotsAvailable[vehicleSize] += 1
class ParkingTicket:
def init(self, enteringDate: int, spotSize: SpotSize, spotFloor: Floor):
self.enteringDate = enteringDate
self.spotSize = spotSize
self.spotFloor = spotFloor
class Vehicle:
def init(self, plate: str, size: SpotSize):
self.plate = plate
self.size = size
self.parkingTicket = None
class Motorbike(Vehicle):
def init(self, plate: str):
super().init(plate, SpotSize.SMALL)
class Car(Vehicle):
def init(self, plate: str):
super().init(plate, SpotSize.MEDIUM)
class Truck(Vehicle):
def init(self, plate: str):
super().init(plate, SpotSize.LARGE)
def vehicleFactory(plate: str, vehicleType: str) -> Vehicle:
if(vehicleType == "motorbike"):
return Motorbike(plate)
if(vehicleType == "car"):
return Car(plate)
if(vehicleType == "truck"):
return Truck(plate)
class FeeCalculator:
def init(self, timeLimit: int, minuteFee: Dict[SpotSize, int], penaltyFee: Dict[SpotSize, int]):
self.timeLimit = timeLimit
self.minuteFee = minuteFee
self.penaltyFee = penaltyFee
def vehicleFee(self, vehicle: Vehicle, leavingDate: int) -> int:
parkingTicket = vehicle.parkingTicket
minutesUsingSpot = leavingDate - parkingTicket.enteringDate
fee = minutesUsingSpot * self.minuteFee[vehicle.size]
if minutesUsingSpot > self.timeLimit:
fee += self.penaltyFee[vehicle.size]
return fee
class ParkingLot:
_instance = None
def new(cls, feeCalculator: FeeCalculator, floors: List[Floor]):
if cls._instance is None:
cls._instance = super().new(cls)
cls._instance.feeCaclulator = feeCalculator
cls._instance.floors = floors
cls._instance.parkingLock = Lock()
return cls._instance
def enterParkingSlot(self, vehicle: Vehicle, enteringDate: int) -> ParkingTicket:
self.parkingLock.acquire()
spotSize, spotFloor = self.findSpotForVehicle(vehicle.size)
self.parkingLock.release()
if not spotSize:
return None
parkingTicket = ParkingTicket(enteringDate, spotSize, spotFloor)
vehicle.parkingTicket = parkingTicket
return parkingTicket
def leaveParkingSlot(self, vehicle: Vehicle, leavingDate: int) -> Optional[int]:
if not vehicle.parkingTicket:
print("No spot found for vehicle", vehicle.plate)
return None
parkingTicket = vehicle.parkingTicket
parkingTicket.spotFloor.freeSpot(parkingTicket.spotSize)
return self.feeCaclulator.vehicleFee(vehicle, leavingDate)
def findSpotForVehicle(self, vehicleSize: SpotSize) -> Tuple[Optional[bool], Optional[Floor]]:
spotSizeAvailable = None
spotFloor = None
for spotSize in SpotSize:
if spotSize.value < vehicleSize.value:
continue
if spotSizeAvailable != None:
break
for floor in self.floors:
if floor.isSpotForVehicleSizeAvailable(spotSize):
spotSizeAvailable = spotSize
spotFloor = floor
break
if spotSizeAvailable == None:
return None, None
print("Found spot with size", spotSize, "in floor", spotFloor.floorNumber)
spotFloor.useSpot(spotSizeAvailable)
return spotSizeAvailable, spotFloor
if name == "main":
car = vehicleFactory("abc123", "car")
car2 = vehicleFactory("abc124", "car")
car3 = vehicleFactory("abc125", "car")
check if no spot found
floor1 = Floor(1, {
SpotSize.MEDIUM: 1,
SpotSize.LARGE: 1
})
floors = [floor1]
minuteFee = {SpotSize.SMALL: 1, SpotSize.MEDIUM: 2, SpotSize.LARGE: 3}
penaltyFee = {SpotSize.SMALL: 10, SpotSize.MEDIUM: 20, SpotSize.LARGE: 30}
feeCalculator =FeeCalculator(120, minuteFee, penaltyFee)
parkingLot = ParkingLot(feeCalculator, floors)
ticket1 = parkingLot.enterParkingSlot(car, 1)
print(ticket1.spotSize)
ticket2 = parkingLot.enterParkingSlot(car2, 2)
print(ticket2.spotSize)
ticket3 = parkingLot.enterParkingSlot(car3, 3)
print(ticket3)
print(parkingLot.leaveParkingSlot(car, 10))
print(parkingLot.leaveParkingSlot(car2, 12))
print(parkingLot.leaveParkingSlot(car3, 12))
Adhere to SOLID Guidelines
Yes
Consider Scalability and Flexibility
It is flexible, since accepts more types of cars with sizes defined already
It is scalable since each parking slot can handle its own parking spots inside its class
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
Add parking SPot class
Add location of pot, and heap that orders spots in a floor depending on location
Add lock so only one car enters and uses a spot at the time