Beispiel #1
0
 public QPriority(QGameState node, BuildingGS targetGS, HiddenRequirement hiddenReq)
 {
     this.hiddenReq     = hiddenReq;
     this.currentNode   = node;
     this.targetGS      = targetGS;
     this.distanceRuler = LTPHelper.estematedRemainingDistance(node.gameState, targetGS);
 }
    private static readonly int NODES_CHECKED_PER_YIELD = 150; // Check n nodes every frame


    public static IEnumerator BuildPlan(BuildingGS initialGS,
                                        BuildingGS targetGS,
                                        PriorityQueue <QPriority, QGameState> priorityQueue,
                                        Func <QGameState, bool> finishCallback)
    {
        int nodesChecked = 0;
        // Initialize data structures
        Dictionary <int, int> bestCostToGetHere = new Dictionary <int, int>();
        HiddenRequirement     hiddenReq         = new HiddenRequirement();

        // NOTE: Don't add the initial state to the bestCostToGetHere, that will be done automatically
        Work       initialWork   = new Work(EWork.EMPTY, BuildingType.NONE, 0);
        QGameState firstGS       = new QGameState(initialGS, null, initialWork, 0);
        QPriority  firstPriority = new QPriority(firstGS, targetGS, hiddenReq);

        priorityQueue.Enqueue(firstPriority, firstGS);


        int totalChecks = 0;

        while (priorityQueue.Count > 0)
        {
            nodesChecked++;
            if (nodesChecked >= NODES_CHECKED_PER_YIELD)
            {
                // TODO: There may be an off by 1 error, but not a major problem
                nodesChecked = 0;
                yield return(null);
            }
            totalChecks++;
            KeyValuePair <QPriority, QGameState> kvp = priorityQueue.Dequeue();
            QGameState qe = kvp.Value;

            if (false)
            {
                Debug.Log("===============================================================================================");
                Debug.Log("Cost to get here: " + qe.costToGetHere + " + " + kvp.Key.maxWaitTime);
                Debug.Log("incoming work: " + qe.transitionWork.workType + "  " + qe.transitionWork.buildingType);

                Debug.Log(" +  infinities     : " + kvp.Key.numberOfInfinities);
                Debug.Log(" +  unaquiriable   : " + kvp.Key.unaquirableResourceCount);
                //Debug.Log(" +  estTotalDist   : " + kvp.Key.estTotalDist);
                Debug.Log(" +  BestTotalDist  : " + kvp.Key.bestMaxWaitTime);
                Debug.Log(" +  totalCPTDelta  : " + kvp.Key.totalCPTDelta);
                Debug.Log(" +  preRecDelta    : " + kvp.Key.reccomendedPreRecDelta);
                //Debug.Log(" +  best CPTDelta  : " + heuristic.bestCPTDelta);
                Debug.Log(" +  fudge factor   : " + kvp.Key.totalResourcesSpent);
                Debug.Log("iron  cpt: " + qe.gameState.getChangePerTick(ResourceType.Iron));
                Debug.Log("coal  cpt: " + qe.gameState.getChangePerTick(ResourceType.Coal));
                Debug.Log("Steel cpt: " + qe.gameState.getChangePerTick(ResourceType.Steel));
                Debug.Log("building count: " + qe.gameState.totalBuildingCount());
                Debug.Log("worker count: " + qe.gameState.totalWorkerCount());
            }

            // Early exit conditions
            if (LTPHelper.estematedRemainingDistance(qe.gameState, targetGS).atTarget())
            {
                // If we are 0 distance away from the target game state
                // IE: If we have found the target game state
                finishCallback(qe);
                yield break;
            }
            else if (totalChecks > LTPHelper.MAX_DEPTH)
            {
                finishCallback(null);
                yield break;
            }

            if (bestCostToGetHere.ContainsKey(qe.gameState.GetHashCode()) &&
                bestCostToGetHere[qe.gameState.GetHashCode()] <= qe.costToGetHere)
            {
                // If we've already explored this game state
                // AND if some other path is to this game state is cheeper
                continue;
            }
            else
            {
                // Else, this Queue Entry represents a cheeper path to get to this node
                bestCostToGetHere[qe.gameState.GetHashCode()] = qe.costToGetHere;
            }

            foreach (QGameState neighbor in LTPHelper.getNeighbors(qe))
            {
                // The neighbor already has an updated gamestate, a job and an updated cost

                if (bestCostToGetHere.ContainsKey(neighbor.gameState.GetHashCode()) &&
                    bestCostToGetHere[neighbor.gameState.GetHashCode()] <= neighbor.costToGetHere)
                {
                    // If we already have a better way to get to the neighbor
                    continue;
                }

                QPriority heuristic = new QPriority(neighbor, targetGS, hiddenReq);



                if (false)
                {
                    Debug.Log("********************");
                    Debug.Log("**  Adding neighbor: ");
                    Debug.Log("**  transition work: " + neighbor.transitionWork.workType + "  " + neighbor.transitionWork.buildingType);
                    Debug.Log(" +  infinities     : " + heuristic.numberOfInfinities);
                    Debug.Log(" +  unaquiriable   : " + heuristic.unaquirableResourceCount);
                    //Debug.Log(" +  estTotalDist   : " + kvp.Key.estTotalDist);
                    Debug.Log(" +  BestTotalDist  : " + kvp.Key.bestMaxWaitTime);
                    Debug.Log(" +  totalCPTDelta  : " + heuristic.totalCPTDelta);
                    Debug.Log(" +  preRecDelta    : " + heuristic.reccomendedPreRecDelta);
                    //Debug.Log(" +  best CPTDelta  : " + heuristic.bestCPTDelta);
                    Debug.Log(" +  fudge factor   : " + heuristic.totalResourcesSpent);
                    Debug.Log("iron  cpt: " + neighbor.gameState.getChangePerTick(ResourceType.Iron));
                    Debug.Log("coal  cpt: " + neighbor.gameState.getChangePerTick(ResourceType.Coal));
                    Debug.Log("Steel cpt: " + neighbor.gameState.getChangePerTick(ResourceType.Steel));
                    Debug.Log("building count: " + neighbor.gameState.totalBuildingCount());
                    Debug.Log("worker count: " + neighbor.gameState.totalWorkerCount());
                }


                priorityQueue.Enqueue(heuristic, neighbor);
            } // End foreach neighbor
        }     // End while queue is NOT empty

        finishCallback(null);
        yield break;
    }