Skip to content
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

Solution for Python Elevator Challenge #16

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MyElevator.py
elevator.pyc
fuzzy.md
241 changes: 239 additions & 2 deletions elevator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
DOWN = 2
FLOOR_COUNT = 6

import time

class ElevatorLogic(object):
"""
An incorrect implementation. Can you make it pass all the tests?
Expand All @@ -16,10 +18,23 @@ class ElevatorLogic(object):
elevator by setting the `motor_direction` property. See below for how this is done.
"""

class Call(object):
def __init__(self, floor, time):
self.floor = floor
self.time = time

def __repr__(self):
return "%d" % self.floor

def __init__(self):
# Feel free to add any instance variables you want.
self.destination_floor = None
self.callbacks = None
self.orders = {}
self.orders[UP] = []
self.orders[DOWN] = []
self.current_direction = None
self.bounded_direction = None

def on_called(self, floor, direction):
"""
Expand All @@ -30,7 +45,55 @@ def on_called(self, floor, direction):
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

if not self.valid_floor(floor) or direction not in [UP, DOWN]:
return



direction_to_floor = self.direction_to(floor)

if self.current_direction is None:
# Change direction
self.current_direction = direction_to_floor

if self.callbacks.current_floor != floor:
self.index(direction, floor)
# Reorder
self.sort(UP)
self.sort(DOWN)
if self.current_direction == UP and self.orders[UP]:
self.destination_floor = self.orders[UP][0].floor
else:
self.destination_floor = self.orders[direction][0].floor
else:
# Missed the boat, come back later
self.index(self.other_direction(self.current_direction), floor)

# print "direction to floor: ", self.direction_str(direction_to_floor)
self.log("on called")

def index(self, direction, floor):
if not direction:
return
self.orders[direction].insert(0, self.Call(floor, time.time()))

def sort(self, direction):
if direction == UP:
if self.callbacks.motor_direction:
self.orders[UP].sort(key=lambda x: x.floor)
elif all(x.floor > self.callbacks.current_floor for x in self.orders[UP]):
self.orders[UP].sort(key=lambda x: x.floor)
else:
self.orders[UP].sort(key=lambda x: x.time)
elif direction == DOWN:
self.orders[DOWN].sort(key=lambda x: x.time, reverse=True)
else:
pass

@staticmethod
def valid_floor(floor):
return floor >= 1 or floor <= FLOOR_COUNT

def on_floor_selected(self, floor):
"""
Expand All @@ -40,23 +103,197 @@ def on_floor_selected(self, floor):

floor: the floor that was requested
"""
self.destination_floor = floor

if not self.valid_floor(floor):
return


direction_to_floor = self.direction_to(floor)

if direction_to_floor is None:
self.log("missed the boat")
return

# Check the other queue for duplicates
other_direction = self.other_direction(direction_to_floor)
if self.orders[other_direction]:
_floor = self.orders[other_direction][0].floor
if _floor == floor:
# Serve that, but not this floor request (line 485)
return

if self.bounded_direction:
self.log("floor selected. bounded direction detected. direction to floor %d: %s"
% (floor, self.direction_str(direction_to_floor))
)
if direction_to_floor == self.bounded_direction:
self.current_direction = self.bounded_direction
self.bounded_direction = None
else:
self.log("floor selection ignored. Mismatch between bounded direction and direction to floor selected")
# self.bounded_direction = None
return

if self.current_direction and self.current_direction != direction_to_floor:
# Set it to wait for requests to move to the other direction
other_direction = self.other_direction(self.current_direction)
self.current_direction = other_direction
self.log("""\
floor selection ignored.
floor selected: %d
Direction to floor: %s.
Must wait for requests to move to the other direction"""
% (floor, self.direction_str(direction_to_floor)))
# Clear for the next call
if self.callbacks.current_floor == self.destination_floor:
self.log("Clear for the next call")
# Reverse again
other_direction = self.other_direction(other_direction)
if self.orders[other_direction] and self.orders[other_direction][0].floor == self.callbacks.current_floor:
self.orders[other_direction].pop(0)
self.current_direction = None
return

self.index(direction_to_floor, floor)

# sort the list so closer floors are attended first
# self.orders[direction_to_floor].sort()
self.sort(direction_to_floor)

if self.current_direction is None:
self.current_direction = direction_to_floor

self.destination_floor = self.orders[self.current_direction][0].floor

self.log("on floor selected")

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:
self.log("on change. Destiny %d reached" % self.destination_floor)
self.callbacks.motor_direction = None

if self.current_direction and self.orders[self.current_direction]:
self.orders[self.current_direction].pop(0)
else:
if self.current_direction and self.orders[self.other_direction(self.current_direction)]:
self.orders[self.other_direction(self.current_direction)].pop(0) # something had to be served (

if self.current_direction and self.orders[self.current_direction]:
next_destination = self.orders[self.current_direction][0].floor
if next_destination != self.callbacks.current_floor:
self.destination_floor = next_destination
else:
self.orders[self.current_direction].pop(0) # drop it, already there
self.destination_floor = None
self.bounded_direction = self.current_direction

else:
self.bounded_direction = self.current_direction

if self.current_direction and not self.orders[self.current_direction]:
other_direction = self.other_direction(self.current_direction)
if other_direction and self.orders[other_direction]:
self.current_direction = other_direction
# Set the new target floor
if self.orders[self.current_direction]:
self.destination_floor = self.orders[self.current_direction][0].floor

if self.is_idle():
self.current_direction = None # Elevator is idle

if self.callbacks.current_floor <= 1 and self.callbacks.motor_direction == DOWN:
# self.callbacks.current_floor = 1
self.callbacks.motor_direction = None
self.current_direction = None
self.bounded_direction = None

if self.callbacks.motor_direction == UP and self.callbacks.current_floor == FLOOR_COUNT:
self.callbacks.motor_direction = DOWN
self.bounded_direction = None
self.destination_floor = FLOOR_COUNT

self.log("on_changed")

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 and not self.valid_floor(self.destination_floor):
self.destination_floor = None
self.callbacks.motor_direction = None



# print "on ready: dest floor: %d" % self.destination_floor
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
else:
self.bounded_direction = None

if self.callbacks.motor_direction == DOWN and self.callbacks.current_floor == 1:
self.callbacks.motor_direction = None

if self.callbacks.motor_direction == UP and self.callbacks.current_floor == FLOOR_COUNT:
self.callbacks.motor_direction = None
self.bounded_direction = None
self.destination_floor = None


self.log("on ready")

def direction_to(self, floor):
direction = None
if floor > self.callbacks.current_floor:
direction = UP
elif floor < self.callbacks.current_floor:
direction = DOWN
return direction

def is_idle(self):
return not self.orders[UP] and not self.orders[DOWN]

@staticmethod
def other_direction(direction):
if UP == direction:
return DOWN
if DOWN == direction:
return UP
return None

@staticmethod
def direction_str(direction):
if UP == direction:
return "UP"
elif DOWN == direction:
return "DOWN"
else:
return "None"

def status(self):
return """\
Current direction: %s
Current floor: %s
Destination floor: %s
Bounded direction: %s
orders UP: %s
orders DOWN: %s
""" % (self.direction_str(self.current_direction),
self.callbacks.current_floor,
self.destination_floor,
self.direction_str(self.bounded_direction),
self.orders[UP],
self.orders[DOWN])

def log(self, msg):
# print "%s. \nstatus:\n%s" % (msg, self.status())
pass