CCCPaste

Elevator System LLD

enum ElevatorState {
   MOVING_UP, MOVING_DOWN, IDLE
}

enum Direction {
   UP, DOWN
}

class Request {
   private int sourceFloor;
   private Direction direction;

   public Request(int sourceFloor, Direction direction) {
       this.sourceFloor = sourceFloor;
       this.direction = direction;
   }

   public int getSourceFloor() { return sourceFloor; }
   public Direction getDirection() { return direction; }
}

class Elevator {
   private int currentFloor;
   private ElevatorState state;
   private TreeSet upRequests = new TreeSet<>();
   private TreeSet downRequests = new TreeSet<>(Comparator.reverseOrder());

   public Elevator() {
       this.currentFloor = 0;
       this.state = ElevatorState.IDLE;
   }

   public void addRequest(int floor) {
       if (floor > currentFloor) {
           upRequests.add(floor);
       } else if (floor < currentFloor) {
           downRequests.add(floor);
       }
   }

   public void addInternalRequest(int destinationFloor) {
       addRequest(destinationFloor);
   }

   /**
    * Simulates the elevator's state transition.
    *
    * IDLE:
    *   - Move to MOVING_UP if upRequests exist
    *   - Move to MOVING_DOWN if no upRequests but downRequests exist
    *
    * MOVING_UP:
    *   - Increment currentFloor
    *   - Stop if currentFloor is in upRequests, remove it, allow destination input
    *   - If upRequests are empty, switch to MOVING_DOWN if downRequests exist
    *   - Else, return to IDLE
    *
    * MOVING_DOWN:
    *   - Decrement currentFloor
    *   - Stop if currentFloor is in downRequests, remove it, allow destination input
    *   - If downRequests are empty, switch to MOVING_UP if upRequests exist
    *   - Else, return to IDLE
    */
   public void step() {
       if (state == ElevatorState.IDLE) {
           if (!upRequests.isEmpty()) {
               state = ElevatorState.MOVING_UP;
           } else if (!downRequests.isEmpty()) {
               state = ElevatorState.MOVING_DOWN;
           } else {
               return;
           }
       }

       if (state == ElevatorState.MOVING_UP) {
           currentFloor++;
           System.out.println("Elevator moving up to floor: " + currentFloor);
           if (upRequests.remove(currentFloor)) {
               System.out.println("Stopping at floor: " + currentFloor);
               int destination = simulateUserDestination();
               addInternalRequest(destination);
           }

           if (upRequests.isEmpty() && !downRequests.isEmpty()) {
               state = ElevatorState.MOVING_DOWN;
           } else if (upRequests.isEmpty()) {
               state = ElevatorState.IDLE;
           }

       } else if (state == ElevatorState.MOVING_DOWN) {
           currentFloor--;
           System.out.println("Elevator moving down to floor: " + currentFloor);
           if (downRequests.remove(currentFloor)) {
               System.out.println("Stopping at floor: " + currentFloor);
               int destination = simulateUserDestination();
               addInternalRequest(destination);
           }

           if (downRequests.isEmpty() && !upRequests.isEmpty()) {
               state = ElevatorState.MOVING_UP;
           } else if (downRequests.isEmpty()) {
               state = ElevatorState.IDLE;
           }
       }
   }

   private int simulateUserDestination() {
       Random random = new Random();
       int destination = random.nextInt(10);
       while (destination == currentFloor) {
           destination = random.nextInt(10);
       }
       System.out.println("User entered destination floor: " + destination);
       return destination;
   }

   public int getCurrentFloor() { return currentFloor; }
   public ElevatorState getState() { return state; }
}

class ElevatorController {
   private List elevators;

   public ElevatorController(int numberOfElevators) {
       elevators = new ArrayList<>();
       for (int i = 0; i < numberOfElevators; i++) {
           elevators.add(new Elevator());
       }
   }

   public void handleExternalRequest(Request request) {
       Elevator bestElevator = findBestElevator(request.getSourceFloor(), request.getDirection());
       bestElevator.addRequest(request.getSourceFloor());
   }

   /**
    * Selects the best elevator for the request.
    * Priority is given to elevators that:
    * - Are IDLE
    * - Are moving in the same direction as the request and heading towards the request floor
    * - Otherwise, selects the closest elevator by default
    */
   private Elevator findBestElevator(int floor, Direction direction) {
       Elevator selected = null;
       int minDistance = Integer.MAX_VALUE;

       for (Elevator elevator : elevators) {
           int distance = Math.abs(elevator.getCurrentFloor() - floor);
           boolean suitable = false;

           if (elevator.getState() == ElevatorState.IDLE) {
               suitable = true;
           } else if (elevator.getState() == ElevatorState.MOVING_UP && direction == Direction.UP && elevator.getCurrentFloor() <= floor) {
               suitable = true;
           } else if (elevator.getState() == ElevatorState.MOVING_DOWN && direction == Direction.DOWN && elevator.getCurrentFloor() >= floor) {
               suitable = true;
           }

           if (suitable && distance < minDistance) {
               minDistance = distance;
               selected = elevator;
           }
       }

       return selected != null ? selected : elevators.get(0);
   }

   public void stepAllElevators() {
       for (Elevator elevator : elevators) {
           elevator.step();
           System.out.println("Elevator at floor: " + elevator.getCurrentFloor() + " State: " + elevator.getState());
       }
   }
}

/**
* ElevatorSystemDemo demonstrates the elevator system by initializing a controller,
* submitting some example external requests, and simulating the elevator steps over time.
*/
public class ElevatorSystemDemo {
   public static void main(String[] args) throws InterruptedException {
       ElevatorController controller = new ElevatorController(3);

       controller.handleExternalRequest(new Request(5, Direction.UP));
       controller.handleExternalRequest(new Request(2, Direction.DOWN));

       for (int i = 0; i < 15; i++) {
           System.out.println("Step " + i);
           controller.stepAllElevators();
           Thread.sleep(1000);
       }
   }
}