private void Swap(int indexOne, int indexTwo) { PlannerState temp = Heap[indexOne]; Heap[indexOne] = Heap[indexTwo]; Heap[indexTwo] = temp; }
private bool CompareGreaterThan(PlannerState left, PlannerState right) { if (left.fCost == right.fCost) { return(left.hCost > right.hCost); } return(left.fCost > right.fCost); }
public PlannerState(S state, PlannerState previousState, A action, int gCost, int hCost) { this.state = state; this.previousState = previousState; this.action = action; this.gCost = gCost; this.hCost = hCost; }
public override bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) { return(false); } PlannerState p = (PlannerState)obj; return(state.Equals(p.state)); }
/// <summary> /// 直前のCompoundTaskの状態まで遡れるように、現在のPlannerStateを記録 /// </summary> private void RecordDecompositionOfTask(CompoundTask nextCompoundTask) { var copyOfPlannerState = new PlannerState( plannerState.WorkingWS.Clone(), new List <TaskBase>(plannerState.FinalPlanList), new List <TaskBase>(plannerState.TaskListToProcess), plannerState.NextMethodNumber); copyOfPlannerState.TaskListToProcess.Add(nextCompoundTask); plannerStateHistory.Add(copyOfPlannerState); }
private List <A> RetraceActions(PlannerState plannerState) { List <A> actionSequence = new List <A>(); while (plannerState.previousState != null) { actionSequence.Add(plannerState.action); plannerState = plannerState.previousState; } actionSequence.Reverse(); return(actionSequence); }
private void RestoreToLastDecomposedTask() { // これ以上過去のPlannerStateに遡れない場合、Planningを終了させる if (plannerStateHistory.Count == 0) { plannerState.TaskListToProcess.Clear(); return; } plannerState = plannerStateHistory.Last(); plannerStateHistory.RemoveAt(plannerStateHistory.Count - 1); }
public PlannerState Pop() { if (Heap.Count == 0) { return(null); } PlannerState state = Heap[0]; Heap[0] = Heap[Heap.Count - 1]; Heap.RemoveAt(Heap.Count - 1); HeapifyDown(); return(state); }
public List <TaskBase> Planning(IWorldState currentState, TaskBase rootTask) { plannerStateHistory.Clear(); plannerState = new PlannerState( currentState.Clone(), new List <TaskBase>(), new List <TaskBase>() { rootTask }, 0); while (plannerState.TaskListToProcess.Count > 0) { var currentTask = plannerState.TaskListToProcess[0]; Debug.Log("CurrentTask:" + currentTask); if (currentTask is CompoundTask currentCompoundTask) { var satisfiedMethod = FindSatisfiedMethod(currentCompoundTask, plannerState); if (satisfiedMethod != null) { RecordDecompositionOfTask(currentCompoundTask); plannerState.TaskListToProcess.RemoveAt(0); plannerState.TaskListToProcess.InsertRange(0, satisfiedMethod.SubTasks); } else { RestoreToLastDecomposedTask(); } } else // PrimitiveTask { if (currentTask.CheckPreCondition(plannerState.WorkingWS)) { plannerState.TaskListToProcess.RemoveAt(0); plannerState.FinalPlanList.Add(currentTask); plannerState.WorkingWS = currentTask.ApplyEffects(plannerState.WorkingWS); } else { RestoreToLastDecomposedTask(); } } } return(new List <TaskBase>(plannerState.FinalPlanList)); }
/// <summary> /// CompoundTaskが保有しているMethodの中から、現在のWorldStateに合致するMethodを返す。 /// なければ、nullを返す。 /// </summary> private Method FindSatisfiedMethod(CompoundTask currentCompoundTask, PlannerState plannerState) { var methodsWorldState = plannerState.WorkingWS.Clone(); var methods = currentCompoundTask.Methods; while (plannerState.NextMethodNumber < methods.Count) { var method = methods[plannerState.NextMethodNumber]; plannerState.NextMethodNumber++; if (method.CheckPreCondition(methodsWorldState)) { return(method); } } return(null); }
void SaveHistory(List <Task> taskQueue, List <PrimitiveTask> plan, List <StateVariable> state) { PlannerState ps; if (plannerStatePool.Count > 0) { ps = plannerStatePool.Pop(); } else { ps = new PlannerState(); } ps.queue.AddRange(taskQueue); ps.plan.AddRange(plan); foreach (var i in state) { ps.state.Add(i.value); } history.Push(ps); }
// TODO: actions should be a set (?) public Plan <T, S, A> GeneratePlan(Goal <S> goal, S state, List <A> actions) { // TODO: Sort actions based on cost PlannerStateHeap openSet = new PlannerStateHeap(); HashSet <S> closedSet = new HashSet <S>(); openSet.Add(new PlannerState(state, null, null, 0, goal.CalculateHCost(state))); while (openSet.Count > 0) { PlannerState currentState = openSet.Pop(); if (closedSet.Contains(currentState.state)) { continue; } closedSet.Add(currentState.state); if (goal.ValidateState(currentState.state)) { return(new Plan <T, S, A>(goal, RetraceActions(currentState))); } for (int i = 0; i < actions.Count; i++) { S newState = actions[i].UpdateState(currentState.state.DeepClone()); if (!closedSet.Contains(newState) && actions[i].ValidateState(currentState.state)) { int newGCost = currentState.gCost + actions[i].GetCost(); int hCost = goal.CalculateHCost(newState); PlannerState newPlannerState = new PlannerState(newState, currentState, actions[i], newGCost, hCost); openSet.Add(newPlannerState); } } } return(null); }
public void dumpPlanToConsole(PlannerState final) { Console.WriteLine("UGLY REVERSE TIME PLAN DUMP"); PlannerState s = final; while (s.parent != null) { if (s.lastRoute == null) { Console.WriteLine("\tEMPTY RUN FROM "+s.parent.sysName+" TO "+s.sysName); } else { Console.WriteLine("\tquantity = " + s.lastQuantityHauled + "; route = " + s.lastRoute.ToString()); } s = s.parent; } }
public void nicelyDumpPlanToConsole(PlannerState final) { Console.WriteLine("TRADE PLAN"); //reverse the ordering List<PlannerState> states = new List<PlannerState>(); PlannerState s = final; while (s.parent != null) { states.Insert(0, s); s = s.parent; } //print them nicely for (int i = 0; i < states.Count; ++i) { PlannerState si = states[i]; string header = "[" + (i + 1) + "] " + si.parent.sysName + " --- "; string footer = " --> " + si.sysName + " ~ "; if (si.lastRoute == null) { Console.WriteLine(header + "empty" + footer+"1 jump;"); } else { Console.WriteLine(header + si.lastQuantityHauled + " x " + si.lastRoute.seller.item.name + footer+si.lastRoute.jumps+" jump(s);"); Console.WriteLine("\t SELL ORDER = " + si.lastRoute.seller); Console.WriteLine("\t BUY ORDER = " + si.lastRoute.buyer); } Console.WriteLine("\tWallet = "+si.wallet); } }
//used to construct an initial state public PlannerState(double cargoCapacity, double wallet, string sysName) { this.cargoCapacity = cargoCapacity; this.wallet = wallet; this.sysName = sysName; this.parent = null; this.lastRoute = null; this.lastQuantityHauled = 0; }
//used to advance to a new state via a trade route public PlannerState(PlannerState previous, TradeRouteMiner.Route routeToTake, int quantityToHaul) { this.cargoCapacity = previous.cargoCapacity; this.wallet = previous.wallet + routeToTake.profitPerItem * quantityToHaul; this.jumpsElapsed = previous.jumpsElapsed + jumpElapsedCost(routeToTake.jumps); this.sysName = routeToTake.buyer.location.name; this.parent = previous; this.lastRoute = routeToTake; this.lastQuantityHauled = quantityToHaul; }
//used to advance to a new state via an empty jump public PlannerState(PlannerState previous, string destination) { this.cargoCapacity = previous.cargoCapacity; this.wallet = previous.wallet; this.jumpsElapsed = previous.jumpsElapsed + 1.0; this.sysName = destination; this.parent = previous; this.lastRoute = null; this.lastQuantityHauled = 0; }
public PlannerState computePlan(double initialWallet, double initialCargoCap, string initialSystemName, int maxJumps) { //reset lists this.open = new PriorityQueue<double, PlannerState>(); this.closed = new SpaceTimeProfitCache(); //compute a heuristic for the max possible profit rate double bestProfitRate = 0.0; double candidateProfitRate = 0.0; foreach(List<TradeRouteMiner.Route> lr in trm.systemRoutes.Values) { foreach (TradeRouteMiner.Route r in lr) { candidateProfitRate = Math.Min(r.profitDensityRate * initialCargoCap, r.bulkProfitRate); bestProfitRate = Math.Max(bestProfitRate, candidateProfitRate); } } //hence we can order PlannerStates by state.wallet + bestProfitRate*(maxJumps-state.jumpsElapsed) //and use a* Console.WriteLine("best profit rate heuristic : " + bestProfitRate); //establish the initial state PlannerState initialState = new PlannerState(initialCargoCap, initialWallet, initialSystemName); open.push(getPriority(initialState, bestProfitRate, maxJumps), initialState); //stat tracking int statTouchedStates = 0; int statAddedStates = 0; int progressUpdateFrequency = 10000; //use a* to find the optimal plan up to max specified number of jumps while (open.count() > 0) { PriorityQueue<double, PlannerState>.Pair pair = open.pop(); ++statTouchedStates; //Console.WriteLine("!tradeplanner : open count = " + open.count() // + "; jumpsElapsed = " + pair.value.jumpsElapsed // + "; priority = "+pair.key); if (statTouchedStates % progressUpdateFrequency == 0) { //display search progress update for user Console.WriteLine("TradePlanner Stats : WORKING"); Console.WriteLine("\ttouched states = " + statTouchedStates); Console.WriteLine("\tadded states = " + statAddedStates); Console.WriteLine("\tstates in open list = " + open.count()); Console.WriteLine("\thighest priority = " + pair.key); Console.WriteLine("\trecent jumps elapsed = " + pair.value.jumpsElapsed); } //check for stopping condition if (pair.value.jumpsElapsed >= maxJumps) { Console.WriteLine("TradePlanner Stats : FINISHED!"); Console.WriteLine("\ttouched states = " + statTouchedStates); Console.WriteLine("\tadded states = " + statAddedStates); Console.WriteLine("\tstates in open list = " + open.count()); Console.WriteLine("\thighest priority = " + pair.key); Console.WriteLine("\trecent jumps elapsed = " + pair.value.jumpsElapsed); return pair.value; } //otherwise, expand planner state and pop children back into the open list foreach (PlannerState childState in pair.value.expandStates(trm, graph)) { //only add the child state if it gives us an improved profit upon what we've already seen if(closed.achievesBetterProfit(childState.sysName, childState.jumpsElapsed, childState.wallet)) { open.push(getPriority(childState,bestProfitRate, maxJumps), childState); ++statAddedStates; } } } //we've failed, for some reason, to find a plan return null; }
public void plan(GameController.WorldState currentWorldState) { finalPlan = new Stack <PrimitiveTask>(); Stack <PlannerState> decompHistory = new Stack <PlannerState>(); GameController.WorldState WorkingWS = currentWorldState.Copy(); tasksToProcess.Push(new PlayGame()); while (tasksToProcess.Count > 0) { Task CurrentTask = tasksToProcess.Pop(); if (CurrentTask.GetType().IsSubclassOf(typeof(CompoundTask))) { CompoundTask CurrentCompoundTask = (CompoundTask)CurrentTask; Method SatisfiedMethod = CurrentCompoundTask.FindSatisfiedMethod(WorkingWS); if (SatisfiedMethod != null) { //PlannerState currentState = new PlannerState(CurrentCompoundTask, finalPlan, tasksToProcess, SatisfiedMethod); // decompHistory.Push(currentState); SatisfiedMethod.subTasks.Reverse(); foreach (Task t in SatisfiedMethod.subTasks) { tasksToProcess.Push(t); } SatisfiedMethod.subTasks.Reverse(); } else if (decompHistory.Count > 0) { //RestoreToLastDecomposedTask(): PlannerState lastState = decompHistory.Pop(); CompoundTask lastCompoundTask = lastState.currentTask; finalPlan = lastState.finalPlan; tasksToProcess = lastState.tasksToProcess; // Remove the failed method and return CompoundTask to the stack. On the next iteration, it will be checked again for a valid method. lastCompoundTask.InvalidateMethod(lastState.currentMethod); tasksToProcess.Push(lastCompoundTask); } } else//Primitive Task { PrimitiveTask CurrentPrimitiveTask = (PrimitiveTask)CurrentTask; if (CurrentPrimitiveTask.PrimitiveConditionsMet(WorkingWS)) { // CurrentPrimitiveTask.ApplyEffects(this, WorkingWS); // Add this PrimitiveTask to the bottom of the finalPlan Stack <PrimitiveTask> temp = new Stack <PrimitiveTask>(); for (int i = 0; i < finalPlan.Count; i++) { PrimitiveTask nextTask = finalPlan.Pop(); temp.Push(nextTask); } temp.Push(CurrentPrimitiveTask); finalPlan = new Stack <PrimitiveTask>(); for (int i = 0; i < temp.Count; i++) { PrimitiveTask nextTask = temp.Pop(); finalPlan.Push(nextTask); } } else if (decompHistory.Count > 0) { //RestoreToLastDecomposedTask(); PlannerState lastState = decompHistory.Pop(); CompoundTask lastCompoundTask = lastState.currentTask; finalPlan = lastState.finalPlan; tasksToProcess = lastState.tasksToProcess; // Remove the failed method and return CompoundTask to the stack. On the next iteration, it will be checked again for a valid method. lastCompoundTask.InvalidateMethod(lastState.currentMethod); tasksToProcess.Push(lastCompoundTask); } } } }
public void Add(PlannerState state) { Heap.Add(state); HeapifyUp(); }
public double getPriority(PlannerState state, double bestProfitRate, int maxJumps) { //note here we're implicitly heavily penalising plans that go over max jumps return state.wallet + bestProfitRate * (maxJumps - state.jumpsElapsed); }
/// <summary> /// Sets the value of the property /// </summary> /// <param name="state">Current state of the calendar</param> private void SetState(PlannerState state) { _state = state; }