Skip to content

Instantly share code, notes, and snippets.

@gombosg
Created May 16, 2018 12:54
Show Gist options
  • Select an option

  • Save gombosg/aadcfb4b2539c2ecb4788e8d1e7f32bf to your computer and use it in GitHub Desktop.

Select an option

Save gombosg/aadcfb4b2539c2ecb4788e8d1e7f32bf to your computer and use it in GitHub Desktop.

Revisions

  1. gombosg created this gist May 16, 2018.
    237 changes: 237 additions & 0 deletions elevatorSaga.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,237 @@
    {
    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)
    }
    }