示例#1
0
    private static PathSolutionScript CrossOver(PathSolutionScript p1, PathSolutionScript p2)
    {
        var child = p1.Actions.Length > p2.Actions.Length ? new PathSolutionScript(p1.Actions.Length) : new PathSolutionScript(p2.Actions.Length);

        for (var i = 0; i < child.Actions.Length; i++)
        {
            if (i < p1.Actions.Length && i % 2 == 0)
            {
                child.Actions[i] = p1.Actions[i];
            }
            else if (i < p2.Actions.Length && i % 2 != 0)
            {
                child.Actions[i] = p2.Actions[i];
            }
            else if (i > p1.Actions.Length)
            {
                child.Actions[i] = p2.Actions[i];
            }
            else if (i > p2.Actions.Length)
            {
                child.Actions[i] = p1.Actions[i];
            }
        }
        return(child);
    }
示例#2
0
    public void LaunchSimulation(PathSolutionScript solution)
    {
        InSimulation = true;

        _initialPosition = transform.position;
        this.GetComponent <TrailRenderer>().time = _totalAnimationTime;
        _solution = solution;
        Initialize();
        StartCoroutine("PlaySolution", _totalAnimationTime);
    }
示例#3
0
    public PathSolutionScript CopySolution(PathSolutionScript sol)
    {
        var newSol = new PathSolutionScript(_totalSolutionSteps);

        for (int i = 0; i < sol.Actions.Length; i++)
        {
            newSol.Actions[i].Action = sol.Actions[i].Action;
        }

        return(newSol);
    }
示例#4
0
    /// <summary>
    /// Fonction utilitaire ayant pour but de copier
    /// dans un nouvel espace m�moire une solution
    /// </summary>
    /// <param name="sol">La solution � copier</param>
    /// <returns>Une copie de la solution</returns>
    public PathSolutionScript CopySolution(PathSolutionScript sol)
    {
        // Initialisation de la nouvelle s�quence d'action
        // de la m�me longueur que celle que l'on souhaite copier
        var newSol = new PathSolutionScript(sol.Actions.Length);

        // Pour chaque action de la s�quence originale,
        // on copie le type d'action.
        for (int i = 0; i < sol.Actions.Length; i++)
        {
            newSol.Actions[i].Action = sol.Actions[i].Action;
        }

        // Renvoi de la solution copi�e
        return(newSol);
    }
示例#5
0
    public IEnumerator NaiveLocalSearch()
    {
        _isRunning = true;

        var currentSolution = new PathSolutionScript(42);

        var scoreEnumerator = GetError(currentSolution);

        yield return(StartCoroutine(scoreEnumerator));

        float currentError = scoreEnumerator.Current;

        var minimumError = GetMinError();

        Debug.Log(currentError);

        int iterations = 0;

        while (currentError != minimumError)
        {
            var newsolution = CopySolution(currentSolution);

            RandomChangeInSolution(newsolution);

            var newscoreEnumerator = GetError(newsolution);
            yield return(StartCoroutine(newscoreEnumerator));

            float newError = newscoreEnumerator.Current;

            Debug.Log(currentError + "   -   " + newError);

            if (newError <= currentError)
            {
                currentSolution = newsolution;

                currentError = newError;
            }

            iterations++;

            yield return(null);
        }

        _isRunning = false;

        Debug.Log("CONGRATULATIONS !!! Solution Found in " + iterations + " iterations !");
    }
