public static SimpleGameMap GenerateMirroredMap(EMapSize size, int numTeams = -1) { var rnd = StrategyGame.Random; var iSize = (int)size; // Lock Large/Small maps to 2/4 teams for less variation if (size == EMapSize.Small) { numTeams = 2; } if (size == EMapSize.Large) { numTeams = 4; } if (numTeams == -1 && size == EMapSize.Normal) { numTeams = rnd.Next(1, 3) * 2; } var map = new SimpleGameMap($"{size} Random{numTeams}"); // 0:hor/1:vert/2:hor&vert var mirrorType = numTeams == 2 ? rnd.Next(3) : 2; var mirrorIncrement = mirrorType == 2 ? 4 : 2; // Determine num sectors based on size & num teams // small: (min = num teams*2, max = num teams*4) // normal: (min = num teams*3, max = num teams*5) // large: (min = num teams*4, max = num teams*6) var minNumSectors = numTeams * (iSize + 2); var maxNumSectors = numTeams * (iSize + 4); var xDim = 7; var yDim = 7; var nextSectorId = 0; // Add sectors in all positions for (var x = 0; x < xDim; x++) { for (var y = 0; y < yDim; y++) { var s = new SimpleMapSector(nextSectorId++, new Point(x, y)); map.Sectors.Add(s); } } var maxChances = map.Sectors.Count * 3; var l = 0; // Loop with a decreasing chance to remove sectors (mirrored) var removeChance = 0.97; while ((l++ < maxChances || map.Sectors.Count - mirrorIncrement > maxNumSectors) && map.Sectors.Count - mirrorIncrement > minNumSectors) { var s = StrategyGame.RandomItem(map.Sectors); if (rnd.NextDouble() < removeChance) { removeChance -= 0.03; map.Sectors.Remove(s); // Horiz mirrored or both if (mirrorType == 0 || mirrorType == 2) { var mX = MirrorDimension(xDim, s.MapPosition.X); var mY = s.MapPosition.Y; var s2 = map.Sectors.FirstOrDefault(_ => _.MapPosition.X == mX && _.MapPosition.Y == mY); if (s2 != null) { map.Sectors.Remove(s2); } } // Vert mirrored or both if (mirrorType == 1 || mirrorType == 2) { var mX = s.MapPosition.X; var mY = MirrorDimension(yDim, s.MapPosition.Y); var s2 = map.Sectors.FirstOrDefault(_ => _.MapPosition.X == mX && _.MapPosition.Y == mY); if (s2 != null) { map.Sectors.Remove(s2); } } // Mirrored for both dimensions if (mirrorType == 2) { var mX = MirrorDimension(xDim, s.MapPosition.X); var mY = MirrorDimension(yDim, s.MapPosition.Y); var s2 = map.Sectors.FirstOrDefault(_ => _.MapPosition.X == mX && _.MapPosition.Y == mY); if (s2 != null) { map.Sectors.Remove(s2); } } } } // Fix SectorIDs after removing, they actually need to be indexes... l = 0; foreach (var s in map.Sectors) { s.Id = l++; } // Triangulate, loop with a small chance to remove an edges if that sector has > 2 connections var vertices = new List <Vertex <SimpleMapSector> >(); foreach (var s in map.Sectors) { var p = s.MapPosition; vertices.Add(new Vertex <SimpleMapSector>(new Vector2(p.X, p.Y), s)); } var delaunay = Delaunay2D <SimpleMapSector> .Triangulate(vertices); var mapEdges = new List <Edge <SimpleMapSector> >(); foreach (var edge in delaunay.Edges) { if (!map.WormholeExists(edge.U.Item.Id, edge.V.Item.Id)) { map.WormholeIds.Add(new WormholeId(edge.U.Item.Id, edge.V.Item.Id)); } } // Find Starting Positions (mirrored) var teamsAdded = 0; { var startPosMinX = 0; var startPosMinY = 0; var startPosMaxX = mirrorType == 1 ? xDim : xDim / 2 - 1; var startPosMaxY = mirrorType == 0 ? yDim : yDim / 2 - 1; var startSectors = map.Sectors .Where(_ => _.MapPosition.X >= startPosMinX && _.MapPosition.X <= startPosMaxX && _.MapPosition.Y >= startPosMinY && _.MapPosition.Y <= startPosMaxY) .ToList(); var s = StrategyGame.RandomItem(startSectors); // Safety check if (s == null) { return(GenerateMirroredMap(size)); } s.StartingSectorTeam = ++teamsAdded; // Mirrored for both dimensions if (mirrorType == 2) { var mX = MirrorDimension(xDim, s.MapPosition.X); var mY = MirrorDimension(yDim, s.MapPosition.Y); var s2 = map.Sectors.FirstOrDefault(_ => _.MapPosition.X == mX && _.MapPosition.Y == mY); if (s2 != null) { s2.StartingSectorTeam = ++teamsAdded; } } // Horiz mirrored or both if (mirrorType == 0 || (mirrorType == 2 && numTeams > 2)) { var mX = MirrorDimension(xDim, s.MapPosition.X); var mY = s.MapPosition.Y; var s2 = map.Sectors.FirstOrDefault(_ => _.MapPosition.X == mX && _.MapPosition.Y == mY); if (s2 != null) { s2.StartingSectorTeam = ++teamsAdded; } } // Vert mirrored or both if (mirrorType == 1 || (mirrorType == 2 && numTeams > 2)) { var mX = s.MapPosition.X; var mY = MirrorDimension(yDim, s.MapPosition.Y); var s2 = map.Sectors.FirstOrDefault(_ => _.MapPosition.X == mX && _.MapPosition.Y == mY); if (s2 != null) { s2.StartingSectorTeam = ++teamsAdded; } } } // Final Checks if (teamsAdded < numTeams || !map.IsValid()) { return(GenerateMirroredMap(size)); } return(map); }
public static SimpleGameMap GenerateSimpleMap(EMapSize size) { var rnd = StrategyGame.Random; var map = new SimpleGameMap($"{size} Random"); var mirror = (EMirrorType)rnd.Next(2); var maxX = (mirror == EMirrorType.Horizontal ? MaxWidth / 2 : MaxWidth); var maxY = (mirror == EMirrorType.Vertical ? MaxHeight / 2 : MaxHeight); var nextSectorId = 0; var numSectors = 2 + (int)size; var s1 = new SimpleMapSector(nextSectorId++, new Point(rnd.Next(maxX), rnd.Next(maxY))); s1.StartingSectorTeam = 1; map.Sectors.Add(s1); var s2 = new SimpleMapSector(nextSectorId++, MirrorPoint(s1.MapPosition, mirror)); s2.StartingSectorTeam = 2; map.Sectors.Add(s2); for (var i = 0; i < numSectors; i++) { var attemptCount = 0; bool pathClear; Point p; SimpleMapSector linkedSector; var checkSectors = Utils.Shuffle(map.Sectors, rnd); do { p = new Point(rnd.Next(maxX), rnd.Next(maxY)); pathClear = false; linkedSector = null; attemptCount++; var existingSector = map.Sectors.FirstOrDefault(_ => _.MapPosition == p); if (existingSector != null) { continue; } // Checking if there is a clear path from this point to any other random sector, to add a wormhole foreach (var s in checkSectors) { if (s.MapPosition == p) { continue; } pathClear = IsPathClear(map, p, s.MapPosition, 2f); if (pathClear) { linkedSector = s; break; } } } while (!pathClear && attemptCount < 40); if (pathClear) { var newS = new SimpleMapSector(nextSectorId++, p); map.Sectors.Add(newS); if (!map.WormholeExists(newS.Id, linkedSector.Id)) { map.WormholeIds.Add(new WormholeId(newS.Id, linkedSector.Id)); } var newS2 = new SimpleMapSector(nextSectorId++, MirrorPoint(newS.MapPosition, mirror)); map.Sectors.Add(newS2); // Add wormhole from the mirrored sector to equivilant var m2 = MirrorPoint(linkedSector.MapPosition, mirror); var linkedSector2 = map.Sectors.FirstOrDefault(_ => _.MapPosition == m2); if (linkedSector2 != null) { if (!map.WormholeExists(newS2.Id, linkedSector2.Id)) { map.WormholeIds.Add(new WormholeId(newS2.Id, linkedSector2.Id)); } } } } var c = 0; foreach (var a in map.Sectors) { var rndSectors = Utils.Shuffle(map.Sectors, rnd); foreach (var b in rndSectors) { if (a.StartingSectorTeam != 0 && b.StartingSectorTeam != 0) { continue; } if (map.WormholeExists(a.Id, b.Id)) { continue; } if (c < 2 && IsPathClear(map, a.MapPosition, b.MapPosition, 2f)) { map.WormholeIds.Add(new WormholeId(a.Id, b.Id)); // mirror wormhole! var ma = MirrorPoint(a.MapPosition, mirror); var mb = MirrorPoint(b.MapPosition, mirror); var sa = map.Sectors.FirstOrDefault(_ => _.MapPosition == ma); var sb = map.Sectors.FirstOrDefault(_ => _.MapPosition == mb); if (sa != null && sb != null && !map.WormholeExists(sa.Id, sb.Id)) { map.WormholeIds.Add(new WormholeId(sa.Id, sb.Id)); } c++; break; } } } if (!map.IsValid()) { return(GenerateSimpleMap(size)); } return(map); }