Beispiel #1
0
        public void ProcessMap(Map <T> map, DungeonConfiguration configuration, IRandomizer randomizer)
        {
            var cellsToRemove = (int)(map.Width * map.Height * configuration.Sparseness);

            while (cellsToRemove != 0)
            {
                //Look at every cell in the maze grid. If the given cell contains a corridor that exits the cell in only one direction
                //"erase" that cell by removing the corridor
                var changedCells = new HashSet <T>();

                var deadEndCells = map.AllCells.Where(cell => cell.Sides.Values.Count(side => side) == 1).ToList();
                if (!deadEndCells.Any())
                {
                    break;
                }
                foreach (var deadEndCell in deadEndCells)
                {
                    deadEndCell.IsOpen = false;
                    var openDirection = deadEndCell.Sides.First(pair => pair.Value).Key;
                    deadEndCell.Sides[openDirection] = false;
                    var oppositeCell = map.GetAdjacentCell(deadEndCell, openDirection);
                    oppositeCell.Sides[openDirection.Opposite()] = false;
                    changedCells.Add(deadEndCell);
                    changedCells.Add(oppositeCell);
                    cellsToRemove--;
                    if (cellsToRemove == 0)
                    {
                        break;
                    }
                }
                //Repeat step #1 sparseness times
            }
        }
Beispiel #2
0
        /// <summary>
        /// Generate a map according the configuration received.
        /// </summary>
        /// <param name="config">The configuration used to generate the map.</param>
        /// <param name="seed">A seed to be used for the generation. If null a random seed will be generated.</param>
        /// <returns>The generated map.</returns>
        public virtual Map <T> Generate(DungeonConfiguration config, int?seed = null)
        {
            var randomizer = new Randomizer();

            if (!seed.HasValue)
            {
                seed = Guid.NewGuid().GetHashCode();
            }
            randomizer.SetSeed(seed.Value);
            var halfHeight = config.Height / 2;
            var halfWidth  = config.Width / 2;
            var map        = new Map <BinaryCell>(halfWidth, halfHeight);

            //pre processing
            foreach (var preProcessor in mPreProcessors)
            {
                preProcessor.ProcessMap(map, config, randomizer);
            }

            //double map
            var postMap = mMapConverter.ConvertMap(map, config, randomizer);

            //post processing
            foreach (var postProcessor in mPostProcessors)
            {
                postProcessor.ProcessMap(postMap, config, randomizer);
            }

            return(postMap);
        }
Beispiel #3
0
 /// <summary>
 /// Generates a map on a different thread.
 /// </summary>
 /// <param name="callback">Will be called when the generation is complete (on a different thread).</param>
 /// <param name="config">The configuration used to generate the map.</param>
 /// <param name="seed">A seed to be used for the generation. If null a random seed will be generated.</param>
 public void BeginGenerate(Action <Map <T> > callback, DungeonConfiguration config, int?seed = null)
 {
     new Thread(() => {
         var map = Generate(config, seed);
         callback(map);
     }).Start();
 }
Beispiel #4
0
        public void ProcessMap(Map <T> map, DungeonConfiguration configuration, IRandomizer randomizer)
        {
            var isolatedRooms = map.Rooms.Where(room => map.GetCellsAdjacentToRoom(room).All(cell => cell.Terrain == TerrainType.Rock)).ToList();

            foreach (var room in map.Rooms)
            {
                if (isolatedRooms.Contains(room))
                {
                    ConnectRoom(map, randomizer, room, isolatedRooms);
                }
                //place doors
                foreach (var cell in map.GetCellsAdjacentToRoom(room)
                         .Where(cell => cell.Terrain == TerrainType.Floor &&
                                map.GetAllAdjacentCells(cell).All(c => c.Terrain != TerrainType.Door)))
                {
                    //don't place a door if it leads to nowhere
                    if (map.GetAllAdjacentCells(cell).Count(c => c.Terrain == TerrainType.Floor) == 1)
                    {
                        continue;
                    }

                    cell.Terrain = TerrainType.Door;
                }
            }
        }
