Code for Elevator Saga
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

elevator.js 7.0KB

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