-
Notifications
You must be signed in to change notification settings - Fork 0
/
travelCardSorter.js
188 lines (156 loc) · 6.51 KB
/
travelCardSorter.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/**
* Сортировщик карточек путешественника
* Автор: Марк Сурнин
*/
/*
* @param {Array} data - неупорядоченный массив карточек
*
* Контекст определен в каждой функции - решение для проблемы с контекстом в forEach.
*/
function TravelCardSorter(data) {
var ctx = this;
ctx.trip = [];
ctx.cards = [];
ctx.hashTable = {};
if (data) {
ctx.importCards(data);
}
return ctx;
}
/**
* Конструктор хеш-таблицы
*
* Предоставляет быстрый доступ к следующей карточке в маршруте.
* В итоге, хеш-таблица принимает вот такой вид:
* {
* Madrid: 0,
* Barcelona: 1,
* Stockholm: 2,
* Gerona_Airport: 3
* }
Например, имея карточку Мадрид-Барселона, следующая находится вот так:
1) Индекс пункта назначения (Барселоны) - 1.
2) ctx.cards[индекс]
*/
TravelCardSorter.prototype.buildHashTable = function() {
var ctx = this;
ctx.cards.forEach(function(card, i) {
ctx.hashTable[card.origin.name] = i;
});
}
/**
* Импорт карточек
* @param {Array} data - неупорядоченный массив карточек
*
* Копирует данные из data в cards (cвойство TravelCardSorter).
* Здесь же вызывается buildHashTable();
*/
TravelCardSorter.prototype.importCards = function(data) {
var ctx = this;
// Reset the cards Array
ctx.cards = [];
if (data instanceof Array) {
// Check if input is invalid
data.forEach(function(card) {
if (!card.origin.name || card.origin.name === '') {
console.error('origin.name property is missing in ' + JSON.stringify(card));
} else if (!card.destination.name || card.destination.name === '') {
console.error('destination.name property is missing in ' + JSON.stringify(card));
}
})
ctx.cards = data;
}
ctx.buildHashTable();
}
/**
* Поиск начальной карточки
*
* Cоздает массив с всеми пунктами назначения, а затем определяет
* пункт отправления, который не присутствует в этом массиве.
* Временная сложность - О(2n) = O(n).
*/
TravelCardSorter.prototype.findDepartureCard = function() {
var ctx = this;
var destinations = [];
ctx.cards.forEach(function(card) {
destinations.push(card.destination.name);
});
ctx.cards.forEach(function(card) {
if (destinations.indexOf(card.origin.name) === -1) {
ctx.trip.push(card);
}
});
}
/**
* Сортировка карточек/построение маршрута
*
* Зная первую карточку и имея доступ к хеш-таблица,
* построение маршрута становится тривиальным.
*
* 1) Найти значение card.destination.name в хеш-таблице.
* 2) В первоначальном массиве cards найти следующую карточку cards[index].
*
* Временная сложность - О(1) * n = O(n).
*/
TravelCardSorter.prototype.sortCards = function() {
var ctx = this;
ctx.departureCard = ctx.findDepartureCard();
for (var i = 0; i < ctx.cards.length - 1; i++) {
var currentCard = ctx.trip[i];
var nextCardIndex = ctx.hashTable[currentCard.destination.name];
var nextCard = cards[nextCardIndex];
ctx.trip.push(nextCard);
}
}
/**
* Вывод маршрута
*
* Зная первую карточку и имея доступ к хеш-таблица,
* построение маршрута становится тривиальным.
*
* 1) Найти значение card.destination.name в хеш-таблице.
* 2) В первоначальном массиве cards найти следующую карточку cards[index].
*
* Временная сложность - О(1) * n = O(n).
*/
TravelCardSorter.prototype.printItinerary = function() {
var ctx = this;
// Вспомогательная функция для вывода информации о месте в транспорте.
var printSeat = function(card) {
if (card.transport.seat) {
return 'Seat ' + card.transport.seat + '. ';
} else {
return 'No seat assigned. ';
}
};
// Создает элемент для вывода маршрута.
var itinerary = document.createElement('div');
ctx.trip.forEach(function(card) {
var cardDirections = '';
switch (card.transport.type) {
case 'plane':
// Определяет, какую информацию о багаже добавить в маршрут.
// Could be implemented in the same way as printSeat for consistency.
var baggage = (card.transport.baggage_drop ? 'Baggage drop at ticket counter ' + card.transport.baggage_drop + '. ' : '');
cardDirections = '<span>From ' + card.origin.name + ', take flight ' + card.transport.route + ' to ' + card.destination.name + '. Gate ' + card.transport.gate + '. ' + printSeat(card) + baggage + (card.transport.notes || '') + '</span><br>';
break;
case 'train':
cardDirections = '<span>Take train ' + card.transport.route + ' from ' + card.origin.name + ' to ' + card.destination.name + '. ' + printSeat(card) + (card.transport.notes || '') + '</span><br>';
break;
case 'airport_bus':
cardDirections = '<span>Take the airport bus from ' + card.origin.name + ' to ' + card.destination.name + '. ' + printSeat(card) + (card.transport.notes || '') + '</span><br>';
break;
case 'taxi':
cardDirections = '<span>Take a Yandex.Taxi from ' + card.origin.name + ' to ' + card.destination.name + '. ' + (card.transport.notes || '') + '</span><br>';
break;
case 'walking':
cardDirections = '<span>Walk from ' + card.origin.name + ' to ' + card.destination.name + '. ' + (card.transport.notes || '') + '</span><br>';
break;
default:
cardDirections = '<span>Go from ' + card.origin.name + ' to ' + card.destination.name + '. ' + (card.transport.notes || '') + '</span><br>';
}
// Inserts directions into the element with id 'itinerary'.
itinerary.innerHTML += cardDirections;
});
document.getElementsByTagName('body')[0].appendChild(itinerary);
}