Beispiel #5
0
        public void ProcessMap(Map <T> map, DungeonConfiguration configuration, IRandomizer randomizer)
        {
            var deadends = map.AllCells.Where(cell => cell.Sides.Values.Count(type => type) == 1).ToList();

            foreach (var cell in deadends)
            {
                if (randomizer.GetRandomDouble() > configuration.ChanceToRemoveDeadends)
                {
                    continue;
                }

                var currentCell  = cell;
                var previousCell = map.GetAdjacentCell(cell, cell.Sides.First(pair => pair.Value).Key);
                var connected    = false;
                while (!connected)
                {
                    var direction = GetRandomValidDirection(map, currentCell, previousCell, randomizer);
                    if (!direction.HasValue)
                    {
                        break;
                    }

                    var adjacentCell = map.GetAdjacentCell(currentCell, direction.Value);
                    connected           = adjacentCell.IsOpen;
                    adjacentCell.IsOpen = true;
                    currentCell.Sides[direction.Value] = adjacentCell.Sides[direction.Value.Opposite()] = true;
                    previousCell = currentCell;
                    currentCell  = adjacentCell;
                }
            }
        }
Beispiel #6
0
        private static HashSet <Size> GetAllPossibleRoomSizes(DungeonConfiguration configuration)
        {
            var sizes = new HashSet <Size>();

            for (int i = configuration.MinRoomHeight; i <= configuration.MaxRoomHeight; i++)
            {
                for (int j = configuration.MinRoomWidth; j <= configuration.MaxRoomWidth; j++)
                {
                    sizes.Add(new Size(j, i));
                }
            }
            return(sizes);
        }
Beispiel #7
0
        public void ProcessMap(Map <T> map, DungeonConfiguration configuration, IRandomizer randomizer)
        {
            //Start with a rectangular grid, x units wide and y units tall. Mark each cell in the grid unvisited
            var visitedCells      = new HashSet <T>();
            var visitedValidCells = new HashSet <T>();
            //            var deadEndCells = new HashSet<T>();
            Direction?previousDirection = null;

            //Pick a random cell in the grid and mark it visited. This is the current cell.
            var currentCell = randomizer.GetRandomCell(map);

            currentCell.IsOpen = true;
            while (visitedCells.Count < map.Width * map.Height)
            {
                var oldCell = currentCell;
                var changed = false;
                visitedCells.Add(currentCell);
                visitedValidCells.Add(currentCell);
                //From the current cell, pick a random direction (north, south, east, or west).
                //If (1) there is no cell adjacent to the current cell in that direction, or (2) if
                //the adjacent cell in that direction has been visited, then that direction
                //is invalid, and you must pick a different random direction.
                var direction = GetRandomValidDirection(map, currentCell, visitedCells, configuration.Randomness, previousDirection, randomizer);
                if (direction.HasValue)
                {
                    //Let's call the cell in the chosen direction C. Create a corridor between the
                    //current cell and C, and then make C the current cell. Mark C visited.
                    changed     = !currentCell.Sides[direction.Value];
                    currentCell = map.GetAdjacentCell(currentCell, direction.Value);
                    currentCell.Sides[direction.Value.Opposite()] = oldCell.Sides[direction.Value] = true;
                    previousDirection = direction;
                }
                else
                {
                    //If all directions are invalid, pick a different random visited cell in the grid and start this step over again.
                    //                    deadEndCells.Add(currentCell);
                    visitedValidCells.Remove(currentCell);
                    currentCell = randomizer.GetRandomItem(visitedValidCells);
                }
                if (currentCell.IsOpen && !changed)
                {
                    continue;
                }

                currentCell.IsOpen = true;
                //Repeat until all cells in the grid have been visited.
            }
        }
Beispiel #8
0
        private void GenerateAndAssert(
            Func <DungeonConfigurationGenerator <Cell>, DungeonConfigurationGenerator <Cell> > method,
            Action <DungeonConfiguration> assertMethod)
        {
            DungeonConfiguration targetConfiguration = null;
            var fakeGenerator = A.Fake <DungeonGenerator <Cell> >();

            A.CallTo(() => fakeGenerator.Generate(null, null))
            .WithAnyArguments()
            .Invokes(callObject => targetConfiguration = callObject.Arguments[0] as DungeonConfiguration);

            var configGenerator = new DungeonConfigurationGenerator <Cell>(fakeGenerator);

            method(configGenerator).Now();

            assertMethod(targetConfiguration);
        }
