2017-02-13 7 views
1

Ich versuche eine genetische Algorithmus-Simulation in JavaScript mithilfe der P5.JS-Bibliothek durchzuführen, aber ich habe einige Probleme. Hier ist, was ich bisher:JS - Fehler: "Eigenschaft von undefiniert nicht lesen"

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

Dies ist der wichtigste Teil des Codes:

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; 

} 

Also, wenn es hier bekommt:

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

i das bekommen Fehler: "Kann Eigenschaft 'DNA' von undefined nicht lesen, warum in aller Welt passiert das?" Wenn ich den Debugger in Chrome verwende, kann ich klar sehen, dass der Paarungspool 2000 Elemente hat, aber wenn ich versuche, einen zufälligen zu bekommen, gibt es "undefined" zurück.

Die komische Sache ist, dass elterB funktioniert, aber parentA tut nicht.

enter image description here

Jede Hilfe ist sehr geschätzt. Entire Code läuft hier: http://codepen.io/felipe_mare/pen/bgOYMN

Wenn es hilft, ich manchmal den Fehler: „Kann nicht lesen Eigenschaft‚0‘undefinierten“ statt, an der Linie 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

Wie sieht dein 'random()' aus? – JohanP

+0

@JohanP Bitte beachten Sie das Tag [tag: p5.js]. Die P5.js-Bibliothek bietet die Funktion 'random()'. –

+0

Welche Zeile ist "Zeile 138"? – Li357

Antwort

3

In Zukunft bitte bitte versuchen Sie es um Ihre Fragen auf MCVE zu beschränken. Ich verstehe, dass dies ein kompliziertes Problem zu debuggen war, aber Sie werden viel mehr Glück haben, wenn Sie versuchen, Ihr Problem auf ein minimales (unter 20 Zeilen) Beispiel einzugrenzen. Die meiste Zeit werden Sie Ihren Fehler beim Erstellen des MCVE finden.

Aber Ihr Problem ist eigentlich, wenn Sie die matingpool Array zu erstellen, hier:

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

Wenn ich eine print-Anweisung innerhalb der inneren for Schleife hinzufügen, wie folgt aus:

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

Dann sehe ich dass Sie undefined in das Array ein paar Mal drücken:

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

Dann wählen Sie zufällig aus diesem Array, weshalb Ihr Fehler an zufälligen Stellen in Ihrem Code angezeigt wird.

Sie müssen dies weiter debuggen, um herauszufinden, warum das passiert - es scheint komisch, dass Sie Schleifen basierend auf einer Fitness statt einer Array-Länge, aber ich verstehe nicht wirklich den Code gut genug um sicher zu sein. Hoffentlich bringt dich das auf jeden Fall auf den richtigen Weg.

+0

Wenn Sie es ein Array geben gibt es ein zufälliges Element – Pepe

+0

@Pepe Oh wow. Ich habe das nie gewusst. Ordentlich. Ich werde weiter graben und meine Antwort bearbeiten, wenn ich es herausgefunden habe. –

+0

Ich habe auch versucht 'this.matingpool [Boden (zufällig (0, this.matingpool.length))];' und es funktioniert immer noch nicht – Pepe

Verwandte Themen