/// <summary>
        /// Apply random mutation using a mutation factor, default is 0.01
        /// </summary>
        public Gene Mutate(Gene gene, float mutationFactor = 0.01f)
        {
            var backup = new Gene(gene);

            for (int i = 0; i < gene.Count; i++)
            {
                var mutate = Utility.CheckProbability(mutationFactor);
                if (mutate)
                {
                    var    randomType = Utility.GetRandomAction();
                    Action action     = null;

                    switch (randomType)
                    {
                    case ActionType.Move:
                        action = new MoveAction();
                        break;

                    case ActionType.Turn:
                        action = new TurnAction();
                        break;

                    case ActionType.Look:
                        action = new LookAction(_objectiveAgent, _escapeAgent);
                        break;
                    }
                    gene[i] = action;
                }
            }

            //discard mutation if not valid
            return(!gene.IsValid() ? backup : gene);
        }
        /// <summary>
        /// Returns the offspring genes resulting from a single point crossover chosen at random
        /// </summary>
        public Gene[] SinglePointCrossover(Gene parent1, Gene parent2)
        {
            var crossoverPosition = UnityEngine.Random.Range(0, _geneSize);

            var offspring1 = new List <Action>();
            var offspring2 = new List <Action>();

            for (int chromosome = 0; chromosome < _geneSize; chromosome++)
            {
                var p1 = parent1[chromosome];
                var p2 = parent2[chromosome];

                var swap = crossoverPosition >= chromosome;
                if (swap)
                {
                    offspring2.Add(p1);
                    offspring1.Add(p2);
                }
                else
                {
                    offspring1.Add(p1);
                    offspring2.Add(p2);
                }
            }

            var child1 = new Gene(offspring1);
            var child2 = new Gene(offspring2);

            if (!child1.IsValid() || !child2.IsValid())
            {
                return(SinglePointCrossover(parent1, parent2));
            }

            return(new Gene[]
            {
                child1,
                child2
            });
        }
        /// <summary>
        /// Returns 2 offsprings using Uniform UniformCrossover, by default using 0.5 ratio
        /// </summary>
        public Gene[] UniformCrossover(Gene parent1, Gene parent2, float crossoverRatio = 0.5f)
        {
            var offspring1 = new List <Action>();
            var offspring2 = new List <Action>();

            for (int chromosome = 0; chromosome < _geneSize; chromosome++)
            {
                var p1 = parent1[chromosome];
                var p2 = parent2[chromosome];

                var swap = Utility.CheckProbability(crossoverRatio);
                if (swap)
                {
                    offspring2.Add(p1);
                    offspring1.Add(p2);
                }
                else
                {
                    offspring1.Add(p1);
                    offspring2.Add(p2);
                }
            }

            var child1 = new Gene(offspring1);
            var child2 = new Gene(offspring2);

            if (!child1.IsValid() || !child2.IsValid())
            {
                return(UniformCrossover(parent1, parent2, crossoverRatio));
            }

            return(new Gene[]
            {
                child1,
                child2
            });
        }