diff --git a/Inventory.java b/Inventory.java new file mode 100644 index 00000000..fc2ca502 --- /dev/null +++ b/Inventory.java @@ -0,0 +1,230 @@ +/* + * Tracks the restaurant's inventory of ingredients and supplies + */ +import java.util.Scanner; + +public class Inventory { + /* + * attributes + */ + private int cup; + private int tea; + private int milk; + private int boba; + private double cupBuyIn; + private double teaBuyIn; + private double milkBuyIn; + private double bobaBuyIn; + + /* + * constructor that create inventory with default value + */ + public Inventory(){ + this.cup = 5; + this.tea = 5; + this.milk = 5; + this.boba = 5; + this.cupBuyIn = 0.5; + this.teaBuyIn = 1; + this.milkBuyIn = 1; + this.bobaBuyIn = 0.5; + } + + /** + * getter of cup quantity + * @return cup + */ + public int getCup() { + return cup; + } + + /** + * getter of tea quantity + * @return tea + */ + public int getTea() { + return tea; + } + + /** + * getter of milk quantity + * @return milk + */ + public int getMilk() { + return milk; + } + + /** + * getter of boba quantity + * @return boba + */ + public int getBoba() { + return boba; + } + + /** + * getter of cup price + * @return cupBuyIn + */ + public double getCupBuyIn() { + return cupBuyIn; + } + + /** + * getter of tea price + * @return teaBuyIn + */ + public double getTeaBuyIn() { + return teaBuyIn; + } + + /** + * getter of milk price + * @return milkBuyIn + */ + public double getMilkBuyIn() { + return milkBuyIn; + } + + /** getter of boba price + * @return bobaBuyIn + */ + public double getBobaBuyIn() { + return bobaBuyIn; + } + + /** + * Setter of cup + * @param cup + */ + public void setCup(int cup) { + this.cup = cup; + } + + /** + * Setter of tea + * @param tea + */ + public void setTea(int tea) { + this.tea = tea; + } + + /** + * Setter of milk + * @param milk + */ + public void setMilk(int milk) { + this.milk = milk; + } + + /** + * Setter of boba + * @param boba + */ + public void setBoba(int boba) { + this.boba = boba; + } + + /** + * accessor of inventory + * @return inventoryList string that describes inventory + */ + public String getInventoryList() { + String inventoryList = "\nCurrent Inventory:\n" +"----------------\n" + + "a. Cups: " + cup + "\tBuy in price: " + cupBuyIn + + "\nb. Tea: " + tea + "\tBuy in price: " + teaBuyIn + + "\nc. Milk: " + milk + "\tBuy in price: " + milkBuyIn + + "\nd. Boba: " + boba + "\tBuy in price: " + bobaBuyIn + + "\n----------------"; + return inventoryList; + } + + /** + * @param itemType + * @param quantity + * @return cost for restock + */ + public double restockCost(String itemType, int quantity) { + switch (itemType) { + case "a": + return cupBuyIn * quantity; + case "b": + return teaBuyIn * quantity; + case "c": + return milkBuyIn * quantity; + case "d": + return bobaBuyIn * quantity; + default: + return 0; + } + } + + /** + * method that restock in different cases + * @param store + * @param input + * @param number + * @param in + */ + public void restock(Store store, String input, int number, Scanner in){ + boolean response; + switch (input) { + case "a": + if (store.getBalance() >= cupBuyIn * number) { + System.out.println("Purchase confirmed?"); + response = handleInput.handleYesNoInput(in); + if (response) { + store.setBalance(store.getBalance() - cupBuyIn * number); + this.cup += number; + } + } else { + System.out.println("Insufficient balance."); + } + break; + + case "b": + if (store.getBalance() >= teaBuyIn * number) { + System.out.println("Purchase confirmed?"); + response = handleInput.handleYesNoInput(in); + if (response) { + store.setBalance(store.getBalance() - teaBuyIn * number); + this.tea += number; + } + } else { + System.out.println("Insufficient balance."); + } + break; + + case "c": + if (store.getBalance() >= milkBuyIn * number) { + System.out.println("Purchase confirmed?"); + response = handleInput.handleYesNoInput(in); + if (response) { + store.setBalance(store.getBalance() - milkBuyIn * number); + this.milk += number; + } + } else { + System.out.println("Insufficient balance."); + } + break; + + case "d": + if (store.getBalance() >= bobaBuyIn * number) { + System.out.println("Purchase confirmed?"); + response = handleInput.handleYesNoInput(in); + if (response) { + store.setBalance(store.getBalance() - bobaBuyIn * number); + this.boba += number; + } + } else { + System.out.println("Insufficient balance."); + } + break; + + default: + System.out.println("Invalid input."); + break; + } + } +} + diff --git a/Menu.java b/Menu.java new file mode 100644 index 00000000..bdb7bb04 --- /dev/null +++ b/Menu.java @@ -0,0 +1,51 @@ +/* + * class that aggregate all menu items + */ +import java.util.Random; +import java.util.ArrayList; +import java.util.List; + +public class Menu { + /* + * aggregation of objects in menuItem class + */ + public List items; + + /** + * constructor + */ + public Menu() { + items = new ArrayList<>(); + } + + /** + * method that add menuitem to the list + * @param item + */ + public void addMenuItem(menuItem item) { + items.add(item); + } + + /** + * method that return menu list + * @return menuList + */ + public String getMenuList() { + StringBuilder menuList = new StringBuilder("Menu Details:\n" + "----------------\n"); + for (menuItem item : items) { + menuList.append(item.getMenuItem()).append("\n"); + } + menuList.append("----------------"); + return menuList.toString(); + } + + /** + * method that randomly generate a menu item + * @return an object from menuItem + */ + public menuItem getRandomMenuItem() { + Random random = new Random(); + int index = random.nextInt(items.size()); + return items.get(index); + } +} diff --git a/MenuItem.java b/MenuItem.java new file mode 100644 index 00000000..8550f9a9 --- /dev/null +++ b/MenuItem.java @@ -0,0 +1,94 @@ +/* + * Manages the menu items and their properties + */ + public class menuItem { + /* + * attributes + */ + private String name; + private int tea; + private int milk; + private boolean extraSize; + private boolean boba; + private double price; + + /** + * constructor + * @param name + * @param tea + * @param milk + * @param extraSize + * @param boba + * @param price + */ + public menuItem(String name, int tea, int milk, boolean extraSize, boolean boba, double price){ + this.name = name; + this.tea = tea; + this.milk = milk; + this.extraSize = extraSize; + this.boba = boba; + this.price = price; + } + + /** + * getter of name + * @return name + */ + public String getName() { + return name; + } + + /** + * method that return inventory of tea + * @return tea + */ + public int getTea() { + return tea; + } + + /** + * method that return inventory of milk + * @return milk + */ + public int getMilk() { + return milk; + } + + /** + * method that returns boolean value for extra size + * @return extraSize + */ + public boolean isExtraSize() { + return extraSize; + } + + /** + * method that returns boolean value for boba + * @return boba + */ + public boolean isBoba() { + return boba; + } + + /** + * getter of price + * @return price + */ + public double getPrice() { + return price; + } + + /** + * method that return single menu item + * @return menu description + */ + public String getMenuItem() { + return "Name: " + name + + "\tTea: " + tea + + "\tMilk: " + milk + + "\tExtra Size: " + extraSize + + "\tBoba: " + boba + + "\tPrice: " + price; + } +} + diff --git a/README.md b/README.md index c1a995eb..910a5889 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,38 @@ # CSC120-FinalProject ## Deliverables: - - Your final codebase - - Your revised annotated architecture diagram - - Design justification (including a brief discussion of at least one alternative you considered) - - A map of your game's layout (if applicable) + - Your final codebase (`Store.java`, `menuItem.java`, `Menu.java`, `Inventory.java`, `handleInput.java`, `gameController.java`) + - Your revised annotated architecture diagram (`architecture diagram.png`) + - Design justification (including a brief discussion of at least one alternative you considered) (`design justification.md`) + - A map of your game's layout (if applicable) (text included in `cheatsheet.md`) - `cheatsheet.md` - Completed `rubric.md` ## Additional Reflection Questions - What was your **overall approach** to tackling this project? + +My approach to this project begins from making draft for classes structure along with its attributes and methods for the game. Then, I systematically implement each part of this deaft. I also revised my plan based on feasibility and user experience. + - What **new thing(s)** did you learn / figure out in completing this project? + +I learned the use for scanner class since it is frequently called in my code. I also figure out how to draw up the plan and build a game from start to end. + - Is there anything that you wish you had **implemented differently**? + +I wish I could organize classes in a different structure and avoid taking scanner as an input argument in methods. + - If you had **unlimited time**, what additional features would you implement? + +I will add techinique, equipments and cleaniness to the store. Each of them has different way to improve and higher the value is, higher the income the player will get. + - What was the most helpful **piece of feedback** you received while working on your project? Who gave it to you? + +My boyfriend has some experience in java and he is the first player of my game. He suggested me to get rid of the parts that I was not able to handle, and helped me design the game values and make sure they are balanced。 + - If you could go back in time and give your past self some **advice** about this project, what hints would you give? + +I will tell myself "Don't be too stressful!" I was so worried that I wouldn't be able to finish the project that I sacrificed some of the fun and interactivity of the game. + - _If you worked with a team:_ please comment on how your **team dynamics** influenced your experience working on this project. + +I work alone. diff --git a/Store.java b/Store.java new file mode 100644 index 00000000..c84c4504 --- /dev/null +++ b/Store.java @@ -0,0 +1,190 @@ +/* + * class that represents the store + */ +import java.util.Scanner; + +public class Store { + /* + * attributes + */ + private String name; + // public double income; + // public double cost; + private double balance; + private int openingTime; + // public int equipment; + // public int technique; + // public int cleanliness; + // public double satisfaction; + + /** + * constructor that build a store in default value + * @param name + */ + public Store(String name){ + this.name = name; + this.balance = 0; + this.openingTime = 5; + // this.equipment = 0; + // this.technique = 0; + // this.cleanliness = 10; + } + + /** + * getter of name + * @return name + */ + public String getName() { + return name; + } + + /** + * getter of balance + * @return balance + */ + public double getBalance() { + return balance; + } + + /** + * getter of opening time + * @return openingTime + */ + public int getOpeningTime() { + return openingTime; + } + + /** + * mutator of store name + * @param in + */ + public void setName(Scanner in){ + System.out.println("Enter a name for your store: "); + String newName = in.next(); + this.name = newName; + System.out.println("Update successful! Your store is now named " + this.name + "."); + } + + /** + * setter of balance + * @param balance + */ + public void setBalance(double balance) { + this.balance = balance; + } + + /** + * setter for opening time + * @param openingTime + */ + public void setOpeningTime(int openingTime) { + this.openingTime = openingTime; + } + + /** + * method to extend opening time + * @param store + * @param in + * @param hours number of hour that player wants to extend + */ + public void extendOpeningTime(Store store, Scanner in) { + System.out.println("Enter number of hours you want to extend: "); + handleInput.handleExtendHourInput(store, in); + } + + /** + * Method that print out all attributes and value of a store + * @return storeInfo list that contains store information + */ + public String getStoreInfo() { + String storeInfo = "Store Information: \n" + "----------------" + + "\nName: " + this.name + + "\nBalance: " + this.balance + + "\nOpening Time: " + this.openingTime + "\n----------------"; + return storeInfo; + } + + // /* + // * method to improve equipment + // * @param hours number of hour that player wants to extend + // * @return OpeningTime new opening time + // * @return Balance new balance + // */ + // public void improveEquipment() { + // Scanner in = new Scanner (System.in); + // System.out.println("Enter number of points you want to improve for equipments: "); + // int value = in.nextInt(); + // if (this.equipment == 10) { + // System.out.println("The equipment of the store is updated to maximum! You have made great progress."); + // } + // else if (this.equipment + value <= 10) { + // this.equipment += value; + // this.balance = balance - value*20; + // System.out.println("You spend" + value*20 + "to improve your store's equipment! Your equipements are" + equipment + "out of 10 and your balance is" + balance + "."); + // in.close(); + // } else { + // System.out.println("The number you have entered may have exceeded the upgrade limit, please try again."); + // } + // } + + // /* + // * method to improve technique + // * @param hours number of hour that player wants to extend + // * @return OpeningTime new opening time + // * @return Balance new balance + // */ + // public void improveTechnique() { + // if (income >= 10) { + // this.technique = 1; + // } + // else if (income >= 50) { + // this.technique = 2; + // } + // else if (income >= 100) { + // this.technique = 3; + // } + // else if (income >= 200) { + // this.technique = 4; + // } + // else if (income >= 300) { + // this.technique = 5; + // } + // else if (income >= 500) { + // this.technique = 6; + // } + // else if (income >= 700) { + // this.technique = 7; + // } + // else if (income >= 1000) { + // this.technique = 8; + // } + // else if (income >= 1500) { + // this.technique = 9; + // } + // else if (income >= 2000) { + // this.technique = 10; + // } + // } + + // /* + // * method to improve cleaniness + // * @param hours number of hour that player wants to extend + // * @return OpeningTime new opening time + // * @return Balance new balance + // */ + // public void improveCleanliness() { + // Scanner in = new Scanner (System.in); + // System.out.println("Do you want to take a day off for deep cleaning? This will resume your cleanliness points back to 10. (yes/no)"); + // String value = in.next(); + // if ("yes".equalsIgnoreCase(value)) { + // System.out.println("The equipment of the store is updated to maximum! You have made great progress."); + // // !!function to skip the day and show result with clenainess back to 10. + // in.close(); + // } + // } + + // public void updateSatisfaction(){ + // double value = cleanliness*-0.1 + technique*0.05 + 2.5; + // this.satisfaction = value; + // } +} \ No newline at end of file diff --git a/architecture diagram.drawio.png b/architecture diagram.drawio.png new file mode 100644 index 00000000..56cd659f Binary files /dev/null and b/architecture diagram.drawio.png differ diff --git a/cheatsheet.md b/cheatsheet.md index d5dc4294..8a337a82 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -1,8 +1,78 @@ -This file will contain documentation for all commands available in your game. +# SPOILER ALERT +This file will contain documentation for all commands available in my game. -Note: It's a good idea to also make this list available inside the game, in response to a `HELP` command. +## Available Commands +### `Store` Class +- Store(String name) +- getName() +- getBalance() +- getOpeningTime() +- setName(Scanner in) +- setBalance(double balance) +- setOpeningTime(int openingTime) +- extendOpeningTime(Store store, Scanner in) +- getStoreInfo() +### `Menu` Class +- Menu() +- addMenuItem(MenuItem item) +- getMenuList() +- getRandomMenuItem() -# SPOILER ALERT +### `MenuItem` Class +- MenuItem(String name, int tea, int milk, boolean extraSize, boolean boba, double price) +- getName() +- getTea() +- getMilk() +- isExtraSize() +- isBoba() +- getPrice() +- getMenuItem() + +### `Inventory` Class +- Inventory() +- getCup() +- getTea() +- getMilk() +- getBoba() +- getCupBuyIn() +- getTeaBuyIn() +- getMilkBuyIn() +- getBobaBuyIn() +- setCup(int cup) +- setTea(int tea) +- setMilk(int milk) +- setBoba(int boba) +- getInventoryList() +- restockCost(String itemType, int quantity) +- restock(Store store, String input, int number, Scanner in) + +### `gameController` Class +- helpPage(Store store, Menu menu, Inventory inventory, Scanner in) +- description() +- dailyOrder(Store store, Menu menu, Inventory inventory, Hashtable dailyReceipt) +- orderAvailability(Inventory inventory, menuItem order) +- orderAvailabilityIdentifier(menuItem order, Inventory inventory) +- updateInventory(Inventory inventory, menuItem order) +- getReceipt(Integer day, Hashtable dailyReceipt, double dailyIncome) +- manageTab(Inventory inventory, Menu menu, Store store, double dailyIncome, Scanner in) +- getTotalReceipt(Hashtable totalReceipt) +- finalResult(Store store, Inventory inventory, Hashtable totalReceipt) + +### `handleInput` Class +- handleResetNameInput(Store store, Scanner in) +- handleHelpPageInput(Store store, Menu menu, Inventory inventory, Scanner in, Boolean loop) +- handleManageInput(Store store, Menu menu, Inventory inventory, Scanner in, Boolean loop) +- handleRestockInput(Store store, Inventory inventory, Scanner in) +- handleRestockNumberInput(String message, Scanner in) +- handleExtendHourInput(Store store, Scanner in) +- handleYesNoInput(Scanner in) + +## Description Of The Layout +The game is about running a boba store for 7 days. During the day the game automatically and randomly generate orders based on opening hour. At the end of the day, the program will check whether player achieves daily income goal, and if yes, the player will have access to manage the store by restocking and extending opening hours. Whenever the game stops, the program will print out a wrap up for the players' game record. + +## Challenges +To keep surviving, the main challenge is to earn as much money as possible and strategically spend it on updating your store. +- **Restock** ensures that your store is able to take all orders in stead of refund. For a business that is just starting out and therefore in desperate need of money, any refund could be fatal! +- As players move into the later stages of the game, the guaranteed inventory per order is not enough to meet the rapidly growing income goals, thus it is worth considering to **Extend Opening Hours**. However, considering how to divide the funds becomes a new dilemma. -If your game includes challenges that must be overcome to win, also list them below. diff --git a/design justification.md b/design justification.md new file mode 100644 index 00000000..917cadc3 --- /dev/null +++ b/design justification.md @@ -0,0 +1,26 @@ +## Design Choices and Decisions +I want to design a manage game since I love to play this kind of games. I play *Cooking Fever* and *Good Pizza, Great Pizza* most often and inspired of a google doodle [game](https://doodles.google/doodle/celebrating-bubble-tea/), I decided to set up boba store as context. + +The overall sturcture of this game, as stated in `readme.md` and in `cheatsheet.md`, is a manage game for 7 days. +>During the day the game automatically and randomly generate orders based on opening hour. At the end of the day, the program will check whether player achieves daily income goal, and if yes, the player will have access to manage the store by restocking and extending opening hours. Whenever the game stops, the program will print out a wrap up for the players' game record. + +Following the pattern I learned from previous assignments, I created 6 classes in my code: `Store`, `Menu`, `menuItem`, `Inventory`, `gameController`, and `handleInput`. Among all: +- `menu` has dependency with `menuItem` +- `gameController` has dependencies with `Store`, `Menu`, `Inventory` +- `handleInput` has interactions with `Store`, `Menu`, `Inventory` + +Specifically, I added `handleInput` class after first draft of my code. The major reason is that creating multiple scanner object is danger to my code and it frequently fell into error. For instance, I decided to applying merely one scanner throughout the code and aggregate all related codes into one class. After that, I no longer need to import scanner in every class and I am able to use same method for multiple places to avoid petition (e.g., `handleYesNoInput()` method). + +## Trade-offs and Alternative Consideration: +I realize that I did not fully take advantage of the associations between classes. For example, having both quantity and price in `Inventory` class does not seem like a good idea. Instead, I can design two subclasses that represents price and quantity respectively that contribute to `Inventory` class. + +Also, I think that I could make the section of taking orders more interesting and engaging. Perhaps, I can ask customers to memorize recipe of menu items and take orders by themselves. + + Since this was my first time creating a project on my own and I was too worried about my coding ability, I was not able to follow all java conventions very well. For exmaple, it is strange to ask for a scanner as input in methods like `setName()`. + + All these shortcomings are due to the fact that I prioritized simplicity over reasonableness when I wrote the code. Nevertheless, I appreciate this exprience and I believe I can do better next time. + +## Scalability and Conclusion: +The code demonstrates flexibility to accommodate future enhancements, such as introducing tips, expanding the menu, or adding attributes like cleanliness. Besides, this project serves as a valuable learning experience, laying the foundation for more polished and refined projects in the future. + +In conclusion, my design choices aim to deliver an enjoyable gaming experience while providing room for future expansion and improvement. The journey of this project has been really insightful, reinforcing my knowledge in java language and object oriented programming. \ No newline at end of file diff --git a/gameController.java b/gameController.java new file mode 100644 index 00000000..bc895def --- /dev/null +++ b/gameController.java @@ -0,0 +1,261 @@ +/* + * Manages the game's overall flow and interactions between different components + */ +import java.util.Hashtable; +import java.util.Scanner; + +public class gameController{ + /* + * attributes + */ + public int day; + public static int days = 7; + // public double dailyGoal = Math.pow(day, 2); + // public double dailyIncome; + + /** + * method printed at the beginning of the game as help page + * @param store + * @param menu + * @param inventory + * @param in + */ + public static void helpPage(Store store, Menu menu, Inventory inventory, Scanner in){ + System.out.println("What aspect of the store would you like to know about?" + + "\n a. Basic Infomation" + + "\n b. Menu" + + "\n c. Inventory" + + "\n d. Game Process"); + handleInput.handleHelpPageInput(store, menu, inventory, in, true); + } + + /** + * method that prints out description of the game + * @return description + */ + public static String description(){ + String description = ("- Your business will be run on a day to day basis, during the day you will make orders to earn money, and at the end of the day you will have the opportunity to review your bills, extend your opening hours, and c inventory!" + + "\n - openingTime represents the total opening hour of your store. You will earn more money with longer opening time per day. The maximum value is 10 hours and each extra hour costs 20.00." + "\n - The goal of your game is to imrpove your store to achieve daily goal for 7 days!"); + // System.out.println("equipment represents the equipments in your store. Better equipments brings higher income, and you can improve equipment by money. The maximum value is 10 points and each extra point costs 300.00."); + // System.out.println("- technique represents your technique of making orders. Better technique enhance income as well as satisfaction from customers. The maximum value is 10 points and you can improve technique by reaching goals in income."); + // System.out.println("- cleaniness represents the environment of your store. The more dirty your store is, the less customers you will take. The maximum value is 10 points and you need to close your store to take a deep clean."); + // System.out.println("- satisfaction represents the feedback from customers. You can gain more tips with better satisfaction. The maximum value is 5.0 and it consists of all factors of your store."); + return description; + } + + /** + * method that generate order and record income per day + * @param store + * @param menu + * @param inventory + * @param dailyReceipt + * @return dailyIncome + */ + public static double dailyOrder(Store store, Menu menu, Inventory inventory, Hashtable dailyReceipt) { + double dailyIncome = 0; + for (int time = 1; time <= store.getOpeningTime(); time++) { + menuItem order = menu.getRandomMenuItem(); + String name = order.getName(); + double price = order.getPrice(); + + if (orderAvailability(inventory, order)) { + dailyIncome += price; + updateInventory(inventory, order); + dailyReceipt.put(time, name + "\t " + price); + } else { + String identifier = orderAvailabilityIdentifier(order, inventory); + dailyReceipt.put(time, "Insufficient inventory (" + identifier + " )\t " + "0.0"); + } + } + return dailyIncome; + } + + /** + * method that evaluate whether inventory is sufficient for a specific order + * @param inventory + * @param order + * @return boolean value for order availability + */ + private static boolean orderAvailability(Inventory inventory, menuItem order) { + return inventory.getCup() >= 1 && + inventory.getMilk() >= order.getMilk() && + inventory.getTea() >= order.getTea() && + (!order.isBoba() || inventory.getBoba() >= 1); + } + + /** + * method that returns which kind(s) of ingredient is out of stock for a specific order + * @param order + * @param inventory + * @return identifier that contains insufficient ingredient(s) + */ + private static String orderAvailabilityIdentifier(menuItem order, Inventory inventory) { + StringBuilder identifier = new StringBuilder(); + if (inventory.getCup() < 1) { + identifier.append(" cup"); + } + if (inventory.getMilk() < order.getMilk()) { + identifier.append(" milk"); + } + if (inventory.getTea() < order.getTea()) { + identifier.append(" tea"); + } + if ((order.isBoba() && inventory.getBoba() < 1)) { + identifier.append(" boba"); + }; + return identifier.toString(); + } + + /** + * method that update inventory after taking an order + * @param inventory + * @param order + */ + private static void updateInventory(Inventory inventory, menuItem order) { + inventory.setCup(inventory.getCup() - 1); + inventory.setMilk(inventory.getMilk() - order.getMilk()); + inventory.setTea(inventory.getTea() - order.getTea()); + if (order.isBoba()) { + inventory.setBoba(inventory.getBoba() - 1); + } + } + + /** + * method that return receipt which shows order records within a day + * @param day + * @param dailyReceipt + * @param dailyIncome + * @return receipt for one day + */ + public static String getReceipt(Integer day, Hashtable dailyReceipt, double dailyIncome){ + StringBuilder receipt = new StringBuilder(); + receipt.append("\nCheck your receipt: \n"); + receipt.append("Day " + day); + receipt.append("\n----------------\n"); + for (Integer key : dailyReceipt.keySet()) { + receipt.append("Order ").append(key).append(": ").append(dailyReceipt.get(key)).append("\n"); + } + receipt.append("----------------\n"); + receipt.append("Total income: ").append(dailyIncome).append("\n"); + return receipt.toString(); + } + + /** + * method that shows manage tab after one day's business is over + * @param inventory + * @param menu + * @param store + * @param dailyIncome + * @param in + */ + public static void manageTab(Inventory inventory, Menu menu, Store store, double dailyIncome, Scanner in){ + store.setBalance(store.getBalance() + dailyIncome); + boolean loop = true; + System.out.println("You've earned " + dailyIncome + " today and your store balance is " + store.getBalance() + " ! How do you want to manage your store?" ); + while (loop) { + loop = handleInput.handleManageInput(store, menu, inventory, in, loop); + } + } + + /** + * method that prints out all receipt during the game + * @param totalReceipt + * @return receipt for all days + */ + public static String getTotalReceipt(Hashtable totalReceipt){ + StringBuilder receipt = new StringBuilder(); + receipt.append("\nReceipt Records: "); + receipt.append("\n----------------\n"); + for (Integer key : totalReceipt.keySet()) { + receipt.append("Day ").append(key).append(": ").append(totalReceipt.get(key)).append("\n"); + } + receipt.append("----------------\n"); + return receipt.toString(); + } + + /** + * method that print out all informations again after the game is done + * @param store + * @param inventory + * @param totalReceipt + */ + public static void finalResult(Store store, Inventory inventory, Hashtable totalReceipt){ + String storeInfo = store.getStoreInfo(); + String inventoryList = inventory.getInventoryList(); + String gameRecord = gameController.getTotalReceipt(totalReceipt); + System.out.println("Here's a summary of your game records. We hope you've enjoyed the game!"); + System.out.println(storeInfo); + System.out.println(inventoryList); + System.out.println(gameRecord); + } + + /** + * @param args + */ + public static void main(String[] args) { + /* + * Initialization + */ + Store bobaStore = new Store("Boba Fever"); + String storeName = bobaStore.getName(); + Inventory inventory = new Inventory(); + Menu menu = new Menu(); + menu.addMenuItem(new menuItem("Small Milk Tea", 1, 1, false, false, 4.00)); + menu.addMenuItem(new menuItem("Large Milk Tea",2, 1, true, false, 6.00)); + menu.addMenuItem(new menuItem("Small Boba Milk Tea",1, 1, false, true, 5.00)); + menu.addMenuItem(new menuItem("Large Boba Milk Tea",2, 1, true, true, 7.50)); + menu.addMenuItem(new menuItem("Small Milk with Boba",0, 2, false, true, 5.00)); + menu.addMenuItem(new menuItem("Large Milk with Boba",0, 3, true, true, 7.50)); + menu.addMenuItem(new menuItem("Small Tea",2, 0, false, false, 4.00)); + menu.addMenuItem(new menuItem("Large Tea",3, 0, false, false, 6.00)); + handleInput handle = new handleInput(); + Hashtable totalReceipt= new Hashtable<>(); + Scanner in = new Scanner (System.in); + + /* + * Welcome + */ + System.out.println("\nWelcome to Boba Fever! Get ready to fulfill customer orders and keep your business running to survive for a week!"); + System.out.print("The initial store is named " + storeName + ". "); + handle.handleResetNameInput(bobaStore, in); + + /* + * Print store information and rules + */ + System.out.println("\nNow, let's explore your store."); + gameController.helpPage(bobaStore, menu, inventory, in); + System.out.println("\nIt appears you have some understanding of your store. Are you ready to start?"); + Boolean loop = handleInput.handleYesNoInput(in); + + /* + * Processing the game + */ + if (!loop) { + System.out.println("\nThat's perfectly fine. Hope to see you back soon! "); + } + else if (loop) { + System.out.println("\nLet's get started!\n"); + for (int day = 1; day <= days; day++) { + double dailyGoal = Math.pow(day, 2); + Hashtable dailyReceipt = new Hashtable<>(); + System.out.println("Goal of day " + day + ": " + dailyGoal); + + double dailyIncome = gameController.dailyOrder(bobaStore, menu, inventory, dailyReceipt); + String Receipt = gameController.getReceipt(day, dailyReceipt, dailyIncome); + System.out.println(Receipt); + totalReceipt.put(day, dailyIncome); + + if (dailyIncome < dailyGoal) { + System.out.println("Today's goal was not achieved. Game Over!\n"); + gameController.finalResult(bobaStore, inventory, totalReceipt); + break; + } else { + System.out.println("Congratulations! You achieved today's goal! Let's switch to the management tab...\n"); + gameController.manageTab(inventory, menu, bobaStore, dailyIncome, in); + } + gameController.finalResult(bobaStore, inventory, totalReceipt); + } + } + in.close(); + } +} \ No newline at end of file diff --git a/handleInput.java b/handleInput.java new file mode 100644 index 00000000..d2098067 --- /dev/null +++ b/handleInput.java @@ -0,0 +1,205 @@ +/* + * class that aggregate all scanner during the game + */ +import java.util.Scanner; + +public class handleInput { + /** + * method that deal with name change of the store + * @param store + * @param in + */ + public void handleResetNameInput(Store store, Scanner in) { + while (true) { + System.out.println("Would you like to make a change? (yes/no): "); + String input = in.nextLine().trim().toLowerCase(); + + if (input.equals("yes")) { + System.out.println("Continuing..."); + store.setName(in); + break; + } else if (input.equals("no")) { + System.out.println("Continuing as Boba Store..."); + break; + } else { + System.out.println("Invalid input. Please enter 'yes' or 'no'."); + } + } + } + + /** + * method that deal with help page at the beginning of the game + * @param store + * @param menu + * @param inventory + * @param in + * @param loop + */ + public static void handleHelpPageInput(Store store, Menu menu, Inventory inventory, Scanner in, Boolean loop) { + String storeInfo = store.getStoreInfo(); + String menuList = menu.getMenuList(); + String inventoryList = inventory.getInventoryList(); + String description = gameController.description(); + + while (loop){ + System.out.println("(a/b/c/d): "); + String input = in.next().trim().toLowerCase(); + if (input.equals("a")) { + System.out.println("Loading..."); + System.out.println(storeInfo); + } else if (input.equals("b")) { + System.out.println("Loading..."); + System.out.println(menuList); + } else if (input.equals("c")) { + System.out.println("Loading..."); + System.out.println(inventoryList); + } else if (input.equals("d")) { + System.out.println("Loading..."); + System.out.println(description); + } else { + System.out.println("Invalid input. Please enter 'a', 'b', 'c' or 'd'."); + } + System.out.println("\nDo you have any other parts you'd like to know about?"); + loop = handleInput.handleYesNoInput(in); + } + } + + /** + * method that handle manage tab process + * @param store + * @param menu + * @param inventory + * @param in + * @param loop + * @return boolean value about whether player wants to stay in manage tab + */ + public static boolean handleManageInput(Store store, Menu menu, Inventory inventory, Scanner in, Boolean loop){ + while (loop){ + System.out.println("\n a. Check inventory and restock" + + "\n b. Extend opening hour" + + "\n c. Exit management tab" + "\n(a/b/c): "); + String input = in.next().trim().toLowerCase(); + if (input.equals("a")) { + System.out.println("Loading..."); + handleRestockInput(store, inventory, in); + } else if (input.equals("b")) { + System.out.println("Loading..."); + store.extendOpeningTime(store, in); + } else if (input.equals("c")) { + System.out.println("\nMoving on to the next day...\n"); + return false; + } else { + System.out.println("Invalid input. Please enter 'a' or 'b'."); + } + } + System.out.println("\nDo you have any other tasks to complete in the management tab?"); + return handleInput.handleYesNoInput(in); + } + + /** + * method that deal with restock - part 1 + * @param store + * @param menu + * @param inventory + * @param in + * @param loop + */ + public static void handleRestockInput(Store store, Inventory inventory, Scanner in) { + while (true) { + String inventoryList = inventory.getInventoryList(); + System.out.println(inventoryList); + + System.out.println("Enter the index that you want to purchase (a/b/c/d), or 'e' to exit: "); + String input = in.next().trim().toLowerCase(); + + if ("e".equals(input)) { + break; // Exit the restock loop + } + + if (input.equals("a") || input.equals("b") || input.equals("c") || input.equals("d")) { + int number = handleRestockNumberInput("Enter the number of items you want to purchase: ", in); + double cost = inventory.restockCost(input, number); + + if (store.getBalance() >= cost) { + inventory.restock(store, input, number, in); + System.out.println("Restock successful. New balance: " + store.getBalance()); + } else { + System.out.println("Insufficient balance."); + } + } else { + System.out.println("Invalid input."); + } + } + } + + /** + * method that deal with restock - part 2 + * @param store + * @param inventory + * @param input + * @param in + */ + private static int handleRestockNumberInput(String message, Scanner in) { + System.out.println(message); + while (!in.hasNextInt()) { + System.out.println("Invalid input. Please enter a number."); + in.next(); // Consume the invalid input + } + return in.nextInt(); + } + + /** + * method that deal with request for extending opening hour + * @param store + * @param in + */ + public static void handleExtendHourInput(Store store, Scanner in){ + if (in.hasNextInt()) { + int input = in.nextInt(); + int openingTime = store.getOpeningTime(); + double balance = store.getBalance(); + if (openingTime == 10 || openingTime + input > 10) { + System.out.println("Invalid number. Back to main tab..."); + } else if (openingTime + input <= 10) { + System.out.println("Extend " + input + " of opening hour will cost you " + input * 20 + ". Purchase confirmed?"); + boolean response = handleYesNoInput(in); + if (response) { + if (balance >= input * 20) { + store.setOpeningTime(store.getOpeningTime() + input); + store.setBalance(store.getBalance() - input * 20); + System.out.println("Purchase Successful. You spend " + input * 20 + " to extend your store's opening time! You can take " + store.getOpeningTime() + " orders per day and your balance is " + store.getBalance() + " ."); + } else { + System.out.println("Insufficient balance, please try again."); + } + } else { + System.out.println("Returning to the previous step..."); + } + } else { + System.out.println("Invalid input. Please enter a valid integer."); + in.next(); + } + } + } + + /** + * method that deal with general yes/no response questions + * @param in + * @return boolean value that turns yes/no into true/false + */ + public static boolean handleYesNoInput(Scanner in) { + while (true) { + System.out.println(" (yes/no): "); + String input = in.next().trim().toLowerCase(); + + if (input.equals("yes")) { + System.out.println("Continuing..."); + return true; + } else if (input.equals("no")) { + System.out.println("Continuing..."); + return false; + } else { + System.out.println("Invalid input. Please enter 'yes' or 'no'."); + } + } + } +} \ No newline at end of file diff --git a/rubric.md b/rubric.md index 8bb8f4c8..a05db27e 100644 --- a/rubric.md +++ b/rubric.md @@ -1,48 +1,48 @@ ## Front-End Design (10 pts) -_____ 2 pts: Game has a **robust, understandable text-based interface** that allows the player to control their movement through the game. Player should be able to enter any command at any time, and if it makes sense in the current context it will be carried out. +yes 2 pts: Game has a **robust, understandable text-based interface** that allows the player to control their movement through the game. Player should be able to enter any command at any time, and if it makes sense in the current context it will be carried out. -_____ 2 pts: Submission includes a **cheat sheet** (`cheatsheet.md`) documenting all of the available commands, as well as a **description of the layout** of your game world's underlying physical layout; this can be described in words, or included as a separate image file if you prefer to sketch a map by hand. If your game includes **challenges** that must be overcome to win, also describe them here. +yes 2 pts: Submission includes a **cheat sheet** (`cheatsheet.md`) documenting all of the available commands, as well as a **description of the layout** of your game world's underlying physical layout; this can be described in words, or included as a separate image file if you prefer to sketch a map by hand. If your game includes **challenges** that must be overcome to win, also describe them here. -_____ 2 pts: Storyline driving the game is **engaging**, and individual elements of play make sense within the context of the story. +yes 2 pts: Storyline driving the game is **engaging**, and individual elements of play make sense within the context of the story. -_____ 2 pts: Game has **multiple possible paths / outcomes** (i.e. gameplay depends on player's choices and is not the same every time). +yes 2 pts: Game has **multiple possible paths / outcomes** (i.e. gameplay depends on player's choices and is not the same every time). -_____ 1 pt: Gameplay supports **reversible moves** where reasonable (e.g., if you pick up an object, you should be able to put it back down again later, possibly in a different place; if you go north then you should be able to return to the previous location by going south unless something has blocked your return path). +yes 1 pt: Gameplay supports **reversible moves** where reasonable (e.g., if you pick up an object, you should be able to put it back down again later, possibly in a different place; if you go north then you should be able to return to the previous location by going south unless something has blocked your return path). -_____ 1 pt: Some paths through the game have **restricted access** until the player has completed a task or acquired a specific item (i.e. a key to open a door, etc.). +yes 1 pt: Some paths through the game have **restricted access** until the player has completed a task or acquired a specific item (i.e. a key to open a door, etc.). ## Back-End Design (10 pts) -_____ 2 pts: Selected classes(s) are **effective, efficient** at supporting the desired operations and program behavior. +yes 2 pts: Selected classes(s) are **effective, efficient** at supporting the desired operations and program behavior. -_____ 2 pts: Design justification includes a discussion of at least one (reasonable) **alternative design** that could have been used, and the reasons why you decided against this alternative. +yes 2 pts: Design justification includes a discussion of at least one (reasonable) **alternative design** that could have been used, and the reasons why you decided against this alternative. -_____ 2 pts: The project makes effective use of **Java built-in classes** whenever they are appropriate. +yes 2 pts: The project makes effective use of **Java built-in classes** whenever they are appropriate. -_____ 2 pts: The project's design is **extensible** (i.e. someone else could pick up where you left off, adding on or modifying the game without requiring a total rewrite). +yes 2 pts: The project's design is **extensible** (i.e. someone else could pick up where you left off, adding on or modifying the game without requiring a total rewrite). -_____ 2 pts: Submission includes an **architecture diagram** describing the relationships between all classes. +yes 2 pts: Submission includes an **architecture diagram** describing the relationships between all classes. ## General Items (10 pts): -_____ 4 pts: Program compiles without errors or warnings. +yes 4 pts: Program compiles without errors or warnings. -_____ 2 pts: Executes fully & consistently without crashing (exception/freeze). +yes 2 pts: Executes fully & consistently without crashing (exception/freeze). -_____ 2 pt: Complies with style guidelines (missing items 1 pt each): +yes 2 pt: Complies with style guidelines (missing items 1 pt each): - _____ Classes & class members all have Javadoc header comments. + yes Classes & class members all have Javadoc header comments. - _____ Clear and consistent indentation of bracketed sections. + yes Clear and consistent indentation of bracketed sections. - _____ Adheres to Java conventions on naming & capitalization. + yes Adheres to Java conventions on naming & capitalization. - _____ Methods & variables all have clear and accurate names. + yes Methods & variables all have clear and accurate names. - _____ Methods avoid confusing side effects. + yes Methods avoid confusing side effects. -_____ 1 pt: All required files included with submission (including completed checklist file). +yes 1 pt: All required files included with submission (including completed checklist file). -_____ 1 pt: `readme.md` contains your reflection on the project and responses to all prompts . +yes 1 pt: `readme.md` contains your reflection on the project and responses to all prompts .