Skip to content

Instantly share code, notes, and snippets.

@tjwudi
Last active January 14, 2016 16:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tjwudi/bc63370afd912a86e6cd to your computer and use it in GitHub Desktop.
Save tjwudi/bc63370afd912a86e6cd to your computer and use it in GitHub Desktop.
{
init: function(elevators, floors) {
function Tour (pickupRequest, direction, startFloorNum) {
this.pickingUp = !!pickupRequest;
this.pickupRequest = pickupRequest;
this.direction = direction; // either 'up' or 'down'
this.startFloorNum = startFloorNum;
}
function Controller (elevator) {
var currentController = this;
this.elevator = elevator;
this.tour = null;
this.elevator.on('stopped_at_floor', function (floorNum) {
console.log('stopped at floor: ', floorNum);
console.log('when stopped, destinationQueue: ', currentController.elevator.destinationQueue);
if (currentController.tour
&& currentController.elevator.destinationQueue.length === 0
&& floorNum != currentController.tour.startFloorNum) {
currentController.finishTour();
}
});
this.elevator.on('idle', function () {
console.log('idle');
if (currentController.tour) {
currentController.finishTour();
}
});
this.elevator.on('floor_button_pressed', function (floorNum) {
currentController.goToFloor(floorNum);
});
}
Controller.prototype.canAcceptExternalRequest = function (request) {
return !(this.tour
&& this.tour.direction === 'up'
&& this.elevator.currentFloor() >= request.floorNum)
&& !(this.tour
&& this.tour.direction === 'down'
&& this.elevator.currentFloor() <= request.floorNum)
&& !(this.tour
&& this.tour.direction === 'up'
&& request.direction === 'down')
&& !(this.tour
&& this.tour.direction === 'down'
&& request.direction === 'up')
&& !(this.elevator.loadFactor() === 1.0)
&& !(this.tour
&& this.elevator.currentFloor === request.floorNum);
};
Controller.prototype.goToFloor = function (floorNum) {
this.elevator.goToFloor(floorNum);
this.rearrangeDestinations();
};
Controller.prototype.rearrangeDestinations = function () {
var currentController = this;
if (currentController.tour) {
this.elevator.destinationQueue.sort(
function (lhs, rhs) {
return currentController.tour.direction === 'up' ? lhs > rhs : lhs < rhs;
});
this.elevator.checkDestinationQueue();
}
};
Controller.prototype.acceptExternalRequest = function (request) {
var currentFloor = this.elevator.currentFloor();
if (this.tour) {
// The request is going to join the tour
this.goToFloor(request.floorNum);
}
else {
// The request is going to start a new tour
if (request.floorNum !== currentFloor) {
console.log('start a new pick up tour');
this.startTour(new Tour(request,
request.floorNum > currentFloor ? 'up' : 'down',
currentFloor));
this.goToFloor(request.floorNum);
}
else {
console.log('start a new tour');
this.startTour(new Tour(null, request.direction, currentFloor));
}
}
};
Controller.prototype.startTour = function (tour) {
console.log('tour start', tour);
this.tour = tour;
this.elevator.goingUpIndicator(tour.direction === 'up');
this.elevator.goingDownIndicator(tour.direction === 'down');
}
Controller.prototype.finishTour = function () {
var currentController = this;
console.log('tour finished');
if (this.tour.pickingUp) {
setTimeout(function () {
currentController.startTour(new Tour(null,
currentController.tour.pickupRequest.direction,
currentController.elevator.currentFloor()));
currentController.goToFloor(
currentController.elevator.currentFloor())
}, 0);
}
else {
this.elevator.goingUpIndicator(false);
this.elevator.goingDownIndicator(false);
this.tour = null;
}
};
Controller.prototype.evaluatePriorityIndex = function (request) {
return - 1 * this.elevator.loadFactor() -
Math.abs(this.elevator.currentFloor() - request.floorNum);
};
function ExternalRequest (floorNum, direction) {
this.floorNum = floorNum;
this.direction = direction;
}
function Scheduler (elevators, floors) {
var currentScheduler = this;
this.controllers = elevators.map(function (elevator) {
return new Controller(elevator);
});
this.requestPoll = [];
floors.forEach(function (floor) {
floor.on('up_button_pressed', function () {
console.log('up_button_pressed');
setTimeout(function () {
currentScheduler.dispatchExternalRequest(new ExternalRequest(
floor.floorNum(), 'up'));
}, 500);
});
floor.on('down_button_pressed', function () {
console.log('down_button_pressed');
setTimeout(function () {
currentScheduler.dispatchExternalRequest(new ExternalRequest(
floor.floorNum(), 'down'))
}, 500);
});
});
setTimeout(function drainPolledRequests() {
var requestPollClone = currentScheduler.requestPoll.map(function (_) {
return _;
});
currentScheduler.requestPoll = [];
while (requestPollClone.length > 0) {
currentScheduler.dispatchExternalRequest(
requestPollClone.pop());
}
// I just don't like setInterval
setTimeout(drainPolledRequests, 13);
}, 13);
}
Scheduler.prototype.dispatchExternalRequest = function (request) {
var viableControllers = this.controllers.filter(function (controller) {
return controller.canAcceptExternalRequest(request);
}).map(function (controller) {
return {
// The higher the priorityIndex the higher the priority
priorityIndex: controller.evaluatePriorityIndex(request),
controller: controller
};
}).sort(function (lhs, rhs) {
return lhs.priorityIndex > rhs.priorityIndex; // descending order
}).map(function (_) {
return _.controller;
});
if (!viableControllers.length) {
this.pollExternalRequest(request);
return;
}
var chosenController = viableControllers[0];
chosenController.acceptExternalRequest(request);
};
Scheduler.prototype.pollExternalRequest = function (request) {
this.requestPoll.push(request);
};
new Scheduler(elevators, floors);
},
update: function(dt, elevators, floors) {
// We normally don't need to do anything here
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment