diff --git a/Lift-Problem-Demo.mov b/Lift-Problem-Demo.mov deleted file mode 100644 index 37c5865d..00000000 Binary files a/Lift-Problem-Demo.mov and /dev/null differ diff --git a/Lift-Simulation-Example.png b/Lift-Simulation-Example.png deleted file mode 100644 index 2eef4f8e..00000000 Binary files a/Lift-Simulation-Example.png and /dev/null differ diff --git a/README.md b/README.md index bd506176..9620631d 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,10 @@ # Lift-Simulation -Create a web app where you can simulate lift mechanics for a client -# UI Example -![Lift Simulation Example](Lift-Simulation-Example.png "Lift Simulation Example") +This project is a Lift Simulator that, upon receiving the number of floors and lifts as input, generates an interface with the corresponding number of lifts and floors. This simulator demonstrates the lift movements in response to button presses. -# Requirements - 1. Have a page where you input the number of floors and lifts from the user - 2. An interactive UI is generated, where we have visual depictions of lifts and buttons on floors - 3. Upon clicking a particular button on the floor, a lift goes to that floor +In this version, each elevator has an up and down button on every floor, and the elevator whose button is pressed +responds to the call. - Milestone 1: - - Data store that contains the state of your application data - - JS Engine that is the controller for which lift goes where - - Dumb UI that responds to controller's commands - - Milestone 2: - - Lift having doors open in 2.5s, then closing in another 2.5s - - Lift moving at 2s per floor - - Lift stopping at every floor where it was called - - Mobile friendly design +This is V1, hosted [here](https://main--zesty-peony-c9432e.netlify.app/). + +V2 repo is [here](https://github.com/AnshJain-Shwalia/Lift-Simulation-Vercel), and is hosted [here](https://lift-simulation-lilac-two.vercel.app/). diff --git a/src/css/main.css b/src/css/main.css deleted file mode 100644 index e69de29b..00000000 diff --git a/src/index.html b/src/index.html index e69de29b..1d5ad54d 100644 --- a/src/index.html +++ b/src/index.html @@ -0,0 +1,29 @@ + + + + + + + Lift Simulation + + + + +
+

Lift Simulation.

