Home   dsa  

How to design parking lot system

Let's design a Parking Lot System in Node.js. We'll break it down into the main components and provide an implementation for each.

Requirements Recap

Functional Requirements

  1. Parking Spots Management:
    • Different types of parking spots (e.g., regular, compact, handicapped, electric).
  2. Vehicle Management:
    • Vehicles can be parked and removed.
    • Different types of vehicles (e.g., motorcycles, cars, trucks).
  3. Parking Fee Calculation:
    • Calculate parking fees based on time and type of vehicle.
  4. Entry/Exit Points:
    • Handle vehicle entry and exit.
  5. Availability Check:
    • Check for available parking spots.

Non-Functional Requirements

  1. Scalability:
    • Handle a large number of vehicles and parking spots.
  2. Reliability:
    • Ensure the system is always available.
  3. Performance:
    • Efficiently handle the entry and exit of vehicles.

Node.js Implementation

We'll use Express for the web framework and a simple in-memory data structure to manage the parking lot state.

1. Project Setup

First, set up a new Node.js project:

mkdir parking-lot-system
cd parking-lot-system
npm init -y
npm install express

2. Basic Structure

Create the following files:

3. Models (models.js)

Define the classes for ParkingLot, ParkingSpot, Vehicle, and Ticket:

// models.js
const { v4: uuidv4 } = require('uuid');

class ParkingSpot {
  constructor(id, spotType) {
    this.id = id;
    this.spotType = spotType;
    this.isAvailable = true;
    this.vehicle = null;
  }

  assignVehicle(vehicle) {
    this.isAvailable = false;
    this.vehicle = vehicle;
  }

  removeVehicle() {
    this.isAvailable = true;
    this.vehicle = null;
  }
}

class Vehicle {
  constructor(licensePlate, vehicleType) {
    this.licensePlate = licensePlate;
    this.vehicleType = vehicleType;
  }
}

class Ticket {
  constructor(vehicle, entryTime) {
    this.id = uuidv4();
    this.vehicle = vehicle;
    this.entryTime = entryTime;
    this.exitTime = null;
    this.fee = 0;
  }

  setExitTime(exitTime) {
    this.exitTime = exitTime;
    this.calculateFee();
  }

  calculateFee() {
    const parkedHours = Math.ceil((this.exitTime - this.entryTime) / (1000 * 60 * 60));
    this.fee = parkedHours * 10; // Example fee rate: $10 per hour
  }
}

class ParkingLot {
  constructor() {
    this.spots = [];
    this.activeTickets = new Map();
  }

  createParkingSpots(numSpots) {
    for (let i = 0; i < numSpots; i++) {
      let spotType;
      if (i % 4 === 0) {
        spotType = 'REGULAR';
      } else if (i % 4 === 1) {
        spotType = 'COMPACT';
      } else if (i % 4 === 2) {
        spotType = 'HANDICAPPED';
      } else {
        spotType = 'ELECTRIC';
      }
      this.spots.push(new ParkingSpot(i, spotType));
    }
  }

  findAvailableSpot(vehicleType) {
    return this.spots.find(spot => spot.isAvailable && (
      (vehicleType === 'MOTORCYCLE' && ['REGULAR', 'COMPACT', 'HANDICAPPED', 'ELECTRIC'].includes(spot.spotType)) ||
      (vehicleType === 'CAR' && ['REGULAR', 'HANDICAPPED', 'ELECTRIC'].includes(spot.spotType)) ||
      (vehicleType === 'TRUCK' && spot.spotType === 'REGULAR')
    ));
  }

  parkVehicle(vehicle) {
    const spot = this.findAvailableSpot(vehicle.vehicleType);
    if (spot) {
      spot.assignVehicle(vehicle);
      const ticket = new Ticket(vehicle, new Date());
      this.activeTickets.set(vehicle.licensePlate, ticket);
      return ticket;
    }
    return null;
  }

  removeVehicle(licensePlate) {
    const ticket = this.activeTickets.get(licensePlate);
    if (ticket) {
      const spot = this.spots.find(spot => spot.vehicle && spot.vehicle.licensePlate === licensePlate);
      spot.removeVehicle();
      ticket.setExitTime(new Date());
      this.activeTickets.delete(licensePlate);
      return ticket;
    }
    return null;
  }
}

module.exports = { ParkingLot, Vehicle };

4. Routes (routes.js)

Define the routes for parking and removing vehicles:

// routes.js
const express = require('express');
const router = express.Router();
const { ParkingLot, Vehicle } = require('./models');

const parkingLot = new ParkingLot();
parkingLot.createParkingSpots(100);

router.post('/park', (req, res) => {
  const { licensePlate, vehicleType } = req.body;
  const vehicle = new Vehicle(licensePlate, vehicleType);
  const ticket = parkingLot.parkVehicle(vehicle);
  if (ticket) {
    res.json(ticket);
  } else {
    res.status(400).json({ error: 'No available spot for the vehicle' });
  }
});

router.post('/remove', (req, res) => {
  const { licensePlate } = req.body;
  const ticket = parkingLot.removeVehicle(licensePlate);
  if (ticket) {
    res.json(ticket);
  } else {
    res.status(400).json({ error: 'Ticket not found' });
  }
});

module.exports = router;

5. Main Application (app.js)

Set up the Express server and include the routes:

// app.js
const express = require('express');
const bodyParser = require('body-parser');
const parkingRoutes = require('./routes');

const app = express();
const PORT = 3000;

app.use(bodyParser.json());
app.use('/parking', parkingRoutes);

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

Running the Application

Start the application:

node app.js

Testing the API

You can use a tool like Postman or curl to test the endpoints:

Park a Vehicle

curl -X POST http://localhost:3000/parking/park -H "Content-Type: application/json" -d '{"licensePlate": "ABC123", "vehicleType": "CAR"}'

Remove a Vehicle

curl -X POST http://localhost:3000/parking/remove -H "Content-Type: application/json" -d '{"licensePlate": "ABC123"}'

Considerations

  1. Persistence:

    • For a production system, use a database to persist data instead of in-memory storage.
  2. Concurrency:

    • Use proper locking mechanisms if multiple instances are running to avoid race conditions.
  3. Scalability:

    • Implement a distributed system with microservices if the parking lot needs to scale.

This basic implementation demonstrates the core functionalities of a Parking Lot System in Node.js, with extensibility for more complex features as needed.

Published on: Jul 10, 2024, 12:04 AM  
 

Comments

Add your comment