javascript - 神经进化 - func 不是函数错误
问题描述
我正在使用p5.js库。
我正在使用 Toy-Neural-Network-JS制作我的第一个神经网络。我遵循了Coding Train教程,它有点工作(对象随机移动),但出了点问题,它给了我一个错误(见图)。
这是我的代码。每次当所有玩家被杀死时都会发生错误。它有什么问题?我检查了 X 次,没有发现任何错误。
let balls = [];
let totalBalls = 5;
let players = [];
let tmpplayers = [];
let totalPlayers = 100;
function nextGeneration(){
calcFitness();
for(let i = 0; i < totalPlayers; i++){
players.push(pickOnePlayer());
}
tmpplayers = [];
console.log("next generation");
}
function pickOnePlayer(){
let index = 0;
let r = random(1);
while(r > 0){
r = r - tmpplayers[index].fitness;
index++;
}
index--;
let player = tmpplayers[index];
let child = new Player(player.brain);
child.mutate();
return child;
}
function calcFitness(){
let sum = 0;
for(let player of tmpplayers){
sum += player.score;
}
for(let player of tmpplayers){
player.fitness = player.score / sum;
}
}
class Ball {
constructor(){
this.r = 15;
this.randX = random(this.r, width - this.r);
this.randY = random(this.r, height - this.r);
this.pos = new p5.Vector(this.randX, this.randY);
this.acc = new p5.Vector(random(-5, 5), random(-5, 5));
this.count = 0;
this.color = [random(0, 255), random(0, 255), random(0, 255)];
}
update(){
this.pos.x += this.acc.x;
this.pos.y += this.acc.y;
if(this.pos.x < this.r || this.pos.x > width - this.r){
this.acc.x *= -1;
}
if(this.pos.y < this.r || this.pos.y > height - this.r){
this.acc.y *= -1;
}
}
checkIntersect(another){ // check if ball hits another ball
return dist(this.pos.x, this.pos.y, another.pos.x, another.pos.y) < (this.r + another.r);
}
show(){
// show ball
fill(this.color[0], this.color[1], this.color[2]);
ellipse(this.pos.x, this.pos.y, this.r * 2);
// show ball score
fill(0);
textSize(20);
text(this.count, this.pos.x - (this.r / 2), this.pos.y + (this.r / 2));
}
}
class Player {
constructor(brain){
this.range = 150;
this.r = 15;
this.count = 0;
this.score = 0;
this.fitness = 0;
this.pos = new p5.Vector(width / 2, height / 2);
this.acc = new p5.Vector();
// if brain was passed, copy it, else make new neuralnetwork
if(brain != undefined){
this.brain = brain.copy();
} else {
this.brain = new NeuralNetwork(6, 4, 1);
}
}
mutate(){
this.brain.mutate(x=>x*0.1);
}
move(x, y){
this.acc.x = x;
this.acc.y = y;
this.pos.x += this.acc.x;
this.pos.y += this.acc.y;
if(this.pos.x < this.r || this.pos.x > width - this.r){
this.pos.x -= this.acc.x;
}
if(this.pos.y < this.r || this.pos.y > height - this.r){
this.pos.y -= this.acc.y;
}
}
think(){
let inputs = [];
// set INPUTS of this particular Player
inputs.push(this.pos.x / width);
inputs.push(this.pos.y / height);
inputs.push(this.count);
// get closest ball
let closestBall = balls[0];
let closestD = dist(this.pos.x, this.pos.y, closestBall.pos.x, closestBall.pos.y);
for(let ball of balls){
let d = dist(this.pos.x, this.pos.y, ball.pos.x, ball.pos.y);
if(d < closestD){
closestD = d;
closestBall = ball;
}
}
// set INPUTS of closest Ball
inputs.push(closestBall.pos.x / width);
inputs.push(closestBall.pos.y / height);
inputs.push(closestBall.count);
// predict inputs and then do actions
let output = this.brain.predict(inputs);
if(output < 0.25){
this.move(0, -3); // up
} else if(output >= 0.25 && output < 0.5){
this.move(-3, 0); // left
} else if(output >= 0.5 && output < 0.75){
this.move(0, 3); // down
} else {
this.move(3, 0); // right
}
}
checkIntersect(another){ // check if player hits ball
return dist(this.pos.x, this.pos.y, another.pos.x, another.pos.y) < (this.r + another.r);
}
show(){
//fill(255, 0, 0, 20);
//ellipse(this.pos.x, this.pos.y, this.range * 2);
// show player
fill(0, 255, 0);
ellipse(this.pos.x, this.pos.y, this.r * 2);
// show player score
fill(0);
textSize(20);
text("!" + this.count, this.pos.x - (this.r / 2), this.pos.y + (this.r / 2));
}
}
function setup(){
createCanvas(windowWidth, windowHeight);
// create balls
for(let i = 0; i < totalBalls; i++){
balls.push(new Ball());
}
// create players
for(let i = 0; i < totalPlayers; i++){
players.push(new Player());
}
}
function draw(){
background(51);
// keep spawning new balls
if(balls.length != totalBalls){
while(balls.length != totalBalls){
balls.push(new Ball());
}
}
// reset game and make a nextGeneration out of previous
if(players.length == 0 || frameCount == 1000){
nextGeneration();
}
// some special graphic stuff, NOT IMPORTANT
let rw = round(windowWidth / totalBalls);
for(let i = 0; i < balls.length; i++){
let rh = constrain(balls[i].count, 0, height);
let c = balls[i].color;
c[3] = 50; // transparent background
fill(c);
rect(i * rw, height, rw, -rh);
}
for(let player of players){
player.score++;
player.think();
player.show();
for(let ball of balls){
if(player.checkIntersect(ball)){
if(player.count > ball.count){
player.count += 1;
player.count += ball.count;
balls.splice(balls.indexOf(ball), 1);
} else {
ball.count += 1;
ball.count += player.count;
tmpplayers.push(players.splice(players.indexOf(player), 1)[0]);
}
}
}
}
for(let ball of balls){
ball.update();
ball.show();
for(let another of balls){
if(ball != another){
if(ball.checkIntersect(another)){
if(ball.count > another.count){
ball.count += 1;
ball.count += another.count;
balls.splice(balls.indexOf(another), 1);
} else {
another.count += 1;
another.count += ball.count;
balls.splice(balls.indexOf(ball), 1);
}
}
}
}
}
}
* {
padding: 0;
margin: 0;
overflow: hidden;
}
<script src="https://rawgit.com/CodingTrain/Toy-Neural-Network-JS/master/lib/matrix.js"></script>
<script src="https://rawgit.com/CodingTrain/Toy-Neural-Network-JS/master/lib/nn.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.js"></script>
解决方案
似乎 mutate 需要函数参数,而不是数字。
更改 Player 的方法mutate
如下:
this.brain.mutate(0.1)
至
this.brain.mutate(x=>x*0.1)
这会将每个元素乘以 0.1
let balls = [];
let totalBalls = 5;
let players = [];
let tmpplayers = [];
let totalPlayers = 100;
function nextGeneration(){
calcFitness();
for(let i = 0; i < totalPlayers; i++){
players.push(pickOnePlayer());
}
tmpplayers = [];
console.log("next generation");
}
function pickOnePlayer(){
let index = 0;
let r = random(1);
while(r > 0){
r = r - tmpplayers[index].fitness;
index++;
}
index--;
let player = tmpplayers[index];
let child = new Player(player.brain);
child.mutate();
return child;
}
function calcFitness(){
let sum = 0;
for(let player of tmpplayers){
sum += player.score;
}
for(let player of tmpplayers){
player.fitness = player.score / sum;
}
}
class Ball {
constructor(){
this.r = 15;
this.randX = random(this.r, width - this.r);
this.randY = random(this.r, height - this.r);
this.pos = new p5.Vector(this.randX, this.randY);
this.acc = new p5.Vector(random(-5, 5), random(-5, 5));
this.count = 0;
this.color = [random(0, 255), random(0, 255), random(0, 255)];
}
update(){
this.pos.x += this.acc.x;
this.pos.y += this.acc.y;
if(this.pos.x < this.r || this.pos.x > width - this.r){
this.acc.x *= -1;
}
if(this.pos.y < this.r || this.pos.y > height - this.r){
this.acc.y *= -1;
}
}
checkIntersect(another){ // check if ball hits another ball
return dist(this.pos.x, this.pos.y, another.pos.x, another.pos.y) < (this.r + another.r);
}
show(){
// show ball
fill(this.color[0], this.color[1], this.color[2]);
ellipse(this.pos.x, this.pos.y, this.r * 2);
// show ball score
fill(0);
textSize(20);
text(this.count, this.pos.x - (this.r / 2), this.pos.y + (this.r / 2));
}
}
class Player {
constructor(brain){
this.range = 150;
this.r = 15;
this.count = 0;
this.score = 0;
this.fitness = 0;
this.pos = new p5.Vector(width / 2, height / 2);
this.acc = new p5.Vector();
// if brain was passed, copy it, else make new neuralnetwork
if(brain != undefined){
this.brain = brain.copy();
} else {
this.brain = new NeuralNetwork(6, 4, 1);
}
}
mutate(){
this.brain.mutate(x=>x*0.1);
}
move(x, y){
this.acc.x = x;
this.acc.y = y;
this.pos.x += this.acc.x;
this.pos.y += this.acc.y;
if(this.pos.x < this.r || this.pos.x > width - this.r){
this.pos.x -= this.acc.x;
}
if(this.pos.y < this.r || this.pos.y > height - this.r){
this.pos.y -= this.acc.y;
}
}
think(){
let inputs = [];
// set INPUTS of this particular Player
inputs.push(this.pos.x / width);
inputs.push(this.pos.y / height);
inputs.push(this.count);
// get closest ball
let closestBall = balls[0];
let closestD = dist(this.pos.x, this.pos.y, closestBall.pos.x, closestBall.pos.y);
for(let ball of balls){
let d = dist(this.pos.x, this.pos.y, ball.pos.x, ball.pos.y);
if(d < closestD){
closestD = d;
closestBall = ball;
}
}
// set INPUTS of closest Ball
inputs.push(closestBall.pos.x / width);
inputs.push(closestBall.pos.y / height);
inputs.push(closestBall.count);
// predict inputs and then do actions
let output = this.brain.predict(inputs);
if(output < 0.25){
this.move(0, -3); // up
} else if(output >= 0.25 && output < 0.5){
this.move(-3, 0); // left
} else if(output >= 0.5 && output < 0.75){
this.move(0, 3); // down
} else {
this.move(3, 0); // right
}
}
checkIntersect(another){ // check if player hits ball
return dist(this.pos.x, this.pos.y, another.pos.x, another.pos.y) < (this.r + another.r);
}
show(){
//fill(255, 0, 0, 20);
//ellipse(this.pos.x, this.pos.y, this.range * 2);
// show player
fill(0, 255, 0);
ellipse(this.pos.x, this.pos.y, this.r * 2);
// show player score
fill(0);
textSize(20);
text("!" + this.count, this.pos.x - (this.r / 2), this.pos.y + (this.r / 2));
}
}
function setup(){
createCanvas(windowWidth, windowHeight);
// create balls
for(let i = 0; i < totalBalls; i++){
balls.push(new Ball());
}
// create players
for(let i = 0; i < totalPlayers; i++){
players.push(new Player());
}
}
function draw(){
background(51);
// keep spawning new balls
if(balls.length != totalBalls){
while(balls.length != totalBalls){
balls.push(new Ball());
}
}
// reset game and make a nextGeneration out of previous
if(players.length == 0 || frameCount == 1000){
nextGeneration();
}
// some special graphic stuff, NOT IMPORTANT
let rw = round(windowWidth / totalBalls);
for(let i = 0; i < balls.length; i++){
let rh = constrain(balls[i].count, 0, height);
let c = balls[i].color;
c[3] = 50; // transparent background
fill(c);
rect(i * rw, height, rw, -rh);
}
for(let player of players){
player.score++;
player.think();
player.show();
for(let ball of balls){
if(player.checkIntersect(ball)){
if(player.count > ball.count){
player.count += 1;
player.count += ball.count;
balls.splice(balls.indexOf(ball), 1);
} else {
ball.count += 1;
ball.count += player.count;
tmpplayers.push(players.splice(players.indexOf(player), 1)[0]);
}
}
}
}
for(let ball of balls){
ball.update();
ball.show();
for(let another of balls){
if(ball != another){
if(ball.checkIntersect(another)){
if(ball.count > another.count){
ball.count += 1;
ball.count += another.count;
balls.splice(balls.indexOf(another), 1);
} else {
another.count += 1;
another.count += ball.count;
balls.splice(balls.indexOf(ball), 1);
}
}
}
}
}
}
* {
padding: 0;
margin: 0;
overflow: hidden;
}
<script src="https://rawgit.com/CodingTrain/Toy-Neural-Network-JS/master/lib/matrix.js"></script>
<script src="https://rawgit.com/CodingTrain/Toy-Neural-Network-JS/master/lib/nn.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.js"></script>
推荐阅读
- sql - APEX:如何在分离成数组后存储值并将它们写入表中
- javascript - 无法进入 JavaScript 中的函数
- python - 在树莓派的线程中调用时无法重用 imshow 窗口
- javascript - 迭代并计算数组内对象内的对象
- azure - Azure 服务器中的 laravel 5.4 + php 7.0 错误
- visual-studio-2015 - 无法连接到 Azure 存储
- javascript - Draggable 无法正常获取未捕获的引用错误
- python - 为 chi_square 创建一个函数
- java - 如何通过 Selenium WebDriver 和 Java 找到具有以下提到的属性的取消按钮
- reactjs - Proptypes isRequired undefined