示例#6
0
    /// <summary>
    /// Exemple d'oracle nous renvoyant un score que l'on essaye de minimiser
    /// Ici est utilis� la position de la case d'arriv�e, la position finale
    /// atteinte par la solution. Il est recommand� d'essayer plusieurs oracles
    /// pour �tudier le comportement des algorithmes selon la qualit� de ces
    /// derniers
    ///
    /// Parmi les param�tres pouvant �tre utilis�s pour calculer le score/erreur :
    ///
    ///  - position de la case d'arriv�e    : PlayerScript.GoalXPositionInMatrix
    ///                                       PlayerScript.GoalYPositionInMatrix
    ///  - position du joueur               : player.PlayerXPositionInMatrix
    ///                                       player.PlayerYPositionInMatrix
    ///  - position de d�part du joueur     : PlayerScript.StartXPositionInMatrix
    ///                                       PlayerScript.StartYPositionInMatrix
    ///  - nombre de cases explor�es        : player.ExploredPuts
    ///  - nombre d'actions ex�cut�es       : player.PerformedActionsNumber
    ///  - vrai si le la balle a touch� la case d'arriv�e : player.FoundGoal
    ///  - vrai si le la balle a touch� un obstacle : player.FoundObstacle
    ///  - interrogation de la matrice      :
    ///       � la case de coordonn�e (i, j) est elle un obstacle (i et j entre 0 et 49) :
    ///           player.GetPutTypeAtCoordinates(i, j) == LayerMask.NameToLayer("Obstacle")
    ///       � la case de coordonn�e (i, j) est elle explor�e (i et j entre 0 et 49) :
    ///           player.GetPutTypeAtCoordinates(i, j) == 1
    ///       � la case de coordonn�e (i, j) est elle inexplor�e (i et j entre 0 et 49) :
    ///           player.GetPutTypeAtCoordinates(i, j) == 0
    /// </summary>
    /// <param name="solution"></param>
    /// <returns></returns>
    IEnumerator <float> GetError(PathSolutionScript solution)
    {
        // On indique que l'on s'appr�te � lancer la simulation
        _inSimulation = true;

        // On cr�� notre objet que va ex�cuter notre s�quence d'action
        var player = PlayerScript.CreatePlayer();

        // Pour pouvoir visualiser la simulation (moins rapide)
        player.RunWithoutSimulation = true;

        // On lance la simulation en sp�cifiant
        // la s�quence d'action � ex�cuter
        player.LaunchSimulation(solution);

        // Tout pendant que la simulation n'est pas termin�e
        while (player.InSimulation)
        {
            // On rend la main au moteur Unity3D
            yield return(-1f);
        }

        // Calcule la distance de Manhattan entre la case d'arriv�e et la case finale de
        // notre objet, la pond�re (la multiplie par z�ro si le but a �t� trouv�)
        // et ajoute le nombre d'actions jou�es
        var error = (Mathf.Abs(PlayerScript.GoalXPositionInMatrix - player.PlayerXPositionInMatrix)
                     + Mathf.Abs(PlayerScript.GoalYPositionInMatrix - player.PlayerYPositionInMatrix))
                    * (player.FoundGoal ? 0 : 100) +
                    player.PerformedActionsNumber;

        //Debug.Log(player.FoundGoal);

        // D�truit  l'objet de la simulation
        Destroy(player.gameObject);

        // Renvoie l'erreur pr�c�demment calcul�e
        yield return(error);

        // Indique que la phase de simulation est termin�e
        _inSimulation = false;
    }
示例#7
0
 /// <summary>
 /// Execute un changement al�atoire sur une solution
 /// ici, une action de la s�quence est tir�e au hasard et remplac�e
 /// par une nouvelle au hasard.
 /// </summary>
 /// <param name="sol"></param>
 public void RandomChangeInSolution(PathSolutionScript sol)
 {
     sol.Actions[Random.Range(0, sol.Actions.Length)] = new ActionSolutionScript();
 }
示例#8
0
    public IEnumerator SimulatedAnnealing()
    {
        _isRunning = true;

        var currentSolution = new PathSolutionScript(42);

        var scoreEnumerator = GetError(currentSolution);

        yield return(StartCoroutine(scoreEnumerator));

        float currentError = scoreEnumerator.Current;
        var   temperature  = 0f;
        var   stagnation   = 0;

        var minimumError = GetMinError();

        Debug.Log(currentError);

        int iterations = 0;

        while (currentError != minimumError)
        {
            float oldError = currentError;

            var newsolution = CopySolution(currentSolution);
            RandomChangeInSolution(newsolution);
            var newscoreEnumerator = GetError(newsolution);
            yield return(StartCoroutine(newscoreEnumerator));

            float newError = newscoreEnumerator.Current;

            Debug.Log(currentError + "   -   " + newError);
            var rdm = Random.Range(0f, 1f);
            if (rdm <= MetropolisCriterium(currentError, newError, temperature))
            {
                currentSolution = newsolution;
                currentError    = newError;
            }

            if (oldError == currentError)
            {
                stagnation++;
            }
            else
            {
                stagnation = 0;
            }
            if (stagnation > 200)
            {
                temperature = 6f;
                stagnation  = 0;
            }

            temperature *= 0.9999f;
            Debug.Log("Temperature: " + temperature + " Stagnation: " + stagnation);
            iterations++;
            yield return(0);
        }

        _isRunning = false;

        Debug.Log("CONGRATULATIONS !!! Solution Found in " + iterations + " iterations !");
    }
