public void Analyze(Tyr tyr) { // Determine the start location. foreach (Unit unit in tyr.Observation.Observation.RawData.Units) { if (unit.Owner == tyr.PlayerId && UnitTypes.ResourceCenters.Contains(unit.UnitType)) { StartLocation = unit.Pos; } } List <MineralField> mineralFields = new List <MineralField>(); foreach (Unit mineralField in tyr.Observation.Observation.RawData.Units) { if (UnitTypes.MineralFields.Contains(mineralField.UnitType)) { mineralFields.Add(new MineralField() { Pos = mineralField.Pos, Tag = mineralField.Tag }); } } Dictionary <ulong, int> mineralSetIds = new Dictionary <ulong, int>(); List <List <MineralField> > mineralSets = new List <List <MineralField> >(); int currentSet = 0; foreach (MineralField mineralField in mineralFields) { if (mineralSetIds.ContainsKey(mineralField.Tag)) { continue; } BaseLocation baseLocation = new BaseLocation(); BaseLocations.Add(baseLocation); mineralSetIds.Add(mineralField.Tag, currentSet); baseLocation.MineralFields.Add(mineralField); for (int i = 0; i < baseLocation.MineralFields.Count; i++) { MineralField mineralFieldA = baseLocation.MineralFields[i]; foreach (MineralField closeMineralField in mineralFields) { if (mineralSetIds.ContainsKey(closeMineralField.Tag)) { continue; } if (SC2Util.DistanceGrid(mineralFieldA.Pos, closeMineralField.Pos) <= 5) { mineralSetIds.Add(closeMineralField.Tag, currentSet); baseLocation.MineralFields.Add(closeMineralField); } } } currentSet++; } List <Gas> gasses = new List <Gas>(); foreach (Unit unit in tyr.Observation.Observation.RawData.Units) { if (UnitTypes.GasGeysers.Contains(unit.UnitType)) { gasses.Add(new Gas() { Pos = unit.Pos, Tag = unit.Tag }); } } foreach (BaseLocation loc in BaseLocations) { float x = 0; float y = 0; foreach (MineralField field in loc.MineralFields) { x += (int)field.Pos.X; y += (int)field.Pos.Y; } x /= loc.MineralFields.Count; y /= loc.MineralFields.Count; // Round to nearest half position. Nexii are 5x5 and therefore always centered in the middle of a tile. x = (int)(x) + 0.5f; y = (int)(y) + 0.5f; // Temporary position, we still need a proper position. loc.Pos = SC2Util.Point(x, y); MineralField closest = null; float distance = 10000; foreach (MineralField field in loc.MineralFields) { if (SC2Util.DistanceGrid(field.Pos, loc.Pos) < distance) { distance = SC2Util.DistanceGrid(field.Pos, loc.Pos); closest = field; } } // Move the estimated base position slightly away from the closest mineral. // This ensures that the base location will not end up on the far side of the minerals. if (closest.Pos.X < loc.Pos.X) { loc.Pos.X += 2; } else if (closest.Pos.X > loc.Pos.X) { loc.Pos.X -= 2; } if (closest.Pos.Y < loc.Pos.Y) { loc.Pos.Y += 2; } else if (closest.Pos.Y > loc.Pos.Y) { loc.Pos.Y -= 2; } for (int i = 0; i < gasses.Count; i++) { if (SC2Util.DistanceGrid(loc.Pos, gasses[i].Pos) <= 24) { loc.Gasses.Add(gasses[i]); gasses[i] = gasses[gasses.Count - 1]; gasses.RemoveAt(gasses.Count - 1); i--; } } float closestDist = 1000000; for (int i = 0; i < 20; i++) { for (int j = 0; j == 0 || j < i; j++) { float maxDist; Point2D newPos; newPos = SC2Util.Point(loc.Pos.X + i - j, loc.Pos.Y + j); maxDist = checkPosition(newPos, loc); if (maxDist < closestDist) { loc.Pos = newPos; closestDist = maxDist; } newPos = SC2Util.Point(loc.Pos.X + i - j, loc.Pos.Y - j); maxDist = checkPosition(newPos, loc); if (maxDist < closestDist) { loc.Pos = newPos; closestDist = maxDist; } newPos = SC2Util.Point(loc.Pos.X - i + j, loc.Pos.Y + j); maxDist = checkPosition(newPos, loc); if (maxDist < closestDist) { loc.Pos = newPos; closestDist = maxDist; } newPos = SC2Util.Point(loc.Pos.X - i + j, loc.Pos.Y - j); maxDist = checkPosition(newPos, loc); if (maxDist < closestDist) { loc.Pos = newPos; closestDist = maxDist; } } } if (closestDist >= 999999) { System.Console.WriteLine("Unable to find proper base placement: " + loc.Pos); } } if (tyr.GameInfo.MapName.Contains("Blueshift")) { foreach (BaseLocation loc in BaseLocations) { if (SC2Util.DistanceSq(loc.Pos, SC2Util.Point(141.5f, 112.5f)) <= 5 * 5 && (loc.Pos.X != 141.5 || loc.Pos.Y != 112.5)) { System.Console.WriteLine("Incorrect base location, fixing: " + loc.Pos); loc.Pos = SC2Util.Point(141.5f, 112.5f); } else if (SC2Util.DistanceSq(loc.Pos, SC2Util.Point(34.5f, 63.5f)) <= 5 * 5 && (loc.Pos.X != 34.5 || loc.Pos.Y != 63.5)) { System.Console.WriteLine("Incorrect base location, fixing: " + loc.Pos); loc.Pos = SC2Util.Point(34.5f, 63.5f); } } } Stopwatch stopWatch = Stopwatch.StartNew(); int width = Tyr.Bot.GameInfo.StartRaw.MapSize.X; int height = Tyr.Bot.GameInfo.StartRaw.MapSize.Y; Placement = new ImageBoolGrid(tyr.GameInfo.StartRaw.PlacementGrid); StartArea = Placement.GetConnected(SC2Util.To2D(StartLocation)); ArrayBoolGrid startLocations = new ArrayBoolGrid(Placement.Width(), Placement.Height()); foreach (Point2D startLoc in Tyr.Bot.GameInfo.StartRaw.StartLocations) { for (int x = -2; x <= 2; x++) { for (int y = -2; y <= 2; y++) { startLocations[(int)startLoc.X + x, (int)startLoc.Y + y] = true; } } } for (int x = -2; x <= 2; x++) { for (int y = -2; y <= 2; y++) { startLocations[(int)StartLocation.X + x, (int)StartLocation.Y + y] = true; } } BoolGrid unPathable = new ImageBoolGrid(Tyr.Bot.GameInfo.StartRaw.PathingGrid).GetAnd(startLocations.Invert()); BoolGrid pathable = unPathable.Invert(); BoolGrid chokes = Placement.Invert().GetAnd(pathable); BoolGrid mainExits = chokes.GetAdjacent(StartArea); enemyDistances = EnemyDistances; int dist = 1000; Point2D mainRamp = null; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (mainExits[x, y]) { int newDist = enemyDistances[x, y]; if (newDist < dist) { dist = newDist; mainRamp = SC2Util.Point(x, y); } } } } BoolGrid ramp = chokes.GetConnected(mainRamp); BoolGrid pathingWithoutRamp = pathable.GetAnd(ramp.Invert()); MainAndPocketArea = pathingWithoutRamp.GetConnected(SC2Util.To2D(StartLocation)); if (Tyr.Bot.MyRace == Race.Protoss) { DetermineWall(ramp, unPathable); } WallDistances = Distances(unPathable); stopWatch.Stop(); System.Console.WriteLine("Total time to find wall: " + stopWatch.ElapsedMilliseconds); /* * System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, height); * for (int x = 0; x < width; x++) * for (int y = 0; y < height; y++) * { * if (WallDistances[x, y] == 0) * bmp.SetPixel(x, height - 1 - y, System.Drawing.Color.Red); * else if (WallDistances[x, y] >= 25) * bmp.SetPixel(x, height - 1 - y, System.Drawing.Color.Green); * else * bmp.SetPixel(x, height - 1 - y, System.Drawing.Color.FromArgb(WallDistances[x, y] * 10, WallDistances[x, y] * 10, WallDistances[x, y] * 10)); * } * foreach (BaseLocation loc in BaseLocations) * for (int dx = -2; dx <= 2; dx++) * for (int dy = -2; dy <= 2; dy++) * bmp.SetPixel((int)loc.Pos.X + dx, height - 1 - (int)loc.Pos.Y - dy, System.Drawing.Color.Blue); * * foreach (Unit unit in tyr.Observation.Observation.RawData.Units) * { * if (UnitTypes.GasGeysers.Contains(unit.UnitType)) * for (int dx = -1; dx <= 1; dx++) * for (int dy = -1; dy <= 1; dy++) * bmp.SetPixel((int)unit.Pos.X + dx, height - 1 - (int)unit.Pos.Y - dy, System.Drawing.Color.Cyan); * if (UnitTypes.MineralFields.Contains(unit.UnitType)) * for (int dx = 0; dx <= 1; dx++) * bmp.SetPixel((int)(unit.Pos.X - 0.5f) + dx, height - 1 - (int)(unit.Pos.Y - 0.5f), System.Drawing.Color.Cyan); * } * bmp.Save(@"C:\Users\Simon\Desktop\WallDistances.png"); */ }
public void Analyze(Tyr tyr) { // Determine the start location. foreach (Unit unit in tyr.Observation.Observation.RawData.Units) { if (unit.Owner == tyr.PlayerId && UnitTypes.ResourceCenters.Contains(unit.UnitType)) { StartLocation = unit.Pos; } } List <MineralField> mineralFields = new List <MineralField>(); foreach (Unit mineralField in tyr.Observation.Observation.RawData.Units) { if (UnitTypes.MineralFields.Contains(mineralField.UnitType)) { mineralFields.Add(new MineralField() { Pos = mineralField.Pos, Tag = mineralField.Tag }); } } // The Units provided in our observation are not guaranteed to be in the same order every game. // To ensure the base finding algorithm finds the same base location every time we sort the mineral fields by position. mineralFields.Sort((a, b) => (int)(2 * (a.Pos.X + a.Pos.Y * 10000 - b.Pos.X - b.Pos.Y * 10000))); Dictionary <ulong, int> mineralSetIds = new Dictionary <ulong, int>(); List <List <MineralField> > mineralSets = new List <List <MineralField> >(); int currentSet = 0; foreach (MineralField mineralField in mineralFields) { if (mineralSetIds.ContainsKey(mineralField.Tag)) { continue; } BaseLocation baseLocation = new BaseLocation(); BaseLocations.Add(baseLocation); mineralSetIds.Add(mineralField.Tag, currentSet); baseLocation.MineralFields.Add(mineralField); for (int i = 0; i < baseLocation.MineralFields.Count; i++) { MineralField mineralFieldA = baseLocation.MineralFields[i]; foreach (MineralField closeMineralField in mineralFields) { if (mineralSetIds.ContainsKey(closeMineralField.Tag)) { continue; } if (SC2Util.DistanceSq(mineralFieldA.Pos, closeMineralField.Pos) <= 4 * 4) { mineralSetIds.Add(closeMineralField.Tag, currentSet); baseLocation.MineralFields.Add(closeMineralField); } } } currentSet++; } List <Gas> gasses = new List <Gas>(); foreach (Unit unit in tyr.Observation.Observation.RawData.Units) { if (UnitTypes.GasGeysers.Contains(unit.UnitType)) { gasses.Add(new Gas() { Pos = unit.Pos, Tag = unit.Tag }); } } // The Units provided in our observation are not guaranteed to be in the same order every game. // To ensure the base finding algorithm finds the same base location every time we sort the gasses by position. gasses.Sort((a, b) => (int)(2 * (a.Pos.X + a.Pos.Y * 10000 - b.Pos.X - b.Pos.Y * 10000))); foreach (BaseLocation loc in BaseLocations) { DetermineFinalLocation(loc, gasses); } if (tyr.GameInfo.MapName.Contains("Blueshift")) { foreach (BaseLocation loc in BaseLocations) { if (SC2Util.DistanceSq(loc.Pos, SC2Util.Point(141.5f, 112.5f)) <= 5 * 5 && (loc.Pos.X != 141.5 || loc.Pos.Y != 112.5)) { DebugUtil.WriteLine("Incorrect base location, fixing: " + loc.Pos); loc.Pos = SC2Util.Point(141.5f, 112.5f); } else if (SC2Util.DistanceSq(loc.Pos, SC2Util.Point(34.5f, 63.5f)) <= 5 * 5 && (loc.Pos.X != 34.5 || loc.Pos.Y != 63.5)) { DebugUtil.WriteLine("Incorrect base location, fixing: " + loc.Pos); loc.Pos = SC2Util.Point(34.5f, 63.5f); } } } Stopwatch stopWatch = Stopwatch.StartNew(); int width = Tyr.Bot.GameInfo.StartRaw.MapSize.X; int height = Tyr.Bot.GameInfo.StartRaw.MapSize.Y; Placement = new ImageBoolGrid(tyr.GameInfo.StartRaw.PlacementGrid); StartArea = Placement.GetConnected(SC2Util.To2D(StartLocation)); ArrayBoolGrid startLocations = new ArrayBoolGrid(Placement.Width(), Placement.Height()); foreach (Point2D startLoc in Tyr.Bot.GameInfo.StartRaw.StartLocations) { for (int x = -2; x <= 2; x++) { for (int y = -2; y <= 2; y++) { startLocations[(int)startLoc.X + x, (int)startLoc.Y + y] = true; } } } for (int x = -2; x <= 2; x++) { for (int y = -2; y <= 2; y++) { startLocations[(int)StartLocation.X + x, (int)StartLocation.Y + y] = true; } } BoolGrid unPathable; if (Tyr.Bot.OldMapData) { unPathable = new ImageBoolGrid(Tyr.Bot.GameInfo.StartRaw.PathingGrid).GetAnd(startLocations.Invert()); Pathable = unPathable.Invert(); } else { Pathable = new ImageBoolGrid(Tyr.Bot.GameInfo.StartRaw.PathingGrid).GetOr(startLocations); unPathable = Pathable.Invert(); } BoolGrid chokes = Placement.Invert().GetAnd(Pathable); BoolGrid mainExits = chokes.GetAdjacent(StartArea); enemyDistances = EnemyDistances; int dist = 1000; Point2D mainRamp = null; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (mainExits[x, y]) { int newDist = enemyDistances[x, y]; if (newDist < dist) { dist = newDist; mainRamp = SC2Util.Point(x, y); } } } } Ramp = chokes.GetConnected(mainRamp); BoolGrid pathingWithoutRamp = Pathable.GetAnd(Ramp.Invert()); MainAndPocketArea = pathingWithoutRamp.GetConnected(SC2Util.To2D(StartLocation)); if (Tyr.Bot.MyRace == Race.Protoss) { DetermineWall(Ramp, unPathable); } WallDistances = Distances(unPathable); stopWatch.Stop(); DebugUtil.WriteLine("Total time to find wall: " + stopWatch.ElapsedMilliseconds); }