├── README.md
├── evolution.png
├── react-es6
├── build
│ ├── css
│ │ └── style.css
│ ├── index.html
│ └── js
│ │ └── bundle.js
├── gulp.config.js
├── gulpfile.js
├── package.json
└── src
│ ├── index.html
│ ├── jsx
│ ├── DNA.js
│ ├── Population.js
│ ├── Util.js
│ ├── World.jsx
│ └── index.jsx
│ └── scss
│ └── style.scss
└── vanilla
├── DNA.js
├── Population.js
├── index.html
└── sketch.js
/README.md:
--------------------------------------------------------------------------------
1 | # React.js Genetic Algorithm Boilerplate
2 |
3 | ## What is a Genetic Algorithm?
4 |
5 | Genetic Algorithms apply principles from biological evolution to find solutions to problems with no human input. The solution to the problem automatically evolves from random and incorrect trials and it gets better over time until the goal is reached.
6 |
7 | ## Can I see some examples to help me understand this?
8 | Put all this in perspective and to get you excited have a look at a few inspiring examples where developers used genetic algorithms to search for unknown solutions to known problems:
9 | - https://www.youtube.com/watch?v=qv6UVOQ0F44
10 | - https://www.youtube.com/watch?v=bBt0imn77Zg
11 | - https://www.youtube.com/watch?v=Gl3EjiVlz_4
12 | - https://www.youtube.com/watch?v=uwz8JzrEwWY
13 | - https://www.youtube.com/watch?v=8vzTCC-jbwM
14 | - https://www.youtube.com/watch?v=pgaEE27nsQw
15 |
16 | ## What are the core principles this algorithm inherits from Nature and the Darwinian Evolution?
17 | In order for natural selection to work like in Nature, all three of the below has to happen:
18 |
19 | - **Heredity**: Creatures pass down their genetic information (DNA) to their offsprings to the next generation if they live long enough to be able to reproduce.
20 |
21 | - **Variation**: Variety must be present when heredity happens. If all creatures are exactly the same then with no variation the species can't evolve. Variation normally happens when the genetic information of the parents mix at reproduction and with the random mutation.
22 |
23 | - **Selection**: Successful members of the population become parents and pass down their genetic information, unsuccessful ones die without offsprings. This is what we normally refer to as “survival of the fittest.” Natural selection is what allows a species to evolve and each generation to be more successful than their parents.
24 |
25 | 
26 |
27 | ## How can this be used in a computer algorithm to solve other, generic problems?
28 |
29 | You first have to start by defining your goal. **Remember that even though we use ideas from Nature, the goal of your algorithm can be ANYTHING.** The goal needs to be measurable and easily comparable to the performance and efficiency of each member of the population as members in the population represent the potential solution to the problem.
30 |
31 | In the first generation the population is filled with members (solutions) that are completely random. In this completely random pool there are always a few who, by pure luck and chance, perform ever so slightly better than the others. These are the "fittest" members. At the end of the genereation the fittest, best performing variations are selected to become parents for the new generation.
32 |
33 | Through many generations and rounds of natural selection solutions will become better and better. All this with no human input.
34 |
35 | ## What is the actual problem solved in the boilerplate?
36 |
37 | The goal of the example Genetic Algorith project found in this repository is to find the string: "Hello Web on Devices".
38 |
39 | Each member in the population of the first generation is a random string with the same length as the target string. This is essentially the DNA of the member that is going to be passed down from each parent. Remember that member = DNA, DNA = data representing the potential solution.
40 |
41 | There is also a compare function that calculates a fitness score for each member. This is essential to decide how close are they getting to the goal. In this case this just a function that counts the matching characters between the target string and the DNA string of the member. If the DNA has one matching character at the same location, then the score is 1, if it has 5 then the score is 5. This score will help us select the best performing solutions to become parents for the new generation.
42 |
43 | When two members reproduce to create an offsring they essentially combine their genetic information (DNA) which in this case means randomly combining the DNA string from each parent. Yes, this means that we may lose already matching characters, but overal, this mutation and variation help the solution evolve faster.
44 |
45 | After a couple of dozen or hundred generations members in the generation will come closer and closer to the goal and eventually one of them will actually reach it.
46 |
47 | ## How all this is implemented in React.js?
48 |
49 | There are two key classes to support the genetic algorithm: `DNA()` and `Population()`. Each member of the population is a new instance of the DNA class since that's their most defining property. The `DNA()` class provides methods like `crossOver`, `mutate` and `calcFitness` to support the reproduction mechanism. On the other hand the `Population()` class deals with higher level logic like natural selection, generating new populations and evaluating the fitness score of its members.
50 |
51 | The `` React component is the entry point of the whole algorithm. This is what you can plug in to your existing React.js application. There's only one state in this component which keeps track of the best solution so far. The constructor of the component exposes some settings for the algorithm:
52 | ```
53 | // Simulation settings
54 | this.targetPhrase = 'Hello Web on Devices';
55 | this.mutationRate = 0.01;
56 | this.populationSize = 300;
57 | ```
58 | You can try tweaking this try to speed up the algorithm.
59 |
60 | This is also the place where the `Population()` class is initialised with the settings:
61 | ```
62 | this.population = new Population(this.targetPhrase, this.mutationRate, this.populationSize);
63 | ```
64 |
65 | When the component is mounted we call the `draw()` method which recursively calls itself using `requestAnimationFrame()`. The `draw()` method is where most of the algorithm happens:
66 | ```
67 | draw() {
68 |
69 | // Generate weighed mating pool with the fittest members
70 | this.population.naturalSelection();
71 |
72 | // Generate new population of children from parents in the mating pool
73 | this.population.generate();
74 |
75 | // Calculate fitness score of the new population
76 | this.population.calcPopulationFitness();
77 |
78 | // Find the fittest member of the population and see if target is reached
79 | this.population.evaluate();
80 |
81 | // If target phrase is found, stop
82 | if (this.population.isFinished()) this.running = false;
83 |
84 | // Display best result so far
85 | this.setState({result: this.population.getBest()});
86 |
87 | // Loop and start new generation
88 | if (this.running) window.requestAnimationFrame(this.draw);
89 | }
90 | ```
91 |
92 | Finally, in the render function you can use the state to display the result.
93 |
94 | ## What else is this good for?
95 |
96 | The boilerplate is universal which means the algorithm can be used to work on any problems where you can:
97 | - Define the goal with a function that can calculate the fitness score of each member
98 | - Define the DNA of each member that drives their behavior towards the solution
99 |
100 | When you have these two defined then all you need to do is let the algorithm workout the logic.
--------------------------------------------------------------------------------
/evolution.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webondevices/react-genetic-algorithm/95e966fbe1095baed2f5b5a443d5b00ab683380b/evolution.png
--------------------------------------------------------------------------------
/react-es6/build/css/style.css:
--------------------------------------------------------------------------------
1 | body{font-family:sans-serif}.result{font-size:20px;width:300px;padding:25px;color:white;text-align:center;transition:background-color 300ms}
2 |
--------------------------------------------------------------------------------
/react-es6/build/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | React testing
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/react-es6/gulp.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function() {
2 | var paths = {
3 | build: './build/',
4 | source: './src/'
5 | };
6 |
7 | return paths;
8 | };
--------------------------------------------------------------------------------
/react-es6/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require("gulp");
2 | var browserify = require("browserify");
3 | var source = require("vinyl-source-stream");
4 | var sass = require("gulp-sass");
5 | var connect = require("gulp-connect");
6 | var config = require("./gulp.config.js")();
7 |
8 | function copy(settings) {
9 | return gulp.src(settings.from)
10 | .pipe(gulp.dest(settings.to))
11 | .pipe(connect.reload());
12 | }
13 |
14 | gulp.task("browserify", function() {
15 | return browserify(config.source + "jsx/index.jsx")
16 | .transform("babelify", {presets: ['es2015', 'react']})
17 | .bundle()
18 | .pipe(source('bundle.js'))
19 | .pipe(gulp.dest(config.build + "js/"))
20 | .pipe(connect.reload());
21 | });
22 |
23 | gulp.task("copy", function() {
24 |
25 | // Copy all HTML files
26 | copy({
27 | from: config.source + "*.html",
28 | to: config.build
29 | });
30 |
31 | // Copy all Images files
32 | copy({
33 | from: config.source + "images/**/*",
34 | to: config.build + "images/"
35 | });
36 | });
37 |
38 | gulp.task("sass", function() {
39 | var options = {
40 | outputStyle: "compressed"
41 | }
42 | return gulp.src(config.source + "scss/style.scss")
43 | .pipe(sass(options))
44 | .pipe(gulp.dest(config.build + "css/"))
45 | .pipe(connect.reload());
46 | });
47 |
48 | gulp.task("watch", ["sass", "copy", "browserify"], function() {
49 | gulp.watch(config.source + "scss/**/*", ["sass"]);
50 | gulp.watch([config.source + "images/**/*", ".src/*.html"], ["copy"]);
51 | gulp.watch(config.source + "jsx/**/*", ["browserify"]);
52 | });
53 |
54 | gulp.task("connect", function() {
55 | connect.server({
56 | root: "build",
57 | livereload: true
58 | })
59 | })
60 |
61 | gulp.task("default", ["connect", "watch"]);
--------------------------------------------------------------------------------
/react-es6/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-start",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "Liran, Mate and Binu",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "babel-preset-es2015": "^6.18.0",
13 | "babel-preset-react": "^6.16.0",
14 | "babelify": "^7.3.0",
15 | "browserify": "^13.1.1",
16 | "gulp": "^3.9.1",
17 | "gulp-connect": "^5.0.0",
18 | "gulp-sass": "^3.0.0",
19 | "react": "^15.4.1",
20 | "react-dom": "^15.4.1",
21 | "vinyl-source-stream": "^1.1.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/react-es6/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | React testing
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/react-es6/src/jsx/DNA.js:
--------------------------------------------------------------------------------
1 | import util from './util.js';
2 |
3 | class DNA {
4 | constructor(num){
5 |
6 | // The genetic sequence
7 | this.genes = [];
8 | this.fitness = 0;
9 |
10 | // Random DNA generated from characters
11 | this.genes = Array(num).fill(null);
12 | this.genes = this.genes.map(() => util.newChar());
13 | }
14 |
15 | // Converts character array to a String
16 | getPhrase() {
17 | return this.genes.join('');
18 | }
19 |
20 | // Fitness function (returns floating point % of "correct" characters)
21 | calcFitness(target) {
22 | let score = 0;
23 |
24 | this.genes.forEach((gene, i) => {
25 | if (gene === target.charAt(i)) score += 1;
26 | });
27 |
28 | this.fitness = score / target.length;
29 | }
30 |
31 | // Cross DNA with partner to produce child
32 | crossover(partner) {
33 |
34 | // Initialise new child
35 | const child = new DNA(this.genes.length);
36 | const midpoint = util.randomInt(0, this.genes.length - 1);
37 |
38 | // Cross DNA from two parents from each side of midpoint
39 | this.genes.forEach((gene, i) => {
40 |
41 | if (i > midpoint) {
42 | child.genes[i] = this.genes[i];
43 | } else {
44 | child.genes[i] = partner.genes[i];
45 | }
46 | });
47 |
48 | return child;
49 | }
50 |
51 | // picks a new random character based on a mutation probability
52 | mutate(mutationRate) {
53 | this.genes.forEach((gene, i) => {
54 |
55 | if (Math.random(0, 1) < mutationRate) {
56 | this.genes[i] = util.newChar();
57 | }
58 | });
59 | }
60 | }
61 |
62 | export default DNA;
--------------------------------------------------------------------------------
/react-es6/src/jsx/Population.js:
--------------------------------------------------------------------------------
1 | import DNA from './DNA.js';
2 | import util from './util.js';
3 |
4 | class Population {
5 | constructor(t, m, populationSize) {
6 | this.target = t;
7 | this.mutationRate = m;
8 | this.generations = 0;
9 | this.perfectScore = 1;
10 | this.finished = false;
11 | this.matingPool = [];
12 | this.best = '';
13 |
14 | // Fill population with DNA instances
15 | this.population = Array(populationSize).fill(null);
16 | this.population = this.population.map(() => new DNA(this.target.length));
17 |
18 | this.calcPopulationFitness();
19 | }
20 |
21 | // Calculate fitness value for every member of the population
22 | calcPopulationFitness() {
23 | this.population.forEach(member => {
24 | member.calcFitness(this.target);
25 | });
26 | }
27 |
28 | // Generate a weighed mating pool
29 | naturalSelection() {
30 | let maxFitness = 0;
31 |
32 | this.matingPool = [];
33 |
34 | // Find the highest fitness value in the population
35 | this.population.forEach(member => {
36 | maxFitness = member.fitness > maxFitness ? member.fitness : maxFitness;
37 | });
38 |
39 | // Based on fitness, each member is added to the mating pool a weighed number of times
40 | // higher fitness = more instance in pool = more likely to be picked as a parent
41 | // lower fitness = less instance in pool = less likely to be picked as a parent
42 | this.population.forEach(member => {
43 | const fitness = util.map(member.fitness, 0, maxFitness, 0, 1);
44 |
45 | // Arbitrary multiplier
46 | let n = Math.floor(fitness * 50);
47 | for ( ; n >= 0; n--) {
48 | this.matingPool.push(member);
49 | }
50 | });
51 | }
52 |
53 | // Create a new generation
54 | generate() {
55 |
56 | this.population.forEach((member, i) => {
57 |
58 | // Random index for the pool
59 | const a = util.randomInt(0, this.matingPool.length - 1);
60 | const b = util.randomInt(0, this.matingPool.length - 1);
61 |
62 | // Picking a random item from the pool
63 | const partnerA = this.matingPool[a];
64 | const partnerB = this.matingPool[b];
65 |
66 | // Generating a child with DNA crossover
67 | const child = partnerA.crossover(partnerB);
68 |
69 | // Mutate DNA for diversity
70 | child.mutate(this.mutationRate);
71 |
72 | // Add child to the population
73 | this.population[i] = child;
74 |
75 | });
76 |
77 | this.generations += 1;
78 | }
79 |
80 |
81 | getBest() {
82 | return this.best;
83 | }
84 |
85 | evaluate() {
86 | let worldrecord = 0.0;
87 | let index = 0;
88 |
89 | // Find the fittest member of the population
90 | this.population.forEach((member, i) => {
91 | if (member.fitness > worldrecord) {
92 | index = i;
93 | worldrecord = member.fitness;
94 | }
95 | });
96 |
97 | // Get best result so far
98 | this.best = this.population[index].getPhrase();
99 |
100 | // Stop simulation if found result
101 | if (worldrecord === this.perfectScore) this.finished = true;
102 | }
103 |
104 | isFinished() {
105 | return this.finished;
106 | }
107 |
108 | getGenerations() {
109 | return this.generations;
110 | }
111 |
112 | // Get average fitness for the population
113 | getAverageFitness() {
114 | let total = 0;
115 |
116 | this.population.forEach(member => {
117 | total += member.fitness;
118 | });
119 |
120 | return total / this.population.length;
121 | }
122 | }
123 |
124 | export default Population;
--------------------------------------------------------------------------------
/react-es6/src/jsx/Util.js:
--------------------------------------------------------------------------------
1 | const util = {
2 | map: function(value, low1, high1, low2, high2) {
3 | return low2 + (high2 - low2) * (value - low1) / (high1 - low1);
4 | },
5 |
6 | randomInt: function(min, max) {
7 | return Math.floor(Math.random() * (max - min + 1) + min);
8 | },
9 |
10 | newChar: function(){
11 | var c = this.randomInt(63, 122 - 1);
12 |
13 | if (c === 63) c = 32;
14 | if (c === 64) c = 46;
15 |
16 | return String.fromCharCode(c);
17 | }
18 | }
19 |
20 | export default util;
--------------------------------------------------------------------------------
/react-es6/src/jsx/World.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Population from './Population.js';
3 |
4 | class World extends React.Component {
5 |
6 | constructor() {
7 | super();
8 |
9 | this.state = {
10 | result: ''
11 | };
12 |
13 | // Simulation settings
14 | this.targetPhrase = 'Hello Web on Devices';
15 | this.mutationRate = 0.01;
16 | this.populationSize = 300;
17 |
18 | this.running = true;
19 |
20 | // Initialise population
21 | this.population = new Population(this.targetPhrase, this.mutationRate, this.populationSize);
22 |
23 | this.draw = this.draw.bind(this);
24 | }
25 |
26 | componentDidMount(){
27 |
28 | // Start simulation
29 | this.draw();
30 | }
31 |
32 | draw() {
33 |
34 | // Generate weighed mating pool with the fittest members
35 | this.population.naturalSelection();
36 |
37 | // Generate new population of children from parents in the mating pool
38 | this.population.generate();
39 |
40 | // Calculate fitness score of the new population
41 | this.population.calcPopulationFitness();
42 |
43 | // Find the fittest member of the population and see if target is reached
44 | this.population.evaluate();
45 |
46 | // If target phrase is found, stop
47 | if (this.population.isFinished()) this.running = false;
48 |
49 | // Display best result so far
50 | this.setState({result: this.population.getBest()});
51 |
52 | // Loop and start new generation
53 | if (this.running) window.requestAnimationFrame(this.draw);
54 | }
55 |
56 | render() {
57 | const myStyle = this.running ? {backgroundColor: 'red'} : {backgroundColor: 'green'};
58 |
59 | return (
60 |
61 | { this.state.result }
62 |
63 | );
64 | }
65 | }
66 |
67 | export default World;
--------------------------------------------------------------------------------
/react-es6/src/jsx/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import World from './World.jsx';
4 |
5 | ReactDOM.render(, document.getElementById('react-app'));
--------------------------------------------------------------------------------
/react-es6/src/scss/style.scss:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: sans-serif;
3 | }
4 |
5 | .result {
6 | font-size: 20px;
7 | width: 300px;
8 | padding: 25px;
9 | color: white;
10 | text-align: center;
11 | transition: background-color 300ms;
12 | }
--------------------------------------------------------------------------------
/vanilla/DNA.js:
--------------------------------------------------------------------------------
1 | // DNA constructor, generates random DNA
2 | function DNA(num) {
3 |
4 | // The genetic sequence
5 | this.genes = [];
6 | this.fitness = 0;
7 |
8 | // Random DNA generated from characters
9 | for (var i = 0; i < num; i++) {
10 | this.genes[i] = newChar();
11 | }
12 |
13 | // Converts character array to a String
14 | this.getPhrase = function() {
15 | return this.genes.join("");
16 | }
17 |
18 | // Fitness function (returns floating point % of "correct" characters)
19 | this.calcFitness = function(target) {
20 | var score = 0;
21 |
22 | for (var i = 0; i < this.genes.length; i++) {
23 |
24 | if (this.genes[i] == target.charAt(i)) {
25 | score++;
26 | }
27 | }
28 |
29 | this.fitness = score / target.length;
30 | }
31 |
32 | // Cross to members
33 | this.crossover = function(partner) {
34 |
35 | // A new child
36 | var child = new DNA(this.genes.length);
37 | var midpoint = randomInt(0,this.genes.length - 1);
38 |
39 | // Half from one, half from the other
40 | for (var i = 0; i < this.genes.length; i++) {
41 |
42 | if (i > midpoint) {
43 | child.genes[i] = this.genes[i];
44 | } else {
45 | child.genes[i] = partner.genes[i];
46 | }
47 | }
48 |
49 | return child;
50 | }
51 |
52 | // picks a new random character based on a mutation probability
53 | this.mutate = function(mutationRate) {
54 |
55 | for (var i = 0; i < this.genes.length; i++) {
56 |
57 | if (Math.random(0, 1) < mutationRate) {
58 | this.genes[i] = newChar();
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/vanilla/Population.js:
--------------------------------------------------------------------------------
1 | function Population(p, m, num) {
2 | this.population; // Array to hold the current population
3 | this.matingPool; // ArrayList which we will use for our "mating pool"
4 | this.generations = 0; // Number of generations
5 | this.finished = false; // Are we finished evolving?
6 | this.target = p; // Target phrase
7 | this.mutationRate = m; // Mutation rate
8 | this.perfectScore = 1;
9 | this.best = '';
10 | this.population = [];
11 |
12 | for (var i = 0; i < num; i++) {
13 | this.population[i] = new DNA(this.target.length);
14 | }
15 |
16 | this.matingPool = [];
17 |
18 | // Fill our fitness array with a value for every member of the population
19 | this.calcFitness = function() {
20 | for (var i = 0; i < this.population.length; i++) {
21 | this.population[i].calcFitness(target);
22 | }
23 | }
24 |
25 | this.calcFitness();
26 |
27 | // Generate a mating pool
28 | this.naturalSelection = function() {
29 | var maxFitness = 0;
30 |
31 | // Clear the ArrayList
32 | this.matingPool = [];
33 |
34 | for (var i = 0; i < this.population.length; i++) {
35 | if (this.population[i].fitness > maxFitness) {
36 | maxFitness = this.population[i].fitness;
37 | }
38 | }
39 |
40 | // Based on fitness, each member will get added to the mating pool a certain number of times
41 | // a higher fitness = more entries to mating pool = more likely to be picked as a parent
42 | // a lower fitness = fewer entries to mating pool = less likely to be picked as a parent
43 | for (var i = 0; i < this.population.length; i++) {
44 | var fitness = map(this.population[i].fitness,0,maxFitness,0,1);
45 |
46 | // Arbitrary multiplier, could also use monte carlo method
47 | var n = Math.floor(fitness * 100);
48 |
49 | for (var j = 0; j < n; j++) {
50 | this.matingPool.push(this.population[i]);
51 | }
52 | }
53 | }
54 |
55 | // Create a new generation
56 | this.generate = function() {
57 |
58 | // Refill the population with children from the mating pool
59 | for (var i = 0; i < this.population.length; i++) {
60 |
61 | // Getting a random index for the pool
62 | var a = randomInt(0, this.matingPool.length - 1);
63 | var b = randomInt(0, this.matingPool.length - 1);
64 |
65 | // Picking a random item from the pool
66 | var partnerA = this.matingPool[a];
67 | var partnerB = this.matingPool[b];
68 |
69 | // Generating an offspring
70 | var child = partnerA.crossover(partnerB);
71 |
72 | // Mutate DNA
73 | child.mutate(this.mutationRate);
74 |
75 | // Add child to the population
76 | this.population[i] = child;
77 | }
78 |
79 | this.generations++;
80 | }
81 |
82 |
83 | this.getBest = function() {
84 | return this.best;
85 | }
86 |
87 | // Compute the current "most fit" member of the population
88 | this.evaluate = function() {
89 | var worldrecord = 0.0;
90 | var index = 0;
91 |
92 | for (var i = 0; i < this.population.length; i++) {
93 |
94 | if (this.population[i].fitness > worldrecord) {
95 | index = i;
96 | worldrecord = this.population[i].fitness;
97 | }
98 | }
99 |
100 | this.best = this.population[index].getPhrase();
101 |
102 | if (worldrecord === this.perfectScore) {
103 | this.finished = true;
104 | }
105 | }
106 |
107 | this.isFinished = function() {
108 | return this.finished;
109 | }
110 |
111 | this.getGenerations = function() {
112 | return this.generations;
113 | }
114 |
115 | // Compute average fitness for the population
116 | this.getAverageFitness = function() {
117 | var total = 0;
118 |
119 | for (var i = 0; i < this.population.length; i++) {
120 | total += this.population[i].fitness;
121 | }
122 |
123 | return total / (this.population.length);
124 | }
125 |
126 | this.allPhrases = function() {
127 | var everything = "";
128 | var displayLimit = Math.min(this.population.length,50);
129 |
130 | for (var i = 0; i < displayLimit; i++) {
131 | everything += this.population[i].getPhrase() + " ";
132 | }
133 |
134 | return everything;
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/vanilla/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/vanilla/sketch.js:
--------------------------------------------------------------------------------
1 | var target;
2 | var popmax;
3 | var mutationRate;
4 | var population;
5 |
6 | var running = true;
7 |
8 | function setup() {
9 | target = 'Hello Web on Devices';
10 | mutationRate = 0.01;
11 | popmax = 300;
12 |
13 | // Create a population with a target phrase, mutation rate, and population max
14 | population = new Population(target, mutationRate, popmax);
15 |
16 | // Initialise first generation
17 | draw();
18 | }
19 |
20 | function draw() {
21 |
22 | // Generate weighed mating pool with the fittest members
23 | population.naturalSelection();
24 |
25 | // Generate new population of offsprings from parents in the mating pool
26 | population.generate();
27 |
28 | // Calculate fitness of the new population
29 | population.calcFitness();
30 |
31 | // Find the fittest member of the population and see if target is reached
32 | population.evaluate();
33 |
34 | // If target phrase is found, stop
35 | if (population.isFinished()) running = false;
36 |
37 | // Display best result so far
38 | displayInfo();
39 |
40 | // Loop and start new generation
41 | if (running) window.requestAnimationFrame(draw);
42 | }
43 |
44 | function displayInfo() {
45 | var answer = population.getBest();
46 | var element = document.getElementById('result');
47 |
48 | element.innerHTML = answer;
49 | }
50 |
51 | function map(value, low1, high1, low2, high2) {
52 | return low2 + (high2 - low2) * (value - low1) / (high1 - low1);
53 | }
54 |
55 | function randomInt(min, max) {
56 | return Math.floor( Math.random() * (max - min + 1) + min );
57 | }
58 |
59 | function newChar() {
60 | var c = randomInt(63, 122 - 1);
61 |
62 | if (c === 63) c = 32;
63 | if (c === 64) c = 46;
64 |
65 | return String.fromCharCode(c);
66 | }
67 |
68 | window.onload = setup;
69 |
--------------------------------------------------------------------------------