Exemplo n.º 1
0
        public bool Generate()
        {
            Initialize();

            designInfo = new DesignInfo[designs.Count];

            designCount = 0;
            foreach (Level design in designs)
            {
                // Extract design data.
                Array2D<Cell> designData = new Array2D<Cell>(design.Data);
                if (useEntireLevel)
                {
                    designData.Replace(Cell.Outside, Cell.Wall);
                }

                // Create a map of all squares that cannot be altered, initialized to false.
                Array2D<bool> designFixed = new Array2D<bool>(designData.Height, designData.Width);
                Coordinate2D sokobanCoord = Coordinate2D.Undefined;
                int designBoxes = 0;
                foreach (Coordinate2D coord in designData.NonPerimeterCoordinates)
                {
                    if (clearDesign)
                    {
                        if (designData[coord] != Cell.Wall)
                        {
                            designData[coord] = Cell.Empty;
                        }
                    }
                    if (designData[coord] != Cell.Undefined)
                    {
                        // Record squares that should not be changed.
                        designFixed[coord] = true;
                    }
                    if (Level.IsSokoban(designData[coord]))
                    {
                        // Remove sokoban if present but record its coordinate.
                        designData[coord] &= ~Cell.Sokoban;
                        sokobanCoord = coord;
                    }
                    if (Level.IsBox(designData[coord]))
                    {
                        // Count boxes included in design.
                        designBoxes++;
                    }
                }

                // Store in design array.
                DesignInfo info = new DesignInfo();
                info.Data = designData;
                info.Fixed = designFixed;
                info.SokobanCoordinate = sokobanCoord;
                info.Boxes = designBoxes;
                designInfo[designCount] = info;
                designCount++;
            }

            // Now generate levels.
            if (threads == 1)
            {
                return GenerateLevels();
            }
            return MultiThreadedGenerateLevels();
        }
Exemplo n.º 2
0
        private Level GenerateLevelBlob(State state, int size, Array2D<Cell> designData, Array2D<bool> designFixed, out int designRow, out int designColumn)
        {
            // Inflate size for extra cells to be subtracted.
            int blobSize = size * (density + 100) / 100;
            // Create larger work array and corresponding fixed map.
            Array2D<Cell> array = new Array2D<Cell>(2 * size, 2 * size);
            array.SetAll(Cell.Outside);
            Array2D<bool> arrayFixed = new Array2D<bool>(array.Height, array.Width);

            // Adjust design data so that outside or undefined cells are empty.
            Array2D<Cell> designDataCopy = new Array2D<Cell>(designData);
            designDataCopy.Replace(Cell.Outside, Cell.Empty);
            designDataCopy.Replace(Cell.Undefined, Cell.Empty);

            // Copy design into middle of work array.
            designRow = size;
            designColumn = size;
            designDataCopy.CopyTo(array, designRow + 1, designColumn + 1, 1, 1, designData.Height - 2, designData.Width - 2);
            designFixed.CopyTo(arrayFixed, designRow + 1, designColumn + 1, 1, 1, designData.Height - 2, designData.Width - 2);

            // Set intial boundaries.
            int rowMin = array.Height;
            int colMin = array.Width;
            int rowMax = -1;
            int colMax = -1;
            int count = 0;
            foreach (Coordinate2D coord in array.Coordinates)
            {
                if (!Level.IsOutside(array[coord]))
                {
                    rowMin = Math.Min(rowMin, coord.Row);
                    colMin = Math.Min(colMin, coord.Column);
                    rowMax = Math.Max(rowMax, coord.Row);
                    colMax = Math.Max(colMax, coord.Column);
                    count++;
                }
            }

            while (count < blobSize)
            {
                // Choose an edge at random.
                int edge = state.Random.Next(4);
                int row = 0;
                int column = 0;
                int limit = 0;
                int hIncr = 0;
                int vIncr = 0;
                switch (edge)
                {
                    case 0:
                        row = rowMin - 1;
                        column = colMin + state.Random.Next(colMax - colMin + 1);
                        limit = rowMax - rowMin + 1;
                        vIncr = 1;
                        hIncr = 0;
                        break;
                    case 1:
                        row = rowMax + 1;
                        column = colMin + state.Random.Next(colMax - colMin + 1);
                        limit = rowMax - rowMin + 1;
                        vIncr = -1;
                        hIncr = 0;
                        break;
                    case 2:
                        row = rowMin + state.Random.Next(rowMax - rowMin + 1);
                        column = colMin - 1;
                        limit = colMax - colMin + 1;
                        vIncr = 0;
                        hIncr = 1;
                        break;
                    case 3:
                        row = rowMin + state.Random.Next(rowMax - rowMin + 1);
                        column = colMax + 1;
                        limit = colMax - colMin + 1;
                        vIncr = 0;
                        hIncr = -1;
                        break;
                }

                // Search along a line until we hit a empty or fixed cell.
                bool found = false;
                for (int i = 0; i < limit; i++)
                {
                    if (array[row + vIncr, column + hIncr] != Cell.Outside || arrayFixed[row + vIncr, column + hIncr])
                    {
                        if (!arrayFixed[row, column])
                        {
                            found = true;
                        }
                        break;
                    }
                    row += vIncr;
                    column += hIncr;
                }

                // If we didn't find anything, try again.
                if (!found)
                {
                    continue;
                }

                // Don't allow the level to grow outside the array.
                if (row < 1 || row >= array.Height - 1 || column < 1 || column >= array.Width - 1)
                {
                    continue;
                }

                // Add the new square and update the boundaries.
                array[row, column] = Cell.Empty;
                rowMin = Math.Min(rowMin, row);
                colMin = Math.Min(colMin, column);
                rowMax = Math.Max(rowMax, row);
                colMax = Math.Max(colMax, column);
                count++;
            }

            int attemptsLeft = 2 * (count - size);
            while (count > size && attemptsLeft > 0)
            {
                // Choose a new square at random.
                int row = rowMin + state.Random.Next(rowMax - rowMin + 1);
                int column = colMin + state.Random.Next(colMax - colMin + 1);
                Coordinate2D coord = new Coordinate2D(row, column);
                if (!array.IsValid(coord))
                {
                    continue;
                }

                // Avoid existing walls and outside areas.
                if (!Level.IsInside(array[coord]))
                {
                    continue;
                }

                // We might get into an infinite loop.
                attemptsLeft--;

                // Avoid fixed cells.
                if (arrayFixed[coord])
                {
                    continue;
                }

                // Avoid cells on the perimeter.
                bool isAdjacent = false;
                foreach (Coordinate2D neighbor in coord.EightNeighbors)
                {
                    if (array[neighbor] == Cell.Outside)
                    {
                        isAdjacent = true;
                        break;
                    }
                }
                if (isAdjacent)
                {
                    continue;
                }

                // Remove the cell.
                array[coord] = Cell.Wall;
                count--;

            }

            // Extract the constructed level.
            Array2D<Cell> subarray = array.GetSubarray(rowMin - 1, colMin - 1, rowMax - rowMin + 3, colMax - colMin + 3);
            subarray.Replace(Cell.Outside, Cell.Wall);
            Level level = new Level(subarray);

            // Adjust design coordinate.
            designRow -= rowMin - 1;
            designColumn -= colMin - 1;

            return level;
        }
