Javascript: случайное рисование фигур сгустками (генетический алгоритм)

#javascript #random-forest #genetic-algorithm #p5.js

#javascript #случайный лес #genetic-algorithm #p5.js

Вопрос:

Проблема

Я пытаюсь создать графику, имитирующую вид леса с высоты птичьего полета, поэтому мне нужно случайным образом генерировать зеленые фигуры на холсте. Однако я хочу, чтобы эти фигуры были в рандомизированных сгустках, чтобы больше походить на настоящий лес. Есть ли аккуратный способ сделать это?

Мой код включает в себя основы генетического алгоритма, прежде чем целевая функция будет действительно включена, с помощью Javascript и p5.js пакет.

Основная проблема

 var settings = {
  forestSize : 500,
  rows : 124,
  cols : 249,
};

function onCanvas(position){
  return position*4 2;
}

var forest = new Forest(settings.forestSize);

function Tree(){
  this.posx = Math.floor(Math.random()*settings.cols);
  this.posy = Math.floor(Math.random()*settings.rows);
}

function Forest(f){
  this.forSize = f;
  this.trees = [];

  for (var x = 0; x < this.forSize; x  ) {
    this.trees[x] = new Tree();
    if(this.trees.length>1){
      for(var y=0; y<x; y  ){
      while(this.trees[x].posx==this.trees[y].posxamp;amp;this.trees[x].posy==this.trees[y].posy){
        this.trees[x] = new Tree();
        }
      }
    }
  }
}

//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);
  }
}

function setup() {
  createCanvas(1000, 500);
}

function draw() {
  createWorld();
} 
  

Весь скрипт

 var settings = {
  populationSize : 25,
  geneLength : 8,
  mutationProbability : 0.05,
  forestSize : 500,
  rows : 124,
  cols : 249,
  year : 365,
};

function onCanvas(position){
  return position*4 2;
}

function randombetween(min, max){
  return Math.random()*max;
}

var population = new Population(settings.populationSize, settings.geneLength);

function Sheep(g, dna){
  this.genLen = g;
  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 = [];

  for (var x = 0; x < this.popSize; x  ) {
    this.sheep[x] = new Sheep(g, null);
  }
}

var forest = new Forest(settings.forestSize);

function Tree(){
  this.posx = Math.floor(Math.random()*settings.cols);
  this.posy = Math.floor(Math.random()*settings.rows);
}

function Forest(f){
  this.forSize = f;
  this.trees = [];

  for (var x = 0; x < this.forSize; x  ) {
    this.trees[x] = new Tree();
    if(this.trees.length>1){
      for(var y=0; y<x; y  ){
      while(this.trees[x].posx==this.trees[y].posxamp;amp;this.trees[x].posy==this.trees[y].posy){
        this.trees[x] = new Tree();
        }
      }
    }
  }
}


//begin generation count
var generation=0;

//begin day count
var counter = 0;
function endRun(end){
  if(end>=settings.year){
    noLoop();
  }
}

//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  ){
    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 amp;amp; population.sheep[x].ypos==forest.trees[y].posy){
        forest.trees[y].posx=null;
        forest.trees[y].posy=null;
        population.sheep[x].fitness  ;
      }
    }
  }

  //move eaters based on chromosome
  for(var x=0; x<settings.populationSize; x  ){
    var move = Math.random();
    if(move<population.sheep[x].chromosome[0]){
      //up
      if(population.sheep[x].ypos>0){
        population.sheep[x].ypos-=1;
      }
    }
    else if(move-population.sheep[x].chromosome[0]<population.sheep[x].chromosome[1]){
      //down
      if(population.sheep[x].ypos<settings.rows-1){
        population.sheep[x].ypos =1;
      }
    }
    else if(move-population.sheep[x].chromosome[0]-population.sheep[x].chromosome[1]<population.sheep[x].chromosome[2]){
      //right
      if(population.sheep[x].xpos<settings.cols-1){
        population.sheep[x].xpos =1;
      }
    }
    else{
      //left
      if(population.sheep[x].xpos>0){
        population.sheep[x].xpos-=1;
      }
    }
  }
  counter  ;
  endRun(counter);
}

function setup() {
  createCanvas(1000, 500);
}

function draw() {
  createWorld();
} 
  

Комментарии:

1. Да, сначала начните с добавления вашего кода .. достаточного для воссоздания того, что вы получаете в данный момент. Вы также могли бы сделать это как «фрагмент», чтобы он выполнялся здесь, на странице. Вы можете сделать это, нажав кнопку на экране редактирования, которая выглядит как бумажный файл с < > внутри него

2. добавлена популяция радиального дерева

Ответ №1:

Моя идея состояла бы в том, чтобы определить форму и плотность внутри этой формы, а затем сгенерировать эту форму для определенных случайных координат.

