Пример #1
0
        static Cell FindNearestCell(ACircularUnit my)
        {
            double ds = Const.MapSize / GridSize;

            var    I = (int)(my.X / ds + Const.Eps);
            var    J = (int)(my.Y / ds + Const.Eps);
            int    seldI = int.MaxValue, seldJ = int.MaxValue;
            double minDist   = int.MaxValue;
            var    obstacles = _obstacles
                               .Concat(BuildingsObserver.Buildings)
                               .Concat(TreesObserver.Trees)
                               .ToArray();

            for (var di = 0; di < 2; di++)
            {
                for (var dj = 0; dj < 2; dj++)
                {
                    var dst = WizardPath.GetSegmentWeight(_points[I + di, J + dj], my, true);
                    if (dst < minDist &&
                        obstacles.All(ob =>
                                      !Geom.SegmentCircleIntersects(my, _points[I + di, J + dj], ob, ob.Radius + my.Radius + MagicConst.RadiusAdditionalEpsilon))
                        )
                    {
                        minDist = dst;
                        seldI   = di;
                        seldJ   = dj;
                    }
                }
            }
            if (seldI == int.MaxValue)
            {
                return(null);
            }
            return(new Cell(I + seldI, J + seldJ));
        }
Пример #2
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);
        }
Пример #3
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)));
        }
Пример #4
0
        private ATree _getNearestTree(Point a, Point b)
        {
            var dir = b - a;

            for (var i = 0; i <= SegmentDivideParts; i++)
            {
                Point p     = dir * (1.0 * i / SegmentDivideParts) + a;
                var   trees = TreesObserver.GetNearestTrees(p);
                foreach (var tree in trees)
                {
                    if (Geom.SegmentCircleIntersects(a, b, tree,
                                                     tree.Radius + Const.WizardRadius + MagicConst.RadiusAdditionalEpsilon))
                    {
                        return(tree);
                    }
                }
            }
            return(null);
        }
Пример #5
0
        private void _simplify(ACircularUnit[] obstacles, double maxLength)
        {
            double length = 0;

            for (var i = 2; i < Count; i++)
            {
                var a = this[i - 2];
                var b = this[i - 1];
                var c = this[i];

                if (_getNearestTree(a, b) != null)
                {
                    break;
                }

                var bcTree = _getNearestTree(b, c);
                var acTree = _getNearestTree(a, c);
                if (bcTree != null || acTree != null)
                {
                    if (acTree == bcTree)
                    {
                        RemoveAt(i - 1);
                    }
                    break;
                }

                if (length + a.GetDistanceTo(b) > maxLength)
                {
                    break;
                }

                if (obstacles.All(ob => !Geom.SegmentCircleIntersects(a, c, ob, Const.WizardRadius + ob.Radius + MagicConst.RadiusAdditionalEpsilon)))
                {
                    RemoveAt(i - 1);
                    i--;
                }
                else
                {
                    length += a.GetDistanceTo(b);
                }
            }
        }
Пример #6
0
        public static double GetSegmentWeight(Point a, Point b, bool checkStart)
        {
            var   dir  = b - a;
            var   res  = dir.Length;
            ATree prev = null;

            for (var i = (checkStart ? 0 : 1); i <= SegmentDivideParts; i++)
            {
                var p    = dir * (1.0 * i / SegmentDivideParts) + a;
                var tree = TreesObserver.GetNearestTree(p);
                if (tree != null && tree != prev &&
                    Geom.SegmentCircleIntersects(a, b, tree,
                                                 tree.Radius + Const.WizardRadius + MagicConst.RadiusAdditionalEpsilon))
                {
                    res += Math.Ceiling(tree.Life / 12) * MagicConst.TreeObstacleWeight;
                    prev = tree;
                }
            }
            return(res);
        }
Пример #7
0
        public bool Move(Func <AProjectile, bool> check = null)

        {
            var prev        = new Point(this);
            var nearestTree = TreesObserver.GetNearestTree(this);

            for (var i = 0; i < MicroTicks; i++)
            {
                if (!Exists)
                {
                    return(false);
                }

                MicroMove();
                if (nearestTree != null && GetDistanceTo2(nearestTree) <= Math.Sqrt(Radius + nearestTree.Radius))
                {
                    // снаряд ударился об дерево
                    RemainingDistance = 0;
                    return(false);
                }

                if (!Exists)
                {
                    return(false);
                }
                if (check != null && !check(this))
                {
                    return(false);
                }
            }
            if (nearestTree != null && Geom.SegmentCircleIntersects(prev, this, nearestTree, nearestTree.Radius + Radius))
            {
                // снаряд ударился об дерево (это более точная проверка)
                RemainingDistance = 0;
                return(false);
            }

            return(true);
        }
Пример #8
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);
        }