Пример #1
0
        public static void AffectConnectedTiles(Loc rectStart, Loc rectSize, LocAction action, LocTest checkBlock, LocTest checkDiagBlock, Loc loc)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }
            if (checkBlock == null)
            {
                throw new ArgumentNullException(nameof(checkBlock));
            }
            if (checkDiagBlock == null)
            {
                throw new ArgumentNullException(nameof(checkDiagBlock));
            }

            // 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];
            }

            FloodFill(
                new Rect(rectStart, rectSize),
                (Loc testLoc) => (checkBlock(testLoc) || fillArray[testLoc.X - rectStart.X][testLoc.Y - rectStart.Y]),
                (Loc testLoc) => (checkDiagBlock(testLoc) || fillArray[testLoc.X - rectStart.X][testLoc.Y - rectStart.Y]),
                (Loc actLoc) =>
            {
                action(actLoc);
                fillArray[actLoc.X - rectStart.X][actLoc.Y - rectStart.Y] = true;
            },
                loc);
        }
Пример #2
0
        public static Loc ResizeJustified <T>(ref T[][] array, int width, int height, Dir8 dir, LocAction newLocOp, LocAction newTileOp)
        {
            if (newLocOp == null)
            {
                throw new ArgumentNullException(nameof(newLocOp));
            }
            if (newTileOp == null)
            {
                throw new ArgumentNullException(nameof(newTileOp));
            }

            dir.Separate(out DirH horiz, out DirV vert);

            Loc offset = Loc.Zero;

            if (horiz == DirH.None)
            {
                offset.X = (width - array.Length) / 2;
            }
            else if (horiz == DirH.Left)
            {
                offset.X = width - array.Length;
            }

            if (vert == DirV.None)
            {
                offset.Y = (height - array[0].Length) / 2;
            }
            else if (vert == DirV.Up)
            {
                offset.Y = height - array[0].Length;
            }

            T[][] prevArray = array;
            array = new T[width][];
            for (int ii = 0; ii < width; ii++)
            {
                array[ii] = new T[height];
            }

            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    if (x >= offset.X && x < offset.X + prevArray.Length && y >= offset.Y && y < offset.Y + prevArray[0].Length)
                    {
                        array[x][y] = prevArray[x - offset.X][y - offset.Y];
                        newLocOp(new Loc(x, y));
                    }
                    else
                    {
                        newTileOp(new Loc(x, y));
                    }
                }
            }

            return(offset);
        }
Пример #3
0
        private static void ScanFill(
            Rect rect,
            LocTest checkBlock,
            LocTest checkDiagBlock,
            LocAction fillOp,
            int min,
            int max,
            int range_min,
            int range_max,
            int y,
            bool isNext,
            DirV dir,
            Stack <ScanLineTile> stack)
        {
            if (checkBlock == null)
            {
                throw new ArgumentNullException(nameof(checkBlock));
            }
            if (fillOp == null)
            {
                throw new ArgumentNullException(nameof(fillOp));
            }

            // move y down or up
            int new_y = y + dir.GetLoc().Y;

            // for diagonal checking: check slightly further
            int sub = (range_min > rect.Start.X) ? 1 : 0;
            int add = (range_max < rect.Start.X + rect.Size.X - 1) ? 1 : 0;

            int line_start = -1;
            int x          = range_min - sub;

            for (; x <= range_max + add; x++)
            {
                bool unblocked = !checkBlock(new Loc(x, new_y));

                // check diagonal if applicable
                if (x < range_min)
                {
                    unblocked &= !IsDirBlocked(new Loc(range_min, y), DirExt.Combine(DirH.Left, dir), checkBlock, checkDiagBlock);
                }
                else if (x > range_max)
                {
                    unblocked &= !IsDirBlocked(new Loc(range_max, y), DirExt.Combine(DirH.Right, dir), checkBlock, checkDiagBlock);
                }

                // skip testing, if testing previous line within previous range
                bool empty = (isNext || (x <min || x> max)) && unblocked;

                if (line_start == -1 && empty)
                {
                    line_start = x;
                }
                else if (line_start > -1 && !empty)
                {
                    stack.Push(new ScanLineTile(new IntRange(line_start, x - 1), new_y, dir, line_start <= range_min, x > range_max));
                    line_start = -1;
                }

                if (line_start > -1)
                {
                    fillOp(new Loc(x, new_y));
                }

                if (!isNext && x == min)
                {
                    x = max;
                }
            }

            if (line_start > -1)
            {
                stack.Push(new ScanLineTile(new IntRange(line_start, x - 1), new_y, dir, line_start <= range_min, true));
            }
        }