Например:

     function radialTreePopulation(x,y,r,count){

          let trees = []
          for(let i = 0;i < count; i  ){
            trees.push({
             posx : (x   (Math.random()* r * (Math.random() < 0.5 ? -1 : 1)))| 0,
             posy : (y   (Math.random()* r * (Math.random() < 0.5 ? -1 : 1)))| 0
            })
          }

      return trees
  }
  

и чем:

 function Forest(f){
  let segmentCount = (Math.random() * 75)| 0;
  this.forSize = f ;
  this.trees = [];

  while(this.forSize){


    this.trees.push(...radialTreePopulation(
         (Math.random() *settings.cols)| 0,
         (Math.random() *settings.rows)| 0,
         (Math.random()*12) | 0 , // think squared > max segmentCount
         segmentCount)
         )

    segmentCount = (Math.random() * 100)| 0
    this.forSize -= this.forSize > segmentCount ?
                         segmentCount: this.forSize;

  }

}
  

фрагмент:

 var settings = {
      populationSize : 25,
      geneLength : 8,
      mutationProbability : 0.05,
      forestSize : 1500,
      rows : 124,
      cols : 249,
      year : 365,
    };

    function onCanvas(position){
      return position*4 2;
    }

    function randombetween(min, max){
      return Math.random()*max;
    }

    var population = new Population(settings.populationSize, settings.geneLength);

    function Sheep(g, dna){
      this.genLen = g;
      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 = [];

      for (var x = 0; x < this.popSize; x  ) {
        this.sheep[x] = new Sheep(g, null);
      }
    }

    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.random()* r * (Math.random() < 0.5 ? -1 : 1)))| 0,
         posy : (y   (Math.random()* r * (Math.random() < 0.5 ? -1 : 1)))| 0
        })
      }
      
      return trees
  }

    function Tree(){
      this.posx = Math.floor(Math.random()*settings.cols);
      this.posy = Math.floor(Math.random()*settings.rows);
    }

    
function Forest(f){
  let segmentCount = (Math.random() * 75)| 0;
  this.forSize = f ;
  this.trees = [];

  while(this.forSize){

    
    this.trees.push(...radialTreePopulation(
         (Math.random() *settings.cols)| 0,
         (Math.random() *settings.rows)| 0,
         (Math.random()*12) | 0 , // think squared > max segmentCount
         segmentCount)
         )
     
    segmentCount = (Math.random() * 75)| 0
    this.forSize -= this.forSize > segmentCount ?
                         segmentCount: this.forSize;
     
  }

}


    //begin generation count
    var generation=0;

    //begin day count
    var counter = 0;
    function endRun(end){
      if(end>=settings.year){
        noLoop();
      }
    }

    //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  ){
        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 amp;amp; population.sheep[x].ypos==forest.trees[y].posy){
            forest.trees[y].posx=null;
            forest.trees[y].posy=null;
            population.sheep[x].fitness  ;
          }
        }
      }

      //move eaters based on chromosome
      for(var x=0; x<settings.populationSize; x  ){
        var move = Math.random();
        if(move<population.sheep[x].chromosome[0]){
          //up
          if(population.sheep[x].ypos>0){
            population.sheep[x].ypos-=1;
          }
        }
        else if(move-population.sheep[x].chromosome[0]<population.sheep[x].chromosome[1]){
          //down
          if(population.sheep[x].ypos<settings.rows-1){
            population.sheep[x].ypos =1;
          }
        }
        else if(move-population.sheep[x].chromosome[0]-population.sheep[x].chromosome[1]<population.sheep[x].chromosome[2]){
          //right
          if(population.sheep[x].xpos<settings.cols-1){
            population.sheep[x].xpos =1;
          }
        }
        else{
          //left
          if(population.sheep[x].xpos>0){
            population.sheep[x].xpos-=1;
          }
        }
      }
      counter  ;
      endRun(counter);
    }

    function setup() {
      createCanvas(1000, 500);
    }

    function draw() {
      createWorld();
    }  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>  

Комментарии:

1. Спасибо за помощь! Кроме того, я добавил основную проблему (генерация деревьев и их рисование) отдельно от всего скрипта, чтобы сделать его более доступным.

2. Большое спасибо! Это работает действительно хорошо! Я немного незнаком с операторами здесь, так предотвращает ли это перекрытие деревьев? Также просто интересно, могли бы вы направить на некоторые ресурсы, где вы изучали Javascript.

3. нет, они не могут перекрываться — это просто грязное случайное размещение в радиусе. Изучил javascript, выполняя проекты шаг за шагом — в freecodecamp etc есть несколько простых проектов и руководств… и скоро вы научитесь читать спецификации и т. Д