示例#9
0
    /// <summary>
    /// Fonction utilitaire ayant pour but de copier
    /// dans un nouvel espace mémoire une solution
    /// </summary>
    /// <param name="sol">La solution à copier</param>
    /// <returns>Une copie de la solution</returns>
    public PathSolutionScript CopySolution(PathSolutionScript sol)
    {
        // Initialisation de la nouvelle séquence d'action
        // de la même longueur que celle que l'on souhaite copier
        var newSol = new PathSolutionScript(sol.Actions.Length);

        // Pour chaque action de la séquence originale,
        // on copie le type d'action.
        for (int i = 0; i < sol.Actions.Length; i++)
        {
            newSol.Actions[i].Action = sol.Actions[i].Action;
        }

        // Renvoi de la solution copiée
        return newSol;
    }
示例#10
0
    /// <summary>
    /// Exemple d'oracle nous renvoyant un score que l'on essaye de minimiser
    /// Ici est utilisé la position de la case d'arrivée, la position finale
    /// atteinte par la solution. Il est recommandé d'essayer plusieurs oracles
    /// pour étudier le comportement des algorithmes selon la qualité de ces
    /// derniers
    /// 
    /// Parmi les paramètres pouvant être utilisés pour calculer le score/erreur :
    /// 
    ///  - position de la case d'arrivée    : PlayerScript.GoalXPositionInMatrix
    ///                                       PlayerScript.GoalYPositionInMatrix
    ///  - position du joueur               : player.PlayerXPositionInMatrix
    ///                                       player.PlayerYPositionInMatrix
    ///  - position de départ du joueur     : PlayerScript.StartXPositionInMatrix
    ///                                       PlayerScript.StartYPositionInMatrix
    ///  - nombre de cases explorées        : player.ExploredPuts
    ///  - nombre d'actions exécutées       : player.PerformedActionsNumber
    ///  - vrai si le la balle a touché la case d'arrivée : player.FoundGoal
    ///  - vrai si le la balle a touché un obstacle : player.FoundObstacle
    ///  - interrogation de la matrice      :
    ///       € la case de coordonnée (i, j) est elle un obstacle (i et j entre 0 et 49) :
    ///           player.GetPutTypeAtCoordinates(i, j) == LayerMask.NameToLayer("Obstacle")
    ///       € la case de coordonnée (i, j) est elle explorée (i et j entre 0 et 49) :
    ///           player.GetPutTypeAtCoordinates(i, j) == 1
    ///       € la case de coordonnée (i, j) est elle inexplorée (i et j entre 0 et 49) :
    ///           player.GetPutTypeAtCoordinates(i, j) == 0
    /// </summary>
    /// <param name="solution"></param>
    /// <returns></returns>
    IEnumerator<float> GetError(PathSolutionScript solution, System.DateTime time,int iteration)
    {
        // On indique que l'on s'apprête à lancer la simulation
        _inSimulation = true;

        // On créé notre objet que va exécuter notre séquence d'action
        var player = PlayerScript.CreatePlayer();

        // Pour pouvoir visualiser la simulation (moins rapide)
        player.RunWithoutSimulation = false;

        // On lance la simulation en spécifiant
        // la séquence d'action à exécuter
        player.LaunchSimulation(solution);

        // Tout pendant que la simulation n'est pas terminée
        while (player.InSimulation)
        {
            // On rend la main au moteur Unity3D
            yield return -1f;
        }

        // Calcule la distance de Manhattan entre la case d'arrivée et la case finale de
        // notre objet, la pondère (la multiplie par zéro si le but a été trouvé)
        // et ajoute le nombre d'actions jouées
        var error = (Mathf.Abs(PlayerScript.GoalXPositionInMatrix - player.PlayerXPositionInMatrix)
            + Mathf.Abs(PlayerScript.GoalYPositionInMatrix - player.PlayerYPositionInMatrix))
            * (player.FoundGoal ? 0 : 100)  +
            player.PerformedActionsNumber;

        if(player.FoundGoal==true)
        {
            if(!_wasTrue){
                _wasTrue = true;
            string localCsvLine = _csvLog;
                TimeSpan simulation = DateTime.Now - time;
                localCsvLine += "00:00:"+simulation.TotalSeconds+";"+iteration+";Correct;\n";

            Debug.Log("Premier True En "+ simulation.TotalSeconds + " secondes");
            File.AppendAllText(@"log.csv",localCsvLine );
            }
            }

        // Détruit  l'objet de la simulation
        Destroy(player.gameObject);

        // Renvoie l'erreur précédemment calculée
        yield return error;

        // Indique que la phase de simulation est terminée
        _inSimulation = false;
    }