Пример #4
0
        /// <summary>
        /// Traverses a grid. Does not internally handle the state of traversed/untraversed nodes.
        /// </summary>
        /// <param name="rect"></param>
        /// <param name="checkBlock"></param>
        /// <param name="checkDiagBlock"></param>
        /// <param name="fillOp"></param>
        /// <param name="loc"></param>
        public static void FloodFill(Rect rect, LocTest checkBlock, LocTest checkDiagBlock, LocAction fillOp, Loc loc)
        {
            if (checkBlock == null)
            {
                throw new ArgumentNullException(nameof(checkBlock));
            }
            if (fillOp == null)
            {
                throw new ArgumentNullException(nameof(fillOp));
            }

            Stack <ScanLineTile> stack = new Stack <ScanLineTile>();

            stack.Push(new ScanLineTile(new IntRange(loc.X, loc.X), loc.Y, DirV.None, true, true));
            fillOp(loc);

            while (stack.Count > 0)
            {
                ScanLineTile fillCandidate = stack.Pop();

                int rangeMinX = fillCandidate.X.Min;
                if (fillCandidate.GoLeft)
                {
                    while (rangeMinX > rect.Start.X && !checkBlock(new Loc(rangeMinX - 1, fillCandidate.Y)))
                    {
                        rangeMinX--;
                        fillOp(new Loc(rangeMinX, fillCandidate.Y));
                    }
                }

                int rangeMaxX = fillCandidate.X.Max;
                if (fillCandidate.GoRight)
                {
                    while (rangeMaxX + 1 < rect.Start.X + rect.Size.X && !checkBlock(new Loc(rangeMaxX + 1, fillCandidate.Y)))
                    {
                        rangeMaxX++;
                        fillOp(new Loc(rangeMaxX, fillCandidate.Y));
                    }
                }

                if (fillCandidate.Y < rect.Start.Y + rect.Size.Y - 1)
                {
                    ScanFill(rect, checkBlock, checkDiagBlock, fillOp, fillCandidate.X.Min, fillCandidate.X.Max, rangeMinX, rangeMaxX, fillCandidate.Y, fillCandidate.Dir != DirV.Up, DirV.Down, stack);
                }

                if (fillCandidate.Y > rect.Start.Y)
                {
                    ScanFill(rect, checkBlock, checkDiagBlock, fillOp, fillCandidate.X.Min, fillCandidate.X.Max, rangeMinX, rangeMaxX, fillCandidate.Y, fillCandidate.Dir != DirV.Down, DirV.Up, stack);
                }
            }
        }
Пример #5
0
        /// <summary>
        /// Resizes a 2-D array in a certain direction.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="array"></param>
        /// <param name="width">The new width.</param>
        /// <param name="height">The new height.</param>
        /// <param name="dir">The direction to expand/shrink in.</param>
        /// <param name="newLocOp">The operation to perform on the tile when it is moved.</param>
        /// <param name="newTileOp">The operation to perform on the tile when it is completely new.</param>
        /// <returns></returns>
        public static Loc ResizeJustified <T>(ref T[][] array, int width, int height, Dir8 dir, LocAction newLocOp, LocAction newTileOp)
        {
            if (newLocOp == null)
            {
                throw new ArgumentNullException(nameof(newLocOp));
            }
            if (newTileOp == null)
            {
                throw new ArgumentNullException(nameof(newTileOp));
            }

            Loc offset = GetResizeOffset(array.Length, array[0].Length, width, height, dir);

            T[][] prevArray = array;
            array = new T[width][];
            for (int ii = 0; ii < width; ii++)
            {
                array[ii] = new T[height];
            }

            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    if (x >= offset.X && x < offset.X + prevArray.Length && y >= offset.Y && y < offset.Y + prevArray[0].Length)
                    {
                        array[x][y] = prevArray[x - offset.X][y - offset.Y];
                        newLocOp(new Loc(x, y));
                    }
                    else
                    {
                        newTileOp(new Loc(x, y));
                    }
                }
            }

            return(offset);
        }