Functional Scope (In-Scope)
- Ingredient Density Unit Conversion: Converts fluid volume into metric weight utilizing dynamic density tables (e.g. converting sugar, flour, and milk accurately).
- Dynamic Servings Scaling Engine: Adjusts raw volume metrics based on target-to-base ratio and performs decimal fraction formatting.
- Dietary Tag Classification Matching: Restricts options strictly by filtering against specific dietary profiles (e.g. Vegetarian, Vegan, Gluten-Free).
- Ingredient Overlap Recommendation Scoring: Analyzes a user's local pantry list to sort matching recipes by matching ratios.
Explicit Boundaries (Out-of-Scope)
- Direct Grocery Order Delivery Integrations: Ignores external merchant APIs, payment checkouts, and routing logistics.
- Active Recipe Social Sharing Boards: Excludes live user forums, comment systems, or photo attachment storage grids.
Production reference implementations demonstrating ingredient density translations and recipe scaling in Java and Python:
// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
enum Unit {
GRAMS("Weight", 1.0),
KILOGRAMS("Weight", 1000.0),
MILLILITERS("Volume", 1.0),
LITERS("Volume", 1000.0),
CUPS("Volume", 240.0),
TABLESPOON("Volume", 15.0),
TEASPOON("Volume", 5.0);
private final String type;
private final double baseFactor; // Factor to convert to base unit (Grams or Milliliters)
Unit(String type, double baseFactor) {
this.type = type;
this.baseFactor = baseFactor;
}
public String getType() { return type; }
public double getBaseFactor() { return baseFactor; }
}
enum DietaryTag {
VEGETARIAN, VEGAN, GLUTEN_FREE, KETO, NUT_FREE
}
class Ingredient {
private final String name;
private final double quantity;
private final Unit unit;
public Ingredient(String name, double quantity, Unit unit) {
this.name = name;
this.quantity = quantity;
this.unit = unit;
}
public String getName() { return name; }
public double getQuantity() { return quantity; }
public Unit getUnit() { return unit; }
@Override
public String toString() {
return String.format("%.2f %s of %s", quantity, unit, name);
}
}
class Recipe {
private final String recipeId;
private final String title;
private final int baseServings;
private final List<Ingredient> ingredients;
private final List<String> instructions;
private final Set<DietaryTag> dietaryTags;
public Recipe(String recipeId, String title, int baseServings, List<Ingredient> ingredients, List<String> instructions, Set<DietaryTag> dietaryTags) {
this.recipeId = recipeId;
this.title = title;
this.baseServings = baseServings;
this.ingredients = ingredients;
this.instructions = instructions;
this.dietaryTags = dietaryTags;
}
public String getRecipeId() { return recipeId; }
public String getTitle() { return title; }
public int getBaseServings() { return baseServings; }
public List<Ingredient> getIngredients() { return ingredients; }
public List<String> getInstructions() { return instructions; }
public Set<DietaryTag> getDietaryTags() { return dietaryTags; }
@Override
public String toString() {
return "Recipe{title='" + title + "', tags=" + dietaryTags + "}";
}
}
class UnitConverter {
// Density table for cross-family conversions: IngredientName -> Density (grams per milliliter)
private static final Map<String, Double> densities = new HashMap<>();
static {
densities.put("flour", 0.53); // 0.53g per ml
densities.put("sugar", 0.84); // 0.84g per ml
densities.put("milk", 1.03); // 1.03g per ml
densities.put("water", 1.00); // 1.00g per ml
}
public static Ingredient convert(Ingredient ingredient, Unit targetUnit) {
if (ingredient.getUnit() == targetUnit) {
return ingredient;
}
double val = ingredient.getQuantity();
Unit sourceUnit = ingredient.getUnit();
String name = ingredient.getName().toLowerCase();
// 1. Convert within the same family (e.g. Weight -> Weight)
if (sourceUnit.getType().equals(targetUnit.getType())) {
double valueInBase = val * sourceUnit.getBaseFactor();
double targetValue = valueInBase / targetUnit.getBaseFactor();
return new Ingredient(ingredient.getName(), targetValue, targetUnit);
}
// 2. Cross-family conversion using density (Volume <-> Weight)
double density = densities.getOrDefault(name, 1.0); // Fallback density
double volumeInMl;
if ("Weight".equals(sourceUnit.getType())) {
// Weight to Volume: grams / density = ml
double grams = val * sourceUnit.getBaseFactor();
volumeInMl = grams / density;
} else {
// Volume to Weight: ml * density = grams
double ml = val * sourceUnit.getBaseFactor();
volumeInMl = ml * density; // This is weight in grams
}
// Convert base value of destination family to target unit
double targetVal = volumeInMl / targetUnit.getBaseFactor();
return new Ingredient(ingredient.getName(), targetVal, targetUnit);
}
}
class RecipeService {
private final List<Recipe> recipes = new CopyOnWriteArrayList<>();
public void addRecipe(Recipe recipe) {
recipes.add(recipe);
}
public List<Ingredient> scaleRecipe(Recipe recipe, int targetServings) {
double ratio = (double) targetServings / recipe.getBaseServings();
return recipe.getIngredients().stream()
.map(i -> new Ingredient(i.getName(), roundToSensibleFraction(i.getQuantity() * ratio), i.getUnit()))
.collect(Collectors.toList());
}
private double roundToSensibleFraction(double value) {
return Math.round(value * 100.0) / 100.0;
}
// Pantry matching score resolver
public List<Recipe> findRecipesByIngredients(Set<String> availableIngredients, Set<DietaryTag> dietaryFilters) {
Set<String> lowerAvailable = availableIngredients.stream()
.map(String::toLowerCase)
.collect(Collectors.toSet());
return recipes.stream()
.filter(r -> r.getDietaryTags().containsAll(dietaryFilters))
.sorted((r1, r2) -> {
double score1 = getMatchScore(r1, lowerAvailable);
double score2 = getMatchScore(r2, lowerAvailable);
return Double.compare(score2, score1); // Descending score
})
.collect(Collectors.toList());
}
private double getMatchScore(Recipe recipe, Set<String> lowerAvailable) {
if (recipe.getIngredients().isEmpty()) return 0.0;
long matches = recipe.getIngredients().stream()
.map(i -> i.getName().toLowerCase())
.filter(lowerAvailable::contains)
.count();
return (double) matches / recipe.getIngredients().size();
}
}
public class Main {
public static void main(String[] args) {
System.out.println("=== STARTING FOOD RECIPE APP SIMULATION ===");
RecipeService service = new RecipeService();
// Create mock recipes
List<Ingredient> cakeIngredients = List.of(
new Ingredient("flour", 2.0, Unit.CUPS),
new Ingredient("sugar", 200.0, Unit.GRAMS),
new Ingredient("milk", 1.0, Unit.CUPS)
);
Recipe sweetCake = new Recipe("r1", "Sweet Cake", 4, cakeIngredients, List.of("Mix", "Bake"), Set.of(DietaryTag.VEGETARIAN));
List<Ingredient> breadIngredients = List.of(
new Ingredient("flour", 3.0, Unit.CUPS),
new Ingredient("water", 1.5, Unit.CUPS)
);
Recipe veganBread = new Recipe("r2", "Vegan Bread", 6, breadIngredients, List.of("Knead", "Rise", "Bake"), Set.of(DietaryTag.VEGETARIAN, DietaryTag.VEGAN, DietaryTag.NUT_FREE));
service.addRecipe(sweetCake);
service.addRecipe(veganBread);
// 1. Density-based conversion testing
System.out.println("--- Density-Based Converter Test ---");
Ingredient sugarInCups = new Ingredient("sugar", 2.0, Unit.CUPS);
Ingredient sugarInGrams = UnitConverter.convert(sugarInCups, Unit.GRAMS);
System.out.println("2 Cups of Sugar converted to Grams: " + sugarInGrams); // Uses density: 2 * 240 * 0.84 = 403.2g
Ingredient milkInGrams = new Ingredient("milk", 500.0, Unit.GRAMS);
Ingredient milkInCups = UnitConverter.convert(milkInGrams, Unit.CUPS);
System.out.println("500g of Milk converted to Cups: " + milkInCups); // Uses density
// 2. Scaling recipe servings
System.out.println("\n--- Recipe Ingestion Scaling Test ---");
System.out.println("Scaling Sweet Cake from 4 servings to 12 servings:");
List<Ingredient> scaled = service.scaleRecipe(sweetCake, 12);
for (Ingredient ing : scaled) {
System.out.println(" " + ing);
}
// 3. Pantry Match Matching Test
System.out.println("\n--- Pantry-based Match Ranking ---");
Set<String> pantry = Set.of("flour", "water");
System.out.println("Searching vegetarian recipes matching pantry items: " + pantry);
List<Recipe> matched = service.findRecipesByIngredients(pantry, Set.of(DietaryTag.VEGETARIAN));
for (Recipe r : matched) {
System.out.println(" Matched Recipe: " + r.getTitle());
}
System.out.println("=== FOOD RECIPE APP SIMULATION COMPLETE ===");
}
}