Created
February 10, 2022 02:45
-
-
Save natafaye/89d3128c8cf535d05d59fc4b54aecef4 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
/* | |
* | |
* | |
* This code was written specifically for a CodeWars kata, and is different than the code | |
* we worked through in class because it is designed for a different purpose. | |
* It shows that there is not one right way to break things into classes/objects (or functions) | |
* it depends on what your goals are and what you need it to do! | |
* | |
* Also, this isn't doctrine on how to solve this problem, | |
* it's just a solution to this CodeWars kata that I made, using classes, for fun :) | |
* https://www.codewars.com/kata/58905bfa1decb981da00009e | |
* | |
* | |
*/ | |
/********** BUILDING **********/ | |
class Building { | |
constructor(queues) { | |
this.queues = queues; // an array of arrays of numbers (passengers) | |
} | |
/* Is there no one calling the elevator */ | |
get isEmpty() { return !this.queues.some(q => q.length) } | |
/* Top floor with someone calling the elevator */ | |
get topCallingFloor() { | |
let top = this.queues.length - 1 - this.queues.slice().reverse().findIndex(q => q.length) | |
if(top >= this.queues.length) top = -1; | |
return top; | |
} | |
/* Bottom floor with someone calling the elevator */ | |
get bottomCallingFloor() { | |
let bottom = this.queues.findIndex(q => q.length); | |
if(bottom < 0) bottom = this.queues.length; | |
return bottom; | |
} | |
/* Checks if a floor has anyone calling the elevator in that direction */ | |
isCalling(floor, goingUp, canSwitchDirection) { | |
return this.queues[floor].some(p => canSwitchDirection || p > floor === goingUp); | |
} | |
/* Takes an amount of passengers from the floor that are going in that direction */ | |
getPassengers(floor, amount, goingUp, canSwitchDirection) { | |
const queue = this.queues[floor]; | |
const passengers = []; | |
// packaged in a function so we can run it again in the other direction if we need to | |
const tryGettingPassengers = () => { | |
for(let i = 0; i < queue.length; i++) { | |
// If the elevator is full, stop loading passengers | |
if(!amount) return passengers; | |
// Load a passenger if they're going in the right direction | |
if(goingUp && queue[i] > floor || !goingUp && queue[i] < floor) { | |
passengers.push(queue.splice(i, 1).pop()); | |
amount--; | |
i--; // Adjust index for removed passenger | |
} | |
} | |
} | |
// Use the function to get the passengers (maybe trying a second time in the other direction) | |
tryGettingPassengers(); | |
if(!passengers.length && canSwitchDirection) { | |
goingUp = !goingUp; | |
tryGettingPassengers(); | |
} | |
return passengers; | |
} | |
} | |
/********** ELEVATOR **********/ | |
class Elevator { | |
constructor(capacity) { | |
this.floor = 0; | |
this.goingUp = true; | |
this.capacity = capacity; | |
this.contents = []; // an array of numbers (passengers) | |
this.floorLog = [0]; | |
} | |
/* Is the elevator empty */ | |
get isEmpty() { return !this.contents.length } | |
/* How much space is available for passengers */ | |
get availableSpace() { return this.capacity - this.contents.length } | |
/* Is the elevator on the ground floor */ | |
get isOnGroundFloor() { return this.floor === 0 } | |
/* An arry of all floors the elevator stopped on */ | |
get stoppedFloors() { return this.floorLog } | |
/* The top floor requested by passengers in the elevator */ | |
get topRequestedFloor() { | |
if(this.isEmpty) return -1; | |
return this.contents[this.contents.length - 1]; | |
} | |
/* The bottom floor requested by passengers in the elevator */ | |
get bottomRequestedFloor() { | |
if(this.isEmpty) return Number.POSITIVE_INFINITY; | |
return this.contents[0]; | |
} | |
/* Checks if there is anyone on the elevator requesting the floor */ | |
isRequested(floor) { | |
return this.contents.includes(floor); | |
} | |
/* The farthest in the current direction the elevator should go */ | |
getBoundary(building) { return (this.goingUp) ? Math.max(building.topCallingFloor, this.topRequestedFloor) : | |
Math.min(building.bottomCallingFloor, this.bottomRequestedFloor) } | |
/* Loads passengers on the elevator from the building on the current floor of the elevator */ | |
load(building) { | |
const canSwitchDirection = this.floor === this.getBoundary(building); | |
const passengers = building.getPassengers(this.floor, this.availableSpace, this.goingUp, canSwitchDirection); | |
this.contents.push(...passengers); | |
this.contents.sort(); | |
} | |
/* Unloads all passengers on the elevator that want to get off at the current floor */ | |
unload() { | |
this.contents = this.contents.filter(p => p !== this.floor); | |
} | |
/* Takes the elevator to the next floor it should go to */ | |
/* This one method took 90% of the work */ | |
goToNextFloor(building) { | |
// If we just finished, go to the bottom | |
if(building.isEmpty && this.isEmpty) { | |
// Only actually move if we're not already there | |
if(this.floor !== 0) { | |
this.floor = 0; | |
this.floorLog.push(this.floor); | |
} | |
return; | |
} | |
let boundary = this.getBoundary(building); | |
// If we're now past the limit (meaning we've unloaded or loaded everything in this direction), turn around | |
if(this.floor > boundary === this.goingUp || this.floor === boundary) { | |
this.goingUp = !this.goingUp | |
boundary = this.getBoundary(building); // update the boundary for the new direction | |
} | |
let canSwitchDirection; // declared outside the loop for scope | |
do { | |
// Move up or down | |
(this.goingUp) ? this.floor++ : this.floor--; | |
// If we've reached the end of what we need to do in this direction, we can pick up passengers in either direction | |
canSwitchDirection = this.floor === boundary; | |
// Keep moving if not a requested or calling floor | |
} while(!this.isRequested(this.floor) && !building.isCalling(this.floor, this.goingUp, canSwitchDirection)) | |
this.floorLog.push(this.floor); | |
} | |
} | |
/********** TOP LEVEL FUNCTION **********/ | |
const theLift = (queues, capacity) => { | |
// Set up objects | |
const elevator = new Elevator(capacity); | |
const building = new Building(queues); | |
// Loop as long as there's anything to do | |
while(!elevator.isEmpty || !building.isEmpty || !elevator.isOnGroundFloor) { | |
elevator.unload(); | |
elevator.load(building); | |
elevator.goToNextFloor(building); | |
} | |
// Return the floors the elevator stopped at | |
return elevator.stoppedFloors; | |
} |
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
let building1, building2, building3, elevator1, elevator2, elevator3; | |
/*** NOTE: This is not using Mocha/Chai, this is using CodeWars' testing library, based on Mocha ***/ | |
// A function for creating the buildings before each test | |
function createBuildings() { | |
building1 = new Building([ | |
[], // G | |
[5,4], // 1 | |
[1,1], // 2 | |
[], // 3 | |
[2,6], // 4 | |
[], // 5 | |
[], // 6 | |
]); | |
building2 = new Building([ | |
[3], // G | |
[], // 1 | |
[5,5,3], // 2 | |
[], // 3 | |
[], // 4 | |
[], // 5 | |
[3], // 6 | |
]); | |
building3 = new Building([ | |
[], // G | |
[], // 1 | |
[], // 2 | |
[], // 3 | |
[], // 4 | |
[], // 5 | |
[], // 6 | |
]); | |
} | |
/********** BUILDING **********/ | |
describe("Building", function() { | |
before(createBuildings) // runs at the beginning of this section | |
describe("#isEmpty", function() { | |
it("should check if empty", function() { | |
Test.assertEquals(building1.isEmpty, false) | |
Test.assertEquals(building2.isEmpty, false) | |
Test.assertEquals(building3.isEmpty, true) | |
}) | |
}) | |
describe("#topCallingFloor", function() { | |
it("should return the top floor with a passenger waiting", function() { | |
Test.assertEquals(building1.topCallingFloor, 4) | |
Test.assertEquals(building2.topCallingFloor, 6) | |
Test.assertEquals(building3.topCallingFloor, -1) | |
}) | |
}) | |
describe("#bottomCallingFloor", function() { | |
it("should return the bottom floor with a passenger waiting", function() { | |
Test.assertEquals(building1.bottomCallingFloor, 1) | |
Test.assertEquals(building2.bottomCallingFloor, 0) | |
Test.assertEquals(building3.bottomCallingFloor, 7) | |
}) | |
}) | |
describe("#isCalling", function() { | |
it("should return true if there is a passenger calling the elevator on that floor in that direction", function() { | |
Test.assertEquals(building1.isCalling(1, true), true) | |
Test.assertEquals(building1.isCalling(4, true), true) | |
Test.assertEquals(building1.isCalling(4, false), true) | |
Test.assertEquals(building1.isCalling(2, false), true) | |
}) | |
it("should return false if there isn't a passenger calling the elevator on that floor in that direction", function() { | |
Test.assertEquals(building1.isCalling(0, true), false) | |
Test.assertEquals(building1.isCalling(2, true), false) | |
Test.assertEquals(building1.isCalling(3, true), false) | |
Test.assertEquals(building1.isCalling(5, true), false) | |
Test.assertEquals(building1.isCalling(6, true), false) | |
Test.assertEquals(building1.isCalling(0, false), false) | |
Test.assertEquals(building1.isCalling(1, false), false) | |
Test.assertEquals(building1.isCalling(3, false), false) | |
Test.assertEquals(building1.isCalling(5, false), false) | |
Test.assertEquals(building1.isCalling(6, false), false) | |
}) | |
}) | |
describe("#getPassengers", function() { | |
it("should fill with passengers correctly going up", function() { | |
Test.assertDeepEquals(building1.getPassengers(1, 5, true), [5, 4]) | |
Test.assertDeepEquals(building1.getPassengers(2, 5, true), []) | |
Test.assertDeepEquals(building1.getPassengers(3, 5, true), []) | |
Test.assertDeepEquals(building1.getPassengers(4, 5, true), [6]) | |
}) | |
it("should fill with passengers correctly going down", function() { | |
Test.assertDeepEquals(building1.getPassengers(4, 5, false), [2]) | |
Test.assertDeepEquals(building1.getPassengers(3, 5, false), []) | |
Test.assertDeepEquals(building1.getPassengers(2, 5, false), [1, 1]) | |
Test.assertDeepEquals(building1.getPassengers(1, 5, false), []) | |
}) | |
it("should be removing passengers from queues", function() { | |
building1.getPassengers(1, 5, true) | |
building1.getPassengers(2, 5, true) | |
building1.getPassengers(3, 5, true) | |
building1.getPassengers(4, 5, true) | |
building1.getPassengers(4, 5, false) | |
building1.getPassengers(3, 5, false) | |
building1.getPassengers(2, 5, false) | |
building1.getPassengers(1, 5, false) | |
Test.assertEquals(building1.isEmpty, true) | |
}) | |
it("should only give within the amount of passengers", function() { | |
Test.assertDeepEquals(building2.getPassengers(0, 0, true), []) | |
Test.assertDeepEquals(building2.getPassengers(2, 2, true), [5, 5]) | |
Test.assertDeepEquals(building2.getPassengers(3, 2, true), []) | |
Test.assertDeepEquals(building2.getPassengers(6, 3, false), [3]) | |
}) | |
}) | |
}) | |
/********** ELEVATOR **********/ | |
describe("Elevator", function() { | |
before(function() { | |
elevator1 = new Elevator(1); | |
elevator2 = new Elevator(5); | |
elevator3 = new Elevator(0); | |
}) | |
describe("#isEmpty", function() { | |
before(createBuildings) // Recreates the building for this test | |
it("should check if empty", function() { | |
elevator1.contents = [4]; | |
elevator2.contents = [1, 3, 5]; | |
elevator3.contents = []; | |
Test.assertEquals(elevator1.isEmpty, false) | |
Test.assertEquals(elevator2.isEmpty, false) | |
Test.assertEquals(elevator3.isEmpty, true) | |
}) | |
}) | |
describe("#availableSpace", function() { | |
it("should return the space left in the elevator for passengers", function() { | |
elevator1.contents = [4]; | |
elevator2.contents = [1, 3, 5]; | |
elevator3.contents = []; | |
Test.assertEquals(elevator1.availableSpace, 0) | |
Test.assertEquals(elevator2.availableSpace, 2) | |
Test.assertEquals(elevator3.availableSpace, 0) | |
}) | |
}) | |
describe("#topRequestedFloor", function() { | |
it("should return the top floor requested by a passenger", function() { | |
Test.assertEquals(elevator1.topRequestedFloor, 4) | |
Test.assertEquals(elevator2.topRequestedFloor, 5) | |
Test.assertEquals(elevator3.topRequestedFloor, -1) | |
}) | |
}) | |
describe("#bottomRequestedFloor", function() { | |
it("should return the bottom floor requested by a passenger", function() { | |
Test.assertEquals(elevator1.bottomRequestedFloor, 4) | |
Test.assertEquals(elevator2.bottomRequestedFloor, 1) | |
Test.assertEquals(elevator3.bottomRequestedFloor, Number.POSITIVE_INFINITY) | |
}) | |
}) | |
describe("#load", function() { | |
before(createBuildings) // Recreates the building for each test | |
it("should fill with passengers correctly going up", function() { | |
elevator2.goingUp = true; | |
elevator2.contents = []; | |
elevator2.floor = 0; | |
elevator2.load(building1) | |
Test.assertDeepEquals(elevator2.contents, []) | |
elevator2.floor = 1; | |
elevator2.load(building1) | |
Test.assertDeepEquals(elevator2.contents, [4, 5]) | |
elevator2.floor = 2; | |
elevator2.load(building1) | |
Test.assertDeepEquals(elevator2.contents, [4, 5]) | |
elevator2.floor = 3; | |
elevator2.load(building1) | |
Test.assertDeepEquals(elevator2.contents, [4, 5]) | |
elevator2.floor = 4; | |
elevator2.load(building1) | |
Test.assertDeepEquals(elevator2.contents, [4, 5, 6]) | |
}) | |
it("should fill with passengers correctly going down", function() { | |
elevator2.goingUp = false; | |
elevator2.contents = []; | |
elevator2.floor = 4; | |
elevator2.load(building1) | |
Test.assertDeepEquals(elevator2.contents, [2]) | |
elevator2.floor = 3; | |
elevator2.load(building1) | |
Test.assertDeepEquals(elevator2.contents, [2]) | |
elevator2.floor = 2; | |
elevator2.load(building1) | |
Test.assertDeepEquals(elevator2.contents, [1, 1, 2]) | |
elevator2.floor = 1; | |
elevator2.load(building1) | |
Test.assertDeepEquals(elevator2.contents, [1, 1, 2]) | |
elevator2.floor = 0; | |
elevator2.load(building1) | |
Test.assertDeepEquals(elevator2.contents, [1, 1, 2]) | |
}) | |
it("should only fill up to the capacity", function() { | |
elevator3.goingUp = true; | |
elevator3.contents = []; | |
elevator3.floor = 0 | |
elevator3.load(building2); | |
Test.assertDeepEquals(elevator3.contents, []) | |
elevator1.goingUp = true; | |
elevator1.contents = []; | |
elevator1.floor = 0; | |
elevator1.load(building2); | |
Test.assertDeepEquals(elevator1.contents, [3]) | |
elevator1.floor = 2; | |
elevator1.load(building2); | |
Test.assertDeepEquals(elevator1.contents, [3]) | |
elevator1.contents = []; | |
elevator1.load(building2); | |
Test.assertDeepEquals(elevator1.contents, [5]) | |
elevator2.goingUp = true; | |
elevator2.contents = [1, 2, 3]; | |
elevator2.floor = 2; | |
elevator2.load(building2); | |
Test.assertDeepEquals(elevator2.contents, [1, 2, 3, 3, 5]) | |
}) | |
}) | |
describe("#unload", function() { | |
it("should unload passengers correctly", function() { | |
elevator2.contents = [1, 1, 2, 4]; | |
elevator2.floor = 0; | |
elevator2.unload(); | |
Test.assertDeepEquals(elevator2.contents, [1, 1, 2, 4]) | |
elevator2.floor = 1; | |
elevator2.unload(); | |
Test.assertDeepEquals(elevator2.contents, [2, 4]) | |
elevator2.floor = 4; | |
elevator2.unload(); | |
Test.assertDeepEquals(elevator2.contents, [2]) | |
elevator2.floor = 2; | |
elevator2.unload(); | |
Test.assertDeepEquals(elevator2.contents, []) | |
}) | |
}) | |
describe("#goToNextFloor", function() { | |
before(createBuildings) // Recreates the buildings for each test | |
it("should go up when there's no reason to go down", function() { | |
elevator2.goingUp = false; | |
elevator2.floor = 0; | |
elevator2.goToNextFloor(building1); | |
Test.assertEquals(elevator2.goingUp, true) | |
Test.assertEquals(elevator2.floor, 1) | |
}) | |
it("should stop on a floor while going up if there's someone there waiting to go up", function() { | |
elevator2.goingUp = true; | |
elevator2.floor = 0; | |
elevator2.goToNextFloor(building1); | |
Test.assertEquals(elevator2.goingUp, true) | |
Test.assertEquals(elevator2.floor, 1) | |
elevator2.goToNextFloor(building1); | |
Test.assertEquals(elevator2.goingUp, true) | |
Test.assertEquals(elevator2.floor, 4) | |
}) | |
it("should go down when there's no reason to go up", function() { | |
elevator2.goingUp = true; | |
elevator2.floor = 6; | |
elevator2.goToNextFloor(building1); | |
Test.assertEquals(elevator2.goingUp, false) | |
Test.assertEquals(elevator2.floor, 4) | |
elevator2.goingUp = true; | |
elevator2.floor = 5; | |
elevator2.goToNextFloor(building1); | |
Test.assertEquals(elevator2.goingUp, false); | |
Test.assertEquals(elevator2.floor, 4); | |
}) | |
it("should stop on a floor while going down if there's someone there waiting to go down", function() { | |
elevator2.goingUp = false; | |
elevator2.floor = 6; | |
elevator2.goToNextFloor(building1); | |
Test.assertEquals(elevator2.goingUp, false); | |
Test.assertEquals(elevator2.floor, 4); | |
elevator2.goToNextFloor(building1); | |
Test.assertEquals(elevator2.goingUp, false); | |
Test.assertEquals(elevator2.floor, 2); | |
}) | |
it("should stop on a floor if there's someone who needs to get off there", function() { | |
elevator2.goingUp = true; | |
elevator2.floor = 0; | |
elevator2.contents = [1, 3, 5]; | |
elevator2.goToNextFloor(building3); | |
Test.assertEquals(elevator2.goingUp, true); | |
Test.assertEquals(elevator2.floor, 1); | |
elevator2.goToNextFloor(building3); | |
Test.assertEquals(elevator2.goingUp, true); | |
Test.assertEquals(elevator2.floor, 3); | |
elevator2.goToNextFloor(building3); | |
Test.assertEquals(elevator2.goingUp, true); | |
Test.assertEquals(elevator2.floor, 5); | |
}) | |
it("should go to the bottom if there's no one waiting and no one inside", function() { | |
elevator2.goingUp = true; | |
elevator2.floor = 3; | |
elevator2.contents = []; | |
elevator2.goToNextFloor(building3); | |
Test.assertEquals(elevator2.goingUp, true); | |
Test.assertEquals(elevator2.floor, 0); | |
}) | |
}) | |
}) | |
/********** CODEWARS TESTS **********/ | |
describe("Example Tests", function() { | |
it("up", function() { | |
var queues = [ | |
[], // G | |
[], // 1 | |
[5,5,5], // 2 | |
[], // 3 | |
[], // 4 | |
[], // 5 | |
[], // 6 | |
]; | |
var result = theLift(queues,5); | |
Test.assertDeepEquals(result, [0,2,5,0]); | |
}); | |
it("down", function() { | |
var queues = [ | |
[], // G | |
[], // 1 | |
[1,1], // 2 | |
[], // 3 | |
[], // 4 | |
[], // 5 | |
[], // 6 | |
]; | |
var result = theLift(queues,5); | |
Test.assertDeepEquals(result, [0,2,1,0]); | |
}); | |
it("up and up", function() { | |
var queues = [ | |
[], // G | |
[3], // 1 | |
[4], // 2 | |
[], // 3 | |
[5], // 4 | |
[], // 5 | |
[], // 6 | |
]; | |
var result = theLift(queues,5); | |
Test.assertDeepEquals(result, [0,1,2,3,4,5,0]); | |
}); | |
it("down and down", function() { | |
var queues = [ | |
[], // G | |
[0], // 1 | |
[], // 2 | |
[], // 3 | |
[2], // 4 | |
[3], // 5 | |
[], // 6 | |
]; | |
var result = theLift(queues,5); | |
Test.assertDeepEquals(result, [0,5,4,3,2,1,0]); | |
}); | |
it("up and down", function() { | |
var queues = [ | |
[], // G | |
[5,4], // 1 | |
[1,1], // 2 | |
[], // 3 | |
[2,6], // 4 | |
[], // 5 | |
[], // 6 | |
]; | |
var result = theLift(queues, 5); | |
Test.assertDeepEquals(result, [0,1,4,5,6,4,2,1,0]); | |
}); | |
it("everyone down", function() { | |
var queues = [ | |
[], | |
[0, 0, 0, 0], | |
[0, 0, 0, 0], | |
[0, 0, 0, 0], | |
[0, 0, 0, 0], | |
[0, 0, 0, 0], | |
[0, 0, 0, 0] | |
] | |
var result = theLift(queues, 5); | |
Test.assertDeepEquals(result, [0,6,5,4,3,2,1,0,5,4,3,2,1,0,4,3,2,1,0,3,2,1,0,1,0]); | |
}) | |
it("up down up down", function() { | |
var queues = [ [ 1, 4, 4, 1 ], [ 3, 2 ], [ 3, 4, 0, 3 ], [], [] ] | |
var result = theLift(queues, 4); | |
Test.assertDeepEquals(result, [0,1,2,3,4,2,0,2,3,4,0]); | |
}) | |
it("not enough room", function() { | |
var queues = [ [], [], [ 4, 4, 4, 4 ], [], [ 2, 2, 2, 2 ], [], [] ] | |
var result = theLift(queues, 2); | |
Test.assertDeepEquals(result, [0,2,4,2,4,2,0]); | |
}) | |
}); | |
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
class Elevator { | |
constructor(building, capacity) { | |
this.floor = 0; | |
this.building = building; | |
this.capacity = capacity; | |
this.contents = []; | |
} | |
goToNextFloor() { | |
this.building | |
} | |
load() { | |
} | |
unload() { | |
} | |
} | |
class Building { | |
constructor(queues) { | |
this.queues = queues; | |
} | |
isEmpty() { | |
return this.queues.find( floor => floor.length !== 0) === undefined; | |
} | |
} | |
var theLift = function(queues, capacity) { | |
const building = new Building(queues); | |
const elevator = new Elevator(building, capacity); | |
// the elevator to pick people up and take them where they need to go until the building is empty | |
while( !building.isEmpty() ) { | |
elevator.goToNextFloor(); | |
elevator.unload(); | |
elevator.load(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment