Skip to content

Commit f68749e

Browse files
committed
parking lot class designs
1 parent f9cf00e commit f68749e

File tree

1 file changed

+339
-0
lines changed

1 file changed

+339
-0
lines changed

Diff for: system_design/parking_lot.py

+339
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,344 @@
5454
Add/Modify parking rate: To allow admin to add or modify the hourly parking rate.
5555
5656
"""
57+
from enum import Enum
5758

59+
class VehicleType(Enum):
60+
CAR, TRUCK, ELECTRIC, VAN, MOTORBIKE = 1, 2, 3, 4, 5
61+
62+
63+
class ParkingSpotType(Enum):
64+
HANDICAPPED, COMPACT, LARGE, MOTORBIKE, ELECTRIC = 1, 2, 3, 4, 5
65+
66+
67+
class AccountStatus(Enum):
68+
ACTIVE, BLOCKED, BANNED, COMPROMISED, ARCHIVED, UNKNOWN = 1, 2, 3, 4, 5, 6
69+
70+
71+
class ParkingTicketStatus(Enum):
72+
ACTIVE, PAID, LOST = 1, 2, 3
73+
74+
75+
class Address:
76+
def __init__(self, street, city, state, zip_code, country):
77+
self.__street_address = street
78+
self.__city = city
79+
self.__state = state
80+
self.__zip_code = zip_code
81+
self.__country = country
82+
83+
84+
class Person():
85+
def __init__(self, name, address, email, phone):
86+
self.__name = name
87+
self.__address = address
88+
self.__email = email
89+
self.__phone = phone
90+
91+
class Account:
92+
def __init__(self, user_name, password, person, status=AccountStatus.Active):
93+
self.__user_name = user_name
94+
self.__password = password
95+
self.__person = person
96+
self.__status = status
97+
98+
def reset_password(self):
99+
None
100+
101+
102+
class Admin(Account):
103+
def __init__(self, user_name, password, person, status=AccountStatus.Active):
104+
super().__init__(user_name, password, person, status)
105+
106+
def add_parking_floor(self, floor):
107+
None
108+
109+
def add_parking_spot(self, floor_name, spot):
110+
None
111+
112+
def add_parking_display_board(self, floor_name, display_board):
113+
None
114+
115+
def add_customer_info_panel(self, floor_name, info_panel):
116+
None
117+
118+
def add_entrance_panel(self, entrance_panel):
119+
None
120+
121+
def add_exit_panel(self, exit_panel):
122+
None
123+
124+
125+
class ParkingAttendant(Account):
126+
def __init__(self, user_name, password, person, status=AccountStatus.Active):
127+
super().__init__(user_name, password, person, status)
128+
129+
def process_ticket(self, ticket_number):
130+
None
131+
132+
from abc import ABC
133+
class ParkingSpot(ABC):
134+
def __init__(self, number, parking_spot_type):
135+
self.__number = number
136+
self.__free = True
137+
self.__vehicle = None
138+
self.__parking_spot_type = parking_spot_type
139+
140+
def is_free(self):
141+
return self.__free
142+
143+
def assign_vehicle(self, vehicle):
144+
self.__vehicle = vehicle
145+
free = False
146+
147+
def remove_vehicle(self):
148+
self.__vehicle = None
149+
free = True
150+
151+
152+
class HandicappedSpot(ParkingSpot):
153+
def __init__(self, number):
154+
super().__init__(number, ParkingSpotType.HANDICAPPED)
155+
156+
157+
class CompactSpot(ParkingSpot):
158+
def __init__(self, number):
159+
super().__init__(number, ParkingSpotType.COMPACT)
160+
161+
162+
class LargeSpot(ParkingSpot):
163+
def __init__(self, number):
164+
super().__init__(number, ParkingSpotType.LARGE)
165+
166+
167+
class MotorbikeSpot(ParkingSpot):
168+
def __init__(self, number):
169+
super().__init__(number, ParkingSpotType.MOTORBIKE)
170+
171+
172+
class ElectricSpot(ParkingSpot):
173+
def __init__(self, number):
174+
super().__init__(number, ParkingSpotType.ELECTRIC)
175+
176+
from abc import ABC, abstractmethod
177+
178+
class Vehicle(ABC):
179+
def __init__(self, license_number, vehicle_type, ticket=None):
180+
self.__license_number = license_number
181+
self.__type = vehicle_type
182+
self.__ticket = ticket
183+
184+
def assign_ticket(self, ticket):
185+
self.__ticket = ticket
186+
187+
188+
class Car(Vehicle):
189+
def __init__(self, license_number, ticket=None):
190+
super().__init__(license_number, VehicleType.CAR, ticket)
191+
192+
193+
class Van(Vehicle):
194+
def __init__(self, license_number, ticket=None):
195+
super().__init__(license_number, VehicleType.VAN, ticket)
196+
197+
198+
class Truck(Vehicle):
199+
def __init__(self, license_number, ticket=None):
200+
super().__init__(license_number, VehicleType.TRUCK, ticket)
201+
202+
203+
# Similarly we can define classes for Motorcycle and Electric vehicles
204+
205+
class ParkingFloor:
206+
def __init__(self, name):
207+
self.__name = name
208+
self.__handicapped_spots = {}
209+
self.__compact_spots = {}
210+
self.__large_spots = {}
211+
self.__motorbike_spots = {}
212+
self.__electric_spots = {}
213+
self.__info_portals = {}
214+
self.__display_board = ParkingDisplayBoard()
215+
216+
def add_parking_spot(self, spot):
217+
pass
218+
219+
def assign_vehicleToSpot(self, vehicle, spot):
220+
spot.assign_vehicle(vehicle)
221+
switcher = {
222+
ParkingSpotType.HANDICAPPED: self.update_display_board_for_handicapped(spot),
223+
ParkingSpotType.COMPACT: self.update_display_board_for_compact(spot),
224+
ParkingSpotType.LARGE: self.update_display_board_for_large(spot),
225+
ParkingSpotType.MOTORBIKE: self.update_display_board_for_motorbike(spot),
226+
ParkingSpotType.ELECTRIC: self.update_display_board_for_electric(spot),
227+
}
228+
switcher(spot.get_type(), 'Wrong parking spot type!')
229+
230+
def update_display_board_for_handicapped(self, spot):
231+
if self.__display_board.get_handicapped_free_spot().get_number() == spot.get_number():
232+
# find another free handicapped parking and assign to display_board
233+
for key in self.__handicapped_spots:
234+
if self.__handicapped_spots.get(key).is_free():
235+
self.__display_board.set_handicapped_free_spot(
236+
self.__handicapped_spots.get(key))
237+
238+
self.__display_board.show_empty_spot_number()
239+
240+
def update_display_board_for_compact(self, spot):
241+
if self.__display_board.get_compact_free_spot().get_number() == spot.get_number():
242+
# find another free compact parking and assign to display_board
243+
for key in self.__compact_spots.key_set():
244+
if self.__compact_spots.get(key).is_free():
245+
self.__display_board.set_compact_free_spot(
246+
self.__compact_spots.get(key))
247+
248+
self.__display_board.show_empty_spot_number()
249+
250+
def free_spot(self, spot):
251+
spot.remove_vehicle()
252+
253+
class ParkingDisplayBoard:
254+
def __init__(self, id):
255+
self.__id = id
256+
self.__handicapped_free_spot = None
257+
self.__compact_free_spot = None
258+
self.__large_free_spot = None
259+
self.__motorbike_free_spot = None
260+
self.__electric_free_spot = None
261+
262+
def show_empty_spot_number(self):
263+
message = ""
264+
if self.__handicapped_free_spot.is_free():
265+
message += "Free Handicapped: " + self.__handicapped_free_spot.get_number()
266+
else:
267+
message += "Handicapped is full"
268+
message += "\n"
269+
270+
if self.__compact_free_spot.is_free():
271+
message += "Free Compact: " + self.__compact_free_spot.get_number()
272+
else:
273+
message += "Compact is full"
274+
message += "\n"
275+
276+
if self.__large_free_spot.is_free():
277+
message += "Free Large: " + self.__large_free_spot.get_number()
278+
else:
279+
message += "Large is full"
280+
message += "\n"
281+
282+
if self.__motorbike_free_spot.is_free():
283+
message += "Free Motorbike: " + self.__motorbike_free_spot.get_number()
284+
else:
285+
message += "Motorbike is full"
286+
message += "\n"
287+
288+
if self.__electric_free_spot.is_free():
289+
message += "Free Electric: " + self.__electric_free_spot.get_number()
290+
else:
291+
message += "Electric is full"
292+
293+
print(message)
294+
295+
import threading
296+
297+
class ParkingLot:
298+
# singleton ParkingLot to ensure only one object of ParkingLot in the system,
299+
# all entrance panels will use this object to create new parking ticket: get_new_parking_ticket(),
300+
# similarly exit panels will also use this object to close parking tickets
301+
instance = None
302+
303+
class __OnlyOne:
304+
def __init__(self, name, address):
305+
# 1. initialize variables: read name, address and parking_rate from database
306+
# 2. initialize parking floors: read the parking floor map from database,
307+
# this map should tell how many parking spots are there on each floor. This
308+
# should also initialize max spot counts too.
309+
# 3. initialize parking spot counts by reading all active tickets from database
310+
# 4. initialize entrance and exit panels: read from database
311+
312+
self.__name = name
313+
self.__address = address
314+
# self.__parking_rate = ParkingRate()
315+
316+
self.__compact_spot_count = 0
317+
self.__large_spot_count = 0
318+
self.__motorbike_spot_count = 0
319+
self.__electric_spot_count = 0
320+
self.__max_compact_count = 0
321+
self.__max_large_count = 0
322+
self.__max_motorbike_count = 0
323+
self.__max_electric_count = 0
324+
325+
self.__entrance_panels = {}
326+
self.__exit_panels = {}
327+
self.__parking_floors = {}
328+
329+
# all active parking tickets, identified by their ticket_number
330+
self.__active_tickets = {}
331+
332+
self.__lock = threading.Lock()
333+
334+
def __init__(self, name, address):
335+
if not ParkingLot.instance:
336+
ParkingLot.instance = ParkingLot.__OnlyOne(name, address)
337+
else:
338+
ParkingLot.instance.__name = name
339+
ParkingLot.instance.__address = address
340+
341+
def __getattr__(self, name):
342+
return getattr(self.instance, name)
343+
344+
def get_new_parking_ticket(self, vehicle):
345+
if self.is_full(vehicle.get_type()):
346+
raise Exception('Parking full!')
347+
# synchronizing to allow multiple entrances panels to issue a new
348+
# parking ticket without interfering with each other
349+
self.__lock.acquire()
350+
ticket = "ParkingTicket()"
351+
vehicle.assign_ticket(ticket)
352+
ticket.save_in_DB()
353+
# if the ticket is successfully saved in the database, we can increment the parking spot count
354+
self.__increment_spot_count(vehicle.get_type())
355+
self.__active_tickets.put(ticket.get_ticket_number(), ticket)
356+
self.__lock.release()
357+
return ticket
358+
359+
def is_full(self, type):
360+
# trucks and vans can only be parked in LargeSpot
361+
if type == VehicleType.Truck or type == VehicleType.Van:
362+
return self.__large_spot_count >= self.__max_large_count
363+
364+
# motorbikes can only be parked at motorbike spots
365+
if type == VehicleType.Motorbike:
366+
return self.__motorbike_spot_count >= self.__max_motorbike_count
367+
368+
# cars can be parked at compact or large spots
369+
if type == VehicleType.Car:
370+
return (self.__compact_spot_count + self.__large_spot_count) >= (self.__max_compact_count + self.__max_large_count)
371+
372+
# electric car can be parked at compact, large or electric spots
373+
return (self.__compact_spot_count + self.__large_spot_count + self.__electric_spot_count) >= (self.__max_compact_count + self.__max_large_count
374+
+ self.__max_electric_count)
375+
376+
# increment the parking spot count based on the vehicle type
377+
def increment_spot_count(self, type):
378+
pass
379+
380+
def is_full(self):
381+
for key in self.__parking_floors:
382+
if not self.__parking_floors.get(key).is_full():
383+
return False
384+
return True
385+
386+
def add_parking_floor(self, floor):
387+
# store in database
388+
None
389+
390+
def add_entrance_panel(self, entrance_panel):
391+
# store in database
392+
None
393+
394+
def add_exit_panel(self, exit_panel):
395+
# store in database
396+
None
58397

0 commit comments

Comments
 (0)