Created
June 15, 2021 13:12
-
-
Save amok/da3359ab3afec3c2cd1ee0e2a7e6be9f to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| const DIRECTION_DOWN = -1; | |
| const DIRECTION_NONE = 0; | |
| const DIRECTION_UP = 1; | |
| function HardwareElevator() {} | |
| HardwareElevator.prototype = { | |
| moveUp: function() { console.log("up") }, | |
| moveDown: function() { console.log("down") }, | |
| stopAndOpenDoors: function() { console.log("stop and open") }, | |
| getCurrentFloor: function() {}, | |
| getCurrentDirection: function() {} | |
| }; | |
| function Elevator() { | |
| this.hw = new HardwareElevator(); | |
| this.hw.on("doorsClosed", _bind(this.onDoorsClosed, this)); | |
| this.hw.on("beforeFloor", _bind(this.onBeforeFloor, this)); | |
| this.hw.on("floorButtonPressed", _bind(this.onFloorButtonPressed, this)); | |
| this.hw.on("cabinButtonPressed", _bind(this.onCabinButtonPressed, this)); | |
| } | |
| Elevator.prototype = { | |
| onDoorsClosed: function() { | |
| this.moveElevatorOnIfNecessary(); | |
| }, | |
| onBeforeFloor: function() { | |
| this.stopElevatorOnThisFloorIfNecessary(); | |
| }, | |
| onFloorButtonPressed: function(floor, direction) { | |
| this.enqueueFloor(floor, direction); | |
| }, | |
| onCabinButtonPressed: function(floor) { | |
| this.enqueueFloor(floor); | |
| } | |
| ////////////////////////////////////////////////////////////////////////////// | |
| stopElevatorOnThisFloorIfNecessary() { | |
| const floor = this.hw.getCurrentFloor() + 1; | |
| if (!this.getRequestedFloors().includes(floor)) { | |
| return; | |
| } | |
| this.stopElevatorFloorIfNecessary(floor); | |
| } | |
| stopElevatorFloorIfNecessary(floor) { | |
| const command = this[floor]; | |
| const isSameDirection = command === this.hw.getCurrentDirection(); | |
| const shouldVisitFloor = command === DIRECTION_NONE; | |
| const isElevatorStopped = this.hw.getCurrentDirection() === DIRECTION_NONE; | |
| if (isElevatorStopped) { | |
| // open doors and "unrequest" the floor | |
| // we assume that this.hw.stopAndOpenDoors is idempotent and if | |
| // we try to "stop" already stopped elevator it doesn't explode :) | |
| this.hw.stopAndOpenDoors(); | |
| delete this[floor]; | |
| } else if (shouldVisitFloor || isSameDirection) { | |
| this.lastElevatorDirection = this.hw.getCurrentDirection(); | |
| this.hw.stopAndOpenDoors(); | |
| delete this[floor]; | |
| } else if (!isSameDirection) { | |
| // pick up on the way back | |
| this[floor] = DIRECTION_NONE; | |
| } | |
| } | |
| getRequestedFloors() { | |
| return Object.keys(this).filter(isFinite).filter(floor => { | |
| return [DIRECTION_NONE, DIRECTION_DOWN, DIRECTION_UP].includes(this[floor]); | |
| }).map(it => parseInt(it, 10)); | |
| } | |
| moveElevatorOnIfNecessary() { | |
| const requestedFloors = this.getRequestedFloors(); | |
| if (!requestedFloors.length) { | |
| // nowhere to move | |
| return; | |
| } | |
| if (this.hw.getCurrentDirection() !== DIRECTION_NONE) { | |
| // we're already moving | |
| return; | |
| } | |
| const currentElevatorFloor = this.hw.getCurrentFloor(); | |
| const lastElevatorDirection = this.lastElevatorDirection; | |
| if (requestedFloors.find(floor => floor === currentElevatorFloor)) { | |
| // we're pressing up/down/cabin button being on the "currrent floor" | |
| this.stopElevatorFloorIfNecessary(floor); | |
| } else if (lastElevatorDirection === DIRECTION_DOWN && requestedFloors.find(floor => floor < currentElevatorFloor)) { | |
| // we're moving down and there's a requested floor in the direction we move to | |
| this.hw.moveDown(); | |
| } else if (lastElevatorDirection === DIRECTION_UP && requestedFloors.find(floor => floor > currentElevatorFloor)) { | |
| // we're moving up and there's a requested floor in the direction we move to | |
| this.hw.moveUp(); | |
| } else if (lastElevatorDirection === DIRECTION_UP) { | |
| // we've been moving up, but only lower floors are left to visit | |
| this.hw.moveDown(); | |
| } else if (lastElevatorDirection === DIRECTION_DOWN) { | |
| // we've been moving down, but only upper floors are left to visit | |
| this.hw.moveUp(); | |
| } | |
| } | |
| enqueueFloor(floor, direction) { | |
| // we write directly to "this" for simplicity | |
| this[floor] = direction || DIRECTION_NONE; | |
| this.moveElevatorOnIfNecessary(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment