예제 #1
0
파일: AMinion.cs 프로젝트: znsoft/AiCup
        public override void EthalonMove(ACircularUnit target)
        {
            var isFrozen = RemainingFrozen > 0;

            SkipTick();

            if (isFrozen)
            {
                return;
            }

            if (target == null)
            {
                X += Math.Cos(Angle) * MyStrategy.Game.MinionSpeed;
                Y += Math.Sin(Angle) * MyStrategy.Game.MinionSpeed;
            }
            else
            {
                var angleTo = GetAngleTo(target);
                if (GetDistanceTo2(target) >
                    Geom.Sqr(this is AOrc
                        ? MyStrategy.Game.OrcWoodcutterAttackRange + target.Radius
                        : MyStrategy.Game.FetishBlowdartAttackRange + target.Radius + MyStrategy.Game.DartRadius))
                {
                    X += Math.Cos(Angle + angleTo) * MyStrategy.Game.MinionSpeed;
                    Y += Math.Sin(Angle + angleTo) * MyStrategy.Game.MinionSpeed;
                }
                Angle += Utility.EnsureInterval(angleTo, MyStrategy.Game.MinionMaxTurnAngle);
            }
        }
예제 #2
0
        DijkstraPointCostFunc MoveCostFunc(IEnumerable <ACombatUnit> buildings, ALaneType lane)
        {
            return(pos =>
            {
                foreach (var building in buildings)
                {
                    if (building != null && building.GetDistanceTo2(pos) <= building.CastRange * building.CastRange)
                    {
                        if (RoadsHelper.Roads.All(seg => seg.GetDistanceTo(pos) > 200))
                        {
                            return Const.Infinity;
                        }
                    }
                }

                if (RoadsHelper.GetAllowedForLine(lane).All(r => r.GetDistanceTo(pos) > (World.TickIndex < 900 && World.TickIndex > 200 ? 200 : 700)))
                {
                    return 1000;
                }

                foreach (var opp in OpponentWizards)
                {
                    if (pos.GetDistanceTo2(opp) < Geom.Sqr(opp.CastRange + Const.WizardRadius + 20))
                    {
                        return 400;
                    }
                }

                return 0.0;
            });
        }
예제 #3
0
        double _getProjectilesDamage(List <AWizard> myStates)
        {
            var totalDamage = 0.0;

            foreach (var arr in ProjectilesPaths1)
            {
                if (arr[0].GetDistanceTo2(ASelf) > Geom.Sqr(1000))
                {
                    continue;
                }

                var         fireballMinDist        = 1000.0;
                AProjectile fireballMinDistState   = null;
                AWizard     fireballMinDistMyState = null;

                for (var ticksPassed = 0; ticksPassed < ProjectilesCheckTicks; ticksPassed++)
                {
                    var cur = myStates[Math.Min(ticksPassed, myStates.Count - 1)];
                    for (var mt = 0; mt <= arr[0].MicroTicks; mt++)
                    {
                        var microTick = ticksPassed * arr[0].MicroTicks + mt;
                        var proj      = arr[microTick];

                        if (!proj.Exists)
                        {
                            ticksPassed = ProjectilesCheckTicks; // выход из внешнего цикла
                            break;
                        }

                        if (proj.Type == ProjectileType.Fireball)
                        {
                            var dist = cur.GetDistanceTo(proj);

                            if (dist < fireballMinDist && (!proj.IsFriendly || proj.RemainingDistance < Const.Eps)) // для своих фаерболов точно известно когда взорвется
                            {
                                fireballMinDist        = dist;
                                fireballMinDistState   = proj;
                                fireballMinDistMyState = cur;
                            }
                        }
                        else
                        {
                            if (proj.IntersectsWith(cur) || microTick > 0 && Geom.SegmentCircleIntersects(arr[microTick - 1], proj, cur, cur.Radius + proj.Radius))
                            {
                                totalDamage += proj.Damage;
                                ticksPassed  = ProjectilesCheckTicks; // выход из внешнего цикла
                                break;
                            }
                        }
                    }
                }

                if (fireballMinDistState != null)
                {
                    totalDamage += AProjectile.GetFireballDamage(fireballMinDistState, fireballMinDistMyState);
                }
            }
            return(totalDamage);
        }
