document.oncontextmenu = disableRightClick;

var w = 50; //size of square
var moveDescription = new Array("L", "U", "R", "D"); // possible moves
var x0, y0; // coord empty cell
var board = new Array(3);
var boardGoal = new Array(3);
var resultString = new Array();
var goalX = new Array(15); //goalX[i] - coord x itoj cell, ...
var goalY = new Array(15);
var timerID = null;

function doLoad() 
{
  var i, j;

  for (i = 0; i <= 15; i++) {
    goalX[i + 1] = Math.floor(i / 4);
    goalY[i + 1] = i % 4;
  }
  goalX[0] = 3;
  goalY[0] = 3;

  for (i = 0; i < 4; i++) {
    board[i] = new Array();
  }
  for (i = 0; i < 4; i++) {
    boardGoal[i] = new Array();
  }

  boardGoal[0] = [1, 2, 3, 4];
  boardGoal[1] = [5, 6, 7, 8];
  boardGoal[2] = [9, 10, 11, 12];
  boardGoal[3] = [13, 14, 15, 0];

  doStart();
}

function disableRightClick() 

{
  alert('Source code is COPYRIGHTED. Please, do not reproduce.');
  return false;
}

function doStart() 
{
  document.getElementById("cmdStep").disabled = false;
  document.getElementById("cmdAuto").disabled = false;
  window.clearTimeout(timerID);
  resultString = new Array();
  GetRandomPosition();
  Paint();
}

function GetRandomPosition() 
{
  board[0] = [1, 2, 3, 4];
  board[1] = [5, 6, 7, 8];
  board[2] = [9, 10, 11, 12];
  board[3] = [13, 14, 15, 0];
  y0 = 3;
  x0 = 3;

  for (var j = 0; j < 100; j++) 
  {
    doShift();
  }
}

function Paint() 
{
  document.getElementById("cmdStep").style.cursor = "wait";
  var obj = null;
  for (var i = 0; i < 4; i++) 
  {
    for (var j = 0; j < 4; j++) 
    {
      obj = document.getElementById( "p" + board[i][j] );
      if (navigator.appName == "Netscape") {
        obj.style.top = i * w + "px";
        obj.style.left = j * w + "px";
      }
      else {
        obj.style.pixelTop = i * w;
        obj.style.pixelLeft = j * w;
      }
      obj = null;
    }
  }
  document.getElementById("cmdStep").style.cursor = "default";
}

function doShift() 
{
  var newx, newy, value, value2;
  var rndValue = Math.round(Math.random() * 4);
  switch (rndValue) 
  {
    case 0: //"L"
      newy = y0;
      newx = x0 - 1;
      break;
    case 1: //"U"
      newy = y0 - 1;
      newx = x0;
      break;
    case 2: //"R"
      newy = y0;
      newx = x0 + 1;
      break;
    case 3: //"D"
      newy = y0 + 1;
      newx = x0;
      break;
  }
  if ((newy <= 3) && (newy >= 0) && (newx <= 3) && (newx >= 0)) 
  {
    if (resultString.length > 0) 
    {
      value = resultString[resultString.length - 1];
      value2 = moveDescription[rndValue];
      if ((value == "L" && value2 != "R") ||
          (value == "U" && value2 != "D") ||
          (value == "R" && value2 != "L") ||
          (value == "D" && value2 != "U")) 
      {
        swap(newy, newx); // move empty cell to new place
        resultString.push(moveDescription[rndValue]); //save this move
      }
    }
    else 
    {
      swap(newy, newx); 
      resultString.push(moveDescription[rndValue]); 
    }
  }
}

function doMove(me) {
  document.getElementById("cmdStep").disabled = true;
  document.getElementById("cmdAuto").disabled = true;
  var newy, newx, x, y, i;
  if (navigator.appName == "Netscape") 
  {
    y = me.style.top;
    y = y.substring(0,y.length - 2);
    newy = y / w;

    x = me.style.left;
    x = x.substring(0,x.length - 2);
    newx = x / w;
  }
  else 
  {
    newy = me.style.pixelTop / w;
    newx = me.style.pixelLeft / w;
  }
  
  if ((Math.abs(newx - x0) == 0 && Math.abs(newy - y0) <= 1) ||
      (Math.abs(newx - x0) <= 1 && Math.abs(newy - y0) == 0)) 
  {
    swap(newy, newx);
  }
  Paint();
  if (estimate() == 0) alert("Congratulations!");
}

//evristic function Manhattan distance
function estimate() 
{
  var manhattan = 0;
  var value, i, j;
  for (i = 0; i < 4; i++) 
  {
    for (j = 0; j < 4; j++) 
    {
      value = board[i][j];
      if ((value > 0) && (value != boardGoal[i][j])) 
      {
        manhattan += Math.abs(i - goalX[value]) + Math.abs(j - goalY[value]);
      }
    }
  }
  return manhattan;
}

function doStep() 
{
  var newy, newx;
  if (resultString.length > 0) 
  {
    switch (resultString[resultString.length - 1]) 
    {
      case "L":
        newy = y0;
        newx = x0 + 1;
        break;
      case "U":
        newy = y0 + 1;
        newx = x0;
        break;
      case "R":
        newy = y0;
        newx = x0 - 1;
        break;
      case "D":
        newy = y0 - 1;
        newx = x0;
        break;
    }
    swap(newy, newx);
    resultString.pop();
    Paint();
  }
}

function doAuto() 
{
  doStep();
  timerID = window.setTimeout("doAuto()", 500);
}

function swap(y, x) 
{
  var value1 = board[y0][x0];
  var value2 = board[y][x];
  board[y0][x0] = value2;
  board[y][x] = value1;
  y0 = y;
  x0 = x;
}

