/*var seedSlider = document.getElementById('sliderRange') seedSlider.onChange = function(){ return this.value; } var citiesSlider = document.getElementById('nRange') citiesSlider.onChange = function(){ return this.value; }*/ var Seed = 21//seedChange(11); var totalCities = 25//citiesChange(9); // Sketch One var randomSearch = function( p ) { // p could be any variable name var cities = []; var recordDistance; var bestEver; var localSeed = Seed; var localCities = totalCities; p.setup = function() { p.createCanvas(400, 400); p.setupPoints(Seed, totalCities); } p.setupPoints = function(rngSeed, numCities){ p.randomSeed(rngSeed); for (var i = 0; i < numCities; i++) { var v = p.createVector(p.random(p.width), p.random(p.height/2)); cities[i] = v; } var d = p.calcDistance(cities); recordDistance = d; bestEver = cities.slice(); } p.draw = function() { if(localSeed != Seed){ p.setupPoints(Seed, localCities); localSeed = Seed; } if(localCities != totalCities){ setupPoints(localSeed, totalCities); localCities = totalCities; } p.background(0); p.fill(255); p.stroke(255); for (var i = 0; i < cities.length; i++) { p.ellipse(cities[i].x, cities[i].y, 8, 8); } p.stroke(255, 0, 255); p.strokeWeight(4); p.noFill(); p.beginShape(); for (var i = 0; i < cities.length; i++) { p.vertex(bestEver[i].x, bestEver[i].y); } p.endShape(); p.stroke(255); p.translate(0 , p.height/2); p.strokeWeight(1); p.noFill(); p.beginShape(); for (var i = 0; i < cities.length; i++) { p.vertex(cities[i].x, cities[i].y); } p.endShape(); var i = p.floor(p.random(cities.length)); var j = p.floor(p.random(cities.length)); p.swap(cities, i, j); var d = p.calcDistance(cities); if (d < recordDistance) { recordDistance = d; bestEver = cities.slice(); } } p.swap = function(a, i, j) { var temp = a[i]; a[i] = a[j]; a[j] = temp; } p.calcDistance = function(points) { var sum = 0; for (var i = 0; i < points.length - 1; i++) { var d = p.dist(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y); sum += d; } return sum; } }; var myp5 = new p5(randomSearch, 'c1'); // Sketch Two var lexicographicOrder = function( q ) { var cities = []; var order = []; var totalPermutations; var count = 0; var recordDistance; var bestEver; q.setup = function() { q.randomSeed(Seed); q.createCanvas(400, 400); for (var i = 0; i < totalCities; i++) { var v = q.createVector(q.random(q.width), q.random(q.height / 2)); cities[i] = v; order[i] = i; } var d = q.calcDistance(cities, order); recordDistance = d; bestEver = order.slice(); } q.draw = function() { q.background(0); q.fill(255); for (var i = 0; i < cities.length; i++) { q.ellipse(cities[i].x, cities[i].y, 8, 8); } q.stroke(255, 0, 255); q.strokeWeight(4); q.noFill(); q.beginShape(); for (var i = 0; i < order.length; i++) { var n = bestEver[i]; q.vertex(cities[n].x, cities[n].y); } q.endShape(); q.translate(0, q.height / 2); q.stroke(255); q.strokeWeight(1); q.noFill(); q.beginShape(); for (var i = 0; i < order.length; i++) { var n = order[i]; q.vertex(cities[n].x, cities[n].y); } q.endShape(); var d = q.calcDistance(cities, order); if (d < recordDistance) { recordDistance = d; bestEver = order.slice(); } q.nextOrder(); } q.swap = function(a, i, j) { var temp = a[i]; a[i] = a[j]; a[j] = temp; } q.calcDistance = function(points, order) { var sum = 0; for (var i = 0; i < order.length - 1; i++) { var cityAIndex = order[i]; var cityA = points[cityAIndex]; var cityBIndex = order[i + 1]; var cityB = points[cityBIndex]; var d = q.dist(cityA.x, cityA.y, cityB.x, cityB.y); sum += d; } return sum; } // This is my lexical order algorithm q.nextOrder = function() { // STEP 1 of the algorithm // https://www.quora.com/How-would-you-explain-an-algorithm-that-generates-permutations-using-lexicographic-ordering var largestI = -1; for (var i = 0; i < order.length - 1; i++) { if (order[i] < order[i + 1]) { largestI = i; } } if (largestI == -1) { q.noLoop(); } // STEP 2 var largestJ = -1; for (var j = 0; j < order.length; j++) { if (order[largestI] < order[j]) { largestJ = j; } } // STEP 3 q.swap(order, largestI, largestJ); // STEP 4: reverse from largestI + 1 to the end var endArray = order.splice(largestI + 1); endArray.reverse(); order = order.concat(endArray); } }; var myp5 = new p5(lexicographicOrder, 'c2'); var geneticSearch = function( p ) { var cities = []; var popSize = 500; var population = []; var fitness = []; var recordDistance = Infinity; var bestEver; var currentBest; var statusP; p.setup = function(){ p.randomSeed(Seed); p.createCanvas(400, 400); var order = []; for (var i = 0; i < totalCities; i++) { var v = p.createVector(p.random(p.width), p.random(p.height / 2)); cities[i] = v; order[i] = i; } for (var i = 0; i < popSize; i++) { population[i] = p.shuffle(order); } statusP = p.createP('').style('font-size', '32pt'); } p.draw = function() { p.background(0); p.stroke(255); p.fill(255); for (var i = 0; i < cities.length; i++) { p.ellipse(cities[i].x, cities[i].y, 8, 8); } p.calculateFitness(); p.normalizeFitness(); p.nextGeneration(); p.noFill(); p.strokeWeight(4); p.beginShape(); for (var i = 0; i < bestEver.length; i++) { var n = bestEver[i]; p.stroke(255, 0, 255); p.vertex(cities[n].x, cities[n].y); //p.stroke(255); //p.ellipse(cities[n].x, cities[n].y, 8, 8); } p.endShape(); p.translate(0, p.height / 2); p.stroke(255); p.strokeWeight(1); p.noFill(); p.beginShape(); for (var i = 0; i < currentBest.length; i++) { var n = currentBest[i]; p.vertex(cities[n].x, cities[n].y); //p.ellipse(cities[n].x, cities[n].y, 8, 8); } p.endShape(); } p.swap = function(a, i, j) { var temp = a[i]; a[i] = a[j]; a[j] = temp; } p.calcDistance = function(points, order) { var sum = 0; for (var i = 0; i < order.length - 1; i++) { var cityAIndex = order[i]; var cityA = points[cityAIndex]; var cityBIndex = order[i + 1]; var cityB = points[cityBIndex]; var d = p.dist(cityA.x, cityA.y, cityB.x, cityB.y); sum += d; } return sum; } p.calculateFitness = function() { var currentRecord = Infinity; for (var i = 0; i < population.length; i++) { var d = p.calcDistance(cities, population[i]); if (d < recordDistance) { recordDistance = d; bestEver = population[i]; } if (d < currentRecord) { currentRecord = d; currentBest = population[i]; } fitness[i] = 1 / (p.pow(d, 8) + 1); } } p.normalizeFitness = function() { var sum = 0; for (var i = 0; i < fitness.length; i++) { sum += fitness[i]; } for (var i = 0; i < fitness.length; i++) { fitness[i] = fitness[i] / sum;; } } p.nextGeneration = function() { var newPopulation = []; for (var i = 0; i < population.length; i++) { var orderA = p.pickOne(population, fitness); var orderB = p.pickOne(population, fitness); var order = p.crossOver(orderA, orderB); p.mutate(order, 0.01); newPopulation[i] = order; } population = newPopulation; } p.pickOne = function(list, prob) { var index = 0; var r = p.random(1); while (r > 0) { r = r - prob[index]; index++; } index--; return list[index].slice(); } p.crossOver = function(orderA, orderB) { var start = p.floor(p.random(orderA.length)); var end = p.floor(p.random(start + 1, orderA.length)); var neworder = orderA.slice(start, end); // var left = totalCities - neworder.length; for (var i = 0; i < orderB.length; i++) { var city = orderB[i]; if (!neworder.includes(city)) { neworder.push(city); } } return neworder; } p.mutate = function(order, mutationRate) { for (var i = 0; i < totalCities; i++) { if (p.random(1) < mutationRate) { var indexA = p.floor(p.random(order.length)); var indexB = (indexA + 1) % totalCities; p.swap(order, indexA, indexB); } } } } var myp5 = new p5(geneticSearch, 'c3');