diff options
author | raylu <lurayl@gmail.com> | 2016-02-22 21:38:26 -0800 |
---|---|---|
committer | raylu <lurayl@gmail.com> | 2016-02-22 21:59:35 -0800 |
commit | e6bb1edfc2f16c7d75d7f849bef08397e7a968d2 (patch) | |
tree | 05a013ba4c6e2fa6f37bc1c3add7766290945d9b /elevator.py | |
parent | c4bfe29b8fb90ea805201f6b741d757bc49f59d4 (diff) | |
download | elevator-master.tar.xz |
Diffstat (limited to 'elevator.py')
-rwxr-xr-x | elevator.py | 88 |
1 files changed, 79 insertions, 9 deletions
diff --git a/elevator.py b/elevator.py index 4a60ece..8ab5517 100755 --- a/elevator.py +++ b/elevator.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +import copy from enum import Enum class Elevator: @@ -7,9 +8,11 @@ class Elevator: self.id = e_id self.floor = floor self.goal = goal + self.pickup_direction = None # the direction we're handling pickup requests for self.dropoffs = [] def direction(self): + ' the direction the elevator is currently moving in ' if self.goal is None: return None if self.goal > self.floor: @@ -22,12 +25,14 @@ class Elevator: assert self.goal is not None return assert floor != self.floor + assert self.pickup_direction is None if self.goal is None: self.goal = floor self.dropoffs.append(floor) else: direction = self.direction() + # TODO: handle opposite direction dropoffs if direction == Direction.UP: if floor > self.goal: self.goal = floor @@ -39,6 +44,42 @@ class Elevator: self.dropoffs.append(floor) self.dropoffs.sort(reverse=True) + def estimate_pickup_time(self, floor, direction): + # while dropping off, can handle requests in same elevator dir in between current and goal + # while picking up, can handle requests in same dir as request dir + # when requested floor is in dir of elevator + our_dir = self.direction() + if our_dir is None: + return abs(floor - self.floor) + + if self.dropoffs: # we are moving and have dropoffs + if our_dir == Direction.UP: + if self.floor <= floor and direction == our_dir: + return floor - self.floor + else: + to_goal = self.goal - self.floor + to_request = abs(self.goal - floor) + return to_goal + to_request + else: + if self.floor >= floor and direction == our_dir: + return self.floor - floor + else: + to_goal = self.floor - self.goal + to_request = abs(self.goal - floor) + return to_goal + to_request + else: # we are moving to pick up a request + assert self.pickup_direction is not None + if our_dir == Direction.UP: + if self.floor <= floor <= self.goal and direction == self.pickup_direction: + return floor - self.floor + else: + return float('inf') + else: + if self.floor >= floor >= self.goal and direction == self.pickup_direction: + return self.floor - floor + else: + return float('inf') + def __repr__(self): attrs = ', '.join('%s=%s' % t for t in self.__dict__.items()) return 'Elevator(%s)' % attrs @@ -60,11 +101,25 @@ class ElevatorControlSystem: def step(self): # serve pickup requests - free_elevators = list(filter(lambda e: e.goal is None, self.elevators.values())) - while free_elevators and self.pickup_requests: - floor, direction = self.pickup_requests.pop(0) - elevator = min(free_elevators, key=lambda e: abs(e.floor - floor)) - elevator.goal = floor + for floor, direction in copy.copy(self.pickup_requests): + min_time = float('inf') + min_elevator = None + for elevator in self.elevators.values(): + time = elevator.estimate_pickup_time(floor, direction) + if time < min_time: + min_time = time + min_elevator = elevator + if min_elevator: + # only handle the request now if the min_elevator is right here or doing nothing. if + # it's moving, min_time should improve by at least 1 per step. handle this request + # later (in case some other elevator finishes a dropoff and can pickup sooner) + if min_time == 0: + assert min_elevator.floor == floor + self.pickup_requests.remove((floor, direction)) + elif min_elevator.goal is None: + min_elevator.goal = floor + min_elevator.pickup_direction = direction + self.pickup_requests.remove((floor, direction)) # move elevators to requested floors for elevator in self.elevators.values(): @@ -77,7 +132,7 @@ class ElevatorControlSystem: if elevator.dropoffs and elevator.dropoffs[0] == elevator.floor: elevator.dropoffs = elevator.dropoffs[1:] if elevator.goal == elevator.floor: - elevator.goal = None + elevator.goal = elevator.pickup_direction = None if __name__ == '__main__': ecs = ElevatorControlSystem(2) @@ -94,12 +149,27 @@ if __name__ == '__main__': ecs.step() print(' '*4, ecs.elevators) - print('requesting dropoff on floor 3') + print('requesting dropoff on floor 5 and 3') + ecs.dropoff(1, 5) ecs.dropoff(1, 3) ecs.step() print(' '*4, ecs.elevators) - print('requesting pickup on floor 2 up') - ecs.pickup(2, Direction.UP) + print('requesting pickup on floor 3 up') + ecs.pickup(3, Direction.UP) + ecs.step() + print(' '*4, ecs.elevators) + + print('requesting pickup on floor 5 down') + ecs.pickup(5, Direction.DOWN) + ecs.step() + print(' '*8, ecs.pickup_requests) + print(' '*4, ecs.elevators) + + ecs.step() + print(' '*8, ecs.pickup_requests) + print(' '*4, ecs.elevators) + ecs.step() + print(' '*8, ecs.pickup_requests) print(' '*4, ecs.elevators) |