/// <summary> /// Function to generate a HTN tree for this monster /// </summary> /// <returns></returns> HTN_node generateHTNtree() { // the image of this tree is shown in PDF file // root node HTN_CompoundNode root = new HTN_CompoundNode(); // create children methods HTN_MethodNode method1 = new HTN_MethodNode(Task.DISTANCE_ATTACK); HTN_MethodNode method2 = new HTN_MethodNode(Task.IDLE); root.addChild(method1); root.addChild(method2); // create children tasks for method1 //HTN_CompoundNode crate_attack = new HTN_CompoundNode(); //HTN_CompoundNode rock_attack = new HTN_CompoundNode(); HTN_CompoundNode distance_attack = new HTN_CompoundNode(); HTN_MethodNode crate_attackM = new HTN_MethodNode(Task.CRATE_ATTACK); HTN_MethodNode rock_attackM = new HTN_MethodNode(Task.ROCK_ATTACK); crate_attackM.addChild(new HTN_PrimitiveNode(Task.MOVE_TO_CRATE)); crate_attackM.addChild(new HTN_PrimitiveNode(Task.THROW_CRATE)); rock_attackM.addChild(new HTN_PrimitiveNode(Task.MOVE_TO_ROCK)); rock_attackM.addChild(new HTN_PrimitiveNode(Task.THROW_ROCK)); //method1.addChild(crate_attack); //method1.addChild(rock_attack); method1.addChild(distance_attack); //crate_attack.addChild(crate_attackM); //rock_attack.addChild(rock_attackM); distance_attack.addChild(crate_attackM); distance_attack.addChild(rock_attackM); // add child task for method2 HTN_CompoundNode idle = new HTN_CompoundNode(); HTN_MethodNode yelling_wanderM = new HTN_MethodNode(Task.YELLING_WANDER); HTN_MethodNode wanderM = new HTN_MethodNode(Task.ONLY_WANDER); yelling_wanderM.addChild(new HTN_PrimitiveNode(Task.YELLING)); yelling_wanderM.addChild(new HTN_PrimitiveNode(Task.WANDER)); wanderM.addChild(new HTN_PrimitiveNode(Task.WANDER)); method2.addChild(idle); idle.addChild(yelling_wanderM); idle.addChild(wanderM); //method2.addChild(new HTN_PrimitiveNode(Task.WANDER)); return(root); }
/// <summary> /// Function to generate a plan for a given root node of HTN tree /// </summary> /// <param name="rootNode"></param> public void planning(HTN_node rootNode) { HTN_WorldState state = this.currentWorldState.clone(); // make a copy of the current state ArrayList finalPlanList = new ArrayList(); Stack <HTN_node> tasksNodes = new Stack <HTN_node>(); // stack for store Method node for backtracking Stack <ArrayList> backTrackingMethods = new Stack <ArrayList>(); // each list in this stack is a list of methods // stack for store planList for backtracking Stack <ArrayList> backTrackingPlan = new Stack <ArrayList>(); Stack <HTN_WorldState> states = new Stack <HTN_WorldState>(); // store the copy of states for backtracking tasksNodes.Push(rootNode); // put the root node into the task stack // while the stack is not empty while (!(tasksNodes.Count == 0)) { HTN_node taskNode = tasksNodes.Pop(); // if the node is a compound node if (taskNode is HTN_CompoundNode) { ArrayList methods = ((HTN_CompoundNode)taskNode).findSatisfiedMethods(this.currentWorldState); //HTN_MethodNode method = ((HTN_CompoundNode)taskNode).findSatisfiedMethod(this.currentWorldState); HTN_MethodNode method = (HTN_MethodNode)methods[0]; methods.RemoveAt(0); if (method != null) { // store the plan and the next method node for backtracking when needed backTrackingPlan.Push(new ArrayList(finalPlanList)); // clone the current plan list backTrackingMethods.Push(methods); states.Push(state.clone()); // push the subtasks of this method into the list (push backward since we want the first subtask to be pop next) for (int i = method.getChildren().Count - 1; i >= 0; i--) { tasksNodes.Push((HTN_node)method.getChildren()[i]); } } else { // restore to the saved backtracking state state = states.Pop(); finalPlanList = backTrackingPlan.Pop(); tasksNodes.Clear(); // empty the tasksNode stack // pop a methods list ArrayList btMethods = backTrackingMethods.Pop(); while (btMethods.Count == 0) { btMethods = backTrackingMethods.Pop(); } // get the first method in that list HTN_MethodNode btMethodNode = (HTN_MethodNode)btMethods[0]; btMethods.RemoveAt(0); // delete that method from the list if (btMethods.Count > 0) { backTrackingMethods.Push(btMethods); // put the method list back } // push the subtasks of this method into the list (push backward since we want the first subtask to be pop next) for (int i = btMethodNode.getChildren().Count - 1; i >= 0; i--) { tasksNodes.Push((HTN_node)btMethodNode.getChildren()[i]); } } } else // primative node { // if the precondition is met if (((HTN_PrimitiveNode)taskNode).verifyPrecondition(state)) { // apply the effect of this task on the world state ((HTN_PrimitiveNode)taskNode).applyTask(state); finalPlanList.Add(taskNode); // add this taskNode to the plan list // if this primitive task is the last in the stack, our planning is finish if (tasksNodes.Count == 0) { break; } } else { // restore to the saved backtracking state state = states.Pop(); finalPlanList = backTrackingPlan.Pop(); tasksNodes.Clear(); // empty the tasksNode stack // pop a methods list ArrayList btMethods = backTrackingMethods.Pop(); while (btMethods.Count == 0) { btMethods = backTrackingMethods.Pop(); } // get the first method in that list HTN_MethodNode btMethodNode = (HTN_MethodNode)btMethods[0]; btMethods.RemoveAt(0); // delete that method from the list if (btMethods.Count > 0) { backTrackingMethods.Push(btMethods); // put the method list back } // push the subtasks of this method into the list (push backward since we want the first subtask to be pop next) for (int i = btMethodNode.getChildren().Count - 1; i >= 0; i--) { tasksNodes.Push((HTN_node)btMethodNode.getChildren()[i]); } } } } this.plan = finalPlanList; // set the current plan to the final plan list }