private int findDist(UniverseGraph.SystemId source, UniverseGraph.SystemId dest) { open = new PriorityQueue<int, Node>(); closed = new HashSet<UniverseGraph.SystemId>(); open.push(0, new Node(null, source)); Node current = null; int currentPriority = 0; while ((open.count() > 0) && (closed.Count < maxClosedSize)) { //pop top PriorityQueue<int, Node>.Pair head = open.pop(); current = head.value; currentPriority = head.key; //check if we've reached the destination if (current.sysid.id == dest.id) return currentPriority*-1; if (!closed.Contains(current.sysid)) { //mark that we've already expanded it closed.Add(current.sysid); //expand it foreach (UniverseGraph.SystemId neighbour in graph.systemEdges[current.sysid]) { if (graph.idToInfo[neighbour].security > minSecurity) { Node nNode = new Node(current, neighbour); //decrease priority by number of jumps so far - ie breadth first search //some a* like heuristic would be nice.... int nPriority = currentPriority - 1; open.push(nPriority, nNode); } } } } //some kind of failure state - either no path, or seach size exceeded (too far) return -1; }
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; }