Skip to content

Implement elevator logic #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 98 additions & 44 deletions elevator.py
Original file line number Diff line number Diff line change
@@ -1,62 +1,116 @@
#!/usr/bin/env python

UP = 1
DOWN = 2
FLOOR_COUNT = 6

class ElevatorLogic(object):
"""
An incorrect implementation. Can you make it pass all the tests?

Fix the methods below to implement the correct logic for elevators.
The tests are integrated into `README.md`. To run the tests:
$ python -m doctest -v README.md

To learn when each method is called, read its docstring.
To interact with the world, you can get the current floor from the
`current_floor` property of the `callbacks` object, and you can move the
elevator by setting the `motor_direction` property. See below for how this is done.
"""

def __init__(self):
# Feel free to add any instance variables you want.
self.destination_floor = None
# Required.
self.callbacks = None

def on_called(self, floor, direction):
"""
This is called when somebody presses the up or down button to call the elevator.
This could happen at any time, whether or not the elevator is moving.
The elevator could be requested at any floor at any time, going in either direction.
# Current elevator direction.
self._direction = None

# Pending requests. A request is a pair (floor, direction), in which
# direction can be None if the floor was selected from the elevator, or
# a given direction if the elevator was called from a floor. Telling
# both cases apart is actually needed.
self._requests = set()

floor: the floor that the elevator is being called to
direction: the direction the caller wants to go, up or down
"""
self.destination_floor = floor
def _try_add(self, floor, direction):
# Basic checks when storing a new request.
if ((floor, direction) not in self._requests
and floor >= 1 and floor <= FLOOR_COUNT
and (self.callbacks.current_floor != floor
or self.callbacks.motor_direction is not None)):

# Save the request.
self._requests.add((floor, direction))

# Set direction now if possible. This gives priority to earliest
# requests first.
if self._direction is None:
cur = self.callbacks.current_floor
if floor < cur:
self._direction = DOWN
elif floor > cur:
self._direction = UP
elif direction is not None:
self._direction = direction

def on_called(self, floor, direction):
self._try_add(floor, direction)

def on_floor_selected(self, floor):
"""
This is called when somebody on the elevator chooses a floor.
This could happen at any time, whether or not the elevator is moving.
Any floor could be requested at any time.
# This call requires a few additional checks to ignore floors that
# contradict the current direction.
cur = self.callbacks.current_floor
if (self._direction is None or
(self._direction == UP and floor > cur) or
(self._direction == DOWN and floor < cur)):
self._try_add(floor, None)

floor: the floor that was requested
"""
self.destination_floor = floor
def _any_above(self, floor):
return any(f > floor for (f, d) in self._requests)

def _any_below(self, floor):
return any(f < floor for (f, d) in self._requests)

# Any requests in my current direction?
def _should_continue(self):
cur = self.callbacks.current_floor
return ((self._direction == UP and self._any_above(cur))
or (self._direction == DOWN and self._any_below(cur)))

def _opposite(self):
if self._direction is None:
return None
if self._direction == UP:
return DOWN
return UP

def on_floor_changed(self):
"""
This lets you know that the elevator has moved one floor up or down.
You should decide whether or not you want to stop the elevator.
"""
if self.destination_floor == self.callbacks.current_floor:
cur = self.callbacks.current_floor

# Reasons to stop:
# (a) Passenger requested the current floor.
# (b) Current floor requested in the current direction.
# (c) No further requests in this direction.
if ((cur, None) in self._requests or
(cur, self._direction) in self._requests or
(not self._should_continue())):

self.callbacks.motor_direction = None

# Deal with (a).
self._requests.discard((cur, None))

# Now maybe (b) or, if not, maybe (c).
aux = (cur, self._direction)
if aux in self._requests:
self._requests.discard(aux)
elif not self._should_continue():
aux = (cur, self._opposite())
if aux in self._requests:
self._requests.discard(aux)
self._direction = self._opposite()

def on_ready(self):
"""
This is called when the elevator is ready to go.
Maybe passengers have embarked and disembarked. The doors are closed,
time to actually move, if necessary.
"""
if self.destination_floor > self.callbacks.current_floor:
self.callbacks.motor_direction = UP
elif self.destination_floor < self.callbacks.current_floor:
self.callbacks.motor_direction = DOWN
# Continue in the current direction if possible.
if self._should_continue():
self.callbacks.motor_direction = self._direction

# Forget direction when done.
elif len(self._requests) == 0:
self._direction = None

else:
# Change direction. Serve curent floor or start motor.
aux = (self.callbacks.current_floor, self._opposite())
if aux in self._requests:
self._requests.discard(aux)
else:
self.callbacks.motor_direction = self._opposite()
self._direction = self._opposite()