Python boot camp by Dr.Angela day15

#Mission>> Virtual Starbucks Machine
かの有名なスタバの自動販売機を作成してみよう！
__機能__
__・3つの味があり、レシピがそれぞれ異なる__
☑Latte(450円)：200ml water, 24g coffee, 100ml milk
★Coffee(300円)：100ml water, 18g coffee     →こいつだけmilkのkeyがないのでどうするか
☑Mocha(400円)：200ml water, 24g coffee, 150ml milk
__・小銭とお札で販売する__
☑使用できるのは 50 / 100 / 500円玉 と1000円札
☑それぞれの枚数を聞いてくる
☑入金合計が注文した料金に足らなければ商品は渡さず、全額返金
☑入金合計が注文した料金に足りるのであれば、お釣りを計算して返してくれる
__・自動ディスペンサー__
☑タンクに water500ml, coffee100mg, milk300ml備蓄してある
☑注文来ても材料(備蓄量)がなければつくれないため、"Sorry..."と返金および材料を減らさない。
☑スタッフを呼んで補充してもらいたいか聞く
→ Yesですべてリセットされて再度注文可能
→ Noでプログラム自体終了
__・報告機能__
☑"report"をタイプしたら、その時点での残り備蓄量および売上金を出力してくれる
↑一番最後の機能については1日文をメールで報告し、1週間分のデータにしてサーバに格納というような拡張ができそうだな～。スキル上がったらまたやってみよう。
→item == "report"だと、keyにreportがないからkey Errorになる。どうするか
__・終了__
☑注文受付時に"end"をタイプすると終了する

まとめると以下。
1. Print report
2. Check resources sufficient?
3. Process coins
4. Check transaction successful?
5. Make Coffee

```python3:starbucks_machine_menu.py
MENU = {
    "latte": {
        "ingredients": {
            "water": 200,
            "coffee": 24,
            "milk": 100,
        },
        "cost": 450,
    },
    "coffee": {
        "ingredients": {
            "water": 100,
            "coffee": 18,
        },
        "cost": 300,
    },
    "mocha": {
        "ingredients": {
            "water": 200,
            "milk": 150,
            "coffee": 24,
        },
        "cost": 400,
    }
}

resources = {
    "water": 500,
    "milk": 100,
    "coffee": 300,
}
```
上記restoreのwater,milk,coffeeを随時変更してrunさせることでテストケース実行に使用。

####starbucks_machine_2.py
※starbucks_machine_1.pyは試作段階のものなので割愛

```python3:starbucks_machine_2.py
from starbucks_machine_menu import MENU,resources

def status(item,stock_water,stock_coffee,stock_milk):
    """注文後の販売した状態を返す"""
    if item != "coffee":
        stock_water -= MENU[item]['ingredients']['water']
        stock_coffee -= MENU[item]['ingredients']['coffee']
        stock_milk -= MENU[item]['ingredients']['milk']
        return stock_water,stock_coffee,stock_milk
    else:
        stock_water -=  MENU[item]['ingredients']['water']
        stock_coffee -= MENU[item]['ingredients']['coffee']
        return stock_water,stock_coffee,stock_milk


def refund_status(item,stock_water,stock_coffee,stock_milk):
    """注文後の販売しなかった状態を返す"""
    if item != "coffee":
        stock_water += MENU[item]['ingredients']['water']
        stock_coffee += MENU[item]['ingredients']['coffee']
        stock_milk += MENU[item]['ingredients']['milk']
        return stock_water,stock_coffee,stock_milk
    else:
        stock_water +=  MENU[item]['ingredients']['water']
        stock_coffee += MENU[item]['ingredients']['coffee']
        return stock_water,stock_coffee,stock_milk


def calculate_result(item_price,total_insert):
    """入金が足りているかTrue or Falseで返し、お釣りor合計金額を返す"""
    substraction = total_insert - item_price
    if substraction >= 0:
        return True,substraction
    else:
        return False,total_insert
    
# def calculate(item_price,total_insert):
#     """おつりor返金合計額を返す"""
#     substraction = total_insert - item_price
#     if substraction >= 0:
#         return substraction
#     else:
#         return total_insert
 

vending_machine = True   
while vending_machine:
    stock_water = resources['water']
    stock_coffee = resources['coffee']
    stock_milk = resources['milk']
    money = 0
    line1 = "---------------------------------------------"
    line2 = "------------------"

    while stock_water >= 100 or stock_coffee >= 18:
        print(f"{line1}\n ☕ Welcome to Starbucks vending machine ☕ \n{line1}")
        item = input("\nWhat would you like? [Latte/Coffee/Mocha] ")
        if item == "end":
            vending_machine = False
            break
        elif item != "report":
            stock_water,stock_coffee,stock_milk = status(item,stock_water,stock_coffee,stock_milk)
            if stock_water >= 0 and stock_coffee >= 0 and stock_milk >= 0: 
                item_price = MENU[item]['cost']
                print(f"It's {item_price} yen.")
                print("\nPlease insert coins.")
                coin1 = int(input("50 yen: "))
                coin2 = int(input("100 yen: "))
                coin3 = int(input("500 yen: "))
                coin4 = int(input("1000 yen: "))
                total_insert = coin1*50 + coin2*100 + coin3*500 + coin4*1000

                TorF, in_charge = calculate_result(item_price,total_insert)
                while TorF:
                    print(f"\nHere {in_charge} yen in charge\n")
                    money += item_price
                    break
                else:
                    print(f"\n>> Sorry that's not enough money.\n>> {in_charge} yen refunded.\n")
                    stock_water,stock_coffee,stock_milk = refund_status(item,stock_water,stock_coffee,stock_milk)
            else:
                print(f"\n>> Sorry...\n>> {item} is sold out.")
                if input("\n>> Do you call a staff and restore?? [y/n]:" ) == "n":
                    vending_machine = False
                    break
                else:
                    break
        elif item == "report":
            print(f"\n~~~~~ report ~~~~~\nstock water:{stock_water}\nstock coffee:{stock_coffee}\nstock milk:{stock_milk}\n------------------\nstored money:{money}\n\n") 
```

独力1回目で完成させたので、着実に力はついているのかなーという感じ。
今までは「while True:　」がうまく使えていなかったので、関数のネストをつくったりしてたけど、今回から徐々に使えるようになってきたのでスムーズに作れるようになった。

なお、先生の解答はこのような感じで、__メイン関数がとてもシンプル__で読みやすい。自分のは、メイン関数がやたら長くて読む気が失せる。
####coffee_machine_answer.py

```python3:coffee_machine_answer.py
#以下コーヒー作成だけ抜粋
def make_coffee(drink_name, order_ingredients):
    """Deduct the required ingredients from the resources."""
    for item in order_ingredients:      #いちいちdictの中身を定義せず、for文で回している。
        resources[item] -= order_ingredients[item]
    print(f"Here is your {drink_name} ☕️. Enjoy!")


#以下メイン関数だけ抜粋
is_on = True

while is_on:
    choice = input("​What would you like? (espresso/latte/cappuccino): ")
    if choice == "off":
        is_on = False
    elif choice == "report":
        print(f"Water: {resources['water']}ml")
        print(f"Milk: {resources['milk']}ml")
        print(f"Coffee: {resources['coffee']}g")
        print(f"Money: ${profit}")
    else:
        drink = MENU[choice]
        if is_resource_sufficient(drink["ingredients"]):   #材料が足りているならば
            payment = process_coins()                      #支払い額=process_coinsからreturnされる
            if is_transaction_successful(payment, drink["cost"]):  #トランザクションが成功したら
                make_coffee(choice, drink["ingredients"])          #コーヒーを作る
```
メイン関数をもっと上手に作れるようになりたいなぁ...。

```python3:
for item in order_ingredients:
    resources[item] -= order_ingredients[item]
```
あと、今後この書き方真似したい。