예제 #1
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();
            }
        }
예제 #2
0
        double EstimateDanger(AWizard my, bool considerWizardBesieded = true)
        {
            double res          = 0;
            var    nearestTower = OpponentCombats.FirstOrDefault(x => x is ABuilding && x.GetDistanceTo2(my) <= Geom.Sqr(x.CastRange));

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            return(res);
        }