{ init: function(elevators, floors) { // ---------------------------- // INIT // ---------------------------- let myFloors = []; initFloors(); // ---------------------------- // ELEVATOR CALLBACKS // ---------------------------- for (var elevator of elevators) { elevator.on("floor_button_pressed", function (floorNum) { setIndicator(floorNum, this); startElevator(this, floorNum); }); elevator.on("stopped_at_floor", function (floorNum) { cleanDestQueue(this); // Remove this floor from destination queue removeFromDestQueue(floorNum, this); if (!this.destinationQueue.length) { // Idle elevator this.goingUpIndicator(true); this.goingDownIndicator(true); } else { // Set indicator for next destination setIndicator(this.destinationQueue[0], this); } this.goingUpIndicator() && resetFloor(floorNum, "up"); this.goingDownIndicator() && resetFloor(floorNum, "down"); }); elevator.on("passing_floor", function (floorNum, direction) { if ((direction === "up" && myFloors[floorNum].up && hasFreeSpaceFor(this, 2)) || (direction === "down" && myFloors[floorNum].down && hasFreeSpaceFor(this, 2)) || this.destinationQueue.includes(floorNum)) { removeFromDestQueue(floorNum, this); startElevator(this, floorNum, true); } }); elevator.on("idle", function () { console.log("Idle..."); // useLogic(this, lowestNotBookedFloor); // useLogic(this, closestNotBookedFloor); useLogic(this, longestWaitingFloor); }); } // ---------------------------- // CHALLENGE-SPECIFIC // ---------------------------- // FOR CHALLENGE 10 // elevators[0].on("idle", function() { // console.log("Idle..."); // useLogic(this, closestNotBookedFloor); // }); // elevators[1].on("idle", function() { // console.log("Idle..."); // useLogic(this, longestWaitingFloor); // }); // CHALLENGE 12 // elevators[0].on("idle", function () { // console.log("Idle..."); // useLogic(this, lowestNotBookedFloor); // }); // elevators[1].on("idle", function () { // console.log("Idle..."); // useLogic(this, highestNotBookedFloor); // }); // ---------------------------- // LOGIC // ---------------------------- function useLogic(elevator, fcn) { let currentFloor = elevator.currentFloor(); fcn(currentFloor) !== null && startElevator(elevator, fcn(currentFloor)); } function lowestNotBookedFloor() { let ind = myFloors.findIndex((_,floorNum) => calledNotBooked(floorNum)); console.log("Lowest not booked: ", ind); return ind === -1 ? null : ind; } function highestNotBookedFloor() { let ind = myFloors.reverse().findIndex((_,floorNum) => calledNotBooked(floorNum)); console.log("Lowest not booked: ", ind); return ind === -1 ? null : myFloors.length - 1 - ind; } function closestNotBookedFloor(currentFloor) { let limit = (arr, val) => { val = Math.min(val, arr.length - 1); val = Math.max(val, 0); return val; } let r = 1; while (r < floors.length) { let result; let plusFloorNum = limit(floors, currentFloor + r); let minusFloorNum = limit(floors, currentFloor - r); if (calledNotBooked(plusFloorNum)) result = plusFloorNum; if (calledNotBooked(minusFloorNum)) result = minusFloorNum; if (result) { console.log("Closest not booked: ", result); return result; } r++; } console.log("Closest not booked not found"); return null; } function longestWaitingFloor() { let now = new Date(); let waiting = myFloors.map(val => (val.up && val.down && Math.min(val.up, val.down)) || val.up || val.down || Infinity); let min = Math.min(...waiting); let idx = min === Infinity ? null : waiting.findIndex(val => val == Math.min(...waiting)); console.log("Longest waiting: ", idx); return idx === -1 ? null : idx; } // ---------------------------- // FLOOR CALLBACKS // ---------------------------- for (var floor of floors) { floor.on("up_button_pressed", function () { myFloors[this.floorNum()].up = Date.now(); console.log("up", this.floorNum(), myFloors) callIdleElevator(this.floorNum()); }); floor.on("down_button_pressed", function () { myFloors[this.floorNum()].down = Date.now(); console.log("down", this.floorNum(), myFloors) callIdleElevator(this.floorNum()); }); } // ---------------------------- // HELPER FUNCTIONS // ---------------------------- function isBooked(floorNum) { return myFloors[floorNum].bookedUp || myFloors[floorNum].bookedDown; } function calledNotBooked(floorNum) { return (myFloors[floorNum].up || myFloors[floorNum].down) && !isBooked(floorNum); } function initFloors() { for (let floorNum in floors) { myFloors[floorNum] = {}; resetFloor(floorNum, "up"); resetFloor(floorNum, "down"); } } function resetFloor(floorNum, direction) { if (direction === "up") { Object.assign(myFloors[floorNum], { up: null, bookedUp: false, }); } else if (direction === "down") { Object.assign(myFloors[floorNum], { down: null, bookedDown: false }); } } function hasFreeSpaceFor(elevator, passNum) { return elevator.loadFactor() <= (1 - passNum / elevator.maxPassengerCount()); } function startElevator(elevator, floorNum, priority = false) { console.log("Start: ", floorNum); if (!elevator.destinationQueue.includes(floorNum)) { if (myFloors[floorNum].up && elevator.goingUpIndicator()) myFloors[floorNum].bookedUp = true; if (myFloors[floorNum].down && elevator.goingDownIndicator()) myFloors[floorNum].bookedDown = true; elevator.goToFloor(floorNum, priority); } } function callIdleElevator(floorNum) { for (var idx in elevators) { let elevator = elevators[idx]; // if (elevator.destinationDirection() === "stopped" && !floors[floorNum].booked()) { console.log("Dest queue: ", elevator.destinationQueue); if (!elevator.destinationQueue.length && !isBooked(floorNum)) { console.log("Call idle to floor: ", floorNum, "elevator: ", idx); startElevator(elevator, floorNum); // Only call 1 elevator! return; // useLogic(elevator, longestWaitingFloor); } } } function cleanDestQueue(elevator) { elevator.destinationQueue = elevator.destinationQueue.filter(item => (myFloors[item].up || myFloors[item].down || elevator.getPressedFloors().includes(item))); } function removeFromDestQueue(floor, elevator) { elevator.destinationQueue = elevator.destinationQueue.filter(x => x != floor); } function setIndicator(floorNum, elevator) { var up = (floorNum > elevator.currentFloor()); elevator.goingUpIndicator(up); elevator.goingDownIndicator(!up); } }, update: function(dt, elevators, floors) { // NOT USED (yet) } }