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
|
//An implement of CSCI-1200 HW2 Ride Sharing
//Author: JamesFlare
//Date: 2025/1/20
//#include <algorithm>
//#include <cstdlib>
#include <cmath>
#include <vector>
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
#include <iomanip>
#include "Driver.h"
#include "Rider.h"
void debug_print(const std::string &msg) {
std::cout << "DEBUG: " << msg << std::endl;
}
bool isPhoneNumberValid(const std::string &phone)
{
if (phone.size() != 12) return false;
//xxx-xxx-xxxx
for (int i = 0; i < 12; i++) {
if (i == 3 || i == 7) {
if (phone[i] != '-') return false;
} else {
if (!std::isdigit((unsigned char)phone[i])) return false;
}
}
return true;
}
void loadDrivers(std::ifstream &ifs, std::vector<Driver> &drivers) {
//read the file line by line, total of 13
while (!ifs.eof()) {
std::string fName, lName, gender, phone, vehicleType, state;
std::string rF, rL, rP;
int age;
double rating, lat, lon;
ifs >> fName >> lName >> gender >> age >> phone >> rating >> lat >> lon
>> vehicleType >> state >> rF >> rL >> rP;
if (!ifs.fail()) {
//change "null" to empty string
if (rF == "null") rF = "";
if (rL == "null") rL = "";
if (rP == "null") rP = "";
//create driver
Driver d(fName, lName, gender, age, phone, rating, lat, lon,
vehicleType, state, rF, rL, rP);
drivers.push_back(d);
}
}
ifs.close();
}
void loadRiders(std::ifstream &ifs, std::vector<Rider> &riders) {
//read the file line by line, total of 17
while (!ifs.eof()) {
std::string fName, lName, gender, phone, pickupLoc, dropoffLoc, vPref, state;
std::string dF, dL, dP;
int age;
double rating, pickupLat, pickupLon, dropoffLat, dropoffLon;
ifs >> fName >> lName >> gender >> age >> phone >> rating
>> pickupLoc >> pickupLat >> pickupLon
>> dropoffLoc >> dropoffLat >> dropoffLon
>> vPref >> state
>> dF >> dL >> dP;
if (!ifs.fail()) {
//fill null with empty string
if (dF == "null") dF = "";
if (dL == "null") dL = "";
if (dP == "null") dP = "";
//create rider
Rider r(fName, lName, gender, age, phone, rating,
pickupLoc, pickupLat, pickupLon,
dropoffLoc, dropoffLat, dropoffLon,
vPref, state, dF, dL, dP);
riders.push_back(r);
}
}
ifs.close();
}
std::ifstream loadFile(const std::string &filename) {
//read file and return ifstream
std::ifstream ifs(filename);
if (!ifs) {
std::cerr << "Error opening file: " << filename << std::endl;
exit(1);
}
return ifs;
}
void saveFile(const std::string &filename, const std::string &msg) {
std::ofstream ofs(filename);
if (!ofs) {
std::cerr << "Error opening file: " << filename << std::endl;
exit(1);
}
ofs << msg;
ofs.close();
}
void exportDrivers(const std::string &filename, const std::vector<Driver> &drivers) {
//save drivers to file
std::ofstream ofs(filename);
if (!ofs) {
std::cerr << "Error opening output file: " << filename << std::endl;
return;
}
for (int i = 0; i < (int)drivers.size(); i++) {
const Driver &d = drivers[i];
ofs << d.toFileString() << "\n";
}
ofs.close();
}
void exportRiders(const std::string &filename, const std::vector<Rider> &riders) {
//save riders to file
std::ofstream ofs(filename);
if (!ofs) {
std::cerr << "Error opening output file: " << filename << std::endl;
return;
}
for (int i = 0; i < (int)riders.size(); i++) {
const Rider &r = riders[i];
ofs << r.toFileString() << "\n";
}
ofs.close();
}
// calculate the distance between two coordinates using Haversine formula
double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
const double radiusOfEarth = 6371.0; // Earth's radius in kilometers
// convert latitude and longitude from degrees to radians
lat1 *= M_PI / 180.0;
lon1 *= M_PI / 180.0;
lat2 *= M_PI / 180.0;
lon2 *= M_PI / 180.0;
// Haversine formula
double dLat = lat2 - lat1;
double dLon = lon2 - lon1;
double a = sin(dLat / 2.0) * sin(dLat / 2.0) + cos(lat1) * cos(lat2) * sin(dLon / 2.0) * sin(dLon / 2.0);
double c = 2.0 * atan2(sqrt(a), sqrt(1.0 - a));
// distance in kilometers
double distanceKM = radiusOfEarth * c;
// convert it to distance in miles
double distanceMiles = distanceKM * 0.621371;
return distanceMiles;
}
int findClosestDriver(const std::vector<Driver> &drivers,
const Rider &rider) {
double minDistance = 1e9;
int bestIndex = -1;
for (int i = 0; i < (int)drivers.size(); i++) {
const Driver &drv = drivers[i];
if (drv.getCurrentState() == "Available" &&
drv.getVehicleType() == rider.getVehiclePref()) {
double dist = calculateDistance(drv.getLatitude(), drv.getLongitude(),
rider.getPickupLatitude(), rider.getPickupLongitude());
if (dist < minDistance) {
minDistance = dist;
bestIndex = i;
}
}
}
return bestIndex;
}
int findRiderIndexByPhone(const std::vector<Rider> &riders, const std::string &phone) {
for (int i = 0; i < (int)riders.size(); i++) {
if (riders[i].getPhoneNumber() == phone) {
return i;
}
}
return -1;
}
int findDriverIndexByPhone(const std::vector<Driver> &drivers, const std::string &phone) {
for (int i = 0; i < (int)drivers.size(); i++) {
if (drivers[i].getPhoneNumber() == phone) {
return i;
}
}
return -1;
}
std::string autoAAn(const std::string &word) {
if (word.empty()) return "";
if (word[0] == 'A' || word[0] == 'E' || word[0] == 'I' || word[0] == 'O' || word[0] == 'U') {
return "an";
}
return "a";
}
int main(int argc, char *argv[]) {
//take 3 arguments
if (argc < 8) {
std::cout << "Usage: nyride drivers.txt riders.txt output0.txt output1.txt output2.txt phoneNumber [request|cancel]\n" << std::endl;
return 1;
}
//load arguments
const std::string drivers_fName = argv[1];
const std::string riders_fName = argv[2];
std::string msg_fName = argv[3];
std::string updated_drivers_fName = argv[4];
std::string updated_riders_fName = argv[5];
std::string phone_number = argv[6];
std::string command = argv[7];
//turn on debug mode is last argument is debug
bool debug_mode = false;
if (std::string(argv[argc - 1]) == "debug") {
debug_mode = true;
}
if (debug_mode) {
debug_print("drivers_fName = " + drivers_fName);
debug_print("riders_fName = " + riders_fName);
debug_print("msg_fName = " + msg_fName);
debug_print("updated_drivers_fName = " + updated_drivers_fName);
debug_print("updated_riders_fName = " + updated_riders_fName);
debug_print("phone_number = " + phone_number);
debug_print("command = " + command);
}
//load drivers
std::vector<Driver> drivers;
std::ifstream drivers_file = loadFile(drivers_fName);
loadDrivers(drivers_file, drivers);
//load riders
std::vector<Rider> riders;
std::ifstream riders_file = loadFile(riders_fName);
loadRiders(riders_file, riders);
if (debug_mode) {
debug_print("drivers.size() = " + std::to_string(drivers.size()));
debug_print("riders.size() = " + std::to_string(riders.size()));
}
//check if phone number is valid
std::ostringstream msg;
if (!isPhoneNumberValid(phone_number)) {
std::cout << "Error: Invalid phone number" << std::endl;
msg << "Phone number is invalid.\n";
saveFile(msg_fName, msg.str());
return 1;
}
//check if command is valid
if (command != "request" && command != "cancel") {
std::cout << "Error: Invalid command" << std::endl;
return 1;
} else if (command == "request") {
//for request cases
int rIdx = findRiderIndexByPhone(riders, phone_number);
if (rIdx == -1) {
//if rider does not exist
msg << "Account does not exist.\n";
saveFile(msg_fName, msg.str());
return 1;
}
Rider &r = riders[rIdx];
//check rider
if (r.getCurrentState() == "Driver_on_the_way") {
msg << "You have already requested a ride and your driver is on the way to the pickup location.\n";
saveFile(msg_fName, msg.str());
return 1;
}
if (r.getCurrentState() == "During_the_trip") {
msg << "You can not request a ride at this moment as you are already on a trip.\n";
saveFile(msg_fName, msg.str());
return 1;
}
if (r.getCurrentState() == "Ready_to_request") {
msg << "Ride requested for rider " << r.getFirstName()
<< ", looking for " << autoAAn(r.getVehiclePref()) << " "
<< r.getVehiclePref() << " vehicle.\n"
<< "Pick Up Location: " << r.getPickupLocationName()
<< ", Drop Off Location: " << r.getDropoffLocationName() << ".\n";
//find closest driver
int dIdx = findClosestDriver(drivers, r);
if (dIdx == -1) {
//no driver
msg << "Sorry we can not find a driver for you at this moment.\n";
} else {
Driver &d = drivers[dIdx];
double dist = calculateDistance(d.getLatitude(), d.getLongitude(),
r.getPickupLatitude(), r.getPickupLongitude());
dist = (int)(dist * 10) / 10.0; //cut to 1 decimal
msg << "We have found the closest driver " << d.getFirstName() << "("
<< std::fixed << std::setprecision(1) << d.getRating() << ") for you.\n"
<< d.getFirstName() << " is now "
<< std::fixed << std::setprecision(1) << dist
<< " miles away from you.\n";
//update status
d.setCurrentState("On_the_way_to_pickup");
d.setRiderInfo(r.getFirstName(), r.getLastName(), r.getPhoneNumber());
r.setCurrentState("Driver_on_the_way");
r.setDriverInfo(d.getFirstName(), d.getLastName(), d.getPhoneNumber());
}
}
} else if (command == "cancel") {
//for cancel cases
//find phone_number in riders
int rIdx = findRiderIndexByPhone(riders, phone_number);
if (rIdx == -1) {
//in case of driver's cancel
int dIdx = findDriverIndexByPhone(drivers, phone_number);
if (dIdx == -1) {
//in case of not both rider and driver
msg << "Account does not exist.\n";
saveFile(msg_fName, msg.str());
return 1;
}
Driver &driver = drivers[dIdx];
if (driver.getCurrentState() != "On_the_way_to_pickup") {
msg << "You can only cancel a ride request if you are currently on the way to the pickup location.\n";
saveFile(msg_fName, msg.str());
return 1;
}
//get rider's phone number
std::string rPh = driver.getRiderPhoneNumber();
//clean driver's rider info
driver.setCurrentState("Available");
driver.setRiderInfo("", "", "");
msg << "Your driver " << driver.getFirstName()
<< " has canceled the ride request. We will now find a new driver for you.\n";
//find rider
int theRiderIdx = findRiderIndexByPhone(riders, rPh);
Rider &r = riders[theRiderIdx];
//reset rider
r.setCurrentState("Ready_to_request");
r.setDriverInfo("", "", "");
//find a new driver
msg << "Ride requested for rider " << r.getFirstName()
<< ", looking for " << autoAAn(r.getVehiclePref()) << " "
<< r.getVehiclePref() << " vehicle.\n"
<< "Pick Up Location: " << r.getPickupLocationName()
<< ", Drop Off Location: " << r.getDropoffLocationName() << ".\n";
int newDIdx = findClosestDriver(drivers, r);
if (newDIdx == -1) {
msg << "Sorry we can not find a driver for you at this moment.\n";
} else {
Driver &newDriver = drivers[newDIdx];
double dist = calculateDistance(newDriver.getLatitude(), newDriver.getLongitude(),
r.getPickupLatitude(), r.getPickupLongitude());
dist = (int)(dist * 10) / 10.0; //cut to 1 decimal
msg << "We have found the closest driver " << newDriver.getFirstName() << "("
<< std::fixed << std::setprecision(1) << newDriver.getRating() << ") for you.\n"
<< newDriver.getFirstName() << " is now "
<< std::fixed << std::setprecision(1) << dist
<< " miles away from you.\n";
//update driver's status
newDriver.setCurrentState("On_the_way_to_pickup");
newDriver.setRiderInfo(r.getFirstName(), r.getLastName(), r.getPhoneNumber());
//update rider's status
r.setCurrentState("Driver_on_the_way");
r.setDriverInfo(newDriver.getFirstName(), newDriver.getLastName(), newDriver.getPhoneNumber());
}
} else {
//in case of rider's cancel
Rider &rider = riders[rIdx];
if (rider.getCurrentState() != "Driver_on_the_way") {
msg << "You can only cancel a ride request if your driver is currently on the way to the pickup location.\n";
saveFile(msg_fName, msg.str());
return 1;
}
//find driver's phone_number
std::string dPh = rider.getDriverPhoneNumber();
msg << "Ride request for rider " << rider.getFirstName()
<< " is now canceled by the rider.\n";
//set driver's status to Available
int dIdx = findDriverIndexByPhone(drivers, dPh);
if (dIdx != -1) {
Driver &drv = drivers[dIdx];
drv.setCurrentState("Available");
drv.setRiderInfo("", "", "");
}
//set rider's status to Ready_to_request
rider.setCurrentState("Ready_to_request");
rider.setDriverInfo("", "", "");
}
}
//save msg
saveFile(msg_fName, msg.str());
//save updated drivers and riders
exportDrivers(updated_drivers_fName, drivers);
exportRiders(updated_riders_fName, riders);
return 0;
}
|