-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
153 lines (138 loc) · 3.51 KB
/
index.js
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import Fsm from 'fsm.js';
/**
* Our `Elevator` implementation implements
* 3 states :
* - `open`: the elevator doors are opened
* - `closed`: the elevator doors are closed
* - `moving`: the elevator is moving towards a level
*
* It exposes an external `goToLevel` method used to
* post a user request for the elevator to go to the
* given level.
*/
const Elevator = function () {
const self = this;
const TIME_PER_LEVEL = 1 * 1000;
this.level = 0;
this.stack = [];
this.fsm = new Fsm();
/**
* The elevator is in a stationary state
* and its doors are opened.
*/
const open = new Fsm.State({
fsm: self.fsm,
name: 'open',
onEntry: function () {
console.log('Door opened at level', self.level);
setTimeout(() => {
this.transitionTo(closed);
}, 2000);
},
/**
* As the elevator's doors are currently opened
* we push any user request to go to
* a level on the level stack.
*/
onEvent: (event) => {
if (event.name === 'goToLevel'
&& event.level !== self.level) {
self.pushLevel(event.level);
}
}
});
/**
* The elevator is in a stationary state
* and its doors are closed.
*/
const closed = new Fsm.State({
fsm: self.fsm,
name: 'closed',
onEntry: function () {
console.log('Door closed');
// If there is a channel in the stack,
// we move to that channel.
if (self.stack[0]) {
this.transitionTo(moving);
}
},
/**
* When the elevator's doors are closed,
* we wait for a request to move to another
* level.
*/
onEvent: function (event) {
if (event.name === 'goToLevel') {
if (event.level === self.level) {
this.transitionTo(open);
} else {
self.pushLevel(event.level);
this.transitionTo(moving);
}
}
}
});
/**
* The elevator is currently moving from a
* level to another.
*/
const moving = new Fsm.State({
fsm: self.fsm,
name: 'moving',
onEntry: function () {
const next = self.stack.shift();
console.log('Moving to level', next);
setTimeout(() => {
console.log('Reached level', next);
self.level = next;
this.transitionTo(open);
}, TIME_PER_LEVEL * Math.abs(next - self.level));
},
/**
* As the elevator is currently moving and
* cannot change direction nor open the
* doors, we push any user request to go to
* a level on the level stack.
*/
onEvent: (event) => {
if (event.name === 'goToLevel') {
self.pushLevel(event.level);
}
}
});
// Starting the elevator in the `closed` state.
this.fsm.start(closed);
};
/**
* States whether the elevator is already scheduled
* to go to the given level.
*/
Elevator.prototype.isduplicate = function (level) {
for (let i = 0; i < this.stack.length; ++i) {
if (this.stack[i] === level) {
return (true);
}
}
return (false);
};
/**
* Schedules the elevator to go to the given level,
* if it is not already.
*/
Elevator.prototype.pushLevel = function (level) {
if (!this.isduplicate(level)) {
this.stack.push(level);
}
};
/**
* Requests the elevator to go to the
* given level.
*/
Elevator.prototype.goToLevel = function (level) {
this.fsm.postEvent({ name: 'goToLevel', level: level });
};
// Creating a new `Elevator` instance.
const elevator = new Elevator();
// Sending level inputs to the `Elevator`.
elevator.goToLevel(1);
elevator.goToLevel(5);