整理桌面
This commit is contained in:
92
node_modules/neataptic/mkdocs/theme/js/articles/agar.ioai/field.js
generated
vendored
Normal file
92
node_modules/neataptic/mkdocs/theme/js/articles/agar.ioai/field.js
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
/* Global vars */
|
||||
var players = [];
|
||||
var foods = [];
|
||||
var iteration = 0;
|
||||
var highestScore = 0;
|
||||
|
||||
/** Setup the canvas */
|
||||
function setup(){
|
||||
var canvas = createCanvas(WIDTH, HEIGHT);
|
||||
canvas.parent('field');
|
||||
initNeat();
|
||||
|
||||
// Create some food
|
||||
for(var i = 0; i < FOOD_AMOUNT; i++){
|
||||
new Food();
|
||||
}
|
||||
|
||||
startEvaluation();
|
||||
}
|
||||
|
||||
function draw(){
|
||||
clear();
|
||||
squareGrid();
|
||||
|
||||
// Check if evaluation is done
|
||||
if(iteration == ITERATIONS){
|
||||
endEvaluation();
|
||||
iteration = 0;
|
||||
}
|
||||
|
||||
// Update and visualise players
|
||||
for(var i = players.length - 1; i >= 0; i--){
|
||||
var player = players[i];
|
||||
|
||||
// Some players are eaten during the iteration
|
||||
player.update();
|
||||
player.show();
|
||||
}
|
||||
|
||||
// Update and visualise food
|
||||
for(var i = foods.length - 1; i >= 0; i--){
|
||||
foods[i].show();
|
||||
}
|
||||
|
||||
iteration++;
|
||||
}
|
||||
|
||||
/** Draw a square grid with grey lines */
|
||||
function squareGrid(){
|
||||
stroke(204, 204, 204, 160);
|
||||
fill(255);
|
||||
for(var x = 0; x < WIDTH/40; x++){
|
||||
line(x * 40, 0, x * 40, HEIGHT);
|
||||
}
|
||||
for(var y = 0; y < HEIGHT/40; y++){
|
||||
line(0, y * 40, WIDTH, y * 40);
|
||||
}
|
||||
noStroke();
|
||||
}
|
||||
|
||||
/** Calculate distance between two points */
|
||||
function distance(x1, y1, x2, y2){
|
||||
var dx = x1 - x2;
|
||||
var dy = y1 - y2;
|
||||
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
/** Get a relative color between red and green */
|
||||
var activationColor = function(value, max){
|
||||
var power = 1 - Math.min(value/max, 1);
|
||||
var color = [255, 255, 0]
|
||||
|
||||
if(power < 0.5){
|
||||
color[0] = 2 * power * 255;
|
||||
} else {
|
||||
color[1] = (1.0 - 2 * (power - 0.5)) * 255;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
/** Get the angle from one point to another */
|
||||
function angleToPoint(x1, y1, x2, y2){
|
||||
d = distance(x1, y1, x2, y2);
|
||||
dx = (x2-x1) / d;
|
||||
dy = (y2-y1) / d;
|
||||
|
||||
a = Math.acos(dx);
|
||||
a = dy < 0 ? 2 * Math.PI - a : a;
|
||||
return a;
|
||||
}
|
31
node_modules/neataptic/mkdocs/theme/js/articles/agar.ioai/food.js
generated
vendored
Normal file
31
node_modules/neataptic/mkdocs/theme/js/articles/agar.ioai/food.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
function Food(){
|
||||
this.x = Math.floor(Math.random() * WIDTH);
|
||||
this.y = Math.floor(Math.random() * HEIGHT);
|
||||
this.area = FOOD_AREA;
|
||||
|
||||
this.color = [
|
||||
Math.round(Math.random() * 255),
|
||||
Math.round(Math.random() * 255),
|
||||
Math.round(Math.random() * 255)
|
||||
];
|
||||
|
||||
foods.push(this);
|
||||
}
|
||||
|
||||
Food.prototype = {
|
||||
/** Display the player on the field */
|
||||
show: function(){
|
||||
var radius = Math.sqrt(this.area / PI);
|
||||
|
||||
fill(this.color[0], this.color[1], this.color[2]);
|
||||
noStroke();
|
||||
ellipse(this.x, this.y, radius);
|
||||
},
|
||||
|
||||
/** Restart from new position */
|
||||
restart: function(){
|
||||
this.x = Math.floor(Math.random() * WIDTH);
|
||||
this.y = Math.floor(Math.random() * HEIGHT);
|
||||
},
|
||||
|
||||
};
|
37
node_modules/neataptic/mkdocs/theme/js/articles/agar.ioai/import.js
generated
vendored
Normal file
37
node_modules/neataptic/mkdocs/theme/js/articles/agar.ioai/import.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
var scripts = [
|
||||
{ type: 'script', url: "https://cdn.rawgit.com/wagenaartje/neataptic/a7610e38/dist/neataptic.js"},
|
||||
{ type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/p5.js"},
|
||||
{ type: 'script', url: "../../js/articles/agar.ioai/main.js"},
|
||||
{ type: 'script', url: "../../js/articles/agar.ioai/population.js"},
|
||||
{ type: 'script', url: "../../js/articles/agar.ioai/player.js"},
|
||||
{ type: 'script', url: "../../js/articles/agar.ioai/food.js"},
|
||||
{ type: 'script', url: "../../js/articles/agar.ioai/field.js"}
|
||||
];
|
||||
|
||||
/** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/
|
||||
function require(list) {
|
||||
function loadScript(link) {
|
||||
return new Promise(function(fulfill, reject) {
|
||||
if(link.type == 'script'){
|
||||
var script = document.createElement("script");
|
||||
script.addEventListener("load", fulfill);
|
||||
script.src = link.url;
|
||||
document.head.appendChild(script);
|
||||
} else if(link.type == 'css'){
|
||||
var stylesheet = document.createElement('link');
|
||||
stylesheet.rel = 'stylesheet';
|
||||
stylesheet.type = 'text/css';
|
||||
stylesheet.href = link.url;
|
||||
stylesheet.media = "screen,print";
|
||||
document.head.appendChild(stylesheet);
|
||||
}
|
||||
});
|
||||
}
|
||||
loadScript(list.shift()).then(function() {
|
||||
if (list.length > 0) {
|
||||
require(list);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
require(scripts);
|
113
node_modules/neataptic/mkdocs/theme/js/articles/agar.ioai/main.js
generated
vendored
Normal file
113
node_modules/neataptic/mkdocs/theme/js/articles/agar.ioai/main.js
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
/** Rename vars */
|
||||
var Neat = neataptic.Neat;
|
||||
var Methods = neataptic.Methods;
|
||||
var Config = neataptic.Config;
|
||||
var Architect = neataptic.Architect;
|
||||
|
||||
/** Turn off warnings */
|
||||
Config.warnings = false;
|
||||
|
||||
/** Settings */
|
||||
var WIDTH = $('#field').width();
|
||||
var HEIGHT = 500;
|
||||
|
||||
var MAX_AREA = 10000;
|
||||
var MIN_AREA = 400;
|
||||
|
||||
var RELATIVE_SIZE = 1.1;
|
||||
var DECREASE_SIZE = 0.998;
|
||||
|
||||
var DETECTION_RADIUS = 150;
|
||||
var FOOD_DETECTION = 3;
|
||||
var PLAYER_DETECTION = 3;
|
||||
|
||||
var MIN_SPEED = 0.6;
|
||||
var SPEED = 2;
|
||||
|
||||
var FOOD_AREA = 80;
|
||||
var FOOD_AMOUNT = Math.round(WIDTH * HEIGHT * 4e-4);
|
||||
|
||||
// GA settings
|
||||
var PLAYER_AMOUNT = Math.round(WIDTH * HEIGHT * 8e-5);
|
||||
var ITERATIONS = 10e10;
|
||||
var START_HIDDEN_SIZE = 0;
|
||||
|
||||
// Trained population
|
||||
var USE_TRAINED_POP = true;
|
||||
|
||||
// Global vars
|
||||
var neat;
|
||||
|
||||
/** Construct the genetic algorithm */
|
||||
function initNeat(){
|
||||
neat = new Neat(
|
||||
1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2,
|
||||
2,
|
||||
null,
|
||||
{
|
||||
mutation: [
|
||||
Methods.Mutation.ADD_NODE,
|
||||
Methods.Mutation.SUB_NODE,
|
||||
Methods.Mutation.ADD_CONN,
|
||||
Methods.Mutation.SUB_CONN,
|
||||
Methods.Mutation.MOD_WEIGHT,
|
||||
Methods.Mutation.MOD_BIAS,
|
||||
Methods.Mutation.MOD_ACTIVATION,
|
||||
Methods.Mutation.ADD_GATE,
|
||||
Methods.Mutation.SUB_GATE,
|
||||
Methods.Mutation.ADD_SELF_CONN,
|
||||
Methods.Mutation.SUB_SELF_CONN,
|
||||
Methods.Mutation.ADD_BACK_CONN,
|
||||
Methods.Mutation.SUB_BACK_CONN
|
||||
],
|
||||
popsize: PLAYER_AMOUNT,
|
||||
mutationRate: 0.3,
|
||||
elitism: Math.round(0.1 * PLAYER_AMOUNT),
|
||||
network: new Architect.Random(
|
||||
1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2,
|
||||
START_HIDDEN_SIZE,
|
||||
2
|
||||
)
|
||||
}
|
||||
);
|
||||
|
||||
if(USE_TRAINED_POP){
|
||||
neat.population = population;
|
||||
}
|
||||
}
|
||||
|
||||
/** Start the evaluation of the current generation */
|
||||
function startEvaluation(){
|
||||
players = [];
|
||||
highestScore = 0;
|
||||
|
||||
for(var genome in neat.population){
|
||||
genome = neat.population[genome];
|
||||
new Player(genome);
|
||||
}
|
||||
}
|
||||
|
||||
/** End the evaluation of the current generation */
|
||||
function endEvaluation(){
|
||||
console.log('Generation:', neat.generation, '- average score:', neat.getAverage());
|
||||
|
||||
neat.sort();
|
||||
var newPopulation = [];
|
||||
|
||||
// Elitism
|
||||
for(var i = 0; i < neat.elitism; i++){
|
||||
newPopulation.push(neat.population[i]);
|
||||
}
|
||||
|
||||
// Breed the next individuals
|
||||
for(var i = 0; i < neat.popsize - neat.elitism; i++){
|
||||
newPopulation.push(neat.getOffspring());
|
||||
}
|
||||
|
||||
// Replace the old population with the new population
|
||||
neat.population = newPopulation;
|
||||
neat.mutate();
|
||||
|
||||
neat.generation++;
|
||||
startEvaluation();
|
||||
}
|
180
node_modules/neataptic/mkdocs/theme/js/articles/agar.ioai/player.js
generated
vendored
Normal file
180
node_modules/neataptic/mkdocs/theme/js/articles/agar.ioai/player.js
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
function Player(genome){
|
||||
this.x = Math.floor(Math.random() * WIDTH);
|
||||
this.y = Math.floor(Math.random() * HEIGHT);
|
||||
this.vx = 0;
|
||||
this.vy = 0;
|
||||
|
||||
this.brain = genome;
|
||||
this.brain.score = 0;
|
||||
|
||||
this.area = MIN_AREA;
|
||||
this.visualarea = this.area;
|
||||
|
||||
players.push(this);
|
||||
}
|
||||
|
||||
Player.prototype = {
|
||||
/** Update the stats */
|
||||
update: function(){
|
||||
if(this.area > MAX_AREA) this.area = MAX_AREA;
|
||||
if(this.area < MIN_AREA) this.area = MIN_AREA;
|
||||
|
||||
var input = this.detect();
|
||||
var output = this.brain.activate(input);
|
||||
|
||||
var moveangle = output[0] * 2 * PI;
|
||||
var movespeed = output[1] > 1 ? 1 : output[1] < 0 ? 0 : output[1];
|
||||
|
||||
this.vx = movespeed * Math.cos(moveangle) * SPEED;
|
||||
this.vy = movespeed * Math.sin(moveangle) * SPEED;
|
||||
|
||||
// Large blobs move slower
|
||||
this.vx *= Math.max(1 - (this.area / MAX_AREA), MIN_SPEED / SPEED);
|
||||
this.vy *= Math.max(1 - (this.area / MAX_AREA), MIN_SPEED / SPEED);
|
||||
|
||||
this.x += this.vx;
|
||||
this.y += this.vy;
|
||||
|
||||
// Limit position to width and height
|
||||
this.x = this.x >= WIDTH ? this.x % WIDTH : this.x <= 0 ? this.x + WIDTH : this.x;
|
||||
this.y = this.y >= HEIGHT ? this.y % HEIGHT : this.y <= 0 ? this.y + HEIGHT : this.y;
|
||||
|
||||
this.area *= DECREASE_SIZE;
|
||||
|
||||
// Replace highest score to visualise
|
||||
this.brain.score = this.area;
|
||||
highestScore = this.brain.score > highestScore ? this.brain.score : highestScore;
|
||||
},
|
||||
|
||||
/** Restart from new position */
|
||||
restart: function(){
|
||||
this.x = Math.floor(Math.random() * WIDTH);
|
||||
this.y = Math.floor(Math.random() * HEIGHT);
|
||||
this.vx = 0;
|
||||
this.vy = 0;
|
||||
this.area = MIN_AREA;
|
||||
this.visualarea = this.area;
|
||||
},
|
||||
|
||||
/** Display the player on the field */
|
||||
show: function(){
|
||||
this.visualarea = lerp(this.visualarea, this.area, 0.2);
|
||||
var radius = Math.sqrt(this.visualarea / PI);
|
||||
var color = activationColor(this.brain.score, highestScore);
|
||||
|
||||
fill(color);
|
||||
ellipse(this.x, this.y, radius);
|
||||
},
|
||||
|
||||
/** Visualies the detection of the brain */
|
||||
showDetection: function(detected){
|
||||
noFill();
|
||||
for(var object in detected){
|
||||
object = detected[object];
|
||||
|
||||
if(object != undefined){
|
||||
stroke(object instanceof Player ? 'red' : 'lightgreen');
|
||||
line(this.x, this.y, object.x, object.y);
|
||||
}
|
||||
}
|
||||
|
||||
var color = activationColor(this.brain.score, highestScore);
|
||||
stroke(color);
|
||||
ellipse(this.x, this.y, DETECTION_RADIUS*2);
|
||||
noStroke();
|
||||
},
|
||||
|
||||
/* Checks if object can be eaten */
|
||||
eat: function(object){
|
||||
var dist = distance(this.x, this.y, object.x, object.y);
|
||||
|
||||
var radius1 = Math.sqrt(this.area / PI);
|
||||
var radius2 = Math.sqrt(object.area / PI);
|
||||
if(dist < (radius1 + radius2) / 2 && this.area > object.area * RELATIVE_SIZE){
|
||||
this.area += object.area;
|
||||
object.restart();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/** Detect other genomes around */
|
||||
detect: function(){
|
||||
// Detect nearest objects
|
||||
var nearestPlayers = [];
|
||||
var playerDistances = Array.apply(null, Array(PLAYER_DETECTION)).map(Number.prototype.valueOf, Infinity);
|
||||
|
||||
for(var player in players){
|
||||
player = players[player];
|
||||
if(player == this || this.eat(player)) continue;
|
||||
|
||||
var dist = distance(this.x, this.y, player.x, player.y);
|
||||
if(dist < DETECTION_RADIUS){
|
||||
// Check if closer than any other object
|
||||
var maxNearestDistance = Math.max.apply(null, playerDistances);
|
||||
var index = playerDistances.indexOf(maxNearestDistance);
|
||||
|
||||
if(dist < maxNearestDistance){
|
||||
playerDistances[index] = dist;
|
||||
nearestPlayers[index] = player;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Detect nearest foods
|
||||
var nearestFoods = [];
|
||||
var foodDistances = Array.apply(null, Array(FOOD_DETECTION)).map(Number.prototype.valueOf, Infinity);
|
||||
|
||||
for(var food in foods){
|
||||
food = foods[food];
|
||||
if(this.eat(food)) continue;
|
||||
|
||||
var dist = distance(this.x, this.y, food.x, food.y);
|
||||
if(dist < DETECTION_RADIUS){
|
||||
// Check if closer than any other object
|
||||
var maxNearestDistance = Math.max.apply(null, foodDistances);
|
||||
var index = foodDistances.indexOf(maxNearestDistance);
|
||||
|
||||
if(dist < maxNearestDistance){
|
||||
foodDistances[index] = dist;
|
||||
nearestFoods[index] = food;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create and normalize input
|
||||
var output = [this.area / MAX_AREA];
|
||||
|
||||
for(var i = 0; i < PLAYER_DETECTION; i++){
|
||||
var player = nearestPlayers[i];
|
||||
var dist = playerDistances[i];
|
||||
|
||||
if(player == undefined){
|
||||
output = output.concat([0, 0, 0]);
|
||||
} else {
|
||||
output.push(angleToPoint(this.x, this.y, player.x, player.y) / (2 * PI));
|
||||
output.push(dist / DETECTION_RADIUS);
|
||||
output.push(player.area / MAX_AREA);
|
||||
}
|
||||
}
|
||||
|
||||
for(var i = 0; i < FOOD_DETECTION; i++){
|
||||
var food = nearestFoods[i];
|
||||
var dist = foodDistances[i];
|
||||
|
||||
if(food == undefined){
|
||||
output = output.concat([0, 0]);
|
||||
} else {
|
||||
output.push(angleToPoint(this.x, this.y, food.x, food.y) / (2 * PI));
|
||||
output.push(dist / DETECTION_RADIUS);
|
||||
}
|
||||
}
|
||||
|
||||
if(distance(mouseX, mouseY, this.x, this.y) < Math.sqrt(this.visualarea / PI)){
|
||||
var detected = nearestPlayers.concat(nearestFoods);
|
||||
this.showDetection(detected);
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
};
|
29160
node_modules/neataptic/mkdocs/theme/js/articles/agar.ioai/population.js
generated
vendored
Normal file
29160
node_modules/neataptic/mkdocs/theme/js/articles/agar.ioai/population.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8
node_modules/neataptic/mkdocs/theme/js/articles/classifycolors/custom.css
generated
vendored
Normal file
8
node_modules/neataptic/mkdocs/theme/js/articles/classifycolors/custom.css
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
#circle {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
-webkit-border-radius: 10px;
|
||||
-moz-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
display: inline-block;
|
||||
}
|
24
node_modules/neataptic/mkdocs/theme/js/articles/classifycolors/events.js
generated
vendored
Normal file
24
node_modules/neataptic/mkdocs/theme/js/articles/classifycolors/events.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
$('.colors').change(function(){
|
||||
var color = $(this).attr('value');
|
||||
if($(this).is(":checked")) {
|
||||
COLORS.push(color);
|
||||
} else {
|
||||
COLORS.splice(COLORS.indexOf(color), 1);
|
||||
}
|
||||
|
||||
set = createSet();
|
||||
visualiseSet();
|
||||
});
|
||||
$('.start').click(function(e){
|
||||
e.preventDefault();
|
||||
if(running == false){
|
||||
running = true;
|
||||
iteration = 0;
|
||||
createNeat();
|
||||
$(this).html('<span class="glyphicon glyphicon-pause"></span> Stop evolution');
|
||||
setTimeout(loop, 1);
|
||||
} else {
|
||||
running = false;
|
||||
$(this).html('<span class="glyphicon glyphicon-play"></span> Start evolution');
|
||||
}
|
||||
});
|
35
node_modules/neataptic/mkdocs/theme/js/articles/classifycolors/import.js
generated
vendored
Normal file
35
node_modules/neataptic/mkdocs/theme/js/articles/classifycolors/import.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
var scripts = [
|
||||
{ type: 'script', url: "https://wagenaartje.github.io/neataptic/cdn/1.2.22/neataptic.js" },
|
||||
{ type: 'script', url: "../../js/articles/classifycolors/events.js" },
|
||||
{ type: 'script', url: "../../js/articles/classifycolors/randomColor.js" },
|
||||
{ type: 'script', url: "../../js/articles/classifycolors/neural.js" },
|
||||
{ type: 'css', url: "../../js/articles/classifycolors/custom.css"}
|
||||
];
|
||||
|
||||
/** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/
|
||||
function require(list) {
|
||||
function loadScript(link) {
|
||||
return new Promise(function(fulfill, reject) {
|
||||
if(link.type == 'script'){
|
||||
var script = document.createElement("script");
|
||||
script.addEventListener("load", fulfill);
|
||||
script.src = link.url;
|
||||
document.head.appendChild(script);
|
||||
} else if(link.type == 'css'){
|
||||
var stylesheet = document.createElement('link');
|
||||
stylesheet.rel = 'stylesheet';
|
||||
stylesheet.type = 'text/css';
|
||||
stylesheet.href = link.url;
|
||||
stylesheet.media = "screen,print";
|
||||
document.head.appendChild(stylesheet);
|
||||
}
|
||||
});
|
||||
}
|
||||
loadScript(list.shift()).then(function() {
|
||||
if (list.length > 0) {
|
||||
require(list);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
require(scripts);
|
106
node_modules/neataptic/mkdocs/theme/js/articles/classifycolors/neural.js
generated
vendored
Normal file
106
node_modules/neataptic/mkdocs/theme/js/articles/classifycolors/neural.js
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
var Neat = neataptic.Neat;
|
||||
var Methods = neataptic.Methods;
|
||||
var Network = neataptic.Network;
|
||||
|
||||
var set;
|
||||
var neat;
|
||||
var running = false;
|
||||
var iteration = 0;
|
||||
|
||||
var PER_COLOR = 50;
|
||||
// Possible colors: red, orange, yellow, green, blue, purple, pink and monochrome
|
||||
var COLORS = ['red', 'green', 'blue'];
|
||||
var network;
|
||||
|
||||
$( document ).ready(function(){
|
||||
set = createSet();
|
||||
visualiseSet();
|
||||
});
|
||||
|
||||
function createNeat(){
|
||||
network = new Network(3, COLORS.length);
|
||||
/*neat = new Neat(3, COLORS.length, fitness, {
|
||||
mutation: [
|
||||
Methods.Mutation.ADD_NODE,
|
||||
Methods.Mutation.ADD_CONN,
|
||||
Methods.Mutation.MOD_WEIGHT,
|
||||
Methods.Mutation.MOD_BIAS,
|
||||
Methods.Mutation.SUB_NODE,
|
||||
Methods.Mutation.MOD_ACTIVATION
|
||||
],
|
||||
mutationRate: 0.6,
|
||||
elitism: 5,
|
||||
popsize: 100,
|
||||
});*/
|
||||
}
|
||||
|
||||
function visualiseSet(){
|
||||
$('.set').empty();
|
||||
for(color in COLORS){
|
||||
$('.set').append('<div class="row ' + COLORS[color] + '"><h3>' + COLORS[color] + '</h3></div>');
|
||||
}
|
||||
|
||||
for(var item in set){
|
||||
item = set[item];
|
||||
$('.'+ item.color).append('<div id="circle" style="background-color:' + item.rgb + '"></div>');
|
||||
}
|
||||
}
|
||||
|
||||
function visualiseGenomeSet(genome){
|
||||
$('.fittestset').empty();
|
||||
for(color in COLORS){
|
||||
$('.fittestset').append('<div class="row fittest' + COLORS[color] + '"><h3>' + COLORS[color] + '</h3></div>');
|
||||
}
|
||||
|
||||
for(var item in set){
|
||||
item = set[item];
|
||||
var output = genome.activate(item.input);
|
||||
var max = Math.max.apply(null, output);
|
||||
var color = COLORS[output.indexOf(max)];
|
||||
|
||||
$('.fittest'+ color).append('<div id="circle" style="background-color:' + item.rgb + '"></div>');
|
||||
}
|
||||
}
|
||||
|
||||
function loop(){
|
||||
network.evolve(set, {
|
||||
iterations: 1,
|
||||
mutationRate: 0.6,
|
||||
elisitm: 5,
|
||||
popSize: 100,
|
||||
mutation: Methods.Mutation.FFW,
|
||||
cost: Methods.Cost.MSE
|
||||
});
|
||||
|
||||
visualiseGenomeSet(network);
|
||||
|
||||
$('.iteration').text(iteration);
|
||||
$('.bestfitness').text(network.test(set).error);
|
||||
|
||||
iteration++;
|
||||
if(running) setTimeout(loop, 1);
|
||||
}
|
||||
|
||||
// Thanks to https://github.com/davidmerfield/randomColor !!
|
||||
function createSet(){
|
||||
var set = [];
|
||||
|
||||
for(index in COLORS){
|
||||
var color = COLORS[index];
|
||||
|
||||
var randomColors = randomColor({ hue : color, count: PER_COLOR, format: 'rgb'});
|
||||
|
||||
for(var random in randomColors){
|
||||
var rgb = randomColors[random];
|
||||
random = rgb.substring(4, rgb.length-1).replace(/ /g, '').split(',');
|
||||
for(var y in random) random[y] = random[y]/255;
|
||||
|
||||
var output = Array.apply(null, Array(COLORS.length)).map(Number.prototype.valueOf, 0);
|
||||
output[index] = 1;
|
||||
|
||||
set.push({ input: random, output: output, color: color, rgb: rgb});
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
431
node_modules/neataptic/mkdocs/theme/js/articles/classifycolors/randomColor.js
generated
vendored
Normal file
431
node_modules/neataptic/mkdocs/theme/js/articles/classifycolors/randomColor.js
generated
vendored
Normal file
@@ -0,0 +1,431 @@
|
||||
// randomColor by David Merfield under the CC0 license
|
||||
// https://github.com/davidmerfield/randomColor/
|
||||
|
||||
;(function(root, factory) {
|
||||
|
||||
// Support AMD
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define([], factory);
|
||||
|
||||
// Support CommonJS
|
||||
} else if (typeof exports === 'object') {
|
||||
var randomColor = factory();
|
||||
|
||||
// Support NodeJS & Component, which allow module.exports to be a function
|
||||
if (typeof module === 'object' && module && module.exports) {
|
||||
exports = module.exports = randomColor;
|
||||
}
|
||||
|
||||
// Support CommonJS 1.1.1 spec
|
||||
exports.randomColor = randomColor;
|
||||
|
||||
// Support vanilla script loading
|
||||
} else {
|
||||
root.randomColor = factory();
|
||||
}
|
||||
|
||||
}(this, function() {
|
||||
|
||||
// Seed to get repeatable colors
|
||||
var seed = null;
|
||||
|
||||
// Shared color dictionary
|
||||
var colorDictionary = {};
|
||||
|
||||
// Populate the color dictionary
|
||||
loadColorBounds();
|
||||
|
||||
var randomColor = function (options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
// Check if there is a seed and ensure it's an
|
||||
// integer. Otherwise, reset the seed value.
|
||||
if (options.seed !== undefined && options.seed !== null && options.seed === parseInt(options.seed, 10)) {
|
||||
seed = options.seed;
|
||||
|
||||
// A string was passed as a seed
|
||||
} else if (typeof options.seed === 'string') {
|
||||
seed = stringToInteger(options.seed);
|
||||
|
||||
// Something was passed as a seed but it wasn't an integer or string
|
||||
} else if (options.seed !== undefined && options.seed !== null) {
|
||||
throw new TypeError('The seed value must be an integer or string');
|
||||
|
||||
// No seed, reset the value outside.
|
||||
} else {
|
||||
seed = null;
|
||||
}
|
||||
|
||||
var H,S,B;
|
||||
|
||||
// Check if we need to generate multiple colors
|
||||
if (options.count !== null && options.count !== undefined) {
|
||||
|
||||
var totalColors = options.count,
|
||||
colors = [];
|
||||
|
||||
options.count = null;
|
||||
|
||||
while (totalColors > colors.length) {
|
||||
|
||||
// Since we're generating multiple colors,
|
||||
// incremement the seed. Otherwise we'd just
|
||||
// generate the same color each time...
|
||||
if (seed && options.seed) options.seed += 1;
|
||||
|
||||
colors.push(randomColor(options));
|
||||
}
|
||||
|
||||
options.count = totalColors;
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
// First we pick a hue (H)
|
||||
H = pickHue(options);
|
||||
|
||||
// Then use H to determine saturation (S)
|
||||
S = pickSaturation(H, options);
|
||||
|
||||
// Then use S and H to determine brightness (B).
|
||||
B = pickBrightness(H, S, options);
|
||||
|
||||
// Then we return the HSB color in the desired format
|
||||
return setFormat([H,S,B], options);
|
||||
};
|
||||
|
||||
function pickHue (options) {
|
||||
|
||||
var hueRange = getHueRange(options.hue),
|
||||
hue = randomWithin(hueRange);
|
||||
|
||||
// Instead of storing red as two seperate ranges,
|
||||
// we group them, using negative numbers
|
||||
if (hue < 0) {hue = 360 + hue;}
|
||||
|
||||
return hue;
|
||||
|
||||
}
|
||||
|
||||
function pickSaturation (hue, options) {
|
||||
|
||||
if (options.luminosity === 'random') {
|
||||
return randomWithin([0,100]);
|
||||
}
|
||||
|
||||
if (options.hue === 'monochrome') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var saturationRange = getSaturationRange(hue);
|
||||
|
||||
var sMin = saturationRange[0],
|
||||
sMax = saturationRange[1];
|
||||
|
||||
switch (options.luminosity) {
|
||||
|
||||
case 'bright':
|
||||
sMin = 55;
|
||||
break;
|
||||
|
||||
case 'dark':
|
||||
sMin = sMax - 10;
|
||||
break;
|
||||
|
||||
case 'light':
|
||||
sMax = 55;
|
||||
break;
|
||||
}
|
||||
|
||||
return randomWithin([sMin, sMax]);
|
||||
|
||||
}
|
||||
|
||||
function pickBrightness (H, S, options) {
|
||||
|
||||
var bMin = getMinimumBrightness(H, S),
|
||||
bMax = 100;
|
||||
|
||||
switch (options.luminosity) {
|
||||
|
||||
case 'dark':
|
||||
bMax = bMin + 20;
|
||||
break;
|
||||
|
||||
case 'light':
|
||||
bMin = (bMax + bMin)/2;
|
||||
break;
|
||||
|
||||
case 'random':
|
||||
bMin = 0;
|
||||
bMax = 100;
|
||||
break;
|
||||
}
|
||||
|
||||
return randomWithin([bMin, bMax]);
|
||||
}
|
||||
|
||||
function setFormat (hsv, options) {
|
||||
|
||||
switch (options.format) {
|
||||
|
||||
case 'hsvArray':
|
||||
return hsv;
|
||||
|
||||
case 'hslArray':
|
||||
return HSVtoHSL(hsv);
|
||||
|
||||
case 'hsl':
|
||||
var hsl = HSVtoHSL(hsv);
|
||||
return 'hsl('+hsl[0]+', '+hsl[1]+'%, '+hsl[2]+'%)';
|
||||
|
||||
case 'hsla':
|
||||
var hslColor = HSVtoHSL(hsv);
|
||||
var alpha = options.alpha || Math.random();
|
||||
return 'hsla('+hslColor[0]+', '+hslColor[1]+'%, '+hslColor[2]+'%, ' + alpha + ')';
|
||||
|
||||
case 'rgbArray':
|
||||
return HSVtoRGB(hsv);
|
||||
|
||||
case 'rgb':
|
||||
var rgb = HSVtoRGB(hsv);
|
||||
return 'rgb(' + rgb.join(', ') + ')';
|
||||
|
||||
case 'rgba':
|
||||
var rgbColor = HSVtoRGB(hsv);
|
||||
var alpha = options.alpha || Math.random();
|
||||
return 'rgba(' + rgbColor.join(', ') + ', ' + alpha + ')';
|
||||
|
||||
default:
|
||||
return HSVtoHex(hsv);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getMinimumBrightness(H, S) {
|
||||
|
||||
var lowerBounds = getColorInfo(H).lowerBounds;
|
||||
|
||||
for (var i = 0; i < lowerBounds.length - 1; i++) {
|
||||
|
||||
var s1 = lowerBounds[i][0],
|
||||
v1 = lowerBounds[i][1];
|
||||
|
||||
var s2 = lowerBounds[i+1][0],
|
||||
v2 = lowerBounds[i+1][1];
|
||||
|
||||
if (S >= s1 && S <= s2) {
|
||||
|
||||
var m = (v2 - v1)/(s2 - s1),
|
||||
b = v1 - m*s1;
|
||||
|
||||
return m*S + b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getHueRange (colorInput) {
|
||||
|
||||
if (typeof parseInt(colorInput) === 'number') {
|
||||
|
||||
var number = parseInt(colorInput);
|
||||
|
||||
if (number < 360 && number > 0) {
|
||||
return [number, number];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (typeof colorInput === 'string') {
|
||||
|
||||
if (colorDictionary[colorInput]) {
|
||||
var color = colorDictionary[colorInput];
|
||||
if (color.hueRange) {return color.hueRange;}
|
||||
}
|
||||
}
|
||||
|
||||
return [0,360];
|
||||
|
||||
}
|
||||
|
||||
function getSaturationRange (hue) {
|
||||
return getColorInfo(hue).saturationRange;
|
||||
}
|
||||
|
||||
function getColorInfo (hue) {
|
||||
|
||||
// Maps red colors to make picking hue easier
|
||||
if (hue >= 334 && hue <= 360) {
|
||||
hue-= 360;
|
||||
}
|
||||
|
||||
for (var colorName in colorDictionary) {
|
||||
var color = colorDictionary[colorName];
|
||||
if (color.hueRange &&
|
||||
hue >= color.hueRange[0] &&
|
||||
hue <= color.hueRange[1]) {
|
||||
return colorDictionary[colorName];
|
||||
}
|
||||
} return 'Color not found';
|
||||
}
|
||||
|
||||
function randomWithin (range) {
|
||||
if (seed === null) {
|
||||
return Math.floor(range[0] + Math.random()*(range[1] + 1 - range[0]));
|
||||
} else {
|
||||
//Seeded random algorithm from http://indiegamr.com/generate-repeatable-random-numbers-in-js/
|
||||
var max = range[1] || 1;
|
||||
var min = range[0] || 0;
|
||||
seed = (seed * 9301 + 49297) % 233280;
|
||||
var rnd = seed / 233280.0;
|
||||
return Math.floor(min + rnd * (max - min));
|
||||
}
|
||||
}
|
||||
|
||||
function HSVtoHex (hsv){
|
||||
|
||||
var rgb = HSVtoRGB(hsv);
|
||||
|
||||
function componentToHex(c) {
|
||||
var hex = c.toString(16);
|
||||
return hex.length == 1 ? '0' + hex : hex;
|
||||
}
|
||||
|
||||
var hex = '#' + componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
|
||||
|
||||
return hex;
|
||||
|
||||
}
|
||||
|
||||
function defineColor (name, hueRange, lowerBounds) {
|
||||
|
||||
var sMin = lowerBounds[0][0],
|
||||
sMax = lowerBounds[lowerBounds.length - 1][0],
|
||||
|
||||
bMin = lowerBounds[lowerBounds.length - 1][1],
|
||||
bMax = lowerBounds[0][1];
|
||||
|
||||
colorDictionary[name] = {
|
||||
hueRange: hueRange,
|
||||
lowerBounds: lowerBounds,
|
||||
saturationRange: [sMin, sMax],
|
||||
brightnessRange: [bMin, bMax]
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function loadColorBounds () {
|
||||
|
||||
defineColor(
|
||||
'monochrome',
|
||||
null,
|
||||
[[0,0],[100,0]]
|
||||
);
|
||||
|
||||
defineColor(
|
||||
'red',
|
||||
[-26,18],
|
||||
[[20,100],[30,92],[40,89],[50,85],[60,78],[70,70],[80,60],[90,55],[100,50]]
|
||||
);
|
||||
|
||||
defineColor(
|
||||
'orange',
|
||||
[19,46],
|
||||
[[20,100],[30,93],[40,88],[50,86],[60,85],[70,70],[100,70]]
|
||||
);
|
||||
|
||||
defineColor(
|
||||
'yellow',
|
||||
[47,62],
|
||||
[[25,100],[40,94],[50,89],[60,86],[70,84],[80,82],[90,80],[100,75]]
|
||||
);
|
||||
|
||||
defineColor(
|
||||
'green',
|
||||
[63,178],
|
||||
[[30,100],[40,90],[50,85],[60,81],[70,74],[80,64],[90,50],[100,40]]
|
||||
);
|
||||
|
||||
defineColor(
|
||||
'blue',
|
||||
[179, 257],
|
||||
[[20,100],[30,86],[40,80],[50,74],[60,60],[70,52],[80,44],[90,39],[100,35]]
|
||||
);
|
||||
|
||||
defineColor(
|
||||
'purple',
|
||||
[258, 282],
|
||||
[[20,100],[30,87],[40,79],[50,70],[60,65],[70,59],[80,52],[90,45],[100,42]]
|
||||
);
|
||||
|
||||
defineColor(
|
||||
'pink',
|
||||
[283, 334],
|
||||
[[20,100],[30,90],[40,86],[60,84],[80,80],[90,75],[100,73]]
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function HSVtoRGB (hsv) {
|
||||
|
||||
// this doesn't work for the values of 0 and 360
|
||||
// here's the hacky fix
|
||||
var h = hsv[0];
|
||||
if (h === 0) {h = 1;}
|
||||
if (h === 360) {h = 359;}
|
||||
|
||||
// Rebase the h,s,v values
|
||||
h = h/360;
|
||||
var s = hsv[1]/100,
|
||||
v = hsv[2]/100;
|
||||
|
||||
var h_i = Math.floor(h*6),
|
||||
f = h * 6 - h_i,
|
||||
p = v * (1 - s),
|
||||
q = v * (1 - f*s),
|
||||
t = v * (1 - (1 - f)*s),
|
||||
r = 256,
|
||||
g = 256,
|
||||
b = 256;
|
||||
|
||||
switch(h_i) {
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
case 5: r = v; g = p; b = q; break;
|
||||
}
|
||||
|
||||
var result = [Math.floor(r*255), Math.floor(g*255), Math.floor(b*255)];
|
||||
return result;
|
||||
}
|
||||
|
||||
function HSVtoHSL (hsv) {
|
||||
var h = hsv[0],
|
||||
s = hsv[1]/100,
|
||||
v = hsv[2]/100,
|
||||
k = (2-s)*v;
|
||||
|
||||
return [
|
||||
h,
|
||||
Math.round(s*v / (k<1 ? k : 2-k) * 10000) / 100,
|
||||
k/2 * 100
|
||||
];
|
||||
}
|
||||
|
||||
function stringToInteger (string) {
|
||||
var total = 0
|
||||
for (var i = 0; i !== string.length; i++) {
|
||||
if (total >= Number.MAX_SAFE_INTEGER) break;
|
||||
total += string.charCodeAt(i)
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
return randomColor;
|
||||
}));
|
20
node_modules/neataptic/mkdocs/theme/js/articles/neuroevolution/events.js
generated
vendored
Normal file
20
node_modules/neataptic/mkdocs/theme/js/articles/neuroevolution/events.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
$(document).on('click', '.panel div.clickable', function (e) {
|
||||
var $this = $(this); //Heading
|
||||
var $panel = $this.parent('.panel');
|
||||
var $panel_body = $panel.children('.panel-body');
|
||||
var $display = $panel_body.css('display');
|
||||
|
||||
if ($display == 'block') {
|
||||
$panel_body.slideUp();
|
||||
} else if($display == 'none') {
|
||||
$panel_body.slideDown();
|
||||
}
|
||||
});
|
||||
|
||||
$(document).ready(function(e){
|
||||
var $classy = '.panel.autocollapse';
|
||||
|
||||
var $found = $($classy);
|
||||
$found.find('.panel-body').hide();
|
||||
$found.removeClass($classy);
|
||||
});
|
89
node_modules/neataptic/mkdocs/theme/js/articles/neuroevolution/graph.css
generated
vendored
Normal file
89
node_modules/neataptic/mkdocs/theme/js/articles/neuroevolution/graph.css
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
.node {
|
||||
cursor: move;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
.link {
|
||||
fill: none;
|
||||
stroke: #BDBDBD;
|
||||
stroke-width: 1.5px;
|
||||
opacity: 0.4;
|
||||
marker-end: url(#end-arrow);
|
||||
}
|
||||
.label {
|
||||
fill: #CCCCCC;
|
||||
font-size: 9px;
|
||||
text-anchor: middle;
|
||||
cursor: move;
|
||||
font-family: Arial;
|
||||
}
|
||||
#end-arrow{
|
||||
opacity: 0.4;
|
||||
}
|
||||
.INPUT{
|
||||
fill: #ff6666;
|
||||
stroke: #ff4d4d;
|
||||
}
|
||||
.OUTPUT{
|
||||
fill : #ff8c66;
|
||||
stroke: #ff794d;
|
||||
}
|
||||
.LOGISTIC{
|
||||
fill: #ffb366;
|
||||
stroke: #ffa64d;
|
||||
}
|
||||
.TANH{
|
||||
fill: #ffd966;
|
||||
stroke: #ffd24d;
|
||||
}
|
||||
.IDENTITY{
|
||||
fill: #ffff66;
|
||||
stroke: #ffff4d;
|
||||
}
|
||||
.STEP{
|
||||
fill: #d9ff66;
|
||||
stroke: #d2ff4d;
|
||||
}
|
||||
.RELU{
|
||||
fill: #b3ff66;
|
||||
stroke: #a6ff4d;
|
||||
}
|
||||
.SOFTSIGN{
|
||||
fill: #8cff66;
|
||||
stroke: #79ff4d;
|
||||
}
|
||||
.SINUSOID{
|
||||
fill: #66ff66;
|
||||
stroke: #4dff4d;
|
||||
}
|
||||
.GAUSSIAN{
|
||||
fill: #66ff8c;
|
||||
stroke: #4dff79;
|
||||
}
|
||||
.BENT_IDENTITY{
|
||||
fill: #66ffd9;
|
||||
stroke: #4dffd2;
|
||||
}
|
||||
.BIPOLAR{
|
||||
fill: #66d9ff;
|
||||
stroke: #4dd2ff;
|
||||
}
|
||||
.BIPOLAR_SIGMOID{
|
||||
fill: #66b3ff;
|
||||
stroke: #4da6ff;
|
||||
}
|
||||
.HARD_TANH{
|
||||
fill: #668cff;
|
||||
stroke: #4d79ff;
|
||||
}
|
||||
.ABSOLUTE{
|
||||
fill: #6666ff;
|
||||
stroke: #4d4dff;
|
||||
}
|
||||
.GATE{
|
||||
fill: #003300;
|
||||
stroke: #001a00;
|
||||
}
|
||||
.CONSTANT{
|
||||
fill: #ff00ff;
|
||||
stroke: #e600e6;
|
||||
}
|
122
node_modules/neataptic/mkdocs/theme/js/articles/neuroevolution/graph.js
generated
vendored
Normal file
122
node_modules/neataptic/mkdocs/theme/js/articles/neuroevolution/graph.js
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
var NODE_RADIUS = 7;
|
||||
var REPEL_FORCE = 0;
|
||||
var LINK_DISTANCE = 100;
|
||||
|
||||
var drawGraph = function(graph, panel, width, height) {
|
||||
var d3cola = cola.d3adaptor()
|
||||
.avoidOverlaps(true)
|
||||
.size([width, height]);
|
||||
|
||||
var svg = d3.select(panel);
|
||||
|
||||
d3.selectAll(panel + "> *").remove();
|
||||
|
||||
// define arrow markers for graph links
|
||||
svg.append('svg:defs').append('svg:marker')
|
||||
.attr('id', 'end-arrow')
|
||||
.attr('viewBox', '0 -5 10 10')
|
||||
.attr('refX', 6)
|
||||
.attr('markerWidth', 4)
|
||||
.attr('markerHeight', 4)
|
||||
.attr('orient', 'auto')
|
||||
.append('svg:path')
|
||||
.attr('d', 'M0,-5L10,0L0,5')
|
||||
|
||||
graph.nodes.forEach(function (v) { v.height = v.width = 2 * NODE_RADIUS; });
|
||||
|
||||
d3cola
|
||||
.nodes(graph.nodes)
|
||||
.links(graph.links)
|
||||
//.constraints(graph.constraints)
|
||||
.symmetricDiffLinkLengths(REPEL_FORCE)
|
||||
.linkDistance(LINK_DISTANCE)
|
||||
.start(10, 15, 20);
|
||||
|
||||
var path = svg.selectAll(".link")
|
||||
.data(graph.links)
|
||||
.enter().append('svg:path')
|
||||
.attr('class', 'link')
|
||||
|
||||
path.append("title")
|
||||
.text(function (d) {
|
||||
var text = "";
|
||||
text += "Weight: " + Math.round(d.weight*1000)/1000 + "\n";;
|
||||
text += "Source: " + d.source.id + "\n";;
|
||||
text += "Target: " + d.target.id;
|
||||
return text;
|
||||
});
|
||||
|
||||
var node = svg.selectAll(".node")
|
||||
.data(graph.nodes)
|
||||
.enter().append("circle")
|
||||
.attr("class", function(d){
|
||||
return "node " + d.name;
|
||||
})
|
||||
.attr("r", function(d) { return NODE_RADIUS; })
|
||||
|
||||
.call(d3cola.drag);
|
||||
|
||||
node.append("title")
|
||||
.text(function (d){
|
||||
var text = "";
|
||||
text += "Activation: " + Math.round(d.activation*1000)/1000 + "\n";
|
||||
text += "Bias: " + Math.round(d.bias*1000)/1000 + "\n";
|
||||
text += "Position: " + d.id;
|
||||
return text;
|
||||
});
|
||||
|
||||
var label = svg.selectAll(".label")
|
||||
.data(graph.nodes)
|
||||
.enter().append("text")
|
||||
.attr("class", "label")
|
||||
.text(function (d){return '(' + d.index + ') ' + d.name; })
|
||||
.call(d3cola.drag)
|
||||
|
||||
d3cola.on("tick", function () {
|
||||
// draw directed edges with proper padding from node centers
|
||||
path.attr('d', function (d) {
|
||||
var deltaX = d.target.x - d.source.x,
|
||||
deltaY = d.target.y - d.source.y,
|
||||
dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
|
||||
normX = deltaX / dist,
|
||||
normY = deltaY / dist;
|
||||
|
||||
if(isNaN(normX)) normX = 0;
|
||||
if(isNaN(normY)) normY = 0;
|
||||
|
||||
sourcePadding = NODE_RADIUS,
|
||||
targetPadding = NODE_RADIUS + 2,
|
||||
sourceX = d.source.x + (sourcePadding * normX),
|
||||
sourceY = d.source.y + (sourcePadding * normY),
|
||||
targetX = d.target.x - (targetPadding * normX),
|
||||
targetY = d.target.y - (targetPadding * normY);
|
||||
|
||||
// Defaults for normal edge.
|
||||
drx = 0,
|
||||
dry = 0,
|
||||
xRotation = 0, // degrees
|
||||
largeArc = 0, // 1 or 0
|
||||
sweep = 1; // 1 or 0
|
||||
|
||||
// Self edge.
|
||||
if (d.source.x === d.target.x && d.source.y === d.target.y) {
|
||||
drx = dist;
|
||||
dry = dist;
|
||||
xRotation = -45;
|
||||
largeArc = 1;
|
||||
drx = 20;
|
||||
dry = 20;
|
||||
targetX = targetX + 1;
|
||||
targetY = targetY + 1;
|
||||
}
|
||||
return 'M' + sourceX + ',' + sourceY + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + targetX + ',' + targetY;
|
||||
});
|
||||
|
||||
node.attr("cx", function (d) { return d.x; })
|
||||
.attr("cy", function (d) { return d.y; })
|
||||
|
||||
label
|
||||
.attr("x", function (d) { return d.x + 10; })
|
||||
.attr("y", function (d) { return d.y - 10; });
|
||||
});
|
||||
};
|
38
node_modules/neataptic/mkdocs/theme/js/articles/neuroevolution/import.js
generated
vendored
Normal file
38
node_modules/neataptic/mkdocs/theme/js/articles/neuroevolution/import.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
var scripts = [
|
||||
{ type: 'script', url: "https://wagenaartje.github.io/neataptic/cdn/1.2.22/neataptic.js"},
|
||||
{ type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.js"},
|
||||
{ type: 'script', url: "../../js/articles/neuroevolution/webcola.js"},
|
||||
{ type: 'script', url: "../../js/articles/neuroevolution/events.js"},
|
||||
{ type: 'script', url: "../../js/articles/neuroevolution/graph.js"},
|
||||
{ type: 'script', url: "../../js/articles/neuroevolution/neural.js"},
|
||||
{ type: 'css', url: "../../js/articles/neuroevolution/graph.css"}
|
||||
];
|
||||
|
||||
/** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/
|
||||
function require(list) {
|
||||
function loadScript(link) {
|
||||
return new Promise(function(fulfill, reject) {
|
||||
if(link.type == 'script'){
|
||||
var script = document.createElement("script");
|
||||
script.addEventListener("load", fulfill);
|
||||
script.src = link.url;
|
||||
document.head.appendChild(script);
|
||||
} else if(link.type == 'css'){
|
||||
var stylesheet = document.createElement('link');
|
||||
stylesheet.addEventListener("load", fulfill);
|
||||
stylesheet.rel = 'stylesheet';
|
||||
stylesheet.type = 'text/css';
|
||||
stylesheet.href = link.url;
|
||||
stylesheet.media = "screen,print";
|
||||
document.head.appendChild(stylesheet);
|
||||
}
|
||||
});
|
||||
}
|
||||
loadScript(list.shift()).then(function() {
|
||||
if (list.length > 0) {
|
||||
require(list);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
require(scripts);
|
165
node_modules/neataptic/mkdocs/theme/js/articles/neuroevolution/neural.js
generated
vendored
Normal file
165
node_modules/neataptic/mkdocs/theme/js/articles/neuroevolution/neural.js
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
var Network = neataptic.Network;
|
||||
var Methods = neataptic.Methods;
|
||||
var Neat = neataptic.Neat;
|
||||
var Config = neataptic.Config;
|
||||
|
||||
Config.warnings = false;
|
||||
|
||||
var examples = [
|
||||
{
|
||||
set: [
|
||||
{ input: [0.0], output: [0.2] },
|
||||
{ input: [0.2], output: [0.4] },
|
||||
{ input: [0.4], output: [0.6] },
|
||||
{ input: [0.6], output: [0.8] },
|
||||
{ input: [0.8], output: [1.0] },
|
||||
{ input: [1.0], output: [0.8] },
|
||||
{ input: [0.8], output: [0.6] },
|
||||
{ input: [0.6], output: [0.4] },
|
||||
{ input: [0.4], output: [0.2] },
|
||||
{ input: [0.2], output: [0.0] }
|
||||
],
|
||||
options: {
|
||||
mutation: Methods.Mutation.ALL,
|
||||
equal: true,
|
||||
elitism: 5,
|
||||
iterations: 1500,
|
||||
clear: true,
|
||||
error: 0.003
|
||||
}
|
||||
},
|
||||
{
|
||||
set: [
|
||||
{ input: [0], output: [0] },
|
||||
{ input: [0], output: [0] },
|
||||
{ input: [0], output: [0] },
|
||||
{ input: [0], output: [0] },
|
||||
{ input: [0], output: [0] },
|
||||
{ input: [0], output: [0] },
|
||||
{ input: [0], output: [0] },
|
||||
{ input: [0], output: [0] },
|
||||
{ input: [0], output: [0] },
|
||||
{ input: [0], output: [1] }
|
||||
],
|
||||
options: {
|
||||
mutation: Methods.Mutation.ALL,
|
||||
equal: true,
|
||||
elitism: 5,
|
||||
iterations: 1500,
|
||||
clear: true,
|
||||
error: 0.003
|
||||
}
|
||||
},
|
||||
{
|
||||
set: [
|
||||
{ input: [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [1] }, // A
|
||||
{ input: [0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // B
|
||||
{ input: [0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // C
|
||||
{ input: [0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // D
|
||||
{ input: [0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [1] }, // E
|
||||
{ input: [0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // F
|
||||
{ input: [0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // G
|
||||
{ input: [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // H
|
||||
{ input: [0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [1] }, // I
|
||||
{ input: [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // J
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // K
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // L
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // M
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // N
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0], output: [1] }, // O
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0], output: [0] }, // P
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0], output: [0] }, // Q
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0], output: [0] }, // R
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], output: [0] }, // S
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0], output: [0] }, // T
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0], output: [1] }, // U
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0], output: [0] }, // V
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0], output: [0] }, // W
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0], output: [0] }, // X
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0], output: [0] }, // Y
|
||||
{ input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], output: [0] }, // Z
|
||||
],
|
||||
options: {
|
||||
mutation: Methods.Mutation.FFW,
|
||||
equal: true,
|
||||
elitism: 5,
|
||||
iterations: 1500,
|
||||
clear: true,
|
||||
error: 0.001
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
function showModal(id, type){
|
||||
if(type == 0){
|
||||
var set = examples[id-1].set;
|
||||
var s = '';
|
||||
for(var i = 0; i < set.length; i++){
|
||||
var input = JSON.stringify(set[i].input);
|
||||
var output = JSON.stringify(set[i].output);
|
||||
s += (`Input: ${input}, output: ${output}\n`);
|
||||
}
|
||||
$('.modalcontent').html(s);
|
||||
$('.modal-title').text('Training set');
|
||||
} else if(type == 1){
|
||||
var options = examples[id-1].options;
|
||||
var keys = Object.keys(options);
|
||||
var s = '';
|
||||
for(var i = 0; i < keys.length; i++){
|
||||
if(keys[i] == 'mutation'){
|
||||
var value = '';
|
||||
for(var j = 0; j < options[keys[i]].length; j++){
|
||||
value += options[keys[i]][j].name + ', ';
|
||||
}
|
||||
} else {
|
||||
var value = options[keys[i]];
|
||||
}
|
||||
s += (`${keys[i]}: ${value}\n`);
|
||||
}
|
||||
$('.modalcontent').html(s);
|
||||
$('.modal-title').text('Evolve settings');
|
||||
} else if(type == 2){
|
||||
$('.modalcontent').html(examples[id-1].output);
|
||||
$('.modal-title').text('Output');
|
||||
}
|
||||
$('#modal').modal();
|
||||
}
|
||||
|
||||
function run(id){
|
||||
var set = examples[id-1].set;
|
||||
var options = examples[id-1].options;
|
||||
|
||||
$('.status' + id).show();
|
||||
$('.status' + id).text('Running...');
|
||||
setTimeout(freeze, 10, id, set, options)
|
||||
}
|
||||
|
||||
function freeze(id, set, options){
|
||||
var network = new Network(set[0].input.length, set[0].output.length);
|
||||
var results = network.evolve(set, options);
|
||||
$('.example' + id).width('100%');
|
||||
$('.example' + id).height(400);
|
||||
$('.example' + id).show();
|
||||
|
||||
var width = $('.example' + id).width();
|
||||
drawGraph(network.graph(width, 400), '.example' + id, width, 400);
|
||||
|
||||
var s = '';
|
||||
for(var i = 0; i < set.length; i++){
|
||||
var input = JSON.stringify(set[i].input);
|
||||
var targetoutput = JSON.stringify(set[i].output);
|
||||
var output = network.activate(set[i].input);
|
||||
|
||||
for(var j = 0; j < output.length; j++){
|
||||
output[j] = Math.round(output[j] * 1000) / 1000;
|
||||
}
|
||||
|
||||
output = JSON.stringify(output);
|
||||
s += (`Input: ${input}, wanted output: ${targetoutput}, actual: ${output}\n`);
|
||||
}
|
||||
examples[id-1].output = s;
|
||||
|
||||
$('.status' + id).text('Show outputs');
|
||||
$('.error' + id).text('Error ' + Math.round(-results.error * 1000) / 1000);
|
||||
$('.error' + id).show();
|
||||
}
|
3
node_modules/neataptic/mkdocs/theme/js/articles/neuroevolution/webcola.js
generated
vendored
Normal file
3
node_modules/neataptic/mkdocs/theme/js/articles/neuroevolution/webcola.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
7
node_modules/neataptic/mkdocs/theme/js/articles/playground/events.js
generated
vendored
Normal file
7
node_modules/neataptic/mkdocs/theme/js/articles/playground/events.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
$( document ).ready(function() {
|
||||
$( ".start" ).click(function() {
|
||||
$( ".start" ).html('<span class="glyphicon glyphicon-dashboard" aria-hidden="true"></span> Running...');
|
||||
newNeat();
|
||||
loop();
|
||||
});
|
||||
});
|
92
node_modules/neataptic/mkdocs/theme/js/articles/playground/extra.css
generated
vendored
Normal file
92
node_modules/neataptic/mkdocs/theme/js/articles/playground/extra.css
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
.btn-group, .input-group, pre{
|
||||
margin-top: 10px;
|
||||
}
|
||||
.node {
|
||||
cursor: move;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
.link {
|
||||
fill: none;
|
||||
stroke: #BDBDBD;
|
||||
stroke-width: 1.5px;
|
||||
opacity: 0.4;
|
||||
marker-end: url(#end-arrow);
|
||||
}
|
||||
.label {
|
||||
fill: #CCCCCC;
|
||||
font-size: 9px;
|
||||
text-anchor: middle;
|
||||
cursor: move;
|
||||
font-family: Arial;
|
||||
}
|
||||
#end-arrow{
|
||||
opacity: 0.4;
|
||||
}
|
||||
.INPUT{
|
||||
fill: #ff6666;
|
||||
stroke: #ff4d4d;
|
||||
}
|
||||
.OUTPUT{
|
||||
fill : #ff8c66;
|
||||
stroke: #ff794d;
|
||||
}
|
||||
.LOGISTIC{
|
||||
fill: #ffb366;
|
||||
stroke: #ffa64d;
|
||||
}
|
||||
.TANH{
|
||||
fill: #ffd966;
|
||||
stroke: #ffd24d;
|
||||
}
|
||||
.IDENTITY{
|
||||
fill: #ffff66;
|
||||
stroke: #ffff4d;
|
||||
}
|
||||
.STEP{
|
||||
fill: #d9ff66;
|
||||
stroke: #d2ff4d;
|
||||
}
|
||||
.RELU{
|
||||
fill: #b3ff66;
|
||||
stroke: #a6ff4d;
|
||||
}
|
||||
.SOFTSIGN{
|
||||
fill: #8cff66;
|
||||
stroke: #79ff4d;
|
||||
}
|
||||
.SINUSOID{
|
||||
fill: #66ff66;
|
||||
stroke: #4dff4d;
|
||||
}
|
||||
.GAUSSIAN{
|
||||
fill: #66ff8c;
|
||||
stroke: #4dff79;
|
||||
}
|
||||
.BENT_IDENTITY{
|
||||
fill: #66ffd9;
|
||||
stroke: #4dffd2;
|
||||
}
|
||||
.BIPOLAR{
|
||||
fill: #66d9ff;
|
||||
stroke: #4dd2ff;
|
||||
}
|
||||
.BIPOLAR_SIGMOID{
|
||||
fill: #66b3ff;
|
||||
stroke: #4da6ff;
|
||||
}
|
||||
.HARD_TANH{
|
||||
fill: #668cff;
|
||||
stroke: #4d79ff;
|
||||
}
|
||||
.ABSOLUTE{
|
||||
fill: #6666ff;
|
||||
stroke: #4d4dff;
|
||||
}
|
||||
.GATE{
|
||||
fill: #003300;
|
||||
stroke: #001a00;
|
||||
}
|
||||
.CONSTANT{
|
||||
fill: #ff00ff;
|
||||
stroke: #e600e6;
|
||||
}
|
128
node_modules/neataptic/mkdocs/theme/js/articles/playground/graph.js
generated
vendored
Normal file
128
node_modules/neataptic/mkdocs/theme/js/articles/playground/graph.js
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
var NODE_RADIUS = 7;
|
||||
var GATE_RADIUS = 2;
|
||||
var REPEL_FORCE = 0;
|
||||
var LINK_DISTANCE = 100;
|
||||
|
||||
var WIDTH = 500;
|
||||
var HEIGHT = 600;
|
||||
|
||||
var d3cola = cola.d3adaptor()
|
||||
.avoidOverlaps(true)
|
||||
.size([WIDTH, HEIGHT]);
|
||||
|
||||
var drawGraph = function(graph, panel) {
|
||||
var svg = d3.select(panel);
|
||||
|
||||
d3.selectAll(panel + "> *").remove();
|
||||
|
||||
// define arrow markers for graph links
|
||||
svg.append('svg:defs').append('svg:marker')
|
||||
.attr('id', 'end-arrow')
|
||||
.attr('viewBox', '0 -5 10 10')
|
||||
.attr('refX', 6)
|
||||
.attr('markerWidth', 4)
|
||||
.attr('markerHeight', 4)
|
||||
.attr('orient', 'auto')
|
||||
.append('svg:path')
|
||||
.attr('d', 'M0,-5L10,0L0,5')
|
||||
|
||||
graph.nodes.forEach(function(v){
|
||||
v.height = v.width = 2 * (v.name == 'GATE' ? GATE_RADIUS : NODE_RADIUS); }
|
||||
);
|
||||
|
||||
d3cola
|
||||
.nodes(graph.nodes)
|
||||
.links(graph.links)
|
||||
.constraints(graph.constraints)
|
||||
.symmetricDiffLinkLengths(REPEL_FORCE)
|
||||
.linkDistance(LINK_DISTANCE)
|
||||
.start(10, 15, 20);
|
||||
|
||||
var path = svg.selectAll(".link")
|
||||
.data(graph.links)
|
||||
.enter().append('svg:path')
|
||||
.attr('class', 'link')
|
||||
|
||||
path.append("title")
|
||||
.text(function (d) {
|
||||
var text = "";
|
||||
text += "Weight: " + Math.round(d.weight*1000)/1000 + "\n";;
|
||||
text += "Source: " + d.source.id + "\n";;
|
||||
text += "Target: " + d.target.id;
|
||||
return text;
|
||||
});
|
||||
|
||||
var node = svg.selectAll(".node")
|
||||
.data(graph.nodes)
|
||||
.enter().append("circle")
|
||||
.attr("class", function(d){
|
||||
return "node " + d.name;
|
||||
})
|
||||
.attr("r", function(d) { return d.name == 'GATE' ? GATE_RADIUS : NODE_RADIUS; })
|
||||
|
||||
.call(d3cola.drag);
|
||||
|
||||
node.append("title")
|
||||
.text(function (d){
|
||||
var text = "";
|
||||
text += "Activation: " + Math.round(d.activation*1000)/1000 + "\n";
|
||||
text += "Bias: " + Math.round(d.bias*1000)/1000 + "\n";
|
||||
text += "Position: " + d.id;
|
||||
return text;
|
||||
});
|
||||
|
||||
var label = svg.selectAll(".label")
|
||||
.data(graph.nodes)
|
||||
.enter().append("text")
|
||||
.attr("class", "label")
|
||||
.text(function (d){return '(' + d.index + ') ' + d.name; })
|
||||
.call(d3cola.drag)
|
||||
|
||||
d3cola.on("tick", function () {
|
||||
// draw directed edges with proper padding from node centers
|
||||
path.attr('d', function (d) {
|
||||
var deltaX = d.target.x - d.source.x,
|
||||
deltaY = d.target.y - d.source.y,
|
||||
dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
|
||||
normX = deltaX / dist,
|
||||
normY = deltaY / dist;
|
||||
|
||||
if(isNaN(normX)) normX = 0;
|
||||
if(isNaN(normY)) normY = 0;
|
||||
|
||||
sourcePadding = d.source.width / 2,
|
||||
targetPadding = d.target.width / 2 + 2,
|
||||
sourceX = d.source.x + (sourcePadding * normX),
|
||||
sourceY = d.source.y + (sourcePadding * normY),
|
||||
targetX = d.target.x - (targetPadding * normX),
|
||||
targetY = d.target.y - (targetPadding * normY);
|
||||
|
||||
// Defaults for normal edge.
|
||||
drx = 0,
|
||||
dry = 0,
|
||||
xRotation = 0, // degrees
|
||||
largeArc = 0, // 1 or 0
|
||||
sweep = 1; // 1 or 0
|
||||
|
||||
// Self edge.
|
||||
if (d.source.x === d.target.x && d.source.y === d.target.y) {
|
||||
drx = dist;
|
||||
dry = dist;
|
||||
xRotation = -45;
|
||||
largeArc = 1;
|
||||
drx = 20;
|
||||
dry = 20;
|
||||
targetX = targetX + 1;
|
||||
targetY = targetY + 1;
|
||||
}
|
||||
return 'M' + sourceX + ',' + sourceY + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + targetX + ',' + targetY;
|
||||
});
|
||||
|
||||
node.attr("cx", function (d) { return d.x; })
|
||||
.attr("cy", function (d) { return d.y; })
|
||||
|
||||
label
|
||||
.attr("x", function (d) { return d.x + 10; })
|
||||
.attr("y", function (d) { return d.y - 10; });
|
||||
});
|
||||
};
|
38
node_modules/neataptic/mkdocs/theme/js/articles/playground/import.js
generated
vendored
Normal file
38
node_modules/neataptic/mkdocs/theme/js/articles/playground/import.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
var scripts = [
|
||||
{ type: 'script', url: "https://wagenaartje.github.io/neataptic/cdn/1.3.4/neataptic.js"},
|
||||
{ type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.js"},
|
||||
{ type: 'script', url: "../../js/articles/neuroevolution/webcola.js"},
|
||||
{ type: 'script', url: "../../js/articles/playground/events.js"},
|
||||
{ type: 'script', url: "../../js/articles/playground/graph.js"},
|
||||
{ type: 'script', url: "../../js/articles/playground/neural.js"},
|
||||
{ type: 'css', url: "../../js/articles/playground/extra.css"}
|
||||
];
|
||||
|
||||
/** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/
|
||||
function require(list) {
|
||||
function loadScript(link) {
|
||||
return new Promise(function(fulfill, reject) {
|
||||
if(link.type == 'script'){
|
||||
var script = document.createElement("script");
|
||||
script.addEventListener("load", fulfill);
|
||||
script.src = link.url;
|
||||
document.head.appendChild(script);
|
||||
} else if(link.type == 'css'){
|
||||
var stylesheet = document.createElement('link');
|
||||
stylesheet.addEventListener("load", fulfill);
|
||||
stylesheet.rel = 'stylesheet';
|
||||
stylesheet.type = 'text/css';
|
||||
stylesheet.href = link.url;
|
||||
stylesheet.media = "screen,print";
|
||||
document.head.appendChild(stylesheet);
|
||||
}
|
||||
});
|
||||
}
|
||||
loadScript(list.shift()).then(function() {
|
||||
if (list.length > 0) {
|
||||
require(list);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
require(scripts);
|
28
node_modules/neataptic/mkdocs/theme/js/articles/playground/neural.js
generated
vendored
Normal file
28
node_modules/neataptic/mkdocs/theme/js/articles/playground/neural.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
var { Network, methods, architect } = neataptic;
|
||||
|
||||
var network = new Network(2, 1);
|
||||
$(document).ready(function () {
|
||||
refresh();
|
||||
activate();
|
||||
});
|
||||
|
||||
function mutate (method) {
|
||||
network.mutate(method);
|
||||
refresh();
|
||||
activate();
|
||||
}
|
||||
|
||||
function activate () {
|
||||
var in1 = $('.input1').val();
|
||||
var in2 = $('.input2').val();
|
||||
|
||||
if(in1 > 1 || in1 < 0 || in2 > 1 || in2 < 0){
|
||||
alert('Inputs must be between 0 and 1!');
|
||||
}
|
||||
|
||||
var output = network.activate([in1, in2]);
|
||||
$('.output').text(output);
|
||||
}
|
||||
function refresh(){
|
||||
drawGraph(network.graph($('.draw').width() / 1.4, $('.draw').height() / 1.4), '.draw');
|
||||
}
|
99
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/field.js
generated
vendored
Normal file
99
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/field.js
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/* Global vars */
|
||||
var players = [];
|
||||
var walker = new Walker();
|
||||
var iteration = 0;
|
||||
var highestScore = 0;
|
||||
|
||||
/** Setup the canvas */
|
||||
function setup(){
|
||||
var canvas = createCanvas(WIDTH, HEIGHT);
|
||||
canvas.parent('field');
|
||||
initNeat();
|
||||
|
||||
// Do some initial mutation
|
||||
if(!USE_TRAINED_POP){
|
||||
for(var i = 0; i < 1; i++) neat.mutate();
|
||||
}
|
||||
|
||||
startEvaluation();
|
||||
}
|
||||
|
||||
function draw(){
|
||||
clear();
|
||||
squareGrid();
|
||||
|
||||
// Check if evaluation is done
|
||||
if(iteration == ITERATIONS){
|
||||
endEvaluation();
|
||||
iteration = 0;
|
||||
}
|
||||
|
||||
// Update and visualise players
|
||||
for(var i = players.length - 1; i >= 0; i--){
|
||||
var player = players[i];
|
||||
|
||||
// Some players are eaten during the iteration
|
||||
player.update();
|
||||
player.show();
|
||||
}
|
||||
|
||||
walker.update();
|
||||
walker.show();
|
||||
|
||||
iteration++;
|
||||
}
|
||||
|
||||
/** Draw a square grid with grey lines */
|
||||
function squareGrid(){
|
||||
stroke(204, 204, 204, 160);
|
||||
strokeWeight(1);
|
||||
fill(255);
|
||||
for(var x = 0; x < WIDTH/40; x++){
|
||||
line(x * 40, 0, x * 40, HEIGHT);
|
||||
}
|
||||
for(var y = 0; y < HEIGHT/40; y++){
|
||||
line(0, y * 40, WIDTH, y * 40);
|
||||
}
|
||||
noStroke();
|
||||
}
|
||||
|
||||
/** Calculate distance between two points */
|
||||
function distance(x1, y1, x2, y2){
|
||||
var dx = x1 - x2;
|
||||
var dy = y1 - y2;
|
||||
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
/** Get a relative color between red and green */
|
||||
var activationColor = function(value, max){
|
||||
var power = 1 - Math.min(value/max, 1);
|
||||
var color = [255, 255, 0]
|
||||
|
||||
if(power < 0.5){
|
||||
color[0] = 2 * power * 255;
|
||||
} else {
|
||||
color[1] = (1.0 - 2 * (power - 0.5)) * 255;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
/** Get the angle from one point to another */
|
||||
function angleToPoint(x1, y1, x2, y2){
|
||||
d = distance(x1, y1, x2, y2);
|
||||
dx = (x2-x1) / d;
|
||||
dy = (y2-y1) / d;
|
||||
|
||||
a = Math.acos(dx);
|
||||
a = dy < 0 ? 2 * Math.PI - a : a;
|
||||
return a;
|
||||
}
|
||||
|
||||
/** Set the walker to a new location */
|
||||
function mouseClicked(){
|
||||
if(mouseX >= 0 && mouseX <= WIDTH && mouseY >= 0 && mouseY <= HEIGHT){
|
||||
walker.x = mouseX;
|
||||
walker.y = mouseY;
|
||||
}
|
||||
}
|
158
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/graph.js
generated
vendored
Normal file
158
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/graph.js
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
var colorTable = [
|
||||
'#2124FF', // input
|
||||
'#FF2718', // output
|
||||
'#1F22C1', // logistic sigmoid
|
||||
'#EE8A2A', // tanh
|
||||
'#B17516', // identity
|
||||
'#B1B0AA', // hlim
|
||||
'#2CB11F', // relu
|
||||
'#C5B12C', // softsign
|
||||
'#E685E7', // sinusoid
|
||||
'#257580', // gaussian
|
||||
'#B0484B', // softplus
|
||||
'#4CB148', // bent_identity
|
||||
'#000000' // GATE
|
||||
];
|
||||
|
||||
var NODE_RADIUS = 7;
|
||||
var REPEL_FORCE = 10;
|
||||
var LINK_DISTANCE = 100;
|
||||
|
||||
var drawGraph = function(graph, panel, activation) {
|
||||
var d3cola = cola.d3adaptor()
|
||||
.avoidOverlaps(true)
|
||||
.size([$('.best').width(), $('.best').height()]);
|
||||
|
||||
var svg = d3.select(panel);
|
||||
|
||||
d3.selectAll(panel + "> *").remove();
|
||||
|
||||
// define arrow markers for graph links
|
||||
svg.append('svg:defs').append('svg:marker')
|
||||
.attr('id', 'end-arrow')
|
||||
.attr('viewBox', '0 -5 10 10')
|
||||
.attr('refX', 6)
|
||||
.attr('markerWidth', 5)
|
||||
.attr('markerHeight', 5)
|
||||
.attr('orient', 'auto')
|
||||
.append('svg:path')
|
||||
.attr('d', 'M0,-5L10,0L0,5')
|
||||
.attr('fill', '#000');
|
||||
|
||||
graph.nodes.forEach(function (v) { v.height = v.width = 2 * NODE_RADIUS; });
|
||||
|
||||
d3cola
|
||||
.nodes(graph.nodes)
|
||||
.links(graph.links)
|
||||
.symmetricDiffLinkLengths(REPEL_FORCE)
|
||||
.linkDistance(LINK_DISTANCE)
|
||||
.start(10, 15, 20);
|
||||
|
||||
var path = svg.selectAll(".link")
|
||||
.data(graph.links)
|
||||
.enter().append('svg:path')
|
||||
.attr('class', 'link')
|
||||
.style("stroke-width", function (d) {
|
||||
if(activation){
|
||||
return 1.5;
|
||||
} else {
|
||||
return 1.5 + Math.sqrt(d.weight * 5);
|
||||
}
|
||||
})
|
||||
.style("stroke", function (d) {
|
||||
if(activation){
|
||||
return activationColor(d.source.activation * d.weight, graph.main.maxActivation * graph.main.maxWeight);
|
||||
} else if(d.gate){
|
||||
if(d.source.activation){
|
||||
return activationColor(d.source.activation, graph.main.maxActivation);
|
||||
} else{
|
||||
return 'rgb(255,0,0)';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var node = svg.selectAll(".node")
|
||||
.data(graph.nodes)
|
||||
.enter().append("circle")
|
||||
.attr("class", "node")
|
||||
.attr("r", function(d) { return NODE_RADIUS; })
|
||||
.style("fill", function (d) {
|
||||
if(activation){
|
||||
return activationColor(d.activation, graph.main.maxActivation);
|
||||
} else {
|
||||
return colorTable[d.type];
|
||||
}
|
||||
|
||||
})
|
||||
.call(d3cola.drag);
|
||||
|
||||
node.append("title")
|
||||
.text(function (d) { return d.id; });
|
||||
|
||||
var label = svg.selectAll(".label")
|
||||
.data(graph.nodes)
|
||||
.enter().append("text")
|
||||
.attr("class", "label")
|
||||
.text(function (d) { return '(' + d.index + ') ' + d.name; })
|
||||
.call(d3cola.drag)
|
||||
|
||||
d3cola.on("tick", function () {
|
||||
// draw directed edges with proper padding from node centers
|
||||
path.attr('d', function (d) {
|
||||
var deltaX = d.target.x - d.source.x,
|
||||
deltaY = d.target.y - d.source.y,
|
||||
dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
|
||||
normX = deltaX / dist,
|
||||
normY = deltaY / dist;
|
||||
|
||||
if(isNaN(normX)) normX = 0;
|
||||
if(isNaN(normY)) normY = 0;
|
||||
|
||||
sourcePadding = NODE_RADIUS,
|
||||
targetPadding = NODE_RADIUS + 2,
|
||||
sourceX = d.source.x + (sourcePadding * normX),
|
||||
sourceY = d.source.y + (sourcePadding * normY),
|
||||
targetX = d.target.x - (targetPadding * normX),
|
||||
targetY = d.target.y - (targetPadding * normY);
|
||||
|
||||
// Defaults for normal edge.
|
||||
drx = 0,
|
||||
dry = 0,
|
||||
xRotation = 0, // degrees
|
||||
largeArc = 0, // 1 or 0
|
||||
sweep = 1; // 1 or 0
|
||||
|
||||
// Self edge.
|
||||
if (d.source.x === d.target.x && d.source.y === d.target.y) {
|
||||
drx = dist;
|
||||
dry = dist;
|
||||
// Fiddle with this angle to get loop oriented.
|
||||
xRotation = -45;
|
||||
|
||||
// Needs to be 1.
|
||||
largeArc = 1;
|
||||
|
||||
// Change sweep to change orientation of loop.
|
||||
//sweep = 0;
|
||||
|
||||
// Make drx and dry different to get an ellipse
|
||||
// instead of a circle.
|
||||
drx = 20;
|
||||
dry = 20;
|
||||
|
||||
// For whatever reason the arc collapses to a point if the beginning
|
||||
// and ending points of the arc are the same, so kludge it.
|
||||
targetX = targetX + 1;
|
||||
targetY = targetY + 1;
|
||||
}
|
||||
return 'M' + sourceX + ',' + sourceY + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + targetX + ',' + targetY;
|
||||
});
|
||||
|
||||
node.attr("cx", function (d) { return d.x; })
|
||||
.attr("cy", function (d) { return d.y; })
|
||||
|
||||
label
|
||||
.attr("x", function (d) { return d.x + 10; })
|
||||
.attr("y", function (d) { return d.y - 10; });
|
||||
});
|
||||
};
|
37
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/import.js
generated
vendored
Normal file
37
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/import.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
var scripts = [
|
||||
{ type: 'script', url: "https://cdn.rawgit.com/wagenaartje/neataptic/a7610e38/dist/neataptic.js"},
|
||||
{ type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/p5.js"},
|
||||
{ type: 'script', url: "../../js/articles/target-seekingai/main.js"},
|
||||
{ type: 'script', url: "../../js/articles/target-seekingai/population.js"},
|
||||
{ type: 'script', url: "../../js/articles/target-seekingai/player.js"},
|
||||
{ type: 'script', url: "../../js/articles/target-seekingai/walker.js"},
|
||||
{ type: 'script', url: "../../js/articles/target-seekingai/field.js"}
|
||||
];
|
||||
|
||||
/** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/
|
||||
function require(list) {
|
||||
function loadScript(link) {
|
||||
return new Promise(function(fulfill, reject) {
|
||||
if(link.type == 'script'){
|
||||
var script = document.createElement("script");
|
||||
script.addEventListener("load", fulfill);
|
||||
script.src = link.url;
|
||||
document.head.appendChild(script);
|
||||
} else if(link.type == 'css'){
|
||||
var stylesheet = document.createElement('link');
|
||||
stylesheet.rel = 'stylesheet';
|
||||
stylesheet.type = 'text/css';
|
||||
stylesheet.href = link.url;
|
||||
stylesheet.media = "screen,print";
|
||||
document.head.appendChild(stylesheet);
|
||||
}
|
||||
});
|
||||
}
|
||||
loadScript(list.shift()).then(function() {
|
||||
if (list.length > 0) {
|
||||
require(list);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
require(scripts);
|
108
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/main.js
generated
vendored
Normal file
108
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/main.js
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/** Rename vars */
|
||||
var Neat = neataptic.Neat;
|
||||
var Methods = neataptic.Methods;
|
||||
var Config = neataptic.Config;
|
||||
var Architect = neataptic.Architect;
|
||||
|
||||
/** Turn off warnings */
|
||||
Config.warnings = false;
|
||||
|
||||
/** Settings */
|
||||
var WIDTH = $('#field').width();
|
||||
var HEIGHT = 500;
|
||||
var MAX_SPEED = 5;
|
||||
var START_X = WIDTH/2;
|
||||
var START_Y = HEIGHT/2;
|
||||
var SCORE_RADIUS = 100;
|
||||
|
||||
// GA settings
|
||||
var PLAYER_AMOUNT = Math.round(2.3e-4 * WIDTH * HEIGHT);
|
||||
var ITERATIONS = 10e6; // should be ~250 for real use
|
||||
var MUTATION_RATE = 0.3;
|
||||
var ELITISM = Math.round(0.1 * PLAYER_AMOUNT);
|
||||
|
||||
// Trained population
|
||||
var USE_TRAINED_POP = true;
|
||||
|
||||
/** Global vars */
|
||||
var neat;
|
||||
|
||||
/** Construct the genetic algorithm */
|
||||
function initNeat(){
|
||||
neat = new Neat(
|
||||
6, 1,
|
||||
null,
|
||||
{
|
||||
mutation: [
|
||||
Methods.Mutation.ADD_NODE,
|
||||
Methods.Mutation.SUB_NODE,
|
||||
Methods.Mutation.ADD_CONN,
|
||||
Methods.Mutation.SUB_CONN,
|
||||
Methods.Mutation.MOD_WEIGHT,
|
||||
Methods.Mutation.MOD_BIAS,
|
||||
Methods.Mutation.MOD_ACTIVATION,
|
||||
Methods.Mutation.ADD_GATE,
|
||||
Methods.Mutation.SUB_GATE,
|
||||
Methods.Mutation.ADD_SELF_CONN,
|
||||
Methods.Mutation.SUB_SELF_CONN,
|
||||
Methods.Mutation.ADD_BACK_CONN,
|
||||
Methods.Mutation.SUB_BACK_CONN
|
||||
],
|
||||
popsize: PLAYER_AMOUNT,
|
||||
mutationRate: MUTATION_RATE,
|
||||
elitism: ELITISM
|
||||
}
|
||||
);
|
||||
|
||||
if(USE_TRAINED_POP){
|
||||
neat.population = population;
|
||||
}
|
||||
}
|
||||
|
||||
/** Start the evaluation of the current generation */
|
||||
function startEvaluation(){
|
||||
players = [];
|
||||
highestScore = 0;
|
||||
|
||||
for(var genome in neat.population){
|
||||
genome = neat.population[genome];
|
||||
new Player(genome);
|
||||
}
|
||||
|
||||
walker.reset();
|
||||
}
|
||||
|
||||
/** End the evaluation of the current generation */
|
||||
function endEvaluation(){
|
||||
console.log('Generation:', neat.generation, '- average score:', Math.round(neat.getAverage()));
|
||||
console.log('Fittest score:', Math.round(neat.getFittest().score));
|
||||
|
||||
// Networks shouldn't get too big
|
||||
for(var genome in neat.population){
|
||||
genome = neat.population[genome];
|
||||
genome.score -= genome.nodes.length * SCORE_RADIUS / 10;
|
||||
}
|
||||
|
||||
// Sort the population by score
|
||||
neat.sort();
|
||||
|
||||
// Init new pop
|
||||
var newPopulation = [];
|
||||
|
||||
// Elitism
|
||||
for(var i = 0; i < neat.elitism; i++){
|
||||
newPopulation.push(neat.population[i]);
|
||||
}
|
||||
|
||||
// Breed the next individuals
|
||||
for(var i = 0; i < neat.popsize - neat.elitism; i++){
|
||||
newPopulation.push(neat.getOffspring());
|
||||
}
|
||||
|
||||
// Replace the old population with the new population
|
||||
neat.population = newPopulation;
|
||||
neat.mutate();
|
||||
|
||||
neat.generation++;
|
||||
startEvaluation();
|
||||
}
|
91
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/player.js
generated
vendored
Normal file
91
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/player.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
function Player(genome){
|
||||
this.x = START_X;
|
||||
this.y = START_Y;
|
||||
this.vx = 0;
|
||||
this.vy = 0;
|
||||
this.r = 6;
|
||||
|
||||
this.brain = genome;
|
||||
this.brain.score = 0;
|
||||
|
||||
players.push(this);
|
||||
}
|
||||
|
||||
Player.prototype = {
|
||||
/** Update the stats */
|
||||
update: function(){
|
||||
var input = this.detect();
|
||||
var output = this.brain.activate(input);
|
||||
|
||||
var moveangle = output[0] * 2 * PI;
|
||||
|
||||
// Calculate next position
|
||||
this.ax = Math.cos(moveangle);
|
||||
this.ay = Math.sin(moveangle);
|
||||
this.vx += this.ax;
|
||||
this.vy += this.ay;
|
||||
|
||||
// Limit speeds to maximum speed
|
||||
this.vx = this.vx > MAX_SPEED ? MAX_SPEED : this.vx < -MAX_SPEED ? -MAX_SPEED : this.vx;
|
||||
this.vy = this.vy > MAX_SPEED ? MAX_SPEED : this.vy < -MAX_SPEED ? -MAX_SPEED : this.vy;
|
||||
|
||||
this.x += this.vx;
|
||||
this.y += this.vy;
|
||||
|
||||
// Limit position to width and height
|
||||
this.x = this.x >= WIDTH ? WIDTH : this.x <= 0 ? 0 : this.x;
|
||||
this.y = this.y >= HEIGHT ? HEIGHT : this.y <= 0 ? 0 : this.y;
|
||||
|
||||
if(this.x == 0 || this.x == WIDTH) this.vx = -this.vx;
|
||||
if(this.y == 0 || this.y == HEIGHT) this.vy = -this.vy;
|
||||
|
||||
this.score();
|
||||
},
|
||||
|
||||
/** Calculate fitness of this players genome **/
|
||||
score: function(){
|
||||
var dist = distance(this.x, this.y, walker.x, walker.y);
|
||||
if(!isNaN(dist) && dist < SCORE_RADIUS){
|
||||
this.brain.score += SCORE_RADIUS - dist;
|
||||
}
|
||||
|
||||
// Replace highest score to visualise
|
||||
highestScore = this.brain.score > highestScore ? this.brain.score : highestScore;
|
||||
},
|
||||
|
||||
/** Display the player on the field, parts borrowed from the CodingTrain */
|
||||
show: function(){
|
||||
// Draw a triangle rotated in the direction of velocity
|
||||
var angle = angleToPoint(this.x, this.y, this.x + this.vx, this.y + this.vy) + HALF_PI;
|
||||
var color = activationColor(this.brain.score, highestScore);
|
||||
|
||||
push();
|
||||
translate(this.x, this.y);
|
||||
rotate(angle);
|
||||
|
||||
fill(color);
|
||||
beginShape();
|
||||
vertex(0, -this.r * 2);
|
||||
vertex(-this.r, this.r * 2);
|
||||
vertex(this.r, this.r * 2);
|
||||
endShape(CLOSE);
|
||||
|
||||
pop();
|
||||
},
|
||||
|
||||
/** Detect and normalize inputs */
|
||||
detect: function(){
|
||||
var dist = Math.sqrt(this.x, this.y, walker.x, walker.y) / Math.sqrt(WIDTH**2 + HEIGHT**2);
|
||||
var targetAngle = angleToPoint(this.x, this.y, walker.x, walker.y) / TWO_PI;
|
||||
var vx = (this.vx + MAX_SPEED) / MAX_SPEED;
|
||||
var vy = (this.vy + MAX_SPEED) / MAX_SPEED;
|
||||
var tvx = (walker.vx + MAX_SPEED) / MAX_SPEED;
|
||||
var tvy = (walker.vy + MAX_SPEED) / MAX_SPEED;
|
||||
|
||||
// NaN checking
|
||||
targetAngle = isNaN(targetAngle) ? 0 : targetAngle;
|
||||
dist = isNaN(dist) ? 0 : dist;
|
||||
|
||||
return [vx, vy, tvx, tvy, targetAngle, dist];
|
||||
},
|
||||
};
|
50723
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/population.js
generated
vendored
Normal file
50723
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/population.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
68
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/walker.js
generated
vendored
Normal file
68
node_modules/neataptic/mkdocs/theme/js/articles/target-seekingai/walker.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
function Walker(){
|
||||
this.x = START_X;
|
||||
this.y = START_Y;
|
||||
this.vx = 0;
|
||||
this.vy = 0;
|
||||
|
||||
this.r = 10;
|
||||
|
||||
this.angle = Math.random() * Math.PI * 2;
|
||||
}
|
||||
|
||||
Walker.prototype = {
|
||||
/** Update the stats */
|
||||
update: function(){
|
||||
if(Math.random() > 0.5){
|
||||
this.angle += Math.random()* 2 -1;
|
||||
}
|
||||
|
||||
// Calculate next position
|
||||
this.ax = Math.cos(this.angle);
|
||||
this.ay = Math.sin(this.angle);
|
||||
this.vx += this.ax;
|
||||
this.vy += this.ay;
|
||||
|
||||
// Limit speeds to maximum speed
|
||||
this.vx = this.vx > MAX_SPEED/2 ? MAX_SPEED/2 : this.vx < -MAX_SPEED/2 ? -MAX_SPEED/2 : this.vx;
|
||||
this.vy = this.vy > MAX_SPEED/2 ? MAX_SPEED/2 : this.vy < -MAX_SPEED/2 ? -MAX_SPEED/2 : this.vy;
|
||||
|
||||
this.x += this.vx;
|
||||
this.y += this.vy;
|
||||
|
||||
// Limit position to width and height
|
||||
this.x = this.x >= WIDTH ? WIDTH : this.x <= 0 ? 0 : this.x;
|
||||
this.y = this.y >= HEIGHT ? HEIGHT : this.y <= 0 ? 0 : this.y;
|
||||
|
||||
if(this.x == 0 || this.x == WIDTH){
|
||||
this.vx = -this.vx;
|
||||
this.angle += PI;
|
||||
}
|
||||
if(this.y == 0 || this.y == HEIGHT){
|
||||
this.vy = -this.vy;
|
||||
this.angle += PI;
|
||||
}
|
||||
},
|
||||
|
||||
reset: function(){
|
||||
this.x = START_X;
|
||||
this.y = START_Y;
|
||||
this.vx = 0;
|
||||
this.vy = 0;
|
||||
|
||||
this.angle = Math.random() * Math.PI * 2;
|
||||
},
|
||||
|
||||
|
||||
/** Display the walker on the field */
|
||||
show: function(){
|
||||
fill(0);
|
||||
ellipse(this.x, this.y, this.r*2);
|
||||
|
||||
// Score radius
|
||||
noFill();
|
||||
stroke('lightgreen');
|
||||
strokeWeight(2);
|
||||
ellipse(this.x, this.y, SCORE_RADIUS*2);
|
||||
noStroke();
|
||||
},
|
||||
};
|
Reference in New Issue
Block a user