diff --git a/solutions/object_oriented_design/parking_lot/__init__.py b/solutions/object_oriented_design/parking_lot/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/solutions/object_oriented_design/parking_lot/parking_lot.ipynb b/solutions/object_oriented_design/parking_lot/parking_lot.ipynb new file mode 100644 index 00000000..4b37bf9d --- /dev/null +++ b/solutions/object_oriented_design/parking_lot/parking_lot.ipynb @@ -0,0 +1,204 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer-primer)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Design a parking lot" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Constraints and assumptions\n", + "\n", + "* What types of vehicles should we support?\n", + " * Motorcycle, Car, Bus\n", + "* Does each vehicle type take up a different amount of parking spots?\n", + " * Yes\n", + " * Motorcycle spot -> Motorcycle\n", + " * Compact spot -> Motorcycle, Car\n", + " * Large spot -> Motorcycle, Car\n", + " * Bus can park if we have 5 consecutive \"large\" spots\n", + "* Does the parking lot have multiple levels?\n", + " * Yes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting parking_lot.py\n" + ] + } + ], + "source": [ + "%%writefile parking_lot.py\n", + "from abc import ABCMeta, abstractmethod\n", + "\n", + "\n", + "class VehicleSize(Enum):\n", + "\n", + " MOTORCYCLE = 0\n", + " COMPACT = 1\n", + " LARGE = 2\n", + "\n", + "\n", + "class Vehicle(metaclass=ABCMeta):\n", + "\n", + " def __init__(self, vehicle_size, license_plate, spot_size):\n", + " self.vehicle_size = vehicle_size\n", + " self.license_plate = license_plate\n", + " self.spot_size\n", + " self.spots_taken = []\n", + "\n", + " def clear_spots(self):\n", + " for spot in self.spots_taken:\n", + " spot.remove_vehicle(self)\n", + " self.spots_taken = []\n", + "\n", + " def take_spot(self, spot):\n", + " self.spots_taken.append(spot)\n", + "\n", + " @abstractmethod\n", + " def can_fit_in_spot(self, spot):\n", + " pass\n", + "\n", + "\n", + "class Motorcycle(Vehicle):\n", + "\n", + " def __init__(self, license_plate):\n", + " super(Motorcycle, self).__init__(VehicleSize.MOTORCYCLE, license_plate, spot_size=1)\n", + "\n", + " def can_fit_in_spot(self, spot):\n", + " return True\n", + "\n", + "\n", + "class Car(Vehicle):\n", + "\n", + " def __init__(self, license_plate):\n", + " super(Car, self).__init__(VehicleSize.COMPACT, license_plate, spot_size=1)\n", + "\n", + " def can_fit_in_spot(self, spot):\n", + " return True if (spot.size == LARGE or spot.size == COMPACT) else False\n", + "\n", + "\n", + "class Bus(Vehicle):\n", + "\n", + " def __init__(self, license_plate):\n", + " super(Bus, self).__init__(VehicleSize.LARGE, license_plate, spot_size=5)\n", + "\n", + " def can_fit_in_spot(self, spot):\n", + " return True if spot.size == LARGE else False\n", + "\n", + "\n", + "class ParkingLot(object):\n", + "\n", + " def __init__(self, num_levels):\n", + " self.num_levels = num_levels\n", + " self.levels = []\n", + "\n", + " def park_vehicle(self, vehicle):\n", + " for level in levels:\n", + " if level.park_vehicle(vehicle):\n", + " return True\n", + " return False\n", + "\n", + "\n", + "class Level(object):\n", + "\n", + " SPOTS_PER_ROW = 10\n", + "\n", + " def __init__(self, floor, total_spots):\n", + " self.floor = floor\n", + " self.num_spots = total_spots\n", + " self.available_spots = 0\n", + " self.parking_spots = []\n", + "\n", + " def spot_freed(self):\n", + " self.available_spots += 1\n", + "\n", + " def park_vehicle(self, vehicle):\n", + " spot = self._find_available_spot(vehicle)\n", + " if spot is None:\n", + " return None\n", + " else:\n", + " spot.park_vehicle(vehicle)\n", + " return spot\n", + "\n", + " def _find_available_spot(self, vehicle):\n", + " \"\"\"Find an available spot where vehicle can fit, or return None\"\"\"\n", + " # ...\n", + "\n", + " def _park_starting_at_spot(self, spot, vehicle):\n", + " \"\"\"Occupy starting at spot.spot_number to vehicle.spot_size.\"\"\"\n", + " # ...\n", + "\n", + "\n", + "class ParkingSpot(object):\n", + "\n", + " def __init__(self, level, row, spot_number, spot_size, vehicle_size):\n", + " self.level = level\n", + " self.row = row\n", + " self.spot_number = spot_number\n", + " self.spot_size = spot_size\n", + " self.vehicle_size = vehicle_size\n", + " self.vehicle = None\n", + "\n", + " def is_available(self):\n", + " return True if self.vehicle is None else False\n", + "\n", + " def can_fit_vehicle(self, vehicle):\n", + " if self.vehicle is not None:\n", + " return False\n", + " return vehicle.can_fit_in_spot(self)\n", + "\n", + " def park_vehicle(self, vehicle): # ...\n", + " def remove_vehicle(self): # ..." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.4.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/solutions/object_oriented_design/parking_lot/parking_lot.py b/solutions/object_oriented_design/parking_lot/parking_lot.py new file mode 100644 index 00000000..c34c010b --- /dev/null +++ b/solutions/object_oriented_design/parking_lot/parking_lot.py @@ -0,0 +1,121 @@ +from abc import ABCMeta, abstractmethod + + +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 True if (spot.size == LARGE or spot.size == COMPACT) else False + + +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 True if spot.size == LARGE else False + + +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 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""" + # ... + + def _park_starting_at_spot(self, spot, vehicle): + """Occupy starting at spot.spot_number to vehicle.spot_size.""" + # ... + + +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): # ... + def remove_vehicle(self): # ... \ No newline at end of file