1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
|
#include <limits>
#include <iostream>
#include <iomanip>
//#include "keyinp.hpp"
#include <string>
#include <type_traits>
#include <algorithm>
#include <optional>
#include <sstream>
#include <cctype>
#include <charconv>
#include <cstdlib>
template<typename T = int>
[[nodiscard]] auto stonum(const std::string& str)
{
static_assert(std::is_arithmetic_v<T>);
constexpr char white[] {" \n\r\t"};
bool ok {false};
T num {};
if (const auto fl {str.find_last_not_of(white)}; fl != std::string::npos) {
const auto end {str.data() + fl + 1};
const auto first {str.data() + str.find_first_not_of(white)};
ok = (end != first) && (std::from_chars(first, end, num).ptr == end);
}
return ok ? std::optional<T>{num} : std::optional<T> {};
}
template<>
[[nodiscard]] auto stonum<double>(const std::string& str)
{
constexpr char white[] {" \n\r\t"};
bool ok {false};
double num {};
if (const auto fl {str.find_last_not_of(white)}; fl != std::string::npos) {
const auto end {str.data() + fl + 1};
const auto first {str.data() + str.find_first_not_of(white)};
if (end != first) {
std::string snum(first, end);
char* ech;
num = strtod(snum.c_str(), &ech);
ok = (*ech == 0);
}
}
return ok ? std::optional<double>{num} : std::optional<double> {};
}
[[nodiscard]] auto getStr(const std::string& prmpt, bool noblank = true)
{
constexpr char term[] {": "};
std::string str;
while ((std::cout << prmpt << term) && (!std::getline(std::cin, str) || (noblank && str[0] < ' '))) {
std::cout << "Invalid input" << std::endl;
std::cin.clear();
}
return str;
}
template<typename T = int>
[[nodiscard]] auto getNum(const std::string& prmpt)
{
static_assert(std::is_arithmetic_v<T>);
decltype(stonum<T>("")) optval;
do {
optval = stonum<T>(getStr(prmpt, true));
} while (!optval && (std::cout << "Bad input" << std::endl));
return *optval;
}
template<typename T = int>
[[nodiscard]] auto getNum(const std::string& prmpt, T nmin, T nmax)
{
static_assert(std::is_arithmetic_v<T>);
if ((nmin == std::numeric_limits<T>::lowest()) && (nmax == std::numeric_limits<T>::max()))
return getNum<T>(prmpt);
const auto defs = [nmin, nmax]() {
std::ostringstream os;
os << " (";
if ((nmin != std::numeric_limits<T>::lowest()) || std::is_unsigned<T>::value)
os << nmin;
os << " - ";
if (nmax != std::numeric_limits<T>::max())
os << nmax;
os << ")";
return os.str();
} ();
T num {};
const std::string pr {prmpt + defs};
do {
num = getNum<T>(pr);
} while (((num < nmin) || (num > nmax)) && (std::cout << "Input out of range" << defs << std::endl));
return num;
}
[[nodiscard]] auto getChar(const std::string& prmpt, int noblank = true) // NOTE int not bool for overload resolution
{
std::string str;
bool bad {true};
do {
str = getStr(prmpt, noblank);
if (bad = (noblank && str.size() != 1) || (!noblank && str.size() > 1); bad)
std::cout << "Bad input" << std::endl;
} while (bad);
return str.empty() ? char(0) : str[0];
}
[[nodiscard]] auto getChar(const std::string& prmpt, char def)
{
using namespace std::string_literals;
const auto ispr = std::isprint(def);
const auto ch = getChar(prmpt + (ispr ? " ["s + def + "]"s : ""s), !ispr);
return ch ? ch : def;
}
[[nodiscard]] auto getChar(const std::string& prmpt, const std::string& val, char def = {}) {
if (val.empty())
return getChar(prmpt, def);
std::string vs {" ("};
for (size_t i = 0; i < val.size(); vs += val[i++])
if (i) vs += '/';
vs += ')';
char ch;
do {
ch = (char)std::toupper(getChar(prmpt + vs, def));
} while ((val.find(ch) == std::string::npos) && (std::cout << "Input not a valid value" << vs << std::endl));
return ch;
}
int main()
{
char name[] = "user.txt";
constexpr auto delux {15.80}; // Delux meal
constexpr auto standard {11.75}; // Standard meal
constexpr auto child {60}; // Child discount percent
constexpr auto chdelux {delux * child / 100.0}; // Child delux meal
constexpr auto chstand {standard * child / 100.0}; // Child standard meal
constexpr auto tiptax {18}; // Tip & tax percent. Applies food only
constexpr auto surcharge {7}; // Surcharge percent for total bill if Friday, Saturday, Sunday
constexpr auto prompt {10}; // Days for discount
constexpr auto maxdisc {5}; // Maximum discount allowed
constexpr auto surday {4}; // First week day surcharge applied
constexpr auto discday {10}; // Discount within days
constexpr double roomrate[5] {55.0, 75.0, 85.0, 100.0, 130.0}; // Room rates
constexpr double discount[][2] {{100.0, 0.5}, {400.0, 3.0}, {800.0, 4.0}}; // Discount rates
const auto AdServ = getNum("Number of adults served", 1, std::numeric_limits<int>::max());
const auto ChldServ = getNum("Number of children served", 0, std::numeric_limits<int>::max());
const auto type = getChar("Type of meal - (D)elux, (S)standard", "DS", 'S');
const auto room = getChar("Room letter", "ABCDE");
const auto day = getNum("Day of week number - Monday(1)..Sunday(7)", 1, 7);
const auto elapse = getNum("Number of days elapsed since held", 0, 365);
const auto deposit = getNum<double>("Deposit", 0, std::numeric_limits<double>::max());
const auto mealcost = (type == 'D') * (delux * AdServ + chdelux * ChldServ) + (type == 'S') * (standard * AdServ + chstand * ChldServ);
auto total = roomrate[room - 'A'] + mealcost * (1.0 + tiptax / 100.0);
if (day > surday)
total += total * surcharge / 100.0;
if (elapse < discday) {
bool apply {false};
for (const auto& d : discount)
if (total < d[0]) {
total -= total * d[1] / 100;
apply = true;
break;
}
if (apply == false)
total -= total * maxdisc / 100.0;
}
total -= deposit;
std::cout << std::fixed << std::setprecision(2) << "Amount payable is $" << total << std::endl;
}
|