public static void Generate(ISettableMapView <bool> map, int crawlerChangeDirectionImprovement, int saveDeadEndChance)
        {
            // Implemented the logic from http://journal.stuffwithstuff.com/2014/12/21/rooms-and-mazes/

            var crawlers = new List <Crawler>();

            var empty         = FindEmptySquare(map);
            var randomCounter = 0;
            var randomSuccess = false;

            while (empty != null)
            {
                Crawler crawler = new Crawler();
                crawlers.Add(crawler);
                crawler.MoveTo(empty);
                var startedCrawler         = true;
                var percentChangeDirection = 0;
                //Color randomCrawlerColor = Color.AliceBlue.GetRandomColor(SadConsole.Global.Random);

                while (crawler.Path.Count != 0)
                {
                    // Dig this position
                    map[crawler.CurrentPosition] = true;
                    //map[crawler.CurrentPosition.X, crawler.CurrentPosition.Y].Background = randomCrawlerColor;

                    // Get valid directions (basically is any position outside the map or not?)
                    var points     = AdjacencyRule.CARDINALS.NeighborsClockwise(crawler.CurrentPosition).ToArray();
                    var directions = AdjacencyRule.CARDINALS.DirectionsOfNeighborsClockwise(Direction.NONE).ToList();
                    var valids     = new bool[4];


                    // Rule out any valids based on their position.
                    // Only process NSEW, do not use diagonals
                    for (var i = 0; i < 4; i++)
                    {
                        valids[i] = IsPointWallsExceptSource(map, points[i], directions[i] + 4);
                    }

                    // If not a new crawler, exclude where we came from
                    if (!startedCrawler)
                    {
                        valids[directions.IndexOf(crawler.Facing + 4)] = false;
                    }

                    // Do we have any valid direction to go?
                    if (valids[0] || valids[1] || valids[2] || valids[3])
                    {
                        var index = 0;

                        // Are we just starting this crawler? OR Is the current crawler facing direction invalid?
                        if (startedCrawler || valids[directions.IndexOf(crawler.Facing)] == false)
                        {
                            // Just get anything
                            index                  = GetDirectionIndex(valids);
                            crawler.Facing         = directions[index];
                            percentChangeDirection = 0;
                            startedCrawler         = false;
                        }
                        else
                        {
                            // Increase probablity we change direction
                            percentChangeDirection += crawlerChangeDirectionImprovement;

                            if (PercentageCheck(percentChangeDirection))
                            {
                                index                  = GetDirectionIndex(valids);
                                crawler.Facing         = directions[index];
                                percentChangeDirection = 0;
                            }
                            else
                            {
                                index = directions.IndexOf(crawler.Facing);
                            }
                        }

                        crawler.MoveTo(points[index]);
                    }
                    else
                    {
                        crawler.Backtrack();
                    }
                }

                empty = FindEmptySquare(map);
            }

            TrimDeadPaths(map, crawlers, saveDeadEndChance);
        }
Beispiel #2
0
        /// <inheritdoc />
        protected override IEnumerator <object?> OnPerform(GenerationContext context)
        {
            // Validate configuration
            if (CrawlerChangeDirectionImprovement > 100)
            {
                throw new InvalidConfigurationException(this, nameof(CrawlerChangeDirectionImprovement),
                                                        "The value must be a valid percent (between 0 and 100).");
            }

            // Logic implemented from http://journal.stuffwithstuff.com/2014/12/21/rooms-and-mazes/

            // Get or create/add a wall-floor context component
            var wallFloorContext = context.GetFirstOrNew <ISettableGridView <bool> >(
                () => new ArrayView <bool>(context.Width, context.Height),
                WallFloorComponentTag
                );

            // Get or create/add a tunnel list context component
            var tunnelList = context.GetFirstOrNew(
                () => new ItemList <Area>(),
                TunnelsComponentTag
                );

            // Record spaces we've crawled to introduce changes.
            int spacesCrawled = 0;


            var crawlers = new List <Crawler>();
            var empty    = FindEmptySquare(wallFloorContext, RNG);

            while (empty != Point.None)
            {
                var crawler = new Crawler();
                crawlers.Add(crawler);
                crawler.MoveTo(empty);
                var    startedCrawler         = true;
                ushort percentChangeDirection = 0;

                while (crawler.Path.Count != 0)
                {
                    // Dig this position
                    wallFloorContext[crawler.CurrentPosition] = true;

                    // Get valid directions (basically is any position outside the map or not?
                    var points     = AdjacencyRule.Cardinals.NeighborsClockwise(crawler.CurrentPosition).ToArray();
                    var directions = AdjacencyRule.Cardinals.DirectionsOfNeighborsClockwise(Direction.None).ToList();

                    var validDirections = new bool[4];

                    // Rule out any valid directions based on their position. Only process cardinals, do not use diagonals
                    for (var i = 0; i < 4; i++)
                    {
                        validDirections[i] = IsPointWallsExceptSource(wallFloorContext, points[i], directions[i] + 4);
                    }

                    // If not a new crawler, exclude where we came from
                    if (!startedCrawler)
                    {
                        validDirections[directions.IndexOf(crawler.Facing + 4)] = false;
                    }

                    // Do we have any valid direction to go?
                    if (validDirections[0] || validDirections[1] || validDirections[2] || validDirections[3])
                    {
                        int index;

                        // Are we just starting this crawler? OR Is the current crawler facing
                        // direction invalid?
                        if (startedCrawler || validDirections[directions.IndexOf(crawler.Facing)] == false)
                        {
                            // Just get anything
                            index                  = GetDirectionIndex(validDirections, RNG);
                            crawler.Facing         = directions[index];
                            percentChangeDirection = 0;
                            startedCrawler         = false;
                        }
                        else
                        {
                            // Increase probability we change direction
                            percentChangeDirection += CrawlerChangeDirectionImprovement;

                            if (RNG.PercentageCheck(percentChangeDirection))
                            {
                                index                  = GetDirectionIndex(validDirections, RNG);
                                crawler.Facing         = directions[index];
                                percentChangeDirection = 0;
                            }
                            else
                            {
                                index = directions.IndexOf(crawler.Facing);
                            }
                        }

                        crawler.MoveTo(points[index]);
                        spacesCrawled++;
                    }
                    else
                    {
                        crawler.Backtrack();
                        spacesCrawled++;
                    }

                    if (spacesCrawled >= 10)
                    {
                        yield return(null);

                        spacesCrawled = 0;
                    }
                }

                if (spacesCrawled > 0)
                {
                    yield return(null);

                    spacesCrawled = 0;
                }

                empty = FindEmptySquare(wallFloorContext, RNG);
            }

            // Add appropriate items to the tunnels list
            tunnelList.AddRange(crawlers.Select(c => c.AllPositions).Where(a => a.Count != 0), Name);
        }
Beispiel #3
0
        /// <summary>
        /// Generates a maze in map using crawlers that walk the map carving tunnels.
        /// </summary>
        /// <param name="map">The map to modify.</param>
        /// <param name="rng">The RNG to use.</param>
        /// <param name="crawlerChangeDirectionImprovement">
        /// Out of 100, how much to increase the chance of the crawler changing direction each step.
        /// Once it changes direction, the chance resets to 0 and increases by this amount. Defaults
        /// to 10.
        /// </param>
        /// <returns>A list of mazes that were generated.</returns>
        public static IEnumerable <MapArea> Generate(ISettableMapView <bool> map, IGenerator rng, int crawlerChangeDirectionImprovement = 10)
        {
            // Implemented the logic from http://journal.stuffwithstuff.com/2014/12/21/rooms-and-mazes/

            if (rng == null)
            {
                rng = SingletonRandom.DefaultRNG;
            }

            var crawlers = new List <Crawler>();

            var empty = FindEmptySquare(map, rng);

            while (empty != Coord.NONE)
            {
                Crawler crawler = new Crawler();
                crawlers.Add(crawler);
                crawler.MoveTo(empty);
                var startedCrawler         = true;
                var percentChangeDirection = 0;

                while (crawler.Path.Count != 0)
                {
                    // Dig this position
                    map[crawler.CurrentPosition] = true;

                    // Get valid directions (basically is any position outside the map or not?)
                    var points     = AdjacencyRule.CARDINALS.NeighborsClockwise(crawler.CurrentPosition).ToArray();
                    var directions = AdjacencyRule.CARDINALS.DirectionsOfNeighborsClockwise(Direction.NONE).ToList();
                    var valids     = new bool[4];

                    // Rule out any valids based on their position. Only process NSEW, do not use diagonals
                    for (var i = 0; i < 4; i++)
                    {
                        valids[i] = IsPointWallsExceptSource(map, points[i], directions[i] + 4);
                    }

                    // If not a new crawler, exclude where we came from
                    if (!startedCrawler)
                    {
                        valids[directions.IndexOf(crawler.Facing + 4)] = false;
                    }

                    // Do we have any valid direction to go?
                    if (valids[0] || valids[1] || valids[2] || valids[3])
                    {
                        var index = 0;

                        // Are we just starting this crawler? OR Is the current crawler facing
                        // direction invalid?
                        if (startedCrawler || valids[directions.IndexOf(crawler.Facing)] == false)
                        {
                            // Just get anything
                            index                  = GetDirectionIndex(valids, rng);
                            crawler.Facing         = directions[index];
                            percentChangeDirection = 0;
                            startedCrawler         = false;
                        }
                        else
                        {
                            // Increase probablity we change direction
                            percentChangeDirection += crawlerChangeDirectionImprovement;

                            if (PercentageCheck(percentChangeDirection, rng))
                            {
                                index                  = GetDirectionIndex(valids, rng);
                                crawler.Facing         = directions[index];
                                percentChangeDirection = 0;
                            }
                            else
                            {
                                index = directions.IndexOf(crawler.Facing);
                            }
                        }

                        crawler.MoveTo(points[index]);
                    }
                    else
                    {
                        crawler.Backtrack();
                    }
                }

                empty = FindEmptySquare(map, rng);
            }

            return(crawlers.Select(c => c.AllPositions).Where(a => a.Count != 0));
        }