public static LinkedList<Point> GetWalkingSteps(Point start, BitArray goals, bool walkInWater = false, bool nearbyOk = false) { Bb.ReadBoard(); if (!goals.ToPoints().Any()) { return null; } Point[] starts = { start }; var passable = Solver.GetPassable(true); var aStarPassable = new BitArray(passable); aStarPassable.Set(start, true); if (nearbyOk) { aStarPassable.Or(goals); } Func<Point, Point, int> cost = (c, n) => (Bb.Water.Get(n) && !walkInWater) ? 10 : 1; var route = Pather.AStar(starts, p => goals.Get(p), aStarPassable, cost, p => 0); if (route == null) { return null; } var steps = new LinkedList<Point>(route); steps.RemoveFirst(); if (steps.Count > 0 && !passable.Get(steps.Last.Value)) { steps.RemoveLast(); } return steps; }
public static void ReadBoard() { if (!init) { throw new Exception("Must call Init(AI ai) before using ReadBoard()"); } Reset(); tileLookup = BaseAI.tiles.ToDictionary(t => t.ToPoint()); foreach (Tile tile in BaseAI.tiles) { int offset = GetOffset(tile.X, tile.Y); Point point = new Point(tile.X, tile.Y); // IsSpawning if (tile.IsSpawning) { IsSpawning[offset] = true; } // Glaciers if (tile.Depth == 0 && tile.WaterAmount > 0 && tile.Owner == 3) { Glaciers[offset] = true; GlaciersSet.Add(point); } // Trenches if (tile.Depth > 0 && tile.WaterAmount == 0) { Trenches[offset] = true; } // Water if (tile.Depth > 0 && tile.WaterAmount > 0) { Water[offset] = true; } // Our Spawns if (tile.Owner == usId && tile.PumpID == -1) { OurSpawns[offset] = true; OurSpawnSet.Add(point); } // Their Spawns if (tile.Owner == themId && tile.PumpID == -1) { TheirSpawns[offset] = true; TheirSpawnSet.Add(point); } // Our Pumps if (tile.Owner == usId && tile.PumpID != -1) { OurPumps[offset] = true; } // Their Pumps if (tile.Owner == themId && tile.PumpID != -1) { TheirPumps[offset] = true; } // Neutral Pumps if (tile.Owner == 2 && tile.PumpID != -1) { NeutralPumps[offset] = true; } } // Units foreach (Unit unit in BaseAI.units) { Point point = new Point(unit.X, unit.Y); int offset = GetOffset(point); // Our Units if (unit.Owner == usId) { OurUnits[offset] = true; OurUnitsSet.Add(unit); switch (unit.Type) { case 0: OurWorkersSet.Add(unit); break; case 1: OurScoutsSet.Add(unit); break; case 2: OurTanksSet.Add(unit); break; } } // Their Units if (unit.Owner == themId) { TheirUnits[offset] = true; TheirUnitsSet.Add(unit); switch (unit.Type) { case 0: TheirWorkersSet.Add(unit); break; case 1: TheirScoutsSet.Add(unit); break; case 2: TheirTanksSet.Add(unit); break; } } } var pumps = new BitArray(OurPumps).Or(TheirPumps).Or(NeutralPumps); var pumpLookup = BaseAI.pumpStations.ToDictionary(p => p.Id); foreach (var p in pumps.ToPoints()) { var tile = tileLookup[p]; if (!pumpLookup.ContainsKey(tile.PumpID)) { continue; } var ps = pumpLookup[tile.PumpID]; pumpLookup.Remove(ps.Id); var pump = new Pump(ps, p); if (pump.station.SiegeAmount > 0) { UnderSiege[GetOffset(pump.SW.x, pump.SW.y)] = true; UnderSiege[GetOffset(pump.NW.x, pump.NW.y)] = true; UnderSiege[GetOffset(pump.SE.x, pump.SE.y)] = true; UnderSiege[GetOffset(pump.NE.x, pump.NE.y)] = true; } if (tile.Owner == usId) { OurPumpSet.Add(pump); } else if (tile.Owner == themId) { TheirPumpSet.Add(pump); } else { NeutralPumpSet.Add(pump); } } pumpPointLookup = OurPumpSet.Union(TheirPumpSet).Union(NeutralPumpSet) .SelectMany(pump => pump.GetPoints().Select(point => new { ump = pump, oint = point })) .ToDictionary(a => a.oint, a => a.ump); }
public static void MoveFarthestAndAttack(Droid attacker, BitArray targets) { if (attacker.AttacksLeft == 0) { return; } var liveTargets = targets.ToPoints().Where(p => Bb.DroidLookup[p].HealthLeft > 0); Func<Point, bool> patherPassable = p => IsPassable(p) || p.Equals(attacker.ToPoint()); var movementSearch = new Pather.Search(new Point[] { attacker.ToPoint() }, patherPassable, p => false, (p1, p2) => 1, attacker.MovementLeft); var walkables = movementSearch.GScore.Keys.Where(p => movementSearch.GScore[p] <= attacker.MovementLeft); var walkablesWithTargets = walkables.Where(p => liveTargets.Any(t => p.IsInRange(attacker.Range, t))); Console.WriteLine("MoveFarthestAndAttack " + attacker.ToPoint()); Console.WriteLine("Walkables: " + walkables.Count()); Console.WriteLine("WalkablesWithTargets: " + walkablesWithTargets.Count()); if (walkablesWithTargets.Any()) { var walkTo = walkablesWithTargets.MaxBy(p => movementSearch.GScore[p]); var path = Pather.ConstructPath(movementSearch.CameFrom, walkTo); foreach (var step in path.Skip(1)) { Console.WriteLine("Move {0} -> {1}", attacker.ToPoint(), step); attacker.move(step.x, step.y); } var target = liveTargets.First(t => attacker.IsInRange(t)); attacker.operate(target.x, target.y); } }
public static void MoveAndAttack(Droid attacker, BitArray targets) { Bb.ReadBoard(); if (attacker.AttacksLeft <= 0) { return; } BitArray validTargets; if ((Unit)attacker.Variant == Unit.HACKER) { validTargets = targets.ToPoints().Where(t => t.IsHackable()).ToBitArray(); } else if ((Unit)attacker.Variant == Unit.REPAIRER) { validTargets = targets.ToPoints().Where(t => t.IsRepairable()).ToBitArray(); } else { validTargets = targets.ToPoints().Where(t => t.IsAttackable()).ToBitArray(); if (Bb.KillHangerCountDown > 0) { validTargets = validTargets.ToPoints().Where(t => { var droid = Bb.DroidLookup[t]; return !((Unit)droid.Variant == Unit.HANGAR && droid.HealthLeft <= attacker.Attack); }).ToBitArray(); } } Func<Point, bool> patherPassable = p => IsPassable(p) || p.Equals(attacker.ToPoint()) || validTargets.Get(p); var path = Pather.AStar(new[] { attacker.ToPoint() }, patherPassable, validTargets.ToFunc()); if (path == null) { return; } if (path.Count() < 2) { Console.WriteLine("Bad path from attacker " + attacker.Id); } MoveAndAttack(attacker, path.Skip(1)); }
public static IEnumerable<Point> Reach(Point start, BitArray targets, BitArray passable) { var open = new Queue<Point>(); open.Enqueue(start); var closed = new HashSet<Point>(); var targetSet = new HashSet<Point>(targets.ToPoints()); var reach = new HashSet<Point>(); while (open.Count > 0) { Point current = open.Dequeue(); closed.Add(current); if (targets.Get(current)) { reach.Add(current); if (reach.Count == targetSet.Count) { break; } } foreach (var n in GetNeighbors(current, passable)) { if (!closed.Contains(n)) { open.Enqueue(n); } } } return reach; }