/**** * Classes ****/ var AI = Container.expand(function () { var self = Container.call(this); self.inheritTraits = function (parent) { this.food = parent.food * 0.5; this.speed = parent.speed; this.agility = parent.agility; this.strength = parent.strength; this.intelligence = parent.intelligence; }; var ais = []; self.foods = []; self.aiGraphics = self.attachAsset('ai', { anchorX: 0.5, anchorY: 0.5 }); self.food = 10; self.generation = 1; self.family = []; self.generationText = new Text2(self.generation.toString(), { size: 50, fill: '#ffffff' }); self.generationText.anchor.set(.5, 0); self.addChild(self.generationText); self.eat = function (food) { if (food.amount > 0) { var familyNeedsFood = this.family.some(function (member) { return member.food < 1; }); if (!familyNeedsFood) { this.food += food.consume(1); } } }; self.share = function (otherAI) { var decision = this.neuralNetwork.feedForward([this.food, otherAI.food, this.fieldOfView]); if (decision > 0) { if (this.food > 10) { var shareAmount = this.food * 0.1; this.food -= shareAmount; this.family.forEach(function (member) { member.food += shareAmount / this.family.length; }); } } }; self.survive = function () { this.food -= 0.01; if (this.food < 0) { this.destroy(); var index = ais.indexOf(this); if (index > -1) { ais.splice(index, 1); } } }; self.neuralNetwork = new NeuralNetwork(); self.neuralNetwork.weights = [Math.random(), Math.random()]; self.neuralNetwork.bias = Math.random(); self.direction = Math.random() * 2 * Math.PI; self.fieldOfView = Math.random() * Math.PI; self.viewDistance = Math.random() * 500; self.speed = Math.random() * 5; self.reproductionThreshold = 2; self.generation = 1; self.agility = Math.random() * 5; self.strength = Math.random() * 5; self.intelligence = Math.random() * 5; self._move_migrated = function () { var nearestFood = null; var nearestFoodDistance = Infinity; for (var i = 0; i < this.foods.length; i++) { var dx = this.foods[i].x - this.x; var dy = this.foods[i].y - this.y; var distance = Math.sqrt(dx * dx + dy * dy); var angle = Math.atan2(dy, dx); var deltaAngle = Math.abs(this.direction - angle); if (distance < this.viewDistance && deltaAngle < this.fieldOfView / 2 && distance < nearestFoodDistance) { nearestFood = this.foods[i]; nearestFoodDistance = distance; } } if (nearestFood) { var dx = nearestFood.x - this.x; var dy = nearestFood.y - this.y; self.direction = Math.atan2(dy, dx); } else { if (Math.random() < 0.05) { self.direction += Math.random() * 0.2 - 0.1; } } var speed = 5; var newX = self.x + Math.cos(self.direction) * speed; var newY = self.y + Math.sin(self.direction) * speed; if (newX < 0) { newX = 0; self.direction = Math.PI - self.direction; } else if (newX > 2048) { newX = 2048; self.direction = Math.PI - self.direction; } if (newY < 0) { newY = 0; self.direction = -self.direction; } else if (newY > 2732) { newY = 2732; self.direction = -self.direction; } self.x = newX; self.y = newY; }; self.reproduce = function () { if (this.food > 10) { var child = new AI(); child.neuralNetwork = this.neuralNetwork.clone(); for (var i = 0; i < child.neuralNetwork.weights.length; i++) { if (Math.random() < 0.1) { child.neuralNetwork.weights[i] += Math.random() * 0.2 - 0.1; } } if (Math.random() < 0.1) { child.neuralNetwork.bias += Math.random() * 0.2 - 0.1; } if (Math.random() < 0.1) { child.fieldOfView += Math.random() * 0.2 - 0.1; } if (Math.random() < 0.1) { child.viewDistance += Math.random() * 100 - 50; } if (Math.random() < 0.1) { child.speed += Math.random() * 0.2 - 0.1; } if (Math.random() < 0.1) { child.reproductionThreshold += Math.random() * 0.2 - 0.1; } if (Math.random() < 0.1) { child.agility += Math.random() * 0.2 - 0.1; } if (Math.random() < 0.1) { child.strength += Math.random() * 0.2 - 0.1; } if (Math.random() < 0.1) { child.intelligence += Math.random() * 0.2 - 0.1; } child.inheritTraits(this); this.food -= 10; ais.push(child); this.family.push(child); child.direction = Math.random() * 2 * Math.PI; child.generation = this.generation + 1; return child; } return null; }; }); var Food = Container.expand(function () { var self = Container.call(this); var foodGraphics = self.attachAsset('food', { anchorX: 0.5, anchorY: 0.5 }); self.amount = 10; self.consume = function (amount) { this.amount -= amount; return amount; }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ var NeuralNetwork = function NeuralNetwork() { var self = this; self.weights = []; self.bias = 0; self.clone = function () { var clone = new NeuralNetwork(); clone.weights = this.weights.slice(); clone.bias = this.bias; return clone; }; self.feedForward = function (inputs) { var sum = 0; for (var i = 0; i < inputs.length; i++) { sum += inputs[i] * this.weights[i]; } return sum + this.bias; }; }; var ais = []; var foods = []; for (var i = 0; i < 3; i++) { var ai = new AI(); ai.x = Math.random() * 2048; ai.y = Math.random() * 2732; ais.push(ai); game.addChild(ai); var food = new Food(); food.x = Math.random() * 2048; food.y = Math.random() * 2732; foods.push(food); game.addChild(food); } LK.on('tick', function () { for (var i = 0; i < ais.length; i++) { var ai = ais[i]; ai._move_migrated(); ai.survive(); ai.generationText.setText(ai.generation.toString()); for (var j = 0; j < foods.length; j++) { var food = foods[j]; if (ai.intersects(food)) { ai.eat(food); food.consume(1); if (food.amount <= 0) { food.destroy(); foods.splice(j, 1); j--; } } } for (var j = i + 1; j < ais.length; j++) { var otherAI = ais[j]; if (ai.intersects(otherAI)) { var decision = ai.neuralNetwork.feedForward([ai.food, otherAI.food]); if (decision > 0) { ai.share(otherAI); } } } if (ai.food <= 0) { var index = ais.indexOf(ai); if (index > -1) { ais.splice(index, 1); } ai.destroy(); i--; if (ais.length === 0) { LK.showGameOver(); } } } if (LK.ticks % 600 == 0) { for (var i = 0; i < ais.length; i++) { var ai = ais[i]; var child = ai.reproduce(); if (child) { child.x = ai.x; child.y = ai.y; game.addChild(child); ais.push(child); } } } if (LK.ticks % 120 == 0) { var food = new Food(); food.x = Math.random() * 2048; food.y = Math.random() * 2732; foods.push(food); game.addChild(food); } });
/****
* Classes
****/
var AI = Container.expand(function () {
var self = Container.call(this);
self.inheritTraits = function (parent) {
this.food = parent.food * 0.5;
this.speed = parent.speed;
this.agility = parent.agility;
this.strength = parent.strength;
this.intelligence = parent.intelligence;
};
var ais = [];
self.foods = [];
self.aiGraphics = self.attachAsset('ai', {
anchorX: 0.5,
anchorY: 0.5
});
self.food = 10;
self.generation = 1;
self.family = [];
self.generationText = new Text2(self.generation.toString(), {
size: 50,
fill: '#ffffff'
});
self.generationText.anchor.set(.5, 0);
self.addChild(self.generationText);
self.eat = function (food) {
if (food.amount > 0) {
var familyNeedsFood = this.family.some(function (member) {
return member.food < 1;
});
if (!familyNeedsFood) {
this.food += food.consume(1);
}
}
};
self.share = function (otherAI) {
var decision = this.neuralNetwork.feedForward([this.food, otherAI.food, this.fieldOfView]);
if (decision > 0) {
if (this.food > 10) {
var shareAmount = this.food * 0.1;
this.food -= shareAmount;
this.family.forEach(function (member) {
member.food += shareAmount / this.family.length;
});
}
}
};
self.survive = function () {
this.food -= 0.01;
if (this.food < 0) {
this.destroy();
var index = ais.indexOf(this);
if (index > -1) {
ais.splice(index, 1);
}
}
};
self.neuralNetwork = new NeuralNetwork();
self.neuralNetwork.weights = [Math.random(), Math.random()];
self.neuralNetwork.bias = Math.random();
self.direction = Math.random() * 2 * Math.PI;
self.fieldOfView = Math.random() * Math.PI;
self.viewDistance = Math.random() * 500;
self.speed = Math.random() * 5;
self.reproductionThreshold = 2;
self.generation = 1;
self.agility = Math.random() * 5;
self.strength = Math.random() * 5;
self.intelligence = Math.random() * 5;
self._move_migrated = function () {
var nearestFood = null;
var nearestFoodDistance = Infinity;
for (var i = 0; i < this.foods.length; i++) {
var dx = this.foods[i].x - this.x;
var dy = this.foods[i].y - this.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var angle = Math.atan2(dy, dx);
var deltaAngle = Math.abs(this.direction - angle);
if (distance < this.viewDistance && deltaAngle < this.fieldOfView / 2 && distance < nearestFoodDistance) {
nearestFood = this.foods[i];
nearestFoodDistance = distance;
}
}
if (nearestFood) {
var dx = nearestFood.x - this.x;
var dy = nearestFood.y - this.y;
self.direction = Math.atan2(dy, dx);
} else {
if (Math.random() < 0.05) {
self.direction += Math.random() * 0.2 - 0.1;
}
}
var speed = 5;
var newX = self.x + Math.cos(self.direction) * speed;
var newY = self.y + Math.sin(self.direction) * speed;
if (newX < 0) {
newX = 0;
self.direction = Math.PI - self.direction;
} else if (newX > 2048) {
newX = 2048;
self.direction = Math.PI - self.direction;
}
if (newY < 0) {
newY = 0;
self.direction = -self.direction;
} else if (newY > 2732) {
newY = 2732;
self.direction = -self.direction;
}
self.x = newX;
self.y = newY;
};
self.reproduce = function () {
if (this.food > 10) {
var child = new AI();
child.neuralNetwork = this.neuralNetwork.clone();
for (var i = 0; i < child.neuralNetwork.weights.length; i++) {
if (Math.random() < 0.1) {
child.neuralNetwork.weights[i] += Math.random() * 0.2 - 0.1;
}
}
if (Math.random() < 0.1) {
child.neuralNetwork.bias += Math.random() * 0.2 - 0.1;
}
if (Math.random() < 0.1) {
child.fieldOfView += Math.random() * 0.2 - 0.1;
}
if (Math.random() < 0.1) {
child.viewDistance += Math.random() * 100 - 50;
}
if (Math.random() < 0.1) {
child.speed += Math.random() * 0.2 - 0.1;
}
if (Math.random() < 0.1) {
child.reproductionThreshold += Math.random() * 0.2 - 0.1;
}
if (Math.random() < 0.1) {
child.agility += Math.random() * 0.2 - 0.1;
}
if (Math.random() < 0.1) {
child.strength += Math.random() * 0.2 - 0.1;
}
if (Math.random() < 0.1) {
child.intelligence += Math.random() * 0.2 - 0.1;
}
child.inheritTraits(this);
this.food -= 10;
ais.push(child);
this.family.push(child);
child.direction = Math.random() * 2 * Math.PI;
child.generation = this.generation + 1;
return child;
}
return null;
};
});
var Food = Container.expand(function () {
var self = Container.call(this);
var foodGraphics = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5
});
self.amount = 10;
self.consume = function (amount) {
this.amount -= amount;
return amount;
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var NeuralNetwork = function NeuralNetwork() {
var self = this;
self.weights = [];
self.bias = 0;
self.clone = function () {
var clone = new NeuralNetwork();
clone.weights = this.weights.slice();
clone.bias = this.bias;
return clone;
};
self.feedForward = function (inputs) {
var sum = 0;
for (var i = 0; i < inputs.length; i++) {
sum += inputs[i] * this.weights[i];
}
return sum + this.bias;
};
};
var ais = [];
var foods = [];
for (var i = 0; i < 3; i++) {
var ai = new AI();
ai.x = Math.random() * 2048;
ai.y = Math.random() * 2732;
ais.push(ai);
game.addChild(ai);
var food = new Food();
food.x = Math.random() * 2048;
food.y = Math.random() * 2732;
foods.push(food);
game.addChild(food);
}
LK.on('tick', function () {
for (var i = 0; i < ais.length; i++) {
var ai = ais[i];
ai._move_migrated();
ai.survive();
ai.generationText.setText(ai.generation.toString());
for (var j = 0; j < foods.length; j++) {
var food = foods[j];
if (ai.intersects(food)) {
ai.eat(food);
food.consume(1);
if (food.amount <= 0) {
food.destroy();
foods.splice(j, 1);
j--;
}
}
}
for (var j = i + 1; j < ais.length; j++) {
var otherAI = ais[j];
if (ai.intersects(otherAI)) {
var decision = ai.neuralNetwork.feedForward([ai.food, otherAI.food]);
if (decision > 0) {
ai.share(otherAI);
}
}
}
if (ai.food <= 0) {
var index = ais.indexOf(ai);
if (index > -1) {
ais.splice(index, 1);
}
ai.destroy();
i--;
if (ais.length === 0) {
LK.showGameOver();
}
}
}
if (LK.ticks % 600 == 0) {
for (var i = 0; i < ais.length; i++) {
var ai = ais[i];
var child = ai.reproduce();
if (child) {
child.x = ai.x;
child.y = ai.y;
game.addChild(child);
ais.push(child);
}
}
}
if (LK.ticks % 120 == 0) {
var food = new Food();
food.x = Math.random() * 2048;
food.y = Math.random() * 2732;
foods.push(food);
game.addChild(food);
}
});