// Name: msglm // Date: Oct 21st, 2022 // Program Name: Menu System // Description: CLI, self-servicing kiosk #include #include #include #include using namespace std; //Classes //I would never, ever make this an object in production //the concept of an "Orderable" is pure data read from a file that should be acted upon, but not act. class Orderable { private: string name; double price; public: Orderable(double iprice, string iname) { name = iname; price = iprice; } string get_name() {return name;} double get_price() {return price;} }; //Structs struct foodOrder { string name; double price; int quantity; }; //Implementation of Nim's readline (https://nim-lang.org/docs/io.html#readLine%2CFile) because //I am absolutely sick of having to deal with C++'s obsession with streaming. // //I swear if I have to reimplement the entire Nim language in C++20 just //to get a compiled language that doesn't increase my chance of stroke 20 fold I will string readline(ifstream & fileVar) { string temp; getline(fileVar, temp); return temp; } void initalize(string location, ifstream & fileVar) { fileVar.open(location); if (!fileVar) { cout << "ERROR! " << location << " failed to open!"; exit(1); } } //Ideally, the input file should be JSON, YAML, or TOML based //instead of pure plain text for ease of human access //but C++ doesn't have JSON parsing library in std for some reason vector encodeOrderables(ifstream & fileVar) { string temp; vector orderablesFromFile; while(fileVar.peek() != EOF) { //Here's something absolutely nasty that I discovered while working on this: //when attempting to write the line //orderablesFromFile.push_back(Orderable(readline(fileVar)), stod(readline(fileVar))); //with the object's constructor taking the name then price parameter, I found out that //constructors are executed from right-to-left, not left-to-right and the price would be //read first rather than the name. // //This might be the case for all functions, I did not check. // //There is literally no good reason for this to be the case. orderablesFromFile.push_back(Orderable(stod(readline(fileVar)), readline(fileVar))); } return orderablesFromFile; } //Menu systems //Wish we could do some ncurses TUI menus, but alas we're stuck with subpar prompts int catagoryMenu() { int choice; //No input validation here since the rubric doesn't call for it. cout << "Pick a catagory\n"; cout << "1. Drink\n"; cout << "2. Appetizer\n"; cout << "3. Entree\n"; cout << "4. Dessert\n"; cout << "5. Finish Order\n"; cout << "Enter Selection: "; cin >> choice; return choice; } foodOrder orderingMenu(vector items) { foodOrder completeOrder; int choice; for(int itemPos = 0; itemPos < items.size(); itemPos++) { cout << itemPos << ". " << items[itemPos].get_name() << " - $" << items[itemPos].get_price() << endl; } cout << "Enter Selection: "; cin >> choice; cout << "Enter Amount Desired: "; cin >> completeOrder.quantity; completeOrder.name = items[choice].get_name(); completeOrder.price = items[choice].get_price(); //"...you will need to record the item name, price and the quantity desired inside of variables (vector or array) for output later..." //I am modifying this instruction a bit to use a struct instead since structs can hold multiple datatypes and play nice with functions return completeOrder; } //Who can afford to pay this much when tipping? //I can barely afford car insurance! double tip() { int choice; //No input validation here since the rubric doesn't call for it. cout << "What percent would you like to tip?\n"; cout << "1. 18%\n"; cout << "2. 20%.\n"; cout << "3. 25%.\n"; cout << "4. Custom Amount.\n"; cin >> choice; switch(choice) { case 1: return 0.18; break; case 2: return 0.20; break; case 3: return 0.25; break; case 4: double tip; cout << "Enter a tip amount (decimal notation) [ex: 0.18]: "; cin >> tip; //Evil solution to evil users return abs(tip); break; default: cout << "ERROR: Your input was invalid, terminating"; exit(1); } return choice; } double figureTotal(vector orderList) { double subtotal; for(int orderPos = 0; orderPos < orderList.size(); orderPos++) { subtotal = subtotal + orderList[orderPos].price; } double tax = subtotal*0.1; double total = subtotal+tax; //tips cout << "===Amount Currently Due==\n"; cout << "Subtotal: $" << subtotal << endl; cout << "Tax: $" << tax << endl; cout << "Total: $" << total << endl; cout << "=========================\n"; total = total + (total*tip()); cout << "\033[2J\033[1;1H"; cout << "===Amount Currently Due==\n"; cout << "Subtotal: $" << subtotal << endl; cout << "Tax: $" << tax << endl; cout << "Total: $" << total << endl; return total; } void collectDues(double amountDue) { double paid; while (amountDue > 0) { cout << "Please pay for the amount owed: $" << amountDue << endl; cout << "Enter payment: "; cin >> paid; amountDue = amountDue - paid; paid = 0; } } int main() { //File Vars & Inits ifstream drinkFile; ifstream appetizerFile; ifstream entreeFile; ifstream dessertFile; initalize("drink.txt", drinkFile); initalize("appetizer.txt", appetizerFile); initalize("entree.txt", entreeFile); initalize("dessert.txt", dessertFile); //Ordering Vars vector possibleDrinks = encodeOrderables(drinkFile); vector possibleAppetizer = encodeOrderables(appetizerFile); vector possibleEntree = encodeOrderables(entreeFile); vector possibleDessert = encodeOrderables(dessertFile); vector userOrderList; bool ordering = true; //"The customer should be able to remain in a category menu until they are ready to return to the main menu" //I assume this means that the customer should be allows to keep ordering until they're satisfied while(ordering) { switch(catagoryMenu()) { case 1: userOrderList.push_back(orderingMenu(possibleDrinks)); break; case 2: userOrderList.push_back(orderingMenu(possibleAppetizer)); break; case 3: userOrderList.push_back(orderingMenu(possibleEntree)); break; case 4: userOrderList.push_back(orderingMenu(possibleDessert)); break; case 5: ordering = false; break; default: cout << "ERROR: Your input was invalid, terminating"; exit(1); } } collectDues(figureTotal(userOrderList)); //When the customer is finished ordering, display the subtotal, tax, and total on the screen //Ask for a tip (make a suggested tip amount with 18%, 20%, 25%), then update the total with the tip amount entered //Get payment from the user and display change due to the customer //If the customer does not pay enough money, then the program should continue to ask for money until the total is paid in full } /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License Version 3 ONLY as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */