コード例 #1
0
        void _rushTo(AWizard self, AWizard opp)
        {
            // TODO: check angle

            if (self.CanUseFrostBolt() &&
                self.GetDistanceTo(opp) <= Game.WizardCastRange + opp.Radius)
            {
                opp.ApplyMagicalDamage(self.FrostBoltDamage);
                opp.RemainingFrozen = Game.FrozenDurationTicks;
                self.RemainingFrostBoltCooldownTicks = Game.FrostBoltCooldownTicks;
                self.RemainingActionCooldownTicks    = Game.WizardActionCooldownTicks;
            }

            if (self.CanUseStaff() &&
                self.GetDistanceTo(opp) <= Game.StaffRange + opp.Radius)
            {
                opp.ApplyDamage(self.StaffDamage);
                self.RemainingStaffCooldownTicks  = Game.StaffCooldownTicks;
                self.RemainingActionCooldownTicks = Game.WizardActionCooldownTicks;
            }

            if (self.CanUseMagicMissile() &&
                self.GetDistanceTo(opp) <= Game.WizardCastRange + opp.Radius)
            {
                opp.ApplyMagicalDamage(self.MagicMissileDamage);
                self.RemainingMagicMissileCooldownTicks = self.MmSkillLevel == 5 ? 0 : Game.MagicMissileCooldownTicks;
                self.RemainingActionCooldownTicks       = Game.WizardActionCooldownTicks;
            }

            if (self.GetDistanceTo(opp) > Game.StaffRange + opp.Radius)
            {
                self.MoveTo(opp, opp);
            }
            self.SkipTick();
        }
コード例 #2
0
ファイル: FindTarget.cs プロジェクト: znsoft/AiCup
        bool CanRush(AWizard self, ACombatUnit opp)
        {
            var wizard = opp as AWizard;
            var minion = opp as AMinion;

            if (wizard != null)
            {
                if (wizard.IsBesieded)
                {
                    return(true);
                }

                if (wizard.Life <= self.MagicMissileDamage)
                {
                    return(true);
                }
                if (self.Life <= wizard.MagicMissileDamage)
                {
                    return(false);
                }

                if (self.Life >= wizard.Life + 3 * self.MagicMissileDamage)
                {
                    return(true);
                }
            }
            else if (minion != null)
            {
                if (minion.Life <= self.MagicMissileDamage)
                {
                    return(true);
                }
            }
            return(false);
        }
コード例 #3
0
ファイル: DangerEstimation.cs プロジェクト: znsoft/AiCup
        List <Tuple <Point, double> > CalculateDangerMap()
        {
            double range  = Self.VisionRange * 1.1,
                   left   = Self.X - range,
                   right  = Self.X + range,
                   top    = Self.Y - range,
                   bottom = Self.Y + range;

            int grid = 60;
            var res  = new List <Tuple <Point, double> >();
            var my   = new AWizard(ASelf);

            for (int i = 0; i <= grid; i++)
            {
                for (int j = 0; j <= grid; j++)
                {
                    var pt = new Point((right - left) / grid * i + left, (bottom - top) / grid * j + top);
                    if (pt.X < 0 || pt.Y < 0 || pt.X > Const.MapSize || pt.Y > Const.MapSize)
                    {
                        continue;
                    }

                    my.X = pt.X;
                    my.Y = pt.Y;
                    res.Add(new Tuple <Point, double>(pt, EstimateDanger(my)));
                }
            }
            return(res);
        }
コード例 #4
0
ファイル: DangerEstimation.cs プロジェクト: znsoft/AiCup
        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);
        }
コード例 #5
0
ファイル: FindTarget.cs プロジェクト: znsoft/AiCup
        Target FindTarget(AWizard self, Point moveTo = null)
        {
            TimerStart();
            var ret = _findTarget(self, moveTo);

            TimerEndLog("FindTarget", 1);
            return(ret);
        }
