2017-02-13 17 views
1

Я пытаюсь создать алгоритм генетического алгоритма в JavaScript с использованием библиотеки P5.JS, но у меня возникают некоторые проблемы. Вот что я до сих пор:JS - Ошибка: «Невозможно прочитать свойство undefined»

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

Это самая важная часть кода:

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; 

} 

Поэтому, когда он попадает сюда:

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

я получаю Ошибка: «Невозможно прочитать свойство« dna »неопределенного», почему на самом деле это происходит? Когда я использую отладчик в chrome, я могу ясно видеть, что matingpool имеет 2000 элементов, но когда я пытаюсь получить случайный, он возвращает «undefined».

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

Странно, что parentB работает, но parentA dosn't.

enter image description here

Любая помощь очень ценится. Весь код работает здесь: http://codepen.io/felipe_mare/pen/bgOYMN

Если это поможет, я иногда получаю сообщение об ошибке: «Не удается прочитать свойство„0“неопределенных» вместо этого, в строке 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

Как выглядит ваш 'random()' look? – JohanP

+0

@JohanP Обратите внимание на тег [tag: p5.js]. Библиотека P5.js предоставляет функцию 'random()'. –

+0

Какая строка находится на «строке 138»? – Li357

ответ

3

В будущем, пожалуйста, пожалуйста, пожалуйста, попробуйте чтобы сузить свои вопросы до MCVE. Я понимаю, что это была сложная проблема для отладки, но вам будет намного лучше, если вы попытаетесь сузить свою проблему до минимального (до 20 строк). В большинстве случаев вы обнаружите свою ошибку в процессе создания MCVE.

Но ваша проблема на самом деле, когда вы создаете matingpool массив, здесь:

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

Если добавить оператор печати внутри внутренней for петли, как это:

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

Тогда я вижу что вы нажимаете undefined в массив несколько раз:

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

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

Вам придется отлаживать это дальше, чтобы выяснить, почему это происходит - кажется странным, что вы зацикливаете на основе фитнеса вместо длины массива, но я действительно недостаточно понимаю код быть уверенным. В любом случае, надеюсь, это поможет вам на правильном пути.

+0

Когда вы даете ему массив, он возвращает случайный элемент – Pepe

+0

@Pepe О, ничего себе. Никогда не знал этого. Ухоженная. Я продолжу копать и редактировать свой ответ, когда узнаю. –

+0

Я также пробовал 'this.matingpool [floor (random (0, this.matingpool.length))];' и он все еще не работает – Pepe