Skip to content

Refactoring: Added code refactoring and optimisations #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,4 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/
1 change: 1 addition & 0 deletions Design_Parking_Lot/problem-statement.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ We welcome contributions to this project. If you are interested in contributing,
- Finalize the testing module.
- Rectify the output format.
- Enhance the command set by adding new commands.
- Add Thread safety in implementation.

If you are interested in contributing to any of these tasks, please feel free to reach out for more information.

142 changes: 97 additions & 45 deletions Design_Parking_Lot/src/commands/commands.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
from model.entrance_gate import EntranceGate
from model.exit_gate import ExitGate
from components.factory.parking_spot_manager_factory import ParkingSpotManagerFactory

class Commands:
def __init__(self, command, entrance_gate: EntranceGate, exit_gate: ExitGate, parking_spot_manager_factory):
self.command = command
self.entrance_gate = entrance_gate
self.exit_gate = exit_gate
self.parking_spot_manager_factory = parking_spot_manager_factory
self.command_handlers = {
'park_vehicle': self._handle_park_vehicle,
'free_parking_spot': self._handle_free_parking_spot,
'get_vehicles_by_color': self._handle_get_vehicles_by_color,
'get_vehicles_by_registration_no': self._handle_get_vehicles_by_registration_no,
'list_all_parked_vehicles': self._handle_list_all_parked_vehicles,
'add_parking_spot': self._handle_add_parking_spot,
'remove_parking_spot': self._handle_remove_parking_spot,
'generate_report': self._handle_generate_report,
'exit': self._handle_exit
}

"""
These commands are limited in scope and do not encompass all potential test cases.
Expand All @@ -17,47 +27,89 @@ def __init__(self, command, entrance_gate: EntranceGate, exit_gate: ExitGate, pa
Additionally, the output format may not be optimal and will be improved at a later time.
"""
def execute(self):
command = self.command.split(' ')
if command[0] == 'park_vehicle':
if len(command) != 4:
raise ValueError(f'Invalid command: {self.command}\nSuggested command format: park_vehicle <registration_no> <color> <vehicle_type>')
self.entrance_gate.park_vehicle(registration_no=command[1], color=command[2], vehicle_type=command[3])

elif command[0] == 'free_parking_spot':
if len(command) != 3:
raise ValueError(f'Invalid command: {self.command}\nSuggested command format: free_parking_spot <spot_number> <vehicle_type>')
parking_spot_manager = self.parking_spot_manager_factory.get_spot_manager(command[2])
parking_spot_manager.free_parking_spot(command[1])

elif command[0] == 'get_vehicles_by_color':
if len(command) != 2:
raise ValueError(f'Invalid command: {self.command}\nSuggested command format: get_vehicles_by_color <color>')
self.entrance_gate.get_vehicles_by_color(color=command[1])

elif command[0] == 'get_vehicles_by_registration_no':
if len(command) != 2:
raise ValueError(f'Invalid command: {self.command}\nSuggested command format: get_vehicles_by_registration_no <registration_no>')
self.entrance_gate.get_vehicle_by_registration_no(command[1])

elif command[0] == 'list_all_parked_vehicles':
if len(command) != 1:
raise ValueError(f'Invalid command: {self.command}\nSuggested command format: list_all_parking_vehicles')
self.entrance_gate.list_all_parked_vehicles()

elif command[0] == 'add_parking_spot':
if len(command) != 3:
raise ValueError(f'Invalid command: {self.command}\nSuggested command format: add_parking_spot <spot_no> <vehicle_type>')
parking_spot_manager = self.parking_spot_manager_factory.get_spot_manager(command[2])
parking_spot_manager.add_parking_spot(command[1])

elif command[0] == 'remove_parking_spot':
if len(command) != 3:
raise ValueError(f'Invalid command: {self.command}\nSuggested command format: remove_parking_spot <spot_no> <vehicle_type>')
parking_spot_manager = self.parking_spot_manager_factory.get_spot_manager(command[2])
parking_spot_manager.remove_parking_spot(command[1])

elif command[0] == 'exit':
exit()

else:
raise ValueError(f'Invalid command: {self.command}')
parts = self.command.strip().split(' ')
cmd = parts[0]

handler = self.command_handlers.get(cmd)
if not handler:
raise ValueError(f'Invalid command: {self.command}')

handler(parts)

# === Command Handlers ===

def _handle_park_vehicle(self, args):
if len(args) != 4:
raise ValueError(f'Invalid command: {" ".join(args)}\nSuggested format: park_vehicle <registration_no> <color> <vehicle_type>')
_, registration_no, color, vehicle_type = args
self.entrance_gate.park_vehicle(registration_no, color, vehicle_type)

def _handle_free_parking_spot(self, args):
if len(args) != 3:
raise ValueError(f'Invalid command: {" ".join(args)}\nSuggested format: free_parking_spot <spot_number> <vehicle_type>')
_, spot_number, vehicle_type = args
manager = self.parking_spot_manager_factory.get_spot_manager(vehicle_type)
manager.free_parking_spot(spot_number)

def _handle_get_vehicles_by_color(self, args):
if len(args) != 2:
raise ValueError(f'Invalid command: {" ".join(args)}\nSuggested format: get_vehicles_by_color <color>')
_, color = args
self.entrance_gate.get_vehicles_by_color(color)

def _handle_get_vehicles_by_registration_no(self, args):
if len(args) != 2:
raise ValueError(f'Invalid command: {" ".join(args)}\nSuggested format: get_vehicles_by_registration_no <registration_no>')
_, registration_no = args
self.entrance_gate.get_vehicle_by_registration_no(registration_no)

def _handle_list_all_parked_vehicles(self, args):
if len(args) != 1:
raise ValueError(f'Invalid command: {" ".join(args)}\nSuggested format: list_all_parked_vehicles')
self.entrance_gate.list_all_parked_vehicles()

def _handle_add_parking_spot(self, args):
if len(args) != 3:
raise ValueError(f'Invalid command: {" ".join(args)}\nSuggested format: add_parking_spot <spot_no> <vehicle_type>')
_, spot_no, vehicle_type = args
manager = self.parking_spot_manager_factory.get_spot_manager(vehicle_type)
manager.add_parking_spot(spot_no)

def _handle_remove_parking_spot(self, args):
if len(args) != 3:
raise ValueError(f'Invalid command: {" ".join(args)}\nSuggested format: remove_parking_spot <spot_no> <vehicle_type>')
_, spot_no, vehicle_type = args
manager = self.parking_spot_manager_factory.get_spot_manager(vehicle_type)
manager.remove_parking_spot(spot_no)

def _handle_generate_report(self, args):
report_data = self.entrance_gate.get_report_data()

print("=" * 20)
print("PARKING LOT REPORT")
print("=" * 20)

total_vehicles = 0

for vehicle_type, data in report_data.items():
print(f"\n Vehicle Type: {vehicle_type}")
print(f"Total Spots : {data['total_spots']}")
print(f"Available Spots : {data['available_spots']}")
print(f"Occupied Spots : {data['occupied_spots']}")
print("Parked Vehicles :")

if not data['vehicles']:
print("No vehicles parked.")
else:
for idx, v in enumerate(data['vehicles'], 1):
print(f" {idx}. RegNo: {v['registration_no']}, Color: {v['color']}, Spot: {v['spot_number']}")

total_vehicles += data['occupied_spots']

print("\n Summary:")
print(f"Total Parked Vehicles: {total_vehicles}")
print("=" * 20)

@staticmethod
def _handle_exit(args):
exit()
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
from abc import ABC, abstractmethod

