<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>GA Babies</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script type="text/javascript" src="population.js"></script>
<script>
var diameter = 960,
format = d3.format(",d"),
color = d3.scale.category20c();
var bubble = d3.layout.pack()
.sort(null)
.size([diameter, diameter])
.padding(1.5);
$(document).ready(function () {
var populous = new Population(256);
var generationCount = 0;
var svg = d3.select("body").append("svg");
function drawPopulous() {
var squareSide = 16;
for (var j = 0; j < squareSide; j++) {
for (var i = 0; i < squareSide; i++) {
var circle = svg.attr("width", 1024)
.attr("height", 1024)
.append("circle")
.attr("cx", 30 * (1 + j))
.attr("cy", 30 * (1 + i))
.attr("r", 10)
.style("stroke", "lightgrey")
.style("fill", "white");
var k = i * (j + i);
if (k < populous.population.length) {
circle.append("svg:title").text(function (item) {
return populous.population[k].geneCode;
});
var utility = fitness(populous.population[k]);
var worst = populous.population[k].geneCode.length;
var shade = (255 * utility) / worst;
shade = shade.toFixed(0);
var colorvalue = "rgb(" + shade + "," + shade + "," + shade + ")";
circle.style("fill", colorvalue);
if (shade < 50) {
StopShizzling();
circle.style("stroke", "#00FF88");
circle.style("stroke-width", "4");
}
}
}
}
}
var breedthem = function () {
var genLeap = 100;
for (var generation = 0; generation < genLeap; generation++) {
populous.Breed();
$("#gencount").text(generation);
}
generationCount += genLeap;
$("#gencount").text(generationCount);
// refresh populous grid
svg.remove();
svg = d3.select("body").append("svg");
drawPopulous();
}
var intHandler = null;
function StopShizzling() {
$("#breedbutton").text("Breed My Preties!");
clearInterval(intHandler);
intHandler = null;
}
$("#breedbutton").click(function() {
if (intHandler !== null) {
StopShizzling();
}
else {
populous.initialise();
intHandler = setInterval(breedthem, 8);
$("#breedbutton").text("STOP!! FOR THE LOVE OF GOD...");
}
});
drawPopulous();
});
</script>
</head>
<body>
<div style="padding: 24px;">
<div>Fitness string:</div>
<div><input type="text" id="fitness-name" value="JoBloggs"/>
<button id="breedbutton">Breed My Pretties!</button>
</div>
<div style="padding: 24px;">
Generation: <span id="gencount">0</span>
</div>
<div id="population">
</div>
</div>
</body>
</html>
function Population(agentCount) {
this.population = new Array();
var me = this;
// Initialise population
this.initialise = function() {
this.population = new Array();
for (var index = 0; index < agentCount; index++) {
var targetFitness = $("#fitness-name").val().toUpperCase();
var stringLen = targetFitness.length;
var result = "";
for (var i = 0; i < stringLen; i++) {
var digit = Math.round(25 * Math.random());
var chr = String.fromCharCode(65 + digit);
result += chr;
}
this.population.push(new Baby("" + index, result));
}
};
this.Breed = function () {
// Sort the populous by fitness utility
me.population.sort(function(agent1, agent2) {
return fitness(agent1) - fitness(agent2);
});
// Only breed the first half of the list
for (var j = 0; j < (me.population.length / 3) ; j++) {
var item = me.population[j];
var matePosition = Math.round((Math.random() * (me.population.length / 3)));
var pairedMate = me.population[matePosition];
item.crossOverWith(pairedMate);
}
};
this.initialise();
return this;
}
function hammingDistance(agent, targetFitness) {
var distance = 0;
var target = targetFitness.toUpperCase();
var upperAgent = agent.geneCode.toUpperCase();
for (var i = 0; i < agent.geneCode.length; i++) {
distance += upperAgent[i] === target[i] ? 0 : 1;
}
return distance;
}
function sumDiff(agent, targetFitness) {
var distance = 0;
var target = targetFitness.toUpperCase();
var upperAgent = agent.geneCode.toUpperCase();
for (var i = 0; i < agent.geneCode.length; i++) {
distance += Math.abs(upperAgent[i] - target[i]);
}
return distance;
}
function fitness(agent) {
var targetFitness = $("#fitness-name").val().toUpperCase();
var distance = hammingDistance(agent, targetFitness);
//var distance = sumDiff(agent, targetFitness);
return distance;
}
function Baby(name, geneCode) {
this.geneCode = geneCode;
this.name = name;
this.crossOverWith = function(otherParent)
{
// Pick a random point in the string
var endOfString = this.geneCode.length;
var swapPoint = Math.random() * endOfString;
// Find same position in other parent
var myGeneticSubencoding = geneCode.substring(swapPoint, endOfString);
var myPartnerGeneticSubencoding = otherParent.geneCode.substring(swapPoint, endOfString);
// Swap the two bits from then on
this.geneCode = geneCode.substring(0, swapPoint) + myPartnerGeneticSubencoding;
otherParent.geneCode = geneCode.substring(0, swapPoint) + myGeneticSubencoding;
};
this.mutate = function() {
// This mutates itself.
// Pick digit position
var endOfString = this.geneCode.length;
var mutatePoint = Math.random() * endOfString;
// randomise the digit in that position
this.geneCode[mutatePoint] = Math.random() * 9;
};
}
function populationView(populous) {
this.populousViewModel = {
"name": "population",
"children" : []
};
var me = this;
populous.population.forEach(function (item) {
var itemView = {
"name": item.name,
"size": "" + fitness(item)
};
me.populousViewModel.children.push(itemView);
});
}
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |