├── README.md ├── WHG - level2 ├── Brain.js ├── Coin.js ├── Dot.js ├── Node.js ├── Player.js ├── Population.js ├── Solid.js ├── Tile.js ├── assets │ └── DAB.png ├── index.html ├── libraries │ ├── p5.dom.js │ ├── p5.js │ └── p5.sound.js ├── setting_level.js └── sketch.js ├── WHG - level3 ├── Brain.js ├── Coin.js ├── Dot.js ├── Node.js ├── Player.js ├── Population.js ├── Solid.js ├── Tile.js ├── assets │ └── DAB.png ├── index.html ├── libraries │ ├── p5.dom.js │ ├── p5.js │ └── p5.sound.js ├── setting_level.js └── sketch.js └── WHG ├── Brain.js ├── Dot.js ├── Node.js ├── Player.js ├── Population.js ├── Solid.js ├── Tile.js ├── assets └── DAB.png ├── index.html ├── libraries ├── p5.dom.js ├── p5.js └── p5.sound.js ├── setting_level.js └── sketch.js /README.md: -------------------------------------------------------------------------------- 1 | # WorldsHardestGameAI 2 | This is the WHG AI I used in one of my videos, I coded it again in javascript so that you can play it online 3 | -------------------------------------------------------------------------------- /WHG - level2/Brain.js: -------------------------------------------------------------------------------- 1 | class Brain { 2 | constructor(size){ 3 | this.directions = []; 4 | this.step =0; 5 | this.randomize(size); 6 | 7 | } 8 | //-------------------------------------------------------------------------------------------------------------------------------- 9 | //sets all the vectors in directions to a random vector with length 1 10 | randomize(size) { 11 | for (var i = 0; i< size; i++) { 12 | this.directions[i] = this.getRandomDirection(); 13 | } 14 | } 15 | 16 | //--------------------------------------------------------------------------------------------------------------------------------------------------------------- 17 | //returns a random PVector 18 | getRandomDirection() { 19 | var randomNumber = floor(random(9)); 20 | switch(randomNumber) { 21 | case 0: 22 | return createVector(0, 1); 23 | case 1: 24 | return createVector(1, 1); 25 | case 2: 26 | return createVector(1, 0); 27 | case 3: 28 | return createVector(1, -1); 29 | case 4: 30 | return createVector(0, -1); 31 | case 5: 32 | return createVector(-1, -1); 33 | case 6: 34 | return createVector(-1, 0); 35 | case 7: 36 | return createVector(-1, 1); 37 | case 8: 38 | return createVector(0, 0); 39 | } 40 | 41 | return createVector(); 42 | } 43 | 44 | //------------------------------------------------------------------------------------------------------------------------------------- 45 | //returns a perfect copy of this brain object 46 | clone() { 47 | var clone = new Brain(this.directions.length); 48 | for (var i = 0; i < this.directions.length; i++) { 49 | clone.directions[i] = this.directions[i].copy(); 50 | } 51 | return clone; 52 | } 53 | 54 | //---------------------------------------------------------------------------------------------------------------------------------------- 55 | 56 | //mutates the brain by setting some of the directions to random vectors 57 | mutate(died, deathStep) { 58 | //chance that any vector in directions gets changed 59 | for (var i =0; i< this.directions.length; i++) { 60 | var rand = random(1); 61 | if (died && i > deathStep - 10) { 62 | rand = random(0.2); 63 | } 64 | 65 | if (rand < mutationRate) { 66 | //set this direction as a random direction 67 | this.directions[i] = this.getRandomDirection(); 68 | } 69 | } 70 | } 71 | 72 | //--------------------------------------------------------------------------------------------------------------------------------------------------------- 73 | //increases the number of elements in directions by 5 74 | increaseMoves() { 75 | for(var i = 0 ; i< increaseMovesBy ;i++){ 76 | this.directions.push(this.getRandomDirection()); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /WHG - level2/Coin.js: -------------------------------------------------------------------------------- 1 | class Coin{ 2 | constructor(x,y){ 3 | this.taken = false; 4 | this.pos = createVector(x,y); 5 | this.diameter = tileSize/2.0; 6 | } 7 | 8 | show(){ 9 | if(!showedCoin && !this.taken){ 10 | stroke(0); 11 | fill(255,255,0); 12 | ellipse(this.pos.x,this.pos.y,this.diameter); 13 | showedCoin = true; 14 | } 15 | 16 | } 17 | 18 | collides(ptl, pbr) {//player dimensions 19 | if(this.taken){ return false;} 20 | 21 | var topLeft = createVector(this.pos.x - this.diameter/2, this.pos.y-this.diameter/2); 22 | var bottomRight = createVector(this.pos.x + this.diameter/2, this.pos.y + this.diameter/2); 23 | if ((ptl.x topLeft.x) &&( ptl.y < bottomRight.y && pbr.y > topLeft.y)) { 24 | 25 | this.taken = true; 26 | return; 27 | 28 | } 29 | return; 30 | } 31 | 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /WHG - level2/Dot.js: -------------------------------------------------------------------------------- 1 | class Dot { 2 | 3 | constructor( t1, t2, velX,velY) { 4 | this.position = createVector(t1.pixelPos.x + tileSize/2, t1.pixelPos.y + tileSize/2); 5 | this.startingPos = createVector(t1.pixelPos.x + tileSize/2, t1.pixelPos.y + tileSize/2); 6 | this.speed = floor(tileSize/6.6); 7 | this.velocity = createVector(velX*this.speed, velY*this.speed); 8 | this.startingVel = createVector(velX*this.speed, velY*this.speed); 9 | this.bouncers = []; 10 | this.bouncers[0] = t1; 11 | this.bouncers[1] = t2; 12 | this.diameter = tileSize/2.0; 13 | this.bounceWait = -1; 14 | this.bounceTimer = 10; 15 | } 16 | 17 | //------------------------------------------------------------------------------------------------------------ 18 | //moves the dot 19 | move() { 20 | 21 | for (var i = 0; i < this.bouncers.length; i++) { 22 | if (this.bounceTimer < 0 && dist(this.position.x, this.position.y, this.bouncers[i].pixelPos.x + tileSize/2, this.bouncers[i].pixelPos.y + tileSize/2) < this.speed) {//if reached bouncer 23 | this.bounceTimer = 10; 24 | this.bounceWait= 1;//wait 1 frames then change direction 25 | } 26 | } 27 | if (this.bounceWait ==0) { 28 | //change direction 29 | this.velocity.y *= -1; 30 | this.velocity.x *= -1; 31 | 32 | } 33 | 34 | this.position.add(this.velocity);//move dot 35 | this.bounceTimer --; 36 | this.bounceWait --; 37 | } 38 | 39 | //------------------------------------------------------------------------------------------------------------ 40 | //draws the dot 41 | show() { 42 | fill(0, 0, 255); 43 | stroke(0); 44 | strokeWeight(4); 45 | ellipse(this.position.x, this.position.y, this.diameter, this.diameter); 46 | } 47 | 48 | 49 | //------------------------------------------------------------------------------------------------------------ 50 | //returns true of the Pvectors define a square which collides with this dot 51 | collides(ptl, pbr) {//player dimensions 52 | 53 | var topLeft = createVector(this.position.x - this.diameter/2, this.position.y-this.diameter/2); 54 | var bottomRight = createVector(this.position.x + this.diameter/2, this.position.y + this.diameter/2); 55 | var playerSize = bottomRight.x - topLeft.x; 56 | if ((ptl.x topLeft.x) &&( ptl.y < bottomRight.y && pbr.y > topLeft.y)) { 57 | 58 | if (dist(this.position.x, this.position.y, (ptl.x + pbr.x) /2.0, (ptl.y + pbr.y) /2.0)< this.diameter/2 + sqrt(playerSize*playerSize *2)/2) { 59 | return true; 60 | } 61 | } 62 | return false; 63 | } 64 | //------------------------------------------------------------------------------------------------------------ 65 | //returns the dot to its starting state 66 | 67 | resetDot() { 68 | this.position = this.startingPos.copy(); 69 | this.velocity = this.startingVel.copy(); 70 | this.bounceTimer = 10; 71 | this.bounceWait = -1; 72 | } 73 | //------------------------------------------------------------------------------------------------------------ 74 | //returns a copy of this dot object 75 | clone() { 76 | var clone = new Dot(this.bouncers[0], this.bouncers[1], floor(this.velocity.x), floor(this.velocity.y)); 77 | clone.velocity = this.velocity.copy(); 78 | clone.position = this.position.copy(); 79 | clone.startingVel = this.startingVel.copy(); 80 | clone.bounceTimer = this.bounceTimer; 81 | clone.bounceWait = this.bounceWait; 82 | return clone; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /WHG - level2/Node.js: -------------------------------------------------------------------------------- 1 | class Node { //used to define short term goals for the players 2 | //------------------------------------------------------------------------------------------------------------------------------ 3 | constructor(nodeTileOrCoin, isTile, isCoin) { 4 | this.reached = false; 5 | this.distToFinish = 0.0; 6 | this.isCoin = isCoin; 7 | 8 | if(isTile){ 9 | this.pos = createVector(nodeTileOrCoin.pixelPos.x, nodeTileOrCoin.pixelPos.y); 10 | this.w = tileSize; 11 | this.h = tileSize; 12 | }else if(isCoin){ 13 | this.pos = createVector(nodeTileOrCoin.pos.x- nodeTileOrCoin.diameter/2.0, nodeTileOrCoin.pos.y- nodeTileOrCoin.diameter/2.0); 14 | this.w = nodeTileOrCoin.diameter; 15 | this.h = nodeTileOrCoin.diameter; 16 | } 17 | this.bottomRight = createVector(this.pos.x + this.w, this.pos.y + this.h); 18 | 19 | } 20 | 21 | //------------------------------------------------------------------------------------------------------------------------------ 22 | collision( ptl, pbr) {//player dimensions 23 | if ((ptl.x this.pos.x) &&( ptl.y < this.bottomRight.y && pbr.y > this.pos.y)) { 24 | this.reached = true; 25 | return true; 26 | }else if(!this.isCoin && pbr.x < this.pos.x){ 27 | this.reached = false; 28 | 29 | } 30 | return false; 31 | } 32 | //------------------------------------------------------------------------------------------------------------------------------ 33 | //set the distance to finish by adding the distance to the finish for the node n plus the distance from this node to node n 34 | setDistanceToFinish(n) { 35 | this.distToFinish = n.distToFinish + dist(this.pos.x, this.pos.y, n.pos.x, n.pos.y); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /WHG - level2/Player.js: -------------------------------------------------------------------------------- 1 | class Player{ 2 | constructor(){ 3 | this.pos = createVector(3*tileSize + xoff,4* tileSize + yoff); 4 | this.vel = createVector(0,0); 5 | this.size = tileSize/2.0; 6 | this.playerSpeed = tileSize/15.0; 7 | this.dead = false; 8 | this.reachedGoal = false; 9 | this.fadeCounter = 255; 10 | this.isBest = false; 11 | this.deathByDot = false; 12 | this.deathAtStep = 0; 13 | this.moveCount = 0; 14 | this.gen =1; 15 | this.fitness = 0; 16 | this.nodes = []; 17 | this.fading = false; 18 | this.brain = new Brain(numberOfSteps); 19 | this.human = false; 20 | this.coin = new Coin(11*tileSize+xoff, 5*tileSize+yoff); 21 | this.setNodes(); 22 | 23 | } 24 | 25 | setNodes() { 26 | this.nodes[1] = new Node(tiles[19][5],true,false); 27 | this.nodes[0] = new Node(this.coin,false,true); 28 | this.nodes[0].setDistanceToFinish(this.nodes[1]); 29 | } 30 | 31 | show(){ 32 | fill(255, 0, 0, this.fadeCounter); 33 | if (this.isBest && !showBest) { 34 | fill(0, 255, 0, this.fadeCounter); 35 | } 36 | stroke(0, 0, 0, this.fadeCounter); 37 | strokeWeight(4); 38 | rect(this.pos.x, this.pos.y, this.size, this.size); 39 | stroke(0); 40 | this.coin.show(); 41 | } 42 | 43 | move(){ 44 | if (!humanPlaying){ 45 | if (this.moveCount == 0) {//move in the direction for 6 frames 46 | if (this.brain.directions.length > this.brain.step) {//if there are still directions left then set the velocity as the next PVector in the direcitons array 47 | this.vel = this.brain.directions[this.brain.step]; 48 | this.brain.step++; 49 | } else {//if at the end of the directions array then the player is dead 50 | this.dead = true; 51 | this.fading = true; 52 | } 53 | this.moveCount =6; 54 | } else { 55 | this.moveCount--; 56 | } 57 | } 58 | var temp = createVector(this.vel.x, this.vel.y); 59 | temp.normalize(); 60 | temp.mult(this.playerSpeed); 61 | for (var i = 0; i< solids.length; i++) { 62 | temp = solids[i].restrictMovement(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size), temp); 63 | } 64 | this.pos.add(temp); 65 | 66 | } 67 | 68 | //checks if the player 69 | checkCollisions() { 70 | this.coin.collides(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size)); 71 | for (var i = 0; i< dots.length; i++) { 72 | if (dots[i].collides(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size))) { 73 | this.fading = true; 74 | this.dead = true; 75 | this.deathByDot = true; 76 | this.deathAtStep = this.brain.step; 77 | } 78 | } 79 | if (this.coin.taken && winArea.collision(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size))) { 80 | this.reachedGoal = true; 81 | } 82 | for (var i = 0; i< this.nodes.length; i++) { 83 | this.nodes[i].collision(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size)); 84 | } 85 | } 86 | //---------------------------------------------------------------------------------------------------------------------------------------------------------- 87 | update() { 88 | if (!this.dead && !this.reachedGoal) { 89 | this.move(); 90 | this.checkCollisions(); 91 | } else if (this.fading) { 92 | if (this.fadeCounter > 0) { 93 | if(humanPlaying || replayGens){ 94 | this.fadeCounter -=10; 95 | }else{ 96 | this.fadeCounter = 0; 97 | 98 | } 99 | } 100 | } 101 | } 102 | //---------------------------------------------------------------------------------------------------------------------------------------------------------- 103 | 104 | calculateFitness() { 105 | if (this.reachedGoal) {//if the dot reached the goal then the fitness is based on the amount of steps it took to get there 106 | this.fitness = 1.0/16.0 + 10000.0/(this.brain.step * this.brain.step); 107 | } else {//if the dot didn't reach the goal then the fitness is based on how close it is to the goal 108 | var estimatedDistance = 0.0;//the estimated distance of the path from the player to the goal 109 | for (var i = this.nodes.length-1; i>=0; i--) { 110 | if (!this.nodes[i].reached) { 111 | estimatedDistance = this.nodes[i].distToFinish; 112 | estimatedDistance += dist(this.pos.x, this.pos.y, this.nodes[i].pos.x, this.nodes[i].pos.y); 113 | } 114 | } 115 | if (this.deathByDot) { 116 | estimatedDistance *= 0.9; 117 | } 118 | this.fitness = 1.0/(estimatedDistance * estimatedDistance); 119 | } 120 | this.fitness*=this.fitness; 121 | if(this.coin.taken){ 122 | this.fitness *=1.2; 123 | } 124 | } 125 | 126 | 127 | 128 | //---------------------------------------------------------------------------------------------------------------------------------------------------------- 129 | gimmeBaby() { 130 | var baby = new Player(); 131 | baby.brain = this.brain.clone();//babies have the same brain as their parents 132 | baby.deathByDot = this.deathByDot; 133 | baby.deathAtStep = this.deathAtStep; 134 | baby.gen = this.gen; 135 | return baby; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /WHG - level2/Population.js: -------------------------------------------------------------------------------- 1 | class Population { 2 | 3 | constructor(size) { 4 | this.players = []; 5 | this.fitnessSum = 0.0; 6 | this.gen = 1; 7 | this.bestPlayer =0; 8 | this.minStep = 10000; 9 | this.genPlayers = []; 10 | this.bestFitness = 0; 11 | this.solutionFound = false; 12 | 13 | for (var i = 0; i< size; i++) { 14 | this.players[i] = new Player(); 15 | } 16 | } 17 | 18 | 19 | //------------------------------------------------------------------------------------------------------------------------------ 20 | //show all players 21 | show() { 22 | if (!showBest) { 23 | for (var i = 1; i< this.players.length; i++) { 24 | this.players[i].show(); 25 | } 26 | } 27 | this.players[0].show(); 28 | } 29 | 30 | //------------------------------------------------------------------------------------------------------------------------------- 31 | //update all players 32 | update() { 33 | for (var i = 0; i< this.players.length; i++) { 34 | if (this.players[i].brain.step > this.minStep) {//if the player has already taken more steps than the best player has taken to reach the goal 35 | this.players[i].dead = true;//then it dead 36 | } else { 37 | this.players[i].update(); 38 | } 39 | } 40 | } 41 | 42 | //----------------------------------------------------------------------------------------------------------------------------------- 43 | //calculate all the fitnesses 44 | calculateFitness() { 45 | for (var i = 0; i< this.players.length; i++) { 46 | this.players[i].calculateFitness(); 47 | } 48 | } 49 | 50 | 51 | //------------------------------------------------------------------------------------------------------------------------------------ 52 | //returns whether all the players are either dead or have reached the goal 53 | allPlayersDead() { 54 | for (var i = 0; i< this.players.length; i++) { 55 | if (!this.players[i].dead && !this.players[i].reachedGoal) { 56 | return false; 57 | } 58 | } 59 | print("bah:"); 60 | return true; 61 | } 62 | 63 | 64 | 65 | //------------------------------------------------------------------------------------------------------------------------------------- 66 | 67 | //gets the next generation of players 68 | naturalSelection() { 69 | var newPlayers = [];//next gen 70 | this.setBestPlayer(); 71 | this.calculateFitnessSum(); 72 | 73 | //the champion lives on 74 | newPlayers[0] = this.players[this.bestPlayer].gimmeBaby(); 75 | newPlayers[0].isBest = true; 76 | for (var i = 1; i< populationSize; i++) { 77 | //select parent based on fitness 78 | var parent = this.selectParent(); 79 | 80 | //get baby from them 81 | newPlayers[i] = parent.gimmeBaby(); 82 | } 83 | 84 | // this.players = newPlayers.slice(); 85 | this.players = []; 86 | for(var i = 0 ; i< newPlayers.length;i++){ 87 | this.players[i] = newPlayers[i]; 88 | } 89 | this.gen ++; 90 | } 91 | 92 | 93 | //-------------------------------------------------------------------------------------------------------------------------------------- 94 | //you get it 95 | calculateFitnessSum() { 96 | this.fitnessSum = 0; 97 | for (var i = 0; i< this.players.length; i++) { 98 | this.fitnessSum += this.players[i].fitness; 99 | } 100 | } 101 | 102 | //------------------------------------------------------------------------------------------------------------------------------------- 103 | 104 | //chooses player from the population to return randomly(considering fitness) 105 | 106 | //this function works by randomly choosing a value between 0 and the sum of all the fitnesses 107 | //then go through all the players and add their fitness to a running sum and if that sum is greater than the random value generated that player is chosen 108 | //since players with a higher fitness function add more to the running sum then they have a higher chance of being chosen 109 | selectParent() { 110 | var rand = random(this.fitnessSum); 111 | 112 | 113 | var runningSum = 0; 114 | 115 | for (var i = 0; i< this.players.length; i++) { 116 | runningSum+= this.players[i].fitness; 117 | if (runningSum > rand) { 118 | return this.players[i]; 119 | } 120 | } 121 | 122 | //should never get to this point 123 | 124 | return null; 125 | } 126 | 127 | //------------------------------------------------------------------------------------------------------------------------------------------ 128 | //mutates all the brains of the babies 129 | mutateDemBabies() { 130 | for (var i = 1; i< this.players.length; i++) { 131 | this.players[i].brain.mutate(this.players[i].deathByDot, this.players[i].deathAtStep); 132 | this.players[i].deathByDot = false; 133 | this.players[i].gen = this.gen; 134 | } 135 | this.players[0].deathByDot = false; 136 | this.players[0].gen = this.gen; 137 | } 138 | 139 | //--------------------------------------------------------------------------------------------------------------------------------------------- 140 | //finds the player with the highest fitness and sets it as the best player 141 | setBestPlayer() { 142 | var max = 0; 143 | var maxIndex = 0; 144 | for (var i = 0; i< this.players.length; i++) { 145 | if (this.players[i].fitness > max) { 146 | max = this.players[i].fitness; 147 | maxIndex = i; 148 | } 149 | } 150 | 151 | this.bestPlayer = maxIndex; 152 | 153 | if (max > this.bestFitness) { 154 | this.bestFitness = max; 155 | this.genPlayers.push(this.players[this.bestPlayer].gimmeBaby()); 156 | } 157 | 158 | //if this player reached the goal then reset the minimum number of steps it takes to get to the goal 159 | if (this.players[this.bestPlayer].reachedGoal) { 160 | this.minStep = this.players[this.bestPlayer].brain.step; 161 | this.solutionFound = true; 162 | } 163 | } 164 | 165 | 166 | increaseMoves() { 167 | if (this.players[0].brain.directions.length < 120 && !this.solutionFound) { 168 | for (var i = 0; i< this.players.length; i++) { 169 | this.players[i].brain.increaseMoves(); 170 | } 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /WHG - level2/Solid.js: -------------------------------------------------------------------------------- 1 | class Solid { 2 | 3 | constructor(topL,botR){ 4 | var lineWidth = 1; 5 | this.pos = createVector(topL.pixelPos.x-lineWidth, topL.pixelPos.y-lineWidth); 6 | this.w = botR.pixelPos.x + tileSize - this.pos.x + lineWidth; 7 | this.h = botR.pixelPos.y + tileSize - this.pos.y + lineWidth; 8 | this.bottomRight = createVector(this.pos.x + this.w, this.pos.y + this.h); 9 | 10 | } 11 | 12 | 13 | restrictMovement(tl, br, movement) {//player dimensions 14 | //add the x first 15 | 16 | var x = movement.x; 17 | var y = movement.y; 18 | // 19 | // movement.x = round(movement.x); 20 | // movement.y = round(movement.y); 21 | var ptl = createVector(tl.x+movement.x, tl.y); 22 | var pbr = createVector(br.x+movement.x, br.y); 23 | 24 | if ((ptl.x this.pos.x) &&( ptl.y < this.bottomRight.y && pbr.y > this.pos.y)) { 25 | 26 | x=0; 27 | } 28 | 29 | //check the y movement 30 | ptl = createVector(tl.x, tl.y +movement.y); 31 | pbr = createVector(br.x, br.y + movement.y); 32 | if ((ptl.x this.pos.x) &&( ptl.y < this.bottomRight.y && pbr.y > this.pos.y)) { 33 | y=0; 34 | } 35 | 36 | return createVector(x, y); 37 | } 38 | 39 | collision(ptl, pbr) {//player dimensions 40 | //add the x first 41 | 42 | if ((ptl.x this.pos.x) &&( ptl.y < this.bottomRight.y && pbr.y > this.pos.y)) { 43 | return true; 44 | } 45 | return false; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /WHG - level2/Tile.js: -------------------------------------------------------------------------------- 1 | class Tile{ 2 | 3 | constructor(x,y){ 4 | this.matrixPos = createVector(x,y); 5 | this.pixelPos = createVector(x*tileSize+xoff, y*tileSize+yoff); 6 | this.safe = false; 7 | this.goal = false; 8 | this.wall = false; 9 | this.edges = []; 10 | 11 | } 12 | 13 | show(){ 14 | if ((this.matrixPos.x +this.matrixPos.y) % 2 ==0) { 15 | fill(247,247,255); 16 | } else { 17 | fill(230,230,255); 18 | } 19 | if (this.wall) { 20 | fill(180, 181, 254); 21 | } 22 | if (this.goal || this.safe) { 23 | fill(181, 254, 180); 24 | } 25 | noStroke(); 26 | rect(this.pixelPos.x,this.pixelPos.y,tileSize,tileSize); 27 | 28 | } 29 | 30 | showEdges(){ 31 | for (var i = 0; i< this.edges.length; i++) { 32 | stroke(0); 33 | strokeWeight(4); 34 | switch(this.edges[i]) { 35 | case 4: 36 | line(this.pixelPos.x, this.pixelPos.y, this.pixelPos.x+tileSize,this.pixelPos.y); 37 | break; 38 | case 1: 39 | line(this.pixelPos.x+tileSize, this.pixelPos.y, this.pixelPos.x+tileSize, this.pixelPos.y+tileSize); 40 | break; 41 | case 2: 42 | line(this.pixelPos.x, this.pixelPos.y+tileSize, this.pixelPos.x+tileSize, this.pixelPos.y+tileSize); 43 | break; 44 | case 3: 45 | line(this.pixelPos.x, this.pixelPos.y, this.pixelPos.x, this.pixelPos.y+tileSize); 46 | break; 47 | } 48 | } 49 | } 50 | 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /WHG - level2/assets/DAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Code-Bullet/WorldsHardestGameAI/2eb083b238857de88c6a48563cba6df62cb7968f/WHG - level2/assets/DAB.png -------------------------------------------------------------------------------- /WHG - level2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |

hi my name is Evan and this is my thing, I hope you enjoy. Pro Tip: use WASD controls to move the player

22 |

The next level is up Next Level

23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /WHG - level2/setting_level.js: -------------------------------------------------------------------------------- 1 | //functions which setup the level 2 | 3 | function setLevel1Walls() { 4 | tiles[0][0].wall = true; 5 | tiles[0][1].wall = true; 6 | tiles[0][2].wall = true; 7 | tiles[0][3].wall = true; 8 | tiles[0][4].wall = true; 9 | tiles[0][5].wall = true; 10 | tiles[0][6].wall = true; 11 | tiles[0][7].wall = true; 12 | tiles[0][8].wall = true; 13 | tiles[0][9].wall = true; 14 | tiles[1][0].wall = true; 15 | tiles[1][1].wall = true; 16 | tiles[1][2].wall = true; 17 | tiles[1][3].wall = true; 18 | tiles[1][4].wall = true; 19 | tiles[1][5].wall = true; 20 | tiles[1][6].wall = true; 21 | tiles[1][7].wall = true; 22 | tiles[1][8].wall = true; 23 | tiles[1][9].wall = true; 24 | tiles[2][0].wall = true; 25 | tiles[2][1].wall = true; 26 | tiles[2][2].wall = true; 27 | tiles[2][3].wall = true; 28 | tiles[2][6].wall = true; 29 | tiles[2][7].wall = true; 30 | tiles[2][8].wall = true; 31 | tiles[2][9].wall = true; 32 | tiles[3][0].wall = true; 33 | tiles[3][1].wall = true; 34 | tiles[3][2].wall = true; 35 | tiles[3][3].wall = true; 36 | tiles[3][6].wall = true; 37 | tiles[3][7].wall = true; 38 | tiles[3][8].wall = true; 39 | tiles[3][9].wall = true; 40 | tiles[4][0].wall = true; 41 | tiles[4][1].wall = true; 42 | tiles[4][2].wall = true; 43 | tiles[4][3].wall = true; 44 | tiles[4][6].wall = true; 45 | tiles[4][7].wall = true; 46 | tiles[4][8].wall = true; 47 | tiles[4][9].wall = true; 48 | tiles[5][0].wall = true; 49 | tiles[5][1].wall = true; 50 | tiles[5][8].wall = true; 51 | tiles[5][9].wall = true; 52 | tiles[6][0].wall = true; 53 | tiles[6][1].wall = true; 54 | tiles[6][8].wall = true; 55 | tiles[6][9].wall = true; 56 | tiles[7][0].wall = true; 57 | tiles[7][1].wall = true; 58 | tiles[7][8].wall = true; 59 | tiles[7][9].wall = true; 60 | tiles[8][0].wall = true; 61 | tiles[8][1].wall = true; 62 | tiles[8][8].wall = true; 63 | tiles[8][9].wall = true; 64 | tiles[9][0].wall = true; 65 | tiles[9][1].wall = true; 66 | tiles[9][8].wall = true; 67 | tiles[9][9].wall = true; 68 | tiles[10][0].wall = true; 69 | tiles[10][1].wall = true; 70 | tiles[10][8].wall = true; 71 | tiles[10][9].wall = true; 72 | tiles[11][0].wall = true; 73 | tiles[11][1].wall = true; 74 | tiles[11][8].wall = true; 75 | tiles[11][9].wall = true; 76 | tiles[12][0].wall = true; 77 | tiles[12][1].wall = true; 78 | tiles[12][8].wall = true; 79 | tiles[12][9].wall = true; 80 | tiles[13][0].wall = true; 81 | tiles[13][1].wall = true; 82 | tiles[13][8].wall = true; 83 | tiles[13][9].wall = true; 84 | tiles[14][0].wall = true; 85 | tiles[14][1].wall = true; 86 | tiles[14][8].wall = true; 87 | tiles[14][9].wall = true; 88 | tiles[15][0].wall = true; 89 | tiles[15][1].wall = true; 90 | tiles[15][8].wall = true; 91 | tiles[15][9].wall = true; 92 | tiles[16][0].wall = true; 93 | tiles[16][1].wall = true; 94 | tiles[16][8].wall = true; 95 | tiles[16][9].wall = true; 96 | tiles[17][0].wall = true; 97 | tiles[17][1].wall = true; 98 | tiles[17][2].wall = true; 99 | tiles[17][3].wall = true; 100 | tiles[17][6].wall = true; 101 | tiles[17][7].wall = true; 102 | tiles[17][8].wall = true; 103 | tiles[17][9].wall = true; 104 | tiles[18][0].wall = true; 105 | tiles[18][1].wall = true; 106 | tiles[18][2].wall = true; 107 | tiles[18][3].wall = true; 108 | tiles[18][6].wall = true; 109 | tiles[18][7].wall = true; 110 | tiles[18][8].wall = true; 111 | tiles[18][9].wall = true; 112 | tiles[19][0].wall = true; 113 | tiles[19][1].wall = true; 114 | tiles[19][2].wall = true; 115 | tiles[19][3].wall = true; 116 | tiles[19][6].wall = true; 117 | tiles[19][7].wall = true; 118 | tiles[19][8].wall = true; 119 | tiles[19][9].wall = true; 120 | tiles[20][0].wall = true; 121 | tiles[20][1].wall = true; 122 | tiles[20][2].wall = true; 123 | tiles[20][3].wall = true; 124 | tiles[20][4].wall = true; 125 | tiles[20][5].wall = true; 126 | tiles[20][6].wall = true; 127 | tiles[20][7].wall = true; 128 | tiles[20][8].wall = true; 129 | tiles[20][9].wall = true; 130 | tiles[21][0].wall = true; 131 | tiles[21][1].wall = true; 132 | tiles[21][2].wall = true; 133 | tiles[21][3].wall = true; 134 | tiles[21][4].wall = true; 135 | tiles[21][5].wall = true; 136 | tiles[21][6].wall = true; 137 | tiles[21][7].wall = true; 138 | tiles[21][8].wall = true; 139 | tiles[21][9].wall = true; 140 | 141 | } 142 | 143 | 144 | function setLevel2Goal() { 145 | tiles[17][4].goal = true; 146 | tiles[17][5].goal = true; 147 | tiles[18][4].goal = true; 148 | tiles[18][5].goal = true; 149 | tiles[19][4].goal = true; 150 | tiles[19][5].goal = true; 151 | } 152 | 153 | function setLevel1SafeArea() { 154 | tiles[2][4].safe = true; 155 | tiles[2][5].safe = true; 156 | tiles[3][4].safe = true; 157 | tiles[3][5].safe = true; 158 | tiles[4][4].safe = true; 159 | tiles[4][5].safe = true; 160 | } 161 | 162 | 163 | function setEdges() { 164 | for (var i = 1; i< tiles.length-1; i++) { 165 | for (var j = 1; j< tiles[0].length-1; j++) { 166 | if (tiles[i][j].wall) { 167 | if (!tiles[i+1][j].wall) { 168 | tiles[i][j].edges.push(1); 169 | } 170 | if (!tiles[i][j+1].wall) { 171 | tiles[i][j].edges.push(2); 172 | } 173 | if (!tiles[i-1][j].wall) { 174 | tiles[i][j].edges.push(3); 175 | } 176 | if (!tiles[i][j-1].wall) { 177 | tiles[i][j].edges.push(4); 178 | } 179 | } 180 | } 181 | } 182 | } 183 | 184 | 185 | function setDots() { 186 | 187 | dots.push(new Dot(tiles[5][2],tiles[5][7], 0, 1)); 188 | dots.push(new Dot(tiles[6][7],tiles[6][2], 0, -1)); 189 | dots.push(new Dot(tiles[7][2],tiles[7][7], 0, 1)); 190 | dots.push(new Dot(tiles[8][7],tiles[8][2], 0, -1)); 191 | dots.push(new Dot(tiles[9][2],tiles[9][7], 0, 1)); 192 | dots.push(new Dot(tiles[10][7],tiles[10][2], 0, -1)); 193 | dots.push(new Dot(tiles[11][2],tiles[11][7], 0, 1)); 194 | dots.push(new Dot(tiles[12][7],tiles[12][2], 0, -1)); 195 | dots.push(new Dot(tiles[13][2],tiles[13][7], 0, 1)); 196 | dots.push(new Dot(tiles[14][7],tiles[14][2], 0, -1)); 197 | dots.push(new Dot(tiles[15][2],tiles[15][7], 0, 1)); 198 | dots.push(new Dot(tiles[16][7],tiles[16][2], 0, -1)); 199 | } 200 | 201 | 202 | function setSolids() { 203 | solids.push(new Solid(tiles[1][6],tiles[4][8])); 204 | solids.push(new Solid(tiles[4][8],tiles[17][8])); 205 | solids.push(new Solid(tiles[17][6],tiles[20][8])); 206 | solids.push(new Solid(tiles[20][3],tiles[20][6])); 207 | solids.push(new Solid(tiles[17][1],tiles[20][3])); 208 | solids.push(new Solid(tiles[4][1],tiles[17][1])); 209 | solids.push(new Solid(tiles[1][1],tiles[4][3])); 210 | solids.push(new Solid(tiles[1][3],tiles[1][6])); 211 | } 212 | -------------------------------------------------------------------------------- /WHG - level2/sketch.js: -------------------------------------------------------------------------------- 1 | var tileSize = 50; 2 | var xoff = 80; 3 | var yoff = 100; 4 | 5 | //human playing vars 6 | var humanPlaying = false; 7 | var left = false; 8 | var right = false; 9 | var up = false; 10 | var down = false; 11 | var p; 12 | 13 | //arrays 14 | var tiles = []; 15 | var solids = []; 16 | var dots = []; 17 | var savedDots = []; 18 | 19 | var showBest = false; 20 | 21 | var winArea;//a solid which is the win zone i.e. the green bits 22 | 23 | //gen replay vars 24 | var replayGens = false; 25 | var genPlayer; 26 | var upToGenPos = 0; 27 | 28 | //population vars 29 | var numberOfSteps = 10; 30 | var testPopulation; 31 | 32 | var winCounter = -1; 33 | 34 | var img; 35 | var flip = true; 36 | 37 | //population size vars 38 | var populationSize = 500; 39 | var popPara; 40 | var popPlus; 41 | var popMinus; 42 | 43 | //mutation rate vars 44 | var mutationRate = 0.01; 45 | var mrPara; 46 | var mrPlus; 47 | var mrMinus; 48 | 49 | //evolution speed vars 50 | var evolutionSpeed =1; 51 | var speedPara; 52 | var speedPlus; 53 | var speedMinus; 54 | 55 | //increaseMoves 56 | var movesH3; 57 | 58 | var increaseMovesBy =5; 59 | var movesPara; 60 | var movesPlus; 61 | var movesMinus; 62 | 63 | var increaseEvery =5; 64 | var everyPara; 65 | var everyPlus; 66 | var everyMinus; 67 | 68 | var firstClick = true; 69 | var showedCoin = false; 70 | 71 | function setup() { 72 | var canvas = createCanvas(1280,720); 73 | htmlStuff(); 74 | for (var i = 0; i< 22; i++) { 75 | tiles[i] = []; 76 | for (var j = 0; j< 10; j++) { 77 | tiles[i][j] = new Tile(i, j); 78 | } 79 | } 80 | 81 | setLevel1Walls(); 82 | setLevel2Goal(); 83 | setLevel1SafeArea(); 84 | setEdges(); 85 | setSolids(); 86 | 87 | p = new Player(); 88 | setDots(); 89 | winArea = new Solid(tiles[17][2], tiles[19][7]); 90 | testPopulation = new Population(populationSize); 91 | img = loadImage("assets/DAB.png"); 92 | //prevents the window from moving from the arrow keys or the spacebar 93 | window.addEventListener("keydown", function(e) { 94 | // space and arrow keys 95 | if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) { 96 | e.preventDefault(); 97 | } 98 | }, false); 99 | } 100 | 101 | function draw(){ 102 | showedCoin = false; 103 | 104 | background(180, 181, 254); 105 | drawTiles(); 106 | writeShit(); 107 | 108 | 109 | if (humanPlaying) {//if the user is controlling the square 110 | if ((p.dead && p.fadeCounter<=0) || p.reachedGoal) { 111 | //reset player and dots 112 | if(p.reachedGoal){ 113 | winCounter = 100; 114 | 115 | } 116 | p = new Player(); 117 | p.human = true; 118 | resetDots(); 119 | 120 | } else { 121 | //update the dots and the players and show them to the screen 122 | 123 | 124 | moveAndShowDots(); 125 | 126 | p.update(); 127 | p.show(); 128 | } 129 | } else 130 | if (replayGens) {//if replaying the best generations 131 | if ((genPlayer.dead && genPlayer.fadeCounter <=0) || genPlayer.reachedGoal) { //if the current gen is done 132 | upToGenPos ++;//next gen 133 | if (testPopulation.genPlayers.length <= upToGenPos) {//if reached the final gen 134 | //stop replaying gens 135 | upToGenPos = 0; 136 | replayGens = false; 137 | //return the dots to their saved position 138 | 139 | loadDots(); 140 | } else {//if there are more generations to show 141 | //set gen player as the best player of that generation 142 | genPlayer = testPopulation.genPlayers[upToGenPos].gimmeBaby(); 143 | //reset the dots positions 144 | resetDots(); 145 | } 146 | } else {//if not done 147 | //move and show dots 148 | moveAndShowDots(); 149 | //move and update player 150 | genPlayer.update(); 151 | genPlayer.show(); 152 | } 153 | } else//if training normaly 154 | if (testPopulation.allPlayersDead()) { 155 | //genetic algorithm 156 | testPopulation.calculateFitness(); 157 | testPopulation.naturalSelection(); 158 | testPopulation.mutateDemBabies(); 159 | //reset dots 160 | resetDots(); 161 | 162 | //every 5 generations incease the number of moves by 5 163 | if (testPopulation.gen % increaseEvery ==0) { 164 | testPopulation.increaseMoves(); 165 | } 166 | 167 | } else { 168 | 169 | // moveAndShowDots(); 170 | //update and show population 171 | 172 | for(var j = 0 ; j< evolutionSpeed; j++){ 173 | for (var i = 0; i < dots.length; i ++) { 174 | dots[i].move(); 175 | } 176 | testPopulation.update(); 177 | } 178 | 179 | for (var i = 0; i < dots.length; i ++) { 180 | dots[i].show(); 181 | } 182 | testPopulation.show(); 183 | } 184 | 185 | } 186 | function moveAndShowDots(){ 187 | for (var i = 0; i < dots.length; i ++) { 188 | dots[i].move(); 189 | dots[i].show(); 190 | } 191 | 192 | } 193 | function resetDots(){ 194 | for (var i = 0; i < dots.length; i ++) { 195 | dots[i].resetDot(); 196 | } 197 | 198 | } 199 | function drawTiles(){ 200 | for (var i = 0; i< tiles.length; i++) { 201 | for (var j = 0; j< tiles[0].length; j++) { 202 | tiles[i][j].show(); 203 | } 204 | } 205 | for (var i = 0; i< tiles.length; i++) { 206 | for (var j = 0; j< tiles[0].length; j++) { 207 | tiles[i][j].showEdges(); 208 | } 209 | } 210 | } 211 | 212 | function loadDots(){ 213 | for (var i = 0; i< dots.length; i++) { 214 | dots[i] = savedDots[i].clone(); 215 | } 216 | } 217 | 218 | function saveDots(){ 219 | for (var i = 0; i< dots.length; i++) { 220 | savedDots[i] = dots[i].clone(); 221 | } 222 | } 223 | 224 | function writeShit(){ 225 | 226 | fill(247, 247, 255); 227 | textSize(20); 228 | noStroke(); 229 | text(" \tPress P to play the game yourself \t\t\t\t\t\t\t\t Press G to replay evolution highlights",250,620 ); 230 | text("Press SPACE to only show the best player", 450,680); 231 | textSize(36); 232 | if(winCounter > 0){ 233 | 234 | if(flip){ 235 | push(); 236 | 237 | scale(-1.0,1.0); 238 | image(img,-300 -img.width + random(5),100+ random(5)); 239 | pop(); 240 | }else{ 241 | image(img,300+ random(5),100 + random(5)); 242 | } 243 | textSize(100); 244 | stroke(0); 245 | 246 | text(" OH YEAH BABYYYYYYYY", 110,400); 247 | winCounter --; 248 | if(winCounter % 10 ==0){ 249 | 250 | flip = !flip; 251 | } 252 | textSize(36); 253 | noStroke(); 254 | } 255 | if (replayGens) { 256 | text("Generation: " + genPlayer.gen, 200, 90); 257 | text("Number of moves: " + genPlayer.brain.directions.length, 700, 90); 258 | } else if(!humanPlaying) { 259 | text("Generation: " + testPopulation.gen, 200, 90); 260 | if(testPopulation.solutionFound){ 261 | text("Wins in " + testPopulation.minStep + " moves",700, 90); 262 | }else{ 263 | text("Number of moves: " + testPopulation.players[0].brain.directions.length, 700, 90); 264 | } 265 | }else{ 266 | text("Have Fun ;)", 500,90); 267 | } 268 | } 269 | function keyPressed(){ 270 | if(humanPlaying){ 271 | switch(keyCode) { 272 | case UP_ARROW: 273 | up = true; 274 | break; 275 | case DOWN_ARROW: 276 | down = true; 277 | break; 278 | case RIGHT_ARROW: 279 | right = true; 280 | break; 281 | case LEFT_ARROW: 282 | left = true; 283 | break; 284 | } 285 | switch(key){ 286 | case 'W': 287 | up = true; 288 | break; 289 | case 'S': 290 | down = true; 291 | break; 292 | case 'D': 293 | right = true; 294 | break; 295 | case 'A': 296 | left = true; 297 | break; 298 | } 299 | setPlayerVelocity(); 300 | }else{//if human is not playing 301 | switch(key) { 302 | case ' ': 303 | showBest = !showBest; 304 | for (var i = 0; i< tiles.length; i++) { 305 | for (var j = 0; j< tiles[0].length; j++) { 306 | if(tiles[i][j].wall){ 307 | print("tiles["+ i+ "][" + j +"].wall = true;")//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<, 308 | } 309 | // if(tiles[i][j].goal){ 310 | // print("tiles["+ i+ "][" + j +"].goal = true;")//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<, 311 | // } 312 | // if(tiles[i][j].safe){ 313 | // print("tiles["+ i+ "][" + j +"].safe = true;")//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<, 314 | // } 315 | } 316 | } 317 | break; 318 | case 'G'://replay gens 319 | if (replayGens) { 320 | upToGenPos = 0; 321 | replayGens = false; 322 | loadDots(); 323 | } else 324 | if (testPopulation.genPlayers.length > 0) { 325 | replayGens = true; 326 | genPlayer = testPopulation.genPlayers[0].gimmeBaby(); 327 | saveDots(); 328 | resetDots(); 329 | } 330 | break; 331 | } 332 | } 333 | 334 | if(key == 'P'){ 335 | if (humanPlaying) {//if human is currently playing 336 | 337 | //reset dots to position 338 | humanPlaying = false; 339 | loadDots(); 340 | } else {//if AI is currently playing 341 | if (replayGens) { 342 | upToGenPos = 0; 343 | replayGens = false; 344 | } 345 | humanPlaying = true; 346 | p = new Player(); 347 | p.human = true; 348 | //save the positions of the dots 349 | saveDots(); 350 | resetDots(); 351 | } 352 | } 353 | } 354 | 355 | 356 | function keyReleased(){ 357 | if(humanPlaying){ 358 | switch(keyCode) { 359 | case UP_ARROW: 360 | up = false; 361 | break; 362 | case DOWN_ARROW: 363 | down = false; 364 | break; 365 | case RIGHT_ARROW: 366 | right = false; 367 | break; 368 | case LEFT_ARROW: 369 | left = false; 370 | break; 371 | } 372 | switch(key){ 373 | case 'W': 374 | up = false; 375 | break; 376 | case 'S': 377 | down = false; 378 | break; 379 | case 'D': 380 | right = false; 381 | break; 382 | case 'A': 383 | left = false; 384 | break; 385 | } 386 | 387 | setPlayerVelocity(); 388 | } 389 | 390 | } 391 | //set the velocity of the player based on what keys are currently down 392 | 393 | function setPlayerVelocity(){ 394 | p.vel.y= 0; 395 | if (up) { 396 | p.vel.y -=1; 397 | } 398 | if (down) { 399 | p.vel.y +=1; 400 | } 401 | p.vel.x= 0; 402 | if (left) { 403 | p.vel.x -=1; 404 | } 405 | if (right) { 406 | p.vel.x +=1; 407 | } 408 | 409 | } 410 | //--------------------------------------------------------------------------------------------------------------------- 411 | function htmlStuff(){ 412 | createElement("h2", "Change Values") 413 | createP("here are some values you can play with, sure it's not sexy but it does the job") 414 | popPara = createDiv("Population Size: " + populationSize); 415 | popMinus = createButton("-"); 416 | popPlus = createButton('+'); 417 | 418 | popPlus.mousePressed(plusPopSize); 419 | popMinus.mousePressed(minusPopSize); 420 | 421 | mrPara = createDiv("Mutation Rate: " + mutationRate); 422 | mrMinus = createButton("1/2"); 423 | mrPlus = createButton('x2'); 424 | mrPlus.mousePressed(plusmr); 425 | mrMinus.mousePressed(minusmr); 426 | 427 | speedPara = createDiv("Evolution Player Speed: " + evolutionSpeed); 428 | speedMinus = createButton("-"); 429 | speedPlus = createButton('+'); 430 | speedPlus.mousePressed(plusSpeed); 431 | speedMinus.mousePressed(minusSpeed); 432 | 433 | movesH3 = createElement("h4", "Increase number of player moves by " + increaseMovesBy + " every " + increaseEvery + " generations"); 434 | movesPara = createDiv("Increase moves by: " + increaseMovesBy); 435 | movesMinus = createButton("-"); 436 | movesPlus = createButton('+'); 437 | movesPlus.mousePressed(plusMoves); 438 | movesMinus.mousePressed(minusMoves); 439 | everyPara = createDiv("Increase every " + increaseEvery + " generations"); 440 | everyMinus = createButton("-"); 441 | everyPlus = createButton('+'); 442 | everyPlus.mousePressed(plusEvery); 443 | everyMinus.mousePressed(minusEvery); 444 | } 445 | 446 | function minusPopSize(){ 447 | if(populationSize > 100){ 448 | populationSize -=100; 449 | popPara.html("Population Size: " + populationSize); 450 | } 451 | } 452 | function plusPopSize(){ 453 | if(populationSize < 10000){ 454 | populationSize +=100; 455 | popPara.html("Population Size: " + populationSize); 456 | 457 | } 458 | } 459 | 460 | function minusmr(){ 461 | if(mutationRate > 0.0001){ 462 | mutationRate /= 2.0; 463 | mrPara.html("Mutation Rate: " + mutationRate); 464 | } 465 | } 466 | function plusmr(){ 467 | if(mutationRate <= 0.5){ 468 | mutationRate *= 2.0; 469 | mrPara.html("Mutation Rate: " + mutationRate); 470 | 471 | } 472 | } 473 | 474 | function minusSpeed(){ 475 | if(evolutionSpeed > 1){ 476 | evolutionSpeed -= 1; 477 | speedPara.html("Evolution Player Speed: " + evolutionSpeed); 478 | } 479 | } 480 | function plusSpeed(){ 481 | if(evolutionSpeed <= 5){ 482 | evolutionSpeed += 1; 483 | speedPara.html("Evolution Player Speed: " + evolutionSpeed); 484 | 485 | } 486 | } 487 | 488 | 489 | function minusMoves(){ 490 | if(increaseMovesBy >= 1){ 491 | increaseMovesBy -= 1; 492 | movesPara.html("Increase moves by: " + increaseMovesBy); 493 | movesH3.html("Increase number of player moves by " + increaseMovesBy + " every " + increaseEvery + " generations"); 494 | } 495 | } 496 | function plusMoves(){ 497 | if(increaseMovesBy <= 500){ 498 | increaseMovesBy += 1; 499 | movesPara.html("Increase moves by: " + increaseMovesBy); 500 | movesH3.html("Increase number of player moves by " + increaseMovesBy + " every " + increaseEvery + " generations"); 501 | } 502 | } 503 | 504 | function minusEvery(){ 505 | if(increaseEvery > 1){ 506 | increaseEvery -= 1; 507 | everyPara.html("Increase every " + increaseEvery + " generations"); 508 | movesH3.html("Increase number of player moves by " + increaseMovesBy + " every " + increaseEvery + " generations"); 509 | } 510 | } 511 | function plusEvery(){ 512 | if(increaseEvery <= 100){ 513 | increaseEvery += 1; 514 | everyPara.html("Increase every " + increaseEvery + " generations"); 515 | movesH3.html("Increase number of player moves by " + increaseMovesBy + " every " + increaseEvery + " generations"); 516 | } 517 | } 518 | 519 | //-------------------------------------------------------------------------------------------------------------------------------- 520 | //this just prints the coordinates of the tile which is clicked, usefull for level building 521 | // function mousePressed() { 522 | 523 | // var x = floor((mouseX - xoff )/tileSize); 524 | // var y = floor((mouseY - yoff )/tileSize); 525 | 526 | // tiles[x][y].wall = !tiles[x][y].wall; 527 | // // tiles[x][y].safe = !tiles[x][y].safe; 528 | // // tiles[x][y].safe = !tiles[x][y].safe; 529 | 530 | // //define solids 531 | // // if(firstClick){ 532 | // // print("solids.push(new Solid(tiles[" + x + "]["+ y + "],"); 533 | // // }else{ 534 | // // print("tiles[" + x + "]["+ y + "]));"); 535 | // // } 536 | // // firstClick = !firstClick; 537 | 538 | // print("tiles[" + x + "]["+ y + "],"); 539 | 540 | // // define dots 541 | // // if(firstClick){ 542 | // // print("dots.push(new Dot(tiles[" + x + "]["+ y + "],"); 543 | // // }else{ 544 | // // print("tiles[" + x + "]["+ y + "], 0, 1));"); 545 | // // } 546 | // // 547 | // // firstClick = !firstClick; 548 | // // dots.push(new Dot(tiles[15][6], tiles[6][6], -1)); 549 | 550 | // } 551 | -------------------------------------------------------------------------------- /WHG - level3/Brain.js: -------------------------------------------------------------------------------- 1 | class Brain { 2 | constructor(size){ 3 | this.directions = []; 4 | this.step =0; 5 | this.randomize(size); 6 | 7 | } 8 | //-------------------------------------------------------------------------------------------------------------------------------- 9 | //sets all the vectors in directions to a random vector with length 1 10 | randomize(size) { 11 | for (var i = 0; i< size; i++) { 12 | this.directions[i] = this.getRandomDirection(); 13 | } 14 | } 15 | 16 | //--------------------------------------------------------------------------------------------------------------------------------------------------------------- 17 | //returns a random PVector 18 | getRandomDirection() { 19 | var randomNumber = floor(random(9)); 20 | switch(randomNumber) { 21 | case 0: 22 | return createVector(0, 1); 23 | case 1: 24 | return createVector(1, 1); 25 | case 2: 26 | return createVector(1, 0); 27 | case 3: 28 | return createVector(1, -1); 29 | case 4: 30 | return createVector(0, -1); 31 | case 5: 32 | return createVector(-1, -1); 33 | case 6: 34 | return createVector(-1, 0); 35 | case 7: 36 | return createVector(-1, 1); 37 | case 8: 38 | return createVector(0, 0); 39 | } 40 | 41 | return createVector(); 42 | } 43 | 44 | //------------------------------------------------------------------------------------------------------------------------------------- 45 | //returns a perfect copy of this brain object 46 | clone() { 47 | var clone = new Brain(this.directions.length); 48 | for (var i = 0; i < this.directions.length; i++) { 49 | clone.directions[i] = this.directions[i].copy(); 50 | } 51 | return clone; 52 | } 53 | 54 | //---------------------------------------------------------------------------------------------------------------------------------------- 55 | 56 | //mutates the brain by setting some of the directions to random vectors 57 | mutate(died, deathStep) { 58 | //chance that any vector in directions gets changed 59 | for (var i =0; i< this.directions.length; i++) { 60 | var rand = random(1); 61 | if (died && i > deathStep - 10) { 62 | rand = random(0.2); 63 | } 64 | 65 | if (rand < mutationRate) { 66 | //set this direction as a random direction 67 | this.directions[i] = this.getRandomDirection(); 68 | } 69 | } 70 | } 71 | 72 | //--------------------------------------------------------------------------------------------------------------------------------------------------------- 73 | //increases the number of elements in directions by 5 74 | increaseMoves() { 75 | for(var i = 0 ; i< increaseMovesBy ;i++){ 76 | this.directions.push(this.getRandomDirection()); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /WHG - level3/Coin.js: -------------------------------------------------------------------------------- 1 | class Coin{ 2 | constructor(x,y){ 3 | this.taken = false; 4 | this.pos = createVector(x,y); 5 | this.diameter = tileSize/2.0; 6 | } 7 | 8 | show(){ 9 | if(!showedCoin && !this.taken){ 10 | stroke(0); 11 | fill(255,255,0); 12 | ellipse(this.pos.x,this.pos.y,this.diameter); 13 | showedCoin = true; 14 | } 15 | 16 | } 17 | 18 | collides(ptl, pbr) {//player dimensions 19 | if(this.taken){ return false;} 20 | 21 | var topLeft = createVector(this.pos.x - this.diameter/2, this.pos.y-this.diameter/2); 22 | var bottomRight = createVector(this.pos.x + this.diameter/2, this.pos.y + this.diameter/2); 23 | if ((ptl.x topLeft.x) &&( ptl.y < bottomRight.y && pbr.y > topLeft.y)) { 24 | 25 | this.taken = true; 26 | return; 27 | 28 | } 29 | return; 30 | } 31 | 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /WHG - level3/Dot.js: -------------------------------------------------------------------------------- 1 | class Dot { 2 | 3 | constructor( t1, t2, t3, t4,startingTile,velX,velY) { 4 | this.position = createVector(startingTile.pixelPos.x + tileSize/2, startingTile.pixelPos.y + tileSize/2); 5 | this.startingPos = createVector(startingTile.pixelPos.x + tileSize/2, startingTile.pixelPos.y + tileSize/2); 6 | this.speed = tileSize/15.0; 7 | this.velocity = createVector(velX*this.speed, velY*this.speed); 8 | this.startingVel = createVector(velX*this.speed, velY*this.speed); 9 | 10 | this.startingTile = startingTile; 11 | 12 | this.bouncers = []; 13 | this.bouncers[0] = t1; 14 | this.bouncers[1] = t2; 15 | this.bouncers[2] = t3; 16 | this.bouncers[3] = t4; 17 | 18 | this.diameter = tileSize/2.0; 19 | this.bounceWait = -1; 20 | this.bounceTimer = -1; 21 | } 22 | 23 | //------------------------------------------------------------------------------------------------------------ 24 | //moves the dot 25 | move() { 26 | 27 | for (var i = 0; i < this.bouncers.length; i++) { 28 | if (this.bounceTimer<0 && dist(this.position.x, this.position.y, this.bouncers[i].pixelPos.x + tileSize/2, this.bouncers[i].pixelPos.y + tileSize/2) < 0.01) {//if reached bouncer 29 | this.bounceTimer = 5; 30 | // this.bounceWait= 1;//wait 1 frames then change direction 31 | this.turnDotRight(); 32 | break; 33 | } 34 | } 35 | // if (this.bounceWait ==0) { 36 | // //change direction 37 | // this.velocity.y *= -1; 38 | // this.velocity.x *= -1; 39 | // 40 | // } 41 | 42 | this.position.add(this.velocity);//move dot 43 | this.bounceTimer --; 44 | this.bounceWait --; 45 | } 46 | turnDotRight(){ 47 | if(this.velocity.x > 0 && this.velocity.y == 0){ 48 | this.velocity = createVector(0,1.0*this.speed); 49 | }else if(this.velocity.x ==0 && this.velocity.y >0){ 50 | this.velocity = createVector(-1.0*this.speed,0); 51 | }else if(this.velocity.x <0 && this.velocity.y ==0){ 52 | this.velocity = createVector(0,-1.0*this.speed); 53 | }else if(this.velocity.x ==0 && this.velocity.y < 0){ 54 | this.velocity = createVector(1.0*this.speed,0); 55 | } 56 | 57 | } 58 | //------------------------------------------------------------------------------------------------------------ 59 | //draws the dot 60 | show() { 61 | fill(0, 0, 255); 62 | stroke(0); 63 | strokeWeight(4); 64 | ellipse(this.position.x, this.position.y, this.diameter, this.diameter); 65 | } 66 | 67 | 68 | //------------------------------------------------------------------------------------------------------------ 69 | //returns true of the Pvectors define a square which collides with this dot 70 | collides(ptl, pbr) {//player dimensions 71 | 72 | var topLeft = createVector(this.position.x - this.diameter/2, this.position.y-this.diameter/2); 73 | var bottomRight = createVector(this.position.x + this.diameter/2, this.position.y + this.diameter/2); 74 | var playerSize = bottomRight.x - topLeft.x; 75 | if ((ptl.x topLeft.x) &&( ptl.y < bottomRight.y && pbr.y > topLeft.y)) { 76 | 77 | if (dist(this.position.x, this.position.y, (ptl.x + pbr.x) /2.0, (ptl.y + pbr.y) /2.0)< this.diameter/2 + sqrt(playerSize*playerSize *2)/2) { 78 | return true; 79 | } 80 | } 81 | return false; 82 | } 83 | //------------------------------------------------------------------------------------------------------------ 84 | //returns the dot to its starting state 85 | 86 | resetDot() { 87 | this.position = this.startingPos.copy(); 88 | this.velocity = this.startingVel.copy(); 89 | this.bounceTimer = -1; 90 | this.bounceWait = -1; 91 | } 92 | //------------------------------------------------------------------------------------------------------------ 93 | //returns a copy of this dot object 94 | clone() { 95 | var clone = new Dot(this.bouncers[0], this.bouncers[1],this.bouncers[2], this.bouncers[3], this.startingTile, floor(this.velocity.x), floor(this.velocity.y)); 96 | clone.velocity = this.velocity.copy(); 97 | clone.position = this.position.copy(); 98 | clone.startingVel = this.startingVel.copy(); 99 | clone.bounceTimer = this.bounceTimer; 100 | clone.bounceWait = this.bounceWait; 101 | return clone; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /WHG - level3/Node.js: -------------------------------------------------------------------------------- 1 | class Node { //used to define short term goals for the players 2 | //------------------------------------------------------------------------------------------------------------------------------ 3 | constructor(nodeTileOrCoin, isTile, isCoin) { 4 | this.reached = false; 5 | this.distToFinish = 0.0; 6 | this.isCoin = isCoin; 7 | 8 | if(isTile){ 9 | this.pos = createVector(nodeTileOrCoin.pixelPos.x, nodeTileOrCoin.pixelPos.y); 10 | this.w = tileSize; 11 | this.h = tileSize; 12 | }else if(isCoin){ 13 | this.pos = createVector(nodeTileOrCoin.pos.x- nodeTileOrCoin.diameter/2.0, nodeTileOrCoin.pos.y- nodeTileOrCoin.diameter/2.0); 14 | this.w = nodeTileOrCoin.diameter; 15 | this.h = nodeTileOrCoin.diameter; 16 | } 17 | this.bottomRight = createVector(this.pos.x + this.w, this.pos.y + this.h); 18 | 19 | } 20 | 21 | //------------------------------------------------------------------------------------------------------------------------------ 22 | collision( ptl, pbr) {//player dimensions 23 | if ((ptl.x this.pos.x) &&( ptl.y < this.bottomRight.y && pbr.y > this.pos.y)) { 24 | this.reached = true; 25 | return true; 26 | }else if(!this.isCoin && pbr.x < this.pos.x){ 27 | this.reached = false; 28 | 29 | } 30 | return false; 31 | } 32 | //------------------------------------------------------------------------------------------------------------------------------ 33 | //set the distance to finish by adding the distance to the finish for the node n plus the distance from this node to node n 34 | setDistanceToFinish(n) { 35 | this.distToFinish = n.distToFinish + dist(this.pos.x, this.pos.y, n.pos.x, n.pos.y); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /WHG - level3/Player.js: -------------------------------------------------------------------------------- 1 | class Player{ 2 | constructor(){ 3 | this.pos = createVector(11*tileSize + xoff,5* tileSize + yoff); 4 | this.vel = createVector(0,0); 5 | this.size = tileSize/2.0; 6 | this.playerSpeed = tileSize/15.0; 7 | this.dead = false; 8 | this.reachedGoal = false; 9 | this.fadeCounter = 255; 10 | this.isBest = false; 11 | this.deathByDot = false; 12 | this.deathAtStep = 0; 13 | this.moveCount = 0; 14 | this.gen =1; 15 | this.fitness = 0; 16 | this.nodes = []; 17 | this.fading = false; 18 | this.brain = new Brain(numberOfSteps); 19 | this.human = false; 20 | this.coin = new Coin(9.5*tileSize+xoff, 2.5*tileSize+yoff); 21 | this.setNodes(); 22 | 23 | } 24 | 25 | setNodes() { 26 | this.nodes[1] = new Node(tiles[11][5],true,false); 27 | this.nodes[0] = new Node(this.coin,false,true); 28 | this.nodes[0].setDistanceToFinish(this.nodes[1]); 29 | } 30 | 31 | show(){ 32 | fill(255, 0, 0, this.fadeCounter); 33 | if (this.isBest && !showBest) { 34 | fill(0, 255, 0, this.fadeCounter); 35 | } 36 | stroke(0, 0, 0, this.fadeCounter); 37 | strokeWeight(4); 38 | rect(this.pos.x, this.pos.y, this.size, this.size); 39 | stroke(0); 40 | this.coin.show(); 41 | } 42 | 43 | move(){ 44 | if (!humanPlaying){ 45 | if (this.moveCount == 0) {//move in the direction for 6 frames 46 | if (this.brain.directions.length > this.brain.step) {//if there are still directions left then set the velocity as the next PVector in the direcitons array 47 | this.vel = this.brain.directions[this.brain.step]; 48 | this.brain.step++; 49 | } else {//if at the end of the directions array then the player is dead 50 | this.dead = true; 51 | this.fading = true; 52 | } 53 | this.moveCount =6; 54 | } else { 55 | this.moveCount--; 56 | } 57 | } 58 | var temp = createVector(this.vel.x, this.vel.y); 59 | temp.normalize(); 60 | temp.mult(this.playerSpeed); 61 | for (var i = 0; i< solids.length; i++) { 62 | temp = solids[i].restrictMovement(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size), temp); 63 | } 64 | this.pos.add(temp); 65 | } 66 | checkCollisions() { 67 | this.coin.collides(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size)); 68 | for (var i = 0; i< dots.length; i++) { 69 | if (dots[i].collides(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size))) { 70 | this.fading = true; 71 | this.dead = true; 72 | this.deathByDot = true; 73 | this.deathAtStep = this.brain.step; 74 | } 75 | } 76 | if (this.coin.taken && winArea.collision(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size))) { 77 | this.reachedGoal = true; 78 | } 79 | for (var i = 0; i< this.nodes.length; i++) { 80 | this.nodes[i].collision(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size)); 81 | } 82 | } 83 | //---------------------------------------------------------------------------------------------------------------------------------------------------------- 84 | update() { 85 | if (!this.dead && !this.reachedGoal) { 86 | this.move(); 87 | this.checkCollisions(); 88 | } else if (this.fading) { 89 | if (this.fadeCounter > 0) { 90 | if(humanPlaying || replayGens){ 91 | this.fadeCounter -=10; 92 | }else{ 93 | this.fadeCounter = 0; 94 | 95 | } 96 | } 97 | } 98 | } 99 | //---------------------------------------------------------------------------------------------------------------------------------------------------------- 100 | 101 | calculateFitness() { 102 | if (this.reachedGoal) {//if the dot reached the goal then the fitness is based on the amount of steps it took to get there 103 | this.fitness = 1.0/16.0 + 10000.0/(this.brain.step * this.brain.step); 104 | } else {//if the dot didn't reach the goal then the fitness is based on how close it is to the goal 105 | var estimatedDistance = 0.0;//the estimated distance of the path from the player to the goal 106 | for (var i = this.nodes.length-1; i>=0; i--) { 107 | if (!this.nodes[i].reached) { 108 | estimatedDistance = this.nodes[i].distToFinish; 109 | estimatedDistance += dist(this.pos.x, this.pos.y, this.nodes[i].pos.x, this.nodes[i].pos.y); 110 | } 111 | } 112 | if (this.deathByDot) { 113 | estimatedDistance *= 0.9; 114 | } 115 | this.fitness = 1.0/(estimatedDistance * estimatedDistance); 116 | } 117 | this.fitness*=this.fitness; 118 | if(this.coin.taken){ 119 | this.fitness *=1.2; 120 | } 121 | } 122 | 123 | //---------------------------------------------------------------------------------------------------------------------------------------------------------- 124 | gimmeBaby() { 125 | var baby = new Player(); 126 | baby.brain = this.brain.clone();//babies have the same brain as their parents 127 | baby.deathByDot = this.deathByDot; 128 | baby.deathAtStep = this.deathAtStep; 129 | baby.gen = this.gen; 130 | return baby; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /WHG - level3/Population.js: -------------------------------------------------------------------------------- 1 | class Population { 2 | 3 | constructor(size) { 4 | this.players = []; 5 | this.fitnessSum = 0.0; 6 | this.gen = 1; 7 | this.bestPlayer =0; 8 | this.minStep = 10000; 9 | this.genPlayers = []; 10 | this.bestFitness = 0; 11 | this.solutionFound = false; 12 | 13 | for (var i = 0; i< size; i++) { 14 | this.players[i] = new Player(); 15 | } 16 | } 17 | 18 | 19 | //------------------------------------------------------------------------------------------------------------------------------ 20 | //show all players 21 | show() { 22 | if (!showBest) { 23 | for (var i = 1; i< this.players.length; i++) { 24 | this.players[i].show(); 25 | } 26 | } 27 | this.players[0].show(); 28 | } 29 | 30 | //------------------------------------------------------------------------------------------------------------------------------- 31 | //update all players 32 | update() { 33 | for (var i = 0; i< this.players.length; i++) { 34 | if (this.players[i].brain.step > this.minStep) {//if the player has already taken more steps than the best player has taken to reach the goal 35 | this.players[i].dead = true;//then it dead 36 | } else { 37 | this.players[i].update(); 38 | } 39 | } 40 | } 41 | 42 | //----------------------------------------------------------------------------------------------------------------------------------- 43 | //calculate all the fitnesses 44 | calculateFitness() { 45 | for (var i = 0; i< this.players.length; i++) { 46 | this.players[i].calculateFitness(); 47 | } 48 | } 49 | 50 | 51 | //------------------------------------------------------------------------------------------------------------------------------------ 52 | //returns whether all the players are either dead or have reached the goal 53 | allPlayersDead() { 54 | for (var i = 0; i< this.players.length; i++) { 55 | if (!this.players[i].dead && !this.players[i].reachedGoal) { 56 | return false; 57 | } 58 | } 59 | print("bah:"); 60 | return true; 61 | } 62 | 63 | 64 | 65 | //------------------------------------------------------------------------------------------------------------------------------------- 66 | 67 | //gets the next generation of players 68 | naturalSelection() { 69 | var newPlayers = [];//next gen 70 | this.setBestPlayer(); 71 | this.calculateFitnessSum(); 72 | 73 | //the champion lives on 74 | newPlayers[0] = this.players[this.bestPlayer].gimmeBaby(); 75 | newPlayers[0].isBest = true; 76 | for (var i = 1; i< populationSize; i++) { 77 | //select parent based on fitness 78 | var parent = this.selectParent(); 79 | 80 | //get baby from them 81 | newPlayers[i] = parent.gimmeBaby(); 82 | } 83 | 84 | // this.players = newPlayers.slice(); 85 | this.players = []; 86 | for(var i = 0 ; i< newPlayers.length;i++){ 87 | this.players[i] = newPlayers[i]; 88 | } 89 | this.gen ++; 90 | } 91 | 92 | 93 | //-------------------------------------------------------------------------------------------------------------------------------------- 94 | //you get it 95 | calculateFitnessSum() { 96 | this.fitnessSum = 0; 97 | for (var i = 0; i< this.players.length; i++) { 98 | this.fitnessSum += this.players[i].fitness; 99 | } 100 | } 101 | 102 | //------------------------------------------------------------------------------------------------------------------------------------- 103 | 104 | //chooses player from the population to return randomly(considering fitness) 105 | 106 | //this function works by randomly choosing a value between 0 and the sum of all the fitnesses 107 | //then go through all the players and add their fitness to a running sum and if that sum is greater than the random value generated that player is chosen 108 | //since players with a higher fitness function add more to the running sum then they have a higher chance of being chosen 109 | selectParent() { 110 | var rand = random(this.fitnessSum); 111 | 112 | 113 | var runningSum = 0; 114 | 115 | for (var i = 0; i< this.players.length; i++) { 116 | runningSum+= this.players[i].fitness; 117 | if (runningSum > rand) { 118 | return this.players[i]; 119 | } 120 | } 121 | 122 | //should never get to this point 123 | 124 | return null; 125 | } 126 | 127 | //------------------------------------------------------------------------------------------------------------------------------------------ 128 | //mutates all the brains of the babies 129 | mutateDemBabies() { 130 | for (var i = 1; i< this.players.length; i++) { 131 | this.players[i].brain.mutate(this.players[i].deathByDot, this.players[i].deathAtStep); 132 | this.players[i].deathByDot = false; 133 | this.players[i].gen = this.gen; 134 | } 135 | this.players[0].deathByDot = false; 136 | this.players[0].gen = this.gen; 137 | } 138 | 139 | //--------------------------------------------------------------------------------------------------------------------------------------------- 140 | //finds the player with the highest fitness and sets it as the best player 141 | setBestPlayer() { 142 | var max = 0; 143 | var maxIndex = 0; 144 | for (var i = 0; i< this.players.length; i++) { 145 | if (this.players[i].fitness > max) { 146 | max = this.players[i].fitness; 147 | maxIndex = i; 148 | } 149 | } 150 | 151 | this.bestPlayer = maxIndex; 152 | 153 | if (max > this.bestFitness) { 154 | this.bestFitness = max; 155 | this.genPlayers.push(this.players[this.bestPlayer].gimmeBaby()); 156 | } 157 | 158 | //if this player reached the goal then reset the minimum number of steps it takes to get to the goal 159 | if (this.players[this.bestPlayer].reachedGoal) { 160 | this.minStep = this.players[this.bestPlayer].brain.step; 161 | this.solutionFound = true; 162 | } 163 | } 164 | 165 | 166 | increaseMoves() { 167 | if (this.players[0].brain.directions.length < 120 && !this.solutionFound) { 168 | for (var i = 0; i< this.players.length; i++) { 169 | this.players[i].brain.increaseMoves(); 170 | } 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /WHG - level3/Solid.js: -------------------------------------------------------------------------------- 1 | class Solid { 2 | 3 | constructor(topL,botR){ 4 | var lineWidth = 1; 5 | this.pos = createVector(topL.pixelPos.x-lineWidth, topL.pixelPos.y-lineWidth); 6 | this.w = botR.pixelPos.x + tileSize - this.pos.x + lineWidth; 7 | this.h = botR.pixelPos.y + tileSize - this.pos.y + lineWidth; 8 | this.bottomRight = createVector(this.pos.x + this.w, this.pos.y + this.h); 9 | 10 | } 11 | 12 | 13 | restrictMovement(tl, br, movement) {//player dimensions 14 | //add the x first 15 | 16 | var x = movement.x; 17 | var y = movement.y; 18 | // 19 | // movement.x = round(movement.x); 20 | // movement.y = round(movement.y); 21 | var ptl = createVector(tl.x+movement.x, tl.y); 22 | var pbr = createVector(br.x+movement.x, br.y); 23 | 24 | if ((ptl.x this.pos.x) &&( ptl.y < this.bottomRight.y && pbr.y > this.pos.y)) { 25 | 26 | x=0; 27 | } 28 | 29 | //check the y movement 30 | ptl = createVector(tl.x, tl.y +movement.y); 31 | pbr = createVector(br.x, br.y + movement.y); 32 | if ((ptl.x this.pos.x) &&( ptl.y < this.bottomRight.y && pbr.y > this.pos.y)) { 33 | y=0; 34 | } 35 | 36 | return createVector(x, y); 37 | } 38 | 39 | collision(ptl, pbr) {//player dimensions 40 | //add the x first 41 | 42 | if ((ptl.x this.pos.x) &&( ptl.y < this.bottomRight.y && pbr.y > this.pos.y)) { 43 | return true; 44 | } 45 | return false; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /WHG - level3/Tile.js: -------------------------------------------------------------------------------- 1 | class Tile{ 2 | 3 | constructor(x,y){ 4 | this.matrixPos = createVector(x,y); 5 | this.pixelPos = createVector(x*tileSize+xoff, y*tileSize+yoff); 6 | this.safe = false; 7 | this.goal = false; 8 | this.wall = false; 9 | this.edges = []; 10 | 11 | } 12 | 13 | show(){ 14 | if ((this.matrixPos.x +this.matrixPos.y) % 2 ==0) { 15 | fill(247,247,255); 16 | } else { 17 | fill(230,230,255); 18 | } 19 | if (this.wall) { 20 | fill(180, 181, 254); 21 | } 22 | if (this.goal || this.safe) { 23 | fill(181, 254, 180); 24 | } 25 | noStroke(); 26 | rect(this.pixelPos.x,this.pixelPos.y,tileSize,tileSize); 27 | 28 | } 29 | 30 | showEdges(){ 31 | for (var i = 0; i< this.edges.length; i++) { 32 | stroke(0); 33 | strokeWeight(4); 34 | switch(this.edges[i]) { 35 | case 4: 36 | line(this.pixelPos.x, this.pixelPos.y, this.pixelPos.x+tileSize,this.pixelPos.y); 37 | break; 38 | case 1: 39 | line(this.pixelPos.x+tileSize, this.pixelPos.y, this.pixelPos.x+tileSize, this.pixelPos.y+tileSize); 40 | break; 41 | case 2: 42 | line(this.pixelPos.x, this.pixelPos.y+tileSize, this.pixelPos.x+tileSize, this.pixelPos.y+tileSize); 43 | break; 44 | case 3: 45 | line(this.pixelPos.x, this.pixelPos.y, this.pixelPos.x, this.pixelPos.y+tileSize); 46 | break; 47 | } 48 | } 49 | } 50 | 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /WHG - level3/assets/DAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Code-Bullet/WorldsHardestGameAI/2eb083b238857de88c6a48563cba6df62cb7968f/WHG - level3/assets/DAB.png -------------------------------------------------------------------------------- /WHG - level3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |

hi my name is Evan and this is my thing, I hope you enjoy. Pro Tip use WASD controls to move the player

22 | 23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /WHG - level3/setting_level.js: -------------------------------------------------------------------------------- 1 | //functions which setup the level 2 | 3 | function setLevel1Walls() { 4 | tiles[0][0].wall = true; 5 | tiles[0][1].wall = true; 6 | tiles[0][2].wall = true; 7 | tiles[0][3].wall = true; 8 | tiles[0][4].wall = true; 9 | tiles[0][5].wall = true; 10 | tiles[0][6].wall = true; 11 | tiles[0][7].wall = true; 12 | tiles[0][8].wall = true; 13 | tiles[0][9].wall = true; 14 | tiles[1][0].wall = true; 15 | tiles[1][1].wall = true; 16 | tiles[1][2].wall = true; 17 | tiles[1][3].wall = true; 18 | tiles[1][4].wall = true; 19 | tiles[1][5].wall = true; 20 | tiles[1][6].wall = true; 21 | tiles[1][7].wall = true; 22 | tiles[1][8].wall = true; 23 | tiles[1][9].wall = true; 24 | tiles[2][0].wall = true; 25 | tiles[2][1].wall = true; 26 | tiles[2][2].wall = true; 27 | tiles[2][3].wall = true; 28 | tiles[2][4].wall = true; 29 | tiles[2][5].wall = true; 30 | tiles[2][6].wall = true; 31 | tiles[2][7].wall = true; 32 | tiles[2][8].wall = true; 33 | tiles[2][9].wall = true; 34 | tiles[3][0].wall = true; 35 | tiles[3][1].wall = true; 36 | tiles[3][2].wall = true; 37 | tiles[3][3].wall = true; 38 | tiles[3][4].wall = true; 39 | tiles[3][5].wall = true; 40 | tiles[3][6].wall = true; 41 | tiles[3][7].wall = true; 42 | tiles[3][8].wall = true; 43 | tiles[3][9].wall = true; 44 | tiles[4][0].wall = true; 45 | tiles[4][1].wall = true; 46 | tiles[4][2].wall = true; 47 | tiles[4][3].wall = true; 48 | tiles[4][4].wall = true; 49 | tiles[4][5].wall = true; 50 | tiles[4][6].wall = true; 51 | tiles[4][7].wall = true; 52 | tiles[4][8].wall = true; 53 | tiles[4][9].wall = true; 54 | tiles[5][0].wall = true; 55 | tiles[5][1].wall = true; 56 | tiles[5][2].wall = true; 57 | tiles[5][3].wall = true; 58 | tiles[5][4].wall = true; 59 | tiles[5][5].wall = true; 60 | tiles[5][6].wall = true; 61 | tiles[5][7].wall = true; 62 | tiles[5][8].wall = true; 63 | tiles[5][9].wall = true; 64 | tiles[6][0].wall = true; 65 | tiles[6][1].wall = true; 66 | tiles[6][2].wall = true; 67 | tiles[6][3].wall = true; 68 | tiles[6][4].wall = true; 69 | tiles[6][5].wall = true; 70 | tiles[6][6].wall = true; 71 | tiles[6][7].wall = true; 72 | tiles[6][8].wall = true; 73 | tiles[6][9].wall = true; 74 | tiles[7][0].wall = true; 75 | tiles[7][1].wall = true; 76 | tiles[7][2].wall = true; 77 | tiles[7][3].wall = true; 78 | tiles[7][4].wall = true; 79 | tiles[7][5].wall = true; 80 | tiles[7][6].wall = true; 81 | tiles[7][7].wall = true; 82 | tiles[7][8].wall = true; 83 | tiles[7][9].wall = true; 84 | tiles[8][0].wall = true; 85 | tiles[8][1].wall = true; 86 | tiles[8][2].wall = true; 87 | tiles[8][3].wall = true; 88 | tiles[8][4].wall = true; 89 | tiles[8][5].wall = true; 90 | tiles[8][6].wall = true; 91 | tiles[8][7].wall = true; 92 | tiles[8][8].wall = true; 93 | tiles[8][9].wall = true; 94 | tiles[9][0].wall = true; 95 | tiles[9][1].wall = true; 96 | tiles[9][7].wall = true; 97 | tiles[9][8].wall = true; 98 | tiles[9][9].wall = true; 99 | tiles[10][0].wall = true; 100 | tiles[10][1].wall = true; 101 | tiles[10][2].wall = true; 102 | tiles[10][7].wall = true; 103 | tiles[10][8].wall = true; 104 | tiles[10][9].wall = true; 105 | tiles[11][0].wall = true; 106 | tiles[11][1].wall = true; 107 | tiles[11][2].wall = true; 108 | tiles[11][7].wall = true; 109 | tiles[11][8].wall = true; 110 | tiles[11][9].wall = true; 111 | tiles[12][0].wall = true; 112 | tiles[12][1].wall = true; 113 | tiles[12][2].wall = true; 114 | tiles[12][7].wall = true; 115 | tiles[12][8].wall = true; 116 | tiles[12][9].wall = true; 117 | tiles[13][0].wall = true; 118 | tiles[13][1].wall = true; 119 | tiles[13][2].wall = true; 120 | tiles[13][3].wall = true; 121 | tiles[13][4].wall = true; 122 | tiles[13][5].wall = true; 123 | tiles[13][6].wall = true; 124 | tiles[13][7].wall = true; 125 | tiles[13][8].wall = true; 126 | tiles[13][9].wall = true; 127 | tiles[14][0].wall = true; 128 | tiles[14][1].wall = true; 129 | tiles[14][2].wall = true; 130 | tiles[14][3].wall = true; 131 | tiles[14][4].wall = true; 132 | tiles[14][5].wall = true; 133 | tiles[14][6].wall = true; 134 | tiles[14][7].wall = true; 135 | tiles[14][8].wall = true; 136 | tiles[14][9].wall = true; 137 | tiles[15][0].wall = true; 138 | tiles[15][1].wall = true; 139 | tiles[15][2].wall = true; 140 | tiles[15][3].wall = true; 141 | tiles[15][4].wall = true; 142 | tiles[15][5].wall = true; 143 | tiles[15][6].wall = true; 144 | tiles[15][7].wall = true; 145 | tiles[15][8].wall = true; 146 | tiles[15][9].wall = true; 147 | tiles[16][0].wall = true; 148 | tiles[16][1].wall = true; 149 | tiles[16][2].wall = true; 150 | tiles[16][3].wall = true; 151 | tiles[16][4].wall = true; 152 | tiles[16][5].wall = true; 153 | tiles[16][6].wall = true; 154 | tiles[16][7].wall = true; 155 | tiles[16][8].wall = true; 156 | tiles[16][9].wall = true; 157 | tiles[17][0].wall = true; 158 | tiles[17][1].wall = true; 159 | tiles[17][2].wall = true; 160 | tiles[17][3].wall = true; 161 | tiles[17][4].wall = true; 162 | tiles[17][5].wall = true; 163 | tiles[17][6].wall = true; 164 | tiles[17][7].wall = true; 165 | tiles[17][8].wall = true; 166 | tiles[17][9].wall = true; 167 | tiles[18][0].wall = true; 168 | tiles[18][1].wall = true; 169 | tiles[18][2].wall = true; 170 | tiles[18][3].wall = true; 171 | tiles[18][4].wall = true; 172 | tiles[18][5].wall = true; 173 | tiles[18][6].wall = true; 174 | tiles[18][7].wall = true; 175 | tiles[18][8].wall = true; 176 | tiles[18][9].wall = true; 177 | tiles[19][0].wall = true; 178 | tiles[19][1].wall = true; 179 | tiles[19][2].wall = true; 180 | tiles[19][3].wall = true; 181 | tiles[19][4].wall = true; 182 | tiles[19][5].wall = true; 183 | tiles[19][6].wall = true; 184 | tiles[19][7].wall = true; 185 | tiles[19][8].wall = true; 186 | tiles[19][9].wall = true; 187 | tiles[20][0].wall = true; 188 | tiles[20][1].wall = true; 189 | tiles[20][2].wall = true; 190 | tiles[20][3].wall = true; 191 | tiles[20][4].wall = true; 192 | tiles[20][5].wall = true; 193 | tiles[20][6].wall = true; 194 | tiles[20][7].wall = true; 195 | tiles[20][8].wall = true; 196 | tiles[20][9].wall = true; 197 | tiles[21][0].wall = true; 198 | tiles[21][1].wall = true; 199 | tiles[21][2].wall = true; 200 | tiles[21][3].wall = true; 201 | tiles[21][4].wall = true; 202 | tiles[21][5].wall = true; 203 | tiles[21][6].wall = true; 204 | tiles[21][7].wall = true; 205 | tiles[21][8].wall = true; 206 | tiles[21][9].wall = true; 207 | } 208 | 209 | 210 | function setLevel2Goal() { 211 | tiles[10][4].goal = true; 212 | tiles[10][5].goal = true; 213 | tiles[11][4].goal = true; 214 | tiles[11][5].goal = true; 215 | } 216 | 217 | function setLevel1SafeArea() { 218 | tiles[9][2].safe = true; 219 | } 220 | 221 | 222 | function setEdges() { 223 | for (var i = 1; i< tiles.length-1; i++) { 224 | for (var j = 1; j< tiles[0].length-1; j++) { 225 | if (tiles[i][j].wall) { 226 | if (!tiles[i+1][j].wall) { 227 | tiles[i][j].edges.push(1); 228 | } 229 | if (!tiles[i][j+1].wall) { 230 | tiles[i][j].edges.push(2); 231 | } 232 | if (!tiles[i-1][j].wall) { 233 | tiles[i][j].edges.push(3); 234 | } 235 | if (!tiles[i][j-1].wall) { 236 | tiles[i][j].edges.push(4); 237 | } 238 | } 239 | } 240 | } 241 | } 242 | 243 | 244 | function setDots() { 245 | 246 | dots.push(new Dot(tiles[9][3],tiles[12][3],tiles[12][6], tiles[9][6],tiles[11][6], -1, 0)); 247 | dots.push(new Dot(tiles[9][3],tiles[12][3],tiles[12][6], tiles[9][6],tiles[10][6], -1, 0)); 248 | dots.push(new Dot(tiles[9][3],tiles[12][3],tiles[12][6], tiles[9][6],tiles[9][6], -1, 0)); 249 | dots.push(new Dot(tiles[9][3],tiles[12][3],tiles[12][6], tiles[9][6],tiles[9][5], 0, -1)); 250 | dots.push(new Dot(tiles[9][3],tiles[12][3],tiles[12][6], tiles[9][6],tiles[9][4], 0, -1)); 251 | 252 | dots.push(new Dot(tiles[9][3],tiles[12][3],tiles[12][6], tiles[9][6],tiles[9][3], 0, -1)); 253 | dots.push(new Dot(tiles[9][3],tiles[12][3],tiles[12][6], tiles[9][6],tiles[10][3], 1, 0)); 254 | dots.push(new Dot(tiles[9][3],tiles[12][3],tiles[12][6], tiles[9][6],tiles[11][3], 1, 0)); 255 | dots.push(new Dot(tiles[9][3],tiles[12][3],tiles[12][6], tiles[9][6],tiles[12][3], 1, 0)); 256 | 257 | dots.push(new Dot(tiles[9][3],tiles[12][3],tiles[12][6], tiles[9][6],tiles[12][4], 0, 1)); 258 | dots.push(new Dot(tiles[9][3],tiles[12][3],tiles[12][6], tiles[9][6],tiles[12][5], 0, 1)); 259 | 260 | } 261 | 262 | 263 | function setSolids() { 264 | solids.push(new Solid(tiles[8][7], tiles[13][7])); 265 | solids.push(new Solid(tiles[13][2], tiles[13][7])); 266 | solids.push(new Solid(tiles[10][2], tiles[13][2])); 267 | solids.push(new Solid(tiles[8][1], tiles[10][1])); 268 | solids.push(new Solid(tiles[8][1], tiles[8][7])); 269 | } 270 | -------------------------------------------------------------------------------- /WHG - level3/sketch.js: -------------------------------------------------------------------------------- 1 | var tileSize = 50; 2 | var xoff = 80; 3 | var yoff = 100; 4 | 5 | //human playing vars 6 | var humanPlaying = false; 7 | var left = false; 8 | var right = false; 9 | var up = false; 10 | var down = false; 11 | var p; 12 | 13 | //arrays 14 | var tiles = []; 15 | var solids = []; 16 | var dots = []; 17 | var savedDots = []; 18 | 19 | var showBest = false; 20 | 21 | var winArea;//a solid which is the win zone i.e. the green bits 22 | 23 | //gen replay vars 24 | var replayGens = false; 25 | var genPlayer; 26 | var upToGenPos = 0; 27 | 28 | //population vars 29 | var numberOfSteps = 10; 30 | var testPopulation; 31 | 32 | var winCounter = -1; 33 | 34 | var img; 35 | var flip = true; 36 | 37 | //population size vars 38 | var populationSize = 500; 39 | var popPara; 40 | var popPlus; 41 | var popMinus; 42 | 43 | //mutation rate vars 44 | var mutationRate = 0.01; 45 | var mrPara; 46 | var mrPlus; 47 | var mrMinus; 48 | 49 | //evolution speed vars 50 | var evolutionSpeed =1; 51 | var speedPara; 52 | var speedPlus; 53 | var speedMinus; 54 | 55 | //increaseMoves 56 | var movesH3; 57 | 58 | var increaseMovesBy =5; 59 | var movesPara; 60 | var movesPlus; 61 | var movesMinus; 62 | 63 | var increaseEvery =5; 64 | var everyPara; 65 | var everyPlus; 66 | var everyMinus; 67 | 68 | var firstClick = true; 69 | var showedCoin = false; 70 | 71 | function setup() { 72 | var canvas = createCanvas(1280,720); 73 | htmlStuff(); 74 | for (var i = 0; i< 22; i++) { 75 | tiles[i] = []; 76 | for (var j = 0; j< 10; j++) { 77 | tiles[i][j] = new Tile(i, j); 78 | } 79 | } 80 | 81 | setLevel1Walls(); 82 | setLevel2Goal(); 83 | setLevel1SafeArea(); 84 | setEdges(); 85 | setSolids(); 86 | 87 | p = new Player(); 88 | setDots(); 89 | winArea = new Solid(tiles[10][4], tiles[11][5]); 90 | testPopulation = new Population(populationSize); 91 | img = loadImage("assets/DAB.png"); 92 | //prevents the window from moving from the arrow keys or the spacebar 93 | window.addEventListener("keydown", function(e) { 94 | // space and arrow keys 95 | if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) { 96 | e.preventDefault(); 97 | } 98 | }, false); 99 | } 100 | 101 | function draw(){ 102 | showedCoin = false; 103 | 104 | background(180, 181, 254); 105 | drawTiles(); 106 | writeShit(); 107 | 108 | 109 | if (humanPlaying) {//if the user is controlling the square 110 | if ((p.dead && p.fadeCounter<=0) || p.reachedGoal) { 111 | //reset player and dots 112 | if(p.reachedGoal){ 113 | winCounter = 100; 114 | 115 | } 116 | p = new Player(); 117 | p.human = true; 118 | resetDots(); 119 | 120 | } else { 121 | //update the dots and the players and show them to the screen 122 | 123 | 124 | moveAndShowDots(); 125 | 126 | p.update(); 127 | p.show(); 128 | } 129 | } else 130 | if (replayGens) {//if replaying the best generations 131 | if ((genPlayer.dead && genPlayer.fadeCounter <=0) || genPlayer.reachedGoal) { //if the current gen is done 132 | upToGenPos ++;//next gen 133 | if (testPopulation.genPlayers.length <= upToGenPos) {//if reached the final gen 134 | //stop replaying gens 135 | upToGenPos = 0; 136 | replayGens = false; 137 | //return the dots to their saved position 138 | 139 | loadDots(); 140 | } else {//if there are more generations to show 141 | //set gen player as the best player of that generation 142 | genPlayer = testPopulation.genPlayers[upToGenPos].gimmeBaby(); 143 | //reset the dots positions 144 | resetDots(); 145 | } 146 | } else {//if not done 147 | //move and show dots 148 | moveAndShowDots(); 149 | //move and update player 150 | genPlayer.update(); 151 | genPlayer.show(); 152 | } 153 | } else//if training normaly 154 | if (testPopulation.allPlayersDead()) { 155 | //genetic algorithm 156 | testPopulation.calculateFitness(); 157 | testPopulation.naturalSelection(); 158 | testPopulation.mutateDemBabies(); 159 | //reset dots 160 | resetDots(); 161 | 162 | //every 5 generations incease the number of moves by 5 163 | if (testPopulation.gen % increaseEvery ==0) { 164 | testPopulation.increaseMoves(); 165 | } 166 | 167 | } else { 168 | 169 | // moveAndShowDots(); 170 | //update and show population 171 | 172 | for(var j = 0 ; j< evolutionSpeed; j++){ 173 | for (var i = 0; i < dots.length; i ++) { 174 | dots[i].move(); 175 | } 176 | testPopulation.update(); 177 | } 178 | 179 | for (var i = 0; i < dots.length; i ++) { 180 | dots[i].show(); 181 | } 182 | testPopulation.show(); 183 | } 184 | 185 | } 186 | function moveAndShowDots(){ 187 | for (var i = 0; i < dots.length; i ++) { 188 | dots[i].move(); 189 | dots[i].show(); 190 | } 191 | 192 | } 193 | function resetDots(){ 194 | for (var i = 0; i < dots.length; i ++) { 195 | dots[i].resetDot(); 196 | } 197 | 198 | } 199 | function drawTiles(){ 200 | for (var i = 0; i< tiles.length; i++) { 201 | for (var j = 0; j< tiles[0].length; j++) { 202 | tiles[i][j].show(); 203 | } 204 | } 205 | for (var i = 0; i< tiles.length; i++) { 206 | for (var j = 0; j< tiles[0].length; j++) { 207 | tiles[i][j].showEdges(); 208 | } 209 | } 210 | } 211 | 212 | function loadDots(){ 213 | for (var i = 0; i< dots.length; i++) { 214 | dots[i] = savedDots[i].clone(); 215 | } 216 | } 217 | 218 | function saveDots(){ 219 | for (var i = 0; i< dots.length; i++) { 220 | savedDots[i] = dots[i].clone(); 221 | } 222 | } 223 | 224 | function writeShit(){ 225 | 226 | fill(247, 247, 255); 227 | textSize(20); 228 | noStroke(); 229 | text(" \tPress P to play the game yourself \t\t\t\t\t\t\t\t Press G to replay evolution highlights",250,620 ); 230 | text("Press SPACE to only show the best player", 450,680); 231 | textSize(36); 232 | if(winCounter > 0){ 233 | 234 | if(flip){ 235 | push(); 236 | 237 | scale(-1.0,1.0); 238 | image(img,-300 -img.width + random(5),100+ random(5)); 239 | pop(); 240 | }else{ 241 | image(img,300+ random(5),100 + random(5)); 242 | } 243 | textSize(100); 244 | stroke(0); 245 | 246 | text(" HELL YEAH", 110,400); 247 | winCounter --; 248 | if(winCounter % 10 ==0){ 249 | 250 | flip = !flip; 251 | } 252 | textSize(36); 253 | noStroke(); 254 | } 255 | if (replayGens) { 256 | text("Generation: " + genPlayer.gen, 200, 90); 257 | text("Number of moves: " + genPlayer.brain.directions.length, 700, 90); 258 | } else if(!humanPlaying) { 259 | text("Generation: " + testPopulation.gen, 200, 90); 260 | if(testPopulation.solutionFound){ 261 | text("Wins in " + testPopulation.minStep + " moves",700, 90); 262 | }else{ 263 | text("Number of moves: " + testPopulation.players[0].brain.directions.length, 700, 90); 264 | } 265 | }else{ 266 | text("Have Fun ;)", 500,90); 267 | } 268 | } 269 | function keyPressed(){ 270 | if(humanPlaying){ 271 | switch(keyCode) { 272 | case UP_ARROW: 273 | up = true; 274 | break; 275 | case DOWN_ARROW: 276 | down = true; 277 | break; 278 | case RIGHT_ARROW: 279 | right = true; 280 | break; 281 | case LEFT_ARROW: 282 | left = true; 283 | break; 284 | } 285 | switch(key){ 286 | case 'W': 287 | up = true; 288 | break; 289 | case 'S': 290 | down = true; 291 | break; 292 | case 'D': 293 | right = true; 294 | break; 295 | case 'A': 296 | left = true; 297 | break; 298 | } 299 | setPlayerVelocity(); 300 | }else{//if human is not playing 301 | switch(key) { 302 | case ' ': 303 | showBest = !showBest; 304 | for (var i = 0; i< tiles.length; i++) { 305 | for (var j = 0; j< tiles[0].length; j++) { 306 | // if(tiles[i][j].wall){ 307 | // print("tiles["+ i+ "][" + j +"].wall = true;")//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<, 308 | // } 309 | // if(tiles[i][j].goal){ 310 | // print("tiles["+ i+ "][" + j +"].goal = true;")//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<, 311 | // } 312 | if(tiles[i][j].safe){ 313 | print("tiles["+ i+ "][" + j +"].safe = true;")//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<, 314 | } 315 | } 316 | } 317 | break; 318 | case 'G'://replay gens 319 | if (replayGens) { 320 | upToGenPos = 0; 321 | replayGens = false; 322 | loadDots(); 323 | } else 324 | if (testPopulation.genPlayers.length > 0) { 325 | replayGens = true; 326 | genPlayer = testPopulation.genPlayers[0].gimmeBaby(); 327 | saveDots(); 328 | resetDots(); 329 | } 330 | break; 331 | } 332 | } 333 | 334 | if(key == 'P'){ 335 | if (humanPlaying) {//if human is currently playing 336 | 337 | //reset dots to position 338 | humanPlaying = false; 339 | loadDots(); 340 | } else {//if AI is currently playing 341 | if (replayGens) { 342 | upToGenPos = 0; 343 | replayGens = false; 344 | } 345 | humanPlaying = true; 346 | p = new Player(); 347 | p.human = true; 348 | //save the positions of the dots 349 | saveDots(); 350 | resetDots(); 351 | } 352 | } 353 | } 354 | 355 | 356 | function keyReleased(){ 357 | if(humanPlaying){ 358 | switch(keyCode) { 359 | case UP_ARROW: 360 | up = false; 361 | break; 362 | case DOWN_ARROW: 363 | down = false; 364 | break; 365 | case RIGHT_ARROW: 366 | right = false; 367 | break; 368 | case LEFT_ARROW: 369 | left = false; 370 | break; 371 | } 372 | switch(key){ 373 | case 'W': 374 | up = false; 375 | break; 376 | case 'S': 377 | down = false; 378 | break; 379 | case 'D': 380 | right = false; 381 | break; 382 | case 'A': 383 | left = false; 384 | break; 385 | } 386 | 387 | setPlayerVelocity(); 388 | } 389 | 390 | } 391 | //set the velocity of the player based on what keys are currently down 392 | 393 | function setPlayerVelocity(){ 394 | p.vel.y= 0; 395 | if (up) { 396 | p.vel.y -=1; 397 | } 398 | if (down) { 399 | p.vel.y +=1; 400 | } 401 | p.vel.x= 0; 402 | if (left) { 403 | p.vel.x -=1; 404 | } 405 | if (right) { 406 | p.vel.x +=1; 407 | } 408 | 409 | } 410 | //--------------------------------------------------------------------------------------------------------------------- 411 | function htmlStuff(){ 412 | createElement("h2", "Change Values") 413 | createP("here are some values you can play with, sure it's not sexy but it does the job") 414 | popPara = createDiv("Population Size: " + populationSize); 415 | popMinus = createButton("-"); 416 | popPlus = createButton('+'); 417 | 418 | popPlus.mousePressed(plusPopSize); 419 | popMinus.mousePressed(minusPopSize); 420 | 421 | mrPara = createDiv("Mutation Rate: " + mutationRate); 422 | mrMinus = createButton("1/2"); 423 | mrPlus = createButton('x2'); 424 | mrPlus.mousePressed(plusmr); 425 | mrMinus.mousePressed(minusmr); 426 | 427 | speedPara = createDiv("Evolution Player Speed: " + evolutionSpeed); 428 | speedMinus = createButton("-"); 429 | speedPlus = createButton('+'); 430 | speedPlus.mousePressed(plusSpeed); 431 | speedMinus.mousePressed(minusSpeed); 432 | 433 | movesH3 = createElement("h4", "Increase number of player moves by " + increaseMovesBy + " every " + increaseEvery + " generations"); 434 | movesPara = createDiv("Increase moves by: " + increaseMovesBy); 435 | movesMinus = createButton("-"); 436 | movesPlus = createButton('+'); 437 | movesPlus.mousePressed(plusMoves); 438 | movesMinus.mousePressed(minusMoves); 439 | everyPara = createDiv("Increase every " + increaseEvery + " generations"); 440 | everyMinus = createButton("-"); 441 | everyPlus = createButton('+'); 442 | everyPlus.mousePressed(plusEvery); 443 | everyMinus.mousePressed(minusEvery); 444 | } 445 | 446 | function minusPopSize(){ 447 | if(populationSize > 100){ 448 | populationSize -=100; 449 | popPara.html("Population Size: " + populationSize); 450 | } 451 | } 452 | function plusPopSize(){ 453 | if(populationSize < 10000){ 454 | populationSize +=100; 455 | popPara.html("Population Size: " + populationSize); 456 | 457 | } 458 | } 459 | 460 | function minusmr(){ 461 | if(mutationRate > 0.0001){ 462 | mutationRate /= 2.0; 463 | mrPara.html("Mutation Rate: " + mutationRate); 464 | } 465 | } 466 | function plusmr(){ 467 | if(mutationRate <= 0.5){ 468 | mutationRate *= 2.0; 469 | mrPara.html("Mutation Rate: " + mutationRate); 470 | 471 | } 472 | } 473 | 474 | function minusSpeed(){ 475 | if(evolutionSpeed > 1){ 476 | evolutionSpeed -= 1; 477 | speedPara.html("Evolution Player Speed: " + evolutionSpeed); 478 | } 479 | } 480 | function plusSpeed(){ 481 | if(evolutionSpeed <= 5){ 482 | evolutionSpeed += 1; 483 | speedPara.html("Evolution Player Speed: " + evolutionSpeed); 484 | 485 | } 486 | } 487 | 488 | 489 | function minusMoves(){ 490 | if(increaseMovesBy >= 1){ 491 | increaseMovesBy -= 1; 492 | movesPara.html("Increase moves by: " + increaseMovesBy); 493 | movesH3.html("Increase number of player moves by " + increaseMovesBy + " every " + increaseEvery + " generations"); 494 | } 495 | } 496 | function plusMoves(){ 497 | if(increaseMovesBy <= 500){ 498 | increaseMovesBy += 1; 499 | movesPara.html("Increase moves by: " + increaseMovesBy); 500 | movesH3.html("Increase number of player moves by " + increaseMovesBy + " every " + increaseEvery + " generations"); 501 | } 502 | } 503 | 504 | function minusEvery(){ 505 | if(increaseEvery > 1){ 506 | increaseEvery -= 1; 507 | everyPara.html("Increase every " + increaseEvery + " generations"); 508 | movesH3.html("Increase number of player moves by " + increaseMovesBy + " every " + increaseEvery + " generations"); 509 | } 510 | } 511 | function plusEvery(){ 512 | if(increaseEvery <= 100){ 513 | increaseEvery += 1; 514 | everyPara.html("Increase every " + increaseEvery + " generations"); 515 | movesH3.html("Increase number of player moves by " + increaseMovesBy + " every " + increaseEvery + " generations"); 516 | } 517 | } 518 | 519 | //-------------------------------------------------------------------------------------------------------------------------------- 520 | //this just prints the coordinates of the tile which is clicked, usefull for level building 521 | function mousePressed() { 522 | 523 | var x = floor((mouseX - xoff )/tileSize); 524 | var y = floor((mouseY - yoff )/tileSize); 525 | 526 | // tiles[x][y].wall = !tiles[x][y].wall; 527 | // tiles[x][y].goal = !tiles[x][y].goal; 528 | // tiles[x][y].safe = !tiles[x][y].safe; 529 | 530 | //define solids 531 | // if(firstClick){ 532 | // print("solids.push(new Solid(tiles[" + x + "]["+ y + "],"); 533 | // }else{ 534 | // print("tiles[" + x + "]["+ y + "]));"); 535 | // } 536 | // firstClick = !firstClick; 537 | 538 | 539 | // // define dots 540 | // if(firstClick){ 541 | // print("dots.push(new Dot(tiles[" + x + "]["+ y + "],"); 542 | // }else{ 543 | // print("tiles[" + x + "]["+ y + "], 0, 1));"); 544 | // } 545 | // 546 | // firstClick = !firstClick; 547 | // dots.push(new Dot(tiles[15][6], tiles[6][6], -1)); 548 | // define dots lvl 3 549 | // print("dots.push(new Dot(tiles[9][3],tiles[12][3],tiles[12][6], tiles[9][6],tiles[" + x + "]["+ y + "], 0, 0);"); 550 | 551 | // 552 | // dots.push(new Dot(tiles[15][6], tiles[6][6], -1)); 553 | // 554 | // print("tiles[" + x + "]["+ y + "]"); 555 | 556 | 557 | } 558 | -------------------------------------------------------------------------------- /WHG/Brain.js: -------------------------------------------------------------------------------- 1 | class Brain { 2 | constructor(size){ 3 | this.directions = []; 4 | this.step =0; 5 | this.randomize(size); 6 | 7 | } 8 | //-------------------------------------------------------------------------------------------------------------------------------- 9 | //sets all the vectors in directions to a random vector with length 1 10 | randomize(size) { 11 | for (var i = 0; i< size; i++) { 12 | this.directions[i] = this.getRandomDirection(); 13 | } 14 | } 15 | 16 | //--------------------------------------------------------------------------------------------------------------------------------------------------------------- 17 | //returns a random PVector 18 | getRandomDirection() { 19 | var randomNumber = floor(random(9)); 20 | switch(randomNumber) { 21 | case 0: 22 | return createVector(0, 1); 23 | case 1: 24 | return createVector(1, 1); 25 | case 2: 26 | return createVector(1, 0); 27 | case 3: 28 | return createVector(1, -1); 29 | case 4: 30 | return createVector(0, -1); 31 | case 5: 32 | return createVector(-1, -1); 33 | case 6: 34 | return createVector(-1, 0); 35 | case 7: 36 | return createVector(-1, 1); 37 | case 8: 38 | return createVector(0, 0); 39 | } 40 | 41 | return createVector(); 42 | } 43 | 44 | //------------------------------------------------------------------------------------------------------------------------------------- 45 | //returns a perfect copy of this brain object 46 | clone() { 47 | var clone = new Brain(this.directions.length); 48 | for (var i = 0; i < this.directions.length; i++) { 49 | clone.directions[i] = this.directions[i].copy(); 50 | } 51 | return clone; 52 | } 53 | 54 | //---------------------------------------------------------------------------------------------------------------------------------------- 55 | 56 | //mutates the brain by setting some of the directions to random vectors 57 | mutate(died, deathStep) { 58 | //chance that any vector in directions gets changed 59 | for (var i =0; i< this.directions.length; i++) { 60 | var rand = random(1); 61 | if (died && i > deathStep - 10) { 62 | rand = random(0.2); 63 | } 64 | 65 | if (rand < mutationRate) { 66 | //set this direction as a random direction 67 | this.directions[i] = this.getRandomDirection(); 68 | } 69 | } 70 | } 71 | 72 | //--------------------------------------------------------------------------------------------------------------------------------------------------------- 73 | //increases the number of elements in directions by 5 74 | increaseMoves() { 75 | for(var i = 0 ; i< increaseMovesBy ;i++){ 76 | this.directions.push(this.getRandomDirection()); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /WHG/Dot.js: -------------------------------------------------------------------------------- 1 | class Dot { 2 | 3 | constructor( t1, t2, velX) { 4 | this.position = createVector(t1.pixelPos.x + tileSize/2, t1.pixelPos.y + tileSize/2); 5 | this.startingPos = createVector(t1.pixelPos.x + tileSize/2, t1.pixelPos.y + tileSize/2); 6 | this.speed = floor(tileSize/6.6); 7 | this.velocity = createVector(velX*this.speed, 0); 8 | this.startingVel = createVector(velX*this.speed, 0); 9 | this.bouncers = []; 10 | this.bouncers[0] = t1; 11 | this.bouncers[1] = t2; 12 | this.diameter = tileSize/2.0; 13 | this.bounceWait = -1; 14 | this.bounceTimer = 10; 15 | } 16 | 17 | //------------------------------------------------------------------------------------------------------------ 18 | //moves the dot 19 | move() { 20 | 21 | for (var i = 0; i < this.bouncers.length; i++) { 22 | if (this.bounceTimer < 0 && dist(this.position.x, this.position.y, this.bouncers[i].pixelPos.x + tileSize/2, this.bouncers[i].pixelPos.y + tileSize/2) < this.speed) {//if reached bouncer 23 | this.bounceTimer = 10; 24 | this.bounceWait= 1;//wait 1 frames then change direction 25 | } 26 | } 27 | if (this.bounceWait ==0) { 28 | //change direction 29 | this.velocity.x *= -1; 30 | } 31 | 32 | this.position.add(this.velocity);//move dot 33 | this.bounceTimer --; 34 | this.bounceWait --; 35 | } 36 | 37 | //------------------------------------------------------------------------------------------------------------ 38 | //draws the dot 39 | show() { 40 | fill(0, 0, 255); 41 | stroke(0); 42 | strokeWeight(4); 43 | ellipse(this.position.x, this.position.y, this.diameter, this.diameter); 44 | } 45 | 46 | 47 | //------------------------------------------------------------------------------------------------------------ 48 | //returns true of the Pvectors define a square which collides with this dot 49 | collides(ptl, pbr) {//player dimensions 50 | 51 | var topLeft = createVector(this.position.x - this.diameter/2, this.position.y-this.diameter/2); 52 | var bottomRight = createVector(this.position.x + this.diameter/2, this.position.y + this.diameter/2); 53 | var playerSize = bottomRight.x - topLeft.x; 54 | if ((ptl.x topLeft.x) &&( ptl.y < bottomRight.y && pbr.y > topLeft.y)) { 55 | 56 | if (dist(this.position.x, this.position.y, (ptl.x + pbr.x) /2.0, (ptl.y + pbr.y) /2.0)< this.diameter/2 + sqrt(playerSize*playerSize *2)/2) { 57 | return true; 58 | } 59 | } 60 | return false; 61 | } 62 | //------------------------------------------------------------------------------------------------------------ 63 | //returns the dot to its starting state 64 | 65 | resetDot() { 66 | this.position = this.startingPos.copy(); 67 | this.velocity = this.startingVel.copy(); 68 | this.bounceTimer = 10; 69 | this.bounceWait = -1; 70 | } 71 | //------------------------------------------------------------------------------------------------------------ 72 | //returns a copy of this dot object 73 | clone() { 74 | var clone = new Dot(this.bouncers[0], this.bouncers[1], floor(this.velocity.x)); 75 | clone.velocity = this.velocity.copy(); 76 | clone.position = this.position.copy(); 77 | clone.startingVel = this.startingVel.copy(); 78 | clone.bounceTimer = this.bounceTimer; 79 | clone.bounceWait = this.bounceWait; 80 | return clone; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /WHG/Node.js: -------------------------------------------------------------------------------- 1 | class Node { //used to define short term goals for the players 2 | //------------------------------------------------------------------------------------------------------------------------------ 3 | constructor(nodeTile) { 4 | this.reached = false; 5 | this.distToFinish = 0.0; 6 | this.pos = createVector(nodeTile.pixelPos.x, nodeTile.pixelPos.y); 7 | this.w = tileSize; 8 | this.h = tileSize; 9 | this.bottomRight = createVector(this.pos.x + this.w, this.pos.y + this.h); 10 | } 11 | //------------------------------------------------------------------------------------------------------------------------------ 12 | collision( ptl, pbr) {//player dimensions 13 | if ((ptl.x this.pos.x) &&( ptl.y < this.bottomRight.y && pbr.y > this.pos.y)) { 14 | this.reached = true; 15 | return true; 16 | }else if(pbr.x < this.pos.x){ 17 | this.reached = false; 18 | 19 | } 20 | return false; 21 | } 22 | //------------------------------------------------------------------------------------------------------------------------------ 23 | //set the distance to finish by adding the distance to the finish for the node n plus the distance from this node to node n 24 | setDistanceToFinish(n) { 25 | this.distToFinish = n.distToFinish + dist(this.pos.x, this.pos.y, n.pos.x, n.pos.y); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /WHG/Player.js: -------------------------------------------------------------------------------- 1 | class Player{ 2 | constructor(){ 3 | this.pos = createVector(3*tileSize + xoff,4* tileSize + yoff); 4 | this.vel = createVector(0,0); 5 | this.size = tileSize/2.0; 6 | this.playerSpeed = tileSize/15.0; 7 | this.dead = false; 8 | this.reachedGoal = false; 9 | this.fadeCounter = 255; 10 | this.isBest = false; 11 | this.deathByDot = false; 12 | this.deathAtStep = 0; 13 | this.moveCount = 0; 14 | this.gen =1; 15 | this.fitness = 0; 16 | this.nodes = []; 17 | this.fading = false; 18 | this.brain = new Brain(numberOfSteps); 19 | this.human = false; 20 | this.setNodes(); 21 | 22 | } 23 | 24 | setNodes() { 25 | this.nodes[0] = new Node(tiles[6][7]); 26 | this.nodes[1] = new Node(tiles[17][2]); 27 | this.nodes[0].setDistanceToFinish(this.nodes[1]); 28 | } 29 | 30 | show(){ 31 | fill(255, 0, 0, this.fadeCounter); 32 | if (this.isBest && !showBest) { 33 | fill(0, 255, 0, this.fadeCounter); 34 | } 35 | stroke(0, 0, 0, this.fadeCounter); 36 | strokeWeight(4); 37 | rect(this.pos.x, this.pos.y, this.size, this.size); 38 | stroke(0); 39 | } 40 | 41 | move(){ 42 | if (!humanPlaying){ 43 | if (this.moveCount == 0) {//move in the direction for 6 frames 44 | if (this.brain.directions.length > this.brain.step) {//if there are still directions left then set the velocity as the next PVector in the direcitons array 45 | this.vel = this.brain.directions[this.brain.step]; 46 | this.brain.step++; 47 | } else {//if at the end of the directions array then the player is dead 48 | this.dead = true; 49 | this.fading = true; 50 | } 51 | this.moveCount =6; 52 | } else { 53 | this.moveCount--; 54 | } 55 | } 56 | var temp = createVector(this.vel.x, this.vel.y); 57 | temp.normalize(); 58 | temp.mult(this.playerSpeed); 59 | for (var i = 0; i< solids.length; i++) { 60 | temp = solids[i].restrictMovement(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size), temp); 61 | } 62 | this.pos.add(temp); 63 | 64 | } 65 | 66 | //checks if the player 67 | checkCollisions() { 68 | for (var i = 0; i< dots.length; i++) { 69 | if (dots[i].collides(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size))) { 70 | this.fading = true; 71 | this.dead = true; 72 | this.deathByDot = true; 73 | this.deathAtStep = this.brain.step; 74 | } 75 | } 76 | if (winArea.collision(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size))) { 77 | this.reachedGoal = true; 78 | } 79 | for (var i = 0; i< this.nodes.length; i++) { 80 | this.nodes[i].collision(this.pos, createVector(this.pos.x+this.size, this.pos.y+this.size)); 81 | } 82 | } 83 | //---------------------------------------------------------------------------------------------------------------------------------------------------------- 84 | update() { 85 | if (!this.dead && !this.reachedGoal) { 86 | this.move(); 87 | this.checkCollisions(); 88 | } else if (this.fading) { 89 | if (this.fadeCounter > 0) { 90 | if(humanPlaying || replayGens){ 91 | this.fadeCounter -=10; 92 | }else{ 93 | this.fadeCounter = 0; 94 | 95 | } 96 | } 97 | } 98 | } 99 | //---------------------------------------------------------------------------------------------------------------------------------------------------------- 100 | 101 | calculateFitness() { 102 | if (this.reachedGoal) {//if the dot reached the goal then the fitness is based on the amount of steps it took to get there 103 | this.fitness = 1.0/16.0 + 10000.0/(this.brain.step * this.brain.step); 104 | } else {//if the dot didn't reach the goal then the fitness is based on how close it is to the goal 105 | var estimatedDistance = 0.0;//the estimated distance of the path from the player to the goal 106 | for (var i = this.nodes.length-1; i>=0; i--) { 107 | if (!this.nodes[i].reached) { 108 | estimatedDistance = this.nodes[i].distToFinish; 109 | estimatedDistance += dist(this.pos.x, this.pos.y, this.nodes[i].pos.x, this.nodes[i].pos.y); 110 | } 111 | } 112 | if (this.deathByDot) { 113 | estimatedDistance *= 0.9; 114 | } 115 | this.fitness = 1.0/(estimatedDistance * estimatedDistance); 116 | } 117 | this.fitness*=this.fitness; 118 | } 119 | 120 | 121 | 122 | //---------------------------------------------------------------------------------------------------------------------------------------------------------- 123 | gimmeBaby() { 124 | var baby = new Player(); 125 | baby.brain = this.brain.clone();//babies have the same brain as their parents 126 | baby.deathByDot = this.deathByDot; 127 | baby.deathAtStep = this.deathAtStep; 128 | baby.gen = this.gen; 129 | return baby; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /WHG/Population.js: -------------------------------------------------------------------------------- 1 | class Population { 2 | 3 | constructor(size) { 4 | this.players = []; 5 | this.fitnessSum = 0.0; 6 | this.gen = 1; 7 | this.bestPlayer =0; 8 | this.minStep = 10000; 9 | this.genPlayers = []; 10 | this.bestFitness = 0; 11 | this.solutionFound = false; 12 | 13 | for (var i = 0; i< size; i++) { 14 | this.players[i] = new Player(); 15 | } 16 | } 17 | 18 | 19 | //------------------------------------------------------------------------------------------------------------------------------ 20 | //show all players 21 | show() { 22 | if (!showBest) { 23 | for (var i = 1; i< this.players.length; i++) { 24 | this.players[i].show(); 25 | } 26 | } 27 | this.players[0].show(); 28 | } 29 | 30 | //------------------------------------------------------------------------------------------------------------------------------- 31 | //update all players 32 | update() { 33 | for (var i = 0; i< this.players.length; i++) { 34 | if (this.players[i].brain.step > this.minStep) {//if the player has already taken more steps than the best player has taken to reach the goal 35 | this.players[i].dead = true;//then it dead 36 | } else { 37 | this.players[i].update(); 38 | } 39 | } 40 | } 41 | 42 | //----------------------------------------------------------------------------------------------------------------------------------- 43 | //calculate all the fitnesses 44 | calculateFitness() { 45 | for (var i = 0; i< this.players.length; i++) { 46 | this.players[i].calculateFitness(); 47 | } 48 | } 49 | 50 | 51 | //------------------------------------------------------------------------------------------------------------------------------------ 52 | //returns whether all the players are either dead or have reached the goal 53 | allPlayersDead() { 54 | for (var i = 0; i< this.players.length; i++) { 55 | if (!this.players[i].dead && !this.players[i].reachedGoal) { 56 | return false; 57 | } 58 | } 59 | print("bah:"); 60 | return true; 61 | } 62 | 63 | 64 | 65 | //------------------------------------------------------------------------------------------------------------------------------------- 66 | 67 | //gets the next generation of players 68 | naturalSelection() { 69 | var newPlayers = [];//next gen 70 | this.setBestPlayer(); 71 | this.calculateFitnessSum(); 72 | 73 | //the champion lives on 74 | newPlayers[0] = this.players[this.bestPlayer].gimmeBaby(); 75 | newPlayers[0].isBest = true; 76 | for (var i = 1; i< populationSize; i++) { 77 | //select parent based on fitness 78 | var parent = this.selectParent(); 79 | 80 | //get baby from them 81 | newPlayers[i] = parent.gimmeBaby(); 82 | } 83 | 84 | // this.players = newPlayers.slice(); 85 | this.players = []; 86 | for(var i = 0 ; i< newPlayers.length;i++){ 87 | this.players[i] = newPlayers[i]; 88 | } 89 | this.gen ++; 90 | } 91 | 92 | 93 | //-------------------------------------------------------------------------------------------------------------------------------------- 94 | //you get it 95 | calculateFitnessSum() { 96 | this.fitnessSum = 0; 97 | for (var i = 0; i< this.players.length; i++) { 98 | this.fitnessSum += this.players[i].fitness; 99 | } 100 | } 101 | 102 | //------------------------------------------------------------------------------------------------------------------------------------- 103 | 104 | //chooses player from the population to return randomly(considering fitness) 105 | 106 | //this function works by randomly choosing a value between 0 and the sum of all the fitnesses 107 | //then go through all the players and add their fitness to a running sum and if that sum is greater than the random value generated that player is chosen 108 | //since players with a higher fitness function add more to the running sum then they have a higher chance of being chosen 109 | selectParent() { 110 | var rand = random(this.fitnessSum); 111 | 112 | 113 | var runningSum = 0; 114 | 115 | for (var i = 0; i< this.players.length; i++) { 116 | runningSum+= this.players[i].fitness; 117 | if (runningSum > rand) { 118 | return this.players[i]; 119 | } 120 | } 121 | 122 | //should never get to this point 123 | 124 | return null; 125 | } 126 | 127 | //------------------------------------------------------------------------------------------------------------------------------------------ 128 | //mutates all the brains of the babies 129 | mutateDemBabies() { 130 | for (var i = 1; i< this.players.length; i++) { 131 | this.players[i].brain.mutate(this.players[i].deathByDot, this.players[i].deathAtStep); 132 | this.players[i].deathByDot = false; 133 | this.players[i].gen = this.gen; 134 | } 135 | this.players[0].deathByDot = false; 136 | this.players[0].gen = this.gen; 137 | } 138 | 139 | //--------------------------------------------------------------------------------------------------------------------------------------------- 140 | //finds the player with the highest fitness and sets it as the best player 141 | setBestPlayer() { 142 | var max = 0; 143 | var maxIndex = 0; 144 | for (var i = 0; i< this.players.length; i++) { 145 | if (this.players[i].fitness > max) { 146 | max = this.players[i].fitness; 147 | maxIndex = i; 148 | } 149 | } 150 | 151 | this.bestPlayer = maxIndex; 152 | 153 | if (max > this.bestFitness) { 154 | this.bestFitness = max; 155 | this.genPlayers.push(this.players[this.bestPlayer].gimmeBaby()); 156 | } 157 | 158 | //if this player reached the goal then reset the minimum number of steps it takes to get to the goal 159 | if (this.players[this.bestPlayer].reachedGoal) { 160 | this.minStep = this.players[this.bestPlayer].brain.step; 161 | this.solutionFound = true; 162 | } 163 | } 164 | 165 | 166 | increaseMoves() { 167 | if (this.players[0].brain.directions.length < 120 && !this.solutionFound) { 168 | for (var i = 0; i< this.players.length; i++) { 169 | this.players[i].brain.increaseMoves(); 170 | } 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /WHG/Solid.js: -------------------------------------------------------------------------------- 1 | class Solid { 2 | 3 | constructor(topL,botR){ 4 | var lineWidth = 1; 5 | this.pos = createVector(topL.pixelPos.x-lineWidth, topL.pixelPos.y-lineWidth); 6 | this.w = botR.pixelPos.x + tileSize - this.pos.x + lineWidth; 7 | this.h = botR.pixelPos.y + tileSize - this.pos.y + lineWidth; 8 | this.bottomRight = createVector(this.pos.x + this.w, this.pos.y + this.h); 9 | 10 | } 11 | 12 | 13 | restrictMovement(tl, br, movement) {//player dimensions 14 | //add the x first 15 | 16 | var x = movement.x; 17 | var y = movement.y; 18 | // 19 | // movement.x = round(movement.x); 20 | // movement.y = round(movement.y); 21 | var ptl = createVector(tl.x+movement.x, tl.y); 22 | var pbr = createVector(br.x+movement.x, br.y); 23 | 24 | if ((ptl.x this.pos.x) &&( ptl.y < this.bottomRight.y && pbr.y > this.pos.y)) { 25 | 26 | x=0; 27 | } 28 | 29 | //check the y movement 30 | ptl = createVector(tl.x, tl.y +movement.y); 31 | pbr = createVector(br.x, br.y + movement.y); 32 | if ((ptl.x this.pos.x) &&( ptl.y < this.bottomRight.y && pbr.y > this.pos.y)) { 33 | y=0; 34 | } 35 | 36 | return createVector(x, y); 37 | } 38 | 39 | collision(ptl, pbr) {//player dimensions 40 | //add the x first 41 | 42 | if ((ptl.x this.pos.x) &&( ptl.y < this.bottomRight.y && pbr.y > this.pos.y)) { 43 | return true; 44 | } 45 | return false; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /WHG/Tile.js: -------------------------------------------------------------------------------- 1 | class Tile{ 2 | 3 | constructor(x,y){ 4 | this.matrixPos = createVector(x,y); 5 | this.pixelPos = createVector(x*tileSize+xoff, y*tileSize+yoff); 6 | this.safe = false; 7 | this.goal = false; 8 | this.wall = false; 9 | this.edges = []; 10 | 11 | } 12 | 13 | show(){ 14 | if ((this.matrixPos.x +this.matrixPos.y) % 2 ==0) { 15 | fill(247,247,255); 16 | } else { 17 | fill(230,230,255); 18 | } 19 | if (this.wall) { 20 | fill(180, 181, 254); 21 | } 22 | if (this.goal || this.safe) { 23 | fill(181, 254, 180); 24 | } 25 | noStroke(); 26 | rect(this.pixelPos.x,this.pixelPos.y,tileSize,tileSize); 27 | 28 | } 29 | 30 | showEdges(){ 31 | for (var i = 0; i< this.edges.length; i++) { 32 | stroke(0); 33 | strokeWeight(4); 34 | switch(this.edges[i]) { 35 | case 4: 36 | line(this.pixelPos.x, this.pixelPos.y, this.pixelPos.x+tileSize,this.pixelPos.y); 37 | break; 38 | case 1: 39 | line(this.pixelPos.x+tileSize, this.pixelPos.y, this.pixelPos.x+tileSize, this.pixelPos.y+tileSize); 40 | break; 41 | case 2: 42 | line(this.pixelPos.x, this.pixelPos.y+tileSize, this.pixelPos.x+tileSize, this.pixelPos.y+tileSize); 43 | break; 44 | case 3: 45 | line(this.pixelPos.x, this.pixelPos.y, this.pixelPos.x, this.pixelPos.y+tileSize); 46 | break; 47 | } 48 | } 49 | } 50 | 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /WHG/assets/DAB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Code-Bullet/WorldsHardestGameAI/2eb083b238857de88c6a48563cba6df62cb7968f/WHG/assets/DAB.png -------------------------------------------------------------------------------- /WHG/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |

hi my name is Evan and this is my thing, I hope you enjoy. Use WASD controls for gameplay

21 |

The next level is up so check it out Next Level

22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /WHG/libraries/p5.dom.js: -------------------------------------------------------------------------------- 1 | /*! p5.dom.js v0.3.2 March 25, 2017 */ 2 | /** 3 | *

The web is much more than just canvas and p5.dom makes it easy to interact 4 | * with other HTML5 objects, including text, hyperlink, image, input, video, 5 | * audio, and webcam.

6 | *

There is a set of creation methods, DOM manipulation methods, and 7 | * an extended p5.Element that supports a range of HTML elements. See the 8 | * 9 | * beyond the canvas tutorial for a full overview of how this addon works. 10 | * 11 | *

Methods and properties shown in black are part of the p5.js core, items in 12 | * blue are part of the p5.dom library. You will need to include an extra file 13 | * in order to access the blue functions. See the 14 | * using a library 15 | * section for information on how to include this library. p5.dom comes with 16 | * p5 complete or you can download the single file 17 | * 18 | * here.

19 | *

See tutorial: beyond the canvas 20 | * for more info on how to use this libary. 21 | * 22 | * @module p5.dom 23 | * @submodule p5.dom 24 | * @for p5.dom 25 | * @main 26 | */ 27 | 28 | (function (root, factory) { 29 | if (typeof define === 'function' && define.amd) 30 | define('p5.dom', ['p5'], function (p5) { (factory(p5));}); 31 | else if (typeof exports === 'object') 32 | factory(require('../p5')); 33 | else 34 | factory(root['p5']); 35 | }(this, function (p5) { 36 | 37 | // ============================================================================= 38 | // p5 additions 39 | // ============================================================================= 40 | 41 | /** 42 | * Searches the page for an element with the given ID, class, or tag name (using the '#' or '.' 43 | * prefixes to specify an ID or class respectively, and none for a tag) and returns it as 44 | * a p5.Element. If a class or tag name is given with more than 1 element, 45 | * only the first element will be returned. 46 | * The DOM node itself can be accessed with .elt. 47 | * Returns null if none found. You can also specify a container to search within. 48 | * 49 | * @method select 50 | * @param {String} name id, class, or tag name of element to search for 51 | * @param {String} [container] id, p5.Element, or HTML element to search within 52 | * @return {Object|p5.Element|Null} p5.Element containing node found 53 | * @example 54 | *

55 | * function setup() { 56 | * createCanvas(100,100); 57 | * //translates canvas 50px down 58 | * select('canvas').position(100, 100); 59 | * } 60 | *
61 | *
62 | * // these are all valid calls to select() 63 | * var a = select('#moo'); 64 | * var b = select('#blah', '#myContainer'); 65 | * var c = select('#foo', b); 66 | * var d = document.getElementById('beep'); 67 | * var e = select('p', d); 68 | *
69 | * 70 | */ 71 | p5.prototype.select = function (e, p) { 72 | var res = null; 73 | var container = getContainer(p); 74 | if (e[0] === '.'){ 75 | e = e.slice(1); 76 | res = container.getElementsByClassName(e); 77 | if (res.length) { 78 | res = res[0]; 79 | } else { 80 | res = null; 81 | } 82 | }else if (e[0] === '#'){ 83 | e = e.slice(1); 84 | res = container.getElementById(e); 85 | }else { 86 | res = container.getElementsByTagName(e); 87 | if (res.length) { 88 | res = res[0]; 89 | } else { 90 | res = null; 91 | } 92 | } 93 | if (res) { 94 | return wrapElement(res); 95 | } else { 96 | return null; 97 | } 98 | }; 99 | 100 | /** 101 | * Searches the page for elements with the given class or tag name (using the '.' prefix 102 | * to specify a class and no prefix for a tag) and returns them as p5.Elements 103 | * in an array. 104 | * The DOM node itself can be accessed with .elt. 105 | * Returns an empty array if none found. 106 | * You can also specify a container to search within. 107 | * 108 | * @method selectAll 109 | * @param {String} name class or tag name of elements to search for 110 | * @param {String} [container] id, p5.Element, or HTML element to search within 111 | * @return {Array} Array of p5.Elements containing nodes found 112 | * @example 113 | *
114 | * function setup() { 115 | * createButton('btn'); 116 | * createButton('2nd btn'); 117 | * createButton('3rd btn'); 118 | * var buttons = selectAll('button'); 119 | * 120 | * for (var i = 0; i < buttons.length; i++){ 121 | * buttons[i].size(100,100); 122 | * } 123 | * } 124 | *
125 | *
126 | * // these are all valid calls to selectAll() 127 | * var a = selectAll('.moo'); 128 | * var b = selectAll('div'); 129 | * var c = selectAll('button', '#myContainer'); 130 | * var d = select('#container'); 131 | * var e = selectAll('p', d); 132 | * var f = document.getElementById('beep'); 133 | * var g = select('.blah', f); 134 | *
135 | * 136 | */ 137 | p5.prototype.selectAll = function (e, p) { 138 | var arr = []; 139 | var res; 140 | var container = getContainer(p); 141 | if (e[0] === '.'){ 142 | e = e.slice(1); 143 | res = container.getElementsByClassName(e); 144 | } else { 145 | res = container.getElementsByTagName(e); 146 | } 147 | if (res) { 148 | for (var j = 0; j < res.length; j++) { 149 | var obj = wrapElement(res[j]); 150 | arr.push(obj); 151 | } 152 | } 153 | return arr; 154 | }; 155 | 156 | /** 157 | * Helper function for select and selectAll 158 | */ 159 | function getContainer(p) { 160 | var container = document; 161 | if (typeof p === 'string' && p[0] === '#'){ 162 | p = p.slice(1); 163 | container = document.getElementById(p) || document; 164 | } else if (p instanceof p5.Element){ 165 | container = p.elt; 166 | } else if (p instanceof HTMLElement){ 167 | container = p; 168 | } 169 | return container; 170 | } 171 | 172 | /** 173 | * Helper function for getElement and getElements. 174 | */ 175 | function wrapElement(elt) { 176 | if(elt.tagName === "INPUT" && elt.type === "checkbox") { 177 | var converted = new p5.Element(elt); 178 | converted.checked = function(){ 179 | if (arguments.length === 0){ 180 | return this.elt.checked; 181 | } else if(arguments[0]) { 182 | this.elt.checked = true; 183 | } else { 184 | this.elt.checked = false; 185 | } 186 | return this; 187 | }; 188 | return converted; 189 | } else if (elt.tagName === "VIDEO" || elt.tagName === "AUDIO") { 190 | return new p5.MediaElement(elt); 191 | } else { 192 | return new p5.Element(elt); 193 | } 194 | } 195 | 196 | /** 197 | * Removes all elements created by p5, except any canvas / graphics 198 | * elements created by createCanvas or createGraphics. 199 | * Event handlers are removed, and element is removed from the DOM. 200 | * @method removeElements 201 | * @example 202 | *
203 | * function setup() { 204 | * createCanvas(100, 100); 205 | * createDiv('this is some text'); 206 | * createP('this is a paragraph'); 207 | * } 208 | * function mousePressed() { 209 | * removeElements(); // this will remove the div and p, not canvas 210 | * } 211 | *
212 | * 213 | */ 214 | p5.prototype.removeElements = function (e) { 215 | for (var i=0; i 243 | * var myDiv; 244 | * function setup() { 245 | * myDiv = createDiv('this is some text'); 246 | * } 247 | * 248 | */ 249 | 250 | /** 251 | * Creates a <p></p> element in the DOM with given inner HTML. Used 252 | * for paragraph length text. 253 | * Appends to the container node if one is specified, otherwise 254 | * appends to body. 255 | * 256 | * @method createP 257 | * @param {String} html inner HTML for element created 258 | * @return {Object|p5.Element} pointer to p5.Element holding created node 259 | * @example 260 | *
261 | * var myP; 262 | * function setup() { 263 | * myP = createP('this is some text'); 264 | * } 265 | *
266 | */ 267 | 268 | /** 269 | * Creates a <span></span> element in the DOM with given inner HTML. 270 | * Appends to the container node if one is specified, otherwise 271 | * appends to body. 272 | * 273 | * @method createSpan 274 | * @param {String} html inner HTML for element created 275 | * @return {Object|p5.Element} pointer to p5.Element holding created node 276 | * @example 277 | *
278 | * var mySpan; 279 | * function setup() { 280 | * mySpan = createSpan('this is some text'); 281 | * } 282 | *
283 | */ 284 | var tags = ['div', 'p', 'span']; 285 | tags.forEach(function(tag) { 286 | var method = 'create' + tag.charAt(0).toUpperCase() + tag.slice(1); 287 | p5.prototype[method] = function(html) { 288 | var elt = document.createElement(tag); 289 | elt.innerHTML = typeof html === undefined ? "" : html; 290 | return addElement(elt, this); 291 | } 292 | }); 293 | 294 | /** 295 | * Creates an <img> element in the DOM with given src and 296 | * alternate text. 297 | * Appends to the container node if one is specified, otherwise 298 | * appends to body. 299 | * 300 | * @method createImg 301 | * @param {String} src src path or url for image 302 | * @param {String} [alt] alternate text to be used if image does not load 303 | * @param {Function} [successCallback] callback to be called once image data is loaded 304 | * @return {Object|p5.Element} pointer to p5.Element holding created node 305 | * @example 306 | *
307 | * var img; 308 | * function setup() { 309 | * img = createImg('http://p5js.org/img/asterisk-01.png'); 310 | * } 311 | *
312 | */ 313 | p5.prototype.createImg = function() { 314 | var elt = document.createElement('img'); 315 | var args = arguments; 316 | var self; 317 | var setAttrs = function(){ 318 | self.width = elt.offsetWidth || elt.width; 319 | self.height = elt.offsetHeight || elt.height; 320 | if (args.length > 1 && typeof args[1] === 'function'){ 321 | self.fn = args[1]; 322 | self.fn(); 323 | }else if (args.length > 1 && typeof args[2] === 'function'){ 324 | self.fn = args[2]; 325 | self.fn(); 326 | } 327 | }; 328 | elt.src = args[0]; 329 | if (args.length > 1 && typeof args[1] === 'string'){ 330 | elt.alt = args[1]; 331 | } 332 | elt.onload = function(){ 333 | setAttrs(); 334 | } 335 | self = addElement(elt, this); 336 | return self; 337 | }; 338 | 339 | /** 340 | * Creates an <a></a> element in the DOM for including a hyperlink. 341 | * Appends to the container node if one is specified, otherwise 342 | * appends to body. 343 | * 344 | * @method createA 345 | * @param {String} href url of page to link to 346 | * @param {String} html inner html of link element to display 347 | * @param {String} [target] target where new link should open, 348 | * could be _blank, _self, _parent, _top. 349 | * @return {Object|p5.Element} pointer to p5.Element holding created node 350 | * @example 351 | *
352 | * var myLink; 353 | * function setup() { 354 | * myLink = createA('http://p5js.org/', 'this is a link'); 355 | * } 356 | *
357 | */ 358 | p5.prototype.createA = function(href, html, target) { 359 | var elt = document.createElement('a'); 360 | elt.href = href; 361 | elt.innerHTML = html; 362 | if (target) elt.target = target; 363 | return addElement(elt, this); 364 | }; 365 | 366 | /** INPUT **/ 367 | 368 | 369 | /** 370 | * Creates a slider <input></input> element in the DOM. 371 | * Use .size() to set the display length of the slider. 372 | * Appends to the container node if one is specified, otherwise 373 | * appends to body. 374 | * 375 | * @method createSlider 376 | * @param {Number} min minimum value of the slider 377 | * @param {Number} max maximum value of the slider 378 | * @param {Number} [value] default value of the slider 379 | * @param {Number} [step] step size for each tick of the slider (if step is set to 0, the slider will move continuously from the minimum to the maximum value) 380 | * @return {Object|p5.Element} pointer to p5.Element holding created node 381 | * @example 382 | *
383 | * var slider; 384 | * function setup() { 385 | * slider = createSlider(0, 255, 100); 386 | * slider.position(10, 10); 387 | * slider.style('width', '80px'); 388 | * } 389 | * 390 | * function draw() { 391 | * var val = slider.value(); 392 | * background(val); 393 | * } 394 | *
395 | * 396 | *
397 | * var slider; 398 | * function setup() { 399 | * colorMode(HSB); 400 | * slider = createSlider(0, 360, 60, 40); 401 | * slider.position(10, 10); 402 | * slider.style('width', '80px'); 403 | * } 404 | * 405 | * function draw() { 406 | * var val = slider.value(); 407 | * background(val, 100, 100, 1); 408 | * } 409 | *
410 | */ 411 | p5.prototype.createSlider = function(min, max, value, step) { 412 | var elt = document.createElement('input'); 413 | elt.type = 'range'; 414 | elt.min = min; 415 | elt.max = max; 416 | if (step === 0) { 417 | elt.step = .000000000000000001; // smallest valid step 418 | } else if (step) { 419 | elt.step = step; 420 | } 421 | if (typeof(value) === "number") elt.value = value; 422 | return addElement(elt, this); 423 | }; 424 | 425 | /** 426 | * Creates a <button></button> element in the DOM. 427 | * Use .size() to set the display size of the button. 428 | * Use .mousePressed() to specify behavior on press. 429 | * Appends to the container node if one is specified, otherwise 430 | * appends to body. 431 | * 432 | * @method createButton 433 | * @param {String} label label displayed on the button 434 | * @param {String} [value] value of the button 435 | * @return {Object|p5.Element} pointer to p5.Element holding created node 436 | * @example 437 | *
438 | * var button; 439 | * function setup() { 440 | * createCanvas(100, 100); 441 | * background(0); 442 | * button = createButton('click me'); 443 | * button.position(19, 19); 444 | * button.mousePressed(changeBG); 445 | * } 446 | * 447 | * function changeBG() { 448 | * var val = random(255); 449 | * background(val); 450 | * } 451 | *
452 | */ 453 | p5.prototype.createButton = function(label, value) { 454 | var elt = document.createElement('button'); 455 | elt.innerHTML = label; 456 | elt.value = value; 457 | if (value) elt.value = value; 458 | return addElement(elt, this); 459 | }; 460 | 461 | /** 462 | * Creates a checkbox <input></input> element in the DOM. 463 | * Calling .checked() on a checkbox returns if it is checked or not 464 | * 465 | * @method createCheckbox 466 | * @param {String} [label] label displayed after checkbox 467 | * @param {boolean} [value] value of the checkbox; checked is true, unchecked is false.Unchecked if no value given 468 | * @return {Object|p5.Element} pointer to p5.Element holding created node 469 | * @example 470 | *
471 | * var checkbox; 472 | * 473 | * function setup() { 474 | * checkbox = createCheckbox('label', false); 475 | * checkbox.changed(myCheckedEvent); 476 | * } 477 | * 478 | * function myCheckedEvent() { 479 | * if (this.checked()) { 480 | * console.log("Checking!"); 481 | * } else { 482 | * console.log("Unchecking!"); 483 | * } 484 | * } 485 | *
486 | */ 487 | p5.prototype.createCheckbox = function() { 488 | var elt = document.createElement('div'); 489 | var checkbox = document.createElement('input'); 490 | checkbox.type = 'checkbox'; 491 | elt.appendChild(checkbox); 492 | //checkbox must be wrapped in p5.Element before label so that label appears after 493 | var self = addElement(elt, this); 494 | self.checked = function(){ 495 | var cb = self.elt.getElementsByTagName('input')[0]; 496 | if (cb) { 497 | if (arguments.length === 0){ 498 | return cb.checked; 499 | }else if(arguments[0]){ 500 | cb.checked = true; 501 | }else{ 502 | cb.checked = false; 503 | } 504 | } 505 | return self; 506 | }; 507 | this.value = function(val){ 508 | self.value = val; 509 | return this; 510 | }; 511 | if (arguments[0]){ 512 | var ran = Math.random().toString(36).slice(2); 513 | var label = document.createElement('label'); 514 | checkbox.setAttribute('id', ran); 515 | label.htmlFor = ran; 516 | self.value(arguments[0]); 517 | label.appendChild(document.createTextNode(arguments[0])); 518 | elt.appendChild(label); 519 | } 520 | if (arguments[1]){ 521 | checkbox.checked = true; 522 | } 523 | return self; 524 | }; 525 | 526 | /** 527 | * Creates a dropdown menu <select></select> element in the DOM. 528 | * @method createSelect 529 | * @param {boolean} [multiple] true if dropdown should support multiple selections 530 | * @return {Object|p5.Element} pointer to p5.Element holding created node 531 | * @example 532 | *
533 | * var sel; 534 | * 535 | * function setup() { 536 | * textAlign(CENTER); 537 | * background(200); 538 | * sel = createSelect(); 539 | * sel.position(10, 10); 540 | * sel.option('pear'); 541 | * sel.option('kiwi'); 542 | * sel.option('grape'); 543 | * sel.changed(mySelectEvent); 544 | * } 545 | * 546 | * function mySelectEvent() { 547 | * var item = sel.value(); 548 | * background(200); 549 | * text("it's a "+item+"!", 50, 50); 550 | * } 551 | *
552 | */ 553 | p5.prototype.createSelect = function(mult) { 554 | var elt = document.createElement('select'); 555 | if (mult){ 556 | elt.setAttribute('multiple', 'true'); 557 | } 558 | var self = addElement(elt, this); 559 | self.option = function(name, value){ 560 | var opt = document.createElement('option'); 561 | opt.innerHTML = name; 562 | if (arguments.length > 1) 563 | opt.value = value; 564 | else 565 | opt.value = name; 566 | elt.appendChild(opt); 567 | }; 568 | self.selected = function(value){ 569 | var arr = []; 570 | if (arguments.length > 0){ 571 | for (var i = 0; i < this.elt.length; i++){ 572 | if (value.toString() === this.elt[i].value){ 573 | this.elt.selectedIndex = i; 574 | } 575 | } 576 | return this; 577 | }else{ 578 | if (mult){ 579 | for (var i = 0; i < this.elt.selectedOptions.length; i++){ 580 | arr.push(this.elt.selectedOptions[i].value); 581 | } 582 | return arr; 583 | }else{ 584 | return this.elt.value; 585 | } 586 | } 587 | }; 588 | return self; 589 | }; 590 | 591 | /** 592 | * Creates a radio button <input></input> element in the DOM. 593 | * The .option() method can be used to set options for the radio after it is 594 | * created. The .value() method will return the currently selected option. 595 | * 596 | * @method createRadio 597 | * @param {String} [divId] the id and name of the created div and input field respectively 598 | * @return {Object|p5.Element} pointer to p5.Element holding created node 599 | * @example 600 | *
601 | * var radio; 602 | * 603 | * function setup() { 604 | * radio = createRadio(); 605 | * radio.option("black"); 606 | * radio.option("white"); 607 | * radio.option("gray"); 608 | * radio.style('width', '60px'); 609 | * textAlign(CENTER); 610 | * fill(255, 0, 0); 611 | * } 612 | * 613 | * function draw() { 614 | * var val = radio.value(); 615 | * background(val); 616 | * text(val, width/2, height/2); 617 | * } 618 | *
619 | *
620 | * var radio; 621 | * 622 | * function setup() { 623 | * radio = createRadio(); 624 | * radio.option('apple', 1); 625 | * radio.option('bread', 2); 626 | * radio.option('juice', 3); 627 | * radio.style('width', '60px'); 628 | * textAlign(CENTER); 629 | * } 630 | * 631 | * function draw() { 632 | * background(200); 633 | * var val = radio.value(); 634 | * if (val) { 635 | * text('item cost is $'+val, width/2, height/2); 636 | * } 637 | * } 638 | *
639 | */ 640 | p5.prototype.createRadio = function() { 641 | var radios = document.querySelectorAll("input[type=radio]"); 642 | var count = 0; 643 | if(radios.length > 1){ 644 | var length = radios.length; 645 | var prev=radios[0].name; 646 | var current = radios[1].name; 647 | count = 1; 648 | for(var i = 1; i < length; i++) { 649 | current = radios[i].name; 650 | if(prev != current){ 651 | count++; 652 | } 653 | prev = current; 654 | } 655 | } 656 | else if (radios.length == 1){ 657 | count = 1; 658 | } 659 | var elt = document.createElement('div'); 660 | var self = addElement(elt, this); 661 | var times = -1; 662 | self.option = function(name, value){ 663 | var opt = document.createElement('input'); 664 | opt.type = 'radio'; 665 | opt.innerHTML = name; 666 | if (arguments.length > 1) 667 | opt.value = value; 668 | else 669 | opt.value = name; 670 | opt.setAttribute('name',"defaultradio"+count); 671 | elt.appendChild(opt); 672 | if (name){ 673 | times++; 674 | var ran = Math.random().toString(36).slice(2); 675 | var label = document.createElement('label'); 676 | opt.setAttribute('id', "defaultradio"+count+"-"+times); 677 | label.htmlFor = "defaultradio"+count+"-"+times; 678 | label.appendChild(document.createTextNode(name)); 679 | elt.appendChild(label); 680 | } 681 | return opt; 682 | }; 683 | self.selected = function(){ 684 | var length = this.elt.childNodes.length; 685 | if(arguments.length == 1) { 686 | for (var i = 0; i < length; i+=2){ 687 | if(this.elt.childNodes[i].value == arguments[0]) 688 | this.elt.childNodes[i].checked = true; 689 | } 690 | return this; 691 | } else { 692 | for (var i = 0; i < length; i+=2){ 693 | if(this.elt.childNodes[i].checked == true) 694 | return this.elt.childNodes[i].value; 695 | } 696 | } 697 | }; 698 | self.value = function(){ 699 | var length = this.elt.childNodes.length; 700 | if(arguments.length == 1) { 701 | for (var i = 0; i < length; i+=2){ 702 | if(this.elt.childNodes[i].value == arguments[0]) 703 | this.elt.childNodes[i].checked = true; 704 | } 705 | return this; 706 | } else { 707 | for (var i = 0; i < length; i+=2){ 708 | if(this.elt.childNodes[i].checked == true) 709 | return this.elt.childNodes[i].value; 710 | } 711 | return ""; 712 | } 713 | }; 714 | return self 715 | }; 716 | 717 | /** 718 | * Creates an <input></input> element in the DOM for text input. 719 | * Use .size() to set the display length of the box. 720 | * Appends to the container node if one is specified, otherwise 721 | * appends to body. 722 | * 723 | * @method createInput 724 | * @param {Number} [value] default value of the input box 725 | * @param {String} [type] type of text, ie text, password etc. Defaults to text 726 | * @return {Object|p5.Element} pointer to p5.Element holding created node 727 | * @example 728 | *
729 | * function setup(){ 730 | * var inp = createInput(''); 731 | * inp.input(myInputEvent); 732 | * } 733 | * 734 | * function myInputEvent(){ 735 | * console.log('you are typing: ', this.value()); 736 | * } 737 | * 738 | *
739 | */ 740 | p5.prototype.createInput = function(value, type) { 741 | var elt = document.createElement('input'); 742 | elt.type = type ? type : 'text'; 743 | if (value) elt.value = value; 744 | return addElement(elt, this); 745 | }; 746 | 747 | /** 748 | * Creates an <input></input> element in the DOM of type 'file'. 749 | * This allows users to select local files for use in a sketch. 750 | * 751 | * @method createFileInput 752 | * @param {Function} [callback] callback function for when a file loaded 753 | * @param {String} [multiple] optional to allow multiple files selected 754 | * @return {Object|p5.Element} pointer to p5.Element holding created DOM element 755 | * @example 756 | * var input; 757 | * var img; 758 | * 759 | * function setup() { 760 | * input = createFileInput(handleFile); 761 | * input.position(0, 0); 762 | * } 763 | * 764 | * function draw() { 765 | * if (img) { 766 | * image(img, 0, 0, width, height); 767 | * } 768 | * } 769 | * 770 | * function handleFile(file) { 771 | * print(file); 772 | * if (file.type === 'image') { 773 | * img = createImg(file.data); 774 | * img.hide(); 775 | * } 776 | * } 777 | */ 778 | p5.prototype.createFileInput = function(callback, multiple) { 779 | 780 | // Is the file stuff supported? 781 | if (window.File && window.FileReader && window.FileList && window.Blob) { 782 | // Yup, we're ok and make an input file selector 783 | var elt = document.createElement('input'); 784 | elt.type = 'file'; 785 | 786 | // If we get a second argument that evaluates to true 787 | // then we are looking for multiple files 788 | if (multiple) { 789 | // Anything gets the job done 790 | elt.multiple = 'multiple'; 791 | } 792 | 793 | // Function to handle when a file is selected 794 | // We're simplifying life and assuming that we always 795 | // want to load every selected file 796 | function handleFileSelect(evt) { 797 | // These are the files 798 | var files = evt.target.files; 799 | // Load each one and trigger a callback 800 | for (var i = 0; i < files.length; i++) { 801 | var f = files[i]; 802 | var reader = new FileReader(); 803 | function makeLoader(theFile) { 804 | // Making a p5.File object 805 | var p5file = new p5.File(theFile); 806 | return function(e) { 807 | p5file.data = e.target.result; 808 | callback(p5file); 809 | }; 810 | }; 811 | reader.onload = makeLoader(f); 812 | 813 | // Text or data? 814 | // This should likely be improved 815 | if (f.type.indexOf('text') > -1) { 816 | reader.readAsText(f); 817 | } else { 818 | reader.readAsDataURL(f); 819 | } 820 | } 821 | } 822 | 823 | // Now let's handle when a file was selected 824 | elt.addEventListener('change', handleFileSelect, false); 825 | return addElement(elt, this); 826 | } else { 827 | console.log('The File APIs are not fully supported in this browser. Cannot create element.'); 828 | } 829 | }; 830 | 831 | 832 | /** VIDEO STUFF **/ 833 | 834 | function createMedia(pInst, type, src, callback) { 835 | var elt = document.createElement(type); 836 | 837 | // allow src to be empty 838 | var src = src || ''; 839 | if (typeof src === 'string') { 840 | src = [src]; 841 | } 842 | for (var i=0; i