コード例 #6
0
        double EmulateRush(AWizard self, AWizard opp)
        {
            TimerStart();
            var ret = _emulateRush(self, opp);

            TimerEndLog("EmulateRush", 1);
            return(ret);
        }
コード例 #7
0
ファイル: FindTarget.cs プロジェクト: znsoft/AiCup
        MovingInfo FindStaffTarget(AWizard self)
        {
            TimerStart();
            var ret = _findStaffTarget(self);

            TimerEndLog("FindStaffTarget", 1);
            return(ret);
        }
コード例 #8
0
ファイル: FindTarget.cs プロジェクト: znsoft/AiCup
        MovingInfo FindCastTarget(AWizard self, ProjectileType projectileType)
        {
            TimerStart();
            var ret = _findCastTarget(self, projectileType);

            TimerEndLog("FindCastTarget", 1);
            return(ret);
        }
コード例 #9
0
ファイル: FindTarget.cs プロジェクト: znsoft/AiCup
        MovingInfo FindCastTarget2(AWizard self, Point moveTo, ProjectileType projectileType)
        {
            TimerStart();
            var ret = _findCastTarget2(self, moveTo, projectileType);

            TimerEndLog("FindCastTarget2", 1);
            return(ret);
        }
コード例 #10
0
ファイル: FindTarget.cs プロジェクト: znsoft/AiCup
        bool CheckIntersectionsAndTress(AWizard self, IEnumerable <ACircularUnit> units)
        {
            if (self.GetFirstIntersection(units) != null)
            {
                return(true);
            }
            var nearestTree = TreesObserver.GetNearestTree(self);

            return(nearestTree != null && self.IntersectsWith(nearestTree));
        }
コード例 #11
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);
        }
コード例 #12
0
ファイル: DangerEstimation.cs プロジェクト: znsoft/AiCup
        bool TryPreDodgeProjectile()
        {
            const int preTicks = 18;
            var       opp      = OpponentWizards
                                 .OrderBy(x => x.GetDistanceTo2(ASelf))
                                 .FirstOrDefault(x =>
                                                 Math.Min(x.RemainingActionCooldownTicks, x.RemainingMagicMissileCooldownTicks) <= preTicks &&
                                                 x.GetDistanceTo(ASelf) <= x.CastRange + ASelf.Radius + Game.MagicMissileRadius + 7 &&
                                                 Math.Abs(x.GetAngleTo(ASelf)) <= Game.StaffSector /* /2*/
                                                 );

            if (opp == null)
            {
                return(false);
            }

            if (Math.Abs(ASelf.GetAngleTo(opp)) < Math.PI / 2 && ASelf.GetDistanceTo(opp) > 500)
            {
                var    obstacles     = Combats.Where(x => x.Id != Self.Id && x.GetDistanceTo(ASelf) < 300).ToArray();
                var    selSign       = 0;
                double selPriority   = int.MaxValue;
                var    requiredAngle = ASelf.GetDistanceTo(opp) <= opp.CastRange + ASelf.Radius
                    ? Math.PI - 2 * ASelf.MaxTurnAngle - 0.001
                    : Math.PI / 2;

                for (var sign = -1; sign <= 1; sign += 2)
                {
                    var my       = new AWizard(ASelf);
                    var priority = 0.0;
                    while (Math.Abs(my.GetAngleTo(opp)) < requiredAngle)
                    {
                        my.Angle += sign * my.MaxTurnAngle;
                        priority += 0.1;
                    }
                    for (var i = 0; i < 15; i++)
                    {
                        if (!my.MoveTo(my + Point.ByAngle(my.Angle), null, w => !CheckIntersectionsAndTress(w, obstacles)))
                        {
                            break;
                        }
                        priority--;
                    }
                    if (priority < selPriority)
                    {
                        selPriority = priority;
                        selSign     = sign;
                    }
                }

                FinalMove.Turn = selSign * 10;
                return(true);
            }
            return(false);
        }
