2017-02-13 1 views
1

Je tente de faire une simulation d'algorithme génétique en JavaScript en utilisant la bibliothèque P5.JS, mais je rencontre quelques problèmes. Voici ce que j'ai jusqu'à présent:JS - Erreur: "Impossible de lire la propriété de indéfini"

//var popS = 2; 
var popu; 
//var balls = []; 
var target; 

function setup() { 
    createCanvas(800, 300); 
    popu = new Population(); 
    target = createVector(width - 15, height/2); 
} 

function draw() { 
    background(50); 
    popu.run(); 

    var ballsC = 0; 
    for (var a = 0; a < popu.balls.length; a++) { 
    if (popu.balls[a].done == true){ 
     ballsC++; 
    } 
    } 
    if (ballsC >= popu.popS) { 
    //popu = new Population(); 
    popu.evaluate(); 
    //popu.selection(); 
    } 

    fill(255, 0, 30); 
    noStroke(); 
    ellipse(target.x, target.y, 20, 20); 
} 

function DNA() { 
    this.genes = []; 
    this.changes = 7;//random(2, 50); 

    for (var a = 0; a < this.changes; a++) { 
    this.genes[a] = random(0, 15); 
    } 

    this.crossover = function (pB) { 
    var newdna = new DNA(); 
    var mid = floor(random(0, this.genes.length)); 
    for (var a = 0; a < this.genes.length; a++) { 
     if (a < mid) { 
     newdna.genes[a] = this.genes[a]; 
     }else { 
     newdna.genes[a] = pB.genes[a]; 
     } 
    } 
    return newdna; 
    } 
} 

function Population() { 
    this.balls = []; 
    this.popS = 50; 
    this.maxfit = 0; 
    this.matingpool = []; 

    for (var a = 0; a < this.popS; a++) { 
    this.balls[a] = new Ball(); 
    } 

    this.evaluate = function() { 
    for (var a = 0; a < this.balls.length; a++) { 
     this.balls[a].calcF(); 
     if (this.balls[a].fitness > this.maxfit) { 
     this.maxfit = this.balls[a].fitness; 
     } 
    } 
    this.matingpool = []; 
    for (var b = 0; b < this.balls.length; b++) { 
     var n = this.balls[b].fitness * 100; 
     for (var c = 0; c < n; c++) { 
     this.matingpool.push(this.balls[c]); 
     } 
    } 

    this.selection(); 
    } 

    this.selection = function() { 
    var newBalls = []; 
    for (var a = 0; a < this.balls.length; a++) { 
     var parentA = this.matingpool[floor(random(0, this.matingpool.length))]; 
     var parentB = this.matingpool[floor(random(0, this.matingpool.length))]; 
     var child = parentA.dna.crossover(parentB.dna); 
     newBalls[a] = new Ball(child); 
    } 
    this.balls = newBalls; 
    } 

    this.run = function() { 
    for (var a = 0; a < this.balls.length; a++) { 
     this.balls[a].update(); 
     this.balls[a].checkCol(); 
     this.balls[a].show(); 
    } 
    } 
} 

function Ball(dna) { 
    this.pos = createVector(10, height/2); 
    this.speed = createVector(2, 2.5); 
    this.mul = -1; 
    this.time = 0; 
    this.a = 0; 
    if (dna) { 
    this.dna = dna; 
    } else { 
    this.dna = new DNA(); 
    } 
    this.done = false; 
    this.fitness = 0; 
    this.reached; 

    this.update = function() { 
    if (this.done == false) { 
     if (this.time >= this.dna.genes[this.a]) { 
     this.a++; 
     this.time = 0; 
     this.mul *= -1; 
     } 
     this.speed.set(2, 2.5 * this.mul); 
     this.pos.add(this.speed); 
    } 
    } 

    this.show = function() { 
    this.time += 0.1; 
    fill(255, 70); 
    noStroke(); 
    ellipse(this.pos.x, this.pos.y, 10, 10); 
    } 

    this.checkCol = function() { 
    if (this.pos.y > height || this.pos.y < 0 || this.pos.x > width) { 
     //print("col"); 
     this.done = true; 
    } 
    if (dist(this.pos.x, this.pos.y, target.x, target.y) <= (10/2) + (20/2)) { 
     //print("done!"); 
     this.done = true; 
     this.reached = true; 
    } 
    } 

    this.calcF = function() { 
    var a = dist(this.pos.x, this.pos.y, target.x, target.y); 
    var b = this.dna.genes.length; 
    var c = 0; 
    if (this.reached){ 
     c = 1; 
    } 

    this.fitness = map(map(a, 0, width, 1, 0) + map(b, 2, 50, 1, 0) + c, 0, 3, 0, 1); 
    } 
} 

Ceci est la partie la plus essentielle du code:

var popu; 

function setup() { 
    createCanvas(800, 300); 
    popu = new Population(); 
} 

function draw() { 
    background(50); 
    //popu = new Population(); 
    popu.evaluate(); 
    //popu.selection(); 
} 

function DNA() { 
    this.genes = []; 
    this.changes = 7; //random(2, 50); 

    for (var a = 0; a < this.changes; a++) { 
    this.genes[a] = random(0, 15); 
    } 

    this.crossover = function(pB) { 
    var newdna = new DNA(); 
    var mid = floor(random(0, this.genes.length)); 
    for (var a = 0; a < this.genes.length; a++) { 
     if (a < mid) { 
     newdna.genes[a] = this.genes[a]; 
     } else { 
     newdna.genes[a] = pB.genes[a]; 
     } 
    } 
    return newdna; 
    } 
} 

