Пример #1
0
 protected static void ApplyGenSteps(T map, StablePriorityQueue <Priority, IGenStep> queue)
 {
     while (queue.Count > 0)
     {
         IGenStep postProc = queue.Dequeue();
         GenContextDebug.StepIn(postProc.ToString());
         postProc.Apply(map);
         GenContextDebug.StepOut();
     }
 }
Пример #2
0
        public static IEnumerable <Loc> FindClosestConnectedTiles(Loc rectStart, Loc rectSize, LocTest checkFree, LocTest checkBlock, LocTest checkDiagBlock, Loc loc, int amount)
        {
            if (checkFree == null)
            {
                throw new ArgumentNullException(nameof(checkFree));
            }

            // create an array to cache which tiles were already traversed
            bool[][] fillArray = new bool[rectSize.X][];
            for (int ii = 0; ii < rectSize.X; ii++)
            {
                fillArray[ii] = new bool[rectSize.Y];
            }

            // use typical fill method
            StablePriorityQueue <int, Loc> locList = new StablePriorityQueue <int, Loc>();
            Loc offset_loc = loc - rectStart;

            locList.Enqueue(0, offset_loc);
            fillArray[offset_loc.X][offset_loc.Y] = true;
            int found = 0;

            while (locList.Count > 0)
            {
                Loc candidate = locList.Dequeue();

                if (checkFree(candidate + rectStart))
                {
                    yield return(candidate + rectStart);

                    found++;
                    if (found >= amount)
                    {
                        yield break;
                    }
                }

                foreach (Dir8 dir in DirExt.VALID_DIR8)
                {
                    Loc movedLoc = candidate + dir.GetLoc();
                    if (Collision.InBounds(rectSize.X, rectSize.Y, movedLoc) && !fillArray[movedLoc.X][movedLoc.Y] && !IsDirBlocked(candidate + rectStart, dir, checkBlock, checkDiagBlock))
                    {
                        Loc diff = movedLoc - offset_loc;
                        locList.Enqueue(diff.DistSquared(), movedLoc);
                        fillArray[movedLoc.X][movedLoc.Y] = true;
                    }
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Gets the N largest rectangles in the grid that are not a subset of a larger rectangle.  Modifies the grid in-place.
        /// </summary>
        /// <param name="grid">2D array of 0's and 1's</param>
        /// <param name="amount">Max number of rectangles to return.</param>
        /// <returns></returns>
        public static List <Rect> DetectNLargestRects(bool[][] grid, int amount)
        {
            StablePriorityQueue <int, Rect> queue = new StablePriorityQueue <int, Rect>();

            foreach (Rect rect in FindAllRects(grid))
            {
                queue.Enqueue(-rect.Width * rect.Height, rect);
            }

            List <Rect> results = new List <Rect>();

            while (results.Count < amount && queue.Count > 0)
            {
                results.Add(queue.Dequeue());
            }
            return(results);
        }
Пример #4
0
        public static List <Loc> FindAPath(Loc rectStart, Loc rectSize, Loc start, Loc[] ends, LocTest checkBlock, LocTest checkDiagBlock)
        {
            // searches for one specific path (ends[0]), but doesn't mind hitting the other ones
            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.Heuristic = Math.Sqrt((ends[0] - start).DistSquared());
            start_tile.Cost      = 0;
            candidates.Enqueue(start_tile.Heuristic + start_tile.Cost, start_tile);

            PathTile farthest_tile = start_tile;

            while (candidates.Count > 0)
            {
                PathTile currentTile = candidates.Dequeue();
                for (int ii = 0; ii < ends.Length; ii++)
                {
                    if (currentTile.Location == ends[ii])
                    {
                        return(GetBackreference(currentTile));
                    }
                }

                if (currentTile.Heuristic < farthest_tile.Heuristic)
                {
                    farthest_tile = currentTile;
                }

                currentTile.Traversed = true;

                foreach (Dir8 dir in DirExt.VALID_DIR8)
                {
                    if (!IsDirBlocked(currentTile.Location, dir, checkBlock, checkDiagBlock))
                    {
                        Loc newLoc = currentTile.Location - rectStart + dir.GetLoc();
                        if (Collision.InBounds(rectSize.X, rectSize.Y, newLoc))
                        {
                            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.Heuristic     = Math.Sqrt((ends[0] - tile.Location).DistSquared());
                                tile.BackReference = currentTile;
                                candidates.AddOrSetPriority(tile.Heuristic + tile.Cost, tile);
                            }
                        }
                    }
                }
            }

            return(GetBackreference(farthest_tile));
        }
Пример #5
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);
        }
Пример #6
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));
        }