Beispiel #9
0
        public Map <TPost> ConvertMap(Map <TPre> map, DungeonConfiguration configuration, IRandomizer randomizer)
        {
            var oldCells = map.AllCells.ToList();
            var newMap   = new Map <TPost>(map.Width * 2 + 1, map.Height * 2 + 1);

            foreach (var oldCell in oldCells.Where(cell => cell.IsOpen))
            {
                var newCell = newMap.GetCell(oldCell.Row * 2 + 1, oldCell.Column * 2 + 1);
                newCell.Terrain = TerrainType.Floor;
                foreach (var kvp in oldCell.Sides.Where(pair => pair.Value))
                {
                    var adjacentCell = newMap.GetAdjacentCell(newCell, kvp.Key);
                    adjacentCell.Terrain = TerrainType.Floor;
                }
            }
            return(newMap);
        }
Beispiel #10
0
        internal Tuple <Map <T>, Dictionary <string, double> > GenerateAndMeasure(DungeonConfiguration config)
        {
            var randomizer = new Randomizer();
            var seed       = Guid.NewGuid().GetHashCode();

            randomizer.SetSeed(seed);
            var      halfHeight = config.Height / 2;
            var      halfWidth  = config.Width / 2;
            var      map        = new Map <BinaryCell>(halfWidth, halfHeight);
            var      results    = new Dictionary <string, double>();
            DateTime start      = DateTime.Now;
            var      totalStart = DateTime.Now;

            //pre processing
            foreach (var preProcessor in mPreProcessors)
            {
                start = DateTime.Now;
                preProcessor.ProcessMap(map, config, randomizer);
                results[preProcessor.GetType().Name] = DateTime.Now.Subtract(start).TotalSeconds;
            }

            //double map
            start = DateTime.Now;
            var postMap = mMapConverter.ConvertMap(map, config, randomizer);

            results[mMapConverter.GetType().Name] = DateTime.Now.Subtract(start).TotalSeconds;

            //post processing
            foreach (var postProcessor in mPostProcessors)
            {
                start = DateTime.Now;
                postProcessor.ProcessMap(postMap, config, randomizer);
                results[postProcessor.GetType().Name] = DateTime.Now.Subtract(start).TotalSeconds;
            }
            results["Total"] = DateTime.Now.Subtract(totalStart).TotalSeconds;
            return(new Tuple <Map <T>, Dictionary <string, double> >(postMap, results));
        }
Beispiel #11
0
        public void ProcessMap(Map <T> map, DungeonConfiguration configuration, IRandomizer randomizer)
        {
            var validSizes = GetAllPossibleRoomSizes(configuration);

            for (var i = 0; i < configuration.RoomCount; i++)
            {
                //Generate a room such that Wmin <= Rw <= Wmax and Hmin <= Rh <= Hmax.
                var room = CreateRoom(randomizer, validSizes);
                if (room == null)
                {
                    break;
                }
                var visitedCells   = new HashSet <T>();
                var unvisitedCells = new HashSet <T>(map.AllCells);
                var roomPlaced     = false;

                while (visitedCells.Count < map.Height * map.Width)
                {
                    //get a random cell
                    var cell = randomizer.GetRandomItem(unvisitedCells);
                    visitedCells.Add(cell);
                    unvisitedCells.Remove(cell);

                    //place the room
                    room.Row    = cell.Row;
                    room.Column = cell.Column;
                    if (room.Column <= 0 || room.Right >= map.Width || room.Row <= 0 || room.Bottom >= map.Height)
                    {
                        continue;                                                                                            //out of bounds
                    }
                    var cells = map.GetRoomCells(room).ToList();

                    //don't place room where it is overlapping another room
                    if (cells.Any(c => map.IsLocationInRoom(c.Row, c.Column)))
                    {
                        continue;
                    }

                    //don't place room where it is adjacent to another room
                    if (map.GetCellsAdjacentToRoom(room).Any(c => map.IsLocationInRoom(c.Row, c.Column)))
                    {
                        continue;
                    }

                    //corners are rock
                    if (!AreAllCornerCellsRocks(map, room))
                    {
                        continue;                                     //NW corner
                    }
                    //all corridors leading into room can become doors (are isolated)
                    if (!CanAllCorridorsLeadingToRoomBeDoors(map, room))
                    {
                        continue;
                    }

                    PlaceRoom(map, room);
                    roomPlaced = true;
                    break;
                }

                if (!roomPlaced)
                {
                    validSizes.Remove(room.Size);
                }
            }
        }