我正在尝试使用 P5.JS 库在 JavaScript 中进行遗传算法模拟,但我遇到了一些问题。这是我到目前为止所拥有的:
//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 个元素,但是当我尝试获取随机元素时,它返回“未定义”。
var parentA = random(this.matingpool);
var parentB = random(this.matingpool);
奇怪的是 parentB 有效,但 parentA 无效。
任何帮助深表感谢。在这里运行的整个代码:http: //codepen.io/felipe_mare/pen/bgOYMN
如果有帮助,我有时会在第 138 行收到错误:“无法读取未定义的属性 '0'”
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);
}
}