Esempio n. 1
0
        private void EnsureThrustKeysBuilt_Finish(KeyThrustRequest[] requests)
        {
            // Remember the mappings between key and desired thrust (this is used to drive the impulse engine)
            _keyThrustRequests = requests;

            if (this.Thrusters == null || this.Thrusters.Length == 0)
            {
                _isThrustMapDirty = false;
                return;
            }

            if (_cancelCurrentBalancer != null)
            {
                _cancelCurrentBalancer.Cancel();
                _cancelCurrentBalancer = null;
            }

            // Remember the current solutions, so they can help get a good start on the new solver
            var previous = _thrustLines.Values.ToArray();

            _thrustLines.Clear();
            _cancelCurrentBalancer = new CancellationTokenSource();

            ThrustContributionModel model = new ThrustContributionModel(this.Thrusters, this.PhysicsBody.CenterOfMass);
            MassMatrix inertia            = this.PhysicsBody.MassMatrix;
            double     mass = inertia.Mass;

            // Several key combos may request the same direction, so group them
            var grouped = requests.
                          ToLookup(KeyThrustRequestComparer);

            foreach (var set in grouped)
            {
                // Create wrappers for this set
                ThrusterSolution[] solutionWrappers = set.
                                                      Select(o => new ThrusterSolution(o, model, inertia, mass)).
                                                      ToArray();

                // Store the wrappers
                foreach (var wrapper in solutionWrappers)
                {
                    _thrustLines.Add(Tuple.Create(wrapper.Request.Key, wrapper.Request.Shift), wrapper);
                }

                // This delegate gets called when a better solution is found.  Distribute the map to the solution wrappers
                var newBestFound = new Action <ThrusterMap>(o =>
                {
                    ThrusterSolutionMap solutionMap = GetThrusterSolutionMap(o, model, inertia, mass);

                    foreach (ThrusterSolution wrapper in solutionWrappers)
                    {
                        wrapper.Map = solutionMap;
                    }
                });

                var options = new DiscoverSolutionOptions2 <Tuple <int, int, double> >()
                {
                    //MaxIterations = 2000,     //TODO: Find a reasonable stop condition
                    ThreadShare = _thrustWorkerThread,
                };

                // Find the previous solution for this request
                var prevMatch = previous.FirstOrDefault(o => KeyThrustRequestComparer(set.Key, o.Request));
                if (prevMatch != null && prevMatch.Map != null)
                {
                    options.Predefined = new[] { prevMatch.Map.Map.Flattened };
                }

                // Find the combination of thrusters that push in the requested direction
                //ThrustControlUtil.DiscoverSolutionAsync(this, solutionWrappers[0].Request.Linear, solutionWrappers[0].Request.Rotate, _cancelCurrentBalancer.Token, model, newBestFound, null, options);
                ThrustControlUtil.DiscoverSolutionAsync2(this, solutionWrappers[0].Request.Linear, solutionWrappers[0].Request.Rotate, _cancelCurrentBalancer.Token, model, newBestFound, options: options);
            }

            _isThrustMapDirty = false;
        }
