示例#1
0
        void GoDirect(Point target, FinalMove move)
        {
            move.MoveTo(null, target);
            var canGo = TryGoByGradient(w => w.GetDistanceTo2(target), null, move);

            TryCutTrees(!canGo, move);
        }
示例#2
0
文件: FinalMove.cs 项目: znsoft/AiCup
 public void Apply(FinalMove move)
 {
     Turn            = move.Turn;
     Speed           = move.Speed;
     StrafeSpeed     = move.StrafeSpeed;
     Action          = move.Action;
     CastAngle       = move.CastAngle;
     MinCastDistance = move.MinCastDistance;
     MaxCastDistance = move.MaxCastDistance;
     StatusTargetId  = move.StatusTargetId;
     Messages        = move.Messages;
 }
示例#3
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);
        }
示例#4
0
        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));
        }
示例#5
0
        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
            });
        }
示例#6
0
        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));
        }
示例#7
0
        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
            });
        }
示例#8
0
 public MovingInfo(Point target, int time, FinalMove move)
 {
     Target = target;
     Time   = time;
     Move   = move;
 }
示例#9
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();
            }
        }
示例#10
0
        bool _tryDodgeProjectile()
        {
            var   obstacles = Combats.Where(x => x.Id != Self.Id && x.GetDistanceTo(ASelf) < 300).ToArray();
            var   minTicks  = int.MaxValue;
            var   minDamage = 1000.0;
            Point selMoveTo = null;
            Point selTurnTo = null;

            foreach (var doTurn in new[] { false, true })
            {
                foreach (var angle in Utility.Range(0, Math.PI * 2, 40, false))
                {
                    if (minTicks == 0 && minDamage < Const.Eps) // ничего не грозит
                    {
                        break;
                    }

                    var ticks    = 0;
                    var my       = new AWizard(ASelf);
                    var bonus    = new ABonus(BonusesObserver.Bonuses.ArgMin(b => b.GetDistanceTo(Self)));
                    var moveTo   = my + Point.ByAngle(angle) * 1000;
                    var turnTo   = doTurn ? moveTo : null;
                    var myStates = new List <AWizard> {
                        new AWizard(my)
                    };

                    while (ticks < ProjectilesCheckTicks)
                    {
                        var totalDamage = _getProjectilesDamage(myStates);

                        if (Utility.Less(totalDamage, minDamage) ||
                            Utility.Equals(totalDamage, minDamage) && ticks < minTicks)
                        {
                            minTicks  = ticks;
                            minDamage = totalDamage;
                            selMoveTo = moveTo;
                            selTurnTo = turnTo;
                        }

                        bonus.SkipTick();
                        my.MoveTo(moveTo, turnTo, w =>
                        {
                            if (CheckIntersectionsAndTress(w, obstacles))
                            {
                                return(false);
                            }
                            if (bonus.RemainingAppearanceTicks < 15 && bonus.IntersectsWith(w))
                            {
                                return(false);
                            }
                            return(true);
                        });
                        myStates.Add(new AWizard(my));

                        ticks++;
                    }
                }
            }
            if (minTicks == 0 || minTicks == int.MaxValue) // нет необходимости уворачиваться
            {
                return(false);
            }

            if (selTurnTo != null || Math.Abs(ASelf.GetAngleTo(selMoveTo)) < Math.PI / 2)
            {
                FinalMove.Turn = 0;
            }
            FinalMove.MoveTo(selMoveTo, selTurnTo);
            return(true);
        }
示例#11
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);
        }
示例#12
0
        private bool TryGoByGradient(Func <AWizard, double> costFunction, Func <AWizard, bool> condition, FinalMove move)
        {
            TimerStart();
            var ret = _TryGoByGradient(costFunction, condition, move);

            TimerEndLog("TryGoByGradient", 1);
            return(ret);
        }