elevator.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #!/usr/bin/env python3
  2. import copy
  3. from enum import Enum
  4. class Elevator:
  5. def __init__(self, e_id, floor, goal):
  6. self.id = e_id
  7. self.floor = floor
  8. self.goal = goal
  9. self.pickup_direction = None # the direction we're handling pickup requests for
  10. self.dropoffs = []
  11. def direction(self):
  12. ' the direction the elevator is currently moving in '
  13. if self.goal is None:
  14. return None
  15. if self.goal > self.floor:
  16. return Direction.UP
  17. else:
  18. return Direction.DOWN
  19. def dropoff(self, floor):
  20. if floor in self.dropoffs:
  21. assert self.goal is not None
  22. return
  23. assert floor != self.floor
  24. assert self.pickup_direction is None
  25. if self.goal is None:
  26. self.goal = floor
  27. self.dropoffs.append(floor)
  28. else:
  29. direction = self.direction()
  30. # TODO: handle opposite direction dropoffs
  31. if direction == Direction.UP:
  32. if floor > self.goal:
  33. self.goal = floor
  34. self.dropoffs.append(floor)
  35. self.dropoffs.sort()
  36. elif direction == Direction.DOWN:
  37. if floor < self.goal:
  38. self.goal = floor
  39. self.dropoffs.append(floor)
  40. self.dropoffs.sort(reverse=True)
  41. def estimate_pickup_time(self, floor, direction):
  42. # while dropping off, can handle requests in same elevator dir in between current and goal
  43. # while picking up, can handle requests in same dir as request dir
  44. # when requested floor is in dir of elevator
  45. our_dir = self.direction()
  46. if our_dir is None:
  47. return abs(floor - self.floor)
  48. if self.dropoffs: # we are moving and have dropoffs
  49. if our_dir == Direction.UP:
  50. if self.floor <= floor and direction == our_dir:
  51. return floor - self.floor
  52. else:
  53. to_goal = self.goal - self.floor
  54. to_request = abs(self.goal - floor)
  55. return to_goal + to_request
  56. else:
  57. if self.floor >= floor and direction == our_dir:
  58. return self.floor - floor
  59. else:
  60. to_goal = self.floor - self.goal
  61. to_request = abs(self.goal - floor)
  62. return to_goal + to_request
  63. else: # we are moving to pick up a request
  64. assert self.pickup_direction is not None
  65. if our_dir == Direction.UP:
  66. if self.floor <= floor <= self.goal and direction == self.pickup_direction:
  67. return floor - self.floor
  68. else:
  69. return float('inf')
  70. else:
  71. if self.floor >= floor >= self.goal and direction == self.pickup_direction:
  72. return self.floor - floor
  73. else:
  74. return float('inf')
  75. def __repr__(self):
  76. attrs = ', '.join('%s=%s' % t for t in self.__dict__.items())
  77. return 'Elevator(%s)' % attrs
  78. class Direction(Enum):
  79. UP = 1
  80. DOWN = 2
  81. class ElevatorControlSystem:
  82. def __init__(self, num_elevators):
  83. self.elevators = {i: Elevator(i, 1, None) for i in range(num_elevators)}
  84. self.pickup_requests = []
  85. def pickup(self, floor, direction):
  86. self.pickup_requests.append((floor, direction))
  87. def dropoff(self, elevator_id, floor):
  88. self.elevators[elevator_id].dropoff(floor)
  89. def step(self):
  90. # serve pickup requests
  91. for floor, direction in copy.copy(self.pickup_requests):
  92. min_time = float('inf')
  93. min_elevator = None
  94. for elevator in self.elevators.values():
  95. time = elevator.estimate_pickup_time(floor, direction)
  96. if time < min_time:
  97. min_time = time
  98. min_elevator = elevator
  99. if min_elevator:
  100. # only handle the request now if the min_elevator is right here or doing nothing. if
  101. # it's moving, min_time should improve by at least 1 per step. handle this request
  102. # later (in case some other elevator finishes a dropoff and can pickup sooner)
  103. if min_time == 0:
  104. assert min_elevator.floor == floor
  105. self.pickup_requests.remove((floor, direction))
  106. elif min_elevator.goal is None:
  107. min_elevator.goal = floor
  108. min_elevator.pickup_direction = direction
  109. self.pickup_requests.remove((floor, direction))
  110. # move elevators to requested floors
  111. for elevator in self.elevators.values():
  112. if elevator.goal is not None:
  113. if elevator.goal > elevator.floor:
  114. elevator.floor += 1
  115. elif elevator.goal < elevator.floor:
  116. elevator.floor -= 1
  117. # check dropoffs and goal after moving
  118. if elevator.dropoffs and elevator.dropoffs[0] == elevator.floor:
  119. elevator.dropoffs = elevator.dropoffs[1:]
  120. if elevator.goal == elevator.floor:
  121. elevator.goal = elevator.pickup_direction = None
  122. if __name__ == '__main__':
  123. ecs = ElevatorControlSystem(2)
  124. print(' '*4, ecs.elevators)
  125. print('requesting pickup on floor 2 down')
  126. ecs.pickup(2, Direction.DOWN)
  127. ecs.step()
  128. print(' '*4, ecs.elevators)
  129. print('requesting dropoff on floor 1 and pickup on floor 1 up')
  130. ecs.dropoff(0, 1)
  131. ecs.pickup(1, Direction.UP)
  132. ecs.step()
  133. print(' '*4, ecs.elevators)
  134. print('requesting dropoff on floor 5 and 3')
  135. ecs.dropoff(1, 5)
  136. ecs.dropoff(1, 3)
  137. ecs.step()
  138. print(' '*4, ecs.elevators)
  139. print('requesting pickup on floor 3 up')
  140. ecs.pickup(3, Direction.UP)
  141. ecs.step()
  142. print(' '*4, ecs.elevators)
  143. print('requesting pickup on floor 5 down')
  144. ecs.pickup(5, Direction.DOWN)
  145. ecs.step()
  146. print(' '*8, ecs.pickup_requests)
  147. print(' '*4, ecs.elevators)
  148. ecs.step()
  149. print(' '*8, ecs.pickup_requests)
  150. print(' '*4, ecs.elevators)
  151. ecs.step()
  152. print(' '*8, ecs.pickup_requests)
  153. print(' '*4, ecs.elevators)