Code for Elevator Saga
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

elevator.js 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. eval({
  2. init: function(elevators, floors) {
  3. // Get elevator/building info
  4. const elevatorCount = elevators.length,
  5. floorCount = floors.length,
  6. bottomFloor = 0,
  7. topFloor = floorCount - 1;
  8. console.clear();
  9. ("Starting (" + floorCount + " floors; " + elevatorCount + " elevator" + (floorCount == 1) ? "s" : "" + ")...");
  10. // Direction constants
  11. const UP = 0,
  12. DOWN = 1,
  13. IDLE = 2;
  14. // Rest floor constants
  15. const LOW = 0,
  16. MED = 1,
  17. HIGH = 2;
  18. // Data structure for floor requests
  19. const requests = [new Set(), new Set()];
  20. // ----
  21. // Functions
  22. // ----
  23. // getClosestFloor takes a floor, a list of floors, an optional
  24. // list of ignored floors, and an optional direction. It
  25. // returns the closest floor from that list in the given
  26. // direction that is not part of the ignored floors list. Ties
  27. // are broken by even/oddness of the current floor.
  28. function getClosestFloor(currentFloor, floorList, ignoredFloors = new Set(), direction = IDLE) {
  29. const isEven = (currentFloor % 2 == 0);
  30. let closestFloor = currentFloor,
  31. distance = floorCount,
  32. newDistance = distance;
  33. floorList.forEach(function(floorNum) {
  34. const direction = getDirection(currentFloor, floorNum);
  35. newDistance = Math.abs(currentFloor - floorNum);
  36. if (newDistance < distance && newDistance > 0 && !(ignoredFloors.has(floorNum))) {
  37. closestFloor = floorNum;
  38. distance = newDistance;
  39. } else if (newDistance == distance && !(ignoredFloors.has(floorNum))) {
  40. if (isEven && direction == UP) {
  41. closestFloor = floorNum;
  42. } else if (!isEven && direction == DOWN) {
  43. closestFloor = floorNum;
  44. }
  45. }
  46. });
  47. if (closestFloor != currentFloor) {
  48. return closestFloor;
  49. } else {
  50. throw new Error("No floor in selected direction");
  51. }
  52. }
  53. // getNextFloor chooses the best destination for an elevator
  54. // when given the index of the elevator, along with all
  55. // destinations, requests, and rest floors.
  56. function getNextFloor(elevators, elevatorIndex, destinations, requests, restFloors) {
  57. let elevator = elevators[elevatorIndex],
  58. floorNum = restFloors[MED];
  59. if (requests[UP].size == 0 && requests[DOWN].size == 0 && destinations.size == 0) {
  60. // No people; send to rest floor
  61. } else if (destinations.size == 0) {
  62. // No destinations; send to pick up passengers
  63. try {
  64. floorNum = getClosestFloor(elevator.currentFloor(), new Set([...requests[UP], ...requests[DOWN]]));
  65. } catch (e) {
  66. console.log("ERROR: Requests set was empty");
  67. }
  68. } else {
  69. // Prioritize dropping off current passengers
  70. try {
  71. floorNum = getClosestFloor(elevator.currentFloor(), destinations);
  72. } catch (e) {
  73. console.log("ERROR: Destinations set was empty");
  74. }
  75. }
  76. return floorNum;
  77. }
  78. // getClosestElevator takes a floor number and returns the
  79. // index of the closest elevator.
  80. function getClosestElevator(floorNum) {
  81. let closestElevator = 0,
  82. distance = floorCount,
  83. newDistance = distance;
  84. elevators.forEach(function(elevator, elevatorIndex) {
  85. newDistance = Math.abs(elevator.currentFloor() - floorNum);
  86. if (newDistance < distance) {
  87. distance = newDistance;
  88. closestElevator = elevatorIndex;
  89. }
  90. });
  91. //console.log("Closest is elevator[" + closestElevator + "]")
  92. return closestElevator;
  93. }
  94. // getDirection get the direction (up or down) that an elevator
  95. // will need to travel to get to a specified floor
  96. function getDirection(currentFloor, floorNum) {
  97. const distance = currentFloor - floorNum;
  98. let direction = IDLE;
  99. if (distance > 0 || currentFloor == topFloor) {
  100. direction = DOWN;
  101. } else if (distance < 0 || currentFloor == bottomFloor) {
  102. direction = UP;
  103. }
  104. return direction;
  105. }
  106. // setDirection changes the indicator lights on a specified
  107. // elevator to match the given direction.
  108. function setDirection(elevator, direction) {
  109. switch (direction) {
  110. case UP:
  111. elevator.goingUpIndicator(true);
  112. elevator.goingDownIndicator(false);
  113. break;
  114. case DOWN:
  115. elevator.goingUpIndicator(false);
  116. elevator.goingDownIndicator(true);
  117. break;
  118. default:
  119. elevator.goingUpIndicator(true);
  120. elevator.goingDownIndicator(true);
  121. }
  122. }
  123. // ----
  124. // Floors
  125. // ----
  126. floors.forEach(function(floor) {
  127. floor.on("up_button_pressed", function() {
  128. //console.log("> Up request on floor[" + floor.level + "]");
  129. requests[UP].add(floor.level);
  130. });
  131. floor.on("down_button_pressed", function() {
  132. //console.log("> Down request on floor[" + floor.level + "]");
  133. requests[DOWN].add(floor.level);
  134. });
  135. });
  136. // ----
  137. // Elevators
  138. // ----
  139. elevators.forEach(function(elevator, elevatorIndex) {
  140. // Elevator info and variables
  141. const restFloors = [
  142. elevatorIndex * Math.floor(floorCount / (elevatorCount + 1)),
  143. (elevatorIndex + 1) * Math.floor(floorCount / (elevatorCount + 1)),
  144. (elevatorIndex + 2) * Math.floor(floorCount / (elevatorCount + 1))
  145. ];
  146. let destinations = new Set(),
  147. nextFloor = restFloors[LOW];
  148. // Start
  149. setDirection(elevator, UP); // Starts on the ground floor, must be going up
  150. console.log("> Elevator[" + elevatorIndex + "] rest floors are " + restFloors[LOW] + ", " + restFloors[MED] + ", and " + restFloors[HIGH] + ". Starting at " + restFloors[LOW] + ".");
  151. elevator.goToFloor(nextFloor); // Nearest rest floor
  152. // Idle
  153. elevator.on("idle", function() {
  154. //console.log("> Elevator[" + elevatorIndex + "] is idle")
  155. nextFloor = getNextFloor(elevators, elevatorIndex, destinations, requests, restFloors);
  156. elevator.goToFloor(nextFloor);
  157. });
  158. // Passing
  159. elevator.on("passing_floor", function(floorNum, direction) {
  160. if (destinations.has(floorNum) ||
  161. (elevator.loadFactor() < 1 &&
  162. (elevator.destinationDirection() == "up" && requests[UP].has(floorNum)) ||
  163. (elevator.destinationDirection() == "down" && requests[DOWN].has(floorNum)))) {
  164. elevator.goToFloor(floorNum, true);
  165. }
  166. });
  167. // Buttons
  168. elevator.on("floor_button_pressed", function(floorNum) {
  169. //console.log("> Pressed floor[" + floorNum + "] on elevator[" + elevatorIndex + "]");
  170. destinations.add(floorNum);
  171. });
  172. // Stopped
  173. elevator.on("stopped_at_floor", function(floorNum) {
  174. //console.log("> elevator[" + elevatorIndex + "] stopped at floor[" + floorNum + "]");
  175. let isNext = (elevator.currentFloor() == nextFloor);
  176. destinations.delete(floorNum);
  177. if (isNext) {
  178. nextFloor = getNextFloor(elevators, elevatorIndex, destinations, requests, restFloors);
  179. setDirection(elevator, getDirection(elevator.currentFloor(), nextFloor));
  180. }
  181. if (elevator.goingUpIndicator() == true) {
  182. requests[UP].delete(floorNum);
  183. }
  184. if (elevator.goingDownIndicator() == true) {
  185. requests[DOWN].delete(floorNum);
  186. }
  187. if (isNext) {
  188. elevator.goToFloor(nextFloor);
  189. }
  190. });
  191. });
  192. },
  193. update: function(dt, elevators, floors) {}
  194. });