示例#11
0
 /// <summary>
 /// Méthode proposant une méthode pour obtenir une nouvel
 /// individu par croisement de deux configurations parentes
 /// </summary>
 /// <param name="parent1">Le parent 1</param>
 /// <param name="parent2">Le parent 2</param>
 /// <returns>L'enfant généré par croisement</returns>
 PathSolutionScript Crossover(PathSolutionScript parent1, PathSolutionScript parent2, int length)
 {
     PathSolutionScript child = new PathSolutionScript(length);
     for (int i = 0; i < parent1.Actions.Count(); i++)
     {
         if(i%2 != 0)child.Actions[i].Action = parent1.Actions[i].Action;
         else child.Actions[i].Action = parent2.Actions[i].Action;
     }
     return child;
 }
示例#12
0
    // Coroutine à utiliser pour implémenter l'algorithme du recuit simulé
    public IEnumerator SimulatedAnnealing()
    {
        /*
         *
         * Implémentation Christophe
         * Implémentation du Recuit Simulé
         * Lire le README AVANT modification
         *
         */

        DateTime time = DateTime.Now;
        DateTime timeEnd = time.AddMinutes(5);
        // Indique que l'algorithme est en cours d'exécution
        _isRunning = true;

        //Génération de la meilleure erreur obtenue
        var minimumError = GetMinError();
        var nbPath = 42;

        // Génère une solution initiale au hazard (ici une séquence
        // de 42 mouvements)
        var currentSolution = new PathSolutionScript(nbPath);
        int iterations = 0;
        // Récupère le score de la solution initiale
        // Sachant que l'évaluation peut nécessiter une
        // simulation, pour pouvoir la visualiser nous
        // avons recours à une coroutine
        var scoreEnumerator = GetError(currentSolution,time,iterations);
        yield return StartCoroutine(scoreEnumerator);
        float currentError = scoreEnumerator.Current;

        //Initialisation de la température à une valeur 'plutot basse'.
        float temperature = 2f;

        ///Initialisation de la valeur de 'stagnation' qui si elle dépasse un
        ///certain seuil provoquera l'augmentation de la température.
        float stagnation = 0.001f;

        // Affichage de l'erreur initiale
        Debug.Log(currentError);

        // Initialisation du nombre d'itérations

        // Tout pendant que l'erreur minimale n'est pas atteinte
        while (currentError != minimumError && DateTime.Compare(DateTime.Now,timeEnd)<0)
        {

            // On obtient une copie de la solution courante
            // pour ne pas la modifier dans le cas ou la modification
            // ne soit pas conservée.
            var newsolution = CopySolution(currentSolution);

            // On procède à une petite modification de la solution
            // courante.
            RandomChangeInSolution(newsolution);

            // Récupère le score de la nouvelle solution
            // Sachant que l'évaluation peut nécessiter une
            // simulation, pour pouvoir la visualiser nous
            // avons recours à une coroutine
            var newscoreEnumerator = GetError(newsolution,time,iterations);
            yield return StartCoroutine(newscoreEnumerator);
            float newError = newscoreEnumerator.Current;

            // On affiche pour des raisons de Debug et de suivi
            // la comparaison entre l'erreur courante et la
            // nouvelle erreur
            Debug.Log(currentError + "   -   " + newError);
            Debug.Log("L'erreur min est :" + minimumError);
            Debug.Log("Le nombre d'itérations est de " + iterations);

            ///Tirage d'un nombre aléatoire entre 0f et 1f.
            float rdm = UnityEngine.Random.Range(0f, 1f);

            ///Comparaison de ce nombre à la probabilité d'accepter un changement
            ///déterminée par le critère de Boltzman.
            if (rdm < BoltzmanCriteria(temperature, currentError, newError))
            {
                ///Si le nombre est inférieur, on accepte la solution changée
                ///et l'on met à jour l'erreur courante.
                currentError = newError;

                //Bien évidement la solution devient la copie de l'ancienne solution
                currentSolution = newsolution;

            }

            ///Si l'erreur stagne
            if (minimumError == currentError)
            {
                ///On incrémente la stagnation
                stagnation *= 1.001f;
            }
            else
            {
                ///Sinon on la réinitialise
                stagnation = 0.001f;
            }

            ///Si l'erreur diminue en deça de la meilleure erreur obtenue
            if (currentError < minimumError)
            {
                ///On met à jour la meilleure erreur obtenue
                 minimumError = (int)currentError;

                ///On réinitialise la stagnation
                stagnation = 0.001f;
            }

            ///On met à jour la temperature à chaque tour de boucle :
            /// - si la stagnation est suffisante la temperature va augmenter
            /// - sinon la temperature décroit de manière géométrique
            temperature *= 0.998f + stagnation;

            ///Affichage dans la console de Debug du couple temperature stagnation
            ///pour pouvoir être témoin de l'augmentation de la température lorsque
            ///l'on se retrouve coincé trop longtemps dans un minimum local.
            Debug.Log(temperature + "  -  " + stagnation);

            ///On rend la main à Unity pendant un court laps de temps pour permettre
            ///le contrôle de la simulation ainsi que la visualisation de l'évolution
            ///de l'algorithme.
            yield return new WaitForSeconds(0.0001f);

            // On incrémente le nombre d'itérations
            iterations++;

            // On rend la main au moteur Unity3D
            yield return 0;

        }

        // Fin de l'algorithme, on indique que son exécution est stoppée
        _isRunning = false;

        TimeSpan simulation = DateTime.Now - time;
        string localCsvLine = _csvLog;
        if(DateTime.Compare(DateTime.Now,timeEnd)<0){
        // On affiche le nombre d'itérations nécessaire à l'algorithme pour trouver la solution
        Debug.Log("CONGRATULATIONS !!! Solution Found in " + iterations + " iterations !");
        localCsvLine += "00:00:"+simulation.TotalSeconds+";"+iterations+";Optimal;\n";
        Debug.Log("En "+ simulation.TotalSeconds + " secondes !");
        }else{
            Debug.Log("FAIL !!! Solution not Found in " + iterations + " iteration and "+ simulation.TotalSeconds+" Seconds, or "+ simulation.TotalMinutes);
            localCsvLine += "00:00:"+simulation.TotalSeconds+";"+iterations+";Echec;\n";
        }
        File.AppendAllText(@"log.csv",localCsvLine );
    }
