Я довольно новичок в Javascript, и я работаю над графическим генетическим алгоритмом.Тем не менее, я думаю, что у меня появляется некоторое видение туннеля после работы над ним, и я не могу понять, что происходит?Я использую Javascript с p5.js .Проблема описана ниже.
Предпосылка
Создайте группу красных точек с движением, основанным на вероятности.Пригодность определяется тем, сколько случайно расположенных зеленых точек они едят.Развивайся, чтобы есть больше.
Ошибки
- Когда я запускаю его, зеленая точка всегда появляется в левом верхнем углу, даже если они должны быть расположены случайным образом.
- (РЕШЕНО) Функция разведения не работает должным образом.Он должен:
- Создать массив для следующего поколения (это работает)
- Рисовать случайных родителей из пула спаривания (это работает)
- Случайно пересекать их массивы хромосом, чтобы сформироватьновый особь (не уверен)
- Применить шанс мутации для каждого нового особи (не уверен)
- Хранить потомство в новом поколении (это работает)
- Заменить случайного потомка нанаиболее подходящий член последнего поколения (не уверен)
- Заменить массив текущего поколения на массив нового поколения (не уверен)
Код
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>