예제 #1
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));
        }
예제 #2
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);
        }
예제 #3
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);
        }
예제 #4
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);
        }
예제 #5
0
        private List <ProjectilePathSegment> _emulate(ACombatUnit[] nearestUnits, double wizardsChangeAngle, TargetsSelector minionsTargetsSelector)
        {
            if (Type != ProjectileType.MagicMissile && Type != ProjectileType.FrostBolt && Type != ProjectileType.Fireball)
            {
                throw new Exception("Unsupported projectile type " + Type);
            }

            // NOTE: nearestUnits уже склонированы
            // NOTE: nearestUnits и они же в minionsTargetsSelector - одни и те же instance

            var list              = new List <ProjectilePathSegment>();
            var projectile        = new AProjectile(this);
            var owner             = nearestUnits.FirstOrDefault(x => x.Id == OwnerUnitId);
            var nearestCandidates = nearestUnits.Where(x => x.Id != OwnerUnitId).ToArray();

            while (projectile.Exists)
            {
                projectile.Move(proj =>
                {
                    if (Type == ProjectileType.Fireball)
                    {
                        double selfDamage = 0;
                        double oppDamage  = 0;
                        var selfBurned    = 0;
                        var oppBurned     = 0;
                        var selfDeads     = 0;
                        var oppDeads      = 0;

                        ACombatUnit importantTarget = null;

                        foreach (var unit in nearestCandidates)
                        {
                            var damage = GetFireballDamage(proj, unit);

                            if (damage > 0)
                            {
                                var deads = 0;
                                if (damage >= unit.Life - Const.Eps)
                                {
                                    // killed
                                    deads++;
                                    damage = unit.Life;
                                }

                                if (unit.Faction == proj.Faction)
                                {
                                    if (unit is AWizard)
                                    {
                                        selfDamage += damage;
                                        selfBurned++;
                                        selfDeads += deads;
                                    }
                                }
                                else if (Utility.HasConflicts(proj, unit))
                                {
                                    oppDamage += damage;
                                    oppBurned++;
                                    oppDeads += deads;
                                    if (importantTarget == null || _targetImportance(unit) > _targetImportance(importantTarget))
                                    {
                                        importantTarget = unit;
                                    }
                                }
                            }
                        }
                        if (owner != null)
                        {
                            var damage = GetFireballDamage(proj, owner);
                            if (damage > 0)
                            {
                                selfBurned++;
                                if (damage >= owner.Life - Const.Eps)
                                {
                                    // killed
                                    selfDamage += owner.Life;
                                    selfDeads++;
                                }
                                else
                                {
                                    selfDamage += damage;
                                }
                            }
                        }
                        list.Add(new ProjectilePathSegment
                        {
                            StartDistance      = list.Count == 0 ? 0 : list.Last().EndDistance,
                            EndDistance        = list.Count == 0 ? 0 : list.Last().EndDistance,
                            OpponentDamage     = oppDamage,
                            SelfDamage         = selfDamage,
                            OpponentDeadsCount = oppDeads,
                            SelfDeadsCount     = selfDeads,
                            State          = (selfDamage + oppDamage < Const.Eps) ? ProjectilePathState.Free : ProjectilePathState.Fireball,
                            OpponentBurned = oppBurned,
                            SelfBurned     = selfBurned,
                            Target         = importantTarget,
                        });
                    }
                    else
                    {
                        var inter = proj.GetFirstIntersection(nearestCandidates);

                        if (inter != null)
                        {
                            if (list.Count == 0 || list.Last().State != ProjectilePathState.Shot)
                            {
                                var opp = inter as ACombatUnit;
                                list.Add(new ProjectilePathSegment
                                {
                                    StartDistance  = list.Count == 0 ? 0 : list.Last().EndDistance,
                                    EndDistance    = list.Count == 0 ? 0 : list.Last().EndDistance,
                                    State          = ProjectilePathState.Shot,
                                    Target         = Utility.CloneCombat(opp),
                                    SelfDamage     = proj.Faction == inter.Faction ? Math.Min(opp.Life, Damage) : 0,
                                    OpponentDamage = Utility.HasConflicts(proj, opp) ? Math.Min(opp.Life, Damage) : 0,
                                });
                            }
                        }
                        else
                        {
                            if (list.Count == 0 || list.Last().State != ProjectilePathState.Free)
                            {
                                list.Add(new ProjectilePathSegment
                                {
                                    StartDistance = list.Count == 0 ? 0 : list.Last().EndDistance,
                                    EndDistance   = list.Count == 0 ? 0 : list.Last().EndDistance,
                                    State         = ProjectilePathState.Free,
                                });
                            }
                        }
                    }
                    list.Last().EndDistance += proj.Speed / proj.MicroTicks;

                    return(true);
                });
                foreach (var unit in nearestCandidates)
                {
                    if (unit is AWizard)
                    {
                        var wizard = unit as AWizard;
                        var dir    = (wizard - this).RotateClockwise(wizardsChangeAngle) + wizard; // вдоль снаряда
                        wizard.MoveTo(dir, null, w =>
                        {
                            var tree = TreesObserver.GetNearestTree(w);
                            return((tree == null || !w.IntersectsWith(tree)) && wizard.GetFirstIntersection(nearestCandidates) == null);
                        });
                    }
                    else if (unit is AMinion)
                    {
                        var target = minionsTargetsSelector.Select(unit);
                        unit.EthalonMove(target);
                    }
                }
            }
            return(list);
        }
