Guest User

Untitled

a guest
May 4th, 2014
159
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. function main() {
  2.     var startTime = (new Date()).getTime();
  3.    
  4.     var points = 30;
  5.     var elites = 10;
  6.     /* Since we force the population count to be a triangular number, those selected for reproduction will always
  7.        produce the same size population after being crossed over with every other selected thing with no repeats
  8.     */
  9.     var polygonCount = elites * (elites + 1) / 2;
  10.     var candidateList = new Array();
  11.    
  12.     var generations = 200;
  13.     var mutationMultiplier = 50;
  14.    
  15.     /* Initialize our canvas as global variables */
  16.     canvas = document.getElementById("drawing");
  17.     context = canvas.getContext("2d");
  18.  
  19.     /* generate a bunch of polygons */
  20.     for (var i = 0; i < polygonCount; i++) {
  21.         var pointSet = new Array();
  22.         for (var j = 0; j < points; j++) {
  23.             var a = Math.ceil(Math.random() * canvas.width);
  24.             var b = Math.ceil(Math.random() * canvas.height);
  25.             pointSet.push(new Point(a, b));
  26.         }
  27.         candidateList.push(new CandidatePolygon(pointSet));
  28.     }
  29.     /* Sort by fitness */
  30.     candidateList.sort(function(a, b){return b.fitness - a.fitness;});
  31.  
  32.     /* Make a table of all the candidates */
  33.     function printATableInTheRankingArea(sortedPolygonList){
  34.         var dataTableElement = document.getElementById("rankingEntry");
  35.         var rowEntry = "";
  36.         for (var i = 0; (i < sortedPolygonList.length) && (i < 100); i++) {
  37.             rowEntry += "<tr id=\"datarow_" + i + "\">" +
  38.                 "<td>" + i + "</td>" +
  39.                 "<td>" + sortedPolygonList[i].area + "px<sup>2</sup></td>" +
  40.                 "<td>" + sortedPolygonList[i].perimeter + "px</td>" +
  41.                 "<td>" + sortedPolygonList[i].sigma + "</td>" +
  42.                 "<td>" + sortedPolygonList[i].mean + "</td>" +
  43.                 "<td>" + sortedPolygonList[i].isoperimetric_ratio + "</td>" +
  44.                 "<td>" + sortedPolygonList[i].fitness + "</td></tr>";
  45.         }
  46.         dataTableElement.innerHTML = rowEntry;
  47.     }
  48.    
  49.     /* Run through the generations */
  50.     for(var n = 0; n < generations; n++){
  51.         var newGeneration = new Array();
  52.         var selectFew = new Array();
  53.         for(var i = 0; i < elites; i++) selectFew.push(candidateList[i]);
  54.        
  55.         for(var j = 0; j < selectFew.length; j++){
  56.             for(var k = 0; k < j; k++){
  57.                 var newPoly = crossover(selectFew[j], selectFew[k], mutationMultiplier);
  58.                 newGeneration.push(newPoly);
  59.             }
  60.         }
  61.         candidateList = newGeneration;
  62.         candidateList.sort(function(a, b){return b.fitness - a.fitness;});
  63.     }
  64.    
  65.     drawPoints(candidateList[0].points);
  66.     printATableInTheRankingArea(candidateList);
  67.    
  68.     var runtime = (new Date()).getTime() - startTime;
  69.     document.getElementById("stats").innerHTML =
  70.         "Took " + runtime + "ms.<br>Count per generation: " + candidateList.length
  71.       + "<br>Height: " + canvas.height + "<br>Width: " + canvas.width;
  72. }
  73.  
  74. /* constructor for an ordered pair */
  75. function Point(x, y) {
  76.     /* Rectangular form in y-inverted coordinates, with the top left as the origin (disgusting) */
  77.     this.x = x;
  78.     this.y = y;
  79.    
  80.     /* Rectangular form in _correct_ coordinates, with the center as the origin */
  81.     this.correctedx = x - (canvas.width / 2);
  82.     this.correctedy = ((canvas.height / 2) - y); // reflect over the Y axis
  83.  
  84.     /* Polar coordinates, with angle in degrees to avoid having to work with floating point precisions of pi and all that shit */
  85.     this.radius = Math.sqrt(this.correctedx * this.correctedx + this.correctedy * this.correctedy);
  86.     this.theta = Math.ceil(Math.atan2(this.correctedy, this.correctedx) * (180 / Math.PI));
  87. }
  88.  
  89.  
  90. /* Draw a collection of points onto the canvas */
  91. function drawPoints(points) {
  92.     var size = points.length;
  93.     for (var i = 0; i < size; i++) {
  94.         var a = points[i];
  95.         var b = (i == size - 1)? points[0] : points[i + 1]; // Last coordinate needs to be the first point
  96.        
  97.         // draw a line
  98.         context.moveTo(a.x, a.y);
  99.         context.lineTo(b.x, b.y);
  100.         context.stroke();
  101.     }
  102. }
  103.  
  104. /* constructor for a polygon */
  105. function CandidatePolygon(scatteredPoints){
  106.     /* gets the area of a polygon from a list of points
  107.        this uses the formula for a set of points defining a convex polygon with determinates
  108.        https://en.wikipedia.org/wiki/Shoelace_formula
  109.     */
  110.     this.determineArea = function() {
  111.         var size = this.cardinality;
  112.         var area = 0;
  113.         for (var i = 0; i < size; i++) {
  114.             var a = this.points[i];
  115.             var b = (i == size - 1)? this.points[0] : this.points[i + 1]; // the last point connects to the first
  116.            
  117.             area = area + ((a.x * b.y) - (b.x * a.y));
  118.         }
  119.         return Math.abs(area * 0.5);
  120.     }
  121.    
  122.     /* Finds the center of the points by using the... center of mass formula */
  123.     this.getStandardDeviationofLengths = function(){
  124.         var size = this.cardinality;       
  125.         var secondMoment = 0;
  126.         for (var i = 0; i < size; i++) {
  127.             var a = this.points[i];
  128.             var b = (i == size - 1)? this.points[0] : this.points[i + 1]; // Last coordinate needs to be the first point
  129.             var distance = (b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y);
  130.             secondMoment += distance;
  131.         }
  132.         return ~(~(Math.sqrt((secondMoment - this.mean * this.mean) / size) * 100))/ 100; // NOT converts to integer
  133.     }
  134.    
  135.     /* Calculate the perimeter of the polygon */
  136.     this.calculatePerimeter = function() {
  137.         var size = this.cardinality;
  138.         var perim = 0;
  139.         for (var i = 0; i < size; i++) {
  140.             var a = this.points[i];
  141.             var b = (i == size - 1)? this.points[0] : this.points[i + 1]; // Last coordinate needs to be the first point
  142.             var distance = Math.sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));
  143.             perim += distance;
  144.         }
  145.         return Math.ceil(perim);
  146.     }
  147.    
  148.     /* Calculate the perimeter of the polygon */
  149.     this.getFitness = function() {
  150.         var fit = 1/(1 - this.isoperimetric_ratio);        
  151.         /* punish some things that aren't good */
  152.         if(this.area > (canvas.width * canvas.height * 0.75)) fit = fit / 10; // really punish
  153.         if(this.area < (canvas.width * canvas.height * 0.10)) fit = fit / 10; // really punish
  154.         if(this.sigma > 30) fit = fit / 5; // punish
  155.        
  156.         /* Also, there is a 5% punishment for every point outside the outside the boundry */
  157.         for(var i = 0; i < this.cardinality; i++){
  158.             var x = this.points[i].x;
  159.             var y = this.points[i].y;
  160.             if( (x < 0) || (x > canvas.width) || (y < 0) || (y > canvas.height) ) fit = fit * 0.95;
  161.         }
  162.         return fit;
  163.     }
  164.    
  165.     /*  Sort them greatest to least, by their corrected polar angle
  166.         This has the effect of making it a (kinda) nice convex polygon
  167.     */
  168.     this.points = scatteredPoints.sort(function(a, b) {return b.theta - a.theta;});
  169.     this.cardinality = this.points.length;
  170.     this.area = this.determineArea();
  171.     this.perimeter = this.calculatePerimeter();
  172.     this.mean = this.perimeter / this.cardinality;
  173.     this.sigma = this.getStandardDeviationofLengths();
  174.     this.isoperimetric_ratio = (4 * 3.1415 * this.area) / (this.perimeter * this.perimeter);
  175.     this.fitness = this.getFitness();
  176. }
  177.  
  178. function crossover(a, b, mutation){
  179.     mutation = (mutation == null)? 100 : mutation;
  180.     var pointSet = new Array();
  181.    
  182.     /* Mutations mut=[-mutation,mutation] */
  183.     var x_mutation =  Math.round((Math.random() * 2 - 1) * mutation);
  184.     var y_mutation =  Math.round((Math.random() * 2 - 1) * mutation);
  185.    
  186.     for (var i = 0; (i < a.cardinality) && (i < b.cardinality); i++) {
  187.         var cx = ((a.points[i].correctedx + b.points[i].correctedx) / 2) + x_mutation;
  188.         var cy = ((a.points[i].correctedy + b.points[i].correctedy) / 2) + y_mutation;
  189.         if((a.area + b.area) < (canvas.width * canvas.height * 0.25)) {
  190.            cx = cx * 2; cy = cy * 2;
  191.            }
  192.         if((a.area + b.area) > (canvas.width * canvas.height)) {
  193.            cx = cx / 2; cy = cy / 2;
  194.            }
  195.         var x = cx + (canvas.width / 2);
  196.         var y = (canvas.height / 2) - cy;
  197.         pointSet.push(new Point(x, y));
  198.     }
  199.     return new CandidatePolygon(pointSet);
  200. }
Advertisement
Add Comment
Please, Sign In to add comment