示例#13
0
 /// <summary>
 /// Execute un changement aléatoire sur une solution
 /// ici, une action de la séquence est tirée au hasard et remplacée
 /// par une nouvelle au hasard.
 /// </summary>
 /// <param name="sol"></param>
 public void RandomChangeInSolution(PathSolutionScript sol)
 {
     sol.Actions[UnityEngine.Random.Range(0, sol.Actions.Length)] = new ActionSolutionScript();
 }
示例#14
0
    /// <summary>
    /// Implémentation possible de la recherche locale naïve
    /// sous forme de coroutine pour le mode pseudo asynchone
    /// </summary>
    /// <returns></returns>
    public IEnumerator NaiveLocalSearch()
    {
        // Indique que l'algorithme est en cours d'exécution
        _isRunning = true;
        DateTime time = DateTime.Now;
        // Génère une solution initiale au hazard (ici une séquence
        // de 42 mouvements)
        var currentSolution = new PathSolutionScript(42);
            int iterations = 0;

        // Récupère le score de la solution initiale
        // Sachant que l'évaluation peut nécessiter une
        // simulation, pour pouvoir la visualiser nous
        // avons recours à une coroutine
        var scoreEnumerator = GetError(currentSolution,time,iterations);
        yield return StartCoroutine(scoreEnumerator);
        float currentError = scoreEnumerator.Current;

        // Nous récupérons l'erreur minimum atteignable
        // Ceci est optionnel et dépendant de la fonction
        // d'erreur
        var minimumError = GetMinError();

        // Affichage de l'erreur initiale
        Debug.Log(currentError);

        // Initialisation du nombre d'itérations

        // Tout pendant que l'erreur minimale n'est pas atteinte
        while (currentError != GetMinError())
        {
            // On obtient une copie de la solution courante
            // pour ne pas la modifier dans le cas ou la modification
            // ne soit pas conservée.
            var newsolution = CopySolution(currentSolution);

            // On procède à une petite modification de la solution
            // courante.
            RandomChangeInSolution(newsolution);

            // Récupère le score de la nouvelle solution
            // Sachant que l'évaluation peut nécessiter une
            // simulation, pour pouvoir la visualiser nous
            // avons recours à une coroutine
            var newscoreEnumerator = GetError(newsolution,time,iterations);
            yield return StartCoroutine(newscoreEnumerator);
            float newError = newscoreEnumerator.Current;

            // On affiche pour des raisons de Debug et de suivi
            // la comparaison entre l'erreur courante et la
            // nouvelle erreur
            Debug.Log(currentError + "   -   " + newError);

            // Si la solution a été améliorée
            if (newError <= currentError)
            {
                // On met à jour la solution courante
                currentSolution = newsolution;

                // On met à jour l'erreur courante
                currentError = newError;
            }

            // On incrémente le nombre d'itérations
            iterations++;

            // On rend la main au moteur Unity3D
            yield return 0;
        }

        // Fin de l'algorithme, on indique que son exécution est stoppée
        _isRunning = false;

        // On affiche le nombre d'itérations nécessaire à l'algorithme pour trouver la solution
        Debug.Log("CONGRATULATIONS !!! Solution Found in " + iterations + " iterations !");
    }
