5
\$\begingroup\$

I made a program which simulates taking an order for 3 meals and a dessert. It's like those packaged food companies you see on Instagram. It asks for a name, and then goes on to ask what they want for each mealtime and stores their orders in a dictionary.

I defined two functions; they help out a lot and make it much easier. You can also only choose from the respected menu for each mealtime; you can't choose from the dessert menu for breakfast. I think I have too many break statements, and I think the program gets too complicated towards the end. How can I clean the program up?

def show_menu(meals, meal_time):
    """Print each element in the list."""
    print(f"\n{meal_time.title()}:")
    for meal in meals:
        print(f"\t-{meal.title()}")

def get_user_meal(menu):
    """Takes orders for each meal and stores it in a dictionary."""
    while True:
        if menu == breakfast_menu:
            breakfast = input(breakfast_prompt)
            breakfast = breakfast.lower()
            if breakfast not in menu:
                print(f"---Please choose from the breakfast menu!---")
                continue
            else:
                user_meals['breakfast'] = breakfast
                break

        if menu == lunch_menu:
            lunch = input(lunch_prompt)
            lunch = lunch.lower()
            if lunch not in menu:
                print(f"---Please choose from the lunch menu!---")
                continue
            else:
                user_meals['lunch'] = lunch
                break

        if menu == dinner_menu:
            dinner = input(dinner_prompt)
            dinner = dinner.lower()
            if dinner not in menu:
                print(f"---Please choose from the dinner menu!---")
                continue
            else:
                user_meals['dinner'] = dinner
                break
        if menu == dessert_menu:
            dessert = input(dessert_prompt)
            dessert = dessert.lower()
            if dessert not in menu:
                print(f"---Please choose from the dessert menu!---")
                continue
            else:
                user_meals['dessert'] = dessert
                break

user_meals = {}

# Menus from which the user can choose meals from.
breakfast_menu = ['omelet', 'cheese platter', 'ham sandwich']
lunch_menu = ['steak', 'chicken breast', 'fish and chips', 'tacos']
dinner_menu = ['lasagna', 'pizza', 'salad', 'cod fish']
dessert_menu = ['chocolate cake', 'ice cream', 'chocolate mousse']

# All prompts that will be used.
name_prompt = "\nWhat's your name? "
breakfast_prompt = "\nWhat would you like for breakfast? "
lunch_prompt = "\nWhat about for lunch? "
dinner_prompt = "\nHow about for dinner? "
dessert_prompt = "\nAnything sweet perhaps for dessert? "
read_back_prompt = "\n\nWould you like for me to read back your meals? (yes/no) "
evaluate_prompt = "\nDid I get everything? (yes/no) "
confirm_prompt = "\nPlease enter 'confirm' to proceed or 'decline' to quit: "

print("Welcome to MealPlanner!")

while True:

    name = input(name_prompt)

    # Show the user the menus
    print("\nHere is what we are offering for todays meals:")
    show_menu(breakfast_menu,'breakfast')
    show_menu(lunch_menu,'lunch')
    show_menu(dinner_menu,'dinner')
    show_menu(dessert_menu,'dessert')

    while True:
        # Ask the user for his meal choices for each mealtime.
        get_user_meal(breakfast_menu)
        get_user_meal(lunch_menu)
        get_user_meal(dinner_menu)
        get_user_meal(dessert_menu)
        
        # Reads back the order if the user asked for it.
        read_back = input(read_back_prompt)
        if read_back.lower() == 'yes':
            print(f"\nFor breakfast you ordered a tasty plate of {user_meals['breakfast'].title()}, "
                f"\nfor lunch you asked for a simmering plate of {user_meals['lunch'].title()}, "
                f"\nfor the last meal of the day you ordered a savory plate of {user_meals['dinner'].title()}, "
                f"\nand to curb your sweet tooth you ordered a mouth-watering plate of {user_meals['dessert'].title()}.")

            rb_evaluate = input(evaluate_prompt) 
            # If the user has changed his mind start from the top of this while loop.
            if rb_evaluate.lower() == 'no':
                print("I'm sorry may I take your order again?")
                continue
            else:
                break
        else:
            break

    # If the user has already seen his orders no need to show him again, so we just ask him for conformation.
    if read_back.lower() == 'yes':
        confirm = input(confirm_prompt)
        if confirm.lower() == 'decline':
            break
    # If the user didn't ask for the read back then show the orders before asking for conformation.
    else:
        print("\nYour order:")
        for key, value in user_meals.items():
            print(f"\t{key.title()}: {value.title()}")

        confirm = input(confirm_prompt)
        if confirm.lower() == 'decline':
            break

    print(f"\nThank you for your order {name.title()}!"
        "\nWe will deliver your order in a few minuets."
        "\nThank you for choosing MealPlanner!")
    break
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

