Advertisement
kutuzzzov

Урок 5-2

Feb 20th, 2023
1,119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.83 KB | None | 0 0
  1. #include <array>
  2. #include <cassert>
  3. #include <chrono>
  4. #include <iomanip>
  5. #include <iostream>
  6. #include <sstream>
  7. #include <string>
  8. #include <tuple>
  9. #include <unordered_map>
  10. #include <vector>
  11.  
  12. using namespace std;
  13.  
  14. class VehiclePlate {
  15. private:
  16.     auto AsTuple() const {
  17.         return tie(letters_, digits_, region_);
  18.     }
  19.  
  20. public:
  21.     bool operator==(const VehiclePlate& other) const {
  22.         return AsTuple() == other.AsTuple();
  23.     }
  24.  
  25.     VehiclePlate(char l0, char l1, int digits, char l2, int region)
  26.         : letters_{ l0, l1, l2 }
  27.         , digits_(digits)
  28.         , region_(region) {
  29.     }
  30.  
  31.     string ToString() const {
  32.         ostringstream out;
  33.         out << letters_[0] << letters_[1];
  34.  
  35.         // чтобы дополнить цифровую часть номера слева нулями
  36.         // до трёх цифр, используем подобные манипуляторы:
  37.         // setfill задаёт символ для заполнения,
  38.         // right задаёт выравнивание по правому краю,
  39.         // setw задаёт минимальное желаемое количество знаков
  40.         out << setfill('0') << right << setw(3) << digits_;
  41.         out << letters_[2] << setw(2) << region_;
  42.  
  43.         return out.str();
  44.     }
  45.  
  46. private:
  47.     array<char, 3> letters_;
  48.     int digits_;
  49.     int region_;
  50. };
  51.  
  52. ostream& operator<<(ostream& out, VehiclePlate plate) {
  53.     out << plate.ToString();
  54.     return out;
  55. }
  56.  
  57. // возьмите реализацию хешера из прошлого задания
  58. class VehiclePlateHasher {
  59. public:
  60.     size_t operator()(const VehiclePlate& plate) const {
  61.         // измените эту функцию, чтобы она учитывала все данные номера
  62.         // рекомендуется использовать метод ToString() и существующий
  63.         // класс hash<string>
  64.         return static_cast<size_t>(hasher_(plate.ToString()));
  65.     }
  66.  
  67. private:
  68.     hash<string> hasher_;
  69. };
  70.  
  71. // выбросьте это исключение в случае ошибки парковки
  72. struct ParkingException {};
  73.  
  74. template <typename Clock>
  75. class Parking {
  76.     // при обращении к типу внутри шаблонного параметра мы обязаны использовать
  77.     // typename; чтобы этого избежать, объявим псевдонимы для нужных типов
  78.     using Duration = typename Clock::duration;
  79.     using TimePoint = typename Clock::time_point;
  80.  
  81. public:
  82.     Parking(int cost_per_second) : cost_per_second_(cost_per_second) {}
  83.  
  84.     // запарковать машину с указанным номером
  85.     void Park(VehiclePlate car) {
  86.         // место для вашей реализации
  87.         if (now_parked_.count(car)) {
  88.             throw ParkingException();
  89.         }
  90.         now_parked_[car] = static_cast<TimePoint>(Clock::now());
  91.     }
  92.  
  93.     // забрать машину с указанным номером
  94.     void Withdraw(const VehiclePlate& car) {
  95.         // место для вашей реализации
  96.         if (!now_parked_.count(car)) {
  97.             throw ParkingException();
  98.         }
  99.         TimePoint end_parking = Clock::now();
  100.         const Duration duration_parking = end_parking - now_parked_.at(car);
  101.         now_parked_.erase(car);
  102.         complete_parks_[car] = duration_parking;
  103.     }
  104.  
  105.     // получить счёт за конкретный автомобиль
  106.     int64_t GetCurrentBill(const VehiclePlate& car) const {
  107.         int64_t result = { 0 };
  108.         if (!(now_parked_.count(car)) && !(complete_parks_.count(car))) { // Если номера нет в системе, верните ноль
  109.             return result;
  110.         }
  111.         else { // сумма завершенной парковки
  112.             if (complete_parks_.count(car)) {
  113.                 auto duration_parking_sec = chrono::duration_cast<chrono::seconds>(complete_parks_.at(car)).count();
  114.                 result += cost_per_second_ * duration_parking_sec;
  115.             }
  116.             if (now_parked_.count(car)) {
  117.                 const TimePoint end_parking = Clock::now();
  118.                 const Duration duration_parking = end_parking - now_parked_.at(car);
  119.                 result += cost_per_second_ * chrono::duration_cast<chrono::seconds>(duration_parking).count();
  120.             }
  121.         }
  122.         return result;
  123.     }
  124.  
  125.     // завершить расчётный период
  126.     // те машины, которые находятся на парковке на данный момент, должны
  127.     // остаться на парковке, но отсчёт времени для них начинается с нуля
  128.     unordered_map<VehiclePlate, int64_t, VehiclePlateHasher> EndPeriodAndGetBills() {
  129.         unordered_map<VehiclePlate, int64_t, VehiclePlateHasher> result;
  130.         for (auto& [plate, start_parking] : now_parked_) {
  131.             const TimePoint end_parking = Clock::now();
  132.             const Duration duration_parking = end_parking - now_parked_.at(plate);
  133.             result[plate] += cost_per_second_ * chrono::duration_cast<chrono::seconds>(duration_parking).count();
  134.             now_parked_[plate] = static_cast<TimePoint>(Clock::now()); // сброс времени парковки
  135.         }
  136.        
  137.         for (auto& [plate, duration] : complete_parks_) {
  138.             result[plate] += chrono::duration_cast<chrono::seconds>(duration).count() * cost_per_second_;
  139.         }
  140.         complete_parks_.clear();
  141.  
  142.         return result;
  143.     }
  144.  
  145.     // не меняйте этот метод
  146.     auto& GetNowParked() const {
  147.         return now_parked_;
  148.     }
  149.  
  150.     // не меняйте этот метод
  151.     auto& GetCompleteParks() const {
  152.         return complete_parks_;
  153.     }
  154.  
  155. private:
  156.     int cost_per_second_;
  157.     unordered_map<VehiclePlate, TimePoint, VehiclePlateHasher> now_parked_;
  158.     unordered_map<VehiclePlate, Duration, VehiclePlateHasher> complete_parks_;
  159. };
  160.  
  161. // эти часы удобно использовать для тестирования
  162. // они покажут столько времени, сколько вы задали явно
  163. class TestClock {
  164. public:
  165.     using time_point = chrono::system_clock::time_point;
  166.     using duration = chrono::system_clock::duration;
  167.  
  168.     static void SetNow(int seconds) {
  169.         current_time_ = seconds;
  170.     }
  171.  
  172.     static time_point now() {
  173.         return start_point_ + chrono::seconds(current_time_);
  174.     }
  175.  
  176. private:
  177.     inline static time_point start_point_ = chrono::system_clock::now();
  178.     inline static int current_time_ = 0;
  179. };
  180.  
  181. int main() {
  182.     Parking<TestClock> parking(10);
  183.  
  184.     TestClock::SetNow(10);
  185.     parking.Park({ 'A', 'A', 111, 'A', 99 });
  186.  
  187.     TestClock::SetNow(20);
  188.     parking.Withdraw({ 'A', 'A', 111, 'A', 99 });
  189.     parking.Park({ 'B', 'B', 222, 'B', 99 });
  190.  
  191.     TestClock::SetNow(40);
  192.     assert(parking.GetCurrentBill({ 'A', 'A', 111, 'A', 99 }) == 100);
  193.     assert(parking.GetCurrentBill({ 'B', 'B', 222, 'B', 99 }) == 200);
  194.     parking.Park({ 'A', 'A', 111, 'A', 99 });
  195.  
  196.     TestClock::SetNow(50);
  197.     assert(parking.GetCurrentBill({ 'A', 'A', 111, 'A', 99 }) == 200);
  198.     assert(parking.GetCurrentBill({ 'B', 'B', 222, 'B', 99 }) == 300);
  199.     assert(parking.GetCurrentBill({ 'C', 'C', 333, 'C', 99 }) == 0);
  200.     parking.Withdraw({ 'B', 'B', 222, 'B', 99 });
  201.  
  202.     TestClock::SetNow(70);
  203.     {
  204.         // проверим счёт
  205.         auto bill = parking.EndPeriodAndGetBills();
  206.  
  207.         // так как внутри макроса используется запятая,
  208.         // нужно заключить его аргумент в дополнительные скобки
  209.         assert((bill
  210.             == unordered_map<VehiclePlate, int64_t, VehiclePlateHasher>{
  211.                 { {'A', 'A', 111, 'A', 99}, 400},
  212.                 { {'B', 'B', 222, 'B', 99}, 300 },
  213.         }));
  214.     }
  215.  
  216.     TestClock::SetNow(80);
  217.     {
  218.         // проверим счёт
  219.         auto bill = parking.EndPeriodAndGetBills();
  220.  
  221.         // так как внутри макроса используется запятая,
  222.         // нужно заключить его аргумент в дополнительные скобки
  223.         assert((bill
  224.             == unordered_map<VehiclePlate, int64_t, VehiclePlateHasher>{
  225.                 { {'A', 'A', 111, 'A', 99}, 100},
  226.         }));
  227.     }
  228.  
  229.     try {
  230.         parking.Park({ 'A', 'A', 111, 'A', 99 });
  231.         assert(false);
  232.     }
  233.     catch (ParkingException) {
  234.     }
  235.  
  236.     try {
  237.         parking.Withdraw({ 'B', 'B', 222, 'B', 99 });
  238.         assert(false);
  239.     }
  240.     catch (ParkingException) {
  241.     }
  242.  
  243.     cout << "Success!"s << endl;
  244. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement