-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
430 lines (387 loc) · 19 KB
/
Copy pathmain.cpp
File metadata and controls
430 lines (387 loc) · 19 KB
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
#include "metro.hpp"
// ---------------------------------------------------------
// Helper: builds a path vector from a Dijkstra "via" array.
// ---------------------------------------------------------
static vector<int> buildPath(vector<int>& via, int src, int dst) {
stack<int> st;
int ptr = dst;
while (ptr >= 0 && ptr < total_stations && ptr != via[ptr]) {
st.push(ptr);
ptr = via[ptr];
}
st.push(src);
vector<int> path;
while (!st.empty()) { path.push_back(st.top()); st.pop(); }
return path;
}
// ---------------------------------------------------------
// Helper: records a ticket sale for the revenue dashboard.
// ---------------------------------------------------------
static void logTicketSale(const string& src, const string& dst, double fare, const string& type) {
TicketRecord rec;
rec.src = src; rec.dst = dst; rec.fare = fare; rec.ticket_type = type;
ticket_log.push_back(rec);
tickets_sold_count++;
route_popularity[src + " -> " + dst]++;
}
// ---------------------------------------------------------
// Helper: prints the standard route summary + map, applying transfer-walk
// and line-snag delays on top of the base ETA. Returns the eta in minutes
// actually used (so callers can reuse it, e.g. for arrival time on tickets).
// ---------------------------------------------------------
static int printRouteSummary(vector<int>& path, double dist, int stops) {
int base_eta = (int)getETA(dist, stops);
int transfer_delay = getTransferDelayMins(path);
int snag_delay = getLineSnagDelayMins(path);
int total_eta = base_eta + transfer_delay + snag_delay;
cout << fixed << setprecision(2);
cout << "\n** Total Distance : " << dist << " km (" << stops << " stops) **\n";
cout << "** Current Time : " << getCurrentTime() << " **\n";
if (transfer_delay > 0)
cout << YEL_COL << "** Transfer Walk : +" << transfer_delay << " mins (platform change) **\n" << RESET;
if (snag_delay > 0)
cout << RED_COL << "** Technical Snag : +" << snag_delay << " mins delay (line disruption) **\n" << RESET;
cout << "** Est. Arrival : " << getArrivalTime(total_eta) << " (~" << total_eta << " mins) **\n";
cout << "** Ticket Fare : Rs. " << getFare(dist) << " **\n";
printRoute(path);
return total_eta;
}
// ---------------------------------------------------------
// Smart Card Services submenu
// ---------------------------------------------------------
static void smartCardMenu() {
while (true) {
cout << "\n----- SMART CARD SERVICES -----\n";
cout << "1. Create New Card / Recharge\n";
cout << "2. Check Balance\n";
cout << "3. Tap In (Enter Station)\n";
cout << "4. Tap Out (Exit Station)\n";
cout << "5. Back to Main Menu\n";
cout << "Choice: ";
int c; cin >> c;
if (cin.fail()) { cout << RED_COL << "[!] Input stream ended.\n" << RESET; exit(0); }
if (c == 1) {
string id; double amt;
cout << "Enter Card ID: "; cin >> id;
cout << "Enter Recharge Amount (Rs.): "; cin >> amt;
if (cin.fail() || amt <= 0) { cout << RED_COL << "[!] Invalid amount.\n" << RESET; continue; }
bool isNew = !cardExists(id);
createOrRechargeCard(id, amt);
cout << GRN_COL << "[OK] Card '" << id << "' " << (isNew ? "created" : "recharged")
<< ". New balance: Rs. " << fixed << setprecision(2) << smartcard_balances[id] << RESET << "\n";
}
else if (c == 2) {
string id; cout << "Enter Card ID: "; cin >> id;
if (!cardExists(id)) cout << RED_COL << "[!] No such card.\n" << RESET;
else cout << "Balance for '" << id << "': Rs. " << fixed << setprecision(2) << smartcard_balances[id] << "\n";
}
else if (c == 3) {
string id, st;
cout << "Enter Card ID: "; cin >> id;
if (!cardExists(id)) { cout << RED_COL << "[!] No such card. Create it first.\n" << RESET; continue; }
if (!hasMinimumBalance(id)) {
cout << RED_COL << "[!] ENTRY DENIED. Minimum balance of Rs. " << MIN_SMARTCARD_BALANCE
<< " required (current: Rs. " << smartcard_balances[id] << ").\n" << RESET;
continue;
}
time_t now_t = time(0);
tm* ltm = localtime(&now_t);
if (!isMetroOpenNow(ltm)) {
cout << RED_COL << "[!] ENTRY DENIED. Station gates are closed (Operating Hours: 6:00 AM - 11:00 PM).\n"
<< " First train departs at: " << nextTrainMessage(ltm) << "\n" << RESET;
continue;
}
cout << "Enter Station Name: "; cin >> st;
if (!validateStation(st)) continue;
if (tapIn(id, code[st])) {
cout << GRN_COL << "[OK] Tapped in at " << st << " at " << getCurrentTime() << ".\n" << RESET;
} else {
cout << RED_COL << "[!] Tap-in failed (already mid-journey, or station closed).\n" << RESET;
}
}
else if (c == 4) {
string id, st;
cout << "Enter Card ID: "; cin >> id;
cout << "Enter Exit Station Name: "; cin >> st;
if (!cardExists(id)) { cout << RED_COL << "[!] No such card.\n" << RESET; continue; }
if (!validateStation(st)) continue;
TapOutResult r = tapOut(id, code[st]);
if (!r.success) {
cout << RED_COL << "[!] " << r.message << RESET << "\n";
continue;
}
cout << GRN_COL << "[OK] " << r.message << RESET << "\n";
cout << fixed << setprecision(2);
cout << "Journey Duration : " << r.duration_mins << " mins\n";
if (!r.same_station_flag) cout << "Distance : " << r.distance_km << " km\n";
cout << "Base Fare : Rs. " << r.base_fare << "\n";
if (r.penalty > 0) cout << RED_COL << "Penalty Applied : Rs. " << r.penalty << RESET << "\n";
cout << "Total Charged : Rs. " << r.total_charged << "\n";
cout << "Remaining Balance: Rs. " << smartcard_balances[id] << "\n";
total_fare_collected += (int)r.total_charged;
logTicketSale("(SmartCard tap)", st, r.total_charged, "SmartCard");
}
else if (c == 5) return;
}
}
// ---------------------------------------------------------
// Admin menu
// ---------------------------------------------------------
static void adminMenu() {
cout << "\n1. Close a Station (Simulate Disruption)\n";
cout << "2. Reopen a Single Station\n";
cout << "3. Reset Network to Normal\n";
cout << "4. Trigger Line-wide Technical Snag\n";
cout << "5. Clear a Line's Technical Snag\n";
cout << "6. Revenue Dashboard\n";
int act; cin >> act;
if (cin.fail()) { cout << RED_COL << "\n[!] Input stream ended.\n" << RESET; exit(0); }
if (act == 1) {
string st; cout << "Enter station to close: "; cin >> st;
if (validateStation(st)) {
int id = code[st];
station_closed[id] = true;
cout << RED_COL << "[!] " << st << " is now CLOSED. Future routes will bypass it." << RESET << "\n";
}
} else if (act == 2) {
string st; cout << "Enter station to reopen: "; cin >> st;
if (validateStation(st)) {
int id = code[st];
if (!station_closed[id]) cout << YEL_COL << "[i] " << st << " was not closed.\n" << RESET;
else { station_closed[id] = false; cout << GRN_COL << "[!] " << st << " is now OPEN again." << RESET << "\n"; }
}
} else if (act == 3) {
map_code();
cout << GRN_COL << "[!] Network Reset. All stations open. Snags cleared." << RESET << "\n";
} else if (act == 4) {
cout << "Which line? 1=RED 2=GREEN 3=BLUE: ";
int l; cin >> l;
if (l >= 1 && l <= 3) {
line_snag[l-1] = true;
const char* names[] = {"RED", "GREEN", "BLUE"};
cout << RED_COL << "[!] Technical snag triggered on " << names[l-1]
<< " Line. All routes through it get +" << LINE_SNAG_DELAY_MINS << " min delay." << RESET << "\n";
}
} else if (act == 5) {
cout << "Which line? 1=RED 2=GREEN 3=BLUE: ";
int l; cin >> l;
if (l >= 1 && l <= 3) {
line_snag[l-1] = false;
const char* names[] = {"RED", "GREEN", "BLUE"};
cout << GRN_COL << "[!] Technical snag cleared on " << names[l-1] << " Line." << RESET << "\n";
}
} else if (act == 6) {
cout << "\n===== REVENUE DASHBOARD =====\n";
cout << "Tickets Sold : " << tickets_sold_count << "\n";
double total_rev = 0;
for (auto& t : ticket_log) total_rev += t.fare;
cout << fixed << setprecision(2);
cout << "Total Revenue : Rs. " << total_rev << "\n";
if (!route_popularity.empty()) {
string best_route; int best_count = -1;
for (auto& p : route_popularity) {
if (p.second > best_count) { best_count = p.second; best_route = p.first; }
}
cout << "Most Popular Route : " << best_route << " (" << best_count << " trips)\n";
} else {
cout << "Most Popular Route : (no data yet)\n";
}
cout << "\nBreakdown by ticket type:\n";
map<string, int> type_counts;
map<string, double> type_revenue;
for (auto& t : ticket_log) { type_counts[t.ticket_type]++; type_revenue[t.ticket_type] += t.fare; }
for (auto& p : type_counts) {
cout << " " << left << setw(12) << p.first << ": " << p.second
<< " tickets, Rs. " << type_revenue[p.first] << "\n";
}
}
}
// ---------------------------------------------------------
// Ticket-type purchase flow (used by main menu option 2)
// ---------------------------------------------------------
static void purchaseTicketFlow(const string& ssrc, const string& sdst, double dist, vector<int>& path) {
double single_fare = getFare(dist);
cout << "\nTicket Type:\n";
cout << "1. Single Journey (Rs. " << fixed << setprecision(2) << single_fare << ")\n";
cout << "2. Return Ticket (valid 24 hrs, simulated price Rs. " << computeReturnFare(single_fare) << ")\n";
cout << "3. Tourist Pass (unlimited travel, 1 day, SIMULATED flat Rs. " << TOURIST_PASS_PRICE << ")\n";
cout << "4. Student Pass (SIMULATED " << (int)(STUDENT_PASS_DISCOUNT*100) << "% off single, Rs. " << computeStudentFare(single_fare) << ")\n";
cout << "Choice: ";
int t; cin >> t;
if (cin.fail()) return;
string type; double fare;
switch (t) {
case 2: type = "Return"; fare = computeReturnFare(single_fare); break;
case 3: type = "Tourist Pass"; fare = TOURIST_PASS_PRICE; break;
case 4: type = "Student Pass"; fare = computeStudentFare(single_fare); break;
default: type = "Single"; fare = single_fare; break;
}
string pnr = generatePNR();
int stops = (int)path.size() - 1;
int eta_mins = (int)getETA(dist, stops) + getTransferDelayMins(path) + getLineSnagDelayMins(path);
generateTicket(ssrc, sdst, dist, stops, eta_mins, path);
total_fare_collected += (int)fare;
logTicketSale(ssrc, sdst, fare, type);
cout << GRN_COL << "[SUCCESS] " << type << " ticket booked. Fare charged: Rs. " << fixed << setprecision(2) << fare << RESET << "\n";
printMockQR(pnr);
}
int main() {
map_code();
initAmenities();
while(true) {
cout << "\n=========================================\n";
cout << " HYDERABAD METRO ROUTING SYSTEM \n";
cout << "=========================================\n";
cout << "1. View list of Stations\n";
cout << "2. Get route & Ticket (A to B)\n";
cout << "3. Get route VIA a station (A to B via C)\n";
cout << "4. View Search History\n";
cout << "5. View Fare Summary\n";
cout << "6. Export Search History to file\n";
cout << "7. Smart Card Services\n";
cout << "8. Station Amenities Directory\n";
cout << "9. Exit System\n";
cout << "-----------------------------------------\n";
int choice;
cout << "Enter your choice: ";
cin >> choice;
if (cin.fail()) {
cout << RED_COL << "\n[!] Input stream ended or invalid. Shutting down.\n" << RESET;
break;
}
if(choice == 0) {
string pass;
cout << RED_COL << "\n[ADMIN MODE] Enter Password: " << RESET;
cin >> pass;
if (cin.fail()) { cout << RED_COL << "\n[!] Input stream ended.\n" << RESET; break; }
if(pass == "admin123") adminMenu();
else cout << RED_COL << "Access Denied.\n" << RESET;
continue;
}
// Operating-hours gate applies to anything that initiates real travel.
time_t now_t = time(0);
tm* ltm = localtime(&now_t);
bool metro_open = isMetroOpenNow(ltm);
if((choice == 2 || choice == 3) && !metro_open) {
cout << RED_COL << "\n[!] The Hyderabad Metro is currently CLOSED.\n";
cout << " Operating Hours: 6:00 AM - 11:00 PM daily.\n";
cout << " First train departs at: " << nextTrainMessage(ltm) << "\n" << RESET;
continue;
}
if(choice == 1) {
cout << "\n";
for(int i = 0; i < total_stations; i += 3) {
string label0 = stations[i] + (station_closed[i] ? " [CLOSED]" : "");
cout << i+1 << ". " << left << setw(28) << label0;
if(i+1 < total_stations) {
string label1 = stations[i+1] + (station_closed[i+1] ? " [CLOSED]" : "");
cout << i+2 << ". " << left << setw(28) << label1;
}
if(i+2 < total_stations) {
string label2 = stations[i+2] + (station_closed[i+2] ? " [CLOSED]" : "");
cout << i+3 << ". " << label2;
}
cout << "\n";
}
}
else if(choice == 2) {
string ssrc, sdst;
cout << "\nEnter Source Station: "; cin >> ssrc;
cout << "Enter Destination Station: "; cin >> sdst;
if (!validateStation(ssrc) || !validateStation(sdst)) continue;
if (station_closed[code[ssrc]] || station_closed[code[sdst]]) {
cout << RED_COL << "\n[!] One of the chosen stations is currently CLOSED for disruption.\n" << RESET;
continue;
}
cout << "\nRouting Preference:\n1. Fastest Route\n2. Fewest Transfers\nChoice: ";
int pref; cin >> pref;
bool avoid_transfers = (pref == 2);
int src = code[ssrc], dst = code[sdst];
vector<int> route = dijk(src, avoid_transfers);
if (mp[dst] >= INF/2) {
cout << RED_COL << "\n[!] ROUTE NOT POSSIBLE. The destination is unreachable.\n" << RESET;
continue;
}
vector<int> path = buildPath(route, src, dst);
double dist = getActualDistance(path);
int stops = (int)path.size() - 1;
// Next-train ETA, based on current peak/off-peak headway.
int headway = getHeadwayMins(ltm);
cout << "\n** Next Train In : ~" << headway << " mins ("
<< (isPeakHour(ltm) ? "Peak" : "Off-Peak") << " frequency) **\n";
printRouteSummary(path, dist, stops);
search_history.push_back(ssrc + " -> " + sdst + " (" + to_string(dist).substr(0,4) + " km)");
cout << "Would you like to buy a ticket? (y/n): ";
char t; cin >> t;
if(t == 'y' || t == 'Y') purchaseTicketFlow(ssrc, sdst, dist, path);
}
else if(choice == 3) {
string ssrc, svia, sdst;
cout << "\nEnter Source: "; cin >> ssrc;
cout << "Enter VIA: "; cin >> svia;
cout << "Enter Destination: "; cin >> sdst;
if (!validateStation(ssrc) || !validateStation(svia) || !validateStation(sdst)) continue;
if (station_closed[code[ssrc]] || station_closed[code[svia]] || station_closed[code[sdst]]) {
cout << RED_COL << "\n[!] One of the chosen stations is currently CLOSED for disruption.\n" << RESET;
continue;
}
int src = code[ssrc], via_node = code[svia], dst = code[sdst];
vector<int> route1 = dijk(src, false);
if (mp[via_node] >= INF/2) {
cout << RED_COL << "\n[!] ROUTE NOT POSSIBLE via that station.\n" << RESET;
continue;
}
vector<int> leg1 = buildPath(route1, src, via_node);
vector<int> route2 = dijk(via_node, false);
if (mp[dst] >= INF/2) {
cout << RED_COL << "\n[!] ROUTE NOT POSSIBLE from that VIA station to destination.\n" << RESET;
continue;
}
vector<int> leg2 = buildPath(route2, via_node, dst);
vector<int> full_path = leg1;
full_path.insert(full_path.end(), leg2.begin() + 1, leg2.end());
double totalDist = getActualDistance(full_path);
int totalStops = (int)full_path.size() - 1;
printRouteSummary(full_path, totalDist, totalStops);
search_history.push_back(ssrc + " -> " + svia + " -> " + sdst + " (" + to_string(totalDist).substr(0,4) + " km)");
}
else if(choice == 4) {
cout << "\n--- RECENT SEARCHES ---\n";
if(search_history.empty()) cout << "No recent searches.\n";
else for(size_t i = 0; i < search_history.size(); i++) cout << i+1 << ". " << search_history[i] << "\n";
}
else if(choice == 5) {
cout << "\n--- FARE SUMMARY (this session) ---\n";
cout << "Total fare collected: Rs. " << total_fare_collected << "\n";
}
else if(choice == 6) {
ofstream hist("search_history.txt");
if (!hist) {
cout << RED_COL << "[!] Could not write search_history.txt\n" << RESET;
} else {
hist << "HYDERABAD METRO - SEARCH HISTORY EXPORT\n";
hist << "========================================\n";
if (search_history.empty()) {
hist << "No searches recorded this session.\n";
} else {
for (size_t i = 0; i < search_history.size(); i++)
hist << i+1 << ". " << search_history[i] << "\n";
}
hist.close();
cout << YEL_COL << "[SUCCESS] History exported to 'search_history.txt'!" << RESET << "\n";
}
}
else if(choice == 7) {
smartCardMenu();
}
else if(choice == 8) {
string st; cout << "\nEnter Station Name: "; cin >> st;
if (validateStation(st)) printAmenities(code[st]);
}
else if (choice == 9) {
cout << MAG_COL << "\n** System Offline. Goodbye! **\n" << RESET;
break;
}
}
return 0;
}