| 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) {}
 - });
 
 
  |