public BoolGrid Invert() { BoolGrid result = Clone(); result.Inverted = true; return(result); }
private BoolGrid Placable(BoolGrid around, BoolGrid shrunkenStart) { ArrayBoolGrid result = new ArrayBoolGrid(around.Width(), around.Height()); for (int x = 0; x < around.Width(); x++) { for (int y = 0; y < around.Height(); y++) { if (around[x, y]) { for (int i = -2; i <= 2; i++) { if (shrunkenStart[x + i, y - 2]) { result[x + i, y - 2] = true; } if (shrunkenStart[x + i, y + 2]) { result[x + i, y + 2] = true; } if (shrunkenStart[x + 2, y + i]) { result[x + 2, y + i] = true; } if (shrunkenStart[x - 2, y + i]) { result[x - 2, y + i] = true; } } } } } return(result); }
private void check(BoolGrid pathingData, int[,] distances, Queue <Point2D> q, Point2D pos, int width, int height, int newVal) { if (check(pathingData, pos, width, height) && distances[(int)pos.X, (int)pos.Y] == 1000000000) { q.Enqueue(pos); distances[(int)pos.X, (int)pos.Y] = newVal; } }
public ArrayBoolGrid(BoolGrid other) { data = new bool[other.Width(), other.Height()]; for (int x = 0; x < Width(); x++) { for (int y = 0; y < Height(); y++) { this[x, y] = other[x, y]; } } }
public BoolGrid GetAnd(BoolGrid other) { ArrayBoolGrid result = new ArrayBoolGrid(Width(), Height()); for (int x = 0; x < Width(); x++) { for (int y = 0; y < Height(); y++) { result[x, y] = this[x, y] && other[x, y]; } } return(result); }
public BoolGrid GetAdjacent(BoolGrid other) { ArrayBoolGrid result = new ArrayBoolGrid(Width(), Height()); for (int x = 0; x < Width(); x++) { for (int y = 0; y < Height(); y++) { result[x, y] = this[x, y] && (other[x + 1, y] || other[x - 1, y] || other[x, y + 1] || other[x, y - 1]); } } return(result); }
public BoolGrid GetConnected(BoolGrid connectedTo, int steps) { ArrayBoolGrid result = new ArrayBoolGrid(Width(), Height()); Queue <Point2D> q1 = new Queue <Point2D>(); for (int x = 0; x < Width(); x++) { for (int y = 0; y < Height(); y++) { if (connectedTo[x, y]) { q1.Enqueue(SC2Util.Point(x, y)); } } } Queue <Point2D> q2 = new Queue <Point2D>(); for (int i = 0; i < steps; i++) { while (q1.Count > 0) { Point2D cur = q1.Dequeue(); if (cur.X < 0 || cur.Y < 0 || cur.X >= Width() || cur.Y >= Height()) { continue; } if (Get(cur) && !result[cur]) { result[cur] = true; q2.Enqueue(SC2Util.Point(cur.X + 1, cur.Y)); q2.Enqueue(SC2Util.Point(cur.X - 1, cur.Y)); q2.Enqueue(SC2Util.Point(cur.X, cur.Y + 1)); q2.Enqueue(SC2Util.Point(cur.X, cur.Y - 1)); } } q1 = q2; q2 = new Queue <Point2D>(); } return(result); }
public BoolGrid FindMainAndNaturalArea(WallInCreator wall) { ArrayBoolGrid pathable = new ArrayBoolGrid(Pathable); foreach (WallBuilding building in wall.Wall) { for (float dx = building.Pos.X - building.Size.X / 2f; dx <= building.Pos.X + building.Size.X / 2f; dx++) { for (float dy = building.Pos.Y - building.Size.Y / 2f; dy <= building.Pos.Y + building.Size.Y / 2f; dy++) { pathable[(int)dx, (int)dy] = false; } } } BoolGrid result = pathable.GetConnected(SC2Util.To2D(StartLocation)); //DrawGrid(result, "MainAndNatural.png"); return(result); }
public int[,] Distances(BoolGrid start) { int width = Bot.Main.GameInfo.StartRaw.MapSize.X; int height = Bot.Main.GameInfo.StartRaw.MapSize.Y; int[,] distances = new int[width, height]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { distances[x, y] = 1000000000; } } Queue <Point2D> q = new Queue <Point2D>(); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (start[x, y]) { distances[x, y] = 0; q.Enqueue(SC2Util.Point(x, y)); } } } while (q.Count > 0) { Point2D cur = q.Dequeue(); check(Pathable, distances, q, SC2Util.Point(cur.X + 1, cur.Y), width, height, distances[(int)cur.X, (int)cur.Y] + 1); check(Pathable, distances, q, SC2Util.Point(cur.X - 1, cur.Y), width, height, distances[(int)cur.X, (int)cur.Y] + 1); check(Pathable, distances, q, SC2Util.Point(cur.X, cur.Y + 1), width, height, distances[(int)cur.X, (int)cur.Y] + 1); check(Pathable, distances, q, SC2Util.Point(cur.X, cur.Y - 1), width, height, distances[(int)cur.X, (int)cur.Y] + 1); } return(distances); }
private bool check(BoolGrid pathingData, Point2D pos, int width, int height) { if (pos.X < 0 || pos.X >= width || pos.Y < 0 || pos.Y >= height) { return(false); } if (pathingData[pos]) { return(true); } foreach (Point2D p in Bot.Main.GameInfo.StartRaw.StartLocations) { if (SC2Util.DistanceGrid(pos, p) <= 3) { return(true); } } if (SC2Util.DistanceGrid(pos, StartLocation) <= 3) { return(true); } return(false); }
public Point2D GetEnemyRamp() { if (EnemyRamp != null) { return(EnemyRamp); } if (Bot.Main.TargetManager.PotentialEnemyStartLocations.Count != 1) { return(null); } int width = Bot.Main.GameInfo.StartRaw.MapSize.X; int height = Bot.Main.GameInfo.StartRaw.MapSize.Y; Point2D start = Bot.Main.TargetManager.PotentialEnemyStartLocations[0]; BoolGrid enemyStartArea = Placement.GetConnected(start); BoolGrid chokes = Placement.Invert().GetAnd(Pathable); BoolGrid mainExits = chokes.GetAdjacent(enemyStartArea); int[,] startDistances = Distances(SC2Util.To2D(StartLocation)); 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 = startDistances[x, y]; FileUtil.Debug("Ramp distance: " + newDist); if (newDist < dist) { dist = newDist; mainRamp = SC2Util.Point(x, y); } } } } BoolGrid enemyRamp = chokes.GetConnected(mainRamp); float totalX = 0; float totalY = 0; float count = 0; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (enemyRamp[x, y]) { totalX += x; totalY += y; count++; } } } EnemyRamp = new Point2D() { X = totalX / count, Y = totalY / count }; return(EnemyRamp); }
private void DetermineWall(BoolGrid ramp, BoolGrid unPathable) { BoolGrid rampAdjacent = unPathable.GetAdjacent(ramp); BoolGrid rampSides = unPathable.GetConnected(rampAdjacent, 5); List <BoolGrid> sides = rampSides.GetGroups(); BoolGrid shrunkenStart = StartArea.Shrink(); List <Point2D> building1Positions = Placable(sides[0], shrunkenStart).ToList(); List <Point2D> building2Positions = Placable(sides[1], shrunkenStart).ToList(); float wallScore = 1000; foreach (Point2D p1 in building1Positions) { foreach (Point2D p2 in building2Positions) { if (System.Math.Abs(p1.X - p2.X) < 3 && System.Math.Abs(p1.Y - p2.Y) < 3) { continue; } float newScore = SC2Util.DistanceGrid(p1, p2); if (newScore >= wallScore) { continue; } for (float i = -2.5f; i < 3; i++) { if (CheckPylon(SC2Util.Point(p1.X + 2.5f, p1.Y + i), p1, p2)) { wallScore = newScore; building1 = p1; building2 = p2; building3 = SC2Util.Point(p1.X + 2.5f, p1.Y + i); } if (CheckPylon(SC2Util.Point(p1.X - 2.5f, p1.Y + i), p1, p2)) { wallScore = newScore; building1 = p1; building2 = p2; building3 = SC2Util.Point(p1.X - 2.5f, p1.Y + i); } if (CheckPylon(SC2Util.Point(p1.X + i, p1.Y + 2.5f), p1, p2)) { wallScore = newScore; building1 = p1; building2 = p2; building3 = SC2Util.Point(p1.X + i, p1.Y + 2.5f); } if (CheckPylon(SC2Util.Point(p1.X + i, p1.Y - 2.5f), p1, p2)) { wallScore = newScore; building1 = p1; building2 = p2; building3 = SC2Util.Point(p1.X + i, p1.Y - 2.5f); } } } } }
public void Analyze(Bot bot) { // Determine the start location. foreach (Unit unit in bot.Observation.Observation.RawData.Units) { if (unit.Owner == bot.PlayerId && UnitTypes.ResourceCenters.Contains(unit.UnitType)) { StartLocation = unit.Pos; } } List <MineralField> mineralFields = new List <MineralField>(); foreach (Unit mineralField in bot.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 bot.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 (bot.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 = Bot.Main.GameInfo.StartRaw.MapSize.X; int height = Bot.Main.GameInfo.StartRaw.MapSize.Y; Placement = new ImageBoolGrid(bot.GameInfo.StartRaw.PlacementGrid); StartArea = Placement.GetConnected(SC2Util.To2D(StartLocation)); ArrayBoolGrid startLocations = new ArrayBoolGrid(Placement.Width(), Placement.Height()); foreach (Point2D startLoc in Bot.Main.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 (Bot.Main.OldMapData) { unPathable = new ImageBoolGrid(Bot.Main.GameInfo.StartRaw.PathingGrid).GetAnd(startLocations.Invert()); Pathable = unPathable.Invert(); } else { Pathable = new ImageBoolGrid(Bot.Main.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 (Bot.Main.MyRace == Race.Protoss) { DetermineWall(Ramp, unPathable); } WallDistances = Distances(unPathable); stopWatch.Stop(); DebugUtil.WriteLine("Total time to find wall: " + stopWatch.ElapsedMilliseconds); }