예제 #4
0
파일: AMinion.cs 프로젝트: znsoft/AiCup
 public override ACombatUnit SelectTarget(ACombatUnit[] candidates)
 {
     return(candidates
            .Where(c =>
                   c.IsAlive &&
                   Utility.HasConflicts(this, c) &&
                   GetDistanceTo2(c) < Geom.Sqr(MyStrategy.Game.MinionVisionRange)
                   )
            .ArgMin(GetDistanceTo2));
 }
예제 #5
0
        public bool CanCastUltimate(ActionType ultimate, AWizard teammate)
        {
            if (!CanUseUltimate(ultimate))
            {
                return(false);
            }

            return(Id == teammate.Id ||
                   GetDistanceTo2(teammate) <= Geom.Sqr(CastRange) &&
                   Math.Abs(GetAngleTo(teammate)) <= MyStrategy.Game.StaffSector / 2);
        }
예제 #6
0
        private static bool CanPass(Point from, Point to)
        {
            if (to.X < Const.WizardRadius || to.Y < Const.WizardRadius || to.X > Const.MapSize - Const.WizardRadius || to.Y > Const.MapSize - Const.WizardRadius)
            {
                return(false);
            }

            if (from.GetDistanceTo2(_startState) > Geom.Sqr(_startState.VisionRange)) // нет смысла проверять препятствия далеко
            {
                return(true);
            }

            return(_obstacles.All(ob =>
                                  !Geom.SegmentCircleIntersects(from, to, ob, ob.Radius + Const.WizardRadius + MagicConst.RadiusAdditionalEpsilon)));
        }
예제 #7
0
        public bool CanStaffAttack(ACircularUnit unit, bool checkCooldown = true)
        {
            if (!CanUseStaff(checkCooldown))
            {
                return(false);
            }

            if (GetDistanceTo2(unit) > Geom.Sqr(MyStrategy.Game.StaffRange + unit.Radius))
            {
                return(false);
            }
            if (Math.Abs(GetAngleTo(unit)) > MyStrategy.Game.StaffSector / 2)
            {
                return(false);
            }
            return(true);
        }
예제 #8
0
파일: AMinion.cs 프로젝트: znsoft/AiCup
        public override bool EthalonCanHit(ACircularUnit target, bool checkCooldown = true)
        {
            if (RemainingFrozen > 0)
            {
                return(false);
            }
            if (checkCooldown && RemainingActionCooldownTicks > 0)
            {
                return(false);
            }

            var angleTo = GetAngleTo(target);

            if (Math.Abs(angleTo) > MyStrategy.Game.OrcWoodcutterAttackSector / 2)
            {
                return(false);
            }
            return(GetDistanceTo2(target) <= Geom.Sqr(MyStrategy.Game.OrcWoodcutterAttackRange + target.Radius));
        }
예제 #9
0
        public static Point _getHalfEllipseDxDy(double a, double b, double c, double angle)
        {
            // http://russianaicup.ru/forum/index.php?topic=708.msg6889#msg6889
            if (Math.Abs(angle) > Math.PI / 2)
            {
                return(new Point(Math.Sin(angle) * c, Math.Cos(angle) * c));
            }

            if (Math.Abs(angle) < Const.Eps)
            {
                return(new Point(0, b));
            }

            var    tan = Math.Tan(angle);
            double dx  = Math.Sqrt(1.0 / (Geom.Sqr(1.0 / a) + Geom.Sqr(1.0 / tan / b)));

            if (angle < 0)
            {
                dx *= -1;
            }
            return(new Point(dx, Math.Abs(dx / tan)));
        }