コード例 #13
0
ファイル: MessagesObserver.cs プロジェクト: znsoft/AiCup
        private static SkillType?_getNearestSkill(AWizard self, SkillType skill)
        {
            var skillGroup = Utility.GetSkillGroup(skill);
            var skillOrder = Utility.GetSkillOrder(skill);

            if (self.SkillsLearnedArr[skillGroup] > skillOrder)
            {
                return(null);
            }

            return(Utility.GetSkill(skillGroup, self.SkillsLearnedArr[skillGroup]));
        }
コード例 #14
0
 public AWizard(AWizard unit) : base(unit)
 {
     IsMaster = unit.IsMaster;
     RemainingCooldownTicksByAction = unit.RemainingCooldownTicksByAction.ToArray();
     Level            = unit.Level;
     Xp               = unit.Xp;
     Mana             = unit.Mana;
     SkillsLearnedArr = unit.SkillsLearnedArr.ToArray();
     SkillsFactorsArr = unit.SkillsFactorsArr.ToArray();
     AurasFactorsArr  = unit.AurasFactorsArr.ToArray();
     MaxMana          = unit.MaxMana;
     IsBesieded       = unit.IsBesieded;
 }
コード例 #15
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());
        }
    }
コード例 #16
0
ファイル: FinalMove.cs プロジェクト: znsoft/AiCup
        public void MoveTo(Point to, Point turnTo)
        {
            var self = MyStrategy.ASelf;

            if (turnTo != null)
            {
                _move.Turn = Utility.EnsureInterval(MyStrategy.Self.GetAngleTo(turnTo.X, turnTo.Y), self.MaxTurnAngle);
            }

            if (to != null && !Utility.PointsEqual(self, to))
            {
                var angle = self.GetAngleTo(to);
                var d     = AWizard._getHalfEllipseDxDy(self.MaxStrafeSpeed, self.MaxForwardSpeed, self.MaxBackwardSpeed, angle);

                _move.Speed       = d.Y;
                _move.StrafeSpeed = d.X;
            }
        }
コード例 #17
0
ファイル: FindTarget.cs プロジェクト: znsoft/AiCup
        MovingInfo FindTreeTarget(AWizard self)
        {
            var   res       = new MovingInfo(null, int.MaxValue, new FinalMove(new Move()));
            var   trees     = TreesObserver.Trees.Where(t => self.GetDistanceTo(t) <= Game.StaffRange + t.Radius).ToArray();
            var   minTicks  = int.MaxValue;
            ATree selTarget = null;

            foreach (var tree in trees)
            {
                var my    = new AWizard(self);
                var ticks = 0;
                while (Math.Abs(my.GetAngleTo(tree)) > Game.StaffSector / 2)
                {
                    my.MoveTo(null, tree);
                    ticks++;
                }
                if (ticks < minTicks && my.CanStaffAttack(tree))
                {
                    minTicks  = ticks;
                    selTarget = tree;
                }
            }

            if (selTarget == null)
            {
                return(res);
            }

            res.Time     = minTicks;
            res.Target   = selTarget;
            res.TargetId = selTarget.Id;
            if (minTicks == 0)
            {
                res.Move.Action = ActionType.Staff;
            }
            else
            {
                res.Move.MoveTo(null, selTarget);
            }

            return(res);
        }
コード例 #18
0
ファイル: FindTarget.cs プロジェクト: znsoft/AiCup
        private bool _isFireballGoodSeg(AWizard self, AProjectile.ProjectilePathSegment seg)
        {
            if (seg.State == AProjectile.ProjectilePathState.Free)
            {
                return(false);
            }

            if (seg.SelfDamage > 0) // TODO: можно и пожертвовать
            {
                return(false);
            }

            return(seg.OpponentBurned > 2 ||
                   seg.OpponentBurned > 0 && seg.Target is AWizard ||
                   seg.OpponentBurned > 0 &&
                   seg.Target is ABuilding &&
                   self.Mana >= 2 * Game.FireballManacost &&
                   seg.OpponentDamage > Game.FireballExplosionMaxDamage - 1        //TODO: костыль
                   );
        }