Exemplo n.º 3
0
        private Level GenerateLevelBuckshot(State state, int size, Array2D<Cell> designData, Array2D<bool> designFixed, out int designRow, out int designColumn)
        {
            // Create larger work array and corresponding fixed map.
            Array2D<Cell> array = new Array2D<Cell>(2 * size + designData.Height, 2 * size + designData.Width);
            array.SetAll(Cell.Wall);
            Array2D<bool> arrayFixed = new Array2D<bool>(array.Height, array.Width);

            // Adjust design data so that undefined cells are walls.
            Array2D<Cell> designDataCopy = new Array2D<Cell>(designData);
            designDataCopy.Replace(Cell.Undefined, Cell.Wall);

            // Copy design into middle of work array.
            designRow = size;
            designColumn = size;
            designDataCopy.CopyTo(array, designRow, designColumn, 0, 0, designData.Height, designData.Width);
            designFixed.CopyTo(arrayFixed, designRow, designColumn, 0, 0, designData.Height, designData.Width);

            // Set intial boundaries.
            int rowMin = array.Height;
            int colMin = array.Width;
            int rowMax = -1;
            int colMax = -1;
            int count = 0;
            foreach (Coordinate2D coord in array.Coordinates)
            {
                if (!Level.IsWall(array[coord]))
                {
                    rowMin = Math.Min(rowMin, coord.Row);
                    colMin = Math.Min(colMin, coord.Column);
                    rowMax = Math.Max(rowMax, coord.Row);
                    colMax = Math.Max(colMax, coord.Column);
                    count++;
                }
            }

            while (count < size)
            {
                // Choose a new square at random.
                int row = rowMin - growth + state.Random.Next(rowMax - rowMin + 1 + 2 * growth);
                int column = colMin - growth + state.Random.Next(colMax - colMin + 1 + 2 * growth);
                Coordinate2D coord = new Coordinate2D(row, column);
                if (!array.IsValid(coord))
                {
                    continue;
                }

                // Avoid fixed cells.
                if (arrayFixed[coord])
                {
                    continue;
                }

                // Avoid existing squares.
                if (!Level.IsWall(array[coord]))
                {
                    continue;
                }

                // Ensure the new square is adjacent to an existing square.
                bool isAdjacent = false;
                foreach (Coordinate2D neighbor in coord.FourNeighbors)
                {
                    if (!Level.IsWall(array[neighbor]))
                    {
                        isAdjacent = true;
                        break;
                    }
                }
                if (!isAdjacent)
                {
                    continue;
                }

                // Add the new square and update the boundaries.
                array[coord] = Cell.Empty;
                rowMin = Math.Min(rowMin, row);
                colMin = Math.Min(colMin, column);
                rowMax = Math.Max(rowMax, row);
                colMax = Math.Max(colMax, column);
                count++;
            }

            // Extract the constructed level.
            Array2D<Cell> subarray = array.GetSubarray(rowMin - 1, colMin - 1, rowMax - rowMin + 3, colMax - colMin + 3);
            Level level = new Level(subarray);

            // Adjust design coordinate.
            designRow -= rowMin - 1;
            designColumn -= colMin - 1;

            return level;
        }