Evolutionary algorithm: Difference between revisions

Line 4,220:
Generation: 50, Best: METHINKS IT IS LIKEZA WEASEL, fitness:1
Generation: 52, Best: METHINKS IT IS LIKE A WEASEL, fitness:0
</pre>
 
 
An attempt using ES6
by A.K.Bateman 2023
<syntaxhighlight lang="javascript">
"use strict"
const TARGET = "METHINKS IT IS LIKE A WEASEL";
const GENE_POOL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ';
const C = 100;
const MUTATION_RATE = 0.3;
 
function randomIdGenerator(length) {
return Math.floor(Math.random() * length);
}
function getGene() {
return GENE_POOL[randomIdGenerator(GENE_POOL.length)];
}
 
class Parent {
_arrayLength;
_genePool;
_geneGenerator;
 
constructor(arrayLength, genePool, geneGenerator) {
if (typeof arrayLength === 'number' && arrayLength > 0) {
this._arrayLength = arrayLength;
}
 
if (typeof genePool === 'string' && genePool.length > 0) {
this._genePool = [...genePool];
}
 
if (typeof geneGenerator === 'function') {
this._geneGenerator = geneGenerator;
}
}
generate() {
const letters = [];
 
while (letters.length < this._arrayLength) {
letters.push(this._geneGenerator());
}
 
return letters.join('');
}
}
 
function fitness(needle, target) {
if (needle.length !== target.length) return 0;
 
const needleArray = [...needle];
let count = 0;
 
[...target].forEach((item, index) => {
if (item === needleArray[index]) count++;
});
 
return count;
}
 
function mutate({ source, mutationRate }) {
if (typeof source !== 'string' || source.length === 0) return '';
const sourceLength = source.length;
const iterations = Math.floor(sourceLength * mutationRate);
const stringArray = [...source];
 
for(let i = 0; i < iterations; i++) {
const shouldReplace = Boolean(Math.floor(Math.random() * 2));
 
if(shouldReplace) {
const id = randomIdGenerator(sourceLength);
stringArray[id] = getGene();
}
}
 
return stringArray.join('');
}
 
function createMutants(parent, mutantNumber) {
const mutantArray = [];
 
for (let i = 0; i < mutantNumber; i++) {
const mutant = mutate({source: parent, mutationRate: MUTATION_RATE});
 
mutantArray.push(
{
mutant,
fitness: fitness(mutant, TARGET),
},
);
}
 
return mutantArray;
}
 
function helperInit(parentString, parentFitness) {
const mutant = createMutants(parentString, C)
.sort( (a,b) => a.fitness - b.fitness ).pop();
 
if (mutant.fitness >= parentFitness) {
return {
string: mutant.mutant,
fitness: mutant.fitness,
};
}
 
return {
string: parentString,
fitness: parentFitness,
};
}
 
function run() {
const parent = new Parent(TARGET.length, GENE_POOL, getGene);
let parentString = parent.generate();
let parentFitness = fitness(parentString, TARGET);
let genCount = 0;
 
while(parentString !== TARGET) {
const init = helperInit(parentString, parentFitness);
parentString = init.string;
parentFitness = init.fitness;
console.log(init.string);
genCount++;
}
 
console.log(`Ended in ${genCount} generations`);
}
 
run();
</syntaxhighlight>
example output:
<pre>
METHYNKS IT IS LIKE A WEASEL
METHYNKS IT IS LIKE A WEASEL
METHYNKS IT IS LIKE A WEASEL
METHYNKS IT IS LIKE A WEASEL
METHYNKS IT IS LIKE A WEASEL
METHINKS IT IS LIKE A WEASEL
Ended in 240 generations
</pre>