public void EvaluateNetworks(ref GnnModel gnnModel)
        {
            // Prevent from negative scores
            var minFitness = gnnModel.ActiveBatchModel.Networks.Min(n => n.FitnessScore);

            // If smallest fitness score is negative we add to all networks amount that needed to
            // zero smallest fitness-score;
            if (minFitness <= 0)
            {
                minFitness = Math.Abs(minFitness) + 1;
                foreach (var network in gnnModel.ActiveBatchModel.Networks)
                {
                    network.FitnessScore += minFitness + 1;
                }
            }

            foreach (var specie in gnnModel.Species)
            {
                _speciesController.CalculateAverageScore(specie);
                _speciesController.SortByFitnessScores(specie);
            }
            //SortSpeciesByAverageFitnessScore(ref gnnModel);
            CalculateFullFitnessScore(ref gnnModel);

            _batchController.UpdateBestPerformingNetwork(gnnModel.ActiveBatchModel);
        }
        public void TrainGeneration(GnnModel model)
        {
            _gnnController.SpecifyNetworks(ref model);
            for (var i = 0; i < model.ActiveBatchModel.Networks.Count - 1; i++)
            {
                var currentNet = model.ActiveBatchModel.Networks[i];
                for (var x = i + 1; x < model.ActiveBatchModel.Networks.Count; x++)
                {
                    var compNet = model.ActiveBatchModel.Networks[x];

                    var gameOne = new GameController(_netNeatController, currentNet, compNet);
                    gameOne.DoMove();

                    var gameTwo = new GameController(_netNeatController, compNet, currentNet);
                    gameOne.DoMove();

                    var gameOneResult = gameOne.CheckGrid();
                    var gameTwoResult = gameTwo.CheckGrid();

                    if (gameOneResult == 1 || gameTwoResult == -1)
                    {
                        currentNet.FitnessScore++;
                        compNet.FitnessScore--;
                    }

                    if (gameOneResult == -1 || gameTwoResult == 1)
                    {
                        currentNet.FitnessScore--;
                        compNet.FitnessScore++;
                    }
                }
            }
            _gnnController.EvaluateNetworks(ref model);
            _gnnController.PopulateNextGeneration(ref model);
        }
        // Works only if fitness scours are all positive
        private static SpeciesModel GetRandomSpeciesModel(GnnModel gnnModel)
        {
            var rnd             = new Random();
            var targetRange     = rnd.Next(0, (int)Math.Ceiling(gnnModel.FullFitnessScore));
            var currentScoreSum = 0.0;

            for (var i = 0; i < gnnModel.Species.Count - 1; i++)
            {
                currentScoreSum += gnnModel.Species[i].AverageFitnessScore;
                if (targetRange <= currentScoreSum)
                {
                    return(gnnModel.Species[i]);
                }
            }
            return(gnnModel.Species.LastOrDefault());
        }
        /// <summary>
        /// From unsigned network list fetches all networks and splits them into
        /// families/species, witch is done by using Neat network similarity algorithm.
        /// </summary>
        /// <param name="gnnModel">Network to specify</param>
        public void SpecifyNetworks(ref GnnModel gnnModel)
        {
            gnnModel.UnsignedNetworks = new List <NetModel>(gnnModel.ActiveBatchModel.Networks);

            // If nothing assign return
            if (gnnModel.UnsignedNetworks.Count == 0)
            {
                return;
            }

            gnnModel.Species = new List <SpeciesModel>();
            foreach (var network in gnnModel.UnsignedNetworks)
            {
                // Resets fitness score to 0 on each run
                network.FitnessScore = 0;

                // Checks if current network is in the same family/specie as
                // already existing ones
                var isNewSpecies = true;
                foreach (var specie in gnnModel.Species)
                {
                    if (_speciesController.IsSameFamily(network, specie.Head))
                    {
                        specie.Members.Add(network);
                        isNewSpecies = false;
                        break;
                    }
                }
                // If its not then new specie is created, and its head is assigned as current network,
                // so that later we can compare species.Hed with other networks to determine its relationship
                // to specie.
                if (isNewSpecies)
                {
                    gnnModel.Species.Add(_speciesController.GetNewWithHead(network));
                }
            }

            gnnModel.UnsignedNetworks.Clear();
        }
 /// <summary>
 /// Sums all species average fitness scores.
 /// And assigns value to gnnModel.FullFitnessScore
 /// </summary>
 /// <param name="gnnModel"></param>
 private static void CalculateFullFitnessScore(ref GnnModel gnnModel)
 {
     gnnModel.FullFitnessScore = gnnModel.Species.Sum(s => s.AverageFitnessScore);
 }
        public void PopulateNextGeneration(ref GnnModel gnnModel)
        {
            gnnModel.UnsignedNetworks = new List <NetModel>();
            _batchController.IncreaseGeneration(gnnModel.ActiveBatchModel);

            #region Adds survivors to next generation

            // Adds survivors of each specie to the next generation
            foreach (var specie in gnnModel.Species)
            {
                // Calculates how many networks keep
                var keepAlive = (int)(specie.Members.Count * Config.KeepPerSpecies);

                // We want at-least one survivor per specie.
                if (keepAlive <= 0)
                {
                    keepAlive = 1;
                }

                // Ads them to next gen.
                for (var i = 0; i < keepAlive; i++)
                {
                    gnnModel.UnsignedNetworks.Add(specie.Members[i]);
                    specie.Members[i].Enabled = true;
                    _netController.Save(specie.Members[i]);
                }

                // Disables old networks
                for (var i = keepAlive; i < specie.Members.Count; i++)
                {
                    specie.Members[i].Enabled = false;
                    _netController.Save(specie.Members[i]);
                }
            }
            #endregion

            #region Populates empty spaces with offspings

            // Populates rest of generation with offspring of survivors
            var networksToAdd = Config.NetworkCountPerPopulation - gnnModel.UnsignedNetworks.Count;
            for (var i = 0; i < networksToAdd; i++)
            {
                var specie = GetRandomSpeciesModel(gnnModel);

                var mother = _speciesController.GetRandomNetModel(specie);
                var father = _speciesController.GetRandomNetModel(specie);

                var child = _breedingController.Breed(gnnModel.ActiveBatchModel, mother, father);

                _mutationController.MutateWithBatch(ref child, 1);  // Add node mutation
                _mutationController.MutateWithBatch(ref child, 2);  // Add connection mutation
                _mutationController.MutateWithBatch(ref child, 3);  // Connections weight mutation

                // If mutation caused dysfunction replace network with new one
                if (IsBroken(child))
                {
                    _netController.Kill(child);
                    child = _netController.New(gnnModel.ActiveBatchModel);
                }

                // Orders
                child.Connections = child.Connections.OrderBy(c => c.InnovationId).ToList();
                child.Nodes       = child.Nodes.OrderBy(n => n.InnovationId).ToList();
                child.Enabled     = true;
                _netController.Save(child);
                gnnModel.UnsignedNetworks.Add(child);
            }
            #endregion

            // Rebuilds batch from db (Why? Because innovation table has changed)
            gnnModel.ActiveBatchModel = _batchController.Load(gnnModel.ActiveBatchModel.Id);
        }
 private static void SortSpeciesByAverageFitnessScore(ref GnnModel gnnModel)
 {
     gnnModel.Species = gnnModel.Species.OrderByDescending(s => s.AverageFitnessScore).ToList();
 }