-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathElevator.rb
137 lines (117 loc) · 3.54 KB
/
Elevator.rb
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
require 'thread'
class Elevator
attr_accessor :name, :maxFloor, :destinations, :direction, :currentFloor, :status
NOT_IDLE_MULTIPLIER = 2
IDLE = "idle"
MOVING = "moving"
OPEN = "open"
CLOSE = "close"
SHUTDOWN = "shutdown"
EACH_FLOOR_MOVING_TIME = 1 #second
GROUND_FLOOR = 0
COUNT_TO_OPEN = 5
SEMAPHORE = Mutex.new
def initialize(name, maxFloor, currentFloor)
@name = name
@maxFloor = maxFloor
@currentFloor = currentFloor
@status = IDLE
@destinations = []
end
def add_destination(floor)
puts "#{@name}'s destinations added floor #{floor}"
SEMAPHORE.synchronize do
@destinations << floor
@status = MOVING if @status == IDLE
end
end
def run
Thread.new do
openCount = 0
status = get_status
while (status != SHUTDOWN) do
case status
when MOVING
updateCurrentFloorAndDirection
process_for_current_floor
when IDLE
when OPEN
openCount += 1
if (openCount == COUNT_TO_OPEN)
status = get_status
closeElevator
openCount = 0
end
end
sleep EACH_FLOOR_MOVING_TIME #simulate moving duration
status = get_status
end
end
end
def get_status
status = nil
SEMAPHORE.synchronize do
status = @status
end
status
end
def updateCurrentFloorAndDirection
SEMAPHORE.synchronize do
@currentFloor += 1 if @direction == "up"
@currentFloor -= 1 if @direction == "down"
@direction = "down" if @currentFloor == @maxFloor
@direction = "up" if @currentFloor == GROUND_FLOOR
puts "#{@name} floor: #{@currentFloor} direction: #{@direction}"
end
end
def process_for_current_floor
SEMAPHORE.synchronize do
nearest = get_nearest_destination
if @currentFloor == nearest
@destinations.delete(@currentFloor)
@status = OPEN
puts "#{@name} floor: #{@currentFloor} OPENED DOOR"
end
end
end
def closeElevator
SEMAPHORE.synchronize do
puts "#{@name} floor: #{@currentFloor} CLOSED DOOR"
@status = CLOSE
correct_direction if @destinations.size == 1
@status = MOVING if @destinations.size > 0
end
end
def correct_direction
destination = get_nearest_destination
@direction = "up" if destination > @currentFloor
@direction = "down" if destination < @currentFloor
end
def get_nearest_destination
nearest = nil
nearest = @destinations[0] if @destinations.size > 0
@destinations.each do |floor|
if (@direction == "up")
nearest = floor if (floor < nearest && floor > @currentFloor) || (nearest < @currentFloor && floor > @currentFloor) || (floor == @currentFloor)
end
if (@direction == "down")
nearest = floor if (floor > nearest && floor <= @currentFloor) || (nearest > @currentFloor && floor <= currentFloor) || (floor == @currentFloor)
end
end
nearest
end
def effort_to(destinationFloor, direction)
if (status == IDLE)
effort = (@currentFloor - destinationFloor).abs
else
if (@direction == direction)
effort = NOT_IDLE_MULTIPLIER * ((@currentFloor - destinationFloor).abs)
else
# opposite direction
effort = NOT_IDLE_MULTIPLIER * (@currentFloor + destinationFloor) if direction == "up"
effort = NOT_IDLE_MULTIPLIER * (2 * @maxFloor - @currentFloor - destinationFloor) if direction == "down"
end
end
effort
end
end