diff --git a/src/include/stop_register.hpp b/src/include/stop_register.hpp index 4ea1826..9720ecb 100644 --- a/src/include/stop_register.hpp +++ b/src/include/stop_register.hpp @@ -12,6 +12,7 @@ struct stop_register_t { hash_t train_ID_hash; uint16_t type : 1; uint16_t startTime : 12; + uint8_t stop_id; }; inline bool operator<(const stop_register_t &A, const stop_register_t &B) { if (A.station_ID_hash != B.station_ID_hash) return A.station_ID_hash < B.station_ID_hash; @@ -37,6 +38,9 @@ class StopRegister : public DataDriverBase { int actual_start_date; int leave_time_stamp; int arrive_time_stamp; + int from_stop_id; + int to_stop_id; + int saleDate_beg; }; // for satety, all the copy/move operations are deleted, please manage it using pointer StopRegister &operator=(const StopRegister &) = delete; @@ -73,7 +77,7 @@ class StopRegister : public DataDriverBase { } inline void AddStopInfo(hash_t station_hash, hash_t train_hash, uint16_t true_saleDate_beg, uint16_t true_saleDate_end, uint16_t startTime, uint16_t arrive_time_offset, - uint16_t leave_time_offset) { + uint16_t leave_time_offset, uint8_t stop_id) { MinimalTrainRecord record_arrive, record_leave; const static int June_1st_2024 = 152; record_arrive.saleDate_beg = true_saleDate_beg - June_1st_2024; @@ -83,10 +87,10 @@ class StopRegister : public DataDriverBase { record_leave.saleDate_end = true_saleDate_end - June_1st_2024; record_leave.vis_time_offset = leave_time_offset; if (arrive_time_offset != uint16_t(-1)) - bpt_indexer->Put({station_hash, train_hash, 0, startTime}, + bpt_indexer->Put({station_hash, train_hash, 0, startTime, stop_id}, *reinterpret_cast(&record_arrive)); if (leave_time_offset != uint16_t(-1)) - bpt_indexer->Put({station_hash, train_hash, 1, startTime}, + bpt_indexer->Put({station_hash, train_hash, 1, startTime, stop_id}, *reinterpret_cast(&record_leave)); } inline void QueryDirectTrains(uint32_t date, hash_t from_station_ID, hash_t to_station_ID, @@ -102,17 +106,24 @@ class StopRegister : public DataDriverBase { ++it_from; continue; } + // LOG->debug("it_from now checks station_id_hash {} train_id_hash {} stop_id {}", key_from.station_ID_hash, + // key_from.train_ID_hash, key_from.stop_id); int true_saleDate_beg = (*reinterpret_cast(&value_from)).saleDate_beg + June_1st_2024; int true_saleDate_end = (*reinterpret_cast(&value_from)).saleDate_end + June_1st_2024; int leave_time_offset = (*reinterpret_cast(&value_from)).vis_time_offset; int startTime = key_from.startTime; int actual_time = startTime + leave_time_offset; int delta_days = actual_time / 1440; - if (date - delta_days < true_saleDate_beg || date - delta_days > true_saleDate_end) continue; + if (date - delta_days < true_saleDate_beg || date - delta_days > true_saleDate_end) { + ++it_from; + continue; + } StopRegister::DirectTrainInfo entry; entry.train_ID_hash = key_from.train_ID_hash; entry.actual_start_date = date - delta_days; - entry.leave_time_stamp = true_saleDate_beg * 1440 + actual_time; + entry.leave_time_stamp = entry.actual_start_date * 1440 + actual_time; + entry.from_stop_id = key_from.stop_id; + entry.saleDate_beg = true_saleDate_beg; while (it_to != bpt_indexer->end_const()) { const auto &key_to = it_to.GetKey(); const auto &value_to = it_to.GetValue(); @@ -121,10 +132,14 @@ class StopRegister : public DataDriverBase { ++it_to; continue; } + // LOG->debug("it_to now checks station_id_hash {} train_id_hash {} stop_id {}", key_to.station_ID_hash, + // key_to.train_ID_hash, key_to.stop_id); if (key_to.train_ID_hash > key_from.train_ID_hash) break; if (key_to.train_ID_hash == key_from.train_ID_hash) { - entry.arrive_time_stamp = true_saleDate_beg * 1440 + startTime + + entry.arrive_time_stamp = entry.actual_start_date * 1440 + startTime + (*reinterpret_cast(&value_to)).vis_time_offset; + entry.to_stop_id = key_to.stop_id; + res.push_back(entry); ++it_to; break; } diff --git a/src/train_system.cpp b/src/train_system.cpp index 6222904..7898dfa 100644 --- a/src/train_system.cpp +++ b/src/train_system.cpp @@ -234,6 +234,7 @@ std::string TicketSystemEngine::ReleaseTrain(const std::string &command) { } } hash_t train_id_hash = SplitMix64Hash(trainID); + LOG->debug("hash({})={}", trainID, train_id_hash); CoreTrainData core_train_data; try { core_train_data_storage.Get(train_id_hash, core_train_data); @@ -262,7 +263,7 @@ std::string TicketSystemEngine::ReleaseTrain(const std::string &command) { } stop_register.AddStopInfo(core_train_data.stations_hash[i], train_id_hash, core_train_data.saleDate_beg, core_train_data.saleDate_end, core_train_data.startTime, arrive_time_offset, - leave_time_offset); + leave_time_offset, i); } response_stream << '[' << command_id << "] 0"; return response_stream.str(); diff --git a/src/transaction_system.cpp b/src/transaction_system.cpp index 2d00b90..1e70a04 100644 --- a/src/transaction_system.cpp +++ b/src/transaction_system.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -51,12 +52,74 @@ std::string TicketSystemEngine::QueryTicket(const std::string &command) { hash_t from_hash = SplitMix64Hash(from), to_hash = SplitMix64Hash(to); std::vector valid_trains; stop_register.QueryDirectTrains(date, from_hash, to_hash, valid_trains); - std::vector> valid_trains_full; size_t len = valid_trains.size(); + std::vector> valid_trains_full(len); + LOG->debug("retrieving full data"); for (size_t i = 0; i < len; i++) { valid_trains_full[i].first = valid_trains[i]; + TicketPriceData ticket_price_data; + SeatsData seats_data; + int from_station_id = valid_trains[i].from_stop_id; + int to_station_id = valid_trains[i].to_stop_id; + ticket_price_data_storage.Get(valid_trains[i].train_ID_hash, ticket_price_data); + LOG->debug("analyzing train {} from {} to {}", ticket_price_data.trainID, from_station_id, to_station_id); + seats_data_storage.Get( + {valid_trains[i].train_ID_hash, valid_trains[i].actual_start_date - valid_trains[i].saleDate_beg}, seats_data); + strcpy(valid_trains_full[i].second.trainID, ticket_price_data.trainID); + int total_price = 0; + for (int j = from_station_id; j < to_station_id; j++) { + total_price += ticket_price_data.price[j]; + } + valid_trains_full[i].second.price = total_price; + int seats = seats_data.seat[from_station_id]; + for (int j = from_station_id + 1; j < to_station_id; j++) { + seats = std::min(seats, (int)seats_data.seat[j]); + } + valid_trains_full[i].second.seats = seats; + } + LOG->debug("successfully retrieved full data"); + std::vector valid_trains_full_index(len); + for (size_t i = 0; i < len; i++) { + valid_trains_full_index[i] = i; + } + if (order_by == "time") { + auto cmp = [&valid_trains_full](int a, int b) { + int time_cost_a = valid_trains_full[a].first.arrive_time_stamp - valid_trains_full[a].first.leave_time_stamp; + int time_cost_b = valid_trains_full[b].first.arrive_time_stamp - valid_trains_full[b].first.leave_time_stamp; + if (time_cost_a != time_cost_b) return time_cost_a < time_cost_b; + return strcmp(valid_trains_full[a].second.trainID, valid_trains_full[b].second.trainID) < 0; + }; + std::sort(valid_trains_full_index.begin(), valid_trains_full_index.end(), cmp); + } else { + // order by price + auto cmp = [&valid_trains_full](int a, int b) { + if (valid_trains_full[a].second.price != valid_trains_full[b].second.price) + return valid_trains_full[a].second.price < valid_trains_full[b].second.price; + return strcmp(valid_trains_full[a].second.trainID, valid_trains_full[b].second.trainID) < 0; + }; + std::sort(valid_trains_full_index.begin(), valid_trains_full_index.end(), cmp); + } + response_stream << "[" << command_id << "] " << len; + for (int i = 0; i < len; i++) { + response_stream << '\n'; + response_stream << valid_trains_full[valid_trains_full_index[i]].second.trainID << ' ' << from << ' '; + int leave_time_stamp = valid_trains_full[valid_trains_full_index[i]].first.leave_time_stamp; + int leave_time_month, leave_time_day, leave_time_hour, leave_time_minute; + RetrieveReadableTimeStamp(leave_time_stamp, leave_time_month, leave_time_day, leave_time_hour, leave_time_minute); + response_stream << std::setw(2) << std::setfill('0') << leave_time_month << '-' << std::setw(2) << std::setfill('0') + << leave_time_day << ' ' << std::setw(2) << std::setfill('0') << leave_time_hour << ':' + << std::setw(2) << std::setfill('0') << leave_time_minute; + response_stream << " -> " << to << ' '; + int arrive_time_stamp = valid_trains_full[valid_trains_full_index[i]].first.arrive_time_stamp; + int arrive_time_month, arrive_time_day, arrive_time_hour, arrive_time_minute; + RetrieveReadableTimeStamp(arrive_time_stamp, arrive_time_month, arrive_time_day, arrive_time_hour, + arrive_time_minute); + response_stream << std::setw(2) << std::setfill('0') << arrive_time_month << '-' << std::setw(2) + << std::setfill('0') << arrive_time_day << ' ' << std::setw(2) << std::setfill('0') + << arrive_time_hour << ':' << std::setw(2) << std::setfill('0') << arrive_time_minute; + response_stream << ' ' << valid_trains_full[valid_trains_full_index[i]].second.price << ' ' + << valid_trains_full[valid_trains_full_index[i]].second.seats; } - response_stream << "[" << command_id << "] QueryTicket"; return response_stream.str(); } diff --git a/test/ctest_config b/test/ctest_config index dee992d..ee46a75 100644 --- a/test/ctest_config +++ b/test/ctest_config @@ -4,7 +4,7 @@ add_test(NAME basic_3 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_3 --ski add_test(NAME basic_4 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_4 --skip-check --ignore-first-dependency --enable-tested-program-logging) add_test(NAME basic_5 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_5 --skip-check --ignore-first-dependency --enable-tested-program-logging) add_test(NAME basic_6 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_6 --skip-check --ignore-first-dependency --enable-tested-program-logging) -add_test(NAME basic_extra COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_extra --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME basic_extra COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_extra --skip-check --ignore-first-dependency) add_test(NAME pressure_1_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_1_easy --skip-check --ignore-first-dependency) add_test(NAME pressure_2_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_2_easy --skip-check --ignore-first-dependency) add_test(NAME pressure_3_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_3_easy --skip-check --ignore-first-dependency)