Guest User

Untitled

a guest
Sep 10th, 2024
45
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.33 KB | Source Code | 0 0
  1. CONFIG = {
  2.     "recipe": {
  3.         "espresso": {
  4.             "ingredients": {
  5.                 "water": 50,
  6.                 "milk": 0,  # Added this in because "sparse" data is usually normalized before used.
  7.                 "coffee": 18,
  8.             },
  9.             "cost": 1.5,
  10.         },
  11.         "latte": {
  12.             "ingredients": {
  13.                 "water": 200,
  14.                 "milk": 150,
  15.                 "coffee": 24,
  16.             },
  17.             "cost": 2.5,
  18.         },
  19.         "cappuccino": {
  20.             "ingredients": {
  21.                 "water": 250,
  22.                 "milk": 100,
  23.                 "coffee": 24,
  24.             },
  25.             "cost": 3.0,
  26.         }
  27.     },
  28.     "resources": {
  29.         "water": 300,
  30.         "milk": 200,
  31.         "coffee": 100,
  32.     },
  33.     "money": {
  34.         "value": 0,
  35.     }
  36. }
  37.  
  38. class CoffeeMaker:
  39.     """A Coffee Maker."""
  40.     def __init__(self, config: dict[str, any]) -> None:
  41.         """Initialize a coffee maker."""
  42.         self.config = config
  43.         self.running = True
  44.  
  45.     def calc_ingredients(self, recipe: dict[str, int]) -> dict[str, float]:
  46.         """Calculate the ingredients left after using recipe."""
  47.         resources = self.config["resources"]
  48.         return {ingredient: resources[ingredient] - recipe[ingredient] for ingredient in resources.keys()}
  49.  
  50.     def charge(self, tender: float, order: str) -> float:
  51.         """Calculate the leftover change from tender after subtracting order cost."""
  52.         cost = self.config["recipe"][order]["cost"]
  53.         self.config["money"]["value"] += cost
  54.         return tender - cost
  55.  
  56.     def get_units(self, ingredient: str) -> str:
  57.         """Return the units used for a particular ingredient"""
  58.         match ingredient:
  59.             case "water" | "milk":
  60.                 return "ml"
  61.             case "coffee":
  62.                 return "g"
  63.             case _:
  64.                 raise TypeError(f"Units not known for ingredient. {ingredient=}")
  65.  
  66.     def is_enough_ingredients(self, ingredients: dict[str, int]) -> bool:
  67.         """Flag whether the coffee maker has sufficient resources for a recipe."""
  68.         return all((ingredient > 0 for ingredient in ingredients.values()))
  69.  
  70.     def is_valid_order(self, order: str) -> bool:
  71.         """Flag whether the order is support by this machine."""
  72.         return order in self.config["recipe"]
  73.  
  74.     def make_recipe(self, ingredients: dict[str, int]) -> None:
  75.         """Reduce the number of resources by the recipe's ingredients."""
  76.         self.config["resources"].update(ingredients)
  77.  
  78.     def prompt(self, typ: str) -> str | int:  # Ideally, functions should only return 1 type.
  79.         """Prompt the user with the given prompt type and return their response."""
  80.         match typ:
  81.             case "menu":
  82.                 if (resp := input("What would you like (espresso/latte/cappuccino): ").lower()) == "off":
  83.                     self.stop()
  84.                 return resp
  85.             case "charge":
  86.                 quarters = int(input("How many quarters: "))
  87.                 dimes = int(input("How many dimes: "))
  88.                 nickels = int(input("How many nickels: "))
  89.                 pennies = int(input("How many pennies: "))
  90.                 return round((quarters * .25) + (dimes * .1) + (nickels * .05) + (pennies * .01), 2)
  91.             case _:
  92.                 raise TypeError(f"Unknown prompt option. {typ=}")
  93.  
  94.     def report(self) -> None:
  95.         """Output a summary report of ingredients leftover and money."""
  96.         report = ""
  97.         for ingredient, leftover in self.config["resources"].items():
  98.             units = self.get_units(ingredient)
  99.             report += f"{ingredient.upper()}: {leftover} {units}\n"
  100.         money = self.config["money"]["value"]
  101.         report += f"MONEY: {money}"
  102.         print(report)
  103.  
  104.     def start(self):
  105.         """Start the coffee maker."""
  106.         try:
  107.             while self.running:
  108.                 order = self.prompt("menu")
  109.  
  110.                 if order == "report":
  111.                     self.report()
  112.                     continue
  113.  
  114.                 if not self.is_valid_order(order):
  115.                     print("Sorry that command is not supported.")
  116.                     continue
  117.  
  118.                 recipe = self.config["recipe"][order]['ingredients']
  119.                 ingredients = self.calc_ingredients(recipe)
  120.  
  121.                 if not self.is_enough_ingredients(ingredients):
  122.                     ingredient = min(ingredients, key=ingredients.get)
  123.                     print(f"Sorry, there is not enough {ingredient}.")
  124.                     continue
  125.  
  126.                 tender = self.prompt("charge")
  127.  
  128.                 if (change := self.charge(tender, order)) < 0:
  129.                     print("Sorry, that's not enough money. Money refunded.")
  130.                     continue
  131.  
  132.                 if change > 0:
  133.                     print(f"Your change is {change}")
  134.  
  135.                 self.make_recipe(ingredients)
  136.         except (StopIteration, KeyboardInterrupt):
  137.             pass
  138.  
  139.     def stop(self):
  140.         """Turn off the coffee maker."""
  141.         # If you had to clean up anything, save a backup, stop a process.
  142.         print("System shutting down.")
  143.         raise StopIteration("System shutdown requested.")
  144.  
  145. def main():
  146.     """Main Entry Point."""
  147.     CoffeeMaker(CONFIG).start()
  148.  
  149. if __name__ == '__main__':
  150.     main()
  151.  
  152.  
Advertisement
Add Comment
Please, Sign In to add comment