from components.parking_spot_managers.two_wheeler_parking_spot_manager import TwoWheelerParkingSpotManager
from components.parking_spot_managers.two_wheeler_parking_spot_manager import TwoWheelerParkingSpotManager
from components.parking_spot_managers.four_wheeler_parking_spot_manager import FourWheelerParkingSpotManager
from components.parking_spot_managers.huv_parking_spot_manager import HUVParkingSpotManager

class ParkingSpotManagerFactory:
def __init__(self):
self.two_wheeler_parking_spot_manager = TwoWheelerParkingSpotManager()
self.four_wheeler_parking_spot_manager = FourWheelerParkingSpotManager()
self.huv_parking_spot_manager = HUVParkingSpotManager()

def get_spot_manager(self, vehicle_type):
if vehicle_type == "TwoWheeler":
return self.two_wheeler_parking_spot_manager
elif vehicle_type == "FourWheeler":
return self.four_wheeler_parking_spot_manager
elif vehicle_type == "HUV":
return self.huv_parking_spot_manager
else:
raise ValueError("Invalid vehicle_type: {}".format(vehicle_type))
self._registry = {
"TwoWheeler": TwoWheelerParkingSpotManager(),
"FourWheeler": FourWheelerParkingSpotManager(),
"HUV": HUVParkingSpotManager()
}

def get_spot_manager(self, vehicle_type: str):
manager = self._registry.get(vehicle_type)
if not manager:
raise ValueError(f"Invalid vehicle type: {vehicle_type}")
return manager
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
from abc import ABC, abstractmethod
from components.parking_spot_managers.parking_spot_manager import ParkingSpotManager
from model.parking_spot import FourWheelerParkingSpot

class FourWheelerParkingSpotManager(ParkingSpotManager):
def __init__(self):
self.parking_spot_list = {}
self.total_spots = 0
self.available_spots = 0

def add_parking_spot(self, spot_number):
parking_spot = FourWheelerParkingSpot(spot_number=spot_number)
try:
self.parking_spot_list.update({spot_number: parking_spot})
self.available_spots += 1
self.total_spots += 1
except:
raise KeyError(f"Parking Spot with this spot number ({spot_number}) already exists")
if spot_number in self.parking_spot_list:
raise KeyError(f"Spot {spot_number} already exists.")

self.parking_spot_list[spot_number] = FourWheelerParkingSpot(spot_number=spot_number)
self.total_spots += 1
self.available_spots += 1
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,11 @@
from model.parking_spot import HUVParkingSpot

class HUVParkingSpotManager(ParkingSpotManager):
def __init__(self):
self.parking_spot_list = {}
self.total_spots = 0
self.available_spots = 0

def add_parking_spot(self, spot_number):
parking_spot = HUVParkingSpot(spot_number=spot_number)
try:
self.parking_spot_list.update({spot_number: parking_spot})
self.available_spots += 1
self.total_spots += 1
except:
raise KeyError(f"Parking Spot with this spot number ({spot_number}) already exists")
if spot_number in self.parking_spot_list:
raise KeyError(f"Spot {spot_number} already exists.")

self.parking_spot_list[spot_number] = HUVParkingSpot(spot_number=spot_number)
self.total_spots += 1
self.available_spots += 1
Original file line number Diff line number Diff line change
@@ -1,68 +1,68 @@
from abc import ABC, abstractmethod
from model.parking_spot import ParkingSpot
from components.strategy.parking_strategy import ParkingStrategy
from model.vehicle import *
from components.strategy.parking_strategy import ParkingStrategyContext


class ParkingSpotManager(ABC):
def __init__(self):
self.parking_spot_list = {}
self.total_spots = 0
self.available_spots = 0

class ParkingSpotManager:
@abstractmethod
def add_parking_spot(self, spot_number):
pass

def remove_parking_spot(self, spot_number):
if spot_number in self.parking_spot_list:
if self.parking_spot_list[spot_number].is_empty == False:
raise ValueError(f"A vehicle is already parked in spot: {spot_number}")

print(f'Available parking spots: {list(self.parking_spot_list.keys())}')
if spot_number in self.parking_spot_list:
value = self.parking_spot_list.pop(spot_number, None)
self.available_spots -= 1
self.total_spots -= 1
print(f'After removing spot({spot_number}) from parking spots: {list(self.parking_spot_list.keys())}')
spot = self.parking_spot_list.get(spot_number)
if not spot:
raise KeyError(f"Parking spot {spot_number} does not exist.")

if not spot.is_empty:
raise ValueError(f"A vehicle is already parked in spot: {spot_number}")

self.parking_spot_list.pop(spot_number)
self.available_spots -= 1
self.total_spots -= 1
print(f'Removed spot {spot_number}. Remaining Spots: {list(self.parking_spot_list.keys())}')

def is_full(self):
if self.available_spots == 0:
return True
return False
return self.available_spots == 0

def find_parking_spot(self, strategy: str = "default"):
return ParkingStrategy().find_parking_spot(parking_spot_list=self.parking_spot_list, strategy=strategy)
return ParkingStrategyContext().find_parking_spot(parking_spot_list=self.parking_spot_list, strategy=strategy)

def park_vehicle(self, vehicle):
if self.is_full():
print("No Parking Spot is available to park this vehicle.")
return
parking_spot = self.find_parking_spot()
parking_spot.park_vehicle(vehicle)
self.available_spots -= 1
return parking_spot

def free_parking_spot(self, spot_number):
if spot_number in self.parking_spot_list:
parking_spot = self.parking_spot_list[spot_number]
parking_spot.remove_vehicle()
self.available_spots += 1
spot = self.parking_spot_list.get(spot_number)
if not spot:
print("This parking spot does not exist.")
return
if spot.is_empty:
print("Spot is already empty.")
return

print("This parking spot is not available")
spot.remove_vehicle()
self.available_spots += 1

def get_spots_by_vehicle_color(self, color):
parking_spots = [
self.parking_spot_list[key] for key in self.parking_spot_list.keys()
if (self.parking_spot_list[key].is_empty==False
and self.parking_spot_list[key].vehicle.color==color)
return [
spot for spot in self.parking_spot_list.values()
if not spot.is_empty and spot.vehicle.color == color
]
return parking_spots

def get_spot_by_vehicle_registration_no(self, registration_no):
parking_spot = [
self.parking_spot_list[key] for key in self.parking_spot_list.keys()
if (self.parking_spot_list[key].is_empty==False
and self.parking_spot_list[key].vehicle.registration_no==registration_no)
]
return None if (len(parking_spot)==0) else parking_spot[0]
for spot in self.parking_spot_list.values():
if not spot.is_empty and spot.vehicle.registration_no == registration_no:
return spot
return None

def list_all_parked_spots(self):
spots = [
self.parking_spot_list[key] for key in self.parking_spot_list.keys() if (self.parking_spot_list[key].is_empty==False)
]
return spots
return [spot for spot in self.parking_spot_list.values() if not spot.is_empty]
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,11 @@
from model.vehicle import *

class TwoWheelerParkingSpotManager(ParkingSpotManager):
def __init__(self):
self.parking_spot_list = {}
self.total_spots = 0
self.available_spots = 0

def add_parking_spot(self, spot_number):
parking_spot = TwoWheelerParkingSpot(spot_number=spot_number)
try:
self.parking_spot_list.update({spot_number: parking_spot})
self.available_spots += 1
self.total_spots += 1
except:
print(f"Parking Spot with this spot number ({spot_number}) already exists")
if spot_number in self.parking_spot_list:
raise KeyError(f"Spot {spot_number} already exists.")

self.parking_spot_list[spot_number] = TwoWheelerParkingSpot(spot_number=spot_number)
self.total_spots += 1
self.available_spots += 1
Loading