├── README.md ├── genetic-hello-world.js └── index.html /README.md: -------------------------------------------------------------------------------- 1 | # Genetic Hello World 2 | 3 | Simple attempt at genetic programming. Demo here: https://sacert.github.io/Genetic-Hello-World/ 4 | -------------------------------------------------------------------------------- /genetic-hello-world.js: -------------------------------------------------------------------------------- 1 | var started = false; 2 | 3 | // individual genes 4 | class Gene { 5 | constructor(code) { 6 | if (code) 7 | this.code = code; 8 | else 9 | this.code = ''; 10 | this.cost = 9999; 11 | } 12 | 13 | generateCode(length) { 14 | for (var i = 0; i < length; i++) { 15 | this.code += String.fromCharCode(Math.floor(Math.random() * 255)); 16 | } 17 | } 18 | 19 | // calculate difference between current gene and other gene 20 | calcDiff(otherGene) { 21 | var val = 0; 22 | for (var i = 0; i < this.code.length; i++) { 23 | val += (this.code.charCodeAt(i) - otherGene.charCodeAt(i)) * (this.code.charCodeAt(i) - otherGene.charCodeAt(i)); 24 | } 25 | this.cost = val; 26 | } 27 | 28 | // mate current gene with another gene 29 | // pivot may be changed for better results 30 | mate(gene) { 31 | 32 | var pivot = Math.round(this.code.length/2) - 1; 33 | 34 | // new children will take half of each gene 35 | var newChild_1 = this.code.substr(0, pivot) + gene.code.substr(pivot); 36 | var newChild_2 = gene.code.substr(0, pivot) + this.code.substr(pivot); 37 | 38 | return [new Gene(newChild_1), new Gene(newChild_2)]; 39 | } 40 | 41 | // randomly mutate gene by a character depending on the percentage 42 | mutate(percentage) { 43 | if (Math.random() > percentage) { 44 | var index = Math.floor(Math.random() * this.code.length); 45 | 46 | // determine how to shift the char 47 | var upDown = Math.random() > 0.5 ? 1 : -1; 48 | 49 | // code = shifted index using upDown val 50 | this.code = this.code.substr(0, index) + String.fromCharCode(this.code.charCodeAt(index) + upDown) + this.code.substr(index + 1); 51 | } 52 | } 53 | } 54 | 55 | class Population { 56 | // stores the entire gene population and finds the targetChromosome 57 | constructor(targetChromosome, popSize) { 58 | this.genePool = []; 59 | this.generationNumber = 0; 60 | this.targetChromosome = targetChromosome; 61 | 62 | // create genes with random codes and insert into gene pool 63 | for (var i = 0; i < popSize; i++) { 64 | var gene = new Gene(); 65 | gene.generateCode(this.targetChromosome.length); 66 | this.genePool.push(gene); 67 | } 68 | } 69 | 70 | // helper function to sort gene pool by cost 71 | sort() { 72 | this.genePool.sort(function (a, b) { 73 | return (a.cost - b.cost); 74 | }); 75 | } 76 | 77 | // perform calculations for current generation 78 | generation() { 79 | 80 | // for all genes, calculate their cost 81 | for (var i = 0 ; i < this.genePool.length; i++) { 82 | this.genePool[i].calcDiff(this.targetChromosome); 83 | } 84 | 85 | this.sort(); 86 | 87 | // mate the genes with the lowest cost 88 | var children = this.genePool[0].mate(this.genePool[1]); 89 | 90 | // remove the genes with the highest cost and replace them with the new children 91 | this.genePool.splice(this.genePool.length - 2, 2, children[0], children[1]); 92 | 93 | // calculate the respective difference for the children genes 94 | this.genePool[this.genePool.length-1].calcDiff(this.targetChromosome); 95 | this.genePool[this.genePool.length-2].calcDiff(this.targetChromosome); 96 | 97 | this.sort(); 98 | this.print(); 99 | 100 | for (var i = 0; i < this.genePool.length; i++) { 101 | 102 | // mutate and calculate difference 103 | this.genePool[i].mutate(0.3); 104 | this.genePool[i].calcDiff(this.targetChromosome); 105 | 106 | // check if gene is the target and display it 107 | if (this.genePool[i].code == this.targetChromosome) { 108 | this.sort(); 109 | this.print(); 110 | started = false; 111 | return true; 112 | } 113 | } 114 | 115 | this.generationNumber++; 116 | 117 | var scope = this; 118 | setTimeout(function() { scope.generation(); } , 20); 119 | } 120 | 121 | print() { 122 | var table = document.getElementById('table') 123 | table.innerHTML = ''; 124 | table.innerHTML += ("

Generation: " + this.generationNumber + "

"); 125 | table.innerHTML += (""); 130 | }; 131 | 132 | } 133 | 134 | function start() { 135 | if ( ! started) { 136 | started = true; 137 | var pop = new Population("Hello, world!", 20); 138 | pop.generation(); 139 | } 140 | }; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Genetic Hello World 5 | 23 | 24 | 25 | 26 |
27 |

Generation: 0

28 |
29 | 30 | 31 | 32 | 33 | --------------------------------------------------------------------------------