• .. and the code that tries ( in a very dumb manner currently ) to find the shortest path between all dots ( it 'd be neat if it was optimized & not accepting lines crossing among other stuff, but this is a very quick & dumb take on the travelling salesman problem or one of its derivative ? .. )

    If someone want to have fun ,why not allowing to specify ( or not ) start and/or end points & then let the magic happen ?

    so, the ( ugly ) code, enjoy ! :)

    <!DOCTYPE html>
    <!--
    Created using JS Bin
    http://jsbin.com
    
    Copyright (c) 2019 by anonymous (http://jsbin.com/qawemovawa/1/edit)
    
    Released under the MIT license: http://jsbin.mit-license.org
    -->
    <meta name="robots" content="noindex">
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>JS Bin</title>
    <style id="jsbin-css">
    [#canvas](http://forum.espruino.com/sear­ch/?q=%23canvas) {
      /*
      width: 160px;
      height: 80px;
      */
      border : 1px solid blue;
    }
    </style>
    </head>
    <body>
      <canvas id="canvas"></canvas>
    <script id="jsbin-javascript">
    // https://www.youtube.com/watch?v=BAejnwN4­Ccw
    // Coding Challenge #35.2: Lexicographic Order: https://www.youtube.com/watch?v=goUlyp4r­wiU
    // Coding Challenge #35.3: Traveling Salesperson with Lexicographic Order
    // Coding Challenge #35.4: Traveling Salesperson with Genetic Algorithm
    // Coding Challenge #35.4: Traveling Salesperson with Genetic Algorithm and Crossover: https://www.youtube.com/watch?v=hnxn6DtL­YcY
    var cnvs = document.querySelector('#canvas');
    var ctx = cnvs.getContext('2d');
    //cnvs.width = 160;
    //cnvs.height = 80;
    cnvs.width = 160*2;
    cnvs.height = 80*2;
    
    // draw dot helper
    var drawDot = function(ctx, x, y, rad){
      ctx.beginPath();
      ctx.arc(x, y, rad, 0, 2 * Math.PI);
      ctx.stroke();
      ctx.fill();
    }
    
    // coords array from Illustrator
    /*
    var coordsArr = [[38.6038818359375,-28.5126953125],[53.5­712890625,-20.8525390625],[67.6137695312­5,-23.0546875],[83.61376953125,-28.22167­96875],[99.447265625,-23.0546875],[113.6­318359375,-20.9112854003906],[128.481628­417969,-28.4538269042969],[128.457397460­938,-47.0709228515625],[113.490051269531­,-54.731201171875],[99.44775390625,-52.5­283203125],[83.447509765625,-47.36132812­5],[67.61376953125,-52.5283203125],[53.4­285278320312,-54.671875],[38.57928466796­88,-47.12939453125]];
    for(var i=0; i< coordsArr.length; i++){
      drawDot(ctx, coordsArr[i][0], cnvs.height + coordsArr[i][1], 2);
    }*/
    
    
    /* ==== following the "coding train" ==== */
    // swapping helper
    function swap(a, i, j){
      var tmp = a[i];
      a[i] = a[j];
      a[j] = tmp;
    }
    
    
    // distance calculation helper
    function dist(p1x, p1y, p2x, p2y){
      return Math.sqrt( Math.pow((p1x - p2x), 2) + Math.pow((p1y - p2y), 2) );
    }
    function calcDistance(points){
      var sum = 0;
      for(var i=0; i < points.length-1; i++){
        var d = dist(points[i][0], points[i][1],
                    points[i+1][0], points[i+1][1]);
        sum += d;
      }
      return sum;
    }
    
    var cities = [];
    var totalCities = 10;
    
    var recordDistance;
    var bestEver;
    
    function setup(){
      /* -- random pts --
      for(var i=0; i< totalCities; i++){
        var v = [Math.random()*cnvs.width, Math.random()*cnvs.height];
        //var v = [10, 10];
        cities[i] = v;
      }
      */
      ///* -- pts from Illu
      // 1st arr is "manually optimized"
      //var coordsArr = [[38.6038818359375,-28.5126953125],[53.5­712890625,-20.8525390625],[67.6137695312­5,-23.0546875],[83.61376953125,-28.22167­96875],[99.447265625,-23.0546875],[113.6­318359375,-20.9112854003906],[128.481628­417969,-28.4538269042969],[128.457397460­938,-47.0709228515625],[113.490051269531­,-54.731201171875],[99.44775390625,-52.5­283203125],[83.447509765625,-47.36132812­5],[67.61376953125,-52.5283203125],[53.4­285278320312,-54.671875],[38.57928466796­88,-47.12939453125]];
      // 2nd array is "intentionally un-optimized" of the 1st
      var coordsArr = [[38.5792846679688,-47.12939453125],[53.­5712890625,-20.8525390625],[67.613769531­25,-23.0546875],[38.6038818359375,-28.51­26953125],[99.447265625,-23.0546875],[83­.61376953125,-28.2216796875],[113.631835­9375,-20.9112854003906],[128.45739746093­8,-47.0709228515625],[67.61376953125,-52­.5283203125],[113.490051269531,-54.73120­1171875],[99.44775390625,-52.5283203125]­,[128.481628417969,-28.4538269042969],[8­3.447509765625,-47.361328125],[53.428527­8320312,-54.671875],];
      for(var i=0; i< coordsArr.length; i++){
        cities[i] = [coordsArr[i][0], cnvs.height + coordsArr[i][1]];
      }
      totalCities = cities.length;
      //*/
    
      //console.log(cities);
      var d = calcDistance(cities);
      recordDistance = d;
      bestEver = cities.slice();
      console.log('recordDistance: ' + recordDistance);
    }
    
    function draw(){
      // redraw
      requestAnimationFrame(draw);
      //setTimeout(draw, 200);
      //console.log('drawing ..');
    
      //ctx.clearRect(0, 0, cnvs.width, cnvs.height);
      ctx.fillStyle = 'black';
      ctx.fillRect(0, 0, cnvs.width, cnvs.height);
    
      // draw dots
      ctx.strokeStyle = 'white';
      ctx.fillStyle = 'white';
      for(var i=0; i< totalCities; i++){
        drawDot(ctx, cities[i][0], cities[i][1], 4);
      }
    
      // draw current cities liaisons
      ctx.strokeStyle = 'white';
      ctx.strokeWeight = 2;
      ctx.beginPath();
      // connect via lines
      for(var i=0; i< totalCities-1; i++){
        ctx.moveTo(cities[i][0], cities[i][1]);
        ctx.lineTo(cities[i+1][0], cities[i+1][1]);
      }
      ctx.closePath();
      ctx.stroke();
    
      // draw best cities liaisons
      ctx.strokeStyle = 'blue';
      ctx.strokeWeight = 4;
      ctx.beginPath();
      // connect via lines
      for(var i=0; i< totalCities-1; i++){
        ctx.moveTo(bestEver[i][0], bestEver[i][1]);
        ctx.lineTo(bestEver[i+1][0], bestEver[i+1][1]);
      }
      ctx.closePath();
      ctx.stroke();
    
      // swap things
      var i = Math.floor( Math.random()*cities.length);
      var j = Math.floor( Math.random()*cities.length);
      //cities = swap(cities, i, j);
      swap(cities, i, j);
    
      var d = calcDistance(cities);
      if(d < recordDistance){
        recordDistance = d;
        bestEver = cities.slice();
        console.log('recordDistance: ' + recordDistance);
      }
    }
    
    
    setup();
    draw();
    </script>
    </body>
    </html>
    
    
About

Avatar for stephaneAG @stephaneAG started