예제 #10
0
        public static WizardPath[] DijkstraFindPath(AWizard start, DijkstraPointStopFunc stopFunc, DijkstraPointCostFunc costFunc)
        {
            start       = new AWizard(start);
            _startState = start;

            _obstacles = Combats
                         .Where(x => !x.IsOpponent && x.Id != start.Id && x.GetDistanceTo2(start) < Geom.Sqr(start.VisionRange)) // (нейтральные включительно)
                         .ToArray();

            var startCell = FindNearestCell(start);

            if (startCell == null)
            {
                return new WizardPath[] {}
            }
            ;

            var endCells = new List <Cell>();

            DijkstraStart(startCell, cell =>
            {
                var point  = _points[cell.I, cell.J];
                var status = stopFunc(point);

                if (status == DijkstraStopStatus.Take || status == DijkstraStopStatus.TakeAndStop)
                {
                    endCells.Add(cell);
                }

                if (status == DijkstraStopStatus.Stop || status == DijkstraStopStatus.TakeAndStop)
                {
                    return(true);
                }
                return(false);
            }, costFunc);

            return(endCells.Select(endCell =>
            {
                var cellsPath = DijkstraGeneratePath(startCell, endCell);

                var res = new WizardPath {
                    start
                };
                res.AddRange(cellsPath.Select(cell => _points[cell.I, cell.J]));
                return res;
            }).ToArray());
        }
    }
예제 #11
0
 public override bool EthalonCanHit(ACircularUnit target, bool checkCooldown = true)
 {
     return((!checkCooldown || RemainingActionCooldownTicks == 0) &&
            GetDistanceTo2(target) <= Geom.Sqr(CastRange));
 }
예제 #12
0
        public override ACombatUnit SelectTarget(ACombatUnit[] candidates)
        {
            var accessible = candidates
                             .Where(x => x.Faction != Faction.Neutral && x.Faction != Faction && x.IsAlive && GetDistanceTo2(x) <= Geom.Sqr(CastRange))
                             .ToArray();

            ACombatUnit sel = null;

            foreach (var x in accessible)
            {
                if (x.Life > Damage)
                {
                    if (sel == null || x.Life < sel.Life || Utility.Equals(x.Life, sel.Life) && x.Id == MyStrategy.Self.Id)
                    {
                        sel = x;
                    }
                }
            }

            if (sel != null)
            {
                return(sel);
            }

            foreach (var x in accessible)
            {
                if (x.Life <= Damage)
                {
                    if (sel == null || x.Life > sel.Life || Utility.Equals(x.Life, sel.Life) && x.Id == MyStrategy.Self.Id)
                    {
                        sel = x;
                    }
                }
            }

            return(sel);
        }
예제 #13
0
파일: FindTarget.cs 프로젝트: znsoft/AiCup
        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));
        }
예제 #14
0
파일: FindTarget.cs 프로젝트: znsoft/AiCup
        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));
        }
예제 #15
0
파일: FindTarget.cs 프로젝트: znsoft/AiCup
        MovingInfo FindBonusTarget(AWizard self)
        {
            var   minTime   = int.MaxValue;
            var   selGo     = 0;
            Point selMoveTo = null;

            foreach (var _bonus in BonusesObserver.Bonuses)
            {
                if (_bonus.GetDistanceTo(self) - self.Radius - _bonus.Radius > Game.StaffRange * 3)
                {
                    continue;
                }
                if (_bonus.RemainingAppearanceTicks > 60)
                {
                    continue;
                }

                var nearest = Combats
                              .Where(x => x.Id != self.Id && self.GetDistanceTo2(x) < Geom.Sqr(self.VisionRange))
                              .ToArray();

                foreach (var angle in Utility.Range(self.Angle, Math.PI * 2 + self.Angle, 24, false))
                {
                    var bonus  = new ABonus(_bonus);
                    var my     = new AWizard(self);
                    var moveTo = my + Point.ByAngle(angle) * self.VisionRange;
                    int time   = 0;
                    int go     = 0;
                    while (my.GetDistanceTo(bonus) > my.Radius + bonus.Radius && time < 60)
                    {
                        if (!my.MoveTo(moveTo, null, w => !CheckIntersectionsAndTress(w, nearest)))
                        {
                            break;
                        }
                        var wait = !bonus.Exists;
                        bonus.SkipTick();
                        time++;
                        if (my.GetDistanceTo(bonus) <= my.Radius + bonus.Radius)
                        {
                            while (!bonus.Exists)
                            {
                                bonus.SkipTick();
                                time++;
                            }
                            if (wait)
                            {
                                time++;
                            }

                            if (time < minTime)
                            {
                                minTime   = time;
                                selMoveTo = moveTo;
                                selGo     = go;
                            }
                            break;
                        }
                        go++;
                    }
                }
            }
            var moving = new MovingInfo(selMoveTo, minTime, new FinalMove(new Move()));

            if (selMoveTo != null)
            {
                if (minTime == 1 || selGo > 0)
                {
                    moving.Move.MoveTo(selMoveTo, null);
                }
                else
                {
                    moving.Target = self;
                }
            }
            return(moving);
        }
