Skip to content
Snippets Groups Projects
Commit 674b97ea authored by borgeha's avatar borgeha
Browse files

Første push av ferdig kode til eksamensrepos. Krysser fingre...

parent 6190f0c7
No related branches found
No related tags found
No related merge requests found
Showing
with 1627 additions and 0 deletions
package food;
import static org.junit.Assert.assertEquals;
import java.util.Collection;
/**
* Generic container of ingredients.
*/
public class IngredientContainer implements Ingredients {
// TODO: necessary declarations and constructors
/**
* Initializes a new, empty IngredientContainer.
*/
public IngredientContainer() {
// TODO
}
/**
* Initializes a new IngredientContainer.
* @param ingredients Initial ingredients in the container
*/
public IngredientContainer(Ingredients ingredients) {
}
/**
* Add `amount` of `ingredient` to the container.
*
* @param ingredient The name of the ingredient to add
* @param amount The amount of the ingredient to add
* @throws (fitting subclass of) RuntimeException if amount cannot be removed from this
*/
public void addIngredient(String ingredient, double amount) {
// TODO
}
/**
* Remove `amount` of `ingredient` to the container.
*
* If the resulting amount of the ingredient is 0, its name should be removed
*
* @param ingredient The name of the ingredient to add
* @param amount The amount of the ingredient to remove
* @throws IllegalArgumentException if amount cannot be removed from this
*/
public void removeIngredient(String ingredient, double amount) {
// TODO
}
/**
* @return An Iterable giving the names of all the ingredients
*/
@Override
public Iterable<String> ingredientNames() {
// TODO
}
/**
* @return A collection containing the names of all the ingredients
*/
@Override
public Collection<String> getIngredientNames() {
// TODO
}
/**
* @param ingredient The ingredient to get the amount of
* If the ingredient does not exist, the double 0.0 should be returned.
* @return The amount of ingredient
*/
@Override
public double getIngredientAmount(String ingredient) {
// TODO
}
/**
* Get a string containing the ingredients with amounts in the format given below:
* Mark that it does not matter in which order the ingredients are listed.
*
* ingredientName1: amount1
* ingredientName2: amount2
* ingredientName3: amount3
* ...
*
* @return A string on the format given above
*/
@Override
public String toString() {
// TODO
}
/**
* Add all ingredients from another Ingredients object into this.
*
* @param ingredients the ingredients to add
*/
public void addIngredients(Ingredients ingredients) {
// TODO
}
/**
* Remove all ingredients in other from this.
*
* @param ingredients the ingredients to remove
* @throws IllegalArgumentException if this does not contain enough of any of the ingredients (without changing this)
*/
public void removeIngredients(Ingredients ingredients) {
// TODO
}
/**
* Checks if the all the ingredients in other is contained in this
* @param other
* @return true of there is at least the same or larger amount of ingredients in this than in other, false otherwise
*/
@Override
public boolean containsIngredients(Ingredients other) {
// TODO
}
/**
* Returns the ingredients that must be added to other for this to be contained in it
* @param other
* @return a new Ingredients that if added to other would make it contain this
*/
@Override
public Ingredients missingIngredients(Ingredients other) {
// TODO
}
/**
* Returns the ingredients that you get if you scale this by factor 'scale'.
* I.e. an IngredientContainer with 4 portions scaled by 2 ends up with 8 portions.
* See example in main method.
* @param scale
* @return a new scaled Ingredients
*/
@Override
public Ingredients scaleIngredients(double scale) {
// TODO
}
/**
* Some helpful code to debug your code. Does not cover everything!
* @param args
*/
public static void main(String[] args) {
final IngredientContainer container = new IngredientContainer();
container.addIngredient("food1", 12.0);
container.addIngredient("food2", 6.0);
container.addIngredient("food2", 2.5);
// food2 should now be 8.5, with a small delta added for double rounding.
assertEquals(8.5, container.getIngredientAmount("food2"), 0.0001);
System.out.println(container);
// Double the ingredients:
Ingredients twice = container.scaleIngredients(2);
assertEquals(17.0, twice.getIngredientAmount("food2"), 0.0001);
// Remove food from the first container:
container.removeIngredient("food1", 10);
System.out.println(container);
assertEquals(2.0, container.getIngredientAmount("food1"), 0.0001);
}
}
package food;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.junit.Test;
public class IngredientContainerTest {
private static final double EPSILON = 0.0001;
private IngredientContainer createDefaultContainer() {
IngredientContainer ig = new IngredientContainer();
ig.addIngredient("food1", 5.0);
ig.addIngredient("food2", 10.0);
ig.addIngredient("food3", 15.0);
return ig;
}
public static <T> void assertCollectionsContainTheSame(Collection<T> expected, Collection<T> actual) {
assertTrue(actual + " differs from " + expected, expected.containsAll(actual) && actual.containsAll(expected));
}
@Test
public void testAddIngredient() {
IngredientContainer container = new IngredientContainer();
container.addIngredient("food1", 12.0);
container.addIngredient("food2", 6.0);
assertEquals(12.0, container.getIngredientAmount("food1"), EPSILON);
assertEquals(6.0, container.getIngredientAmount("food2"), EPSILON);
Collection<String> names = container.getIngredientNames();
Collection<String> expectedNames = Set.of("food1", "food2");
assertCollectionsContainTheSame(expectedNames, names);
container.addIngredient("food1", 5.2);
assertEquals(17.2, container.getIngredientAmount("food1"), EPSILON);
assertEquals(6.0, container.getIngredientAmount("food2"), EPSILON);
names = container.getIngredientNames();
assertCollectionsContainTheSame(expectedNames, names);
}
@Test
public void testRemoveIngredient() {
IngredientContainer container = createDefaultContainer();
container.removeIngredient("food1", 3.0);
assertEquals(2.0, container.getIngredientAmount("food1"), EPSILON);
assertEquals(10.0, container.getIngredientAmount("food2"), EPSILON);
assertEquals(15.0, container.getIngredientAmount("food3"), EPSILON);
Collection<String> expectedNames = Set.of("food1", "food2", "food3");
assertCollectionsContainTheSame(expectedNames, container.getIngredientNames());
container.removeIngredient("food2", 10.0);
assertEquals(2.0, container.getIngredientAmount("food1"), EPSILON);
assertEquals(0.0, container.getIngredientAmount("food2"), EPSILON);
assertEquals(15.0, container.getIngredientAmount("food3"), EPSILON);
expectedNames = Set.of("food1", "food3"); // The ingredient should be removed from the container when no more is left
assertCollectionsContainTheSame(expectedNames, container.getIngredientNames());
}
@Test
public void testGetIngredientNames() {
IngredientContainer container = createDefaultContainer();
Collection<String> expectedNames = Set.of("food1", "food2", "food3");
assertCollectionsContainTheSame(expectedNames, container.getIngredientNames());
}
@Test
public void testGetIngredientAmount() {
IngredientContainer container = createDefaultContainer();
assertEquals(5.0, container.getIngredientAmount("food1"), EPSILON);
assertEquals(10.0, container.getIngredientAmount("food2"), EPSILON);
assertEquals(15.0, container.getIngredientAmount("food3"), EPSILON);
}
@Test
public void testListIngredients() {
IngredientContainer container = createDefaultContainer();
Collection<String> expectedLines = new TreeSet<>(Arrays.asList("food1: 5.0", "food2: 10.0", "food3: 15.0"));
Collection<String> actualLines = new TreeSet<>(Arrays.asList(container.toString().split("\n")));
assertCollectionsContainTheSame(expectedLines, actualLines);
}
}
\ No newline at end of file
package food;
import java.util.Collection;
public interface Ingredients {
/**
*
* @return An Iterable giving the names of all the ingredients
*/
public Iterable<String> ingredientNames();
/**
*
* @return A collection containing the names of all the ingredients
*/
public Collection<String> getIngredientNames();
/**
* @param ingredient The ingredient to get the amount of
* @return The amount of ingredient
*/
public double getIngredientAmount(String ingredient);
/**
* Checks if the all the ingredients in other is contained in this
* @param other
* @return true of there is at least the same or larger amount of ingredients in this than in other, false otherwise
*/
public boolean containsIngredients(Ingredients other);
/**
* Returns the ingredients that must be added to other for this to be contained in it
* @param other
* @return a new Ingredients that if added to other would make it contain this
*/
public Ingredients missingIngredients(Ingredients other);
/**
* Returns the ingredients that you get if you scale this
* @param other
* @param scale
* @return a new scaled Ingredients
*/
public Ingredients scaleIngredients(double scale);
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="food.KitchenController">
<children>
<HBox>
<children>
<ComboBox fx:id="recipeSelector" onAction="#updateSelected" ></ComboBox>
<TextField fx:id="portionField"></TextField>
<Button onAction="#addRecipeToWeekly" text="Add" />
</children>
</HBox>
<TextArea fx:id="recipesChosen" editable="false" prefHeight="100.0" wrapText="true" />
<Button onAction="#submitWeeklyRecipes" text="Submit weekly recipes" />
</children>
</VBox>
package food;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
public class Kitchen {
// TODO: necessary declarations
/**
* Create a new kitchen with the given recipes
* @param recipes The recipes the kitchen knows
*/
public Kitchen(Recipe...recipes) {
// TODO
}
/**
* @return The kitchen's ingredient storage
*/
public IngredientContainer getStorage() {
// TODO
}
/**
* Lookup a recipe in the kitchen's known recipes by name.
*
* If no recipe with the given name is found, `null` is returned.
*
* @param name The name of the recipe
* @return The recipe with the given name, or `null` if no such recipe exists
*/
public Recipe getRecipe(String name) {
// TODO
}
/**
* @return A collection of all the recipes the kitchen knows
*/
public Collection<Recipe> getAllRecipes() {
// TODO
}
/**
* Add a recipe to the recipes of the week
* @param recipe The recipe to add
*/
public void addRecipeToWeekly(Recipe recipe) {
// TODO
}
/**
* Remove a recipe from the recipes of the week
* @param recipe The recipe to remove
*/
public void removeRecipeFromWeekly(Recipe recipe) {
// TODO
}
/**
* Clear the recipes of the week. Useful for selecting next weeks
* recipes.
*/
public void clearWeekly() {
// TODO
}
/**
* This method should be called when the chef has finished setting
* all recipes for the next week, and can be used to trigger
* fitting behavior.
*/
public void registerWeekly() {
// TODO
}
/**
* @return The list of recipes the kitchen will create this week
*/
public Collection<Recipe> getWeeklyRecipes() {
// TODO
}
/**
* Check if this kitchen has the ingredients needed to cook a given recipe
*
* @param recipe The recipe to check for
* @return true if the kitchen has enough ingredients
*/
public boolean canCreateRecipe(Recipe recipe) {
// TODO
}
/**
* Cook the given recipe, i.e. remove the amount of ingredients from this kitchen's storage.
*
* @param recipe The recipe to create
* @throws an appropriate RuntimeException if there's not enough ingredients to create the given recipe.
*/
public void createRecipe(Recipe recipe) {
// TODO
}
/**
* Generic filter method on the recipes in this kitchen
*
* @param predicate The predicate to filter on
* @return The filtered collection of recipes
*/
public Collection<Recipe> filterRecipes(Predicate<Recipe> predicate) {
// TODO
}
/**
* @return All recipes that can be created with the current ingredient store of this kitchen
*/
public Collection<Recipe> getRecipesThatCanBeCreated() {
// TODO
}
/**
* @param ingredient The ingredient to search for
* @return All recipes that contains `ingredient`
*/
public Collection<Recipe> getRecipiesContainingIngredient(String ingredient) {
// TODO
}
// TODO: support observability
public static void main(final String[] args) throws IOException {
// Reading from file:
// Read recipes using RecipeReader. Uncomment to test.
// final RecipeReader recipeReader = new RecipeReader();
// List<Recipe> recipes = new RecipeReader().readRecipes(RecipeReader.class.getResourceAsStream("sample-recipes.txt"));
// System.out.println(recipes.size());
// Use the sample recipes. Uncomment to test
// final Collection<Recipe> dummyrecipes = Recipe.createSampleRecipes();
// System.out.println(dummyrecipes.size());
// Simple kitchen - two recipes only
Recipe[] recipesArray = new Recipe[2];
IngredientContainer ig = new IngredientContainer();
ig.addIngredient("egg", 4);
ig.addIngredient("milk", 5);
ig.addIngredient("flour", 3);
ig.addIngredient("salt", 1);
Recipe pancakes = new Recipe("pancakes", "almost_dinner", 4, ig);
recipesArray[0] = pancakes;
ig = new IngredientContainer();
ig.addIngredient("egg", 5);
ig.addIngredient("milk", 4);
ig.addIngredient("flour", 3);
ig.addIngredient("salt", 1);
ig.addIngredient("vanilla", 1);
Recipe waffles = new Recipe("waffles", "Dessert", 4, ig);
recipesArray[1] = waffles;
final Kitchen kitchen = new Kitchen(recipesArray);
System.out.println("Pancakes: " + kitchen.getRecipe("pancakes"));
// Should print false:
System.out.println(kitchen.canCreateRecipe(pancakes));
kitchen.getStorage().addIngredient("egg", 12);
kitchen.getStorage().addIngredient("milk", 20);
kitchen.getStorage().addIngredient("flour", 2000);
kitchen.getStorage().addIngredient("salt", 100);
// Should print true:
System.out.println(kitchen.canCreateRecipe(pancakes));
// Weekly recipes:
kitchen.addRecipeToWeekly(pancakes.createNPortions(20));
kitchen.registerWeekly();
System.out.println("Kitchens weekly recipes: " + kitchen.getWeeklyRecipes());
System.out.println(kitchen.getStorage());
// Recipes containing egg:
System.out.println("Recipes containing egg: " + kitchen.getRecipiesContainingIngredient("egg"));
}
}
package food;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class KitchenApp extends Application {
@Override
public void start(final Stage stage) throws Exception {
final Parent root = FXMLLoader.load(getClass().getResource("Kitchen.fxml"));
stage.setScene(new Scene(root));
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
package food;
import java.util.Collection;
import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
public class KitchenController {
@FXML
private ComboBox<Recipe> recipeSelector;
private Collection<Recipe> sampleRecipes;
@FXML
private TextField portionField;
@FXML
private TextArea recipesChosen;
private Kitchen kitchen;
@FXML
private void initialize() {
this.sampleRecipes = Recipe.createSampleRecipes();
final Kitchen kitchen = new Kitchen(sampleRecipes.toArray(new Recipe[sampleRecipes.size()]));
initialize(kitchen);
}
/**
* Kicking off the kitchen. You do not have to modify (or even understand) this method.
* It fills the ComboBox called recipeSelector with all recipes available in the kitchen.
* It uses the sample recipes, so as to be available regardless of having implemented
* reading from file or not.
* @param kitchen
*/
public void initialize(Kitchen kitchen) {
this.kitchen = kitchen;
recipeSelector.setCellFactory(listView -> createListCell());
recipeSelector.setButtonCell(createListCell());
recipeSelector.getItems().addAll(sampleRecipes); // Adds recipes to combobox
recipeSelector.getSelectionModel().select(0); // Shows the first item
}
// helper method
private ListCell<Recipe> createListCell() {
return new ListCell<>() {
@Override
protected void updateItem(final Recipe recipe, final boolean empty) {
super.updateItem(recipe, empty);
setText(empty ? null : recipe.getName() != null ? recipe.getName() : "name not set, check Recipe constructor");
}
};
}
@FXML
private void updateSelected() {
portionField.setText(Integer.toString(recipeSelector.getValue().getNPortions()));
}
/**
* Triggered when user presses button to add recipe to weekly
*/
@FXML
private void addRecipeToWeekly() {
// TODO
}
/**
* Triggered when user presses button to state that all recipe for next week are finished.
*/
@FXML
private void submitWeeklyRecipes() {
// TODO
}
/**
* Updates the recipesChosen TextField with recipes chosen to be part of next weeks menu. You do not have to modify this method.
*/
private void updateChosen() {
final String text = kitchen.getWeeklyRecipes().stream()
.map(r -> r.getName() + ": " + r.getNPortions())
.reduce("", (s1, s2) -> s1 + "\n" + s2);
recipesChosen.setText(text);
}
}
package food;
public interface KitchenObserver {
// TODO: necessary method declarations
}
package food;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
public class KitchenTest {
private static final double EPSILON = 0.0001;
private Kitchen kitchen;
private List<Recipe> recipes;
private IngredientContainer createIG(Map<String, Double> ingredients) {
IngredientContainer ig = new IngredientContainer();
for (String i : ingredients.keySet()) {
ig.addIngredient(i, ingredients.get(i));
}
return ig;
}
@Before
public void setup() {
recipes = List.of(
new Recipe(
"Recipe0",
"Dinner",
4,
createIG(Map.of("food1", 10.0, "food2", 31.0, "food3", 1.0))
),
new Recipe(
"Recipe1",
"Cocktail",
4,
createIG(Map.of("food4", 40.0, "food2", 5.0, "food5", 2.0))
)
);
kitchen = new Kitchen(recipes.toArray(new Recipe[recipes.size()]));
}
private void fillKitchen() {
kitchen.getStorage().addIngredient("food1", 15.0);
kitchen.getStorage().addIngredient("food2", 31.0);
kitchen.getStorage().addIngredient("food3", 1.2);
kitchen.getStorage().addIngredient("food4", 35.1);
kitchen.getStorage().addIngredient("food5", 5.0);
}
@Test
public void testSetThisWeeksRecipes() {
kitchen.addRecipeToWeekly(recipes.get(1));
Collection<Recipe> weeklyRecipes = kitchen.getWeeklyRecipes();
assertEquals(1, weeklyRecipes.size());
assertEquals(kitchen.getRecipe("Recipe1"), weeklyRecipes.iterator().next());
}
@Test
public void testCanCreateRecipe() {
// Add enough food to create recipes[0], but not recipes[1]
fillKitchen();
assertTrue(kitchen.canCreateRecipe(recipes.get(0)));
assertFalse(kitchen.canCreateRecipe(recipes.get(1)));
}
@Test
public void testCreateRecipe() {
// Add enough food to create recipes[0], but not recipes[1]
fillKitchen();
try {
kitchen.createRecipe(recipes.get(1));
fail();
} catch (IllegalArgumentException e) {}
kitchen.createRecipe(recipes.get(0));
assertEquals(5.0, kitchen.getStorage().getIngredientAmount("food1"), EPSILON);
assertEquals(0.0, kitchen.getStorage().getIngredientAmount("food2"), EPSILON);
assertEquals(0.2, kitchen.getStorage().getIngredientAmount("food3"), EPSILON);
assertEquals(35.1, kitchen.getStorage().getIngredientAmount("food4"), EPSILON);
assertEquals(5.0, kitchen.getStorage().getIngredientAmount("food5"), EPSILON);
Collection<String> expectedNames = Set.of("food1", "food3", "food4", "food5");
IngredientContainerTest.assertCollectionsContainTheSame(expectedNames, kitchen.getStorage().getIngredientNames());
}
@Test
public void testFilterRecipes() {
Collection<Recipe> expectedFiltered = Set.of(recipes.get(0));
Collection<Recipe> actualFiltered = kitchen.filterRecipes(r -> r.getName().equals("Recipe0"));
IngredientContainerTest.assertCollectionsContainTheSame(expectedFiltered, actualFiltered);
}
@Test
public void testGetRecipesICanCreate() {
fillKitchen();
Collection<Recipe> expectedFiltered = Set.of(recipes.get(0));
Collection<Recipe> actualFiltered = kitchen.getRecipesThatCanBeCreated();
IngredientContainerTest.assertCollectionsContainTheSame(expectedFiltered, actualFiltered);
}
@Test
public void testGetRecipiesContainingIngredient() {
fillKitchen();
Collection<Recipe> expectedFiltered = Set.of(recipes.get(1));
Collection<Recipe> actualFiltered = kitchen.getRecipiesContainingIngredient("food4");
IngredientContainerTest.assertCollectionsContainTheSame(expectedFiltered, actualFiltered);
}
}
\ No newline at end of file
# Le Petite Chef
De fem oppgavene i denne delen følger under.
## Oppgave 1 (25%)
Denne delen handler om **IngredientContainer**, **Recipe** og **RecipeReader**.
**IngredientContainer** holder oversikt over antall/mengde av et sett med ingredienser og er den primære implementasjonen av **Ingredients**. Siden **Ingredients** bare inneholder metoder for å lese ut informasjon, må **IngredientContainer** naturlig nok legge til metoder for å endre antallet/mengden som finnes av hver ingrediens.
**Recipe** (oppskrift) representerer ingrediensene som trengs for en viss mengde porsjoner av en matrett (eller drikk). Hjelpeklassen **RecipeReader** håndterer innlesing av oppskrifter fra en kilde, f.eks. en fil.
**Oppgaven**
Implementer nødvendige metoder (og felt og hjelpeklasser og -metoder) i
- [IngredientContainer](IngredientContainer.java)
- [Recipe](Recipe.java)
- [RecipeReader](RecipeReader.java)
Dersom du ikke klarer å lese oppskrifter fra fil, så kan du senere benytte deg av den statiske metoden **Recipe.createSampleRecipes()**. Denne vil returnere en samling av oppskrifter som du kan bruke. Du finner et eksempel på dette i [KitchenController.java](KitchenController.java) som brukes i oppgave 5.
** Dine kommentarer **
Skriv kommentarer til din løsning i [Oppgavekommentarer](Oppgavekommentarer.md).
## Oppgave 2 (15%)
Denne delen handler om **Kitchen** (uten observatør, de kommer i oppgave 4).
Kjøkkenet har et sett med oppskrifter (**Recipe**, som angis i konstruktøren). Noen metoder (**getRecipe** og **filterRecipes**) håndterer spørring om disse.
Kjøkkenet har et matlager (**getStorage**), som må være fylt med nok matvarer til å kunne lage rettene. Derfor har klassen metoder fokusert på sammenheng mellom oppskrifter og matlageret (**canCreateRecipe**, **getRecipesThatCanBeCreated**, **getRecipiesContainingIngredient**).
Etter at restauranten er stengt for uken planlegger kokken neste ukes meny (vha. metodene **addRecipeToWeekly**, **removeRecipeFromWeekly** og **clearWeekly**). Denne består av et sett med eksisterende oppskrifter og et visst antall porsjoner av dem. Når alle oppskriftene er lagt inn kalles **registerWeekly**, der man f.eks. kunne tenke seg at en handleliste skal lages. Du trenger ikke å implementere funksjonalitet for en slik handleliste eller annen bruk av ukesmenyen.
**Oppgaven**
Implementer nødvendige metoder (og felt og hjelpeklasser og -metoder) i
- [Kitchen](Kitchen.java)
**Dine kommentarer**
Skriv kommentarer til din løsning i [Oppgavekommentarer](Oppgavekommentarer.md).
## Oppgave 3 - Delegering (10%)
En *skalert* oppskrift, som den som returneres av **Recipe** sin **createNPortions**-metode, kan ha nytte av en egen implementasjon av **Ingredients** implementert vha. delegering.
**Oppgaven**
Implementer en skalert oppskrift vha. delegering og bruk denne. Du skal *ikke* endre metoden **createNPortions** som du lagde i oppgave 1, i stedet skal du lage en ekstra metode **createNPortionsUsingDelegation**. Merk: Du skal *ikke bruke* **IngredientContainer.scaleIngredients()**, klassen som får ansvaret delegert skal også implementere skaleringen.
- [ScaledIngredients](ScaledIngredients.java)
- [Recipe](Recipe.java)
**Dine kommentarer**
Skriv kommentarer til din løsning i [Oppgavekommentarer](Oppgavekommentarer.md).
## Oppgave 4 - Observerbarhet (15%)
Restauranten er stengt på søndager. Da setter kokken seg ned og lager neste ukes meny.
- Menyen for den inneværende uken slettes.
- Kokken velger ut hvilke retter som skal serveres, og hvor mange porsjoner av hver det skal kjøpes inn til.
- Når denne jobben er ferdig skal det være mulig for eksterne enheter å få beskjed om dette. Eksempler på slike enheter kan være en innkjøpsansvarlig, eller en illustratør for ukesmenyen.
- Du skal ikke implementere noen av de eksterne lytterne, men lage kode som støtter et slikt mønster.
**Oppgaven**
Deklarer nødvendige grensesnitt og/eller klasser som støtter observerbarhet og implementer nødvendige metoder (og felt og hjelpeklasser og -metoder) for oppførselen beskrevet overfor. Bruk det eksisterende grensesnittet [KitchenObserver](KitchenObserver.java).
- [Kitchen](Kitchen.java)
- Du skal *ikke* implementere en lytter her, men koden din skal støtte en slik.
**Dine kommentarer**
Skriv kommentarer til din løsning i [Oppgavekommentarer](Oppgavekommentarer.md).
## Oppgave 5 - JavaFX og FXML (10%)
Det er laget en app som skal hjelpe kokken med å planlegge neste ukes meny. Filen [Kitchen.fxml](Kitchen.fxml) er knyttet til Controllerklassen [KitchenController.java](KitchenController.java). Grensesnittet inneholder:
- En nedtrekksmeny der alle oppskrifter som finnes er lagt inn. Du behøver ikke å vite mye om hvordan denne nedtrekksmenyen fungerer, i oppgaven blir du kun bedt om å lese hvilken oppskrift som er valgt når en knapp trykkes inn.
- Et tekstfelt der kokken kan legge inn hvor mange porsjoner av retten som skal kunne lages neste uke.
- En knapp som, når den er trykket inn, legger inn oppskrift og antall porsjoner i neste ukes meny.
- Et tekstfelt der alle rettene som til nå er valgt er vist, sammen med antallet porsjoner av retten. Det skal oppdateres med metodekallet **updateChosen()**
- En knapp som, når den trykkes inn, bekrefter til systemet at neste ukes meny er ferdig.
Du kan starte appen ved å kjøre [KitchenApp](KitchenApp.java).
**Oppgaven**
- Forhold deg til den eksisterende koden [Kitchen.fxml](Kitchen.fxml) og [KitchenController.java](KitchenController.java)
- Ferdigstill kontrolleren slik at den følger kravene slik de er beskrevet overfor.
**Dine kommentarer**
Skriv kommentarer til din løsning i [Oppgavekommentarer](Oppgavekommentarer.md).
# Le Petite Chef
The five tasks in this part are below.
## Task 1 (25%)
This section is about ** IngredientContainer **, ** Recipe ** and ** RecipeReader **.
** IngredientContainer ** keeps track of the number / quantity of a set of ingredients and is the primary implementation of ** Ingredients **. Since ** Ingredients ** only contains methods for reading information, ** IngredientContainer ** must naturally add methods to change the number / quantity of each ingredient.
** Recipe ** (recipe) represents the ingredients needed for a certain amount of servings of a dish (or drink). The helper class ** RecipeReader ** handles input of recipes from a source, e.g. a file.
** Task **
Implement necessary methods (and fields and auxiliary classes and methods) in
- [IngredientContainer](IngredientContainer.java)
- [Recipe](Recipe.java)
- [RecipeReader](RecipeReader.java)
If you are unable to finish the code reading recipes from file, you can later on use the static method **Recipe.createSampleRecipes()**. This method returns a collection of recipes that you can use in your work. You will find an example of use in [KitchenController.java](KitchenController.java) used in task 5.
** Your Comments **
Write comments on your solution in [Oppgavekommentarer](Oppgavekommentarer.md).
## Task 2 (15%)
This section is about ** Kitchen ** (without observer, that's done in task 4).
The kitchen has a set of recipes (** Recipe **, as specified in the constructor). Some methods (** getRecipe ** and ** filterRecipes **) handle queries on these.
The kitchen has a food store (** getStorage **), which must be filled with enough food to make the dishes. Therefore, the class has methods focusing on the relationship between recipes and the food store (** canCreateRecipe **, ** getRecipesThatCanBeCreated **, ** getRecipiesContainingIngredient **).
After the restaurant is closed for the week, the chef plans next week's menu (using the methods **addRecipeToWeekly**, **removeRecipeFromWeekly** and **clearWeekly**). This consists of a set of existing recipes and a certain number of portions of them. When all the recipes have been entered, **registerWeekly** is called, where functionality such as creating a shopping list could be envisioned. You do not need to implement functionality for creating such a shopping list, or any other usage of the weekly menu.
** Task **
Implement necessary methods (and fields, methods and helper classes) in
- [Kitchen](Kitchen.java)
** Your Comments **
Write comments on your solution in [Oppgavekommentarer](Oppgavekommentarer.md).
## Task 3 - Delegation (10%)
A *scaled* recipe, like the one returned by ** Recipe ** 's ** createNPortions ** method, can benefit from a separate implementation of ** Ingredients ** implemented using delegation.
** Task **
Implement a scaled recipe using delegation, and use this. You should *not* change the **createNPortions** method you created in Task 1, instead create a new **createNPortionsUsingDelegation** method. Note: You *shall not* use the existing IngredientContainer.scaledIngredients() here. The class delegated to should also implement the scaling.
- [ScaledIngredients](ScaledIngredients.java)
- [Recipe](Recipe.java)
** Your Comments **
Write comments on your solution in [Oppgavekommentarer](Oppgavekommentarer.md).
## Task 4 - Observability (15%)
The restaurant is closed on Sundays, and the chef sits down to create next week's menu:
- The menu for the current week is deleted.
- The chef chooses which dishes to serve and how many portions of each to buy.
- When this job is done, it should be possible for external object to be told. Examples of such objects could be someone responsible for purchases, or an illustrator for the weekly menu.
- You should not implement any of the external listeners, only create code that supports such a pattern.
** Task **
Declare required interfaces and / or classes that support observability and implement required methods (and fields, helper classes and methods) for the behavior described above. Make use of the existing interface [KitchenObserver](KitchenObserver.java).
- [Kitchen](Kitchen.java)
- You should *not* implement a listener here, but your code should support one.
** Your Comments **
Write comments on your solution in [Oppgavekommentarer](Oppgavekommentarer.md).
## Task 5 - JavaFX and FXML (10%)
An app has been created to help the chef plan next week's menu. The file [Kitchen.fxml](Kitchen.fxml) is associated with the Controller class [KitchenController.java](KitchenController.java). The interface contains:
- A drop down menu where all the recipes that are available are entered. You do not need to know much about how this drop-down menu works, in the task you are only asked to read which recipe is selected when a button is pressed.
- A text box where the chef can enter how many portions of the dish can be made next week.
- A button that, when pressed, adds the recipe and the number of servings in next week's menu.
- A text box where all the currently selected dishes are displayed, along with the number of portions of the dish. The content is to be updated by calling the method **updateChosen()**.
- A button that, when pressed, confirms to the system that next week's menu is complete.
You can start the app by running [KitchenApp](KitchenApp.java).
** Task **
- Use the existing code [Kitchen.fxml](Kitchen.fxml) and [KitchenController.java](KitchenController.java)
- Complete the controller to follow the requirements as described above.
** Your Comments **
Write comments on your solution in [Oppgavekommentarer](Oppgavekommentarer.md).
# Le Petite Chef
Dei fem oppgåvene i denne delen følgjer under.
## Oppgåve 1 (25%)
Denne delen handlar om **IngredientContainer**, **Recipe** og **RecipeReader**.
**IngredientContainer** held oversikt over talet/mengda av eit sett med ingrediensar og er den primære implementasjonen av **Ingredients**. Sidan **Ingredients** berre inneheld metodar for å lesa ut informasjon, må **IngredientContainer** naturleg nok legga til metodar for å endra talet/mengda som finst av kvar ingrediens.
**Recipe** (oppskrift) representerer ingrediensane som trengst for ei viss mengde porsjonar av ein matrett (eller drikk). Hjelpeklassen **RecipeReader** handterer innlesing av oppskrifter frå ei kjelde, t.d. ei fil.
**Oppgåva**
Implementer nødvendige metodar (og felt og hjelpeklassar og -metodar) i
- [IngredientContainer](IngredientContainer.java)
- [Recipe](Recipe.java)
- [RecipeReader](RecipeReader.java)
Dersom du ikkje klarer å lesa oppskrifter frå fil, så kan du seinare nytta deg av den statiske metoden **Recipe.createSampleRecipes()**. Denne vil returnera ei samling av oppskrifter som du kan bruka. Du finn eit døme på dette i [KitchenController.java](KitchenController.java) som blir brukt i oppgåve 5.
** Kommentarane dine**
Skriv kommentarar til løysinga di i [Oppgavekommentarer](Oppgavekommentarer.md).
## Oppgåve 2 (15%)
Denne delen handlar om **Kitchen** (utan observatør, dei kjem i oppgåve 4).
Kjøkkenet har eit sett med oppskrifter (**Recipe**, som blir angitt i konstruktøren). Nokre metodar (**getRecipe** og **filterRecipes**) handterer spørjing om desse.
Kjøkkenet har eit matlager (**getStorage**), som må vera fylt med nok matvarer til å kunna laga rettane. Derfor har klassen metodar fokusert på samanheng mellom oppskrifter og matlageret (**canCreateRecipe**, **getRecipesThatCanBeCreated**, **getRecipiesContainingIngredient**).
Etter at restauranten er stengd for veka planlegg kokken neste vekes meny (vha. metodane **addRecipeToWeekly**, **removeRecipeFromWeekly** og **clearWeekly**). Denne består av eit sett med eksisterande oppskrifter og ei viss mengde porsjonar av dei. Når alle oppskriftene er lagt inn kallas **registerWeekly**, der ein t.d. kunne tenkje seg at ein handleliste skal lagast. Du treng ikkje å implementera funksjonalitet for ein slik handleliste eller anna bruk av ukesmenyen.
**Oppgåva**
Implementer nødvendige metodar (og felt og hjelpeklassar og -metodar) i
- [Kitchen](Kitchen.java)
**Kommentarane dine**
Skriv kommentarar til løysinga di i [Oppgavekommentarer](Oppgavekommentarer.md).
## Oppgåve 3 - Delegering (10%)
Ei *skalert* oppskrift, som den som blir returnert av **Recipe** sin **createNPortions**-metode, kan ha nytte av ein eigen implementasjon av **Ingredients** implementert vha. delegering.
**Oppgåva**
Implementer ei skalert oppskrift vha. delegering og bruk denne. Du skal *ikkje* endra metoden **createNPortions** som du laga i oppgåve 1, i staden skal du laga ein ekstra metode **createNPortionsUsingDelegation**. Merk: Du skal *ikkje nytte* **IngredientContainer.scaleIngredients()** her, klassen som får ansvaret skal òg implementera skaleringen.
- [ScaledIngredients](ScaledIngredients.java)
- [Recipe](Recipe.java)
**Kommentarane dine**
Skriv kommentarar til løysinga di i [Oppgavekommentarer](Oppgavekommentarer.md).
## Oppgåve 4 - Observerbarhet (15%)
Restauranten er stengd søndagar. Då set kokken seg ned og lagar neste vekes meny.
- Menyen for den inneverande veka blir sletta.
- Kokken vel ut kva rettar som skal serverast, og kor mange porsjonar av kvar det skal kjøpast inn til.
- Når denne jobben er ferdig skal det vere muleg for eksterne objektar å få beskjed om dette. Døme på slike objektar kan vere ein innkjøpsansvarleg, eller ein illustratør for ukesmenyen.
- Du skal ikkje implementera nokre av dei eksterne lyttarane, men lage kode som støttar eit slikt mønster.
**Oppgåva**
Deklarer nødvendige grensesnitt og/eller klassar som støttar observerbarhet og implementer nødvendige metodar (og felt og hjelpeklassar og -metodar) for åtferda beskrive overfor. Nytt det eksisterande grensesnittet [KitchenObserver](KitchenObserver.java).
- [Kitchen](Kitchen.java)
- Du skal *ikkje* implementera ein lyttar her, men koden din skal støtte ein slik.
**Kommentarane dine**
Skriv kommentarar til løysinga di i [Oppgavekommentarer](Oppgavekommentarer.md).
## Oppgåve 5 - JavaFX og FXML (10%)
Det er laga ein app som skal hjelpa kokken med å planlegga neste vekes meny. Fila [Kitchen.fxml](Kitchen.fxml) er knytt til Controllerklassen [KitchenController.java](KitchenController.java). Grensesnittet inneheld:
- Ein nedtrekkmeny der alle oppskrifter som finst er lagt inn. Du treng ikkje å vita mykje om korleis denne nedtrekkmenyen fungerer, i oppgåva blir du berre bedt om å lesa kva oppskrift som er vald når ein knapp blir trykt inn.
- Eit tekstfelt der kokken kan legga inn kor mange porsjonar av retten som skal kunna lagast neste veke.
- Ein knapp som, når han er trykt inn, legg inn oppskrift og talet på porsjonar i neste vekes meny.
- Eit tekstfelt der alle rettane som til no er valde er viste, saman med talet på porsjonar av retten. Det skal oppdaterast med metodekallet **updateChosen()**.
- Ein knapp som, når han blir trykt inn, stadfestar til systemet at neste vekes meny er ferdig.
Du kan starta appen ved å kjøyra [KitchenApp](KitchenApp.java).
**Oppgåva**
- Forhald deg til den eksisterande koden [Kitchen.fxml](Kitchen.fxml) og [KitchenController.java](KitchenController.java)
- Ferdigstill kontrolleren slik at han følgjer krava slik dei er beskrivne overfor.
**Kommentarane dine**
Skriv kommentarar til løysinga di i [Oppgavekommentarer](Oppgavekommentarer.md).
\ No newline at end of file
Le Petite Chef - Oppgavekommentarer / Task comments
==========================
*For å skrive i denne filen trykker du på 'Markdown Source' nederst til venstre i denne fanen. For å se det fint trykker du på 'Preview'*
*To edit this file, press 'Markdown Source' in the bottom left of this
Beskriv viktige valg du mener sensor bør vite om. Spar tid - vær kort og presis.
Describe important choices for the tasks you think should be known during evaluation. Save time - be short and precise!
## Oppgave 1 // task 1
**Example**
_IngredientContainer_
Not sure about how this one should use getters and setter. I chose to ...
## Oppgave 2 // task 2
*Your comments about task 2*
## Oppgave 3 // task 3
*Your comments about task 3*
## Oppgave 4 // task 4
*Your comments about task 4*
## Oppgave 5 // task 5
*Your comments about task 5*
# Le Petite Chef
(Hvis du ønsker å lese denne filen med pent utseende i Eclipse, husk at du kan trykke på 'Preview'-fanen nede til venstre i md-editoren).
Le Petite Chef er en liten familierestaurant. Du har fått i oppdrag å lage et system for å holde styr på oppskrifter, et lager av matvarer (ingredienser) og innkjøp. Kokken skal bl.a. kunne bestemme hvilke oppskrifter som skal brukes neste uke (med antall), og dette skal kunne brukes ved innkjøp av matvarer.
Dette eksamenssettet bygger på at du skal utvide et eksisterende rammeverk. De fleste klassene eksisterer allerede. Dersom du har behov for å lage noen ekstra, for eksempel hjelpeklasser, så står du fritt til det. Hvis du mener at det kan det være lurt å beskrive valgene, se avsnitt om filen Oppgavekommentarer.md under.
## Sentrale klasser
Sentralt i oppgavene står håndtering av matvarer/ingredienser. F.eks. inneholder både oppskrifter og matlageret en mengde/antall av et sett med ingredienser. En ingrediens representeres med en **String** og mengden/antallet av ingrediensen med et desimaltall (**double**).
**[Ingredients](Ingredients.java)**
Dette er et grensesnitt med metoder for å lese ut og gå gjennom et sett ingredienser og deres mengder/antall og metoder knyttet til sammenligning av sett med ingredienser. Den primære implementasjonen av **Ingredients** er **IngredientsContainer**.
**[IngredientContainer](IngredientContainer.java)**
Denne klassen er en konkret implementasjon av **Ingredients**, med ekstra metoder for å endre (legge til og fjerne) ingredienser. Denne kan brukes av andre klasser som trenger å håndtere ingredienser.
**[Recipe](Recipe.java) og [RecipeReader.java](RecipeReader.java)**
Recipe-klassen representerer en oppskrift med et sett tilhørende ingredienser for et visst antall porsjoner. Oppskrifter kan leses inn fra fil vha. **RecipeReader**-klassen.
**[Kitchen](Kitchen.java)**
Kjøkkenet har en oversikt over alle kjente oppskrifter og de oppskriftene som skal brukes i ukemenyen. I tillegg har den et lager av matvarer, som må etterfylles når en ny ukesmeny legges inn.
## Oppgavestruktur
Le Petit Chef er delt i 5 oppgaver, som er naturlige å gjøre i rekkefølge. Du bør likevel tenke på det som en helhet, og det er sluttresultatet som skal leveres inn. Klassene er allerede opprettet og inneholder (noen av de nødvendige) metodene med javadoc og **// TODO**-kommentarer som indikerer hva som må implementeres.
Her beskrives trinnene skissemessig, detaljer finnes i [oppgavebeskrivelsen](Oppgavebeskrivelse.md). Lenkene under går til toppen av oppgavebeskrivelsen, ikke til de respektive oppgavene.
[Oppgave 1](Oppgavebeskrivelse.md) handler om **IngredientContainer**, som implementerer **Ingredients**, **Recipe** og **RecipeReader**.
[Oppgave 2](Oppgavebeskrivelse.md) handler om **Kitchen**. Denne inneholder et sett med oppskrifter, et lager med ingredienser og neste ukes meny.
[Oppgave 3](Oppgavebeskrivelse.md) handler om delegering, der du skal implementere en ny metode i **Recipe**
[Oppgave 4](Oppgavebeskrivelse.md) handler om observerbarhet, der noen skal få beskjed når kokken har laget ferdig neste ukes meny.
[Oppgave 5](Oppgavebeskrivelse.md) handler om en JavaFX-app der kokken kan legge inn neste ukes meny.
## Kommentering av egen kode
Eclipse sin md-editor har faner nede til venstre for å skrive (**Markdown Source**) og én for å se resultatet (**Preview**). Dersom du trenger å klargjøre antakelser du mener du må gjøre eller ønsker å kommentere til sensor, så kan du gjøre det i md-filen [Oppgavekommentarer.md](Oppgavekommentarer.md), som vi har lenket til i avsnittet **Dine kommentarer**. Gå til seksjonen i denne oppgaven som passer til oppgavenummeret du er i.
# Le Petite Chef
(If you want to read this file in a nice format in Eclipse, remember that you can click on the 'Preview' tab in the bottom left of the MD editor).
Le Petite Chef is a small family restaurant. You have been commissioned to create a system for keeping track of recipes, a stock of food (ingredients) and purchases. The chef must, among other things, be able to decide which recipes to use next week (including number of servings), and this can be used when purchasing food.
This exam set is based on extending an existing framework. Most classes already exist. If you need to create some extra things, such as help classes, you are free to do so. If you for any reason want to describe your choices, see the section on Oppgavekommentarer.md below.
## Central Classes
Central to the tasks is the handling of food / ingredients. Eg. both recipes and the food store contain a quantity / number of a set of ingredients. An ingredient is represented by a ** String ** and the amount / number of the ingredient by a decimal (** double **).
** [Ingredients](Ingredients.java) **
This is an interface with methods for reading and reviewing a set of ingredients and their quantities / numbers and methods related to comparing sets of ingredients. The primary implementation of ** Ingredients ** is ** IngredientsContainer **.
** [IngredientContainer](IngredientContainer.java) **
This class is a concrete implementation of ** Ingredients **, with additional methods for changing (adding and removing) ingredients. This can be used by other classes that need to handle ingredients.
** [Recipe](Recipe.java) and [RecipeReader.java](RecipeReader.java) **
The Recipe class represents a recipe with a set of ingredients for a certain number of servings. Recipes can be loaded from file using the ** RecipeReader ** - class.
** [Kitchen](Kitchen.java) **
The kitchen has an overview of all known recipes and the recipes to be used in the weekly menu. In addition, it has stock of foods, which must be replenished when a new weekly menu is added. The rules for replenishing the stock are described in more detail later.
## Task structure
The Le Petit Chef assignment is divided into 5 tasks, and it is natural to do them in order. You should still think of it as a whole, and it is the end result that needs to be handed in. The classes are already created and contain (some of the required) methods with javadoc and ** // TODO ** comments indicating what needs to be implemented.
Here the steps are outlined, details can be found in [Oppgavebeskrivelse](Oppgavebeskrivelse_EN.md). The links below point to the top of Oppgavebeskrivelse, you need to scroll down to each task.
[Task 1](Oppgavebeskrivelse_EN.md) is about ** IngredientContainer **, which implements ** Ingredients **, ** Recipe ** and ** RecipeReader **.
[Task 2](Oppgavebeskrivelse.md) is about ** Kitchen **. This one includes a set of recipes, a stock of ingredients and next week's menu.
[Task 3](Oppgavebeskrivelse_EN.md) is about delegation, where you need to implement a new method in ** Recipe **
[Task 4](Oppgavebeskrivelse_EN.md) is about observability, where someone should be notified when the chef has finished next week's menu.
[Task 5](Oppgavebeskrivelse_EN.md) is about a JavaFX app where the chef can enter next week's menu.
## Commenting your code
Eclipse's md editor has tabs on the bottom left for writing (** Markdown Source **) and one for viewing the result (** Preview **). If you need to clarify assumptions that you feel you need to make or want to comment on, then you can do so in the md file [Oppgavekommentarer.md](Oppgavekommentarer.md), which we have linked to in the section ** Your comments **. Go to the section of this task that matches the task number you are in.
# Le Petite Chef
(Viss du ønsker å lesa denne fila med fin utsjånad i Eclipse, husk at du kan trykka på 'Preview'-fana nede til venstre i md-editoren).
Le Petite Chef er ein liten familierestaurant. Du har fått i oppdrag å laga eit system for å halda styr på oppskrifter, eit lager av matvarer (ingrediensar) og innkjøp. Kokken skal m.a. kunna bestemma kva oppskrifter som skal brukast neste veke (med mengde), og dette skal kunna brukast ved innkjøp av matvarer.
Dette eksamenssettet bygger på at du skal utvida eit eksisterande rammeverk. Dei fleste klassane eksisterer allereie. Dersom du har behov for å laga nokre ekstra, til dømes hjelpeklassar, så står du fritt til det. Viss du trur at kan det vera lurt å beskriva vala, sjå avsnitt om Oppgavekommentarer.md under.
## Sentrale klassar
Sentralt i oppgåvene står handtering av matvarer/ingrediensar. T.d. inneheld både oppskrifter og matlageret ein mengde av eit sett med ingrediensar. Ein ingrediens blir representert med ein **String** og mengda/talet av ingrediensen med eit desimaltal (*double*).
*[Ingredients](Ingredients.java)*
Dette er eit grensesnitt med metodar for å lesa ut og gå gjennom eit sett ingrediensar og mengdene deira/mengde og metodar knytt til samanlikning av sett med ingrediensar. Den primære implementasjonen av **Ingredients** er **IngredientsContainer**.
*[IngredientContainer](IngredientContainer.java)*
Denne klassen er ein konkret implementasjon av **Ingredients**, med ekstra metodar for å endra (legga til og fjerne) ingrediensar. Denne kan brukast av andre klassar som treng å handtera ingrediensar.
*[Recipe](Recipe.java) og [RecipeReader.java](RecipeReader.java)*
Recipe-klassen representerer ei oppskrift med eit sett tilhøyrande ingrediensar for ei viss mengde porsjonar. Oppskrifter kan lesast inn frå fil vha. **RecipeReader*-klassen.
*[Kitchen](Kitchen.java)*
Kjøkkenet har ei oversikt over alle kjente oppskrifter og dei oppskriftene som skal brukast i vekemenyen. I tillegg har han eit lager av matvarer, som må etterfyllast når ein ny vekemeny blir lagd inn.
## Oppgavestruktur
Le Petit Chef er delt i 5 oppgåver, som er naturlege å gjera i rekkefølgje. Du bør likevel tenka på det som ein heilskap, og det er sluttresultatet som skal leverast inn. Klassane er allereie oppretta og inneheld (nokon av dei nødvendige) metodane med javadoc og *// TODO*-kommentarar som indikerer kva som må implementerast.
Her blir trinna beskrivne skissemessig, detaljar finst i [oppgåveskildringa](Oppgavebeskrivelse_NN.md). Lenkene under går til toppen av oppgåveskildringa, ikkje til dei respektive oppgåvene.
[Oppgåve 1](Oppgavebeskrivelse_NN.md) handlar om **IngredientContainer**, som implementerer **Ingredients**, **Recipe** og **RecipeReader**.
[Oppgåve 2](Oppgavebeskrivelse_NN.md) handlar om **Kitchen**. Denne inneheld eit sett med oppskrifter, eit lager med ingrediensar og neste vekes meny.
[Oppgåve 3](Oppgavebeskrivelse_NN.md) handlar om delegering, der du skal implementera ein ny metode i **Recipe*
[Oppgåve 4](Oppgavebeskrivelse_NN.md) handlar om observerbarhet, der nokon skal få beskjed når kokken har laga ferdig neste vekes meny.
[Oppgåve 5](Oppgavebeskrivelse_NN.md) handlar om ein JavaFX-app der kokken kan legga inn neste vekes meny.
Eclipse sin md-editor har faner nede til venstre for å skriva (**Markdown Source**) og éin for å sjå resultatet (**Preview**). Dersom du treng å klargjera antakelser du meiner du må gjera eller ønsker å kommentera til sensor, så kan du gjera det i md-filen [Oppgavekommentarer.md](Oppgavekommentarer.md), som vi har lenka til i avsnittet *Dine kommentarar**. Gå til seksjonen i denne oppgåva som passar til oppgåvenummeret du er i.
\ No newline at end of file
package food;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Collection;
public class Recipe {
private String name;
private String category;
private int nPortions;
private Ingredients ingredients;
/**
* Initialize a new recipe
*
* @param name The name of the recipe
* @param category The category of the recipe, e.g. "Dinner", "Dessert"
* @param nPortions The number of portions this recipe makes
* @param ingredients The ingredients in the recipe
*/
public Recipe(String name, String category, int nPortions, Ingredients ingredients) {
// TODO
}
/**
* @return The name of the recipe
*/
public String getName() {
return name;
}
/**
* @return The category of the recipe
*/
public String getCategory() {
return category;
}
/**
* @return The number of portions this recipe makes
*/
public int getNPortions() {
return nPortions;
}
/**
* @return The ingredients in the recipe
*/
public Ingredients getIngredients() {
return ingredients;
}
/**
* @return A String representation of this object, showing the values of its fields
*/
@Override
public String toString() {
return "Recipe [name=" + name + ", category=" + category + ", nPortions=" + nPortions + ", ingredients="
+ ingredients + "]";
}
/**
* Create a copy of this recipe, but change the ingredients such that the new
* recipe creates `n` portions instead of the amount this recipe makes.
*
* @param n The number of portions the new recipe should make
* @return The new recipe
*/
public Recipe createNPortions(int n) {
// TODO
}
/**
* Creates a set of sample recipes, that can be used for testing, or to get
* data if you do not manage to implement `RecipeReader`.
*
* @return a collection of sample recipes
*/
public static Collection<Recipe> createSampleRecipes() { // May start out hidden - press + sign to left.
Collection<Recipe> recipes = new ArrayList<>();
IngredientContainer ig = new IngredientContainer();
ig.addIngredient("egg", 4);
ig.addIngredient("milk", 5);
ig.addIngredient("flour", 3);
ig.addIngredient("salt", 1);
Recipe pancakes = new Recipe("pancakes", "almost_dinner", 4, ig);
recipes.add(pancakes);
ig = new IngredientContainer();
ig.addIngredient("egg", 5);
ig.addIngredient("milk", 4);
ig.addIngredient("flour", 3);
ig.addIngredient("salt", 1);
ig.addIngredient("vanilla", 1);
Recipe waffles = new Recipe("waffles", "Dessert", 4, ig);
recipes.add(waffles);
ig = new IngredientContainer();
ig.addIngredient("Egg Yolks", 3.00);
ig.addIngredient("Lime", 4.00);
ig.addIngredient("Double Cream", 300.00);
ig.addIngredient("Condensed Milk", 400.00);
ig.addIngredient("Butter", 150.00);
ig.addIngredient("Digestive Biscuits", 300.00);
ig.addIngredient("Icing Sugar", 1.00);
recipes.add(new Recipe("Key Lime Pie", "Dessert", 4, ig));
ig = new IngredientContainer();
ig.addIngredient("Water", 1.00);
ig.addIngredient("Garlic Clove", 3.00);
ig.addIngredient("Sesame Seed Oil", 5.00);
ig.addIngredient("Carrots", 3.00);
ig.addIngredient("Wonton Skin", 1.00);
ig.addIngredient("Oil", 1.00);
ig.addIngredient("Celery", 3.00);
ig.addIngredient("Soy Sauce", 15.00);
ig.addIngredient("Ginger", 5.00);
ig.addIngredient("Spring Onions", 6.00);
ig.addIngredient("Pork", 1.00);
recipes.add(new Recipe("Wontons", "Pork", 4, ig));
ig = new IngredientContainer();
ig.addIngredient("Strawberries", 300.00);
ig.addIngredient("Caster Sugar", 175.00);
ig.addIngredient("Raspberries", 500.00);
ig.addIngredient("Blackberries", 250.00);
ig.addIngredient("Redcurrants", 100.00);
ig.addIngredient("Bread", 7.00);
recipes.add(new Recipe("Summer Pudding", "Dessert", 4, ig));
ig = new IngredientContainer();
ig.addIngredient("Chicken Stock", 1.00);
ig.addIngredient("Honey", 1.00);
ig.addIngredient("Broccoli", 1.00);
ig.addIngredient("Balsamic Vinegar", 1.00);
ig.addIngredient("Potatoes", 5.00);
ig.addIngredient("Butter", 15.00);
ig.addIngredient("Garlic", 2.00);
ig.addIngredient("Vegetable Oil", 15.00);
ig.addIngredient("Olive Oil", 15.00);
ig.addIngredient("Chicken Breast", 2.00);
recipes.add(new Recipe("Honey Balsamic Chicken with Crispy Broccoli & Potatoes", "Chicken", 4, ig));
ig = new IngredientContainer();
ig.addIngredient("Water", 1.00);
ig.addIngredient("Salt", 1.00);
ig.addIngredient("Egg", 1.00);
ig.addIngredient("Starch", 10.00);
ig.addIngredient("Coriander", 1.00);
ig.addIngredient("Soy Sauce", 10.00);
ig.addIngredient("Tomato Puree", 30.00);
ig.addIngredient("Vinegar", 10.00);
ig.addIngredient("Pork", 200.00);
ig.addIngredient("Sugar", 5.00);
recipes.add(new Recipe("Sweet and Sour Pork", "Pork", 4, ig));
ig = new IngredientContainer();
ig.addIngredient("basil", 1.00);
ig.addIngredient("oregano", 1.00);
ig.addIngredient("allspice", 1.00);
ig.addIngredient("Flour", 2.00);
ig.addIngredient("Egg White", 1.00);
ig.addIngredient("black pepper", 5.00);
ig.addIngredient("celery salt", 1.00);
ig.addIngredient("Salt", 1.00);
ig.addIngredient("onion salt", 2.00);
ig.addIngredient("garlic powder", 1.00);
ig.addIngredient("Oil", 2.00);
ig.addIngredient("paprika", 1.00);
ig.addIngredient("marjoram", 1.00);
ig.addIngredient("chili powder", 5.00);
ig.addIngredient("sage", 1.00);
ig.addIngredient("Chicken", 1.00);
ig.addIngredient("Brown Sugar", 1.00);
recipes.add(new Recipe("Kentucky Fried Chicken", "Chicken", 4, ig));
ig = new IngredientContainer();
ig.addIngredient("Hotsauce", 1.00);
ig.addIngredient("Potatoes", 2.00);
ig.addIngredient("Pepper", 1.00);
ig.addIngredient("Red Onions", 1.00);
ig.addIngredient("Vegetable Oil", 1.00);
ig.addIngredient("Bread", 2.00);
ig.addIngredient("Lime", 1.00);
ig.addIngredient("Salt", 1.00);
ig.addIngredient("Barbeque Sauce", 1.00);
ig.addIngredient("Garlic", 2.00);
ig.addIngredient("Tomato Ketchup", 1.00);
ig.addIngredient("Pork", 1.00);
ig.addIngredient("Sugar", 1.00);
recipes.add(new Recipe("BBQ Pork Sloppy Joes with Pickled Onion & Sweet Potato Wedges", "Pork", 4, ig));
ig = new IngredientContainer();
ig.addIngredient("Vanilla Extract", 1.00);
ig.addIngredient("Oil", 5.00);
ig.addIngredient("Raspberries", 125.00);
ig.addIngredient("Pecan Nuts", 25.00);
ig.addIngredient("Eggs", 2.00);
ig.addIngredient("Baking Powder", 1.00);
ig.addIngredient("Banana", 1.00);
recipes.add(new Recipe("Banana Pancakes", "Dessert", 4, ig));
ig = new IngredientContainer();
ig.addIngredient("Garlic Clove", 4.00);
ig.addIngredient("Plain Flour", 30.00);
ig.addIngredient("Gruyère", 140.00);
ig.addIngredient("Dry White Wine", 250.00);
ig.addIngredient("Onion", 1000.00);
ig.addIngredient("Butter", 50.00);
ig.addIngredient("Olive Oil", 15.00);
ig.addIngredient("Sugar", 5.00);
ig.addIngredient("Beef Stock", 1.00);
ig.addIngredient("Bread", 4.00);
recipes.add(new Recipe("French Onion Soup", "Side", 4, ig));
ig = new IngredientContainer();
ig.addIngredient("garlic", 3.00);
ig.addIngredient("bowtie pasta", 16.00);
ig.addIngredient("Pepper", 1.00);
ig.addIngredient("onion", 1.00);
ig.addIngredient("Butter", 2.00);
ig.addIngredient("milk", 1.00);
ig.addIngredient("Olive Oil", 3.00);
ig.addIngredient("Squash", 1.00);
ig.addIngredient("Parmesan cheese", 1.00);
ig.addIngredient("mushrooms", 8.00);
ig.addIngredient("Salt", 5.00);
ig.addIngredient("Broccoli", 1.00);
ig.addIngredient("white wine", 1.00);
ig.addIngredient("red pepper flakes", 1.00);
ig.addIngredient("heavy cream", 1.00);
ig.addIngredient("Chicken", 5.00);
ig.addIngredient("Parsley", 1.00);
recipes.add(new Recipe("Chicken Alfredo Primavera", "Chicken", 4, ig));
return recipes;
}
public static void main(String[] args) {
IngredientContainer ig = new IngredientContainer();
ig.addIngredient("egg", 4);
ig.addIngredient("milk", 5);
ig.addIngredient("flour", 3);
ig.addIngredient("salt", 1);
Recipe recipe = new Recipe("pancakes", "almost_dinner", 4, ig);
Recipe twice = recipe.createNPortions(8);
assertEquals(8, twice.getIngredients().getIngredientAmount("egg"), 0.00001);
Collection<Recipe> recipes = Recipe.createSampleRecipes();
assertEquals(12, recipes.size(), 0.00001);
}
}
package food;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class RecipeReader {
// regex for column separator
private final String columnSeparatorRegex = "\\$";
/**
* Read recipes from an InputStream with the given format:
*
* name$category$nPortions$ingredient1;ingredient2;...;...$amount1;amount2;...;...
*
* As you see from the format, each recipe is a single line, with fields separated by `$` and
* elements in lists separated by `;`.
*
* Regarding ingredients and amounts, the two lists are sorted in the same order, so `ingredient1`
* should have `amount1`, and so forth. All amounts can be read as doubles, while nPortions is an integer.
*
* Note that the first line of the stream is the header, and so should not be used.
* If a line (i.e. a single recipe) fails to be parsed correctly, that recipe is to be skipped.
*
* @param input The source to read from
* @throws IOException if input (InputStream) throws IOException
*/
public List<Recipe> readRecipes(InputStream input) throws IOException {
// TODO
}
public static void main(String[] args) throws IOException {
// read from sample file
List<Recipe> recipes = new RecipeReader().readRecipes(RecipeReader.class.getResourceAsStream("sample-recipes.txt"));
System.out.println(recipes);
}
}
package food;
import static org.junit.Assert.assertEquals;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
public class RecipeTest {
private static final double EPSILON = 0.0001;
private IngredientContainer createIG(Map<String, Double> ingredients) {
IngredientContainer ig = new IngredientContainer();
for (String i : ingredients.keySet()) {
ig.addIngredient(i, ingredients.get(i));
}
return ig;
}
@Test
public void testCreateNPortions() {
Recipe r = new Recipe(
"Recipe",
"Dinner",
4,
createIG(Map.of("food1", 10.0, "food2", 31.0, "food3", 2.0))
);
Recipe r2 = r.createNPortions(8);
assertEquals(20.0, r2.getIngredients().getIngredientAmount("food1"), EPSILON);
assertEquals(62.0, r2.getIngredients().getIngredientAmount("food2"), EPSILON);
assertEquals(4.0, r2.getIngredients().getIngredientAmount("food3"), EPSILON);
Collection<String> expectedNames = Set.of("food1", "food2", "food3");
IngredientContainerTest.assertCollectionsContainTheSame(expectedNames, r2.getIngredients().getIngredientNames());
Recipe r3 = r.createNPortions(2);
assertEquals(5.0, r3.getIngredients().getIngredientAmount("food1"), EPSILON);
assertEquals(15.5, r3.getIngredients().getIngredientAmount("food2"), EPSILON);
assertEquals(1.0, r3.getIngredients().getIngredientAmount("food3"), EPSILON);
Collection<String> expectedNames2 = Set.of("food1", "food2", "food3");
IngredientContainerTest.assertCollectionsContainTheSame(expectedNames2, r3.getIngredients().getIngredientNames());
}
}
\ No newline at end of file
package food;
public class ScaledIngredients implements Ingredients {
// TODO: necessary declarations
/**
* Create a new scaled ingredients, given by an original `Ingredients`-object and a scale
* @param ingredients The ingredients to be scaled
* @param scale The scale to use
*/
public ScaledIngredients(Ingredients ingredients, double scale) {
// TODO
}
// TODO: necessary methods
// Examples of SOME use of ScaledIngredients.
public static void main(String[] args) {
// ingredients in a recipe could be..
IngredientContainer ig = new IngredientContainer();
ig.addIngredient("egg", 4);
ig.addIngredient("milk", 5);
ig.addIngredient("flour", 3);
ig.addIngredient("salt", 1);
// Scaling IngredientContainer to double the size.
ScaledIngredients scaledIngredients = new ScaledIngredients(ig, 2);
// Should have 8 eggs:
System.out.println("Eggs: " + scaledIngredients.getIngredientAmount("egg"));
// Storage contains...
IngredientContainer storage = new IngredientContainer();
storage.addIngredient("egg", 3);
storage.addIngredient("milk", 3);
storage.addIngredient("flour", 3);
storage.addIngredient("salt",3);
// Storage should miss 5.0 egg, 3.0 flour and 7.0 milk.
System.out.println(scaledIngredients.missingIngredients(storage));
// Should be [salt, egg, flour, milk] (In some order)
System.out.println(scaledIngredients.getIngredientNames());
// Add more salt to original container
ig.addIngredient("salt", 3);
// Should now have 8 salt
System.out.println("Salt: " + scaledIngredients.getIngredientAmount("salt"));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment