Пример #1
0
        private static List <Loc>[] FindMultiPaths(Loc rectStart, Loc rectSize, Loc start, Loc[] ends, LocTest checkBlock, LocTest checkDiagBlock, EvalPaths eval, EvalFallback fallback)
        {
            if (ends.Length == 0)
            {
                return(new List <Loc> [0]);
            }

            PathTile[][] tiles = new PathTile[rectSize.X][];
            for (int ii = 0; ii < rectSize.X; ii++)
            {
                tiles[ii] = new PathTile[rectSize.Y];
                for (int jj = 0; jj < rectSize.Y; jj++)
                {
                    tiles[ii][jj] = new PathTile(new Loc(rectStart.X + ii, rectStart.Y + jj));
                }
            }

            Loc offset_start = start - rectStart;

            StablePriorityQueue <double, PathTile> candidates = new StablePriorityQueue <double, PathTile>();
            PathTile start_tile = tiles[offset_start.X][offset_start.Y];

            start_tile.UpdateHeuristics(ends);
            start_tile.Cost = 0;
            candidates.Enqueue(start_tile.MinHeuristic + start_tile.Cost, start_tile);

            List <Loc>[] resultPaths = new List <Loc> [ends.Length];

            PathTile[] farthestTiles = new PathTile[ends.Length];
            for (int ii = 0; ii < farthestTiles.Length; ii++)
            {
                farthestTiles[ii] = start_tile;
            }

            while (candidates.Count > 0)
            {
                PathTile currentTile = candidates.Dequeue();

                if (eval(ends, resultPaths, farthestTiles, currentTile))
                {
                    return(resultPaths);
                }

                currentTile.Traversed = true;

                foreach (Dir8 dir in DirExt.VALID_DIR8)
                {
                    Loc newLoc = currentTile.Location - rectStart + dir.GetLoc();
                    if (Collision.InBounds(rectSize.X, rectSize.Y, newLoc))
                    {
                        if (!IsDirBlocked(currentTile.Location, dir, checkBlock, checkDiagBlock))
                        {
                            PathTile tile = tiles[newLoc.X][newLoc.Y];

                            if (tile.Traversed)
                            {
                                continue;
                            }

                            int newCost = currentTile.Cost + 1;
                            if (tile.Cost == -1 || newCost < tile.Cost)
                            {
                                tile.Cost = newCost;
                                tile.UpdateHeuristics(ends);
                                tile.BackReference = currentTile;
                                candidates.AddOrSetPriority(tile.MinHeuristic + tile.Cost, tile);
                            }
                        }
                    }
                }
            }

            fallback(resultPaths, farthestTiles);

            return(resultPaths);
        }
Пример #2
0
        /// <summary>
        /// Searches for the N fastest paths to any of the endpoints.
        /// </summary>
        /// <param name="rectStart"></param>
        /// <param name="rectSize"></param>
        /// <param name="start"></param>
        /// <param name="ends">The list of goal points to path to.  Increase in count increases runtime linearly.</param>
        /// <param name="checkBlock"></param>
        /// <param name="checkDiagBlock"></param>
        /// <param name="amt">Top N</param>
        /// <param name="multiTie">If multiple are tied it returns all involved in the tie.</param>
        public static List <Loc>[] FindNPaths(Loc rectStart, Loc rectSize, Loc start, Loc[] ends, LocTest checkBlock, LocTest checkDiagBlock, int amt, bool multiTie)
        {
            EvalPaths evalPathTied = (Loc[] evalEnds, List <Loc>[] resultPaths, PathTile[] farthestTiles, PathTile currentTile) =>
            {
                int foundResults        = 0;
                int highestBackRefCount = 0;
                for (int ii = 0; ii < resultPaths.Length; ii++)
                {
                    if (resultPaths[ii] != null)
                    {
                        foundResults++;
                        highestBackRefCount = Math.Max(highestBackRefCount, resultPaths[ii].Count);
                    }
                }

                bool addedResult = false;
                for (int ii = 0; ii < evalEnds.Length; ii++)
                {
                    if (currentTile.Location == evalEnds[ii])
                    {
                        List <Loc> proposedBackRef = GetBackreference(currentTile);

                        // in multiTie mode, we are waiting for confirmation that we've found all ties.  This means having found something that fails a tie.
                        if (multiTie && foundResults >= amt)
                        {
                            // if this new proposed backref takes more steps than the current longest, then it is a failed tie
                            if (proposedBackRef.Count > highestBackRefCount)
                            {
                                return(true);
                            }
                        }

                        resultPaths[ii] = proposedBackRef;
                    }

                    if (currentTile.Heuristic[ii] < farthestTiles[ii].Heuristic[ii])
                    {
                        farthestTiles[ii] = currentTile;
                    }
                }

                // if we're just looking for the amount and not paying attention to tiebreakers, we can call it a day when we reach the amount.
                if (!multiTie && addedResult)
                {
                    if (foundResults + 1 >= amt)
                    {
                        return(true);
                    }
                }

                return(false);
            };

            EvalFallback evalFallbackTied = (List <Loc>[] resultPaths, PathTile[] farthestTiles) =>
            {
                int foundResults        = 0;
                int highestBackRefCount = 0;
                StablePriorityQueue <int, int> lowestStepsQueue = new StablePriorityQueue <int, int>();
                List <Loc>[] proposedPaths = new List <Loc> [resultPaths.Length];

                for (int ii = 0; ii < resultPaths.Length; ii++)
                {
                    if (resultPaths[ii] != null)
                    {
                        foundResults++;
                        highestBackRefCount = Math.Max(highestBackRefCount, resultPaths[ii].Count);
                    }
                    else
                    {
                        proposedPaths[ii] = GetBackreference(farthestTiles[ii]);
                        lowestStepsQueue.AddOrSetPriority(proposedPaths[ii].Count, ii);
                    }
                }

                while (lowestStepsQueue.Count > 0)
                {
                    int newIdx = lowestStepsQueue.Dequeue();
                    if (multiTie && foundResults >= amt)
                    {
                        // we've run out of ties.  stop adding paths
                        if (proposedPaths[newIdx].Count > highestBackRefCount)
                        {
                            break;
                        }
                    }

                    resultPaths[newIdx] = proposedPaths[newIdx];
                    highestBackRefCount = proposedPaths[newIdx].Count;
                    foundResults++;

                    if (!multiTie)
                    {
                        if (foundResults >= amt)
                        {
                            break;
                        }
                    }
                }
            };

            return(FindMultiPaths(rectStart, rectSize, start, ends, checkBlock, checkDiagBlock, evalPathTied, evalFallbackTied));
        }