Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
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);
        }