function Population() { 
    this.balls = []; 
    this.popS = 50; 
    this.maxfit = 0; 
    this.matingpool = []; 

    for (var a = 0; a < this.popS; a++) { 
    this.balls[a] = new Ball(); 
    } 

    this.evaluate = function() { 
    this.matingpool = []; 
    for (var b = 0; b < this.balls.length; b++) { 
     var n = this.balls[b].fitness * 100; 
     for (var c = 0; c < n; c++) { 
     this.matingpool.push(this.balls[c]); 
     } 
    } 

    this.selection(); 
    } 

    this.selection = function() { 
    var newBalls = []; 
    for (var a = 0; a < this.balls.length; a++) { 
     var parentA = this.matingpool[floor(random(0, this.matingpool.length))]; 
     var parentB = this.matingpool[floor(random(0, this.matingpool.length))]; 
     var child = parentA.dna.crossover(parentB.dna); 
     newBalls[a] = new Ball(child); 
    } 
    this.balls = newBalls; 
    } 
} 

function Ball(dna) { 
    this.pos = createVector(10, height/2); 
    this.speed = createVector(2, 2.5); 
    this.mul = -1; 
    this.time = 0; 
    this.a = 0; 
    if (dna) { 
    this.dna = dna; 
    } else { 
    this.dna = new DNA(); 
    } 
    this.done = false; 
    this.fitness = 0; 
    this.reached; 

} 

Donc, chaque fois qu'il arrive à ici:

this.selection = function() { 
    var newBalls = []; 
    for (var a = 0; a < this.balls.length; a++) { 
     var parentA = random(this.matingpool); 
     var parentB = random(this.matingpool); 
     var child = parentA.dna.crossover(parentB.dna); 
     newBalls[a] = new Ball(child); 
    } 
    this.balls = newBalls; 
    } 

je reçois la erreur: "Impossible de lire la propriété 'ADN' de indéfini", pourquoi diable est-ce qui se passe ?? Quand j'utilise le débogueur en chrome, je peux clairement voir que matingpool a 2000 éléments, mais quand j'essaie d'en obtenir un au hasard, il retourne "undefined".

var parentA = random(this.matingpool); 
var parentB = random(this.matingpool); 

La chose étrange est que parentB fonctionne, mais parentA dosn't.

enter image description here

Toute aide est très appréciée. code complet en cours d'exécution ici: http://codepen.io/felipe_mare/pen/bgOYMN

Si cela peut aider, je parfois l'erreur: « Impossible de lire la propriété « 0 » undefined » à la place, à la ligne 138

this.update = function() { 
    if (this.done == false) { 
     //line 138 
     if (this.time >= this.dna.genes[this.a]) { 
     //line 138 
     this.a++; 
     this.time = 0; 
     this.mul *= -1; 
     } 
     this.speed.set(2, 2.5 * this.mul); 
     this.pos.add(this.speed); 
    } 
    } 
+0

Comment ressemble votre 'random()'? – JohanP

+0

@JohanP Veuillez noter le tag [tag: p5.js]. La bibliothèque P5.js fournit la fonction 'random()'. –

+0

Quelle ligne est "ligne 138"? – Li357

Répondre

3

À l'avenir, s'il vous plaît s'il vous plaît s'il vous plaît essayer pour affiner vos questions à MCVE. Je comprends que c'était un problème compliqué à déboguer, mais vous aurez beaucoup plus de chance si vous essayez de réduire votre problème à un exemple minimal (moins de 20 lignes). La plupart du temps, vous finirez par trouver votre erreur dans le processus de création du MCVE.

Mais votre problème est en fait lorsque vous créez le tableau matingpool, ici:

this.matingpool = []; 
for (var b = 0; b < this.balls.length; b++) { 
    var n = this.balls[b].fitness * 100; 
    for (var c = 0; c < n; c++) { 
    this.matingpool.push(this.balls[c]); 
    } 
} 

Si j'ajoute une déclaration d'impression dans la boucle for intérieure, comme ceci:

this.matingpool = []; 
for (var b = 0; b < this.balls.length; b++) { 
    var n = this.balls[b].fitness * 100; 
    for (var c = 0; c < n; c++) { 
    console.log("pushing: " + this.balls[c]); 
    this.matingpool.push(this.balls[c]); 
    } 
} 

Je vois que vous poussez undefined dans le tableau un certain nombre de fois:

(1178) pushing: [object Object] 
(3) pushing: undefined 
(482) pushing: [object Object] 
(3) pushing: undefined 
(216) pushing: [object Object] 

Ensuite, vous choisissez aléatoirement dans ce tableau, ce qui explique pourquoi votre erreur apparaît dans des endroits aléatoires dans votre code. Vous devrez déboguer davantage pour comprendre pourquoi cela se produit. Il semble étrange que vous ayez une boucle en fonction d'une forme physique plutôt que d'une longueur de tableau, mais je ne comprends pas très bien le code. pour être sûr. En tout cas, j'espère que cela vous met sur la bonne voie.

+0

Lorsque vous lui donnez un tableau, il retourne un élément aléatoire – Pepe

+0

@Pepe Oh wow. Je n'ai jamais su ça. Soigné. Je vais continuer à creuser et modifier ma réponse quand je le comprendrai. –

+0

J'ai également essayé 'this.matingpool [floor (aléatoire (0, this.matingpool.length))];' et il ne fonctionne toujours pas – Pepe