Overview

The code layout is good, and you used meaningful names for functions and variables.

DRY

The get_user_meal function has a lot of repeated code. You can eliminate most of it by creating dictionaries for the menu items and the meal prompts, with the name of the meal being the dict keys. You can simply pass the name of the meal into the function.

This eliminates the repeated calls to the function. They can now be called in a for loop.

This also eliminates the repeated calls to the show_menu function.

As a byproduct, this also eliminates several of the break statements.

Consider the pyinputplus module. It has methods like inputChoice and inputMenu that may do exactly what you are looking for, and they may achieve your goal of reducing the many break statements.

Documentation

You could add usage information to header comments at the top of the file to describe the purpose of the code and what it expects for input.

This is a vague docstring:

"""Print each element in the list."""

Words like element and list convey no specific meaning to your code.

Typo

"conformation" should be "confirmation" in the comments.


Here is new code with the suggestions above:

def show_menu(meals, meal_time):
    """Print each meal in the menu."""
    print(f"\n{meal_time.title()}:")
    for meal in meals:
        print(f"\t-{meal.title()}")

def get_user_meal(meal):
    """Takes orders for each meal and stores it in a dictionary."""
    while True:
        choice = input(meal_prompts[meal])
        choice = choice.lower()
        if choice not in menus[meal]:
            print(f"---Please choose from the {meal} menu!---")
            continue
        else:
            user_meals[meal] = choice
            break

user_meals = {}

# All prompts that will be used.
name_prompt = "\nWhat's your name? "
read_back_prompt = "\n\nWould you like for me to read back your meals? (yes/no) "
evaluate_prompt = "\nDid I get everything? (yes/no) "
confirm_prompt = "\nPlease enter 'confirm' to proceed or 'decline' to quit: "

# Menus from which the user can choose meals from.
menus = {
    'breakfast' : ['omelet', 'cheese platter', 'ham sandwich'],
    'lunch'     : ['steak', 'chicken breast', 'fish and chips', 'tacos'],
    'dinner'    : ['lasagna', 'pizza', 'salad', 'cod fish'],
    'dessert'   : ['chocolate cake', 'ice cream', 'chocolate mousse']
}

meal_prompts = {
    'breakfast' : "\nWhat would you like for breakfast? " ,
    'lunch'     : "\nWhat about for lunch? "              ,
    'dinner'    : "\nHow about for dinner? "              ,
    'dessert'   : "\nAnything sweet perhaps for dessert? "
}

print("Welcome to MealPlanner!")

while True:

    name = input(name_prompt)

    # Show the user the menus
    print("\nHere is what we are offering for todays meals:")
    for meal, menu in menus.items():
        show_menu(menu, meal)

    while True:
        # Ask the user for his meal choices for each mealtime.
        for meal in menus:
            get_user_meal(meal)

        # Reads back the order if the user asked for it.
        read_back = input(read_back_prompt)
        if read_back.lower() == 'yes':
            print(f"\nFor breakfast you ordered a tasty plate of {user_meals['breakfast'].title()}, "
                f"\nfor lunch you asked for a simmering plate of {user_meals['lunch'].title()}, "
                f"\nfor the last meal of the day you ordered a savory plate of {user_meals['dinner'].title()}, "
                f"\nand to curb your sweet tooth you ordered a mouth-watering plate of {user_meals['dessert'].title()}.")

            rb_evaluate = input(evaluate_prompt)
            # If the user has changed his mind start from the top of this while loop.
            if rb_evaluate.lower() == 'no':
                print("I'm sorry may I take your order again?")
                continue
            else:
                break
        else:
            break

    # If the user has already seen his orders no need to show him again, so we just ask him for confirmation.
    if read_back.lower() == 'yes':
        confirm = input(confirm_prompt)
        if confirm.lower() == 'decline':
            break
    # If the user didn't ask for the read back then show the orders before asking for confirmation.
    else:
        print("\nYour order:")
        for key, value in user_meals.items():
            print(f"\t{key.title()}: {value.title()}")

        confirm = input(confirm_prompt)
        if confirm.lower() == 'decline':
            break

    print(f"\nThank you for your order {name.title()}!"
        "\nWe will deliver your order in a few minuets."
        "\nThank you for choosing MealPlanner!")
    break
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.