예제 #6
0
        private void _move(Wizard self, World world, Game game, Move move)
        {
            World     = world;
            Game      = game;
            Self      = self;
            FinalMove = new FinalMove(move);

            Const.Initialize();
            MagicConst.TreeObstacleWeight = Const.IsFinal ? 25 : 35;

            Wizards = world.Wizards
                      .Select(x => new AWizard(x))
                      .ToArray();

            foreach (var wizard in Wizards)
            {
                foreach (var other in Wizards)
                {
                    if (wizard.Faction != other.Faction)
                    {
                        continue;
                    }
                    if (wizard.GetDistanceTo2(other) > Geom.Sqr(Game.AuraSkillRange))
                    {
                        continue;
                    }

                    for (var i = 0; i < 5; i++)
                    {
                        wizard.AurasFactorsArr[i] = Math.Max(wizard.AurasFactorsArr[i], other.SkillsLearnedArr[i] / 2);
                    }
                }
                var orig   = World.Wizards.FirstOrDefault(w => w.Id == wizard.Id);
                var player = World.Players.FirstOrDefault(p => orig != null && p.Id == orig.OwnerPlayerId);
                if (player != null && player.IsStrategyCrashed)
                {
                    wizard.RemainingFrozen = 100500;
                }
            }

            OpponentWizards = Wizards
                              .Where(x => x.IsOpponent)
                              .ToArray();

            MyWizards = Wizards
                        .Where(x => x.IsTeammate)
                        .ToArray();

            Minions = world.Minions
                      .Select(x => x.Type == MinionType.OrcWoodcutter ? (AMinion) new AOrc(x) : new AFetish(x))
                      .ToArray();

            NeutralMinions = Minions
                             .Where(x => x.Faction == Faction.Neutral)
                             .ToArray();

            Combats =
                Minions.Cast <ACombatUnit>()
                .Concat(Wizards)
                .Concat(BuildingsObserver.Buildings)//TODO перед BuildingsObserver.Update????
                .ToArray();

            MyCombats = Combats
                        .Where(x => x.IsTeammate)
                        .ToArray();

            NeutralMinionsObserver.Update();
            OpponentMinions = Minions
                              .Where(x => x.IsOpponent)
                              .ToArray();

            OpponentCombats = Combats
                              .Where(x => x.IsOpponent)
                              .ToArray();

            RoadsHelper.Initialize();
            BuildingsObserver.Update();

            OpponentBuildings = BuildingsObserver.Buildings
                                .Where(x => x.IsOpponent)
                                .ToArray();

            TreesObserver.Update();
            ProjectilesObserver.Update();
            BonusesObserver.Update();
            MessagesObserver.Update();

            InitializeProjectiles();
            InitializeDijkstra();

            ASelf = Wizards.FirstOrDefault(x => x.Id == Self.Id);
            if (ASelf == null)
            {
                throw new Exception("Self not found in wizards list");
            }

            InitializeDangerEstimation();
            SupportObserver.Update();

            if (Self.IsMaster && World.TickIndex == 0)
            {
                MasterSendMessages();
            }
            if (Self.IsMaster)
            {
                MasterCheckRearrange();
            }

            var nearestBonus         = BonusesObserver.Bonuses.ArgMin(b => b.GetDistanceTo(ASelf));
            var opponentsAroundBonus = OpponentWizards.Where(w => nearestBonus.GetDistanceTo(w) < ASelf.VisionRange * 1.5).ToArray();
            var teammatesAroundBonus = MyWizards.Where(w => ASelf.GetDistanceTo(w) < ASelf.VisionRange * 1.5).ToArray();



            WizardPath path        = null;
            AUnit      pathTarget  = null;
            var        goAway      = GoAwayDetect();
            var        bonusMoving = goAway ? new MovingInfo(null, int.MaxValue, null) : GoToBonus();
            var        target      = FindTarget(new AWizard(ASelf), bonusMoving.Target);

            if (target == null && bonusMoving.Target == null && !goAway)
            {
                var nearest = OpponentCombats
                              .Where(
                    x =>
                    Utility.IsBase(x) || RoadsHelper.GetLane(x) == MessagesObserver.GetLane() ||
                    RoadsHelper.GetLaneEx(ASelf) == ALaneType.Middle &&
                    RoadsHelper.GetLaneEx(x) == ALaneType.Middle && CanRush(ASelf, x))
                              .Where(x => x.IsAssailable && x.Faction != Faction.Neutral)
                              .OrderBy(
                    x =>
                    x.GetDistanceTo(self) +
                    (x is AWizard ? -40 : (x is ABuilding && !((ABuilding)x).IsBesieded) ? 1500 : 0))
                              .ToArray();

                foreach (var n in nearest)
                {
                    path = GoAgainst(n);
                    if (path != null)
                    {
                        pathTarget = n;
                        break;
                    }
                }
                if (nearest.Length > 0 && path == null)
                {
                    GoDirect(nearest[0], FinalMove);
                }
            }

            TimerStart();
            if (!TryDodgeProjectile())
            {
                if (target == null)
                {
                    TryPreDodgeProjectile();
                }

                if (goAway)
                {
                    GoAway();
                }
                else if (target == null || target.Type == TargetType.Teammate ||
                         (FinalMove.Action == ActionType.Staff ||
                          FinalMove.Action == ActionType.MagicMissile ||
                          FinalMove.Action == ActionType.Fireball ||
                          FinalMove.Action == ActionType.FrostBolt) && target.Type == TargetType.Opponent)
                {
                    if (bonusMoving.Target != null)
                    {
                        NextBonusWaypoint = bonusMoving.Target;
                        FinalMove.Turn    = bonusMoving.Move.Turn;
                        if (bonusMoving.Move.Action != ActionType.None && bonusMoving.Move.Action != null)
                        {
                            FinalMove.Action          = bonusMoving.Move.Action;
                            FinalMove.MinCastDistance = bonusMoving.Move.MinCastDistance;
                            FinalMove.MaxCastDistance = bonusMoving.Move.MaxCastDistance;
                            FinalMove.CastAngle       = bonusMoving.Move.CastAngle;
                        }

                        NextBonusWaypoint = ASelf + (NextBonusWaypoint - ASelf).Normalized() * (Self.Radius + 30);

                        if (nearestBonus.GetDistanceTo(ASelf) < ASelf.VisionRange * 1.5 &&
                            nearestBonus.GetDistanceTo(ASelf) > 100 &&
                            opponentsAroundBonus.Length <= 1 &&
                            ASelf.Life + 10 >= (opponentsAroundBonus.FirstOrDefault() ?? ASelf).Life &&
                            OpponentMinions.Count(x => x.GetDistanceTo(ASelf) < Game.FetishBlowdartAttackRange) == 0
                            )
                        {
                            FinalMove.MoveTo(NextBonusWaypoint, null);
                        }
                        else
                        {
                            TryGoByGradient(x => EstimateDanger(x), null, FinalMove);
                        }
                    }
                    else
                    {
                        var all = Combats.Select(Utility.CloneCombat).ToArray();
                        var my  = all.FirstOrDefault(x => x.Id == ASelf.Id) as AWizard;

                        my?.Move(FinalMove.Speed, FinalMove.StrafeSpeed);
                        var ts = new TargetsSelector(all);

                        var skipBuildings = path == null ||
                                            path.GetLength() < 300 ||
                                            path.GetLength() < 600 && OpponentBuildings.Any(x =>
                        {
                            var tar = ts.Select(x);
                            return(tar != null && tar.Id == ASelf.Id);
                        });


                        if (TryGoByGradient(x => EstimateDanger(x), x => HasAnyTarget(x, skipBuildings), FinalMove))
                        {
                            var cutTreeMovingInfo = FindTreeTarget(ASelf);
                            if (cutTreeMovingInfo.Target != null)
                            {
                                FinalMove.Turn = cutTreeMovingInfo.Move.Turn;
                                if (cutTreeMovingInfo.Move.Action != null && FinalMove.Action == null)
                                {
                                    FinalMove.Action = cutTreeMovingInfo.Move.Action;
                                }
                                // не будет мешать TryPreDodgeProjectile?
                            }
                        }
                    }
                }

                PostDodgeProjectile();
            }
            TimerEndLog("Go", 1);

            if (ASelf.CanLearnSkill)
            {
                move.SkillToLearn = MessagesObserver.GetSkill();
            }
        }
