CS 302, Program 4

Program 4, Fall 2015: RecipeWrangler

  P4 TEAMS DUE before 12:00 PM (noon) on Friday, Dec 4th
  P4 CODE DUE before 12:00 PM (noon) on Friday, Dec 11th
P4 extension -- Submit ALL FILES BEFORE 8AM on MONDAY, DEC 14th
  NO LATE PROGRAMS WILL BE ACCEPTED!

[ P4 Announcements | Overview | Program Components | File Format | Classes | GettingStarted | Sample Runs | Specifications | Milestones | Testing | Submission |

[+] P4 Announcements

Tip: Don't save a copy of this write-up, you'll miss updates.

Corrections, clarifications, and other announcements regarding this programming assignment will be found in this section:

[+] Overview

Assignment Goals

Description

For this program you will maintain a database system for storing and retrieving recipes. Each recipe has a name, a list of ingredients, and instructions. 

The program adds recipes from a file at the start and then allows the user to add and edit recipes. The program user is able to list the available recipe names and display the information about a specific recipe.  When the program starts, the user is asked for recipe file and the program loads all recipes found in the file. When the program ends, the user is asked for a filename to write (save) all recipes.  The save overwrites the file if it already exists.

We provide a sample recipes.txt file to get you started, but you can create your own recipe file using a text editor (Eclipse can edit text files) or using your program once you implement the Add recipe and Exit (and save to file) options. The required file format is describe later.

[+] The Program

Welcome message

RecipeWrangler is the main class and it contains the main method that gets the program going. It displays the program welcome message and starts the main menu loop as described below.

Recipe Wrangler 2015
Let us help you keep track of your favorite recipes.

The Main Menu loop

The main menu includes options for maintaining the database (list) of recipes.  There is no "remove recipe" option.  Each option is outlined here.  Your program must implement each option according to its specification.

Main Menu
---------
1. Display recipe names (sorted)
2. Display/Edit/Add a recipe
3. Load recipes from a file
4. Save recipes to a file
5. Exit
Enter choice:

1. Display recipe names (sorted)

Display a list of the names of the recipes. If no recipes have been loaded from a file or entered by the user, disp the message: No recipes

Main Menu
---------
1. Display recipe names (sorted)
2. Display/Edit/Add a recipe
3. Load recipes from a file
4. Save recipes to a file
5. Exit
Enter choice: 1
No recipes

Display a list of the names of the recipes.  Keep the recipes in order sorted by name.

Main Menu
---------
1. Display recipe names (sorted)
2. Display/Edit/Add a recipe
3. Load recipes from a file
4. Save recipes to a file
5. Exit
Enter choice: 1
CEREAL
CHOCOLATE CHIP COOKIES
PANCAKES
PESTO

Tip: To sort instances in Java

  1. Define an instantiable Recipe class that implements Comparable<E>
    public class Recipe implements Comparable<Recipe> {
        ...
    }
  2. Define the compareTo method in the Recipe class:
    /**
     * Returns a negative int value if the name 
     * of "this" recipe is lexigraphically less than 
     * the name of otherRecipe.
     * 
     * Returns a positive int value if the name 
     * of "this" recipe is lexigraphically greater than 
     * the name of otherRecipe.
     *
     * returns 0, if the name of "this" recipe 
     * is the same as the name of otherRecipe.
     * 
     * Tip: You can use the compareTo method of the String class
     *;
    public int compareTo ( Recipe otherRecipe ) {
       ...
    }
  3. Store the instances of your Recipe in an array or ArrayList
         Recipe []
    ArrayList<Recipe>
  4. Use Arrays.sort( Recipe [] ) or the sort() method of the ArrayList
    Arrays.sort( arrayOfRecipes ); // sort Recipe[]
    recipeArrayList.sort( null );  // sort ArrayList // sort ArrayList

2. Display/Edit/Add a recipe

Display recipe and allow user to replace ingredients or instructions if the recipe name exists in the recipe list.  If a recipe with that name is not found in the recipe list, prompt the user for ingredients and instruction, create the recipe instance and add it to the list of recipes.

Pseudocode for how to handle Display/Edit/New process array or liet

  1. Prompt the user for a recipe name.
  2. Convert the name to all CAPS.
  3. Get a recipe with that name from the database (if there is one).
    1. If there is no recipe with that name
      1. Ask user for the recipe's ingredients
        (newline means the end of the ingredients)
      2. Ask the user for the recipe's instructions
        (newline means the end of the instructions)
      3. Create an instance of the Recipe (name,ingredients,instructions)
      4. Add the new recipe to the list of recipes
      5. Sort the recipe list
        (Make Recipe class implement java.lang.Comparable<Recipe> and then user either Arrays.sort() or the sort() method of ArrayList class.)
    2. If there is a recipe with that name
      1. Display the recipe's name, ingredients, and instructions.
      2. Display the edit recipe menu
      3. Get the user's edit menu choice
        1. If user selects 1
          1. Get a new list of ingredients
          2. Replace the ingredients of the recipe with the new list
        2. If user selects 2
          1. Get the new instructions
          2. Replace the instructions of the recipe with the new ones
        3. If user selects 3 (or any other input)
          1. Exit the edit recipe menu

Note: Do convert the name to all upper case letters before saving it as part of recipe.  Otherwise, leave each field just it is entered by the user.

3. Load recipes from a file

Use a Scanner to read data from a file that contains recipe information. The file format is as follows:

Line 1: the number of recipes in the file (will be an integer value)
Line 2: name of first recipe
Line 3: ingredients for first recipe
Line 4: insructions for first recipe
Line 5: name of second recipe
Line 6: ingredients for second recipe
Line 7: insructions for second recipe
... (3 lines per recipe)

Example recipes file contents:

4 
Chocolate chip cookies
flour, sugar, oil, butter, vanilla, chocolate chips
mix all ingredients, make cookies, bake 10 min at 350 degrees
Pesto
1 C basil, 1/2 C parmesan cheese, 1/3 C olive oil, 1/4 C walnuts, 1 clove garlic, salt and pepper to taste
mix all ingredients except cheese in a food processor, chop for 1 minute, add cheese and enjoy
PANCAKES
flour, eggs, milk, baking powder, salt, cooking oil 
mix all ingredients (except oil), add oil to skillet, pour batter for each pancake, cook one side then flip when bubbles appear
CREPE
2 eggs, 1C flour, 1/2 C milk, 1/2 C water, 1/2 t salt, 2 T butter
whisk flour, salt, and eggs; add milk and water; pour 1/4 C in small oiled skillet and coat bottom with batter, cook until light brown (~2 minutes) and flip.
  1. Create a Scanner connected to the data file
  2. Read the first line of the file and parse as an int value (number of recipes).
  3. For each recipe in the file:
    1. Get the next line and save it as "name" (save as upper case)
    2. Search program's recipe list for a recipe with this name
    3. If a recipe with same name is found, get it:
      1. Scan next line and save it as ingredients
      2. Replace the ingredients for this Recipe with ingredients
      3. Scan next line and save it as insructions
      4. Replace the instructions for the found Recipe with instructions
  4. Close scanner connected to the input file

4. Save recipes to a file


Writes all recipes in the program to a file in aphabetical order (by name).

  1. Create a PrintWriter connected to the output file name
  2. Write the number (as an int value) of recipes as the first line of the file.
  3. For each recipe in the file:
    1. Write the name of the recipe (write name as upper case and on its own line)
    2. Write the ingredient list for the recipe and a newline character
    3. Write the instruction list for the recipe
  4. Close the printwriter connected to the input file

5. Exit

Display the exit message: Thanks for using RecipeWrangler!

5. Exit
Thanks for using RecipeWrangler!

[+] Data File Format

This program must read from and write recipes to files. Different programs can read and write files of the same format if the file format is specifed. This section describes the file format that your program must read and write. You may assume that any file that we give to your program to read WILL follow this format. 

Line 1 contains the number of recipes.
Lines 2-4 contains name, ingredients, instructions for first recipe
Lines 5-7 contains name, ingredients, instructions for second recipe, an so on...

See example file: recipes_01.txt

If a recipe has a recipe name that is not all CAPS, change it to caps before saving as a recipe.  Other field values must stay the same as they are entered by the user.

If a file contains more recipes than the number specified in the first line, simple ignore those additional recipes.

If a file contains fewer recipes than the number specified in the first line, it is an invalid file format and does not have to be considered. You do not need to detect or decide what to do if the file does not contain the correct format for each recipe or does not contain enough recipes.

[+] Classes

Main Class: Required to Implement

RecipeWrangler (the main class)

The RecipeWrangler class must have the following and use this to launch the program.

public static void main(String [] args) { ... }
The main method used to launch your application.

Your class RecipeWrangler may also be instantiable (but this is not required).

Instantiable Classes: We recommend you define (you need at least one instantiable class anyway)

Recipe

An instantiable class that knows the name, ingredients, and instructions of a recipe. Implements Comparable<Recipe> so that recipes can be sorted by name.  Has getters and setters to allow for editing individual fields.

RecipeBox (or RecipeList)

A class that stores all current recipes, can also be used (and reused) when needing to find and display a recipe.  Can use and reuse one instance of this class, or keep multiple instances for the different uses.  Be careful, instances of class Recipe should not be duplicated for multiple lists, but rather aliases (additional references) to each recipe can be stored as needed.

Pre-defined classes: You will likely want to import and use (you are not limited to these classes)

java.io.File - abstract representation of a file (for reading or writing)
java.io.FileNotFoundException - thrown when a file does not exist
java.io.IOException - thrown when a file can not be read
java.util.ArrayList - can keep expandable lists of filenames, and shape information
java.util.Scanner - for console input from the keyboard and for reading shape information from a file

Pre-defined interface: You will likely want Recipe class to implement

java.lang.Comparable<Recipe> - have your Recipe class implement this interface so that your array or ArrayList of Recipes can be sorted via your ArrayList's sort() method or Arrays.sort( array ).


[+] Getting Started

Outline the data and methods that you will need to represent a Recipe in your program. Write some demo code that creates a Recipe and then writes data of a recipe to the console window, add code to write that recipe to a file in the format required. 

Outline the data and methods that you will use to handle the various functions needed for each recipe, and list of recipes.  Write some demo code that adds recipes to a list and the prints them to console and file.

Outline the methods you will use to implement the main class, RecipeWrangler. Write some demo code to create a few instances of the Recipe class, and add those instances to an instance of your list class.  Then, print the list in order to the console.  To sort the list use Arrays.sort() or ArrayList's sort method.

Add a main menu loop to the main class and continue with the milestones.

Suggested Object-Oriented Design for this program

 

[+] Sample Files

misc-src Directory (sample data files that can be read by program)

recipes_01.txt
recipes_02.txt
NBC_recipes.txt

sample-runs Directory (Sample runs showing prompts and responses while program is running -- additional samples may be added.)

sample_run_01.txt add one recipe and show recipe edit options
sample_run_02.txt add recipes and save to recipes_02.txt
sample_run_03.txt load recipes from recipes_01.txt, recipes_02.txt, and recipes_03.txt (no file) and display
sample_run_04.txt add recipes by menu save to recipes_04.txt
sample_run_05.txt load recipes from recipes_01.txt, add recipes by menu, and load recipes from recipes_02.txt , then save recipes to recipes_5.txt

sample-runs Directory (sample runs with errors)

error_run_01.txt
error_run_02.txt
error_run_03.txt
... more error examples may be added later

No sample Java source code is provided. The main method for your p4 solution must be in a class named RecipeWrangler, in a file named RecipeWrangler.java file.  Be sure to get the capitalization correct, or you will lose points for us having to change it to test your code. 

Tip: The main menu of this program is similar to the form for program 1, so you can copy your program 1 main class and rename and edit it for use in getting started for Program 4.  Be sure to update and include file, class, method headers, and comments in all of your code.

 

[+] Program Specifications

Requirements

  1. The main class that launches your program must be named RecipeWrangler.
  2. Your program must have at least one instantiable class in your program design. We recommend a Recipe class at a minimum; and also a class that manages a list of Recipes.
  3. Your program must get all user input (keyboard) from a single Scanner instance. 
  4. Your program must maintain a dynamic list (array or ArrayList) of recipes and the user must be able to add and edit recipes as described by the menu options.
  5. User input prompts and output message must be as shown in write-up and sample files.  Let us know via Piazza post if you find inconsistencies, so they may resolved.
  6. Your program must follow Style and Commenting guides for full credit.
  7. Your program must not crash on FileNotFoundExceptions and other user input errors. Handle errors as described above.

[+] Development Milestones

We suggest that you incrementally develop this program by following the milestones in the order listed below. This order will make it easy for you to check that each milestone is working properly before you move on to the next one. Don't move on to a new milestone until you can convince yourself that the current milestone is working correctly. The further along you get, the harder it will be to detect errors in code you developed early on.

Note. In order to get any milestone working, you may have to edit classes not mentioned in the milestone description.

Hint. In addition to getting specific functionality in your program.  Think about the design choices you are making, would a method help, or a new class?  Having all code in a single main method (like program 1) will lose 5 points of design, but can otherwise get full credit.  Having all code in a single class, with all static methods and no instances created (like program 2) will lose you 3 points of design, but can otherwise get full credit.  Having all code in one class, with many methods, and only one instance of your own instantiable class created will lose 2 points of design.  To get all 5 points of design, you must have a main class and at least one instantiable class that is used to create multiple instances. 

We suggest a Recipe class to store the data values of a single recipe, and a RecipeList class to store sortable and expandable lists of Recipe instances and provide some helper methods for other functionality.  Each instantiable class should override its inherited toString() method for use during testing and development or the program itself.  The main class is a good place to put methods for reading and writing files.

[+] Testing

You should test your program by running and testing individual methods frequently as you develop. For example, writing methods for each option and unit testing them separately will help ensure that they work together when needed in later parts of the program.

It is to your advantage to always have a compiling program so that you can run it and see what it does. If you follow the milestones outlined above, you should be able to verify whether you have completed each milestone by running your program and interacting with it.

[+] Submission

Before handing in your program, check that you've done the following:

Use the CS302 Forms Page to electronically submit and backup your work:

Submit these files:

© 2015 Deb Deppeler (deppeler@cs.wisc.edu)