private List <long> NextTargetGroup(VehiclesGroup myArmy, World world, Player me)
        {
            var enemyVehicles = VehicleRegistry.EnemyVehicles(me);

            if (!enemyVehicles.Any())
            {
                return(Enumerable
                       .Empty <long>()
                       .ToList());
            }
            if (world.TickIndex - lastClusteringTick > CacheTtl)
            {
                var nextEnemyGroup = NextEnemyGroup(myArmy.Center, enemyVehicles, world.TickIndex)?.ToList();
                cachedTargetGroup = nextEnemyGroup?
                                    .Select(v => v.Id)
                                    .ToList()
                                    ?? new List <long>
                {
                    enemyVehicles
                    .OrderBy(v => v.GetDistanceTo(myArmy.Center))
                    .First()
                    .Id
                };
                lastClusteringTick = world.TickIndex;
                return(cachedTargetGroup);
            }
            return(cachedTargetGroup);
        }
Example #2
0
        private Point2D NextTarget(VehiclesGroup myArmy, World world, Player me, Game game)
        {
            var enemyVehicles = VehicleRegistry.EnemyVehicles(me);

            if (world.TickIndex - lastClusteringTick <= CacheTtl)
            {
                return(cachedTarget);
            }
            var closestUncapturedFacility = VehicleRegistry.GetUncapturedFacilities(world, me, Id)
                                            .OrderBy(f => myArmy.Center.GetDistanceTo(f.ToPoint(game)))
                                            .FirstOrDefault();

            if (closestUncapturedFacility != null)
            {
                VehicleRegistry.SetCaptureTarget(closestUncapturedFacility.Id, Id);
                cachedTarget = closestUncapturedFacility.ToPoint(game);
                return(cachedTarget);
            }

            var nextEnemyGroup = NextEnemyGroup(myArmy.Center, enemyVehicles, world.TickIndex)?.ToList();

            if (nextEnemyGroup != null)
            {
                cachedTargetGroup  = nextEnemyGroup.Select(v => v.Id).ToList();
                cachedTarget       = nextEnemyGroup.GetCenterPoint();
                lastClusteringTick = world.TickIndex;
                return(cachedTarget);
            }

            return(new Point2D(world.Height, world.Width));
        }
 private static void MoveCloserY(VehiclesGroup group, double secondGroupY)
 {
     group
     .SelectVehicles()
     .MoveTo(group.Center.Y > secondGroupY
                                 ? new Point2D(group.Center.X, secondGroupY + MagicConstants.InitialGapSize)
                                 : new Point2D(group.Center.X, group.Center.Y + MagicConstants.InitialGapSize));
 }
 private static void MoveCloserX(VehiclesGroup group, double secondGroupX)
 {
     group
     .SelectVehicles()
     .MoveTo(group.Center.X > secondGroupX
                                 ? new Point2D(secondGroupX + MagicConstants.InitialGapSize, group.Center.Y)
                                 : new Point2D(group.Center.X + MagicConstants.InitialGapSize, group.Center.Y));
 }
 private void Bind(VehiclesGroup myArmy)
 {
     myArmy
     .SelectVehicles()
     .Assign(Id)
     .Scale(0.1);
     VehicleRegistry.RegisterNewFormation(Id, VehicleIds);
     binded = true;
 }