+
+ + +
+
+ + +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/src/js/main.js b/src/js/main.js deleted file mode 100644 index e69de29b..00000000 diff --git a/src/script.js b/src/script.js new file mode 100644 index 00000000..6764fa44 --- /dev/null +++ b/src/script.js @@ -0,0 +1,325 @@ +//Constants +const liftWidth = 50; +const liftHeight = 75; +const floorHeight = 100; +const liftLeftOffset = 75; +const interLiftDistance = 120; +const buttonLeftOffset = 10; +const upButtonHeightOffset = 75; +const downButtonHeightOffset = 40; +const perFloorCrossTime = 2000;//ms +const liftDoorHoldTime = 500; //ms +const liftOpenTime = 1000; //ms +const timeStep = 20; //ms +const numStepsForLiftClimb = perFloorCrossTime / timeStep +const pixelsPerTimeStepForLiftClimb = floorHeight / numStepsForLiftClimb +const numStepsForLiftOpen = liftOpenTime / timeStep +const pixelsPerTimeStepForLiftOpen = liftWidth / numStepsForLiftOpen +const numStepsForLiftHold = liftDoorHoldTime / timeStep + +console.log('start') +const simulate = document.querySelector('.createLiftFloorButton'); + +simulate.addEventListener('click', e => { + e.preventDefault(); + const floorInputValue = document.getElementById('floorNumber').value; + const liftInputValue = document.getElementById('liftNumber').value; + + if (floorInputValue == "" || liftInputValue == "") { + alert('please enter the value') + } + + if (floorInputValue == "0" || liftInputValue == "0") { + alert('please enter the value') + } + else { + document.querySelector('.firstPage').style.display = 'none'; + document.querySelector('.secondPage').style.display = 'block'; + let data = makingFloor() + let lifts = data[0] + let upButtonArray = data[1] + let downButtonArray = data[2] + let buttonStateArray = data[3] + engine(lifts, buttonStateArray) + // tempEngine(lifts) + } +} +) + + +function makingFloor() { + const floorInputValue = Number(document.getElementById('floorNumber').value); + const liftInputValue = Number(document.getElementById('liftNumber').value); + let parent = document.querySelector(".secondPage") + + //add the floors + for (let i = floorInputValue; i > 0; i -= 1) { + console.log(i) + let newFloor = document.createElement("div") + newFloor.className = "floor" + newFloor.innerHTML = `FLOOR${i}` + parent.appendChild(newFloor) + let breakage = document.createElement("div") + breakage.className = "break" + parent.appendChild(breakage) + } + //add the baseBox + let baseBox = document.createElement("div") + baseBox.className = "baseBox" + parent.appendChild(baseBox) + + //add the lifts + let lifts = [] + for (let i = 0; i < liftInputValue; i += 1) { + let newLift = document.createElement("div") + newLift.className = "lift" + newLift.id = `lift${i + 1}` + baseBox.appendChild(newLift) + newLift.style.top = `-${liftHeight}px` + newLift.style.left = `${liftLeftOffset + (i * interLiftDistance)}px` + lifts.push(newLift) + } + + buttonStateArray = Array(liftInputValue).fill(0).map(x => Array(floorInputValue).fill(0)) + let upButtonArray = Array(liftInputValue).fill(0).map(x => Array(floorInputValue).fill(0)) + let downButtonArray = Array(liftInputValue).fill(0).map(x => Array(floorInputValue).fill(0)) + //add the buttons + for (let i = 0; i < liftInputValue; i += 1) { + for (let j = 0; j < floorInputValue; j += 1) { + if (j != floorInputValue - 1) { + let x = document.createElement("BUTTON") + x.innerText = "UP" + x.className = "up" + x.addEventListener("click", () => { + buttonStateArray[i][j] = 1; + }) + upButtonArray[i][j] = x + baseBox.appendChild(x) + x.style.top = `-${upButtonHeightOffset + (floorHeight * j)}px` + x.style.left = `${buttonLeftOffset + (interLiftDistance * i)}px` + } + if (j != 0) { + let y = document.createElement("BUTTON") + y.innerText = "DOWN" + y.className = "down" + // Need to change buttonStateArray[i][j] = 1; to = -1 but i will not do it without specific reason + y.addEventListener("click", () => { + buttonStateArray[i][j] = 1; + }) + downButtonArray[i][j] = y + baseBox.appendChild(y) + y.style.top = `-${downButtonHeightOffset + (floorHeight * j)}px` + y.style.left = `${buttonLeftOffset + (interLiftDistance * i)}px` + } + } + } + return [lifts, upButtonArray, downButtonArray, buttonStateArray]; +} + + + +function tempEngine(lifts) { + for (let i = 0; i < lifts.length; i += 1) { + setInterval(moveUp, timeStep, lifts[i]) + } +} + + +function engine(lifts, buttonStateArray) { + let liftStateArray = new Array(lifts.length) + for (let i = 0; i < lifts.length; i += 1) { + liftStateArray[i] = { + state: 0, + movement: { + movementState: 0, + currTop: -1 * liftHeight, + floor: 0, + step: 0, + // goalFloor: -1, + // goalHeight: -1, + // lastTime: -1, + }, + ohc: { + ohcState: 0, + width: liftWidth, + currLeft: liftLeftOffset + (i * interLiftDistance), + step: 0, + // lastTime: -1, + }, + liftNumber: i, + lift: lifts[i], + } + } + + for (let i = 0; i < lifts.length; i += 1) { + setInterval(liftEngine, timeStep, liftStateArray[i], buttonStateArray) + } +} + +function liftEngine(liftState, buttonStateArray, /*upButtonArray, downButtonArray*/) { + // let start=new Date().getTime() + let currLiftState = liftState.state + if (currLiftState == 0) { + if (liftState.movement.movementState == 0) { + let closestFloor = findClosestFloorWithButtonPressed(liftState.movement.floor, buttonStateArray[liftState.liftNumber]) + if (closestFloor == -1) { + + //pass + } else if (closestFloor == liftState.movement.floor) { + //Open the Gates + liftState.state = 2 + liftState.ohc.ohcState = 1 + } else if (closestFloor > liftState.movement.floor) { + // the closest floor is above the current floor + liftState.state = 1 + liftState.movement.movementState = 1 + } else { + // the closest floor is below the current floor + liftState.state = 1 + liftState.movement.movementState = -1 + } + } else if (liftState.movement.movementState == 1) { + // this scenario happens when ->when we just stopped at a floor, we need to check if we need to open for the current floor or we can continue. + // the liftState.movement.movementState being 1 represents that it was moving upward before. + let closestFloor = findClosestButtonUp(liftState.movement.floor, buttonStateArray[liftState.liftNumber]) + if (closestFloor == -1) { + liftState.movement.movementState = 0 + } else if (closestFloor == liftState.movement.floor) { + liftState.state = 2 + liftState.ohc.ohcState = 1 + } else { + liftState.state = 1 + } + } else { + // in this scenario the state is 0 and lift.movement.movementState is -1. this means that it stopped here while moving down or this was the destination. + let closestFloor = findClosestButtonDown(liftState.movement.floor, buttonStateArray[liftState.liftNumber]) + if (closestFloor == -1) { + liftState.movement.movementState = 0 + } else if (closestFloor == liftState.movement.floor) { + liftState.state = 2 + liftState.ohc.ohcState = 1 + } else { + liftState.state = 1 + } + } + } else if (currLiftState == 1) { + // if this case comes true, this implies that the lift must be moved, where to can be know from liftState.movement.step + if (liftState.movement.movementState == 1) { + if (liftState.movement.step < numStepsForLiftClimb) { + //push the lift up. + liftState.movement.step += 1 + liftState.movement.currTop -= pixelsPerTimeStepForLiftClimb + liftState.lift.style.top = `${Math.round(liftState.movement.currTop)}px` + } else { + liftState.movement.step = 0 + liftState.state = 0 + liftState.movement.floor += 1 + } + } else { + if (liftState.movement.step < numStepsForLiftClimb) { + //push the lift down. + liftState.movement.step += 1 + liftState.movement.currTop += pixelsPerTimeStepForLiftClimb + liftState.lift.style.top = `${Math.round(liftState.movement.currTop)}px` + } else { + liftState.movement.step = 0 + liftState.state = 0 + liftState.movement.floor -= 1 + } + } + } else { + let doorStatus = liftState.ohc.ohcState + if (doorStatus == 0) { + //The liftDoor is closed. This state can only be arrived when we have already closed the lift from going via doorStatus==3(in the else block) + // Update the buttonArray + // Change the state + // change the color + buttonStateArray[liftState.liftNumber][liftState.movement.floor] = 0 + liftState.state = 0 + + + } else if (doorStatus == 1) { + if (liftState.ohc.step < numStepsForLiftOpen) { + liftState.ohc.step += 1 + liftState.ohc.width -= pixelsPerTimeStepForLiftOpen + liftState.lift.style.width = `${Math.round(liftState.ohc.width)}px` + } else { + liftState.ohc.step = 0 + liftState.ohc.ohcState = 2 + } + } else if (doorStatus == 2) { + // hold + if (liftState.ohc.step < numStepsForLiftHold) { + liftState.ohc.step += 1 + } else { + liftState.ohc.ohcState = 3 + liftState.ohc.step = 0 + } + } else { + if (liftState.ohc.step < numStepsForLiftOpen) { + liftState.ohc.step += 1 + liftState.ohc.width += pixelsPerTimeStepForLiftOpen + liftState.lift.style.width = `${Math.round(liftState.ohc.width)}px` + } else { + liftState.ohc.ohcState = 0 + liftState.ohc.step = 0 + } + } + } + // console.log(new Date().getTime()-start,"ms have been used to process this iteration time of the lift") +} + +function moveUp(lift) { + const upMovementAmount = 1; + let topY = lift.style.top; + topY = Number(topY.slice(1, topY.length - 2)); + lift.style.top = `-${topY + upMovementAmount}px`; +} + + +function findClosestFloorWithButtonPressed(floor, list) { + let left = -1; + let right = -1; + for (let i = 0; i <= floor; i += 1) { + if (list[i] == 1) { + left = i + } + } + for (let i = list.length - 1; i > floor; i -= 1) { + if (list[i] == 1) { + right = i + } + } + if (left == -1 && right == -1) { + return -1 + } + if (left == -1) { + return right + } + if (right == -1) { + return left + } + if (floor - left < right - floor) { + return left + } + return right +} + +function findClosestButtonUp(floor, list) { + while (floor < list.length) { + if (list[floor] == 1) { + return floor + } + floor += 1; + } + return -1 +} + +function findClosestButtonDown(floor, list) { + for (let i = floor; i > -1; i -= 1) { + if (list[i] == 1) { + return i + } + } + return -1 +} \ No newline at end of file diff --git a/src/stylesheet.css b/src/stylesheet.css new file mode 100644 index 00000000..346f05f7 --- /dev/null +++ b/src/stylesheet.css @@ -0,0 +1,97 @@ +* { + box-sizing: border-box; +} + +.secondPage { + display: none; +} + +/* .firstPage { + display: none; +} */ + +.break { + background-color: black; + height: 2px; +} + +.floor-text { + position: absolute; + bottom: 0; + right: 0; +} + +.floor { + font-family: Arial, Helvetica, sans-serif; + font-size: 40px; + width: 100%; + background-color: aqua; + /* margin-top: 10px; */ + text-align: end; + height: 98px; + position: relative; +} + +.lift { + height: 75px; + width: 50px; + background-color: black; + position: absolute; +} + + +.down { + position: absolute; +} + +.lift1 { + top: -10px; + left: 10px; +} + +.lift2 { + top: -10px; + left: 100px; +} + +.lift3 { + top: -10px; + left: 200px; +} + +.lift4 { + top: -10px; + left: 300px; +} + +.baseBox { + height: 100px; + background-color: aquamarine; + position: relative; +} + +.button { + border: none; + color: white; + padding: 15px 32px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin: 4px 2px; + cursor: pointer; +} + +.up { + background-color: #04AA6D; + position: absolute; +} + +/* Green */ + +.down { + background-color: #008CBA; + position: absolute; +} + +/* Blue */ \ No newline at end of file