예제 #7
0
        private bool _TryGoByGradient(Func <AWizard, double> costFunction, Func <AWizard, bool> firstMoveCondition, FinalMove move)
        {
            var self = new AWizard(ASelf);

            var obstacles =
                Combats.Where(x => x.Id != Self.Id && !(x is ABuilding)).Cast <ACircularUnit>()
                .Concat(BuildingsObserver.Buildings)
                .Where(x => self.GetDistanceTo2(x) < Geom.Sqr(x.Radius + 150))
                .ToArray();

            var           danger    = costFunction(self); // for debug
            List <double> selVec    = null;
            var           minDanger = double.MaxValue;
            Point         selMoveTo = null;

            foreach (var angle in Utility.Range(self.Angle, Math.PI * 2 + self.Angle, 24, false))
            {
                var moveTo  = self + Point.ByAngle(angle) * self.VisionRange;
                var nearest = Combats
                              .Where(x => x.GetDistanceTo(self) < Math.Max(self.VisionRange, x.VisionRange) * 1.3)
                              .Select(Utility.CloneCombat)
                              .ToArray();
                var tergetsSelector = new TargetsSelector(nearest);
                var opponents       = nearest.Where(x => x.IsOpponent).ToArray();

                var       vec   = new List <double>();
                const int steps = 18;

                var my      = (AWizard)nearest.FirstOrDefault(x => x.Id == self.Id);
                var ok      = true;
                var canMove = true;

                while (vec.Count < steps)
                {
                    if (canMove)
                    {
                        canMove = my.MoveTo(moveTo, null, w => w.GetFirstIntersection(obstacles) == null);
                        if (TreesObserver.GetNearestTrees(my).Any(t => t.IntersectsWith(my)))
                        {
                            break;
                        }
                    }
                    else
                    {
                        my.SkipTick();
                    }

                    var tmp = OpponentCombats;//HACK
                    OpponentCombats = opponents;
                    vec.Add(costFunction(my));
                    OpponentCombats = tmp;
                    foreach (var x in opponents)
                    {
                        var tar = tergetsSelector.Select(x);
                        if (tar != null || x is AWizard)
                        {
                            x.EthalonMove(tar);
                        }
                    }
                    if (vec.Count == 1 && firstMoveCondition != null && !firstMoveCondition(my))
                    {
                        ok = false;
                        break;
                    }
                }

                if (!ok || vec.Count == 0)
                {
                    continue;
                }

                while (vec.Count < steps)
                {
                    vec.Add(CantMoveDanger);
                }

                var newDanger = 0.0;
                for (var k = 0; k < steps; k++)
                {
                    newDanger += vec[k] * Math.Pow(0.87, k);
                }
                newDanger += 3 * vec[0];

                if (newDanger < minDanger)
                {
                    minDanger = newDanger;
                    selMoveTo = Utility.PointsEqual(my, self) ? null : moveTo;
                    selVec    = vec;
                }
            }
            if (selVec != null)
            {
                move.Speed = move.StrafeSpeed = 0;
                move.MoveTo(selMoveTo, null);
                return(true);
            }
            return(false);
        }