/// <summary> /// Plans through a StoryArc up to level "planningUpTo". The returned StoryArc keeps all the previous Events in it and is globally consistent. If that's not possible, an Error is thrown. /// </summary> public StoryArc planGlobalUpTo(int planningUpTo, StoryArc arc, IEnumerable<SmartObject> reducedObjectSpace, PlanSpace option, ref bool success) { Debug.Log ("Start Planning Global"); StoryArc newArc = new StoryArc (arc); //Stacks are used to save: The arcs we planned, from where we started, Beatlevel we plan to. So we can go back if something went wrong Stack<StoryArc> arcStack = new Stack<StoryArc> (); Stack<int> fromStack = new Stack<int> (); Stack<int> ToStack = new Stack<int> (); Stack<List<EventID>> IdListStack = new Stack<List<EventID>>(); Stack<List<BeatPopulation>> BeatPopulationSetStack = new Stack<List<BeatPopulation>> (); Stack<int> xthTryStack = new Stack<int> (); List<StoryBeat> newBeats = new List<StoryBeat>(); List<Transition> upgoing = new List<Transition> (); Transition cur; int maxFails = (planningUpTo * (planningUpTo - 1)) / 2; int maxTrys = 1; int nrFails = 0; int curPlanningFrom = 0; int curPlanningUpTo = planningUpTo; int curTry = 0; arcStack.Push (newArc); fromStack.Push (curPlanningFrom); ToStack.Push (curPlanningUpTo); xthTryStack.Push (curTry); domains.Add (new EventDomain (stateSpaceManager)); EventDomain domain = (EventDomain)domains [0]; if(PlanSpace.Reduced == option) stateSpaceManager.setListReduced (reducedObjectSpace.ToArray ()); stateSpaceManager.option = option; BeatPopulationSetStack.Push (getBestPopulations(curPlanningFrom, arc, maxTrys)); List<Transition> bestChoice = new List<Transition>(); // while "from" isn't the last Beat yet we continue planning while(ToStack.Peek() != fromStack.Peek()) { arc = arcStack.Peek(); curPlanningFrom = fromStack.Peek(); curPlanningUpTo = ToStack.Peek (); //-------------------------------- //PLANNING WITH PARAMETERFILLING curTry = xthTryStack.Peek(); StoryBeat BeatWithNewPop = BeatPopulationSetStack.Peek().ElementAt(curTry).ToStoryBeat(); StoryBeat[] remainingBeats = arc.Beats; remainingBeats[curPlanningFrom] = BeatWithNewPop; arc = new StoryArc(remainingBeats); //-------------------------------- //Convert the EndEvents from Events to Transitions endEvents = arc.Beats[curPlanningFrom].Events; endTransitions = new Transition[endEvents.Length]; for (int i=0;i<endEvents.Length;i++) endTransitions[i] = new Transition(endEvents[i]); if(curTry==0) bestChoice = endTransitions.ToList(); //Adding the relevant states of the end-Transitions, so heuristic only depending on these states can be used to compute plan domain.relevanceMasks = stateSpaceManager.createRelevanceMasks(endTransitions); planner.init (ref domains, MAXNODES); stateSpaceManager.resetGlobalState (); SimulateUpTo (stateSpaceManager, curPlanningFrom, arc); //Set start state to the state after the Beat we are planning from DefaultState startState = new DefaultState (stateSpaceManager.globalState); //end state is set to the state after the startEvents and the necessary preconditions changed DefaultState endState = new DefaultState (startState); List<RelevanceMask> relev = domain.relevanceMasks.ToList(); //end state is changed according to the upgoing conditions for global consistency foreach(Transition t in upgoing) { endState = stateSpaceManager.getGlobalStateBeforeEvent(endState,t); foreach(RelevanceMask mask in stateSpaceManager.createRelevanceMasks(t)) relev.Add(mask); } domain.relevanceMasks = relev.ToArray(); //conditions from upgoing are overwritten if they conflict with preconditions for current beat foreach(Transition t in endTransitions) { endState = stateSpaceManager.getGlobalStateBeforeEvent(endState,t); } stateSpaceManager.endTransitions = endTransitions.ToList(); foreach(Transition t in upgoing) { stateSpaceManager.endTransitions.Add(t); } plan.Clear(); success = planner.computePlan (ref startState, ref endState, ref plan, TIMEOUT); //--------------------------------------------------------------- if (success) { plan.Pop (); //pop start event upgoing.Clear(); int oldNrBeats = arc.Beats.Count(); int newNrEvents = plan.Count; //add Beats up to the starting level of planning for(int i=0; i<curPlanningFrom; i++) { newBeats.Add(arc.Beats[i]); } //add planned beats List<EventID> IdList = new List<EventID>(); while(plan.Count>0) { cur = ((Transition)plan.Pop()); newBeats.Add(new StoryBeat(cur.ToStoryEvent())); IdList.Add(newBeats.Last().Events.First().ID); } //add Beats after the planning for(int i=curPlanningFrom; i<oldNrBeats; i++) { newBeats.Add(arc.Beats[i]); } newArc = new StoryArc(newBeats.ToArray()); IdListStack.Push(IdList); arcStack.Push(newArc); fromStack.Push(curPlanningFrom + 1 + newNrEvents); ToStack.Push (curPlanningUpTo + newNrEvents); if(fromStack.Peek() != ToStack.Peek()) BeatPopulationSetStack.Push (getBestPopulations(fromStack.Peek(), newArc, maxTrys)); xthTryStack.Push(0); newBeats.Clear(); upgoing.Clear(); } else { if(curTry + 1>=maxTrys || curTry >= BeatPopulationSetStack.Peek().Count-1) { nrFails++; //Propagate the Transitions we need to consider upwards if planning fails if (upgoing.Count == 0) foreach(Transition t in bestChoice) upgoing.Add (t); if(fromStack.Peek() > 0) { IdListStack.Pop (); fromStack.Pop (); arcStack.Pop(); ToStack.Pop (); BeatPopulationSetStack.Pop(); xthTryStack.Pop(); } if(fromStack.Peek()==0 || nrFails>maxFails) { return arc; } } else { int temp = xthTryStack.Peek(); temp++; xthTryStack.Pop(); xthTryStack.Push (temp); } } } List<EventID> IDsFromOneLevel; while(IdListStack.Count > 0) { IDsFromOneLevel = IdListStack.Pop (); foreach(EventID i in IDsFromOneLevel) IDs.Add(i); } return arcStack.Peek(); }
/// <summary> /// Plans through a whole StoryArc. The returned StoryArc keeps all the previous Events in it and is globally consistent. If that's not possible, an Error is thrown. /// </summary> public StoryArc planGlobal(StoryArc arc, IEnumerable<SmartObject> reducedObjectSpace, PlanSpace option, ref bool success) { return planGlobalUpTo (arc.Beats.Count (), arc, reducedObjectSpace, option, ref success); }