예제 #16
0
        WizardPath _goAround(ACombatUnit target, bool goAgainst)
        {
            var my              = new AWizard(ASelf);
            var selLane         = Utility.IsBase(target) ? MessagesObserver.GetLane() : RoadsHelper.GetLane(target);
            var nearestBuilding = OpponentBuildings.ArgMin(b => b.GetDistanceTo2(my));

            var buildings = new List <ABuilding>();

            if (nearestBuilding.GetDistanceTo(my) > nearestBuilding.VisionRange)
            {
                buildings.Add(nearestBuilding);
            }
            if (target.IsOpponent && target.Id != nearestBuilding.Id && target is ABuilding)
            {
                buildings.Add((ABuilding)target);
            }

            var threshold = Self.CastRange - 200;

            if (ASelf.GetDistanceTo(target) < Self.CastRange || !goAgainst)
            {
                threshold = 0;
            }

            var path = DijkstraFindPath(ASelf, pos =>
            {
                // точка ОК, если с неё можно стрелять
                var dist2 = pos.GetDistanceTo2(target);
                if (dist2 < Geom.Sqr(Self.CastRange) && dist2 > Geom.Sqr(threshold))
                {
                    var distToLine = RoadsHelper.Roads.Where(seg => seg.LaneType == selLane).Min(seg => seg.GetDistanceTo(pos));

                    if (distToLine < 200 &&
                        (!goAgainst || BuildingsObserver.MyBase.GetDistanceTo2(pos) < BuildingsObserver.MyBase.GetDistanceTo2(target)) &&
                        TreesObserver.Trees
                        .Where(x => x.GetDistanceTo2(pos) < Geom.Sqr(Self.CastRange))
                        .All(x => !Geom.SegmentCircleIntersects(pos, target, x, x.Radius + Game.MagicMissileRadius))
                        )
                    {
                        return(DijkstraStopStatus.TakeAndStop);
                    }
                }
                return(DijkstraStopStatus.Continue);
            }, MoveCostFunc(buildings, selLane)).FirstOrDefault();

            if (path == null && my.GetDistanceTo(target) - my.Radius - target.Radius <= 1)
            {
                path = new WizardPath {
                    my
                }
            }
            ;                                 // из-за эпсилон, если стою близко у цели, то он как бы с ней пересекается, но это не так
            if (path == null || path.Count == 0)
            {
                return(null);
            }

            if (path.Count == 1)
            {
                FinalMove.Turn = my.GetAngleTo(target);
                return(null);
            }

            var obstacles =
                Combats.Where(x => x.Id != Self.Id).Cast <ACircularUnit>()
                .Where(x => my.GetDistanceTo2(x) < Geom.Sqr(my.VisionRange)) //???
                .ToArray();

            path.Simplify(obstacles, MagicConst.SimplifyMaxLength);

            var nextPoint     = path[1];
            var nextNextPoint = path.Count > 2 ? path[2] : target;

            FinalMove.MoveTo(nextPoint, my.GetDistanceTo(nextNextPoint) < Self.VisionRange * 1.2 ? nextNextPoint : nextPoint);

            var nextTree = path.GetNearestTree();

            CutTreesInPath(nextTree, FinalMove);
#if DEBUG
            Visualizer.Visualizer.SegmentsDrawQueue.Add(new object[] { path, Pens.Blue, 3 });
#endif
            return(path);
        }

        void CutTreesInPath(ATree nextTree, FinalMove move)
        {
            if (nextTree == null)
            {
                return;
            }
            var my = new AWizard(ASelf);

            var angleTo = my.GetAngleTo(nextTree);

            if (my.GetDistanceTo(nextTree) < my.VisionRange && Math.Abs(angleTo) > Game.StaffSector / 2)
            {
                move.MoveTo(null, nextTree);
            }

            if (my.RemainingActionCooldownTicks == 0 && Math.Abs(angleTo) <= Game.StaffSector / 2)
            {
                if (my.GetDistanceTo(nextTree) <= Game.StaffRange + nextTree.Radius && my.RemainingStaffCooldownTicks == 0)
                {
                    move.Action = ActionType.Staff;
                }
                else if (my.GetDistanceTo(nextTree) <= my.CastRange + nextTree.Radius && my.RemainingMagicMissileCooldownTicks == 0)
                {
                    move.Action          = ActionType.MagicMissile;
                    move.CastAngle       = angleTo;
                    move.MinCastDistance = Math.Min(my.CastRange - 1, my.GetDistanceTo(nextTree));
                }
            }
        }

        MovingInfo GoToBonus()
        {
            TimerStart();
            var ret = _goToBonus();

            TimerEndLog("GoToBonus", 1);
            return(ret);
        }

        bool _skipBonusCond(ABonus bonus)
        {
            var oppFirst = BuildingsObserver.Buildings.FirstOrDefault(x => x.IsOpponent && x.Lane == MessagesObserver.GetLane() && x.Order == 0);

            if (oppFirst == null || ASelf.GetDistanceTo(oppFirst) <= oppFirst.CastRange)
            {
                return(true);
            }

            var myFirst = BuildingsObserver.Buildings.FirstOrDefault(x => x.IsTeammate && x.Lane == MessagesObserver.GetLane() && x.Order == 0);

            if (myFirst == null || OpponentWizards.Any(x => x.GetDistanceTo(myFirst) <= myFirst.Radius))
            {
                return(true);
            }

            // TODO
            return(false);
        }

        ABonus SelectBonus(AWizard self)
        {
            var bonus = BonusesObserver.Bonuses.ArgMin(b => b.GetDistanceTo2(self));

            if (bonus.RemainingAppearanceTicks > MagicConst.GoToBonusMaxTicks + MagicConst.BonusTimeReserve)
            {
                return(null);
            }

            if (self.GetDistanceTo(BuildingsObserver.OpponentBase) < BuildingsObserver.OpponentBase.CastRange * 1.4)
            {
                return(null);
            }

            if (Game.IsSkillsEnabled && _skipBonusCond(bonus))
            {
                return(null);
            }

            return(bonus);
        }

        MovingInfo _goToBonus()
        {
            var bonus         = SelectBonus(ASelf);
            var selMovingInfo = new MovingInfo(null, int.MaxValue, new FinalMove(new Move()));

            if (bonus == null)
            {
                return(selMovingInfo);
            }

            if (Const.IsFinal)
            {
                var teammates = MyWizards
                                .Where(x => x.Id != ASelf.Id)
                                .Where(x =>
                {
                    var b = SelectBonus(x);
                    return(b != null && b.Id == bonus.Id);
                })
                                .ToArray();
                if (teammates.Any(x => ASelf.GetDistanceTo(bonus) > x.GetDistanceTo(bonus)))
                {
                    return(selMovingInfo);
                }
            }

            var my = new AWizard(ASelf);
            var nearestBuilding = OpponentBuildings.ArgMin(b => b.GetDistanceTo2(my));

            var path = DijkstraFindPath(ASelf, pos =>
            {
                // точка ОК, если бонус совсем близко
                if (pos.GetDistanceTo2(bonus) < Geom.Sqr(bonus.Radius + Self.Radius + 35))
                {
                    return(DijkstraStopStatus.TakeAndStop);
                }

                return(DijkstraStopStatus.Continue);
            }, MoveCostFunc(new [] { nearestBuilding }, MessagesObserver.GetLane())).FirstOrDefault();

            if (path == null)
            {
                GoDirect(bonus, selMovingInfo.Move);
                selMovingInfo.Target = bonus;
                return(selMovingInfo);
            }

            var obstacles =
                Combats.Where(x => x.Id != Self.Id).Cast <ACircularUnit>()
                .Where(x => my.GetDistanceTo2(x) < Geom.Sqr(my.VisionRange))
                .ToArray();

            path.Add(bonus);
            path.Simplify(obstacles, MagicConst.SimplifyMaxLength);


            var time = (int)(path.GetLength() / my.MaxForwardSpeed);

            if (time < MagicConst.GoToBonusMaxTicks)
            {
                selMovingInfo.Time = time;

                var nextPoint     = path[1];
                var nextNextPoint = path.Count > 2 ? path[2] : nextPoint;
                selMovingInfo.Move = new FinalMove(new Move());
                selMovingInfo.Move.MoveTo(nextPoint, my.GetDistanceTo(nextNextPoint) < my.Radius + 20 ? nextNextPoint : nextPoint);
                selMovingInfo.Target = nextPoint;

                var nextTree = path.GetNearestTree();
                CutTreesInPath(nextTree, selMovingInfo.Move);
            }

            if (selMovingInfo.Time <= bonus.RemainingAppearanceTicks - MagicConst.BonusTimeReserve)
            {
                selMovingInfo.Target = null;
            }
#if DEBUG
            if (selMovingInfo.Target != null)
            {
                Visualizer.Visualizer.SegmentsDrawQueue.Add(new object[] { path, Pens.Red, 3 });
            }
#endif
            return(selMovingInfo);
        }
예제 #17
0
        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);
        }
예제 #18
0
        double EstimateDanger(AWizard my, bool considerWizardBesieded = true)
        {
            double res          = 0;
            var    nearestTower = OpponentCombats.FirstOrDefault(x => x is ABuilding && x.GetDistanceTo2(my) <= Geom.Sqr(x.CastRange));

            foreach (var opp in OpponentCombats)
            {
                var dist = opp.GetDistanceTo(my);
                if (dist > 2 * my.VisionRange)
                {
                    continue;
                }

                if (opp is AWizard)
                {
                    var wizard = opp as AWizard;
                    var inner  = (Game.StaffRange + my.Radius) + 1;                         // (куда достаёт посохом) + запас
                    var outer  = (opp.CastRange + my.Radius + Game.MagicMissileRadius) + 1; // (куда достанет MagicMissile) + запас
                    if (GoAwayCond(my, wizard))
                    {
                        outer += GoAwaySafeDist - Game.MagicMissileRadius;
                    }
                    var coeff = 45;
                    if (!wizard.IsBesieded ||
                        !considerWizardBesieded ||
                        (nearestTower != null &&
                         !Utility.IsBase(nearestTower) &&
                         BuildingsObserver.MyBase.GetDistanceTo2(my) > BuildingsObserver.MyBase.GetDistanceTo2(nearestTower) &&
                         BuildingsObserver.MyBase.GetDistanceTo2(wizard) > BuildingsObserver.MyBase.GetDistanceTo2(nearestTower)
                        )
                        )
                    {
                        if (dist < inner)
                        {
                            res += (wizard.StaffDamage + wizard.MagicMissileDamage) * 2;
                        }
                        else if (dist < outer)
                        {
                            res += (wizard.MagicMissileDamage + coeff - (dist - inner) / (outer - inner) * coeff) * 2;
                        }
                    }
                    else
                    {
                        var otr = my.VisionRange * 1.3;
                        if (dist < otr)
                        {
                            res -= 10 + 60 - dist / otr * 60;
                        }
                    }
                }
                else if (opp is ABuilding)
                {
                    var building = opp as ABuilding;

                    if (building.IsBase && !Game.IsSkillsEnabled)
                    {
                        var outer = building.CastRange;
                        if (dist <= outer)
                        {
                            res += 90 - dist / outer * 90 + building.Damage;
                        }
                    }
                    else if (building.IsBesieded)
                    {
                        var inner = my.Radius + building.Radius + 2 * Game.DartRadius + 3; // свои фетиши могут стрелять
                        var outer = building.VisionRange * 1.2;
                        if (dist < inner)
                        {
                            res += 20 - dist / inner * 20;
                        }
                        else if (dist < outer)
                        {
                            res -= 2 - dist / outer * 2;
                        }
                    }
                    else
                    {
                        var    inner = Game.StaffRange + building.Radius; // откуда можно достать посохом
                        var    outer = building.CastRange;                // куда достреливает башня
                        double delta = -80;
                        if (dist < inner)
                        {
                            res += building.Damage - delta;
                        }
                        else if (dist <= outer)
                        {
                            res += (dist - inner) / (outer - inner) * delta + building.Damage - delta;
                        }
                    }
                }
                else if (opp is AOrc)
                {
                    var inner = Game.OrcWoodcutterAttackRange + my.Radius + Game.MinionSpeed + 20 /*запас*/;
                    var outer = 800;
                    if (dist < inner)
                    {
                        res += Game.OrcWoodcutterDamage + 15 - dist / inner * 15;
                    }
                    else if (dist < outer && my.MmSkillLevel < 5)
                    {
                        res -= 3 - (dist - inner) / (outer - inner) * 3;
                    }
                }
                else if (opp is AFetish)
                {
                    var inner = opp.CastRange + my.Radius + Game.DartRadius + 10;
                    if (dist < inner)
                    {
                        var fetishTarget = MinionsTargetsSelector.Select(opp);
                        if (fetishTarget == null || Geom.Sqr(dist - 5) < opp.GetDistanceTo2(fetishTarget))
                        {
                            res += 15 - dist / inner * 15 + Game.DartDirectDamage;
                        }
                    }
                }
            }

            // не прижиматься к своим
            foreach (var co in MyCombats)
            {
                var dist = my.GetDistanceTo(co) - co.Radius - my.Radius;
                if (my.Id != co.Id && dist < 15)
                {
                    res += 1 - dist / 15 * 1;
                }
            }

            if (Game.IsSkillsEnabled)
            {
                // прижиматься за главную башню
                var cr            = new Point(World.Width - 258, 258);
                var cornerMaxDist = 800;
                var distToCorner  = my.GetDistanceTo(cr);
                if (distToCorner < cornerMaxDist)
                {
                    res -= 10 - (distToCorner / cornerMaxDist) * 10;
                }
            }

            // держаться подальше от места появления минионов
            var spawnDelta   = Game.FactionMinionAppearanceIntervalTicks * 0.33;
            var spawnRemains = World.TickIndex % Game.FactionMinionAppearanceIntervalTicks;

            if (spawnRemains < spawnDelta)
            {
                foreach (var pt in MagicConst.MinionAppearencePoints)
                {
                    var dist  = pt.GetDistanceTo(my);
                    var inner = 450;
                    if (dist < inner)
                    {
                        res += 14 - dist / inner * 14;
                    }
                }
            }

            // двигаться по пути к бонусу
            if (NextBonusWaypoint != null)
            {
                var dist  = my.GetDistanceTo(NextBonusWaypoint);
                var outer = 100.0;
                if (dist < outer)
                {
                    res -= GoToBonusDanger - dist / outer * GoToBonusDanger;
                }
            }

            var nearestRoad = RoadsHelper.Roads.ArgMin(seg => seg.GetDistanceTo(my));
            var linePadding = nearestRoad.LaneType == ALaneType.Middle || nearestRoad.LaneType == ALaneType.Middle2 ? 250.0 : 160.0;

            // не прижиматься к лесу
            if (MagicConst.TreesFreeCircles.All(x => x.GetDistanceTo(my) > x.Radius))
            {
                var distToLine   = nearestRoad.GetDistanceTo(my);
                var outerPadding = 500;
                if (distToLine > linePadding && distToLine < outerPadding)
                {
                    res += (distToLine - linePadding) / (outerPadding - linePadding) * 10;
                }
                else if (distToLine >= outerPadding)
                {
                    res += 10;
                }
            }

            {
                // прижиматься к центру дорожки
                var distToLine   = RoadsHelper.Roads.Where(seg => seg.LaneType != ALaneType.Middle2).Min(seg => seg.GetDistanceTo(my));
                var outerPadding = 500;
                if (distToLine > linePadding && distToLine < outerPadding)
                {
                    res -= 1 - (distToLine - linePadding) / (outerPadding - linePadding) * 1;
                }
                else if (distToLine <= linePadding)
                {
                    res -= 1;
                }
            }

            // не прижиматься к стене
            var distToBorders  = Math.Min(Math.Min(my.X, my.Y), Math.Min(Const.MapSize - my.X, Const.MapSize - my.Y));
            var bordersPadding = 45;

            if (distToBorders < bordersPadding)
            {
                res += 4 - distToBorders / bordersPadding * 4;
            }

            // не перекрывать бонус
            foreach (var bonus in BonusesObserver.Bonuses)
            {
                var inner = bonus.Radius + my.Radius;
                var dist  = my.GetDistanceTo(bonus);
                if (dist <= inner && !bonus.Exists && bonus.RemainingAppearanceTicks < 100)
                {
                    res += 30 + 20 - dist / inner * 20;
                }
            }

            // не прижиматься к углам
            for (var i = 0; i <= 3; i += 3)
            {
                var corner = Const.MapCorners[i];
                var dist   = my.GetDistanceTo(corner);
                var outer  = 500;
                if (dist < outer)
                {
                    res += 7 - dist / outer * 7;
                }
            }

            foreach (var tr in BuildingsDangerTriangles)
            {
                if (Geom.ContainPoint(tr, my))
                {
                    res += new Segment(tr[0], tr[1]).GetDistanceTo(my) / 100 * 10;
                }
            }

            return(res);
        }