コード例 #19
0
ファイル: DangerEstimation.cs プロジェクト: znsoft/AiCup
        bool PostDodgeProjectile()
        {
            var self = new AWizard(ASelf);

            var curDamage = _getProjectilesDamage(new List <AWizard> {
                self
            });

            self.Move(FinalMove.Speed, FinalMove.StrafeSpeed);
            var newDamage = _getProjectilesDamage(new List <AWizard> {
                self
            });

            if (Utility.Less(curDamage, newDamage))
            {
                FinalMove.Speed       = 0;
                FinalMove.StrafeSpeed = 0;
                return(true);
            }
            return(false);
        }
コード例 #20
0
        bool TryCutTrees(bool cutNearest, FinalMove move)
        {
            var self         = new AWizard(ASelf);
            var nearestTrees = TreesObserver.Trees.Where(
                t => self.GetDistanceTo(t) < self.CastRange + t.Radius + Game.MagicMissileRadius
                ).ToArray();

            if (nearestTrees.Length == 0)
            {
                return(false);
            }

            if (self.RemainingActionCooldownTicks == 0)
            {
                if (self.GetStaffAttacked(nearestTrees).Length > 0)
                {
                    move.Action = ActionType.Staff;
                    return(true);
                }
                if (self.RemainingMagicMissileCooldownTicks == 0)
                {
                    var proj = new AProjectile(self, 0, ProjectileType.MagicMissile);
                    var path = EmulateProjectileWithNearest(proj);
                    if (path.Count == 0 || path[path.Count - 1].EndDistance < self.CastRange - Const.Eps)
                    {
                        move.MinCastDistance = path[path.Count - 1].EndDistance;
                        move.Action          = ActionType.MagicMissile;
                        return(true);
                    }
                }
            }
            if (cutNearest)
            {
                var nearest = nearestTrees.OrderBy(t => self.GetDistanceTo2(t)).FirstOrDefault();
                move.MoveTo(null, nearest);
            }

            return(false);
        }
コード例 #21
0
ファイル: FindTarget.cs プロジェクト: znsoft/AiCup
        static double GetCombatPriority(AWizard self, ACombatUnit unit)
        {
            // чем меньше - тем важнее стрелять в него первого
            var res = unit.Life;

            if (unit is AWizard)
            {
                res /= 4;
                if ((unit as AWizard).IsBesieded)
                {
                    res /= 4;
                }
                res -= 50;
            }
            var dist = self.GetDistanceTo(unit);

            if (dist <= Game.StaffRange + unit.Radius + 10)
            {
                res -= 60;
                res += Math.Log(dist);
            }
            return(res);
        }
コード例 #22
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);
        }
コード例 #23
0
        private bool HasAnyTarget(AWizard self, bool skipBuildings)
        {
            var my = new AWizard(self);

            foreach (var opp in OpponentCombats)
            {
                if (!opp.IsAssailable)
                {
                    continue;
                }

                var prevCastRange = my.CastRange;

                var bld = opp as ABuilding;
                if (opp is AWizard)
                {
                    if (my.CastRange <= opp.CastRange)
                    {
                        if (GoAwayCond(my, opp as AWizard))
                        {
                            my.CastRange = opp.CastRange + GoAwaySafeDist;
                        }
                        else if (my.CastRange < opp.CastRange)
                        {
                            my.CastRange = my.CastRange + 25; // HACK: чтобы не бояться подходить к тем у кого прокачан range
                        }
                    }
                }
                if (bld != null && (skipBuildings || bld.IsBase))
                {
                    if (!bld.IsBase && bld.Lane != MessagesObserver.GetLane())
                    {
                        continue;
                    }

                    if (!bld.IsBesieded)
                    {
                        // чтобы не подходить близко к одиноким башням
                        if (my.GetDistanceTo(bld) < bld.CastRange + 6)
                        {
                            return(true);
                        }
                    }
                }

                if (my.GetDistanceTo(opp) <= my.CastRange + opp.Radius + Game.MagicMissileRadius)
                {
                    var tmp = opp.RemainingFrozen;
                    opp.RemainingFrozen = 100500;
                    var canCast = my.EthalonCanCastMagicMissile(opp, checkCooldown: false, checkAngle: false);
                    opp.RemainingFrozen = tmp;
                    if (canCast)
                    {
                        return(true);
                    }
                }

                my.CastRange = prevCastRange;
            }
            return(false);
        }