Example #6
0
        private void DoWork()
        {
            var army = new VehiclesGroup(Id, VehicleIds, VehicleRegistry, CommandManager);

            army
            .Select(Id)
            .ResetIdleness()
            .Scale(0.1);
            command = CommandManager.PeekLastCommand(Id) as ScaleCommand;
        }
        private void DoWork(Player me)
        {
            var myVehicles    = VehicleRegistry.MyVehicles(me);
            var tanks         = myVehicles.Where(v => v.Type == VehicleType.Tank).ToList();
            var centerOfTanks = tanks.GetCenterPoint();

            var arrvs         = myVehicles.Where(v => v.Type == VehicleType.Arrv).ToList();
            var centerOfArrvs = arrvs.GetCenterPoint();

            var ifvs         = myVehicles.Where(v => v.Type == VehicleType.Ifv).ToList();
            var centerOfIfvs = ifvs.GetCenterPoint();

            var xTanksArrvs = Math.Abs(centerOfTanks.X - centerOfArrvs.X) < MagicConstants.Eps;
            var xArrvsIfvs  = Math.Abs(centerOfArrvs.X - centerOfIfvs.X) < MagicConstants.Eps;
            var xTanksIfvs  = Math.Abs(centerOfTanks.X - centerOfIfvs.X) < MagicConstants.Eps;
            var yTanksArrvs = Math.Abs(centerOfTanks.Y - centerOfArrvs.Y) < MagicConstants.Eps;
            var yArrvsIfvs  = Math.Abs(centerOfArrvs.Y - centerOfIfvs.Y) < MagicConstants.Eps;
            var yTanksIfvs  = Math.Abs(centerOfTanks.Y - centerOfIfvs.Y) < MagicConstants.Eps;

            var xTanksArrvsGap = yTanksArrvs && Math.Abs(centerOfTanks.X - centerOfArrvs.X) > MagicConstants.InitialGapSize + MagicConstants.Eps;
            var xArrvsIfvsGap  = yArrvsIfvs && Math.Abs(centerOfArrvs.X - centerOfIfvs.X) > MagicConstants.InitialGapSize + MagicConstants.Eps;
            var xTanksIfvsGap  = yTanksIfvs && Math.Abs(centerOfTanks.X - centerOfIfvs.X) > MagicConstants.InitialGapSize + MagicConstants.Eps;
            var yTanksArrvsGap = xTanksArrvs && Math.Abs(centerOfTanks.Y - centerOfArrvs.Y) > MagicConstants.InitialGapSize + MagicConstants.Eps;
            var yArrvsIfvsGap  = xArrvsIfvs && Math.Abs(centerOfArrvs.Y - centerOfIfvs.Y) > MagicConstants.InitialGapSize + MagicConstants.Eps;
            var yTanksIfvsGap  = xTanksIfvs && Math.Abs(centerOfTanks.Y - centerOfIfvs.Y) > MagicConstants.InitialGapSize + MagicConstants.Eps;

            var arrvsGroup = new VehiclesGroup(Id, arrvs.Select(v => v.Id).ToList(), VehicleRegistry, CommandManager);
            var ifvsGroup  = new VehiclesGroup(Id, ifvs.Select(v => v.Id).ToList(), VehicleRegistry, CommandManager);

            if (xTanksArrvsGap)
            {
                MoveCloserX(arrvsGroup, centerOfTanks.X);
            }
            else if (xArrvsIfvsGap)
            {
                MoveCloserX(arrvsGroup, centerOfIfvs.X);
            }
            else if (xTanksIfvsGap)
            {
                MoveCloserX(ifvsGroup, centerOfTanks.X);
            }
            else if (yTanksArrvsGap)
            {
                MoveCloserY(arrvsGroup, centerOfTanks.Y);
            }
            else if (yArrvsIfvsGap)
            {
                MoveCloserY(arrvsGroup, centerOfIfvs.Y);
            }
            else
            {
                MoveCloserY(ifvsGroup, centerOfTanks.Y);
            }
            command = CommandManager.PeekLastCommand(Id) as MoveCommand;
        }
