| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- eval({
- init: function(elevators, floors) {
- // Get elevator/building info
- const elevatorCount = elevators.length,
- floorCount = floors.length,
- bottomFloor = 0,
- topFloor = floorCount - 1;
-
- console.clear();
- ("Starting (" + floorCount + " floors; " + elevatorCount + " elevator" + (floorCount == 1) ? "s" : "" + ")...");
-
- // Direction constants
- const UP = 0,
- DOWN = 1,
- IDLE = 2;
-
- // Rest floor constants
- const LOW = 0,
- MED = 1,
- HIGH = 2;
-
- // Data structure for floor requests
- const requests = [new Set(), new Set()];
-
- // ----
- // Functions
- // ----
-
- // getClosestFloor takes a floor, a list of floors, an optional
- // list of ignored floors, and an optional direction. It
- // returns the closest floor from that list in the given
- // direction that is not part of the ignored floors list. Ties
- // are broken by even/oddness of the current floor.
- // TODO: fix direction shadowing/usage
- function getClosestFloor(currentFloor, floorList, ignoredFloors = new Set(), direction = IDLE) {
- const isEven = (currentFloor % 2 == 0);
-
- let closestFloor = currentFloor,
- distance = floorCount,
- newDistance = distance;
-
- floorList.forEach(function(floorNum) {
- const direction = getDirection(currentFloor, floorNum);
- newDistance = Math.abs(currentFloor - floorNum);
-
- if (newDistance < distance && newDistance > 0 && !(ignoredFloors.has(floorNum))) {
- closestFloor = floorNum;
- distance = newDistance;
- } else if (newDistance == distance && !(ignoredFloors.has(floorNum))) {
- if ((isEven && direction == UP) ||
- (!isEven && direction == DOWN) ||
- (direction == IDLE && Math.random() < 0.5)) {
- closestFloor = floorNum;
- }
- }
- });
-
- if (closestFloor != currentFloor) {
- return closestFloor;
- } else {
- throw new Error("No floor in selected direction");
- }
- }
-
- // getNextFloor chooses the best destination for an elevator
- // when given the index of the elevator, along with all
- // destinations, requests, and rest floors.
- function getNextFloor(elevators, elevatorIndex, destinations, requests, restFloors) {
- let elevator = elevators[elevatorIndex],
- floorNum = restFloors[MED];
-
- if (requests[UP].size == 0 && requests[DOWN].size == 0 && destinations.size == 0) {
- // No people; send to rest floor
- } else if (destinations.size == 0) {
- // No destinations; send to pick up passengers
- try {
- floorNum = getClosestFloor(elevator.currentFloor(), new Set([...requests[UP], ...requests[DOWN]]));
- } catch (e) {
- console.log("ERROR: Requests set was empty");
- }
- } else {
- // Prioritize dropping off current passengers
- try {
- floorNum = getClosestFloor(elevator.currentFloor(), destinations);
- } catch (e) {
- console.log("ERROR: Destinations set was empty");
- }
- }
-
- return floorNum;
- }
-
- // getClosestElevator takes a floor number and returns the
- // index of the closest elevator.
- function getClosestElevator(floorNum) {
- let closestElevator = 0,
- distance = floorCount,
- newDistance = distance;
-
- elevators.forEach(function(elevator, elevatorIndex) {
- newDistance = Math.abs(elevator.currentFloor() - floorNum);
- if (newDistance < distance) {
- distance = newDistance;
- closestElevator = elevatorIndex;
- }
- });
-
- //console.log("Closest is elevator[" + closestElevator + "]")
- return closestElevator;
- }
-
- // getDirection get the direction (up or down) that an elevator
- // will need to travel to get to a specified floor
- function getDirection(currentFloor, floorNum) {
- const distance = currentFloor - floorNum;
- let direction = IDLE;
-
- if (distance > 0 || currentFloor == topFloor) {
- direction = DOWN;
- } else if (distance < 0 || currentFloor == bottomFloor) {
- direction = UP;
- }
-
- return direction;
- }
-
- // setDirection changes the indicator lights on a specified
- // elevator to match the given direction.
- function setDirection(elevator, direction) {
- switch (direction) {
- case UP:
- elevator.goingUpIndicator(true);
- elevator.goingDownIndicator(false);
- break;
- case DOWN:
- elevator.goingUpIndicator(false);
- elevator.goingDownIndicator(true);
- break;
- default:
- elevator.goingUpIndicator(true);
- elevator.goingDownIndicator(true);
- }
- }
-
- // ----
- // Floors
- // ----
-
- floors.forEach(function(floor) {
- floor.on("up_button_pressed", function() {
- //console.log("> Up request on floor[" + floor.level + "]");
- requests[UP].add(floor.level);
- });
- floor.on("down_button_pressed", function() {
- //console.log("> Down request on floor[" + floor.level + "]");
- requests[DOWN].add(floor.level);
- });
- });
-
- // ----
- // Elevators
- // ----
-
- elevators.forEach(function(elevator, elevatorIndex) {
- // Elevator info and variables
- const restFloors = [
- elevatorIndex * Math.floor(floorCount / (elevatorCount + 1)),
- (elevatorIndex + 1) * Math.floor(floorCount / (elevatorCount + 1)),
- (elevatorIndex + 2) * Math.floor(floorCount / (elevatorCount + 1))
- ];
-
- let destinations = new Set(),
- nextFloor = restFloors[LOW];
-
- // Start
- setDirection(elevator, UP); // Starts on the ground floor, must be going up
- console.log("> Elevator[" + elevatorIndex + "] rest floors are " + restFloors[LOW] + ", " + restFloors[MED] + ", and " + restFloors[HIGH] + ". Starting at " + restFloors[LOW] + ".");
- elevator.goToFloor(nextFloor); // Nearest rest floor
-
- // Idle
- elevator.on("idle", function() {
- //console.log("> Elevator[" + elevatorIndex + "] is idle")
- nextFloor = getNextFloor(elevators, elevatorIndex, destinations, requests, restFloors);
- elevator.goToFloor(nextFloor);
- });
-
- // Passing
- elevator.on("passing_floor", function(floorNum, direction) {
- if (destinations.has(floorNum) ||
- (elevator.loadFactor() < 1 &&
- (elevator.destinationDirection() == "up" && requests[UP].has(floorNum)) ||
- (elevator.destinationDirection() == "down" && requests[DOWN].has(floorNum)))) {
- elevator.goToFloor(floorNum, true);
- }
- });
-
- // Buttons
- elevator.on("floor_button_pressed", function(floorNum) {
- //console.log("> Pressed floor[" + floorNum + "] on elevator[" + elevatorIndex + "]");
- destinations.add(floorNum);
- });
-
- // Stopped
- elevator.on("stopped_at_floor", function(floorNum) {
- //console.log("> elevator[" + elevatorIndex + "] stopped at floor[" + floorNum + "]");
- let isNext = (elevator.currentFloor() == nextFloor);
-
- destinations.delete(floorNum);
-
- if (isNext) {
- nextFloor = getNextFloor(elevators, elevatorIndex, destinations, requests, restFloors);
- setDirection(elevator, getDirection(elevator.currentFloor(), nextFloor));
- }
-
- if (elevator.goingUpIndicator() == true) {
- requests[UP].delete(floorNum);
- }
-
- if (elevator.goingDownIndicator() == true) {
- requests[DOWN].delete(floorNum);
- }
-
- if (isNext) {
- elevator.goToFloor(nextFloor);
- }
- });
- });
- },
-
- update: function(dt, elevators, floors) {}
- });
|