Javascript: не могу найти ошибки в графическом генетическом алгоритме - PullRequest
0 голосов
/ 19 марта 2019

Я довольно новичок в Javascript, и я работаю над графическим генетическим алгоритмом.Тем не менее, я думаю, что у меня появляется некоторое видение туннеля после работы над ним, и я не могу понять, что происходит?Я использую Javascript с p5.js .Проблема описана ниже.

Предпосылка

Создайте группу красных точек с движением, основанным на вероятности.Пригодность определяется тем, сколько случайно расположенных зеленых точек они едят.Развивайся, чтобы есть больше.

Ошибки

  1. Когда я запускаю его, зеленая точка всегда появляется в левом верхнем углу, даже если они должны быть расположены случайным образом.
  2. (РЕШЕНО) Функция разведения не работает должным образом.Он должен:
    • Создать массив для следующего поколения (это работает)
    • Рисовать случайных родителей из пула спаривания (это работает)
    • Случайно пересекать их массивы хромосом, чтобы сформироватьновый особь (не уверен)
    • Применить шанс мутации для каждого нового особи (не уверен)
    • Хранить потомство в новом поколении (это работает)
    • Заменить случайного потомка нанаиболее подходящий член последнего поколения (не уверен)
    • Заменить массив текущего поколения на массив нового поколения (не уверен)

Код

