示例#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);
 }
    protected bool processResult(QGameState engineOutput)
    {
        // Process the output result from the LTPEngine
        UnityEngine.Debug.Log("actual EndTime: " + Stopwatch.GetTimestamp());
        UnityEngine.Debug.Log("IG time: " + engineOutput.costToGetHere);

        if (engineOutput == null)
        {
            this.result = new Stack <Work>();
        }

        Stack <Work> result    = new Stack <Work>();
        Work         finalWait = new Work(EWork.Wait, BuildingType.NONE, 10);

        result.Push(finalWait); // TODO: there's some bug that causes the Engine to end one step short :(
        while (engineOutput != null)
        {
            // Note, the finalResult value should be the targetGS. IE: We're looping backwards from
            // finish to start. So last element into the list == the first unit of work that
            // should be done
            if (engineOutput.transitionWork.workType != EWork.Wait)
            {
                result.Push(engineOutput.transitionWork);
            }
            engineOutput = engineOutput.parent;
        }

        this.result   = result;
        this.finished = true;
        return(true);
    }
示例#3
0
 public QGameState(BuildingGS gs, QGameState parent, Work transitionWork, int costToGetHere)
 {
     this.gameState      = gs;
     this.parent         = parent;
     this.transitionWork = transitionWork;
     this.costToGetHere  = costToGetHere;
 }
示例#4
0
    // This function represents an edge
    public static QGameState waitTransition(QGameState qe, int time)
    {
        BuildingGS endGS = waitGameState(qe.gameState, time);

        int  timeCost = qe.costToGetHere + time;
        Work newWork  = new Work(EWork.Wait, BuildingType.NONE, time);

        return(new QGameState(endGS, qe, newWork, timeCost));
    }
示例#5
0
    public static QGameState buyBuilding(QGameState qGS, IBuilding newBuilding)
    {
        BuildingGS newGameState = waitGameState(qGS.gameState, newBuilding.timeToBuild());

        newGameState.buyBuilding(newBuilding);

        int  costToGetHere = qGS.costToGetHere + newBuilding.timeToBuild();
        Work newWork       = new Work(EWork.BuildBuilding, newBuilding.getBuildingType(), newBuilding.timeToBuild());

        return(new QGameState(newGameState, qGS, newWork, costToGetHere));
    }
示例#6
0
    //////////////////////////////////////////////////


    public static QGameState buyWorker(QGameState qGS, BuildingType bt)
    {
        BuildingGS newGameState = waitGameState(qGS.gameState, 1);

        newGameState.buyAndAssignWorker(bt);

        int  costToGetHere = qGS.costToGetHere + 3;
        Work newWork       = new Work(EWork.BuyAndAssignWorker, bt, 3);

        return(new QGameState(newGameState, qGS, newWork, costToGetHere));
    }
 private bool id_processResult(QGameState engineOutput)
 {
     if (engineOutput == null)
     {
         // If no path was found, increase the depth and try again
         ID_LTP(initialGS, targetGS, callback, ID_Queue.NextBount);
     }
     else
     {
         // Otherwise, we have a valid path so process as normal
         base.processResult(engineOutput);
     }
     return(true);
 }
示例#8
0
    public static HashSet <QGameState> getNeighbors(QGameState qEntry)
    {
        // For a given game state return all valid edges out of it

        HashSet <QGameState> result = new HashSet <QGameState>();
        BuildingGS           gs     = qEntry.gameState;

        // Branches related to workers
        if (gs.canBuyWorker())
        {
            // If we have the resources to build a new worker
            foreach (BuildingType bt in gs.getOpenSlots())
            {
                // One branch for every possible type of worker slot we can fill
                QGameState neighbor = QGameStateFactory.buyWorker(qEntry, bt);
                result.Add(neighbor);
            }
        }

        // The length of all the no-op edges we want to consider
        HashSet <int> waitTimes = new HashSet <int>()
        {
            10
        };

        // Branches related to Buildings
        // TODO: Why build a building if we can't populate it with a worker?
        foreach (BuildingType bt in BuildingFactory.allBuildings)
        {
            // One branch for every new possible building
            IBuilding possibleBuilding = BuildingFactory.buildNew(bt, -1, -1); // TODO: do we care about pos when doing A*?
            if (gs.canBuyBuilding(possibleBuilding))
            {
                // If we can build this building, then add a branch
                QGameState neighbor = QGameStateFactory.buyBuilding(qEntry, possibleBuilding);
                result.Add(neighbor);
            }
        }

        // Add in some no-op edges
        foreach (int waitTime in waitTimes)
        {
            result.Add(QGameStateFactory.waitTransition(qEntry, waitTime));
        }

        return(result);
    }
示例#9
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;
    }