Last active
November 16, 2022 15:06
-
-
Save shayan-ys/b4157289c05a7d085db893b6932b9667 to your computer and use it in GitHub Desktop.
Hotel elevators
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Elevator: | |
def __init__(self, index: int, floor: int=0): | |
self.id = index | |
self.floor = floor | |
self.dests = [] | |
self.dir = 0 # 1 up, -1 down, 0 idle | |
def update(self): | |
""" update status of current elevator. | |
Move up/down, change direction based on next destination, or stop at destination when reached | |
""" | |
if not self.dests: | |
if self.dir != 0: | |
print(f'elevator {self.id} stopping at {self.floor}') | |
self.dir = 0 | |
return | |
elif self.floor < self.dests[0]: | |
self.dir = 1 | |
elif self.floor == self.dests[0]: | |
print(f'elevator {self.id} reached dest {self.dests[0]}') | |
self.dests.pop(0) | |
self.dir = 0 | |
else: | |
self.dir = -1 | |
self.floor += self.dir | |
if self.dir != 0: | |
print(f'elevator {self.id} moving {"up" if self.dir > 0 else "down"}, now at {self.floor}') | |
def isEnRoute(self, floor: int, dir: int): | |
""" Checks if the elevator is enroute to the given floor | |
and in same direction as where the user want to go | |
""" | |
return ( | |
# same direction | |
self.dir == dir and ( | |
# going up, elevator's floor -> floor -> first destination | |
(self.dir > 0 and self.floor <= floor <= self.dests[0]) | |
# going down | |
or (self.dir < 0 and self.floor >= floor >= self.dests[0]) | |
) | |
) | |
class Hotel: | |
def __init__(self, elevators_count: int): | |
self.elevators = [Elevator(i) for i in range(elevators_count)] | |
self.waitList = [] | |
def moveElevators(self, waitMinutes: int = 1): | |
# move forward in time! Move multiple minutes (assuming elevators move 1 floor per minute) | |
for _ in range(waitMinutes): | |
for el in self.elevators: | |
el.update() | |
def call(self, fromFloor: int, destFloor: int): | |
""" Handles user's request for an elevator | |
user is located at 'fromFloor' and is requesting to go to 'destFloor' number | |
if elevator is found, return elevator number. | |
if no elevator is available at the moment, user has to wait (all elevators are going in wrong directions) | |
""" | |
if destFloor != fromFloor: | |
self.waitList.append((fromFloor, destFloor)) | |
def process(self, minutes: int = 1): | |
for i, userReq in enumerate(self.waitList): | |
fromFloor, destFloor = userReq | |
if el := self.findElevator(fromFloor, destFloor): | |
self.waitList.pop(i) | |
el.dests += [fromFloor, destFloor] | |
el.dests = sorted(el.dests, reverse=fromFloor > destFloor) | |
print(f'best elevator is {el.id}, dests updated to {el.dests}') | |
self.moveElevators(minutes) | |
def findElevator(self, fromFloor: int, destFloor: int): | |
userDir = 1 if destFloor > fromFloor else -1 | |
idle_elevators = [el for el in self.elevators if el.dir == 0] | |
enroute_elevators = [el for el in self.elevators if el.isEnRoute(fromFloor, userDir)] | |
print(f'idle elevators: {[el.id for el in idle_elevators]}, enroute_elevators: {[el.id for el in enroute_elevators]}') | |
if candidates := idle_elevators + enroute_elevators: | |
# find closest candidate | |
return sorted(candidates, key=lambda el: abs(el.floor - fromFloor))[0] | |
# test run for a hotel with 2 elevators both starting at floor0: | |
# at time=0, user1 from floor5 request elevators to go to floor10 | |
# at time=3, user2 from floor4 request elevators to go to floor6 | |
# same elevator take both user1 and user2 since elevator can service both by continuing in one direction | |
# at time=8, user3 from floor7 request elevators to go down to floor3 | |
# second elevator (which is idle) has to take user3 since other elevator is going in wrong direction | |
# by time=21, all users reached their destinations and elevators become idle again (elevator 0 at floor10 and elevator 1 at floor 3) | |
h = Hotel(elevators_count=2) | |
h.call(5, 10) | |
h.process(minutes=3) | |
h.call(4, 6) | |
h.process(minutes=5) | |
h.call(7, 3) | |
h.process(minutes=13) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment