Advertisement
Petrovi4

Parking

Sep 7th, 2022
1,156
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.14 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 <algorithm>
  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. // возьмите реализацию хешера из прошлого задания
  59. class VehiclePlateHasher {
  60. public:
  61.     size_t operator()(const VehiclePlate& plate) const {
  62.         // измените эту функцию, чтобы она учитывала все данные номера
  63.         // рекомендуется использовать метод ToString() и существующий
  64.         // класс hash<string>
  65.         return hasher_(plate.ToString());
  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.         if (now_parked_.find(car) != now_parked_.end()) {
  87.             throw ParkingException();
  88.         }
  89.  
  90.         now_parked_[car] = Clock::now();
  91.     }
  92.  
  93.     // забрать машину с указанным номером
  94.     void Withdraw(const VehiclePlate& car) {
  95.         if (now_parked_.find(car) == now_parked_.end()) {
  96.             throw ParkingException();
  97.         }
  98.         TimePoint start_point = now_parked_.at(car);
  99.         complete_parks_[car] += (Clock::now() - start_point);
  100.         now_parked_.erase(car);
  101.     }
  102.  
  103.     // получить счёт за конкретный автомобиль
  104.     int64_t GetCurrentBill(const VehiclePlate& car) const {
  105.         if (now_parked_.find(car) == now_parked_.end() && complete_parks_.find(car) == complete_parks_.end()) {
  106.             return 0;
  107.         }
  108.         else {
  109.             TimePoint end_time = Clock::now();
  110.             TimePoint now_point = Clock::now();
  111.             Duration complete_duration = Clock::now() - Clock::now();
  112.             if (now_parked_.find(car) != now_parked_.end()) {
  113.                 now_point = now_parked_.at(car);
  114.             }
  115.             if (complete_parks_.find(car) != complete_parks_.end()) {
  116.                 complete_duration = complete_parks_.at(car);
  117.             }
  118.             Duration duration = (end_time - now_point) + complete_duration;
  119.             return std::chrono::duration_cast<std::chrono::seconds>(duration).count() * cost_per_second_;
  120.         }
  121.     }
  122.  
  123.     // завершить расчётный период
  124.     // те машины, которые находятся на парковке на данный момент, должны
  125.     // остаться на парковке, но отсчёт времени для них начинается с нуля
  126.     unordered_map<VehiclePlate, int64_t, VehiclePlateHasher> EndPeriodAndGetBills() {
  127.         unordered_map<VehiclePlate, int64_t, VehiclePlateHasher> result;
  128.  
  129.         for (const std::pair<VehiclePlate, TimePoint>& value : now_parked_) {
  130.             auto dur = Clock::now() - value.second;
  131.             result[value.first] = static_cast<int>(std::chrono::duration_cast<std::chrono::seconds>(dur).count() * cost_per_second_);
  132.         }
  133.  
  134.         for (auto& [car, complete_duration] : complete_parks_) {
  135.             result[car] += static_cast<int>(std::chrono::duration_cast<std::chrono::seconds>(complete_duration).count() * cost_per_second_);
  136.         }
  137.  
  138.         auto tmp1 = now_parked_;
  139.         for (auto& [car, value] : tmp1) {
  140.             now_parked_[car] = Clock::now();
  141.         }
  142.  
  143.         auto tmp2 = complete_parks_;
  144.         for (auto& [car, value] : tmp2) {
  145.             complete_parks_[car] = Clock::now() - Clock::now();
  146.         }
  147.  
  148.         auto tmp3 = result;
  149.         for (const auto& [key, value] : tmp3) {
  150.             if (value == 0) {
  151.                 result.erase(key);
  152.             }
  153.         }
  154.  
  155.         return result;
  156.     }
  157.  
  158.     // не меняйте этот метод
  159.     auto& GetNowParked() const {
  160.         return now_parked_;
  161.     }
  162.  
  163.     // не меняйте этот метод
  164.     auto& GetCompleteParks() const {
  165.         return complete_parks_;
  166.     }
  167.  
  168. private:
  169.     int cost_per_second_;
  170.     unordered_map<VehiclePlate, TimePoint, VehiclePlateHasher> now_parked_;
  171.     unordered_map<VehiclePlate, Duration, VehiclePlateHasher> complete_parks_;
  172. };
  173.  
  174. // эти часы удобно использовать для тестирования
  175. // они покажут столько времени, сколько вы задали явно
  176. class TestClock {
  177. public:
  178.     using time_point = chrono::system_clock::time_point;
  179.     using duration = chrono::system_clock::duration;
  180.  
  181.     static void SetNow(int seconds) {
  182.         current_time_ = seconds;
  183.     }
  184.  
  185.     static time_point now() {
  186.         return start_point_ + chrono::seconds(current_time_);
  187.     }
  188.  
  189. private:
  190.     inline static time_point start_point_ = chrono::system_clock::now();
  191.     inline static int current_time_ = 0;
  192. };
  193.  
  194. int main() {
  195.     Parking<TestClock> parking(10);
  196.  
  197.     TestClock::SetNow(10);
  198.     parking.Park({ 'A', 'A', 111, 'A', 99 });
  199.  
  200.     TestClock::SetNow(20);
  201.     parking.Withdraw({ 'A', 'A', 111, 'A', 99 });
  202.     parking.Park({ 'B', 'B', 222, 'B', 99 });
  203.  
  204.     TestClock::SetNow(40);
  205.    
  206.     assert(parking.GetCurrentBill({ 'A', 'A', 111, 'A', 99 }) == 100);
  207.     assert(parking.GetCurrentBill({ 'B', 'B', 222, 'B', 99 }) == 200);
  208.     parking.Park({ 'A', 'A', 111, 'A', 99 });
  209.  
  210.     TestClock::SetNow(50);
  211.     assert(parking.GetCurrentBill({ 'A', 'A', 111, 'A', 99 }) == 200);
  212.     assert(parking.GetCurrentBill({ 'B', 'B', 222, 'B', 99 }) == 300);
  213.     assert(parking.GetCurrentBill({ 'C', 'C', 333, 'C', 99 }) == 0);
  214.     parking.Withdraw({ 'B', 'B', 222, 'B', 99 });
  215.  
  216.     TestClock::SetNow(70);
  217.     {
  218.         // проверим счёт
  219.         auto bill = parking.EndPeriodAndGetBills();
  220.  
  221.         for (const auto& [key, value] : bill) {
  222.             cerr << key.ToString() << " - " << value << endl;
  223.         }
  224.  
  225.         // так как внутри макроса используется запятая,
  226.         // нужно заключить его аргумент в дополнительные скобки
  227.         assert((bill
  228.             == unordered_map<VehiclePlate, int64_t, VehiclePlateHasher>{
  229.                 { {'A', 'A', 111, 'A', 99}, 400},
  230.                 { {'B', 'B', 222, 'B', 99}, 300 },
  231.         }));
  232.     }
  233.  
  234.     TestClock::SetNow(80);
  235.     {
  236.         // проверим счёт
  237.         auto bill = parking.EndPeriodAndGetBills();
  238.  
  239.         for (const auto& [key, value] : bill) {
  240.             cerr << key.ToString() << " - " << value << endl;
  241.         }
  242.         // так как внутри макроса используется запятая,
  243.         // нужно заключить его аргумент в дополнительные скобки
  244.         assert((bill
  245.             == unordered_map<VehiclePlate, int64_t, VehiclePlateHasher>{
  246.                 { {'A', 'A', 111, 'A', 99}, 100},
  247.         }));
  248.     }
  249.  
  250.     try {
  251.         parking.Park({ 'A', 'A', 111, 'A', 99 });
  252.         assert(false);
  253.     }
  254.     catch (ParkingException) {
  255.     }
  256.  
  257.     try {
  258.         parking.Withdraw({ 'B', 'B', 222, 'B', 99 });
  259.         assert(false);
  260.     }
  261.     catch (ParkingException) {
  262.     }
  263.  
  264.     cout << "Success!"s << endl;
  265.  
  266.     return 0;
  267. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement