#pragma once #include #include #include #include #include "menugen.cpp" namespace Booking { using seat_num = uint64_t; using seat_range = std::pair; using uiBool = bool; constexpr size_t SEAT_CAPACITY = 20; class BookingException : public std::exception { public: const char* what() const noexcept override { return "Internal exception!"; } }; #define EXCEPTION(INTERNAL, EXTARNAL) \ class INTERNAL : public BookingException { \ const char* what() const noexcept override { return EXTARNAL; } \ }; EXCEPTION(AlreadyReserved, "Already reserved!") EXCEPTION(NotReserved, "Not reserved!") EXCEPTION(InvalidSeat, "Invalid seat number!"); EXCEPTION(InvalidArgument, "Invalid argument!") struct Seat { enum class Status { AVALIBLE, RESERVED, BROKEN }; Status s = Status::AVALIBLE; }; class Booker { private: Seat seats[SEAT_CAPACITY]; public: Seat::Status getSeatState(seat_num seat) { return seats[seat - 1].s; } void reserveSeat(seat_range r) { bool status = false; for (auto i = r.first - 1; i < r.second; ++i) status |= seats[i].s != Seat::Status::AVALIBLE; if (status) throw AlreadyReserved(); for (auto i = r.first - 1; i < r.second; ++i) seats[i].s = Seat::Status::RESERVED; } void cancelSeat(seat_range r) { bool status = false; for (auto i = r.first - 1; i < r.second; ++i) status |= seats[i].s != Seat::Status::RESERVED; if (status) throw NotReserved(); for (auto i = r.first - 1; i < r.second; ++i) seats[i].s = Seat::Status::AVALIBLE; } void breakSeat(seat_range r, std::ostream&os, const char* prefix) { for (auto i = r.first - 1; i < r.second; ++i) { if (seats[i].s == Seat::Status::RESERVED) os << prefix << "Reservation on seat " << i + 1 << " is canceled, seat is now broken\n"; seats[i].s = Seat::Status::BROKEN; } } void filter(const std::function& f, std::ostream& os) { for (seat_num i = 0; i <= SEAT_CAPACITY; ++i) { if (f(seats[i])) os << i + 1 << ' '; } os << '\n'; } auto operator<=>(const Booker& oth) const = default; Booker operator+(const Booker& oth) { Booker b; for (seat_num i = 0; i < SEAT_CAPACITY; ++i) { if (seats[i].s == Seat::Status::AVALIBLE || oth.seats[i].s == Seat::Status::AVALIBLE) b.seats[i].s = Seat::Status::AVALIBLE; if (seats[i].s == Seat::Status::RESERVED || oth.seats[i].s == Seat::Status::RESERVED) b.seats[i].s = Seat::Status::RESERVED; if (seats[i].s == Seat::Status::BROKEN || oth.seats[i].s == Seat::Status::BROKEN) b.seats[i].s = Seat::Status::BROKEN; } return b; } void print(seat_range r, std::ostream& os) const { for (seat_num i = r.first - 1; i < r.second; ++i) { switch (seats[i].s) { case Seat::Status::AVALIBLE: os << Menu::GREEN << "Seat " << i + 1 << " is avaliable\n" << Menu::RESET; break; case Seat::Status::RESERVED: os << Menu::YELLOW << "Seat " << i + 1 << " is reserved\n" << Menu::RESET; break; case Seat::Status::BROKEN: os << Menu::RED << "Seat " << i + 1 << " is broken\n" << Menu::RESET; break; default: break; } } } }; } std::ostream& operator<<(std::ostream& os, const Booking::Booker& b) { b.print({1, Booking::SEAT_CAPACITY}, os); return os; }