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