コード例 #24
0
        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);
                    }
                }
            }
        }
コード例 #25
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));
        }
コード例 #26
0
ファイル: FindTarget.cs プロジェクト: znsoft/AiCup
        MovingInfo _findCastTarget(AWizard self, ProjectileType projectileType)
        {
            var actionType = Utility.GetActionByProjectileType(projectileType);

            var move = new FinalMove(new Move());

            if (self.RemainingActionCooldownTicks > 0 ||
                self.RemainingCooldownTicksByAction[(int)actionType] > 0 ||
                self.Mana < Const.ProjectileInfo[(int)projectileType].ManaCost ||
                !self.IsActionAvailable(actionType)
                )
            {
                return(new MovingInfo(null, int.MaxValue, move));
            }

            var angles = new List <double>();

            foreach (var x in OpponentCombats)
            {
                var distTo = self.GetDistanceTo(x);
                if (distTo > self.CastRange + x.Radius + Const.ProjectileInfo[(int)projectileType].DamageRadius + 3)
                {
                    continue;
                }

                var angleTo = self.GetAngleTo(x);
                if (Math.Abs(angleTo) > Math.PI / 3)
                {
                    continue;
                }

                var deltaAngle = Math.Atan2(x.Radius, distTo);
                angles.AddRange(new[] { angleTo, angleTo + deltaAngle, angleTo - deltaAngle }.Where(a => Math.Abs(a) <= Game.StaffSector / 2));
            }
            if (angles.Count > 0)
            {
                angles.AddRange(Utility.Range(-Game.StaffSector / 2, Game.StaffSector / 2, 16));
            }

            ACombatUnit selTarget = null;
            double
                selMinDist   = 0,
                selMaxDist   = self.CastRange + 20,
                selCastAngle = 0,
                selMaxDamage = 0;

            if (projectileType == ProjectileType.Fireball)
            {
                var maxDamage = 0.0;
                var maxBurned = 0;

                foreach (var angle in angles)
                {
                    var proj = new AProjectile(new AWizard(self), angle, projectileType);
                    var path = EmulateProjectileWithNearest(proj);
                    for (var i = 0; i < path.Count; i++)
                    {
                        var seg = path[i];

                        if (_isFireballGoodSeg(self, seg))
                        {
                            if (seg.OpponentBurned > maxBurned ||
                                seg.OpponentBurned == maxBurned && seg.OpponentDamage > maxDamage
                                //|| seg.OpponentBurned == maxBurned && Utility.Equals(seg.OpponentDamage, maxDamage)
                                //TODO: combare by angle and priority
                                )
                            {
                                maxBurned    = seg.OpponentBurned;
                                maxDamage    = seg.OpponentDamage;
                                selCastAngle = angle;
                                selMinDist   = selMaxDist = seg.StartDistance;
                                selTarget    = seg.Target;
                                selMaxDamage = seg.OpponentDamage;
                            }
                        }
                    }
                }
            }
            else
            {
                double
                    selPriority = int.MaxValue,
                    selAngleTo  = 0;

                foreach (var angle in angles)
                {
                    var proj = new AProjectile(new AWizard(self), angle, projectileType);
                    var path = EmulateProjectileWithNearest(proj);
                    for (var i = 0; i < path.Count; i++)
                    {
                        if (path[i].State == AProjectile.ProjectilePathState.Free)
                        {
                            continue;
                        }

                        // TODO: если можно убить нескольких, убивать того, у кого больше жизней
                        var combat = path[i].Target;
                        if (!combat.IsAssailable)
                        {
                            continue;
                        }

                        var myAngle  = self.Angle + angle;
                        var hisAngle = self.Angle + self.GetAngleTo(combat);
                        var angleTo  = Geom.GetAngleBetween(myAngle, hisAngle);

                        var priority = GetCombatPriority(self, combat);
                        if (combat.IsOpponent &&
                            (priority < selPriority || Utility.Equals(priority, selPriority) && angleTo < selAngleTo) &&
                            self.CheckProjectileCantDodge(proj, Combats.FirstOrDefault(x => x.Id == combat.Id))
                            )
                        {
                            selTarget    = combat;
                            selCastAngle = angle;
                            selAngleTo   = angleTo;
                            selMinDist   = i == 0 ||
                                           path[i - 1].State == AProjectile.ProjectilePathState.Free &&
                                           path[i - 1].Length < 40
                                ? path[i].StartDistance - 1
                                : path[i].StartDistance - 20;
                            selMaxDist = i >= path.Count - 2
                                ? (self.CastRange + 500)
                                : (path[i + 1].EndDistance + path[i].EndDistance) / 2;
                            selPriority  = priority;
                            selMaxDamage = path[i].OpponentDamage;
                        }
                    }
                }
            }
            if (selTarget == null)
            {
                return(new MovingInfo(null, int.MaxValue, move));
            }

            move.Action          = actionType;
            move.MinCastDistance = selMinDist;
            move.MaxCastDistance = selMaxDist;
            move.CastAngle       = selCastAngle;
#if DEBUG
            _lastProjectileTick   = World.TickIndex;
            _lastProjectilePoints = new[]
            {
                self + Point.ByAngle(self.Angle + selCastAngle) * selMinDist,
                self + Point.ByAngle(self.Angle + selCastAngle) * Math.Min(Self.CastRange, selMaxDist),
            };
#endif
            return(new MovingInfo(selTarget, 0, move)
            {
                Damage = selMaxDamage, TargetId = selTarget.Id
            });
        }
