├── .travis.yml ├── LICENSE ├── README.md └── elevator.py /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | script: python -m doctest README.md 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Miles Shang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # So You Think You Can Program An Elevator 2 | 3 | Many of us ride elevators every day. We feel like we understand how they work, how they decide where to go. If you were asked to put it into words, you might say that an elevator goes wherever it's told, and in doing so goes as far in one direction as it can before turning around. Sounds simple, right? Can you put it into code? 4 | 5 | In this challenge, you are asked to implement the business logic for a simplified elevator model in Python. We'll ignore a lot of what goes into a real world elevator, like physics, maintenance overrides, and optimizations for traffic patterns. All you are asked to do is to decide whether the elevator should go up, go down, or stop. 6 | 7 | How does the challenge work? The simulator and test harness are laid out in this document, followed by several examples. All of this can be run in an actual Python interpreter using Python's built-in `doctest` functionality, which extracts the code in this document and runs it. 8 | 9 | A naive implementation of the business logic is provided in the `elevator.py` file in this project. If you run `doctest` using the provided implementation, several examples fail to produce the expected output. Your challenge is to fix that implementation until all of the examples pass. 10 | 11 | Open a pull request with your solution. Good luck! Have fun! 12 | 13 | ## Test Harness 14 | 15 | Like all elevators, ours can go up and down. We define constants for these. The elevator also happens to be in a building with six floors. 16 | 17 | >>> UP = 1 18 | >>> DOWN = 2 19 | >>> FLOOR_COUNT = 6 20 | 21 | We will make an `Elevator` class that simulates an elevator. It will delegate to another class which contains the elevator business logic, i.e. deciding what the elevator should do. Your challenge is to implement this business logic class. 22 | 23 | ### User actions 24 | 25 | A user can interact with the elevator in two ways. She can call the elevator by pressing the up or down button on any floor, and she can select a destination floor by pressing the button for that floor on the panel in the elevator. Both of these actions are passed straight through to the logic delegate. 26 | 27 | >>> class Elevator(object): 28 | ... def call(self, floor, direction): 29 | ... self._logic_delegate.on_called(floor, direction) 30 | ... 31 | ... def select_floor(self, floor): 32 | ... self._logic_delegate.on_floor_selected(floor) 33 | 34 | ### Elevator actions 35 | 36 | The logic delegate can respond by setting the elevator to move up, move down, or stop. It can also read the current floor and movement direction of the elevator. These actions are accessed through `Callbacks`, a mediator provided by the `Elevator` class to the logic delegate. 37 | 38 | >>> class Elevator(Elevator): 39 | ... def __init__(self, logic_delegate, starting_floor=1): 40 | ... self._current_floor = starting_floor 41 | ... print "%s..." % starting_floor, 42 | ... self._motor_direction = None 43 | ... self._logic_delegate = logic_delegate 44 | ... self._logic_delegate.callbacks = self.Callbacks(self) 45 | ... 46 | ... class Callbacks(object): 47 | ... def __init__(self, outer): 48 | ... self._outer = outer 49 | ... 50 | ... @property 51 | ... def current_floor(self): 52 | ... return self._outer._current_floor 53 | ... 54 | ... @property 55 | ... def motor_direction(self): 56 | ... return self._outer._motor_direction 57 | ... 58 | ... @motor_direction.setter 59 | ... def motor_direction(self, direction): 60 | ... self._outer._motor_direction = direction 61 | 62 | ### Simulation 63 | 64 | The simulation runs in steps. Each time step consists of the elevator moving a single floor, or pausing at a floor. Either way, the business logic delegate gets notified. Along the way, we print out the movements of the elevator so that we can keep track of it. We also define a few helper methods that advance the simulation to points of interest, for ease of testing. 65 | 66 | >>> class Elevator(Elevator): 67 | ... def step(self): 68 | ... delta = 0 69 | ... if self._motor_direction == UP: delta = 1 70 | ... elif self._motor_direction == DOWN: delta = -1 71 | ... 72 | ... if delta: 73 | ... self._current_floor = self._current_floor + delta 74 | ... print "%s..." % self._current_floor, 75 | ... self._logic_delegate.on_floor_changed() 76 | ... else: 77 | ... self._logic_delegate.on_ready() 78 | ... 79 | ... assert self._current_floor >= 1 80 | ... assert self._current_floor <= FLOOR_COUNT 81 | ... 82 | ... def run_until_stopped(self): 83 | ... self.step() 84 | ... while self._motor_direction is not None: self.step() 85 | ... 86 | ... def run_until_floor(self, floor): 87 | ... for i in range(100): 88 | ... self.step() 89 | ... if self._current_floor == floor: break 90 | ... else: assert False 91 | 92 | That's it for the framework. 93 | 94 | ## Business Logic 95 | 96 | As for the business logic, an example implementation is provided in the `elevator.py` file in this project. 97 | 98 | >>> from elevator import ElevatorLogic 99 | 100 | As provided, it doesn't pass the tests in this document. Your challenge is to fix it so that it does. To run the tests, run this in your shell: 101 | 102 | python -m doctest -v README.md 103 | 104 | With the correct business logic, here's how the elevator should behave: 105 | 106 | ### Basic usage 107 | 108 | Make an elevator. It starts at the first floor. 109 | 110 | >>> e = Elevator(ElevatorLogic()) 111 | 1... 112 | 113 | Somebody on the fifth floor wants to go down. 114 | 115 | >>> e.call(5, DOWN) 116 | 117 | Keep in mind that the simulation won't actually advance until we call `step` or one of the `run_until_*` methods. 118 | 119 | >>> e.run_until_stopped() 120 | 2... 3... 4... 5... 121 | 122 | The elevator went up to the fifth floor. A passenger boards and wants to go to the first floor. 123 | 124 | >>> e.select_floor(1) 125 | 126 | Also, somebody on the third floor wants to go down. 127 | 128 | >>> e.call(3, DOWN) 129 | 130 | Even though the first floor was selected first, the elevator services the call at the third floor... 131 | 132 | >>> e.run_until_stopped() 133 | 4... 3... 134 | 135 | ...before going to the first floor. 136 | 137 | >>> e.run_until_stopped() 138 | 2... 1... 139 | 140 | ### Directionality 141 | 142 | Elevators want to keep going in the same direction. An elevator will serve as many requests in one direction as it can before going the other way. For example, if an elevator is going up, it won't stop to pick up passengers who want to go down until it's done with everything that requires it to go up. 143 | 144 | >>> e = Elevator(ElevatorLogic()) 145 | 1... 146 | >>> e.call(2, DOWN) 147 | >>> e.select_floor(5) 148 | 149 | Even though the elevator was called at the second floor first, it will service the fifth floor... 150 | 151 | >>> e.run_until_stopped() 152 | 2... 3... 4... 5... 153 | 154 | ...before coming back down for the second floor. 155 | 156 | >>> e.run_until_stopped() 157 | 4... 3... 2... 158 | 159 | In fact, if a passenger tries to select a floor that contradicts the current direction of the elevator, that selection is ignored entirely. You've probably seen this before. You call the elevator to go down. The elevator shows up, and you board, not realizing that it's still going up. You select a lower floor. The elevator ignores you. 160 | 161 | >>> e = Elevator(ElevatorLogic()) 162 | 1... 163 | >>> e.select_floor(3) 164 | >>> e.select_floor(5) 165 | >>> e.run_until_stopped() 166 | 2... 3... 167 | >>> e.select_floor(2) 168 | 169 | At this point the elevator is at the third floor. It's not finished going up because it's wanted at the fifth floor. Therefore, selecting the second floor goes against the current direction, so that request is ignored. 170 | 171 | >>> e.run_until_stopped() 172 | 4... 5... 173 | >>> e.run_until_stopped() # nothing happens, because e.select_floor(2) was ignored 174 | 175 | Now it's done going up, so you can select the second floor. 176 | 177 | >>> e.select_floor(2) 178 | >>> e.run_until_stopped() 179 | 4... 3... 2... 180 | 181 | ### Changing direction 182 | 183 | The process of switching directions is a bit tricky. Normally, if an elevator going up stops at a floor and there are no more requests at higher floors, the elevator is free to switch directions right away. However, if the elevator was called to that floor by a user indicating that she wants to go up, the elevator is bound to consider itself going up. 184 | 185 | >>> e = Elevator(ElevatorLogic()) 186 | 1... 187 | >>> e.call(2, DOWN) 188 | >>> e.call(4, UP) 189 | >>> e.run_until_stopped() 190 | 2... 3... 4... 191 | >>> e.select_floor(5) 192 | >>> e.run_until_stopped() 193 | 5... 194 | >>> e.run_until_stopped() 195 | 4... 3... 2... 196 | 197 | If nobody wants to go further up though, the elevator can turn around. 198 | 199 | >>> e = Elevator(ElevatorLogic()) 200 | 1... 201 | >>> e.call(2, DOWN) 202 | >>> e.call(4, UP) 203 | >>> e.run_until_stopped() 204 | 2... 3... 4... 205 | >>> e.run_until_stopped() 206 | 3... 2... 207 | 208 | If the elevator is called in both directions at that floor, it must wait once for each direction. You may have seen this too. Some elevators will close their doors and reopen them to indicate that they have changed direction. 209 | 210 | >>> e = Elevator(ElevatorLogic()) 211 | 1... 212 | >>> e.select_floor(5) 213 | >>> e.call(5, UP) 214 | >>> e.call(5, DOWN) 215 | >>> e.run_until_stopped() 216 | 2... 3... 4... 5... 217 | 218 | Here, the elevator considers itself to be going up, as it favors continuing in the direction it came from. 219 | 220 | >>> e.select_floor(4) # ignored 221 | >>> e.run_until_stopped() 222 | 223 | Since nothing caused the elevator to move further up, it now waits for requests that cause it to move down. 224 | 225 | >>> e.select_floor(6) # ignored 226 | >>> e.run_until_stopped() 227 | 228 | Since nothing caused the elevator to move down, the elevator now considers itself idle. It can move in either direction. 229 | 230 | >>> e.select_floor(6) 231 | >>> e.run_until_stopped() 232 | 6... 233 | 234 | ### En passant 235 | 236 | Keep in mind that a user could call the elevator or select a floor at any time. The elevator need not be stopped. If the elevator is called or a floor is selected before it has reached the floor in question, then the request should be serviced. 237 | 238 | >>> e = Elevator(ElevatorLogic()) 239 | 1... 240 | >>> e.select_floor(6) 241 | >>> e.run_until_floor(2) # elevator is not stopped 242 | 2... 243 | >>> e.select_floor(3) 244 | >>> e.run_until_stopped() # stops for above 245 | 3... 246 | >>> e.run_until_floor(4) 247 | 4... 248 | >>> e.call(5, UP) 249 | >>> e.run_until_stopped() # stops for above 250 | 5... 251 | 252 | On the other hand, if the elevator is already at, or has passed the floor in question, then the request should be treated like a request in the wrong direction. That is to say, a call is serviced later, and a floor selection is ignored. 253 | 254 | >>> e = Elevator(ElevatorLogic()) 255 | 1... 256 | >>> e.select_floor(5) 257 | >>> e.run_until_floor(2) 258 | 2... 259 | >>> e.call(2, UP) # missed the boat, come back later 260 | >>> e.step() # doesn't stop 261 | 3... 262 | >>> e.select_floor(3) # missed the boat, ignored 263 | >>> e.step() # doesn't stop 264 | 4... 265 | >>> e.run_until_stopped() # service e.select_floor(5) 266 | 5... 267 | >>> e.run_until_stopped() # service e.call(2, UP) 268 | 4... 3... 2... 269 | 270 | ## Fuzz testing 271 | 272 | No amount of legal moves should compel the elevator to enter an illegal state. Here, we run a bunch of random requests against the simulator to make sure that no asserts are triggered. 273 | 274 | >>> import random 275 | >>> e = Elevator(ElevatorLogic()) 276 | 1... 277 | >>> try: print '-', # doctest:+ELLIPSIS 278 | ... finally: 279 | ... for i in range(100000): 280 | ... r = random.randrange(6) 281 | ... if r == 0: e.call( 282 | ... random.randrange(FLOOR_COUNT) + 1, 283 | ... random.choice((UP, DOWN))) 284 | ... elif r == 1: e.select_floor(random.randrange(FLOOR_COUNT) + 1) 285 | ... else: e.step() 286 | - ... 287 | 288 | 289 | ## More Examples 290 | 291 | The rest of these examples may be useful for catching bugs. They are meant to be run via doctest, so they may not be very interesting to read through. 292 | 293 | An elevator is called but nobody boards. It goes idle. 294 | 295 | >>> e = Elevator(ElevatorLogic()) 296 | 1... 297 | >>> e.call(5, UP) 298 | >>> e.run_until_stopped() 299 | 2... 3... 4... 5... 300 | >>> e.run_until_stopped() 301 | >>> e.run_until_stopped() 302 | 303 | The elevator is called at two different floors. 304 | 305 | >>> e = Elevator(ElevatorLogic()) 306 | 1... 307 | >>> e.call(3, UP) 308 | >>> e.call(5, UP) 309 | >>> e.run_until_stopped() 310 | 2... 3... 311 | >>> e.run_until_stopped() 312 | 4... 5... 313 | 314 | Like above, but called in reverse order. 315 | 316 | >>> e = Elevator(ElevatorLogic()) 317 | 1... 318 | >>> e.call(5, UP) 319 | >>> e.call(3, UP) 320 | >>> e.run_until_stopped() 321 | 2... 3... 322 | >>> e.run_until_stopped() 323 | 4... 5... 324 | 325 | The elevator is called at two different floors, but going the other direction. 326 | 327 | >>> e = Elevator(ElevatorLogic()) 328 | 1... 329 | >>> e.call(3, DOWN) 330 | >>> e.call(5, DOWN) 331 | >>> e.run_until_stopped() 332 | 2... 3... 4... 5... 333 | >>> e.run_until_stopped() 334 | 4... 3... 335 | 336 | The elevator is called at two different floors, going in opposite directions. 337 | 338 | >>> e = Elevator(ElevatorLogic()) 339 | 1... 340 | >>> e.call(3, UP) 341 | >>> e.call(5, DOWN) 342 | >>> e.run_until_stopped() 343 | 2... 3... 344 | >>> e.run_until_stopped() 345 | 4... 5... 346 | 347 | Like above, but with directions reversed. 348 | 349 | >>> e = Elevator(ElevatorLogic()) 350 | 1... 351 | >>> e.call(3, DOWN) 352 | >>> e.call(5, UP) 353 | >>> e.run_until_stopped() 354 | 2... 3... 4... 5... 355 | >>> e.run_until_stopped() 356 | 4... 3... 357 | 358 | The elevator is called at two different floors, one above the current floor and one below. It first goes to the floor where it was called first. 359 | 360 | >>> e = Elevator(ElevatorLogic(), 3) 361 | 3... 362 | >>> e.call(2, UP) 363 | >>> e.call(4, UP) 364 | >>> e.run_until_stopped() 365 | 2... 366 | >>> e.run_until_stopped() 367 | 3... 4... 368 | 369 | Like above, but called in reverse order. 370 | 371 | >>> e = Elevator(ElevatorLogic(), 3) 372 | 3... 373 | >>> e.call(4, UP) 374 | >>> e.call(2, UP) 375 | >>> e.run_until_stopped() 376 | 4... 377 | >>> e.run_until_stopped() 378 | 3... 2... 379 | 380 | The elevator is called while it's already moving. 381 | 382 | >>> e = Elevator(ElevatorLogic()) 383 | 1... 384 | >>> e.call(5, UP) 385 | >>> e.run_until_floor(2) 386 | 2... 387 | >>> e.call(3, UP) 388 | >>> e.run_until_stopped() 389 | 3... 390 | >>> e.run_until_stopped() 391 | 4... 5... 392 | 393 | If the elevator is already at, or has passed the floor where it was called, it comes back later. 394 | 395 | >>> e = Elevator(ElevatorLogic()) 396 | 1... 397 | >>> e.call(5, UP) 398 | >>> e.run_until_floor(3) 399 | 2... 3... 400 | >>> e.call(3, UP) 401 | >>> e.run_until_stopped() 402 | 4... 5... 403 | >>> e.run_until_stopped() 404 | 4... 3... 405 | 406 | Two floors are selected. 407 | 408 | >>> e = Elevator(ElevatorLogic()) 409 | 1... 410 | >>> e.select_floor(3) 411 | >>> e.select_floor(5) 412 | >>> e.run_until_stopped() 413 | 2... 3... 414 | >>> e.run_until_stopped() 415 | 4... 5... 416 | 417 | Like above, but selected in reverse order. 418 | 419 | >>> e = Elevator(ElevatorLogic()) 420 | 1... 421 | >>> e.select_floor(5) 422 | >>> e.select_floor(3) 423 | >>> e.run_until_stopped() 424 | 2... 3... 425 | >>> e.run_until_stopped() 426 | 4... 5... 427 | 428 | Two floors are selected, one above the current floor and one below. The first selection sets the direction, so the second one is completely ignored. 429 | 430 | >>> e = Elevator(ElevatorLogic(), 3) 431 | 3... 432 | >>> e.select_floor(2) 433 | >>> e.select_floor(4) 434 | >>> e.run_until_stopped() 435 | 2... 436 | >>> e.run_until_stopped() 437 | 438 | Like above, but selected in reverse order. 439 | 440 | >>> e = Elevator(ElevatorLogic(), 3) 441 | 3... 442 | >>> e.select_floor(4) 443 | >>> e.select_floor(2) 444 | >>> e.run_until_stopped() 445 | 4... 446 | >>> e.run_until_stopped() 447 | 448 | If the elevator is called to a floor going up, it should ignore a request to go down. 449 | 450 | >>> e = Elevator(ElevatorLogic()) 451 | 1... 452 | >>> e.call(5, UP) 453 | >>> e.run_until_stopped() 454 | 2... 3... 4... 5... 455 | >>> e.select_floor(6) 456 | >>> e.select_floor(4) 457 | >>> e.run_until_stopped() 458 | 6... 459 | >>> e.run_until_stopped() 460 | 461 | Like above, but going in other direction. 462 | 463 | >>> e = Elevator(ElevatorLogic()) 464 | 1... 465 | >>> e.call(5, DOWN) 466 | >>> e.run_until_stopped() 467 | 2... 3... 4... 5... 468 | >>> e.select_floor(6) 469 | >>> e.select_floor(4) 470 | >>> e.run_until_stopped() 471 | 4... 472 | >>> e.run_until_stopped() 473 | 474 | Elevator is called to a floor and a passenger also selects the same floor. The elevator should not go back to that floor twice. 475 | 476 | >>> e = Elevator(ElevatorLogic()) 477 | 1... 478 | >>> e.call(5, DOWN) 479 | >>> e.select_floor(5) 480 | >>> e.run_until_stopped() 481 | 2... 3... 4... 5... 482 | >>> e.select_floor(4) 483 | >>> e.run_until_stopped() 484 | 4... 485 | >>> e.run_until_stopped() 486 | 487 | Similarly, if the elevator is called at a floor where it is stopped, it should not go back later. 488 | 489 | >>> e = Elevator(ElevatorLogic()) 490 | 1... 491 | >>> e.call(3, UP) 492 | >>> e.run_until_stopped() 493 | 2... 3... 494 | >>> e.call(3, UP) 495 | >>> e.call(5, DOWN) 496 | >>> e.run_until_stopped() 497 | 4... 5... 498 | >>> e.run_until_stopped() 499 | 500 | Elevator is ready to change direction, new call causes it to keep going in same direction. 501 | 502 | >>> e = Elevator(ElevatorLogic()) 503 | 1... 504 | >>> e.call(2, DOWN) 505 | >>> e.call(4, UP) 506 | >>> e.run_until_stopped() 507 | 2... 3... 4... 508 | >>> e.call(5, DOWN) # It's not too late. 509 | >>> e.run_until_stopped() 510 | 5... 511 | >>> e.run_until_stopped() 512 | 4... 3... 2... 513 | 514 | When changing directions, wait one step to clear current direction. 515 | 516 | >>> e = Elevator(ElevatorLogic()) 517 | 1... 518 | >>> e.select_floor(5) 519 | >>> e.call(5, UP) 520 | >>> e.call(5, DOWN) 521 | >>> e.run_until_stopped() 522 | 2... 3... 4... 5... 523 | >>> e.select_floor(4) # ignored 524 | >>> e.run_until_stopped() 525 | >>> e.select_floor(6) # ignored 526 | >>> e.select_floor(4) 527 | >>> e.run_until_stopped() 528 | 4... 529 | >>> e.run_until_stopped() 530 | 531 | Like above, but going in other direction. 532 | 533 | >>> e = Elevator(ElevatorLogic(), 6) 534 | 6... 535 | >>> e.select_floor(2) 536 | >>> e.call(2, UP) 537 | >>> e.call(2, DOWN) 538 | >>> e.run_until_stopped() 539 | 5... 4... 3... 2... 540 | >>> e.select_floor(3) # ignored 541 | >>> e.run_until_stopped() 542 | >>> e.select_floor(1) # ignored 543 | >>> e.select_floor(3) 544 | >>> e.run_until_stopped() 545 | 3... 546 | >>> e.run_until_stopped() 547 | 548 | If other direction is not cleared, come back. 549 | 550 | >>> e = Elevator(ElevatorLogic()) 551 | 1... 552 | >>> e.select_floor(5) 553 | >>> e.call(5, UP) 554 | >>> e.call(5, DOWN) 555 | >>> e.run_until_stopped() 556 | 2... 3... 4... 5... 557 | >>> e.select_floor(6) 558 | >>> e.run_until_stopped() 559 | 6... 560 | >>> e.run_until_stopped() 561 | 5... 562 | >>> e.select_floor(6) # ignored 563 | >>> e.select_floor(4) 564 | >>> e.run_until_stopped() 565 | 4... 566 | >>> e.run_until_stopped() 567 | 568 | -------------------------------------------------------------------------------- /elevator.py: -------------------------------------------------------------------------------- 1 | UP = 1 2 | DOWN = 2 3 | FLOOR_COUNT = 6 4 | 5 | class ElevatorLogic(object): 6 | """ 7 | An incorrect implementation. Can you make it pass all the tests? 8 | 9 | Fix the methods below to implement the correct logic for elevators. 10 | The tests are integrated into `README.md`. To run the tests: 11 | $ python -m doctest -v README.md 12 | 13 | To learn when each method is called, read its docstring. 14 | To interact with the world, you can get the current floor from the 15 | `current_floor` property of the `callbacks` object, and you can move the 16 | elevator by setting the `motor_direction` property. See below for how this is done. 17 | """ 18 | 19 | def __init__(self): 20 | # Feel free to add any instance variables you want. 21 | self.destination_floor = None 22 | self.callbacks = None 23 | 24 | def on_called(self, floor, direction): 25 | """ 26 | This is called when somebody presses the up or down button to call the elevator. 27 | This could happen at any time, whether or not the elevator is moving. 28 | The elevator could be requested at any floor at any time, going in either direction. 29 | 30 | floor: the floor that the elevator is being called to 31 | direction: the direction the caller wants to go, up or down 32 | """ 33 | self.destination_floor = floor 34 | 35 | def on_floor_selected(self, floor): 36 | """ 37 | This is called when somebody on the elevator chooses a floor. 38 | This could happen at any time, whether or not the elevator is moving. 39 | Any floor could be requested at any time. 40 | 41 | floor: the floor that was requested 42 | """ 43 | self.destination_floor = floor 44 | 45 | def on_floor_changed(self): 46 | """ 47 | This lets you know that the elevator has moved one floor up or down. 48 | You should decide whether or not you want to stop the elevator. 49 | """ 50 | if self.destination_floor == self.callbacks.current_floor: 51 | self.callbacks.motor_direction = None 52 | 53 | def on_ready(self): 54 | """ 55 | This is called when the elevator is ready to go. 56 | Maybe passengers have embarked and disembarked. The doors are closed, 57 | time to actually move, if necessary. 58 | """ 59 | if self.destination_floor > self.callbacks.current_floor: 60 | self.callbacks.motor_direction = UP 61 | elif self.destination_floor < self.callbacks.current_floor: 62 | self.callbacks.motor_direction = DOWN 63 | --------------------------------------------------------------------------------