forked from mshang/python-elevator-challenge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathelevator.py
155 lines (126 loc) · 5.67 KB
/
elevator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
UP = 1
DOWN = 2
OUT = 0
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.callbacks = None
self.requests = []
self.direction = 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.
floor: the floor that the elevator is being called to
direction: the direction the caller wants to go, up or down
"""
if self.is_stopped_at_floor(floor):
return
if self.floor_is_upcoming(floor):
self.requests.insert(0, {"floor": floor, "direction": direction})
else:
self.requests.append({"floor": floor, "direction": direction})
def floor_is_upcoming(self, floor):
if self.direction == UP:
return self.higher_than_current_floor(floor)
elif self.direction == DOWN:
return self.lower_than_current_floor(floor)
def is_stopped_at_floor(self, floor):
return self.equal_to_current_floor(floor) and self.callbacks.motor_direction == None
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.
floor: the floor that was requested
"""
if self.request_is_in_opposite_direction(floor) or self.has_request_at_floor(floor):
return
if self.higher_than_current_floor(floor):
self.direction = UP
elif self.lower_than_current_floor(floor):
self.direction = DOWN
else:
return
self.requests.insert(0, {"floor": floor, "direction": OUT})
def request_is_in_opposite_direction(self, floor):
if self.direction == UP:
return self.lower_than_current_floor(floor)
elif self.direction == DOWN:
return self.higher_than_current_floor(floor)
def has_request_at_floor(self, floor):
return len(self.requests_for_floor(floor)) > 0
def requests_for_floor(self, floor):
return filter(lambda request: request["floor"] == floor, self.requests)
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.
"""
fulfilled_requests = []
for request in self.requests_for_floor(self.callbacks.current_floor):
if self.should_stop_at_floor(request):
self.callbacks.motor_direction = None
fulfilled_requests.append(request)
direction = request["direction"]
self.remove_requests(fulfilled_requests)
if self.has_no_requests():
self.direction = direction
def should_stop_at_floor(self, request):
return self.servable_request(request) or not self.has_further_requests()
def servable_request(self, request):
is_current_floor = self.equal_to_current_floor(request["floor"])
correct_direction = self.callbacks.motor_direction == request["direction"]
out_request = request["direction"] == OUT
return is_current_floor and (correct_direction or out_request)
def has_further_requests(self):
for request in self.requests:
if self.servable_request(request) or self.floor_is_upcoming(request["floor"]):
return True
return False
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.has_no_requests():
self.direction = None
return
next_floor = self.requests[0]["floor"]
if self.higher_than_current_floor(next_floor):
self.callbacks.motor_direction = self.direction = UP
elif self.lower_than_current_floor(next_floor):
self.callbacks.motor_direction = self.direction = DOWN
else:
self.direction = self.opposite_direction()
requests_for_removal = self.requests_for_floor(self.callbacks.current_floor)
self.remove_requests(requests_for_removal)
def opposite_direction(self):
if self.direction == UP:
return DOWN
elif self.direction == DOWN:
return UP
def remove_requests(self, requests):
for request in requests:
self.requests.remove(request)
def has_no_requests(self):
return len(self.requests) == 0
def higher_than_current_floor(self, floor):
return floor > self.callbacks.current_floor
def lower_than_current_floor(self, floor):
return floor < self.callbacks.current_floor
def equal_to_current_floor(self, floor):
return floor == self.callbacks.current_floor