Example #8
0
        public override VehicleFormationResult PerformAction(World world, Player me, Game game)
        {
            var myArmy = new VehiclesGroup(Id, VehicleIds, VehicleRegistry, CommandManager);

            commands.RemoveAll(c => c.IsStarted() && c.IsFinished(world.TickIndex, VehicleRegistry));

            if (commands.Any())
            {
                return(new VehicleFormationResult(this));
            }

            if (FormationHelper.IsNukeAlert(world.GetOpponentPlayer()) && world.TickIndex - nukePreventionTick > game.BaseTacticalNuclearStrikeCooldown / 2)
            {
                commands.Clear();
                CommandManager.ClearCommandsQueue(Id);
                this.PreventNuke(myArmy, world, game, commands);
                nukePreventionTick = world.TickIndex;
                return(new VehicleFormationResult(this));
            }

            var myVehicles = VehicleRegistry.GetVehiclesByIds(VehicleIds).ToList();

            if (cachedTargetGroup != null &&
                this.TryNuke(myArmy, myVehicles, VehicleRegistry.GetVehiclesByIds(cachedTargetGroup), me, game, world, commands))
            {
                return(new VehicleFormationResult(new ShrinkGroundVehicleFormation(Id, VehicleIds, CommandManager, VehicleRegistry)));
            }

            if (commands.Any(c => !c.IsFinished(world.TickIndex, VehicleRegistry)))
            {
                return(new VehicleFormationResult(this));
            }

            var nextTarget = NextTarget(myArmy, world, me, game);
            var direction  = myArmy.Center.To(nextTarget);

            myArmy
            .Select(Id)
            .MoveByVector(direction.Length() > 20
                                                ? direction.Mul(0.1)
                                                : direction,
                          game.TankSpeed * game.ForestTerrainSpeedFactor);
#if DEBUG
            RewindClient.Instance.Line(myArmy.Center.X, myArmy.Center.Y, nextTarget.X, nextTarget.Y, Color.Fuchsia);
#endif
            commands.Add(CommandManager.PeekLastCommand(Id));
            return(new VehicleFormationResult(this));
        }
Example #9
0
        private void Bind(VehiclesGroup myArmy)
        {
            if (r2)
            {
                myArmy
                .SelectVehicles()
                .Assign(Id);
            }
            else
            {
                myArmy
                .SelectVehicles(VehicleType.Fighter)
                .AddToSelectionVehicles(VehicleType.Helicopter)
                .Assign(MagicConstants.AirFormationGroupId);
            }

            VehicleRegistry.RegisterNewFormation(Id, VehicleIds);
            binded = true;
        }
        private void Bind(VehiclesGroup myArmy)
        {
            if (r2)
            {
                myArmy
                .SelectVehicles()
                .Assign(Id);
            }
            else
            {
                myArmy
                .SelectVehicles(VehicleType.Tank)
                .AddToSelectionVehicles(VehicleType.Arrv)
                .AddToSelectionVehicles(VehicleType.Ifv)
                .Assign(MagicConstants.GroundFormationGroupId);
            }

            VehicleRegistry.RegisterNewFormation(Id, VehicleIds);
            binded = true;
        }
Example #11
0
        public static bool TryNuke(this IVehicleFormation formation,
                                   VehiclesGroup myArmy,
                                   IReadOnlyCollection <Vehicle> myVehicles,
                                   IReadOnlyList <Vehicle> enemyVehicles,
                                   Player me,
                                   Game game,
                                   World world,
                                   IList <Command> commands)
        {
            if (me.RemainingNuclearStrikeCooldownTicks != 0)
            {
                return(false);
            }
            if (!enemyVehicles.Any())
            {
                return(false);
            }
            if (myArmy.Center.GetDistanceTo(enemyVehicles.GetCenterPoint()) > 4 * game.TacticalNuclearStrikeRadius)
            {
                return(false);
            }
            var nukeTarget = GetNukeTarget(enemyVehicles, myVehicles, game);

            if (nukeTarget == null)
            {
                return(false);
            }
            var nukeGunner = formation.GetNukeGunner(nukeTarget, myVehicles, world, game);

            if (nukeGunner == null)
            {
                return(false);
            }
            myArmy
            .Nuke(nukeGunner.Id, nukeTarget);
            commands.Add(formation.CommandManager.PeekLastCommand(formation.Id));
            myArmy
            .Select(formation.Id)
            .Stop();
            return(true);
        }
