var steps = new Array(0x01, 0x10, -0x01, -0x10, 0x0f, 0x11, -0x0f, -0x11);
var rookSteps = new Array(0x01, 0x10, -0x01, -0x10);
var bishopSteps = new Array(0x0f, 0x11, -0x0f, -0x11);
var knightSteps = new Array(+14, +18, +31, +33, -14, -18, -31, -33);

function MakeEmptyArray()
{
  var retValue = new Array(0x88);

  for (f=0; f<9; ++f)
    for (r=0; r<8; ++r)
      retValue[f+16*r] = 0;

  return retValue;
}

function PawnAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  function DoMove(delta, isDouble)
  {
    var nextPoint = point + delta;
    if (nextPoint & 0x88) return;
    if (position.board[nextPoint] != '.') return;

    retValue[nextPoint] = 1;
    wasMove = true;

    if (typeof(isDouble) == 'undefined') return;
    if (!isDouble) return;

    DoMove(2*delta);
  }

  DoMove( 0x10, position.activeSide == 'w');
  DoMove( 0x01);
  DoMove(-0x01);
  DoMove(-0x10, position.activeSide == 'b');

  function DoTake(delta)
  {
    var nextPoint = point + delta;
    if (nextPoint & 0x88) return;

    var piece = position.board[nextPoint];
    if (GetColor(piece) != (position.activeSide == WHITE ? BLACK : WHITE)) return;

    retValue[nextPoint] = 1;
    wasMove = true;
  }

  if (position.activeSide == WHITE)
  {
    DoTake(0x11);
    DoTake(0x0f);
  }
  else {
    DoTake(-0x11);
    DoTake(-0x0f);
  }

  return wasMove ? retValue : null;
}

function VeteranAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  function DoMove(delta, notObstacle)
  {
    var nextPoint = point + delta;
    if (nextPoint & 0x88) return;
    if (position.board[nextPoint] != '.') return;

    if (typeof(notObstacle) != 'undefined')
      if (position.board[point + notObstacle] == '$')
        return;

    retValue[nextPoint] = 1;
    wasMove = true;
  }

  DoMove(0x10); DoMove(0x01); DoMove(-0x01); DoMove(-0x10);
  DoMove(0x20, 0x10); DoMove(0x02, 0x01); DoMove(-0x02, -0x01); DoMove(-0x20, -0x10);

  function DoTake(delta)
  {
    var nextPoint = point + delta;
    if (nextPoint & 0x88) return;

    var piece = position.board[nextPoint];
    if (GetColor(piece) != (position.activeSide == WHITE ? BLACK : WHITE)) return;

    retValue[nextPoint] = 1;
    wasMove = true;
  }

  if (position.activeSide == WHITE)
  {
    DoTake(0x11);
    DoTake(0x0f);
  }
  else {
    DoTake(-0x11);
    DoTake(-0x0f);
  }

  return wasMove ? retValue : null;
}

function FanaticAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  function DoMove(delta, notObstacle)
  {
    var nextPoint = point + delta;
    if (nextPoint & 0x88) return;
    if (position.board[nextPoint] != '.') return;

    if (typeof(notObstacle) != 'undefined')
      if (position.board[point + notObstacle] == '$')
        return;

    retValue[nextPoint] = 1;
    wasMove = true;
  }

  DoMove(0x10); DoMove(0x01); DoMove(-0x01); DoMove(-0x10);
  DoMove(0x20, 0x10); DoMove(0x02, 0x01); DoMove(-0x02, -0x01); DoMove(-0x20, -0x10);

  function DoTake(delta)
  {
    var nextPoint = point + delta;
    if (nextPoint & 0x88) return;

    var piece = position.board[nextPoint];
    if (GetColor(piece) != (position.activeSide == WHITE ? BLACK : WHITE)) return;

    retValue[nextPoint] = 1;
    wasMove = true;
  }

  DoTake(+0x01); DoTake(+0x10); DoTake(+0x11); DoTake(+0x0f);
  DoTake(-0x01); DoTake(-0x10); DoTake(-0x11); DoTake(-0x0f);

  return wasMove ? retValue : null;
}


function KingAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  function DoMove(delta)
  {
    var nextPoint = point + delta;
    if (nextPoint & 0x88) return;

    if (position.board[nextPoint] == '$') return;
    if (GetColor(position.board[nextPoint]) == position.activeSide) return;

    retValue[nextPoint] = 1;
    wasMove = true;
  }

  DoMove(+0x01); DoMove(+0x10); DoMove(+0x11), DoMove(+0x0f);
  DoMove(-0x01); DoMove(-0x10); DoMove(-0x11), DoMove(-0x0f);

  return wasMove ? retValue : null;
}

function CannonAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  for(i=0; i<4; ++i)
  {
    var delta = rookSteps[i];
    var p = point;

    for(;;)
    {
      p += delta;
      if (p & 0x88) break;

      var piece = position.board[p];
      if (piece != '.') break;

      wasMove = true;
      retValue[p] = 1;
    }
  }

  function DoTake(delta)
  {
    var nextPoint = point + delta;
    if (nextPoint & 0x88) return;

    var piece = position.board[nextPoint];
    if (GetColor(piece) != (position.activeSide == WHITE ? BLACK : WHITE)) return;

    retValue[nextPoint] = 1;
    wasMove = true;
  }

  DoTake(+0x01); DoTake(+0x10); DoTake(+0x02), DoTake(+0x20);
  DoTake(-0x01); DoTake(-0x10); DoTake(-0x02), DoTake(-0x20);




  return wasMove ? retValue : null;
}


function SuccessorAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  for(i=0; i<8; ++i)
  {
    var delta = steps[i];
    var isFirst = true;
    var p = point;

    for(;;)
    {
      p += delta;
      if (p & 0x88) break;

      var piece = position.board[p];
      if (piece == '$') break;
      if (GetColor(piece) == position.activeSide) break;

      wasMove = true;

      if (piece != '.')
      {
        if (isFirst)
          retValue[p] = 1;
        break;
      }

      retValue[p] = 1;
      isFirst = false;
    }
  }

  return wasMove ? retValue : null;
}

function HorsemanAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  for(i=0; i<8; ++i)
  {
    var delta = knightSteps[i];
    var isFirst = true;
    var p = point;

    for(;;)
    {
      p += delta;
      if (p & 0x88) break;

      var piece = position.board[p];
      if (piece == '$') break;
      if (GetColor(piece) == position.activeSide) break;

      wasMove = true;

      if (piece != '.')
      {
        if (isFirst)
          retValue[p] = 1;
        break;
      }

      retValue[p] = 1;
      isFirst = false;
    }
  }

  return wasMove ? retValue : null;
}

function RookAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  for(i=0; i<4; ++i)
  {
    var delta = rookSteps[i];
    var p = point;

    for(;;)
    {
      p += delta;
      if (p & 0x88) break;

      var piece = position.board[p];
      if (piece == '$') break;
      if (GetColor(piece) == position.activeSide) break;

      wasMove = true;
      retValue[p] = 1;

      if (piece != '.') break;
    }
  }

  return wasMove ? retValue : null;
}

function TurkaAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  for(i=0; i<4; ++i)
  {
    var delta = rookSteps[i];
    var p = point;

    for(;;)
    {
      p += delta;
      if (p & 0x88) break;

      var piece = position.board[p];
      if (piece == '$') break;
      if (GetColor(piece) == position.activeSide) continue;

      wasMove = true;
      retValue[p] = 1;

      if (piece != '.') break;
    }
  }

  return wasMove ? retValue : null;
}

function BishopAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  for(i=0; i<4; ++i)
  {
    var delta = bishopSteps[i];
    var p = point;

    for(;;)
    {
      p += delta;
      if (p & 0x88) break;

      var piece = position.board[p];
      if (piece == '$') break;
      if (GetColor(piece) == position.activeSide) break;

      wasMove = true;
      retValue[p] = 1;

      if (piece != '.') break;
    }
  }

  return wasMove ? retValue : null;
}

function ElephantAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  for(i=0; i<4; ++i)
  {
    var delta = bishopSteps[i];
    var p = point;

    for(;;)
    {
      p += delta;
      if (p & 0x88) break;

      var piece = position.board[p];
      if (piece == '$') break;
      if (GetColor(piece) == position.activeSide) continue;

      wasMove = true;
      retValue[p] = 1;

      if (piece != '.') break;
    }
  }

  return wasMove ? retValue : null;
}

function DragonAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  for(i=0; i<4; ++i)
  {
    var delta = bishopSteps[i];
    var p = point;

    for(;;)
    {
      p += delta;
      if (p & 0x88) break;

      var piece = position.board[p];
      if (piece == '.')
      {
        wasMove = true;
        retValue[p] = 1;
      }
    }
  }

  function DoTake(delta)
  {
    var p1 = point + delta;
    var p2 = point + 2*delta;
    var opponent = position.activeSide == WHITE ? BLACK : WHITE;

    var wasTaking1 = ((p1 & 0x88) == 0) && (GetColor(position.board[p1]) == opponent);
    var wasTaking2 = ((p2 & 0x88) == 0) && (GetColor(position.board[p2]) == opponent);
    var wasTaking = wasTaking1 || wasTaking2;

    if (!wasTaking) return;

    wasMove = true;
    if (wasTaking1) retValue[p1] = 1;
    if (wasTaking2) retValue[p2] = 1;
  }

  DoTake(+0x11); DoTake(+0x0f);
  DoTake(-0x11); DoTake(-0x0f);
  return wasMove ? retValue : null;
}

function QueenAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  for(i=0; i<8; ++i)
  {
    var delta = steps[i];
    var p = point;

    for(;;)
    {
      p += delta;
      if (p & 0x88) break;

      var piece = position.board[p];
      if (piece == '$') break;
      if (GetColor(piece) == position.activeSide) break;

      wasMove = true;
      retValue[p] = 1;

      if (piece != '.') break;
    }
  }

  return wasMove ? retValue : null;
}


function KnightAvailable(position, file, rank)
{
  var retValue = MakeEmptyArray();
  var wasMove = false;
  var point = file + 16*rank;

  for(i=0; i<8; ++i)
  {
    var delta = knightSteps[i];
    var p = point + delta;

    if (p & 0x88) continue;

    var piece = position.board[p];
    if (piece == '$') continue;
    if (GetColor(piece) == position.activeSide) continue;

    wasMove = true;
    retValue[p] = 1;
  }

  return wasMove ? retValue : null;
}



function FanaticBoom(position, point)
{
  function Clear(delta)
  {
    var nextPoint = point + delta;
    if (nextPoint & 0x88) return;

    if (position.board[nextPoint] != '$')
      position.board[nextPoint] = '.';
  }

  Clear(0);
  Clear(+0x01); Clear(+0x10); Clear(+0x11), Clear(+0x0f);
  Clear(-0x01); Clear(-0x10); Clear(-0x11), Clear(-0x0f);
}

function CheckPromotion(position)
{
  for (f=0; f<8; ++f)
  {
    var wp = 0x70 | f;
    switch(position.board[wp])
    {
      case 'P':
        position.board[wp] = 'V';
        break;
      case 'N':
        position.board[wp] = 'H';
        break;
      case 'B':
        position.board[wp] = 'E';
        break;
      case 'R':
        position.board[wp] = 'T';
        break;
    }

    var bp = f;
    switch(position.board[bp])
    {
      case 'p':
        position.board[bp] = 'v';
        break;
      case 'n':
        position.board[bp] = 'h';
        break;
      case 'b':
        position.board[bp] = 'e';
        break;
      case 'r':
        position.board[bp] = 't';
        break;
    }
  }
}

function CheckResult(position)
{
  var whiteKing = -1;
  var blackKing = -1;
  var whiteSuccessor = -1;
  var blackSuccessor = -1;

  for (f=0; f<8; ++f)
    for (r=0; r<8; ++r)
  {
    var p = f+16*r;
    switch(position.board[p])
    {
      case 'K':
        whiteKing = p;
        break;
      case 'k':
        blackKing = p;
        break;
      case 'S':
        whiteSuccessor = p;
        break;
      case 's':
        blackSuccessor = p;
        break;
    }
  }

  if (whiteKing == -1 && whiteSuccessor != -1)
  {
    position.board[whiteSuccessor] = 'K';
    whiteKing = whiteSuccessor;
    whiteSuccessor = -1;
  }

  if (blackKing == -1 && blackSuccessor != -1)
  {
    position.board[blackSuccessor] = 'k';
    blackKing = blackSuccessor;
    blackSuccessor = -1;
  }

  if (whiteKing == -1 && blackKing == -1) position.result = '1/2';
  if (whiteKing == -1 && blackKing != -1) position.result = '0-1';
  if (whiteKing != -1 && blackKing == -1) position.result = '1-0';
  if (whiteKing != -1 && blackKing != -1) position.result = '*';
}

