Advertisement
AyratT

Untitled

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