Esempio n. 2
0
        private void EnsureThrustKeysBuilt_Finish(KeyThrustRequest[] requests)
        {
            if (_cancelCurrentBalancer != null)
            {
                _cancelCurrentBalancer.Cancel();
                _cancelCurrentBalancer = null;
            }

            // Remember the current solutions, so they can help get a good start on the new solver
            var previous = _thrustLines.Values.ToArray();

            _thrustLines.Clear();
            _cancelCurrentBalancer = new CancellationTokenSource();

            ThrustContributionModel model = new ThrustContributionModel(this.Thrusters, this.PhysicsBody.CenterOfMass);
            MassMatrix inertia = this.PhysicsBody.MassMatrix;
            double mass = inertia.Mass;

            // Several key combos may request the same direction, so group them
            var grouped = requests.
                ToLookup(KeyThrustRequestComparer);

            foreach (var set in grouped)
            {
                // Create wrappers for this set
                ThrusterSolution[] solutionWrappers = set.
                    Select(o => new ThrusterSolution(o, model, inertia, mass)).
                    ToArray();

                // Store the wrappers
                foreach (var wrapper in solutionWrappers)
                {
                    _thrustLines.Add(Tuple.Create(wrapper.Request.Key, wrapper.Request.Shift), wrapper);
                }

                // This delegate gets called when a better solution is found.  Distribute the map to the solution wrappers
                var newBestFound = new Action<ThrusterMap>(o =>
                {
                    ThrusterSolutionMap solutionMap = GetThrusterSolutionMap(o, model, inertia, mass);

                    foreach (ThrusterSolution wrapper in solutionWrappers)
                    {
                        wrapper.Map = solutionMap;
                    }
                });

                var options = new DiscoverSolutionOptions2<Tuple<int, int, double>>()
                {
                    //MaxIterations = 2000,     //TODO: Find a reasonable stop condition
                    ThreadShare = _thrustWorkerThread,
                };

                // Find the previous solution for this request
                var prevMatch = previous.FirstOrDefault(o => KeyThrustRequestComparer(set.Key, o.Request));
                if (prevMatch != null && prevMatch.Map != null)
                {
                    options.Predefined = new[] { prevMatch.Map.Map.Flattened };
                }

                // Find the combination of thrusters that push in the requested direction
                //ThrustControlUtil.DiscoverSolutionAsync(this, solutionWrappers[0].Request.Linear, solutionWrappers[0].Request.Rotate, _cancelCurrentBalancer.Token, model, newBestFound, null, options);
                ThrustControlUtil.DiscoverSolutionAsync2(this, solutionWrappers[0].Request.Linear, solutionWrappers[0].Request.Rotate, _cancelCurrentBalancer.Token, model, newBestFound, null, options);
            }

            _isThrustMapDirty = false;
        }
        public static void DiscoverSolutionAsync2(Bot bot, Vector3D? idealLinear, Vector3D? idealRotation, CancellationToken? cancel = null, ThrustContributionModel model = null, Action<ThrusterMap> newBestFound = null, Action<ThrusterMap> finalFound = null, DiscoverSolutionOptions2<Tuple<int, int, double>> options = null)
        {
            long token = bot.Token;

            // Cache Thrusters
            Thruster[] allThrusters = bot.Thrusters;
            if (allThrusters == null || allThrusters.Length == 0)
            {
                throw new ArgumentException("This bot has no thrusters");
            }

            // Ensure model is created (if the caller wants to find solutions for several directions at the same time, it would be
            // more efficient to calculate the model once, and pass to all the solution finders)
            model = model ?? new ThrustContributionModel(bot.Thrusters, bot.PhysicsBody.CenterOfMass);

            // Figure out how much force can be generated in the ideal directions
            double maxForceLinear = idealLinear == null ? 0d : ThrustControlUtil.GetMaximumPossible_Linear(model, idealLinear.Value);
            double maxForceRotate = idealRotation == null ? 0d : ThrustControlUtil.GetMaximumPossible_Rotation(model, idealRotation.Value);

            // Mutate 2% of the elements, with a 10% value drift
            MutateUtility.MuateArgs mutateArgs = new MutateUtility.MuateArgs(false, .02, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, .1));

            #region delegates

            //NOTE: While breeding/mutating, they don't get normalized.  But error calculation and returned maps need them normalized

            var delegates = new DiscoverSolutionDelegates2<Tuple<int, int, double>>()
            {
                GetNewSample = new Func<Tuple<int, int, double>[]>(() =>
                {
                    ThrusterMap map = ThrustControlUtil.GenerateRandomMap(allThrusters, token);
                    return map.Flattened;
                }),

                GetScore = new Func<Tuple<int, int, double>[], double[]>(o =>
                {
                    ThrusterMap map = new ThrusterMap(ThrustControlUtil.Normalize(o), allThrusters, token);
                    return ThrustControlUtil.GetThrustMapScore3(map, model, idealLinear, idealRotation, maxForceLinear, maxForceRotate);
                }),

                Mutate = new Func<Tuple<int, int, double>[], Tuple<int, int, double>[]>(o =>
                {
                    ThrusterMap map = new ThrusterMap(o, allThrusters, token);
                    return ThrustControlUtil.Mutate(map, mutateArgs, false).Flattened;
                }),
            };

            if (cancel != null)
            {
                delegates.Cancel = cancel.Value;
            }

            if (newBestFound != null)
            {
                delegates.NewBestFound = new Action<SolutionResult2<Tuple<int, int, double>>>(o =>
                {
                    ThrusterMap map = new ThrusterMap(ThrustControlUtil.Normalize(o.Item), allThrusters, token);
                    newBestFound(map);
                });
            }

            if (finalFound != null)
            {
                delegates.FinalFound = new Action<SolutionResult2<Tuple<int, int, double>>>(o =>
                {
                    ThrusterMap map = new ThrusterMap(ThrustControlUtil.Normalize(o.Item), allThrusters, token);
                    finalFound(map);
                });
            }

            #endregion

            options = options ?? new DiscoverSolutionOptions2<Tuple<int, int, double>>();
            options.ScoreAscendDescend = new bool[] { false, false };

            // Do it
            //NOTE: If options.ThreadShare is set, then there's no reason to do this async, but there's no harm either
            Task.Run(() => UtilityAI.DiscoverSolution2(delegates, options));
        }