public void Init() { /// /// Notice: /// This map generator may have issues when edge case occurs. /// It'll be manually taken into account so that you don't have to care about that. // Random rd = new Random((int)DateTime.Now.Ticks); // Step 1 : Randomly generate obstacles. { map.Foreach((i, j, r) => { double rate = 1.0 / Config.inst.gridPerObstacles; // 1 obstacle per 5 tiles. if (rd.NextDouble() < rate) { r.type = Tile.Type.Obstacle; } return(r); }); } List <(int x, int y)> vq = null; // Step 2 : Floodfill to find the largest connected componenet in the map. { bool[,] used = new bool[height, width]; Ref <int> res = new Ref <int>(0); map.Foreach((i, j, r) => { if (used[i, j]) { return(r); } int cnt = 0; int[] di = new int[] { 1, -1, 0, 0 }; int[] dj = new int[] { 0, 0, 1, -1 }; var q = new List <(int x, int y)>(); q.Add((i, j)); used[i, j] = true; while (cnt != q.Count) { var(ci, cj) = q[cnt++]; for (int t = 0; t < 4; t++) { var(ni, nj) = (ci + di[t], cj + dj[t]); if (Inside(ni, nj) && map[ni, nj].type != Tile.Type.Obstacle) { if (!used[ni, nj]) { q.Add((ni, nj)); used[ni, nj] = true; } } } } if (res.v < cnt) { res.v = cnt; vq = q; } return(r); }); LogLine("Max connected componenet size: " + vq.Count); } // Generate resources. Remove collected resources. { double rate = 1.0 / Config.inst.gridPerResources; for (int i = 0; i < vq.Count; i++) { if (rd.NextDouble() < rate) { map[vq[i].x, vq[i].y].type = Tile.Type.Resource; (vq[i], vq[vq.Count - 1]) = (vq[vq.Count - 1], vq[i]); vq.RemoveAt(vq.Count - 1); } } } // Generate Factories. { for (int i = 1; i <= playerCount; i++) { var(x, y) = vq[rd.Next(0, vq.Count - 1)]; vq.Remove((x, y)); map[x, y].type = Tile.Type.Factory; map[x, y].owner = i; } } LogLine("Initial map:"); LogLine(OutputString(0)); }