var settings = {
      populationSize : 25,
      geneLength : 8,
      mutationProbability : 0.01,
      forestSize : 1500,
      rows : 124,
      cols : 249,
      year : 250,
      end : 20,
    };
    
    function onCanvas(position){
      return position*4+2;
    }
    
    function randombetween(min, max){
      return Math.random()*max;
    }
    
    //set up sheep
    var population = new Population(settings.populationSize, settings.geneLength);
    
    function Sheep(g, dna){
      this.genLen = g;
      this.state = 0;
      this.fitness=0;
      this.xpos = Math.floor(Math.random()*settings.cols);
      this.ypos = Math.floor(Math.random()*settings.rows);
    
      this.chromosome = new Array(this.genLen);
      if (dna != null){
        this.chromosome = dna;
      } else{
        for(var x=0; x<this.genLen; x+=4){
          this.chromosome[x] = Math.random();
          this.chromosome[x+1] = randombetween(0, 1-this.chromosome[x]);
          this.chromosome[x+2] = randombetween(0, 1-this.chromosome[x]-this.chromosome[x+1]);
          this.chromosome[x+3] = 1-this.chromosome[x]-this.chromosome[x+1]-this.chromosome[x+2];
        }
      }
    }
    
    function Population(p, g){
      this.popSize = p;
      this.sheep = [];
      this.matingPool = [];
      this.maxFit;
      this.maxFitIndex;
    
      for (var x = 0; x < this.popSize; x++) {
        this.sheep[x] = new Sheep(g, null);
      }
    
      this.evaluate = function() {
        //find maximum fitness in generation
        this.maxFit = 0;
        this.maxFitIndex = 0;
        for (var x = 0; x < this.popSize; x++) {
          //this.sheep[x].calcFitness();
          if (this.sheep[x].fitness > this.maxFit){
            this.maxFitIndex = x;
            this.maxFit = this.sheep[x].fitness;
          }
        }
        //document.write("Maximum fitness: " + this.maxFit);
    
        //normalize fitness
        for (var i = 0; i < this.popSize; i++) {
          this.sheep[i].fitness /= this.maxFit;
        }
    
        //reset mating pool every generation
        this.matingPool = [];
    
        //higher fitness means more representation in the pool
        for (var i = 0; i < this.popSize; i++) {
          var n = this.sheep[i].fitness *10;
          for (var j = 0; j < n; j++) {
            this.matingPool.push(this.sheep[i]);
          }
        }
      }
    
      //create children sheep
      this.breed = function (){
        var newsheep = [];
    
        for (var i = 0; i < this.popSize; i++){
          //pick random parents from the mating pool
          let parentA = this.matingPool[Math.floor(Math.random()*this.matingPool.length)];
          let parentB = this.matingPool[Math.floor(Math.random()*this.matingPool.length)];
    
          //parent genes are randomly crossed
          var newchromosome = [];
          var midpoint = Math.floor(Math.random()*g);
          for (var j = 0; j < g; j++){
            if (j > midpoint){
              newchromosome[j] = parentA.chromosome[j];
            } else{
              newchromosome[j] = parentB.chromosome[j];
            }
          }
    
          //offspring may be mutated
          if(Math.random()<=settings.mutationProbability){
            newchromosome[Math.floor(Math.random()*g)]=Math.floor(Math.random()*10+1);
          }
          newsheep[i] = new Eater(g, newchromosome);
        }
    
        //elite offspring survive into next generation, replacing a random offspring
        var random = Math.floor(Math.random()*this.popSize);
    
        if(Math.random()<=settings.mutationProbability){
          this.sheep[this.maxFitIndex].chromosome[Math.floor(Math.random()*g)]=Math.floor(Math.random()*10+1);
        }
        for(var x = 0; x < g; x++){
          newsheep[random].chromosome[x] = this.sheep[this.maxFitIndex].chromosome[x];
        }
    
        //update array of sheep
        for(var x=0; x<this.popSize; x++){
          this.sheep[x] = newsheep[x];
        }
      }
    }
    
    //set up trees
    var forest = new Forest(settings.forestSize);
    
    function radialTreePopulation(x,y,r,count){
      let trees = [];
      for(let i = 0;i < count; i++){
        trees.push({
          posx : (x + Math.floor((Math.random()* r) * (Math.random() < 0.5 ? -1 : 1))),
          posy : (y + Math.floor((Math.random()* r) * (Math.random() < 0.5 ? -1 : 1)))
        });
      }
      return trees;
    }
    
    function Forest(f){
      this.forSize = f/ 75;
      this.trees = [];
    
      for (var x = 0; x < this.forSize ; x++) {
        this.trees.push(...radialTreePopulation(
          (Math.floor(Math.random()*(settings.cols-20)+10))| 0,
          (Math.floor(Math.random()*(settings.rows-20)+10))| 0,
          11,
          75)
        );
      }
    }
    
    //evaluate how to move
    function moveHungry(x, move){
      if(move<population.sheep[x].chromosome[0]){
        return 0;
      }
      else if(move-population.sheep[x].chromosome[0]<population.sheep[x].chromosome[1]){
        return 1;
      }
      else if(move-population.sheep[x].chromosome[0]-population.sheep[x].chromosome[1]<population.sheep[x].chromosome[2]){
        return 2;
      }
      else{
        return 3;
      }
    }
    
    function moveEaten(x,move){
      if(move<population.sheep[x].chromosome[4]){
        return 0;
      }
      else if(move-population.sheep[x].chromosome[4]<population.sheep[x].chromosome[5]){
        return 1;
      }
      else if(move-population.sheep[x].chromosome[4]-population.sheep[x].chromosome[5]<population.sheep[x].chromosome[6]){
        return 2;
      }
      else{
        return 3;
      }
    }
    
    //count generations and days
    var generation=0;
    var counter = 0;
    
    //create world
    function createWorld(){
      background("lightblue");
    
      fill(0,255,0);
      for(var x=0; x<settings.forestSize; x++){
        rect(onCanvas(forest.trees[x].posx), onCanvas(forest.trees[x].posy), 4, 4);
      }
    
      fill(255,0,0);
      for(var x=0; x<settings.populationSize; x++){
        population.sheep[x].state=0;
        rect(onCanvas(population.sheep[x].xpos), onCanvas(population.sheep[x].ypos), 4, 4);
      }
    
      //remove eaten trees
      for(var x=0; x<settings.populationSize; x++){
        for(var y=0; y<settings.forestSize; y++){
          if(population.sheep[x].xpos==forest.trees[y].posx && population.sheep[x].ypos==forest.trees[y].posy){
            forest.trees[y].posx=null;
            forest.trees[y].posy=null;
            population.sheep[x].state=1;
            population.sheep[x].fitness++;
          }
        }
      }
    
      //move sheep based on chromosome
      for(var x=0; x<settings.populationSize; x++){
        var move = Math.random();
        if(population.sheep[x].state==0){
          switch(moveHungry(x, move)){
            case 0: //up
              if(population.sheep[x].ypos>0)
                population.sheep[x].ypos-=1;
              break;
            case 1: //down
              if(population.sheep[x].ypos<settings.rows-1)
                population.sheep[x].ypos+=1;
              break;
            case 2: //right
              if(population.sheep[x].xpos<settings.cols-1)
                population.sheep[x].xpos+=1;
              break;
            case 3: //left
              if(population.sheep[x].xpos>0)
                population.sheep[x].xpos-=1;
          }
        }
        else {
          switch(moveEaten(x, move)){
            case 0: //up
              if(population.sheep[x].ypos>0)
                population.sheep[x].ypos-=1;
              break;
            case 1: //down
              if(population.sheep[x].ypos<settings.rows-1)
                population.sheep[x].ypos+=1;
              break;
            case 2: //right
              if(population.sheep[x].xpos<settings.cols-1)
                population.sheep[x].xpos+=1;
              break;
            case 3: //left
              if(population.sheep[x].xpos>0)
                population.sheep[x].xpos-=1;
          }
        }
      }
      counter++;
    }
    
    function reset(){
      counter=0;
      //regrow forest
      forest = new Forest(settings.forestSize);
      //reset locations and fitness values
      for(var x=0; x<settings.populationSize; x++){
        population.sheep[x].xpos = Math.floor(Math.random()*settings.cols);
        population.sheep[x].ypos = Math.floor(Math.random()*settings.rows);
        population.sheep[x].fitness=0;
      }
    }
    
    function setup() {
      createCanvas(1000, 500);
    }
    
    function draw() {
      createWorld();
      if(counter>=settings.year){
        population.evaluate();
        population.breed();
        reset();
        generation++;
        if(generation>=settings.end){
          noLoop();
        }
      }
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...