/// <summary>
 /// Initializes a new instance of the <see cref="ToyExperiment" /> class.
 /// </summary>
 /// <param name="model">The model.</param>
 /// <param name="game">The game.</param>
 /// <param name="priors">The priors.</param>
 public ToyExperiment(IModel model, Game game, Marginals priors)
 {
     Model      = model;
     Game       = game;
     Priors     = priors;
     Posteriors = Model.Train(Game, Game.Players, Priors).Posteriors;
 }
        /// <summary>
        /// Demonstration of Dynamics.
        /// </summary>
        /// <param name="trueBeta">The true beta.</param>
        /// <param name="beta">The beta.</param>
        /// <param name="stepSize">Size of the step.</param>
        public void DynamicsDemo(double trueBeta, double beta, double stepSize)
        {
            var randomNames = new RandomNameGenerator(0, int.MaxValue, true);

            var    players  = new HashSet <string>(randomNames.Take(100));
            string improver = players.First();

            const double Mu                = 125;
            const double Sigma             = 10;
            var          skillDistribution = new Gaussian(Mu, Sigma * Sigma);
            const double Gamma             = 0.4;


            const double SkillStart = 110;
            const double SkillMax   = 140;

            var inputs1 = new Inputs <TwoPlayerGame> {
                Mu = Mu, Sigma = Sigma, Beta = beta, Gamma = 0
            };
            var inputs2 = new Inputs <TwoPlayerGame> {
                Mu = Mu, Sigma = Sigma, Beta = beta, Gamma = Gamma
            };

            double truePerformanceVariance = trueBeta * trueBeta;

            // number of games
            const int NumberOfGames = 25000;

            var skill1 = Gaussian.PointMass(SkillStart);

            var random = new Random(0);

            var initialSkills = players.ToDictionary(ia => ia, ia => Gaussian.PointMass(skillDistribution.Sample()));

            initialSkills[improver] = skill1;

            var trueSkills = new Dictionary <string, List <double> > {
                { improver, new List <double>() }
            };

            for (int i = 0; i < NumberOfGames; i++)
            {
                // Pick two players to play game
                var gamePlayers = players.OrderBy(ia => random.Next()).Take(2).ToList();

                // update improver's skill
                var truth = new Marginals {
                    Skills = new Dictionary <string, Gaussian>(initialSkills)
                };
                truth.Skills[improver] = skill1;

                // Generate game according to truth
                var game = TwoPlayerVaryingSkills.Sample(truth, gamePlayers, truePerformanceVariance);
                inputs1.Games.Add(game);
                inputs2.Games.Add(game);

                if (gamePlayers.Contains(improver))
                {
                    trueSkills[improver].Add(skill1.Point);

                    // Update skill
                    if (trueSkills[improver].Count > 100 && (trueSkills[improver].Count % 100) >= 90 && skill1.Point < SkillMax)
                    {
                        skill1 = Gaussian.PointMass(skill1.Point + stepSize);
                    }
                }
            }

            var experiment1 = new OnlineExperiment(ia => new TwoPlayerVaryingSkills(ia, ShowFactorGraph), inputs1.TrueSkillParameters)
            {
                Players = players,
                Priors  = inputs1.TrueSkillPriors,
                Name    = "Fixed skill model"
            };

            var experiment2 = new OnlineExperiment(ia => new TwoPlayerVaryingSkills(ia, ShowFactorGraph), inputs2.TrueSkillParameters)
            {
                Players = players,
                Priors  = inputs2.TrueSkillPriors,
                Name    = "Varying skill model"
            };

            AnnounceExperiment(experiment1.Name);
            experiment1.Run(inputs1.Games, inputs1.Games.Count, false);
            AnnounceExperiment(experiment2.Name);
            experiment2.Run(inputs2.Games, inputs2.Games.Count, false);

            var experiments1 = new OnlineExperimentComparison <TwoPlayerGame>(experiment1)
            {
                Truth = trueSkills
            };
            var experiments2 = new OnlineExperimentComparison <TwoPlayerGame>(experiment2)
            {
                Truth = trueSkills
            };

            var initialSkillsTable =
                initialSkills.OrderByDescending(ia => ia.Key)
                .ToDictionaryForTable <KeyValuePair <string, Gaussian>, string, double, double>(
                    ia => ia.Key,
                    new Dictionary <string, Func <KeyValuePair <string, Gaussian>, double> > {
                { "Skill", g => g.Value.Point }
            },
                    false,
                    null,
                    "Player");

            var collection = new OnlineExperimentComparison <TwoPlayerGame>(experiment1, experiment2)
            {
                Truth = trueSkills
            };

            var dynamicsDemo = new Dictionary <string, object>
            {
                { "InitialSkills", initialSkillsTable },
                { "SampledInputs", inputs1 },
                {
                    "Trajectories",
                    new[]
                    {
                        experiments1.PlayerTrajectoriesWithSigmaAndTruth,
                        experiments2.PlayerTrajectoriesWithSigmaAndTruth,
                        collection.PlayerTrajectoriesWithSigmaAndTruth
                    }
                }
            };

            outputter.Out(dynamicsDemo,
                          Contents.S5AllowingTheSkillsToVary.NumberedName,
                          "DynamicsDemo");
        }