예제 #19
0
 public virtual bool IntersectsWith(ACircularUnit unit)
 {
     // если касаются, то false
     return(GetDistanceTo2(unit) < Geom.Sqr(Radius + unit.Radius));
 }
예제 #20
0
        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();
            }
        }
예제 #21
0
        public static void Update()
        {
            var newState = new Dictionary <long, ABuilding>();

            NewBuildings.Clear();
            DisappearedBuildings.Clear();

            foreach (var bld in MyStrategy.World.Buildings)
            {
                var a   = new ABuilding(bld);
                var key = _getCoordinatesKey(a);
                if (!_prevState.ContainsKey(key))
                {
                    // новое здание
                    NewBuildings.Add(a);
                }
                newState[key] = a;

                if (MyStrategy.World.TickIndex == 0)
                {
                    var opposit = new ABuilding(bld);
                    opposit.X          = Const.MapSize - opposit.X;
                    opposit.Y          = Const.MapSize - opposit.Y;
                    opposit.Faction    = opposit.Faction == Faction.Academy ? Faction.Renegades : Faction.Academy;
                    opposit.Id        *= -1; // temp Id
                    opposit.IsTeammate = false;
                    var oppositKey = _getCoordinatesKey(opposit);
                    if (!_prevState.ContainsKey(oppositKey))
                    {
                        // новое здание
                        NewBuildings.Add(opposit);
                    }
                    newState[oppositKey] = opposit;
                }
            }

            foreach (var it in _prevState)
            {
                var bld = it.Value;
                var key = _getCoordinatesKey(bld);
                if (!MyStrategy.IsPointVisible(bld))
                {
                    // его не видно, считаем что осталось
                    if (bld.RemainingActionCooldownTicks == 0)
                    {
                        // значит, если кто-то был поблизости, башня 100% выстрелила
                        if (MyStrategy.Combats.Any(x => x.IsTeammate && bld.GetDistanceTo2(x) <= Geom.Sqr(bld.CastRange)))
                        {
                            bld.RemainingActionCooldownTicks = (bld.IsBase
                                ? MyStrategy.Game.FactionBaseCooldownTicks
                                : MyStrategy.Game.GuardianTowerCooldownTicks) - 1;
                        }
                    }
                    else
                    {
                        bld.RemainingActionCooldownTicks--;
                    }
                    newState[key] = bld;
                }
                else if (!newState.ContainsKey(key))
                {
                    // видно, но исчезло
                    DisappearedBuildings.Add(bld);
                }
            }

            _prevState = newState;

            OpponentBase = Buildings.FirstOrDefault(x => x.IsBase && x.IsOpponent);
            MyBase       = Buildings.FirstOrDefault(x => x.IsBase && x.IsTeammate);

            foreach (var building in Buildings)
            {
                if (building.IsBase)
                {
                    building._isAssailable = Buildings.Count(x => x.Faction == building.Faction && x.Order == 1) < 3;
                }
                else
                {
                    building._isAssailable =
                        Buildings.Count(
                            x =>
                            x.Faction == building.Faction && x.Order + 1 == building.Order &&
                            x.Lane == building.Lane) == 0;
                }
            }
        }