Example #12
0
        private void DoWork()
        {
            var army = new VehiclesGroup(Id, VehicleIds, VehicleRegistry, CommandManager);

            if (!binded)
            {
                Bind(army);
                return;
            }
            var vehicles      = VehicleRegistry.GetVehiclesByIds(VehicleIds);
            var width         = vehicles.Select(v => v.X).Max() - vehicles.Select(v => v.X).Min();
            var height        = vehicles.Select(v => v.Y).Max() - vehicles.Select(v => v.Y).Min();
            var rotationAngle = width > height
                                ? -45.ToRadians()
                                : 45.ToRadians();

            army
            .Select(Id)
            .RotateBy(rotationAngle);
            command = CommandManager.PeekLastCommand(Id) as RotateCommand;
        }
Example #13
0
        private void DoWork(Player me)
        {
            var myVehicles = VehicleRegistry.MyVehicles(me);

            var fightersGroup = new VehiclesGroup(Id,
                                                  myVehicles
                                                  .Where(v => v.Type == VehicleType.Fighter)
                                                  .Select(v => v.Id)
                                                  .ToList(),
                                                  VehicleRegistry,
                                                  CommandManager);
            var helicoptersGroup = new VehiclesGroup(Id,
                                                     myVehicles
                                                     .Where(v => v.Type == VehicleType.Helicopter)
                                                     .Select(v => v.Id)
                                                     .ToList(),
                                                     VehicleRegistry,
                                                     CommandManager);
            var fightersToTheRight = fightersGroup.Center.X > helicoptersGroup.Center.X;

            fightersGroup
            .SelectVehicles(VehicleType.Fighter)
            .Scale(ScaleFactor)
            .MoveByVector(0, 5);

            helicoptersGroup
            .SelectVehicles(VehicleType.Helicopter)
            .ResetIdleness()
            .Scale(ScaleFactor);
            commands.Add(CommandManager.PeekLastCommand(Id));

            fightersGroup
            .SelectVehicles(VehicleType.Fighter)
            .MoveByVector(fightersToTheRight ? -MagicConstants.InitialGapSize - 5 : MagicConstants.InitialGapSize + 5, 0, canBeParallel: true);

            helicoptersGroup
            .SelectVehicles(VehicleType.Helicopter)
            .MoveByVector(fightersToTheRight ? MagicConstants.InitialGapSize : -MagicConstants.InitialGapSize, 0);
            commands.Add(CommandManager.PeekLastCommand(Id));
        }
