public State PlanIngredient(Domain domain, State startingState, IngredientRecipe ingredient) {
    State currentState = new State(startingState);

    List<IngredientRecipe> contents = ingredient.getContents();
    for (IngredientRecipe subIngredient : contents) {
      if (!subIngredient.isSimple()) {
        System.out.println("Planning ingredient " + subIngredient.getName());
        currentState = this.PlanIngredient(domain, currentState, subIngredient);
      }
    }

    ObjectClass simpleIngredientClass = domain.getObjectClass(IngredientFactory.ClassNameSimple);
    ObjectClass containerClass = domain.getObjectClass(ContainerFactory.ClassName);
    ObjectInstance shelfSpace = currentState.getObject("shelf");

    List<ObjectInstance> ingredientInstances =
        IngredientFactory.getSimpleIngredients(simpleIngredientClass, ingredient);
    List<ObjectInstance> containerInstances =
        Recipe.getContainers(containerClass, ingredientInstances, shelfSpace.getName());

    for (ObjectInstance ingredientInstance : ingredientInstances) {
      if (currentState.getObject(ingredientInstance.getName()) == null) {
        currentState.addObject(ingredientInstance);
      }
    }

    for (ObjectInstance containerInstance : containerInstances) {
      if (currentState.getObject(containerInstance.getName()) == null) {
        ContainerFactory.changeContainerSpace(containerInstance, shelfSpace.getName());
        currentState.addObject(containerInstance);
      }
    }

    final PropositionalFunction isSuccess = new RecipeFinished("success", domain, ingredient);
    PropositionalFunction isFailure = new RecipeBotched("botched", domain, ingredient);
    // RewardFunction recipeRewardFunction = new RecipeRewardFunction(brownies);
    // RewardFunction recipeRewardFunction = new RecipeRewardFunction();
    RewardFunction humanRewardFunction = new RecipeAgentSpecificMakeSpanRewardFunction("human");
    RewardFunction robotRewardFunction = new RecipeAgentSpecificMakeSpanRewardFunction("robot");
    TerminalFunction recipeTerminalFunction = new RecipeTerminalFunction(isSuccess, isFailure);

    StateHashFactory hashFactory = new NameDependentStateHashFactory();
    StateConditionTest goalCondition =
        new StateConditionTest() {
          @Override
          public boolean satisfies(State s) {
            return isSuccess.somePFGroundingIsTrue(s);
          }
        };
    // final int numSteps = Recipe.getNumberSteps(ingredient);
    Heuristic heuristic =
        new Heuristic() {
          @Override
          public double h(State state) {
            return 0;
            // List<ObjectInstance> objects =
            // state.getObjectsOfTrueClass(Recipe.ComplexIngredient.className);
            // double max = 0;
            // for (ObjectInstance object : objects)
            // {
            //	max = Math.max(max, this.getSubIngredients(state, object));
            // }
            // return numSteps - max;
          }
          /*
          public int getSubIngredients(State state, ObjectInstance object)
          {
          	int count = 0;
          	count += IngredientFactory.isBakedIngredient(object) ? 1 : 0;
          	count += IngredientFactory.isMixedIngredient(object) ? 1 : 0;
          	count += IngredientFactory.isMeltedIngredient(object) ? 1 : 0;

          	if (IngredientFactory.isSimple(object))
          	{
          		return count;
          	}
          	Set<String> contents = IngredientFactory.getContentsForIngredient(object);
          	for (String str: contents)
          	{
          		count += this.getSubIngredients(state, state.getObject(str));
          	}
          	return count;
          }*/
        };
    boolean finished = false;
    State endState = startingState;
    List<GroundedAction> fullActions = new ArrayList<GroundedAction>();
    List<Double> fullReward = new ArrayList<Double>();
    boolean currentAgent = false;
    while (!finished) {
      currentAgent = !currentAgent;
      RewardFunction recipeRewardFunction =
          (currentAgent) ? humanRewardFunction : robotRewardFunction;
      AStar aStar = new AStar(domain, recipeRewardFunction, goalCondition, hashFactory, heuristic);
      aStar.planFromState(currentState);
      Policy policy = new DDPlannerPolicy(aStar);
      EpisodeAnalysis episodeAnalysis =
          policy.evaluateBehavior(currentState, recipeRewardFunction, recipeTerminalFunction);

      System.out.println("Taking action " + episodeAnalysis.actionSequence.get(0).action.getName());
      fullActions.add(episodeAnalysis.actionSequence.get(0));
      fullReward.add(episodeAnalysis.rewardSequence.get(0));
      currentState = episodeAnalysis.stateSequence.get(1);
      endState = episodeAnalysis.getState(episodeAnalysis.stateSequence.size() - 1);
      List<ObjectInstance> finalObjects =
          new ArrayList<ObjectInstance>(
              endState.getObjectsOfTrueClass(IngredientFactory.ClassNameComplex));
      List<ObjectInstance> containerObjects =
          new ArrayList<ObjectInstance>(endState.getObjectsOfTrueClass(ContainerFactory.ClassName));
      ObjectInstance namedIngredient = null;
      for (ObjectInstance obj : finalObjects) {
        if (Recipe.isSuccess(endState, ingredient, obj)) {
          namedIngredient =
              DualAgentIndependentPlan.getNewNamedComplexIngredient(obj, ingredient.getName());
          String container = IngredientFactory.getContainer(obj);
          DualAgentIndependentPlan.switchContainersIngredients(
              containerObjects, obj, namedIngredient);

          ObjectInstance containerInstance = endState.getObject(container);
          ContainerFactory.removeContents(containerInstance);
          ContainerFactory.addIngredient(containerInstance, ingredient.getName());
          endState.removeObject(obj);
          endState.addObject(namedIngredient);
          // return endState;
        }
      }
      if (episodeAnalysis.actionSequence.size() <= 1) {
        System.out.println("Action sequence size: " + episodeAnalysis.actionSequence.size());
        finished = true;
      }

      for (int i = 0; i < fullActions.size(); ++i) {
        GroundedAction action = fullActions.get(i);

        double reward = fullReward.get(i);
        System.out.print("Cost: " + reward + " " + action.action.getName() + " ");
        for (int j = 0; j < action.params.length; ++j) {
          System.out.print(action.params[j] + " ");
        }
        System.out.print("\n");
      }
    }
    return endState;
  }
 public static void main(String[] args) throws IOException {
   DualAgentIndependentPlan kitchen = new DualAgentIndependentPlan();
   System.out.println("Generating Domain");
   Domain domain = kitchen.generateDomain();
   kitchen.PlanRecipeTwoAgents(domain, new Brownies());
 }