using System; namespace Mr.BrickAdventures.Tools.CaLevelGenerator; public static class CaGenerator { public static bool[,] Generate(CaGeneratorSettings s) { var rng = new Random(s.Seed); return s.Mode switch { CaMode.Cave => GenerateCave(s, rng), CaMode.Platform => GeneratePlatform(s, rng), CaMode.Terrain => GenerateTerrain(s, rng), _ => GenerateCave(s, rng), }; } public static bool[,] Smooth(bool[,] grid) => SmoothPass(grid, 5); // ── Cave ────────────────────────────────────────────────────────────── private static bool[,] GenerateCave(CaGeneratorSettings s, Random rng) { var grid = RandomFill(s.Width, s.Height, s.FillDensity, rng); if (s.BorderWalls) EnforceBorder(grid); for (int i = 0; i < s.SmoothingPasses; i++) { grid = SmoothPass(grid, 5); if (s.BorderWalls) EnforceBorder(grid); } return grid; } // ── Platform ────────────────────────────────────────────────────────── private static bool[,] GeneratePlatform(CaGeneratorSettings s, Random rng) { int w = s.Width, h = s.Height; var grid = new bool[w, h]; for (int x = 0; x < w; x++) { grid[x, h - 1] = true; grid[x, h - 2] = true; for (int y = 0; y < h - 2; y++) { // Density linearly increases from 10% at top to 60% at bottom, // scaled by user's FillDensity relative to default 0.48. float t = (float)y / (h - 3); float rowDensity = (0.1f + t * 0.5f) * (s.FillDensity / 0.48f); grid[x, y] = rng.NextDouble() < rowDensity; } } for (int i = 0; i < s.SmoothingPasses; i++) { // Threshold 4 (not 5): horizontal platform groups survive, isolated // vertical pixels collapse into flat platforms. grid = SmoothPass(grid, 4); for (int x = 0; x < w; x++) { grid[x, h - 1] = true; grid[x, h - 2] = true; } } return grid; } // ── Terrain ─────────────────────────────────────────────────────────── private static bool[,] GenerateTerrain(CaGeneratorSettings s, Random rng) { int w = s.Width, h = s.Height; var grid = new bool[w, h]; // Start terrain surface at ~60% from bottom (40% from top) int surfaceRow = (int)(h * 0.4f); for (int x = 0; x < w; x++) { int delta = rng.Next(-2, 3); surfaceRow = Math.Clamp(surfaceRow + delta, h / 6, h - 2); for (int y = surfaceRow; y < h; y++) grid[x, y] = true; } for (int i = 0; i < s.SmoothingPasses; i++) grid = SmoothPass(grid, 5); return grid; } // ── Shared helpers ──────────────────────────────────────────────── private static bool[,] RandomFill(int w, int h, float density, Random rng) { var grid = new bool[w, h]; for (int x = 0; x < w; x++) for (int y = 0; y < h; y++) grid[x, y] = rng.NextDouble() < density; return grid; } private static bool[,] SmoothPass(bool[,] grid, int threshold) { int w = grid.GetLength(0), h = grid.GetLength(1); var next = new bool[w, h]; for (int x = 0; x < w; x++) for (int y = 0; y < h; y++) next[x, y] = CountSolidNeighbors(grid, x, y) >= threshold; return next; } private static int CountSolidNeighbors(bool[,] grid, int cx, int cy) { int w = grid.GetLength(0), h = grid.GetLength(1), count = 0; for (int dx = -1; dx <= 1; dx++) for (int dy = -1; dy <= 1; dy++) { if (dx == 0 && dy == 0) continue; int nx = cx + dx, ny = cy + dy; // Out-of-bounds counts as solid (closes cave edges naturally) if (nx < 0 || nx >= w || ny < 0 || ny >= h) count++; else if (grid[nx, ny]) count++; } return count; } private static void EnforceBorder(bool[,] grid) { int w = grid.GetLength(0), h = grid.GetLength(1); for (int x = 0; x < w; x++) { grid[x, 0] = true; grid[x, h - 1] = true; } for (int y = 0; y < h; y++) { grid[0, y] = true; grid[w - 1, y] = true; } } }