コード例 #27
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));
        }
コード例 #28
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);
        }
コード例 #29
0
ファイル: FindTarget.cs プロジェクト: znsoft/AiCup
        MovingInfo FindUltimateTarget(AWizard self)
        {
            var ret = new MovingInfo(null, int.MaxValue, new FinalMove(new Move()));

            const int threshold = 29;
            var       minTicks  = int.MaxValue;
            AWizard   selTarget = null;
            var       selAction = ActionType.None;

            foreach (var action in new[] { ActionType.Haste, ActionType.Shield })
            {
                if (action == ActionType.Haste && self.HasteSkillLevel < 5 ||
                    action == ActionType.Shield && self.ShieldSkillLevel < 5
                    )
                {
                    continue;
                }

                var teammates = MyWizards
                                .Where(x => x.Id != self.Id &&
                                       self.GetDistanceTo(x) <= self.CastRange &&
                                       x.RemainingStatusByAction(action) <= threshold
                                       ).
                                ToArray();

                foreach (var teammate in teammates)
                {
                    var ticks = 0;
                    var my    = new AWizard(self);
                    while (Math.Abs(my.GetAngleTo(teammate)) > Game.StaffSector / 2)
                    {
                        ticks++;
                        my.MoveTo(null, teammate);
                    }
                    if (ticks < minTicks && my.CanCastUltimate(action, teammate))
                    {
                        minTicks  = ticks;
                        selTarget = teammate;
                        selAction = action;
                    }
                }

                if (selTarget == null &&
                    teammates.Length == 0 &&
                    self.RemainingStatusByAction(action) <= threshold &&
                    self.CanUseUltimate(action)
                    )
                {
                    minTicks  = 100;
                    selTarget = self;
                    selAction = action;
                }
            }

            if (selTarget == null)
            {
                return(ret);
            }

            ret.Target   = selTarget;
            ret.TargetId = selTarget.Id;
            ret.Time     = minTicks;

            if (self.CanCastUltimate(selAction, selTarget))
            {
                ret.Move.Action         = selAction;
                ret.Move.StatusTargetId = selTarget.Id;
            }
            else
            {
                ret.Move.MoveTo(null, selTarget);
            }

            return(ret);
        }
コード例 #30
0
ファイル: FindTarget.cs プロジェクト: znsoft/AiCup
        Target _findTarget(AWizard self, Point moveTo)
        {
            var t0      = FindBonusTarget(self);
            var tfrost  = FindCastTarget(self, ProjectileType.FrostBolt);
            var tfball  = FindCastTarget(self, ProjectileType.Fireball);
            var tmm     = FindCastTarget(self, ProjectileType.MagicMissile);
            var t2      = FindStaffTarget(self);
            var t3      = FindCastTarget2(self, t0.Target ?? moveTo, ProjectileType.MagicMissile);
            var t3fball = FindCastTarget2(self, t0.Target ?? moveTo, ProjectileType.Fireball);
            var ult     = FindUltimateTarget(self);

            Point ret = null;

            if (t0.Target != null)
            {
                FinalMove.Apply(t0.Move);
                ret = t0.Target;
            }

            if (tfball.Target != null && tfball.Damage + 1 >= t3fball.Damage && tfball.Damage > tmm.Damage)
            {
                FinalMove.Action          = tfball.Move.Action;
                FinalMove.MinCastDistance = tfball.Move.MinCastDistance;
                FinalMove.MaxCastDistance = tfball.Move.MaxCastDistance;
                FinalMove.CastAngle       = tfball.Move.CastAngle;
                return(new Target {
                    Type = ret == null ? TargetType.Opponent : TargetType.Bonus
                });
            }
            if (tfrost.Target != null && tfrost.Time <= Math.Min(t2.Time, t3.Time))
            {
                FinalMove.Action          = tfrost.Move.Action;
                FinalMove.MinCastDistance = tfrost.Move.MinCastDistance;
                FinalMove.MaxCastDistance = tfrost.Move.MaxCastDistance;
                FinalMove.CastAngle       = tfrost.Move.CastAngle;
                return(new Target {
                    Type = ret == null ? TargetType.Opponent : TargetType.Bonus
                });
            }
            if (tmm.Target != null && tmm.Time <= Math.Min(t2.Time, t3.Time))
            {
                var wiz = t3.Target as AWizard;
                if (wiz != null && CanRush(ASelf, wiz) && t3.TargetId != tmm.TargetId)
                {
                }
                else
                {
                    FinalMove.Action          = tmm.Move.Action;
                    FinalMove.MinCastDistance = tmm.Move.MinCastDistance;
                    FinalMove.MaxCastDistance = tmm.Move.MaxCastDistance;
                    FinalMove.CastAngle       = tmm.Move.CastAngle;
                    _LastMmTarget             = tmm.TargetId;
                    return(new Target {
                        Type = ret == null ? TargetType.Opponent : TargetType.Bonus
                    });
                }
            }
            if (t0.Target == null && t2.Target != null && t2.Time <= Math.Min(tmm.Time, t3.Time))
            {
                // иначе вообще не кидает хасту/щит
                if (ult.Target == null || t2.Target is AWizard)
                {
                    FinalMove.Apply(t2.Move);
                    return(new Target {
                        Type = TargetType.Opponent
                    });
                }
            }
            if (t3fball.Target != null)
            {
                FinalMove.Apply(t3fball.Move);
                return(new Target {
                    Type = TargetType.Opponent
                });
            }
            if (t3.Target != null && t3.Time <= Math.Min(tmm.Time, t2.Time))
            {
                FinalMove.Apply(t3.Move);
                return(new Target {
                    Type = TargetType.Opponent
                });
            }

            if (ult.Target != null)
            {
                FinalMove.Apply(ult.Move);
                return(new Target {
                    Type = TargetType.Teammate
                });
            }

            if (ret == null)
            {
                return(null);
            }


            return(new Target {
                Type = TargetType.Bonus
            });
        }