Skip to content

Instantly share code, notes, and snippets.

@shayan-ys
Last active November 16, 2022 15:06
Show Gist options
  • Save shayan-ys/b4157289c05a7d085db893b6932b9667 to your computer and use it in GitHub Desktop.
Save shayan-ys/b4157289c05a7d085db893b6932b9667 to your computer and use it in GitHub Desktop.
Hotel elevators
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