Search code examples
javascriptcanvasrecursionbacktrackinglatin-square

Animate Javascript Canvas while in recursive calculation


I'm trying to animate a solution to the latin-square-problem in javascript.

To do so, I wrote the recursive backtracking algorithm below.

Solving the problem is initiated by calling search(0,0) and it works just fine, displaying a solution after calculating. But I want it to show an animation on it's progress, in terms of redrawing the whole canvas, after changing the colour of one square.

I tried to incoorporate many of the solutions to similar problems, found on stackoverflow or in tutorials about canvas gameloops. Neither of them worked for me, so I'm presenting the javascript code as close as possible to my pseudo-code algorithm (without any setTimeout's or requestAnimationFrame's)

Here's a working jsfiddle containing all the code.

function search(i, j){
    if (latinSquare[i][j] != -1){
        //this square is predefined, skip it
        searchNext(i, j);
    } else {
        var colour = latinSquare[i][j];
        while(colour < n-1){
            colour = colour + 1;
            latinSquare[i][j] = colour;
            //redraw the whole canvas
            drawLatinSquare();
            //check if curent constellation is legal
            var legal = true;
            for (var k = 0; k < n; k++){
                if (k != i){
                    if (latinSquare[k][j] == colour){
                        legal = false;
                        break;
                    }
                }
                if (k != j){
                    if (latinSquare[i][k] == colour){
                        legal = false;
                        break;
                    }
                }
            }
            if (legal){
                searchNext(i, j);
                if (window.found) return;
            }
        }
        latinSquare[i][j] = -1;
    }   
}

function searchNext(i, j){
    if (i < n-1){
        //proceed horizontally
        search(i+1, j);
    } else {
        if (j < n-1){
            //proceed in the next row
            search(0, j+1);
        } else {
            //we're done
            window.found = true;
        }
    }
}

Solution

  • In this solution, an array is created to hold each iteration of the latinSquare arrays. The timeout interval is a function of the length of the array.

    An advantage of this method is that the animation doesn't start until all the calculations are completed, so it runs quite quickly (assuming a solution is found):

    var lsa= [];
    
    function drawLatinSquare() {
      var l= [];
      for(var i = 0 ; i < latinSquare.length ; i++) {
        l.push(latinSquare[i].slice());
      }      
      lsa.push(l);
      setTimeout(function() {
        var ls= lsa.shift();
        ctx.clearRect ( 0 , 0 , canvas.width, canvas.height );
        ctx.lineWidth= 1;
        //draw the grid
        for (var i = 0; i < n + 1; i++){
          ctx.beginPath();
          ctx.moveTo(0,i*21 + 0.5);
          ctx.lineTo((n*(21)+1),i*21 + 0.5);
          ctx.stroke();
        }
        for (var j = 0; j < n + 1; j++){
          ctx.beginPath();
          ctx.moveTo(j*21 + 0.5,0);
          ctx.lineTo(j*21 + 0.5,(n*(21)+1));
          ctx.stroke();
        }
        //draw the squares
        for (var i = 0; i < n; i++){
          for (var j = 0; j < n; j++){
            colour = ls[i][j];
            if (colour == -1){
              colour = "#FFFFFF";
            } else {
              colour = colours[colour];
            }
            ctx.fillStyle = colour;
            ctx.fillRect((i*21)+1.5,(j*21)+1.5,20,20);
          }
        }
      },10*lsa.length);
    } //drawLatinSquare
    

    Fiddle