public List <ProjectilePathSegment> Emulate(ACombatUnit[] nearestUnits, double wizardsChangeAngle) { nearestUnits = nearestUnits.Select(Utility.CloneCombat).ToArray(); var minionsTargetsSelector = new TargetsSelector(nearestUnits) { EnableMinionsCache = true }; return(_emulate(nearestUnits, wizardsChangeAngle, minionsTargetsSelector)); }
MovingInfo _findCastTarget2(AWizard self, Point moveTo, ProjectileType projectileType) { var move = new FinalMove(new Move()); if (projectileType == ProjectileType.MagicMissile) { AUnit mmSelTarget = null; Point mmSelFirstMoveTo = null; var mmMinTicks = int.MaxValue; double mmMinPriority = int.MaxValue; foreach (var opp in OpponentCombats) { if (self.GetDistanceTo2(opp) > Geom.Sqr(self.CastRange + opp.Radius + 40) || !opp.IsAssailable) { continue; } var nearest = Combats .Where(x => self.GetDistanceTo2(x) < Geom.Sqr(Math.Max(x.VisionRange, self.VisionRange) * 1.3)) .Select(Utility.CloneCombat) .ToArray(); var targetsSelector = new TargetsSelector(nearest) { EnableMinionsCache = true }; var nearstOpponents = nearest .Where(x => x.IsOpponent) .ToArray(); var canHitNow = opp.EthalonCanHit(self, checkCooldown: !(opp is AWizard)); var ticks = 0; var my = nearest.FirstOrDefault(x => x.Id == self.Id) as AWizard; var his = nearest.FirstOrDefault(x => x.Id == opp.Id); if (my == null || his == null) { continue; } Point firstMoveTo = null; var buildingsHit = false; while (!my.EthalonCanCastMagicMissile(his, checkCooldown: false)) { if (ticks > 40) { break; } var m = moveTo; var stopIfCannotMove = true; if (m == null && my.EthalonCanCastMagicMissile(his, checkCooldown: false, checkAngle: false)) { stopIfCannotMove = false; m = my + (my - his); var tmp = new AWizard(my); tmp.MoveTo(m, his, w => !CheckIntersectionsAndTress(w, nearest)); if (EstimateDanger(my, false) <= EstimateDanger(tmp, false)) { m = null; } } if (m == null) { m = his; } if (ticks == 0) { firstMoveTo = m; } if (!my.MoveTo(m, his, w => !CheckIntersectionsAndTress(w, nearest)) && Utility.PointsEqual(m, his) && stopIfCannotMove) { break; } foreach (var x in nearest) { if (x.Id == my.Id) { continue; } var tar = targetsSelector.Select(x); buildingsHit = buildingsHit || (x.IsOpponent && x is ABuilding && tar != null && tar.Id == my.Id && x.EthalonCanHit(my)); if (x.IsOpponent) { x.EthalonMove(tar ?? my); } else if (tar != null) { x.EthalonMove(tar); } else { x.SkipTick(); } } ticks++; } if (his is AWizard && (his as AWizard).IsBesieded) { ticks -= 15; // чтобы дать больше приоритета визарду } var priority = GetCombatPriority(self, his); if (ticks < mmMinTicks || ticks == mmMinTicks && priority < mmMinPriority) { if (my.EthalonCanCastMagicMissile(his)) { if (nearstOpponents.All(x => { if (canHitNow && x.Id == opp.Id) // он и так доставал { return(true); } if (!x.EthalonCanHit(my) && (!(x is ABuilding) || !buildingsHit)) { return(true); } if (his.Id == x.Id && CanRush(my, x)) { return(true); } var target = targetsSelector.Select(x); if (target != null && target.Id != my.Id) { return(true); } return(false); }) ) { mmMinTicks = ticks; mmMinPriority = priority; mmSelTarget = opp; mmSelFirstMoveTo = firstMoveTo; } } } } if (mmSelTarget != null) { mmMinTicks = Math.Max(0, mmMinTicks); move.MoveTo(moveTo ?? mmSelFirstMoveTo, mmSelTarget); return(new MovingInfo(mmSelTarget, mmMinTicks, move) { TargetId = mmSelTarget.Id }); } } const int walkLimit = 9; if (projectileType == ProjectileType.Fireball && self.FireballSkillLevel == 5 && Math.Max(self.RemainingActionCooldownTicks, self.RemainingFireballCooldownTicks) <= walkLimit) { var fbMaxDamage = 0.0; Point fbSelTarget = null; var fbMinTicks = int.MaxValue; foreach (var ang in Utility.Range(-Game.StaffSector, Game.StaffSector, 10)) { var nearest = Combats .Where(x => self.GetDistanceTo2(x) < Geom.Sqr(Math.Max(x.VisionRange, self.VisionRange) * 1.3)) .Select(Utility.CloneCombat) .ToArray(); var targetsSelector = new TargetsSelector(nearest) { EnableMinionsCache = true }; var ticks = 0; var my = nearest.FirstOrDefault(x => x.Id == self.Id) as AWizard; var dir = my + Point.ByAngle(my.Angle + ang) * 1000; while (ticks <= walkLimit) { if (my.CanUseFireball()) { var proj = new AProjectile(my, 0, ProjectileType.Fireball); var path = proj.Emulate(nearest, 0.0); var damage = path.Where(x => _isFireballGoodSeg(my, x)) .Select(x => x.OpponentDamage) .DefaultIfEmpty(0) .Max(); if (damage > fbMaxDamage) { fbMaxDamage = damage; fbSelTarget = dir; fbMinTicks = ticks; } } foreach (var x in nearest) { if (x.Id == my.Id) { continue; } if (x is AMinion) { x.EthalonMove(targetsSelector.Select(x)); } else { x.SkipTick(); } } if (!my.MoveTo(dir, dir, w => !CheckIntersectionsAndTress(w, nearest))) { break; } if (nearest.Any(x => x.IsOpponent && x is ABuilding && x.EthalonCanHit(my) && targetsSelector.Select(x) == my)) { break; } ticks++; } } if (fbSelTarget != null) { move.MoveTo(fbSelTarget, fbSelTarget); return(new MovingInfo(fbSelTarget, fbMinTicks, move) { Damage = fbMaxDamage }); } } return(new MovingInfo(null, int.MaxValue, move)); }
MovingInfo _findStaffTarget(AWizard self) { var potentialColliders = Combats .Where(x => x.Id != self.Id && self.GetDistanceTo2(x) < Geom.Sqr(Game.StaffRange * 6)) .ToArray(); int minTicks = int.MaxValue; var move = new FinalMove(new Move()); var attacked = self.GetStaffAttacked(potentialColliders).Cast <ACombatUnit>().ToArray(); ACircularUnit selTarget = attacked.FirstOrDefault(x => x.IsOpponent); if (selTarget != null) // если уже можно бить { move.Action = ActionType.Staff; return(new MovingInfo(selTarget, 0, move)); } if (self.MmSkillLevel == 5) { // т.к. стрелять можно без задержки // возможно, нужно сделать исключение, если прокачан посох return(new MovingInfo(null, int.MaxValue, move)); } Point selMoveTo = null; foreach (var opp in OpponentCombats) { var dist = self.GetDistanceTo(opp); if (dist > Game.StaffRange * 5 || !opp.IsAssailable) { continue; } var range = opp.Radius + Game.StaffRange; foreach (var delta in new[] { -range, -range / 2, 0, range / 2, range }) { var angle = Math.Atan2(delta, dist); var moveTo = self + (opp - self).Normalized().RotateClockwise(angle) * self.VisionRange; var nearstCombats = Combats .Where(x => x.GetDistanceTo(self) <= Math.Max(x.VisionRange, self.VisionRange) * 1.2) .Select(Utility.CloneCombat) .ToArray(); var targetsSelector = new TargetsSelector(nearstCombats) { EnableMinionsCache = true }; var nearstOpponents = nearstCombats.Where(x => x.IsOpponent).ToArray(); var my = nearstCombats.FirstOrDefault(x => x.Id == self.Id) as AWizard; var his = nearstCombats.FirstOrDefault(x => x.Id == opp.Id); var allowRush = opp is AFetish || opp is AWizard; var canHitNow = opp.EthalonCanHit(self, checkCooldown: !allowRush); var ticks = 0; var ok = true; var buildingsHit = false; while (ticks < (allowRush ? 65 : 35) && my.GetDistanceTo2(his) > Geom.Sqr(Game.StaffRange + his.Radius)) { foreach (var x in nearstOpponents) // свои как-бы стоят на месте { var tar = targetsSelector.Select(x); buildingsHit = buildingsHit || (x is ABuilding && tar != null && tar.Id == my.Id && x.EthalonCanHit(my)); x.EthalonMove(tar ?? my); } if (!my.MoveTo(moveTo, his, w => !CheckIntersectionsAndTress(w, potentialColliders))) { ok = false; break; } ticks++; } if (ok && !(opp is AOrc)) { while (Math.Abs(my.GetAngleTo(his)) > Game.StaffSector / 2) { my.MoveTo(null, his); foreach (var x in nearstOpponents) { var tar = targetsSelector.Select(x); buildingsHit = buildingsHit || (x is ABuilding && tar != null && tar.Id == my.Id && x.EthalonCanHit(my)); x.EthalonMove(tar ?? my); } ticks++; } } Func <ACombatUnit, bool> check = x => { if ((opp is AWizard) && (opp as AWizard).IsBesieded && !(x is ABuilding)) { return(true); } if (canHitNow && x.Id == opp.Id) // он и так доставал { return(true); } if (!x.EthalonCanHit(my) && (!(x is ABuilding) || !buildingsHit)) { return(true); } if (his.Id == x.Id && my.StaffDamage >= his.Life) { return(true); } var target = targetsSelector.Select(x); if (target != null && target.Id != my.Id) { return(true); } return(false); }; if (opp is AWizard) { ticks -= 5; if ((opp as AWizard).IsBesieded) { ticks -= 10; } } if (ok && ticks < minTicks) { if (my.CanStaffAttack(his)) { if (nearstOpponents.All(check)) { // успею-ли я вернуться обратно while (my.GetDistanceTo(self) > my.MaxForwardSpeed)//TODO:HACK { my.MoveTo(self, null); foreach (var x in nearstOpponents) { var tar = targetsSelector.Select(x); buildingsHit = buildingsHit || (x is ABuilding && tar != null && tar.Id == my.Id && x.EthalonCanHit(my)); if (tar != null) { x.EthalonMove(tar); } else { x.SkipTick(); } } } if (nearstOpponents.All(check)) { selTarget = opp; selMoveTo = moveTo; minTicks = ticks; } } } } } } if (selTarget != null) { bool angleOk = Math.Abs(self.GetAngleTo(selTarget)) <= Game.StaffSector / 2, distOk = self.GetDistanceTo2(selTarget) <= Geom.Sqr(Game.StaffRange + selTarget.Radius); if (!distOk) { move.MoveTo(selMoveTo, selTarget); } else if (!angleOk) { move.MoveTo(null, selTarget); } } return(new MovingInfo(selTarget, Math.Max(0, minTicks), move)); }
private List <ProjectilePathSegment> _emulate(ACombatUnit[] nearestUnits, double wizardsChangeAngle, TargetsSelector minionsTargetsSelector) { if (Type != ProjectileType.MagicMissile && Type != ProjectileType.FrostBolt && Type != ProjectileType.Fireball) { throw new Exception("Unsupported projectile type " + Type); } // NOTE: nearestUnits уже склонированы // NOTE: nearestUnits и они же в minionsTargetsSelector - одни и те же instance var list = new List <ProjectilePathSegment>(); var projectile = new AProjectile(this); var owner = nearestUnits.FirstOrDefault(x => x.Id == OwnerUnitId); var nearestCandidates = nearestUnits.Where(x => x.Id != OwnerUnitId).ToArray(); while (projectile.Exists) { projectile.Move(proj => { if (Type == ProjectileType.Fireball) { double selfDamage = 0; double oppDamage = 0; var selfBurned = 0; var oppBurned = 0; var selfDeads = 0; var oppDeads = 0; ACombatUnit importantTarget = null; foreach (var unit in nearestCandidates) { var damage = GetFireballDamage(proj, unit); if (damage > 0) { var deads = 0; if (damage >= unit.Life - Const.Eps) { // killed deads++; damage = unit.Life; } if (unit.Faction == proj.Faction) { if (unit is AWizard) { selfDamage += damage; selfBurned++; selfDeads += deads; } } else if (Utility.HasConflicts(proj, unit)) { oppDamage += damage; oppBurned++; oppDeads += deads; if (importantTarget == null || _targetImportance(unit) > _targetImportance(importantTarget)) { importantTarget = unit; } } } } if (owner != null) { var damage = GetFireballDamage(proj, owner); if (damage > 0) { selfBurned++; if (damage >= owner.Life - Const.Eps) { // killed selfDamage += owner.Life; selfDeads++; } else { selfDamage += damage; } } } list.Add(new ProjectilePathSegment { StartDistance = list.Count == 0 ? 0 : list.Last().EndDistance, EndDistance = list.Count == 0 ? 0 : list.Last().EndDistance, OpponentDamage = oppDamage, SelfDamage = selfDamage, OpponentDeadsCount = oppDeads, SelfDeadsCount = selfDeads, State = (selfDamage + oppDamage < Const.Eps) ? ProjectilePathState.Free : ProjectilePathState.Fireball, OpponentBurned = oppBurned, SelfBurned = selfBurned, Target = importantTarget, }); } else { var inter = proj.GetFirstIntersection(nearestCandidates); if (inter != null) { if (list.Count == 0 || list.Last().State != ProjectilePathState.Shot) { var opp = inter as ACombatUnit; list.Add(new ProjectilePathSegment { StartDistance = list.Count == 0 ? 0 : list.Last().EndDistance, EndDistance = list.Count == 0 ? 0 : list.Last().EndDistance, State = ProjectilePathState.Shot, Target = Utility.CloneCombat(opp), SelfDamage = proj.Faction == inter.Faction ? Math.Min(opp.Life, Damage) : 0, OpponentDamage = Utility.HasConflicts(proj, opp) ? Math.Min(opp.Life, Damage) : 0, }); } } else { if (list.Count == 0 || list.Last().State != ProjectilePathState.Free) { list.Add(new ProjectilePathSegment { StartDistance = list.Count == 0 ? 0 : list.Last().EndDistance, EndDistance = list.Count == 0 ? 0 : list.Last().EndDistance, State = ProjectilePathState.Free, }); } } } list.Last().EndDistance += proj.Speed / proj.MicroTicks; return(true); }); foreach (var unit in nearestCandidates) { if (unit is AWizard) { var wizard = unit as AWizard; var dir = (wizard - this).RotateClockwise(wizardsChangeAngle) + wizard; // вдоль снаряда wizard.MoveTo(dir, null, w => { var tree = TreesObserver.GetNearestTree(w); return((tree == null || !w.IntersectsWith(tree)) && wizard.GetFirstIntersection(nearestCandidates) == null); }); } else if (unit is AMinion) { var target = minionsTargetsSelector.Select(unit); unit.EthalonMove(target); } } } return(list); }
double _emulateRush(AWizard self, AWizard opp) { var nearest = Combats.Where(x => x.GetDistanceTo(ASelf) < ASelf.VisionRange * 1.4).Select(Utility.CloneCombat).ToArray(); self = nearest.FirstOrDefault(x => x.Id == self.Id) as AWizard; opp = nearest.FirstOrDefault(x => x.Id == opp.Id) as AWizard; if (self == null || opp == null) { return(int.MinValue); } var tergetsSelector = new TargetsSelector(nearest); if (opp.Id == _LastMmTarget && World.Projectiles.Any(x => x.OwnerUnitId == self.Id)) { opp.ApplyMagicalDamage(self.MagicMissileDamage); } while (true) { _rushTo(self, opp); foreach (var unit in nearest) { if (unit.Id == self.Id) { continue; } if (unit is AWizard) { if (unit.IsOpponent) { _rushTo(unit as AWizard, self); } else { if (Const.IsFinal) { _rushTo(unit as AWizard, opp); } else { unit.SkipTick(); } } } else if (unit is AMinion) { var tar = tergetsSelector.Select(unit); unit.EthalonMove(tar); if (tar != null && unit.EthalonCanHit(tar)) { if (unit is AFetish) { unit.RemainingActionCooldownTicks = Game.FetishBlowdartActionCooldownTicks - 1; tar.ApplyDamage(Game.DartDirectDamage); } else { unit.RemainingActionCooldownTicks = Game.OrcWoodcutterActionCooldownTicks - 1; tar.ApplyDamage(Game.OrcWoodcutterDamage); } } } } if (!self.IsAlive) { return(-opp.Life); } if (!opp.IsAlive) { var mines = nearest.Where(x => x.IsTeammate && x is AWizard).ToArray(); if (mines.Length >= 2 && Const.IsFinal) { if (!mines.All(x => x.Life > 10)) { return(int.MinValue); } return(50.0);//hack } else { if (nearest.Where(x => x.IsOpponent && x is AWizard).Sum(x => x.Life) > self.Life) { return(int.MinValue); } return(self.Life); } } } }
private void _move(Wizard self, World world, Game game, Move move) { World = world; Game = game; Self = self; FinalMove = new FinalMove(move); Const.Initialize(); MagicConst.TreeObstacleWeight = Const.IsFinal ? 25 : 35; Wizards = world.Wizards .Select(x => new AWizard(x)) .ToArray(); foreach (var wizard in Wizards) { foreach (var other in Wizards) { if (wizard.Faction != other.Faction) { continue; } if (wizard.GetDistanceTo2(other) > Geom.Sqr(Game.AuraSkillRange)) { continue; } for (var i = 0; i < 5; i++) { wizard.AurasFactorsArr[i] = Math.Max(wizard.AurasFactorsArr[i], other.SkillsLearnedArr[i] / 2); } } var orig = World.Wizards.FirstOrDefault(w => w.Id == wizard.Id); var player = World.Players.FirstOrDefault(p => orig != null && p.Id == orig.OwnerPlayerId); if (player != null && player.IsStrategyCrashed) { wizard.RemainingFrozen = 100500; } } OpponentWizards = Wizards .Where(x => x.IsOpponent) .ToArray(); MyWizards = Wizards .Where(x => x.IsTeammate) .ToArray(); Minions = world.Minions .Select(x => x.Type == MinionType.OrcWoodcutter ? (AMinion) new AOrc(x) : new AFetish(x)) .ToArray(); NeutralMinions = Minions .Where(x => x.Faction == Faction.Neutral) .ToArray(); Combats = Minions.Cast <ACombatUnit>() .Concat(Wizards) .Concat(BuildingsObserver.Buildings)//TODO перед BuildingsObserver.Update???? .ToArray(); MyCombats = Combats .Where(x => x.IsTeammate) .ToArray(); NeutralMinionsObserver.Update(); OpponentMinions = Minions .Where(x => x.IsOpponent) .ToArray(); OpponentCombats = Combats .Where(x => x.IsOpponent) .ToArray(); RoadsHelper.Initialize(); BuildingsObserver.Update(); OpponentBuildings = BuildingsObserver.Buildings .Where(x => x.IsOpponent) .ToArray(); TreesObserver.Update(); ProjectilesObserver.Update(); BonusesObserver.Update(); MessagesObserver.Update(); InitializeProjectiles(); InitializeDijkstra(); ASelf = Wizards.FirstOrDefault(x => x.Id == Self.Id); if (ASelf == null) { throw new Exception("Self not found in wizards list"); } InitializeDangerEstimation(); SupportObserver.Update(); if (Self.IsMaster && World.TickIndex == 0) { MasterSendMessages(); } if (Self.IsMaster) { MasterCheckRearrange(); } var nearestBonus = BonusesObserver.Bonuses.ArgMin(b => b.GetDistanceTo(ASelf)); var opponentsAroundBonus = OpponentWizards.Where(w => nearestBonus.GetDistanceTo(w) < ASelf.VisionRange * 1.5).ToArray(); var teammatesAroundBonus = MyWizards.Where(w => ASelf.GetDistanceTo(w) < ASelf.VisionRange * 1.5).ToArray(); WizardPath path = null; AUnit pathTarget = null; var goAway = GoAwayDetect(); var bonusMoving = goAway ? new MovingInfo(null, int.MaxValue, null) : GoToBonus(); var target = FindTarget(new AWizard(ASelf), bonusMoving.Target); if (target == null && bonusMoving.Target == null && !goAway) { var nearest = OpponentCombats .Where( x => Utility.IsBase(x) || RoadsHelper.GetLane(x) == MessagesObserver.GetLane() || RoadsHelper.GetLaneEx(ASelf) == ALaneType.Middle && RoadsHelper.GetLaneEx(x) == ALaneType.Middle && CanRush(ASelf, x)) .Where(x => x.IsAssailable && x.Faction != Faction.Neutral) .OrderBy( x => x.GetDistanceTo(self) + (x is AWizard ? -40 : (x is ABuilding && !((ABuilding)x).IsBesieded) ? 1500 : 0)) .ToArray(); foreach (var n in nearest) { path = GoAgainst(n); if (path != null) { pathTarget = n; break; } } if (nearest.Length > 0 && path == null) { GoDirect(nearest[0], FinalMove); } } TimerStart(); if (!TryDodgeProjectile()) { if (target == null) { TryPreDodgeProjectile(); } if (goAway) { GoAway(); } else if (target == null || target.Type == TargetType.Teammate || (FinalMove.Action == ActionType.Staff || FinalMove.Action == ActionType.MagicMissile || FinalMove.Action == ActionType.Fireball || FinalMove.Action == ActionType.FrostBolt) && target.Type == TargetType.Opponent) { if (bonusMoving.Target != null) { NextBonusWaypoint = bonusMoving.Target; FinalMove.Turn = bonusMoving.Move.Turn; if (bonusMoving.Move.Action != ActionType.None && bonusMoving.Move.Action != null) { FinalMove.Action = bonusMoving.Move.Action; FinalMove.MinCastDistance = bonusMoving.Move.MinCastDistance; FinalMove.MaxCastDistance = bonusMoving.Move.MaxCastDistance; FinalMove.CastAngle = bonusMoving.Move.CastAngle; } NextBonusWaypoint = ASelf + (NextBonusWaypoint - ASelf).Normalized() * (Self.Radius + 30); if (nearestBonus.GetDistanceTo(ASelf) < ASelf.VisionRange * 1.5 && nearestBonus.GetDistanceTo(ASelf) > 100 && opponentsAroundBonus.Length <= 1 && ASelf.Life + 10 >= (opponentsAroundBonus.FirstOrDefault() ?? ASelf).Life && OpponentMinions.Count(x => x.GetDistanceTo(ASelf) < Game.FetishBlowdartAttackRange) == 0 ) { FinalMove.MoveTo(NextBonusWaypoint, null); } else { TryGoByGradient(x => EstimateDanger(x), null, FinalMove); } } else { var all = Combats.Select(Utility.CloneCombat).ToArray(); var my = all.FirstOrDefault(x => x.Id == ASelf.Id) as AWizard; my?.Move(FinalMove.Speed, FinalMove.StrafeSpeed); var ts = new TargetsSelector(all); var skipBuildings = path == null || path.GetLength() < 300 || path.GetLength() < 600 && OpponentBuildings.Any(x => { var tar = ts.Select(x); return(tar != null && tar.Id == ASelf.Id); }); if (TryGoByGradient(x => EstimateDanger(x), x => HasAnyTarget(x, skipBuildings), FinalMove)) { var cutTreeMovingInfo = FindTreeTarget(ASelf); if (cutTreeMovingInfo.Target != null) { FinalMove.Turn = cutTreeMovingInfo.Move.Turn; if (cutTreeMovingInfo.Move.Action != null && FinalMove.Action == null) { FinalMove.Action = cutTreeMovingInfo.Move.Action; } // не будет мешать TryPreDodgeProjectile? } } } } PostDodgeProjectile(); } TimerEndLog("Go", 1); if (ASelf.CanLearnSkill) { move.SkillToLearn = MessagesObserver.GetSkill(); } }
private bool _TryGoByGradient(Func <AWizard, double> costFunction, Func <AWizard, bool> firstMoveCondition, FinalMove move) { var self = new AWizard(ASelf); var obstacles = Combats.Where(x => x.Id != Self.Id && !(x is ABuilding)).Cast <ACircularUnit>() .Concat(BuildingsObserver.Buildings) .Where(x => self.GetDistanceTo2(x) < Geom.Sqr(x.Radius + 150)) .ToArray(); var danger = costFunction(self); // for debug List <double> selVec = null; var minDanger = double.MaxValue; Point selMoveTo = null; foreach (var angle in Utility.Range(self.Angle, Math.PI * 2 + self.Angle, 24, false)) { var moveTo = self + Point.ByAngle(angle) * self.VisionRange; var nearest = Combats .Where(x => x.GetDistanceTo(self) < Math.Max(self.VisionRange, x.VisionRange) * 1.3) .Select(Utility.CloneCombat) .ToArray(); var tergetsSelector = new TargetsSelector(nearest); var opponents = nearest.Where(x => x.IsOpponent).ToArray(); var vec = new List <double>(); const int steps = 18; var my = (AWizard)nearest.FirstOrDefault(x => x.Id == self.Id); var ok = true; var canMove = true; while (vec.Count < steps) { if (canMove) { canMove = my.MoveTo(moveTo, null, w => w.GetFirstIntersection(obstacles) == null); if (TreesObserver.GetNearestTrees(my).Any(t => t.IntersectsWith(my))) { break; } } else { my.SkipTick(); } var tmp = OpponentCombats;//HACK OpponentCombats = opponents; vec.Add(costFunction(my)); OpponentCombats = tmp; foreach (var x in opponents) { var tar = tergetsSelector.Select(x); if (tar != null || x is AWizard) { x.EthalonMove(tar); } } if (vec.Count == 1 && firstMoveCondition != null && !firstMoveCondition(my)) { ok = false; break; } } if (!ok || vec.Count == 0) { continue; } while (vec.Count < steps) { vec.Add(CantMoveDanger); } var newDanger = 0.0; for (var k = 0; k < steps; k++) { newDanger += vec[k] * Math.Pow(0.87, k); } newDanger += 3 * vec[0]; if (newDanger < minDanger) { minDanger = newDanger; selMoveTo = Utility.PointsEqual(my, self) ? null : moveTo; selVec = vec; } } if (selVec != null) { move.Speed = move.StrafeSpeed = 0; move.MoveTo(selMoveTo, null); return(true); } return(false); }
void InitializeDangerEstimation() { foreach (var building in OpponentBuildings) { building.OpponentsCount = MyCombats.Count(x => x.GetDistanceTo(building) <= building.VisionRange); if (Game.IsSkillsEnabled) { if (building.OpponentsCount >= 4) { building.IsBesieded = true; } } else { if (building.IsBase && building.OpponentsCount >= 7 || !building.IsBase && building.OpponentsCount >= 5) { building.IsBesieded = true; } } } MinionsTargetsSelector = new TargetsSelector(Combats) { EnableMinionsCache = true }; BuildingsDangerTriangles = new List <Point[]>(); var top1 = BuildingsObserver.Buildings.FirstOrDefault(x => x.IsTeammate && x.Order == 1 && x.Lane == ALaneType.Top); if (top1 != null) { BuildingsDangerTriangles.Add(new[] { top1 + new Point(top1.Radius + Const.WizardRadius, 0), top1 + new Point(-top1.Radius, -(top1.Radius * 7 + Const.WizardRadius)), top1 + new Point(-top1.Radius, 0), }); } var top0 = BuildingsObserver.Buildings.FirstOrDefault(x => x.IsOpponent && x.Order == 0 && x.Lane == ALaneType.Top); if (top0 != null) { BuildingsDangerTriangles.Add(new[] { top0 + new Point(0, top0.Radius + Const.WizardRadius), top0 + new Point(top0.Radius * 7 + Const.WizardRadius, -top0.Radius), top0 + new Point(0, -top0.Radius), }); } var bottom1 = BuildingsObserver.Buildings.FirstOrDefault(x => x.IsOpponent && x.Order == 1 && x.Lane == ALaneType.Bottom); if (bottom1 != null) { BuildingsDangerTriangles.Add(new[] { bottom1 + new Point(-(bottom1.Radius + Const.WizardRadius), 0), bottom1 + new Point(bottom1.Radius, -(bottom1.Radius * 7 + Const.WizardRadius)), bottom1 + new Point(bottom1.Radius, 0), }); } var bottom0 = BuildingsObserver.Buildings.FirstOrDefault(x => x.IsTeammate && x.Order == 0 && x.Lane == ALaneType.Bottom); if (bottom0 != null) { BuildingsDangerTriangles.Add(new[] { bottom0 + new Point(0, -(bottom0.Radius + Const.WizardRadius)), bottom0 + new Point(bottom0.Radius * 7 + Const.WizardRadius, bottom0.Radius), bottom0 + new Point(0, bottom0.Radius), }); } foreach (var opp in OpponentWizards) { if (opp.GetDistanceTo(ASelf) < ASelf.VisionRange) { opp.IsBesieded = EmulateRush(ASelf, opp) > 30; } } }