Example #14
0
        public static void PreventNuke(this IVehicleFormation formation, VehiclesGroup myArmy, World world, Game game, IList <Command> commands)
        {
            var opponentPlayer = world.GetOpponentPlayer();

            myArmy
            .Select(formation.Id)
            .Stop()
            .SelectArea(
                opponentPlayer.NextNuclearStrikeX - game.TacticalNuclearStrikeRadius,
                opponentPlayer.NextNuclearStrikeY - game.TacticalNuclearStrikeRadius,
                opponentPlayer.NextNuclearStrikeX + game.TacticalNuclearStrikeRadius,
                opponentPlayer.NextNuclearStrikeY + game.TacticalNuclearStrikeRadius,
                true
                )
            .Scale(
                opponentPlayer.NextNuclearStrikeX,
                opponentPlayer.NextNuclearStrikeY,
                10.0,
                tick => tick - world.TickIndex > game.TacticalNuclearStrikeDelay)
            .Scale(opponentPlayer.NextNuclearStrikeX,
                   opponentPlayer.NextNuclearStrikeY,
                   0.1);
            commands.Add(formation.CommandManager.PeekLastCommand(formation.Id));
        }
        public override VehicleFormationResult PerformAction(World world, Player me, Game game)
        {
            var army = new VehiclesGroup(Id, VehicleIds, VehicleRegistry, CommandManager);

            if (!binded)
            {
                Bind(army);
                return(new VehicleFormationResult(this));
            }

            commands.RemoveAll(c => c.IsStarted() && c.IsFinished(world.TickIndex, VehicleRegistry));


            if (FormationHelper.IsNukeAlert(world.GetOpponentPlayer()) && world.TickIndex - nukePreventionTick > game.BaseTacticalNuclearStrikeCooldown / 2)
            {
                commands.Clear();
                CommandManager.ClearCommandsQueue(Id);
                this.PreventNuke(army, world, game, commands);
                nukePreventionTick = world.TickIndex;
                return(new VehicleFormationResult(this));
            }

            if (commands.Any())
            {
                return(new VehicleFormationResult(this));
            }

            var closestUncapturedFacility = VehicleRegistry.GetUncapturedFacilities(world, me, Id)
                                            .Where(f => f.Type == FacilityType.VehicleFactory)
                                            .OrderBy(f => army.Center.GetDistanceTo(f.ToPoint(game)))
                                            .FirstOrDefault();
            var myGroudForcesCenter = VehicleRegistry.GetVehiclesByIds(
                VehicleRegistry.GetVehicleIdsByFormationId(MagicConstants.GroundFormationGroupId))
                                      .ToList()
                                      .GetCenterPoint();
            var enemyVehicles = VehicleRegistry.EnemyVehicles(me);

            var enemies      = Dbscan.GetEnemiesClusters(enemyVehicles, DbscanRadius, DbscanMinimumClusterSize, world.TickIndex);
            var nearestEnemy = enemies.OrderBy(c => c.GetCenterPoint().GetDistanceTo(army.Center)).FirstOrDefault();

            if (nearestEnemy != null &&
                this.TryNuke(army, VehicleRegistry.GetVehiclesByIds(army.VehicleIds), nearestEnemy, me, game, world, commands))
            {
                return(new VehicleFormationResult(new ShrinkAirVehicleFormation(Id, VehicleIds, CommandManager, VehicleRegistry)));
            }

            if (nearestEnemy != null &&
                army.Center.GetDistanceTo(nearestEnemy.GetCenterPoint()) < game.TankVisionRange * 0.8 &&
                nearestEnemy.Count > 1.2 * VehicleIds.Count)
            {
                army
                .Select(Id)
                .MoveByVector(nearestEnemy.GetCenterPoint().To(army.Center), game.TankSpeed);
                commands.Add(CommandManager.PeekLastCommand(Id));
                return(new VehicleFormationResult(this));
            }
            var nextTarget = closestUncapturedFacility?.ToPoint(game) ?? myGroudForcesCenter;

            if (army.Center.GetDistanceTo(myGroudForcesCenter) < MagicConstants.NewVehiclesJoinRadius)
            {
                army
                .Select(Id)
                .Assign(MagicConstants.GroundFormationGroupId);
                return(new VehicleFormationResult());
            }
            var direction = army.Center.To(nextTarget);

            army
            .Select(Id)
            .MoveByVector(direction.Length() > 20
                                                ? direction.Mul(0.1)
                                                : direction,
                          game.TankSpeed);
#if DEBUG
            RewindClient.Instance.Line(army.Center.X, army.Center.Y, nextTarget.X, nextTarget.Y, Color.Fuchsia);
#endif
            commands.Add(CommandManager.PeekLastCommand(Id));
            return(new VehicleFormationResult(this));
        }
        private void VerticalFormation(double x1,
                                       double y1,
                                       double x2,
                                       double y2,
                                       IList <Vehicle> allUnits,
                                       Point2D centerOfTanks,
                                       Point2D centerOfArrvs,
                                       Point2D centerOfIfvs)
        {
            for (var i = 0; i < 10; i++)
            {
                var inc = 1 + i * Adjustment + i * Step;
                CommandManager.EnqueueCommand(new SelectCommand(Id, x1 + inc, y1, x2 + inc, y2, VehicleType.Tank));
                CommandManager.EnqueueCommand(new AddToSelectionCommand(Id, x1 + inc, y1, x2 + inc, y2, VehicleType.Arrv));
                CommandManager.EnqueueCommand(new AddToSelectionCommand(Id, x1 + inc, y1, x2 + inc, y2, VehicleType.Ifv, true));
                var moveCommand = new MoveCommand(Id, allUnits.Select(v => v.Id).ToList(), Step, 0);
                CommandManager.EnqueueCommand(moveCommand);
                commands.Add(moveCommand);
            }

            var upperGroupType = FormationHelper.GetUpperOrLeftGroupType(centerOfTanks.Y, centerOfArrvs.Y, centerOfIfvs.Y);
            var upperGroup     = new VehiclesGroup(Id,
                                                   allUnits
                                                   .Where(v => v.Type == upperGroupType)
                                                   .Select(v => v.Id)
                                                   .ToList(),
                                                   VehicleRegistry,
                                                   CommandManager);
            var bottomGroupType = FormationHelper.GetBottomOrRightGroupType(centerOfTanks.Y, centerOfArrvs.Y, centerOfIfvs.Y);
            var bottomGroup     = new VehiclesGroup(Id,
                                                    allUnits
                                                    .Where(v => v.Type == bottomGroupType)
                                                    .Select(v => v.Id)
                                                    .ToList(),
                                                    VehicleRegistry,
                                                    CommandManager);

            upperGroup
            .SelectVehicles(VehicleType.Tank)
            .AddToSelectionVehicles(VehicleType.Arrv)
            .AddToSelectionVehicles(VehicleType.Ifv)
            .MoveByVector(Adjustment, 0);
            commands.Add(CommandManager.PeekLastCommand(Id) as MoveCommand);

            bottomGroup
            .SelectVehicles(VehicleType.Tank)
            .AddToSelectionVehicles(VehicleType.Arrv)
            .AddToSelectionVehicles(VehicleType.Ifv)
            .MoveByVector(-Adjustment, 0);
            commands.Add(CommandManager.PeekLastCommand(Id) as MoveCommand);

            upperGroup
            .SelectVehicles(VehicleType.Tank)
            .AddToSelectionVehicles(VehicleType.Arrv)
            .AddToSelectionVehicles(VehicleType.Ifv)
            .MoveByVector(0, MagicConstants.InitialGapSize, canBeParallel: true);
            commands.Add(CommandManager.PeekLastCommand(Id) as MoveCommand);

            bottomGroup
            .SelectVehicles(VehicleType.Tank)
            .AddToSelectionVehicles(VehicleType.Arrv)
            .AddToSelectionVehicles(VehicleType.Ifv)
            .MoveByVector(0, -MagicConstants.InitialGapSize);
            commands.Add(CommandManager.PeekLastCommand(Id) as MoveCommand);
        }
        public override VehicleFormationResult PerformAction(World world, Player me, Game game)
        {
#if DEBUG
            if (cachedTargetGroup != null)
            {
                foreach (var cachedTarget in VehicleRegistry.GetVehiclesByIds(cachedTargetGroup))
                {
                    RewindClient.Instance.Rectangle(cachedTarget.X - game.VehicleRadius,
                                                    cachedTarget.Y - game.VehicleRadius,
                                                    cachedTarget.X + game.VehicleRadius,
                                                    cachedTarget.Y + game.VehicleRadius,
                                                    Color.Pink);
                }
            }
#endif
            var myArmy = new VehiclesGroup(Id, VehicleIds, VehicleRegistry, CommandManager);
            commands.RemoveAll(c => c.IsStarted() && c.IsFinished(world.TickIndex, VehicleRegistry));

            if (commands.Any())
            {
                return(new VehicleFormationResult(this));
            }

            if (FormationHelper.IsNukeAlert(world.GetOpponentPlayer()) && world.TickIndex - nukePreventionTick > game.BaseTacticalNuclearStrikeCooldown / 2)
            {
                commands.Clear();
                CommandManager.ClearCommandsQueue(Id);
                this.PreventNuke(myArmy, world, game, commands);
                nukePreventionTick = world.TickIndex;
                return(new VehicleFormationResult(this));
            }

            var myVehicles = VehicleRegistry.GetVehiclesByIds(VehicleIds).ToList();

            if (cachedTargetGroup != null &&
                this.TryNuke(myArmy, myVehicles, VehicleRegistry.GetVehiclesByIds(cachedTargetGroup), me, game, world, commands))
            {
                return(new VehicleFormationResult(new ShrinkAirVehicleFormation(Id, VehicleIds, CommandManager, VehicleRegistry)));
            }

            if (commands.Any(c => !c.IsFinished(world.TickIndex, VehicleRegistry)))
            {
                return(new VehicleFormationResult(this));
            }

            Vector2D direction;
            var      groundFormationVehicles = VehicleRegistry.GetVehiclesByIds(
                VehicleRegistry.GetVehicleIdsByFormationId(MagicConstants.GroundFormationGroupId))
                                               .ToList();
            var myGroudForcesCenter = groundFormationVehicles.Any()
                                ? groundFormationVehicles.GetCenterPoint()
                                : new Point2D(0, 0);
            if (TimeToRetreat(myVehicles))
            {
#if DEBUG
                RewindClient.Instance.Message("=== TIME TO RETREAT! ===");
#endif
                var ifvs = groundFormationVehicles.Where(v => v.Type == VehicleType.Ifv).ToList();
                if (ifvs.Any())
                {
                    var ifvsCenter = ifvs.GetCenterPoint();
                    if (myArmy.Center.GetDistanceTo(ifvsCenter) < 10)
                    {
                        return(new VehicleFormationResult(this));
                    }
                    direction = myArmy.Center.To(ifvsCenter);
                }
                else
                {
                    if (myArmy.Center.GetDistanceTo(myGroudForcesCenter) < 10)
                    {
                        myArmy
                        .Select(MagicConstants.AirFormationGroupId)
                        .Assign(MagicConstants.GroundFormationGroupId);
                        return(new VehicleFormationResult());
                    }
                    direction = myArmy.Center.To(myGroudForcesCenter);
                }
            }
            else
            {
                var nextTargetGroup        = NextTargetGroup(myArmy, world, me);
                var closest                = VehicleRegistry.GetVehiclesByIds(nextTargetGroup).GetClosest(myGroudForcesCenter);
                var nextTargetClosestPoint = nextTargetGroup.Any()
                                        ? (closest?.ToPoint() ?? new Point2D(0, 0))
                                        : VehicleRegistry
                                             .GetUncapturedFacilities(world, me, Id)
                                             .Select(f => f.ToPoint(game))
                                             .FirstOrDefault();

                var minimumDistanceToNextTargetCenter          = myVehicles.GetMinimumDistanceTo(nextTargetClosestPoint);
                var minimumDistanceToNextTargetCenterCondition = minimumDistanceToNextTargetCenter > 0.8 * game.HelicopterVisionRange;
                var nextTargetGroupCount = nextTargetGroup.Count;
                var myVehiclesCount      = VehicleIds.Count;
                var countCondition       = nextTargetGroupCount < myVehiclesCount / 2 - 1;
                var myForcesCenterToNextTargetCenterDistance = myGroudForcesCenter.GetDistanceTo(nextTargetClosestPoint);
                var myGroundForcesToMyArmyCenterCondition    = myGroudForcesCenter.GetDistanceTo(myArmy.Center);
                var myGroundForcesCondition = myForcesCenterToNextTargetCenterDistance < myGroundForcesToMyArmyCenterCondition;

#if DEBUG
                RewindClient.Instance.Message($"=== minimumDistanceToNextTargetCenter = {minimumDistanceToNextTargetCenter} ===");
                RewindClient.Instance.Message($"=== minimumDistanceToNextTargetCenterCondition = {minimumDistanceToNextTargetCenterCondition} ===");
                RewindClient.Instance.Message($"=== nextTargetGroupCount = {nextTargetGroupCount} ===");
                RewindClient.Instance.Message($"=== myVehiclesCount = {myVehiclesCount} ===");
                RewindClient.Instance.Message($"=== countCondition = {countCondition} ===");
                RewindClient.Instance.Message($"=== myForcesCenterToNextTargetCenterDistance = {myForcesCenterToNextTargetCenterDistance} ===");
                RewindClient.Instance.Message($"=== myGroundForcesToMyArmyCenterCondition = {myGroundForcesToMyArmyCenterCondition} ===");
                RewindClient.Instance.Message($"=== myGroundForcesCondition = {myGroundForcesCondition} ===");
#endif

                direction = minimumDistanceToNextTargetCenterCondition ||
                            countCondition ||
                            myGroundForcesCondition
                                                ? myArmy.Center.To(nextTargetClosestPoint)
                                                : nextTargetClosestPoint.To(myArmy.Center);
            }

            myArmy
            .Select(Id)
            .MoveByVector(direction.Length() > 5
                                                ? direction.Mul(0.1)
                                                : direction,
                          game.HelicopterSpeed * game.RainWeatherSpeedFactor);
#if DEBUG
            RewindClient.Instance.Line(myArmy.Center.X, myArmy.Center.Y, myArmy.Center.X + direction.X, myArmy.Center.Y + direction.Y, Color.Fuchsia);
#endif
            commands.Add(CommandManager.PeekLastCommand(Id));
            return(new VehicleFormationResult(this));
        }
        private void DoWork(Player me)
        {
            var myVehicles = VehicleRegistry.MyVehicles(me);

            var fightersGroup = new VehiclesGroup(Id,
                                                  myVehicles
                                                  .Where(v => v.Type == VehicleType.Fighter)
                                                  .Select(v => v.Id)
                                                  .ToList(),
                                                  VehicleRegistry,
                                                  CommandManager);
            var helicoptersGroup = new VehiclesGroup(Id,
                                                     myVehicles
                                                     .Where(v => v.Type == VehicleType.Helicopter)
                                                     .Select(v => v.Id)
                                                     .ToList(),
                                                     VehicleRegistry,
                                                     CommandManager);

            var leftPoint  = new Point2D(MagicConstants.InitialGapSize * 1, MagicConstants.InitialGapSize * 3);
            var rightPoint = new Point2D(MagicConstants.InitialGapSize * 3, MagicConstants.InitialGapSize * 1);


            if (fightersGroup.Center.GetDistanceTo(leftPoint) < helicoptersGroup.Center.GetDistanceTo(leftPoint))
            {
                fightersGroup
                .SelectVehicles(VehicleType.Fighter)
                .MoveTo(leftPoint);

                helicoptersGroup
                .SelectVehicles(VehicleType.Helicopter)
                .MoveTo(rightPoint);

                fightersGroup
                .SelectVehicles(VehicleType.Fighter)
                .MoveByVector(0, -MagicConstants.InitialGapSize, canBeParallel: true);
                commands.Add(CommandManager.PeekLastCommand(Id) as MoveCommand);

                helicoptersGroup
                .SelectVehicles(VehicleType.Helicopter)
                .MoveByVector(0, MagicConstants.InitialGapSize);
                commands.Add(CommandManager.PeekLastCommand(Id) as MoveCommand);
            }
            else
            {
                fightersGroup
                .SelectVehicles(VehicleType.Fighter)
                .MoveTo(rightPoint);

                helicoptersGroup
                .SelectVehicles(VehicleType.Helicopter)
                .MoveTo(leftPoint);

                fightersGroup
                .SelectVehicles(VehicleType.Fighter)
                .MoveByVector(0, MagicConstants.InitialGapSize, canBeParallel: true);
                commands.Add(CommandManager.PeekLastCommand(Id) as MoveCommand);

                helicoptersGroup
                .SelectVehicles(VehicleType.Helicopter)
                .MoveByVector(0, -MagicConstants.InitialGapSize);
                commands.Add(CommandManager.PeekLastCommand(Id) as MoveCommand);
            }
        }