Esempio n. 1
0
    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;
    }
Esempio n. 2
0
    public int CompareTo(object obj)
    {
        QPriority other = obj as QPriority;

        if (other == null)
        {
            return(-1);
        }                                 // this thing is smaller than a non QPriority obj

        /**
         * -- Most important reasons --
         * fewer infinities should win
         * access to more resources should win
         * shorter remaining distance should win
         * faster velocity should win
         * less resources spent should win
         * -- least important reasons --
         *
         */

        if (this.numberOfInfinities != other.numberOfInfinities)
        {
            return(this.numberOfInfinities - other.numberOfInfinities);
        }
        if (this.unaquirableResourceCount != other.unaquirableResourceCount)
        {
            return(this.unaquirableResourceCount - other.unaquirableResourceCount);
        }

        if (this.totalCPTDelta != other.totalCPTDelta)
        {
            return(this.totalCPTDelta - other.totalCPTDelta);
        }
        // Figure out which one has less "hidden" pre-recs that are unsatisfied

        if (this.estTotalDist != other.estTotalDist)
        {
            return(this.estTotalDist - other.estTotalDist);
        }

        // When nothing seems to be different, a assigning a worker operation always wins
        if (this.assignWorker != other.assignWorker)
        {
            if (this.assignWorker)
            {
                return(-1);
            }
            else
            {
                return(1);
            }
        }

        if (this.bestMaxWaitTime != other.bestMaxWaitTime)
        {
            return(this.bestMaxWaitTime - other.bestMaxWaitTime);
        }

        if (reccomendedPreRecDelta != other.reccomendedPreRecDelta)
        {
            return(reccomendedPreRecDelta - other.reccomendedPreRecDelta);
        }

        if (this.bestCPTDelta != other.bestCPTDelta)
        {
            return(this.bestCPTDelta - other.bestCPTDelta);
        }

        int myTotalBuildingCount    = this.currentNode.gameState.totalBuildingCount();
        int otherTotalBuildingCount = other.currentNode.gameState.totalBuildingCount();

        if (myTotalBuildingCount != otherTotalBuildingCount)
        {
            return(myTotalBuildingCount - otherTotalBuildingCount);
        }

        // When nothing seems to be different, a wait operation always wins
        if (this.wait != other.wait)
        {
            if (this.wait)
            {
                return(-1);
            }
            else
            {
                return(1);
            }
        }

        // All things equal go for the cheaper option
        return(this.totalResourcesSpent - other.totalResourcesSpent);

        /*
         * Examples:
         * 10 vs 7
         * 10 - 7  =  3  => 2nd entry goes first
         *
         * 7  vs 10
         * 7  - 10 = -3  => 1st entry goes first
         */
    }