示例#15
0
    // Coroutine à utiliser pour implémenter un algorithme génétique
    public IEnumerator GeneticAlgorithm(int popsize,float mutationRate,float fitness,int mutationSequence)
    {
        int iteration = 0;
        DateTime time = DateTime.Now;
        DateTime timeEnd = time.AddMinutes(5);
        #region Paramètres

        ///La taille de la population

        ///Le nombre d'individus séléctionnés pour la reproduction
        ///(ici 40% de la taille de la population)
        int numSelection = (int)(popsize * fitness);

        ///Le taux de mutation (c.à.d. la chance avec laquelle un
        ///individu issu du croisement peut subir une mutation)

        #endregion

        /*
         *
         * INITIALISATION
         *
         */

        ///Initialisation du tableau contenant notre population initiale
        PathSolutionScript[] population = new PathSolutionScript[popsize];

        //Génération de la meilleure erreur obtenue
        var minimumError = GetMinError();
        Debug.Log("Minimum Error to Win : " + minimumError);
        int nbPath = 42;
        var currentSol = new PathSolutionScript(nbPath);
        var sol = new PathSolutionScript(nbPath);

        float bestError = 10000;

        // Récupère le score de la solution initiale
        // Sachant que l'évaluation peut nécessiter une
        // simulation, pour pouvoir la visualiser nous
        // avons recours à une coroutine
        var scoreEnumerator = GetError(currentSol,time,iteration);
        yield return StartCoroutine(scoreEnumerator);
        float currentError = scoreEnumerator.Current;

        for (int i = 0; i < popsize; i++)
        {
            //On génère une solution
            population[i] = new PathSolutionScript(nbPath);

        }

        while (bestError != GetMinError() && DateTime.Compare(DateTime.Now,timeEnd)<0)
        {

            ///Initialisation du tableau destiné à contenir l'ensemble des
            ///couples chemin/erreur une fois la population évaluée
            var scoredIndividuals = new ScoredIndividual[popsize];

            currentSol = new PathSolutionScript(nbPath);

            ///Pour chaque individu de notre population à évaluer
            for (int i = 0; i < population.Length; i++)
            {

                for (int j = 0; j < population[i].Actions.Length; j++)
              {
                    currentSol.Actions[j].Action = population[i].Actions[j].Action;
                }

                scoreEnumerator = GetError(population[i],time,iteration);
                yield return StartCoroutine(scoreEnumerator);
                currentError = scoreEnumerator.Current;

                ///Création d'un couple configuration/solution et stockage
                ///du score obtenu pour la configuration évaluée.
                scoredIndividuals[i] = new ScoredIndividual()
                {
                    Configuration = population[i],
                    Score = currentError
                };
            }

            //operateur de selection

            //selection par tournoi
            PathSolutionScript[] bestIndividuals = new PathSolutionScript[popsize];
            for(int i=0;i< popsize;i++){
            ////si l'individu testé est moins bon que l'aléatoire
            int rand = UnityEngine.Random.Range(0,scoredIndividuals.Length);
            if(scoredIndividuals[i].Score >  scoredIndividuals[rand].Score)
            {
                bestIndividuals[i] = scoredIndividuals[rand].Configuration;
            }else{
                bestIndividuals[i] = scoredIndividuals[i].Configuration;
            }
            //	scoredIndividuals[UnityEngine.Random.Range(0,scoredIndividuals.Length)]
            }
            //On initialise notre stockage de best population
            //var bestIndividuals = scoredIndividuals;
            //Methode Roulette Wheel
            //.OrderBy((scoredindi) => scoredindi.Score*UnityEngine.Random.value)
            //methode Elitiste
            //.OrderBy((scoredindi) => scoredindi.Score)
             //.Take(numSelection)
            //.Select((scoredindi) => scoredindi.Configuration)
            //.ToArray();

            bestError = scoredIndividuals
                .OrderBy((scoredindi) => scoredindi.Score)
                .Select((scoredindi) => scoredindi.Score).First();

            ///Affichage Dans la console de Debug du score du meilleur
            ///individu.
            Debug.Log("Meilleur Score de la génération courante : " + bestError);

            ///Initialisation de la nouvelle population qui va être générée
            ///par croisement.
            PathSolutionScript[] newpopulation = new PathSolutionScript[popsize];

            ///Pour chaque enfant que l'on doit générer par croisement
            for (int i = 0; i < popsize; i++)
            {

             	///Récupération de deux reproduteurs au hasard
             	var parent1 = bestIndividuals[UnityEngine.Random.Range(0, bestIndividuals.Length)];
             	var parent2 = bestIndividuals[UnityEngine.Random.Range(0, bestIndividuals.Length)];

             	///Création d'un individu à partir du croisement des deux parents
             	newpopulation[i] = Crossover(parent1, parent2, nbPath);
            }

            ///Pour chaque individu de la population
            for (int i = 0; i < popsize; i++)
            {
                ///Tirage d'un nombre au hasard entre 0f et 1f
                float rdm = UnityEngine.Random.Range(0f, 1f);

                ///Comparaison de ce nombre au taux de mutation
                ///S'il est inférieur, on procède à la mutation
                if (rdm < mutationRate)
                {
                    ///Mutation proposée :
                    // On procède à une petite modification de la solution
                    // courante.
                    for(int j=0;j<mutationSequence;j++){
                    RandomChangeInSolution(newpopulation[i+j]);
                    }
                }
            }
            ///Remplacement de l'ancienne population par la nouvelle
            population = newpopulation;

            iteration++;

            Debug.Log("Le nombre d'itérations est de : " + iteration);

            // On rend la main au moteur Unity3D
            yield return 0;
        }
           	// Fin de l'algorithme, on indique que son exécution est stoppée
           	_isRunning = false;

           	TimeSpan simulation = DateTime.Now - time;
        string localCsvLine = _csvLog;
        if(DateTime.Compare(DateTime.Now,timeEnd)<0){
            // On affiche le nombre d'itérations nécessaire à l'algorithme pour trouver la solution
            Debug.Log("CONGRATULATIONS !!! Solution Found in " + iteration + " iterations !");
            localCsvLine += "00:00:"+simulation.TotalSeconds+";"+iteration+";Optimal;\n";
            Debug.Log("En "+ simulation.TotalSeconds + " secondes !");
        }else{
            Debug.Log("FAIL !!! Solution not Found in " + iteration + " iteration and "+ simulation.TotalSeconds+" Seconds, or "+ simulation.TotalMinutes);
            localCsvLine += "00:00:"+simulation.TotalSeconds+";"+iteration+";Echec;\n";
        }
        File.AppendAllText(@"log.csv",localCsvLine );
    }