#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 есть несколько простых проектов и руководств… и скоро вы научитесь читать спецификации и т. Д