Last active
January 13, 2016 07:52
-
-
Save cconger/9546dde605b9616858bb to your computer and use it in GitHub Desktop.
A solution to Elevator Saga (http://play.elevatorsaga.com/)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
DIRECTION: { | |
UP: 'up', | |
DOWN: 'down' | |
}, | |
pendingFloors: [], | |
idleVators: [], | |
printPendingState: function() { | |
var upFloors = []; | |
var downFloors = []; | |
this.pendingFloors.forEach((floor, idx) => { | |
if (floor.up) { upFloors.push(idx); } | |
if (floor.down) { downFloors.push(idx); } | |
}); | |
console.log("Floors needing an up elevator :", upFloors); | |
console.log("Floors needing a down elevator :", downFloors); | |
}, | |
init: function(elevators, floors) { | |
elevators.forEach((elevator, elevatorId) => { | |
elevator.stopRequest = new Array(floors.length); | |
var setDirection = (direction) => { | |
elevator.direction = direction; | |
if (direction === this.DIRECTION.UP) { | |
elevator.goingUpIndicator(true); | |
elevator.goingDownIndicator(false); | |
return; | |
} | |
if (direction === this.DIRECTION.DOWN) { | |
elevator.goingUpIndicator(false); | |
elevator.goingDownIndicator(true); | |
return; | |
} | |
elevator.goingUpIndicator(true); | |
elevator.goingDownIndicator(true); | |
}; | |
var anyRequests = () => { | |
return this.pendingFloors.reduce((prev, current) => { | |
return prev || current.down || current.up; | |
}, false); | |
}; | |
var removeFloorFromQueue = (floorNum) => { | |
elevator.destinationQueue = elevator.destinationQueue.filter((floor) => { | |
return floor !== floorNum; | |
}); | |
}; | |
var highestDownFloor = () => { | |
for (var i = floors.length - 1; i >= 0; i--) { | |
if (this.pendingFloors[i].down) { | |
return i; | |
} | |
} | |
}; | |
var lowestUpFloor = () => { | |
for (var i = 0; i < floors.length; i++) { | |
if (this.pendingFloors[i].up) { | |
return i; | |
} | |
} | |
}; | |
setDirection(this.DIRECTION.UP); | |
var self = this; | |
elevator.initialize = function() { | |
//console.log(this.currentFloor(), self.pendingFloors); | |
var highDown = highestDownFloor(); | |
var lowUp = lowestUpFloor(); | |
var highDistance = Math.abs(highDown - this.currentFloor()); | |
var lowDistance = Math.abs(lowUp - this.currentFloor()); | |
console.log({ | |
highDown, | |
lowUp, | |
highDistance, | |
lowDistance | |
}); | |
//TODO: Improvment, have the elevator take people down when its resetting to the bottom | |
// or take people up when its resetting to the top. | |
if (lowUp === undefined && highDown !== undefined || (highDown !== undefined && lowUp !== undefined && highDistance < lowDistance)) { | |
console.log("ELEVATOR", elevatorId, "resetting (down) to ", highDown); | |
setDirection(self.DIRECTION.DOWN); | |
this.goToFloor(highDown); | |
} else if (lowUp !== undefined) { | |
console.log("ELEVATOR", elevatorId, "resetting (up) to ", lowUp); | |
setDirection(self.DIRECTION.UP); | |
this.goToFloor(lowUp); | |
} else { | |
self.idleVators.push(this); | |
} | |
}; | |
elevator.on('idle', () => { | |
// I'm Idle | |
console.log("ELEVATOR", elevatorId, "IDLE"); | |
elevator.initialize(); | |
}); | |
elevator.on('floor_button_pressed', (floorNum) => { | |
elevator.stopRequest[floorNum] = true; | |
if (elevator.direction === this.DIRECTION.UP) { | |
if (elevator.targetFloor === undefined || floorNum > elevator.targetFloor) { | |
removeFloorFromQueue(elevator.targetFloor); | |
elevator.targetFloor = floorNum; | |
elevator.goToFloor(elevator.targetFloor); | |
} | |
} else { | |
if (elevator.targetFloor === undefined || floorNum < elevator.targetFloor) { | |
removeFloorFromQueue(elevator.targetFloor); | |
elevator.targetFloor = floorNum; | |
elevator.goToFloor(elevator.targetFloor); | |
} | |
} | |
console.log('ELEVATOR', elevatorId, 'floor_button_pressed:', floorNum); | |
console.log(' TargetFloor:', elevator.targetFloor); | |
}); | |
elevator.on('passing_floor', (floorNum) => { | |
if (elevator.destinationQueue.includes(floorNum) || elevator.stopRequest[floorNum]) { | |
elevator.goToFloor(floorNum, true); | |
} | |
// If we have room and there are people going in the direction we're going. | |
if (elevator.loadFactor() < 0.5) { | |
if (this.pendingFloors[floorNum][elevator.direction]) { | |
elevator.goToFloor(floorNum, true); | |
} | |
} | |
}); | |
elevator.on('stopped_at_floor', (floorNum) => { | |
//this.printPendingState(); | |
// We took care of a direction on this floor. | |
elevator.stopRequest[floorNum] = false; | |
if (elevator.targetFloor === floorNum) { | |
elevator.targetFloor = undefined; | |
} | |
// THIS IS HIGH RISK SINCE WE MIGHT NOT HAVE GOT EVERYONE. | |
this.pendingFloors[floorNum][elevator.direction] = false; | |
removeFloorFromQueue(floorNum); | |
elevator.checkDestinationQueue(); | |
}); | |
}); | |
floors.forEach((floor) => { | |
var floorNum = floor.floorNum(); | |
this.pendingFloors[floorNum] = {up: false, down: false}; | |
floor.on('up_button_pressed', () => { | |
console.log('up_button_pressed on floor', floorNum); | |
this.pendingFloors[floorNum].up = true; | |
this.printPendingState(); | |
var idle = this.idleVators.pop(); | |
if (idle) { idle.initialize()} | |
}); | |
floor.on('down_button_pressed', () => { | |
console.log('down_button_pressed on floor', floorNum); | |
this.pendingFloors[floorNum].down = true; | |
this.printPendingState(); | |
var idle = this.idleVators.pop(); | |
if (idle) { idle.initialize(); } | |
}); | |
}); | |
}, | |
update: function(dt, elevators, floors) { | |
// We normally don't need to do anything here | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
init: function(elevators, floors) { | |
var floorCount = floors.length; | |
var elevatorCount = elevators.length; | |
elevators.forEach((elevator, idx) => { | |
//var home = Math.floor((floorCount / (elevatorCount + 1)) * (idx + 1)); | |
var self = this; | |
elevator.dispatch = function(floor) { | |
self.markBusy(this); | |
this.goToFloor(floor); | |
}; | |
var recalibrateDestination = () => { | |
// Sort by target distance. | |
// Closest one is the next target. | |
// If we're not full and there is a requestedFloor between me and there... | |
// Stop there too. | |
/* | |
elevator.destinationQueue = elevator.destinationQueue.sort((floorA, floorB) => { | |
var currentFloor = elevator.currentFloor(); | |
var distA = Math.abs(floorA - currentFloor); | |
var distB = Math.abs(floorB - currentFloor); | |
return distB - distA; | |
}); | |
*/ | |
var nextDestination = elevator.destinationQueue[0]; | |
if (nextDestination > elevator.currentFloor()) { | |
// Going up | |
//elevator.goingDownIndicator(false); | |
//elevator.goingUpIndicator(true); | |
} else { | |
// Going down | |
//elevator.goingDownIndicator(true); | |
//elevator.goingUpIndicator(false); | |
} | |
elevator.checkDestinationQueue(); | |
}; | |
elevator.on('idle', () => { | |
var newTarget = this.getOldestRequest(); | |
if (newTarget) { | |
elevator.goToFloor(newTarget); | |
this.clearedFloor(newTarget); | |
recalibrateDestination() | |
} else { | |
this.markIdle(elevator); | |
elevator.goingDownIndicator(true); | |
elevator.goingUpIndicator(true); | |
} | |
}); | |
elevator.on('floor_button_pressed', (floorPressed) => { | |
// Add target to destinations. | |
elevator.goToFloor(floorPressed); | |
//try pre-emptively clearing floors so multiples don't go there. | |
this.clearedFloor(floorPressed); | |
recalibrateDestination(); | |
}); | |
elevator.on('passing_floor', (floorNum, direction) => { | |
if (elevator.loadFactor() < .5 && this.floorNeedsPickup(floorNum)) { | |
elevator.goToFloor(floorNum, true); | |
} | |
var indexInQueue = elevator.destinationQueue.indexOf(floorNum); | |
if (indexInQueue !== -1) { | |
elevator.goToFloor(floorNum, true); | |
elevator.checkDestinationQueue(); | |
} | |
}); | |
elevator.on('stopped_at_floor', (floorNum) => { | |
this.clearedFloor(floorNum); | |
//recalibrateDestination(); | |
}); | |
}); | |
floors.forEach((floor) => { | |
// When button is pushed, add yourself to the requestedPickup list. | |
var queuePickup = () => { | |
this.requestPickup(floor.floorNum()); | |
}; | |
floor.on('up_button_pressed', queuePickup); | |
floor.on('down_button_pressed', queuePickup); | |
}); | |
}, | |
idleVators: [], | |
markIdle: function(elevator) { | |
if (this.idleVators.indexOf(elevator) === -1) { | |
this.idleVators.push(elevator); | |
} | |
}, | |
markBusy: function(elevator) { | |
var elevatorIdx = this.idleVators.indexOf(elevator); | |
if (elevatorIdx >= 0) { | |
this.idleVators.splice(elevatorIdx, 1); | |
} | |
}, | |
pickupFloors: [], | |
requestPickup: function(floor) { | |
if (this.idleVators.length > 0) { | |
this.idleVators[0].dispatch(floor); | |
} else if (this.pickupFloors.indexOf(floor) === -1) { | |
// This floor hasn't been requested yet. | |
this.pickupFloors.push(floor); | |
} | |
}, | |
getOldestRequest: function() { | |
if (this.pickupFloors.length > 0) { | |
return this.pickupFloors.splice(0,1); | |
} else { | |
return null; | |
} | |
}, | |
clearedFloor: function(floor) { | |
var floorIdx = this.pickupFloors.indexOf(floor); | |
if (floorIdx >= 0) { | |
this.pickupFloors.splice(floorIdx, 1); | |
} | |
}, | |
floorNeedsPickup: function(floor) { | |
return this.pickupFloors.indexOf(floor) !== -1; | |
}, | |
update: function(dt, elevators, floors) { | |
// We normally don't need to do anything here | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
init: function(elevators, floors) { | |
var floorCount = floors.length; | |
var elevatorCount = elevators.length; | |
elevators.forEach((elevator, idx) => { | |
//var home = Math.floor((floorCount / (elevatorCount + 1)) * (idx + 1)); | |
var self = this; | |
elevator.dispatch = function(floor) { | |
self.markBusy(this); | |
this.goToFloor(floor); | |
}; | |
var recalibrateDestination = () => { | |
// Sort by target distance. | |
// Closest one is the next target. | |
// If we're not full and there is a requestedFloor between me and there... | |
// Stop there too. | |
elevator.destinationQueue = elevator.destinationQueue.sort((floorA, floorB) => { | |
var currentFloor = elevator.currentFloor(); | |
var distA = Math.abs(floorA - currentFloor); | |
var distB = Math.abs(floorB - currentFloor); | |
return distA - distB; | |
}); | |
var nextDestination = elevator.destinationQueue[0]; | |
if (nextDestination > elevator.currentFloor()) { | |
// Going up | |
//elevator.goingDownIndicator(false); | |
//elevator.goingUpIndicator(true); | |
} else { | |
// Going down | |
//elevator.goingDownIndicator(true); | |
//elevator.goingUpIndicator(false); | |
} | |
elevator.checkDestinationQueue(); | |
}; | |
elevator.on('idle', () => { | |
var newTarget = this.getOldestRequest(); | |
if (newTarget) { | |
elevator.goToFloor(newTarget); | |
this.clearedFloor(newTarget); | |
recalibrateDestination() | |
} else { | |
this.markIdle(elevator); | |
elevator.goingDownIndicator(true); | |
elevator.goingUpIndicator(true); | |
} | |
}); | |
elevator.on('floor_button_pressed', (floorPressed) => { | |
// Add target to destinations. | |
elevator.goToFloor(floorPressed); | |
//try pre-emptively clearing floors so multiples don't go there. | |
this.clearedFloor(floorPressed); | |
recalibrateDestination(); | |
}); | |
elevator.on('passing_floor', (floorNum, direction) => { | |
if (elevator.loadFactor() < .5 && this.floorNeedsPickup(floorNum)) { | |
elevator.goToFloor(floorNum, true); | |
} | |
}); | |
elevator.on('stopped_at_floor', (floorNum) => { | |
this.clearedFloor(floorNum); | |
//recalibrateDestination(); | |
}); | |
}); | |
floors.forEach((floor) => { | |
// When button is pushed, add yourself to the requestedPickup list. | |
var queuePickup = () => { | |
this.requestPickup(floor.floorNum()); | |
}; | |
floor.on('up_button_pressed', queuePickup); | |
floor.on('down_button_pressed', queuePickup); | |
}); | |
}, | |
idleVators: [], | |
markIdle: function(elevator) { | |
if (this.idleVators.indexOf(elevator) === -1) { | |
this.idleVators.push(elevator); | |
} | |
}, | |
markBusy: function(elevator) { | |
var elevatorIdx = this.idleVators.indexOf(elevator); | |
if (elevatorIdx >= 0) { | |
this.idleVators.splice(elevatorIdx, 1); | |
} | |
}, | |
pickupFloors: [], | |
requestPickup: function(floor) { | |
if (this.idleVators.length > 0) { | |
this.idleVators[0].dispatch(floor); | |
} else if (this.pickupFloors.indexOf(floor) === -1) { | |
// This floor hasn't been requested yet. | |
this.pickupFloors.push(floor); | |
} | |
}, | |
getOldestRequest: function() { | |
if (this.pickupFloors.length > 0) { | |
return this.pickupFloors.splice(0,1); | |
} else { | |
return null; | |
} | |
}, | |
clearedFloor: function(floor) { | |
var floorIdx = this.pickupFloors.indexOf(floor); | |
if (floorIdx >= 0) { | |
this.pickupFloors.splice(floorIdx, 1); | |
} | |
}, | |
floorNeedsPickup: function(floor) { | |
return this.pickupFloors.indexOf(floor) !== -1; | |
}, | |
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