├── BestTutorialEver ├── BestTutorialEver.pde ├── Brain.pde ├── Dot.pde └── Population.pde └── README.md /BestTutorialEver/BestTutorialEver.pde: -------------------------------------------------------------------------------- 1 | Population test; 2 | PVector goal = new PVector(400, 10); 3 | 4 | 5 | void setup() { 6 | size(800, 800); //size of the window 7 | frameRate(100);//increase this to make the dots go faster 8 | test = new Population(1000);//create a new population with 1000 members 9 | } 10 | 11 | 12 | void draw() { 13 | background(255); 14 | 15 | //draw goal 16 | fill(255, 0, 0); 17 | ellipse(goal.x, goal.y, 10, 10); 18 | 19 | //draw obstacle(s) 20 | fill(0, 0, 255); 21 | 22 | rect(0, 300, 600, 10); 23 | 24 | 25 | if (test.allDotsDead()) { 26 | //genetic algorithm 27 | test.calculateFitness(); 28 | test.naturalSelection(); 29 | test.mutateDemBabies(); 30 | } else { 31 | //if any of the dots are still alive then update and then show them 32 | 33 | test.update(); 34 | test.show(); 35 | } 36 | } -------------------------------------------------------------------------------- /BestTutorialEver/Brain.pde: -------------------------------------------------------------------------------- 1 | class Brain { 2 | PVector[] directions;//series of vectors which get the dot to the goal (hopefully) 3 | int step = 0; 4 | 5 | 6 | Brain(int size) { 7 | directions = new PVector[size]; 8 | randomize(); 9 | } 10 | 11 | //-------------------------------------------------------------------------------------------------------------------------------- 12 | //sets all the vectors in directions to a random vector with length 1 13 | void randomize() { 14 | for (int i = 0; i< directions.length; i++) { 15 | float randomAngle = random(2*PI); 16 | directions[i] = PVector.fromAngle(randomAngle); 17 | } 18 | } 19 | 20 | //------------------------------------------------------------------------------------------------------------------------------------- 21 | //returns a perfect copy of this brain object 22 | Brain clone() { 23 | Brain clone = new Brain(directions.length); 24 | for (int i = 0; i < directions.length; i++) { 25 | clone.directions[i] = directions[i].copy(); 26 | } 27 | 28 | return clone; 29 | } 30 | 31 | //---------------------------------------------------------------------------------------------------------------------------------------- 32 | 33 | //mutates the brain by setting some of the directions to random vectors 34 | void mutate() { 35 | float mutationRate = 0.01;//chance that any vector in directions gets changed 36 | for (int i =0; i< directions.length; i++) { 37 | float rand = random(1); 38 | if (rand < mutationRate) { 39 | //set this direction as a random direction 40 | float randomAngle = random(2*PI); 41 | directions[i] = PVector.fromAngle(randomAngle); 42 | } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /BestTutorialEver/Dot.pde: -------------------------------------------------------------------------------- 1 | class Dot { 2 | PVector pos; 3 | PVector vel; 4 | PVector acc; 5 | Brain brain; 6 | 7 | boolean dead = false; 8 | boolean reachedGoal = false; 9 | boolean isBest = false;//true if this dot is the best dot from the previous generation 10 | 11 | float fitness = 0; 12 | 13 | Dot() { 14 | brain = new Brain(1000);//new brain with 1000 instructions 15 | 16 | //start the dots at the bottom of the window with a no velocity or acceleration 17 | pos = new PVector(width/2, height- 10); 18 | vel = new PVector(0, 0); 19 | acc = new PVector(0, 0); 20 | } 21 | 22 | 23 | //----------------------------------------------------------------------------------------------------------------- 24 | //draws the dot on the screen 25 | void show() { 26 | //if this dot is the best dot from the previous generation then draw it as a big green dot 27 | if (isBest) { 28 | fill(0, 255, 0); 29 | ellipse(pos.x, pos.y, 8, 8); 30 | } else {//all other dots are just smaller black dots 31 | fill(0); 32 | ellipse(pos.x, pos.y, 4, 4); 33 | } 34 | } 35 | 36 | //----------------------------------------------------------------------------------------------------------------------- 37 | //moves the dot according to the brains directions 38 | void move() { 39 | 40 | if (brain.directions.length > brain.step) {//if there are still directions left then set the acceleration as the next PVector in the direcitons array 41 | acc = brain.directions[brain.step]; 42 | brain.step++; 43 | } else {//if at the end of the directions array then the dot is dead 44 | dead = true; 45 | } 46 | 47 | //apply the acceleration and move the dot 48 | vel.add(acc); 49 | vel.limit(5);//not too fast 50 | pos.add(vel); 51 | } 52 | 53 | //------------------------------------------------------------------------------------------------------------------- 54 | //calls the move function and check for collisions and stuff 55 | void update() { 56 | if (!dead && !reachedGoal) { 57 | move(); 58 | if (pos.x< 2|| pos.y<2 || pos.x>width-2 || pos.y>height -2) {//if near the edges of the window then kill it 59 | dead = true; 60 | } else if (dist(pos.x, pos.y, goal.x, goal.y) < 5) {//if reached goal 61 | 62 | reachedGoal = true; 63 | } else if (pos.x< 600 && pos.y < 310 && pos.x > 0 && pos.y > 300) {//if hit obstacle 64 | dead = true; 65 | } 66 | } 67 | } 68 | 69 | 70 | //-------------------------------------------------------------------------------------------------------------------------------------- 71 | //calculates the fitness 72 | void calculateFitness() { 73 | if (reachedGoal) {//if the dot reached the goal then the fitness is based on the amount of steps it took to get there 74 | fitness = 1.0/16.0 + 10000.0/(float)(brain.step * brain.step); 75 | } else {//if the dot didn't reach the goal then the fitness is based on how close it is to the goal 76 | float distanceToGoal = dist(pos.x, pos.y, goal.x, goal.y); 77 | fitness = 1.0/(distanceToGoal * distanceToGoal); 78 | } 79 | } 80 | 81 | //--------------------------------------------------------------------------------------------------------------------------------------- 82 | //clone it 83 | Dot gimmeBaby() { 84 | Dot baby = new Dot(); 85 | baby.brain = brain.clone();//babies have the same brain as their parents 86 | return baby; 87 | } 88 | } -------------------------------------------------------------------------------- /BestTutorialEver/Population.pde: -------------------------------------------------------------------------------- 1 | class Population { 2 | Dot[] dots; 3 | 4 | float fitnessSum; 5 | int gen = 1; 6 | 7 | int bestDot = 0;//the index of the best dot in the dots[] 8 | 9 | int minStep = 1000; 10 | 11 | Population(int size) { 12 | dots = new Dot[size]; 13 | for (int i = 0; i< size; i++) { 14 | dots[i] = new Dot(); 15 | } 16 | } 17 | 18 | 19 | //------------------------------------------------------------------------------------------------------------------------------ 20 | //show all dots 21 | void show() { 22 | for (int i = 1; i< dots.length; i++) { 23 | dots[i].show(); 24 | } 25 | dots[0].show(); 26 | } 27 | 28 | //------------------------------------------------------------------------------------------------------------------------------- 29 | //update all dots 30 | void update() { 31 | for (int i = 0; i< dots.length; i++) { 32 | if (dots[i].brain.step > minStep) {//if the dot has already taken more steps than the best dot has taken to reach the goal 33 | dots[i].dead = true;//then it dead 34 | } else { 35 | dots[i].update(); 36 | } 37 | } 38 | } 39 | 40 | //----------------------------------------------------------------------------------------------------------------------------------- 41 | //calculate all the fitnesses 42 | void calculateFitness() { 43 | for (int i = 0; i< dots.length; i++) { 44 | dots[i].calculateFitness(); 45 | } 46 | } 47 | 48 | 49 | //------------------------------------------------------------------------------------------------------------------------------------ 50 | //returns whether all the dots are either dead or have reached the goal 51 | boolean allDotsDead() { 52 | for (int i = 0; i< dots.length; i++) { 53 | if (!dots[i].dead && !dots[i].reachedGoal) { 54 | return false; 55 | } 56 | } 57 | 58 | return true; 59 | } 60 | 61 | 62 | 63 | //------------------------------------------------------------------------------------------------------------------------------------- 64 | 65 | //gets the next generation of dots 66 | void naturalSelection() { 67 | Dot[] newDots = new Dot[dots.length];//next gen 68 | setBestDot(); 69 | calculateFitnessSum(); 70 | 71 | //the champion lives on 72 | newDots[0] = dots[bestDot].gimmeBaby(); 73 | newDots[0].isBest = true; 74 | for (int i = 1; i< newDots.length; i++) { 75 | //select parent based on fitness 76 | Dot parent = selectParent(); 77 | 78 | //get baby from them 79 | newDots[i] = parent.gimmeBaby(); 80 | } 81 | 82 | dots = newDots.clone(); 83 | gen ++; 84 | } 85 | 86 | 87 | //-------------------------------------------------------------------------------------------------------------------------------------- 88 | //you get it 89 | void calculateFitnessSum() { 90 | fitnessSum = 0; 91 | for (int i = 0; i< dots.length; i++) { 92 | fitnessSum += dots[i].fitness; 93 | } 94 | } 95 | 96 | //------------------------------------------------------------------------------------------------------------------------------------- 97 | 98 | //chooses dot from the population to return randomly(considering fitness) 99 | 100 | //this function works by randomly choosing a value between 0 and the sum of all the fitnesses 101 | //then go through all the dots and add their fitness to a running sum and if that sum is greater than the random value generated that dot is chosen 102 | //since dots with a higher fitness function add more to the running sum then they have a higher chance of being chosen 103 | Dot selectParent() { 104 | float rand = random(fitnessSum); 105 | 106 | 107 | float runningSum = 0; 108 | 109 | for (int i = 0; i< dots.length; i++) { 110 | runningSum+= dots[i].fitness; 111 | if (runningSum > rand) { 112 | return dots[i]; 113 | } 114 | } 115 | 116 | //should never get to this point 117 | 118 | return null; 119 | } 120 | 121 | //------------------------------------------------------------------------------------------------------------------------------------------ 122 | //mutates all the brains of the babies 123 | void mutateDemBabies() { 124 | for (int i = 1; i< dots.length; i++) { 125 | dots[i].brain.mutate(); 126 | } 127 | } 128 | 129 | //--------------------------------------------------------------------------------------------------------------------------------------------- 130 | //finds the dot with the highest fitness and sets it as the best dot 131 | void setBestDot() { 132 | float max = 0; 133 | int maxIndex = 0; 134 | for (int i = 0; i< dots.length; i++) { 135 | if (dots[i].fitness > max) { 136 | max = dots[i].fitness; 137 | maxIndex = i; 138 | } 139 | } 140 | 141 | bestDot = maxIndex; 142 | 143 | //if this dot reached the goal then reset the minimum number of steps it takes to get to the goal 144 | if (dots[bestDot].reachedGoal) { 145 | minStep = dots[bestDot].brain.step; 146 | println("step:", minStep); 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Smart-Dots-Genetic-Algorithm-Tutorial 2 | Here is the code for my genetic algorithm tutorial 3 | --------------------------------------------------------------------------------