/*
 * Copyright (c) 2008
 * Moritz Hardt
 */
 
Array.prototype.swap=function(a, b) {
  var tmp=this[a];
  this[a]=this[b];
  this[b]=tmp;
}

Array.prototype.addmod2=function(u) {
  for(l=0;l<dim;l++)
    this[l] = (this[l] + u[l])%2;
}

Array.prototype.flip=function(i,j) {
  this[i][j] = 1 - this[i][j];
}

Array.prototype.zeros=function() {
  var n = 0;
  for (i=0;i<dim;i++) {
    for (j=0;j<dim;j++)
      n += this[i][j];
  }
  return dim*dim-n;
}

function coin(p) {
  r = Math.random()
  if (r < p) return 1;
  return 0;
}

function randMatrix() {
  A = [dim];
  for (i=0;i<dim;i++)
    A[i] = [dim];

  for (i=0;i<dim;i++) {
    for (j=0;j<dim;j++)
      A[i][j] = coin(0.5);
  }
  return A;
}

function shuffleMatrix(A,B) {
  for (i=0;i<dim;i++) {
    for (j=0;j<dim;j++) {
      if ( (A[i][j]==1 || B[i][j]==1) && coin(0.5)==1) {
        A.flip(i,j);
        B.flip(i,j);
      }
    }
  }
}

function zeroMatrix() {
  A = [dim];
  for (i=0;i<dim;i++)
    A[i] = [dim];
  for (i=0;i<dim;i++) {
    for (j=0;j<dim;j++)
      A[i][j] = 0;
  }
  return A;
}

function copyMatrix(M) {
  A = [dim];
  for (i=0;i<dim;i++)
    A[i] = [dim];
  
  for (i=0;i<dim;i++) {
    for (j=0;j<dim;j++)
      A[i][j] = M[i][j];
  }
  return A;
}

function rank(M) {
  // Compute binary rank of a matrix using
  // Gaussian elimination
  var A = copyMatrix(M);
  var r = 0;
  var l = 0;
  for (j=0;j<dim;j++) {
    for (i=l;i<dim;i++) {
     if (A[i][j]==1) {
       A.swap(i,r);
       for (k=r+1;k<dim;k++) { 
         if (A[k][j]==1) A[k].addmod2(A[r]);
       } 
       l++;
       r++;
      }
    }
  }
  return r;
}

function printMatrix(A,l) {
  document.write("<table>");
  for (i=0;i<dim;i++)
  {
    document.write("<tr>");
    for (j=0;j<dim;j++)
      {
        s = l+i+"."+j
        document.write("<td>");
        document.write("<img onMouseOver=\"imgOver("+i+","+j+")\"");
        document.write(" onMouseOut=\"imgOut("+i+","+j+")\" onMousedown=\"flip("+i+","+j+")\"");
        if (A[i][j]==0) {
          document.write(" name=\""+s+"\" src=\"images/blue.png\" width=\""+imgSizeL+"\" /></a>");
        }
        else {
          document.write(" name=\""+s+"\" src=\"images/red.png\" width=\""+imgSizeL+"\" /></a>");
        }
        document.write("</td>");
      }
    document.write("</tr>");
  }
  document.write("</table>");
}

function gup(name) {
  // parse argument 'name' from url
  name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
  var regexS = "[\\?&]"+name+"=([^&#]*)";
  var regex = new RegExp( regexS );
  var results = regex.exec( window.location.href );
  if( results == null )
    return "";
  else
    return results[1];
}

var dim;
var d = gup('d');
if (d=='') {
  dim=7;
}
else {
  dim=d;
}
var M1 = randMatrix(); 
var M1rank = rank(M1);
while (M1rank < dim) {
 M1 = randMatrix();
 M1rank = rank(M1);
}
var M3 = zeroMatrix();
var M2 = copyMatrix(M1);
shuffleMatrix(M2,M3);
var sparsity = M1.zeros();
var movesleft = Math.ceil(dim*dim/2);

zero = new Image();
zero.src = "images/blue.png";
zeroh = new Image();
zeroh.src = "images/bluelight.png";
one = new Image();
one.src = "images/red.png";
oneh = new Image();
oneh.src = "images/redlight.png";

var isize;
var isizes = [45,45,45,45,45,40,35,30,25,22,20,18,17,16,15];

if (dim > 14) {
  isize = 14;
}
else {
  isize = isizes[dim];
}

var imgSizeS = isize + 'px';
var imgSizeL = (isize+1) + 'px';

function highlight(img) {
 if (img.src == zero.src) {
   img.src = zeroh.src;
 }
 else {
   img.src = oneh.src;
 }
}

function dehighlight(img) {
 if (img.src == zeroh.src) {
   img.src = zero.src;
 }
 else {
   img.src = one.src;
 }
}

function imgOver(i,j) {
  img = document.images['A'+i+'.'+j];
  highlight(img);
  img = document.images['B'+i+'.'+j];
  highlight(img);
  img = document.images['C'+i+'.'+j];
  highlight(img);
}

function imgOut(i,j) {
  img = document.images['A'+i+'.'+j];
  dehighlight(img);
  img = document.images['B'+i+'.'+j];
  dehighlight(img);
  img = document.images['C'+i+'.'+j];
  dehighlight(img);
}

function flip(i,j) {
  if (movesleft<1) return;
  img = document.images['B'+i+'.'+j]
  if (img.src == zeroh.src) {
    img.src = oneh.src; 
  }
  else {
    img.src = zeroh.src;
  }
  img = document.images['C'+i+'.'+j]
  if (img.src == zeroh.src) {
    img.src = oneh.src; 
  }
  else {
    img.src = zeroh.src;
  }
  movesleft--;
  M2.flip(i,j);
  M3.flip(i,j);
  updateScore();
}

function updateScore() {
  var R = document.getElementById('rank');
  var r = rank(M2);
  R.innerHTML = r;
  var Z = document.getElementById('sparsity');
  var z = M3.zeros();
  Z.innerHTML = (100* z/(dim*dim)).toFixed(0)+'%';
  var S = document.getElementById('score');
  var density = dim*dim - sparsity;
  var s = 100*((M1rank-r)/dim  + (z-sparsity)/density)/2 ;
  S.innerHTML = s.toFixed(2) + '%';
  var M = document.getElementById('moves');
  if(movesleft <= dim) {
    M.innerHTML = "<span style=\"color:red\">"+movesleft+"</span>";
  }
  else {
   M.innerHTML = movesleft;
  }
}

