/* GNU Chess 5.0 - atak.c - attack code
   Copyright (c) 1999-2002 Free Software Foundation, Inc.

   GNU Chess is based on the two research programs 
   Cobalt by Chua Kong-Sian and Gazebo by Stuart Cracraft.

   GNU Chess is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   GNU Chess is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with GNU Chess; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Contact Info: 
     bug-gnu-chess@gnu.org
     cracraft@ai.mit.edu, cracraft@stanfordalumni.org, cracraft@earthlink.net
*/

#include <stdio.h>
#include <string.h>
#include "util.h"
#include "bitboard.h"
#include "piece.h"
#include "move.h"
#include "magic.h"

// TODO: remove this global

BitBoard Ataks[2][7];

short SqAtakd (board_t *board, short sq, short side)
/**************************************************************************
 *
 *  To determine if sq is attacked by any pieces from side.
 *
 **************************************************************************/
{
   register BitBoard *a;
   
   a = board->b[side];

   /* Knights */
   if (a[knight] & bitboards.MoveArray[knight][sq])
      return (true);

   /* Kings */
   if (a[king] & bitboards.MoveArray[king][sq])
      return (true);

   /* Pawns */
   if (a[pawn] & bitboards.MoveArray[ptype[1^side]][sq])
      return (true);
      
   /* Bishops & Queen */

   if(MagicBishopAttack(board,sq) & (a[bishop] | a[queen])){
       return true;
   }

   /* Rook e Queen */

   if(MagicRookAttack(board,sq) & (a[rook] | a[queen])){
       return true;
   }

   return (false);
}

void GenAtaks (board_t *board)
/*************************************************************************
 *
 *  To generate the attack table.
 *  Ataks[side][0] holds the total attack tables.
 *  Ataks[side][pawn] holds the BitBoard of squares attacked by all pawns.
 *
 *************************************************************************/
{
   int side; 
   int sq;
   register BitBoard *a, b, *t, *a0;

   memset (Ataks, 0, sizeof (Ataks)); 
   for (side = white; side <= black; side++)
   {
      a = board->b[side];

      /* Knight */
      t = &Ataks[side][knight];
      b = a[knight];
      while (b)
      {
         sq = leadz (b);
         CLEARBIT (b, sq);
         *t |= bitboards.MoveArray[knight][sq];
      }

      /* Bishops */
      t = &Ataks[side][bishop];
      b = a[bishop];
      while (b)
      {
	 sq = leadz (b);
	 CLEARBIT (b, sq);
	 *t |= MagicBishopAttack(board,sq);
      }

      /*  Rooks */
      t = &Ataks[side][rook];
      b = a[rook];
      while (b)
      {
	 sq = leadz (b);
	 CLEARBIT (b, sq);
	 *t |= MagicRookAttack(board,sq);
      }

      /*  Queen  */
      t = &Ataks[side][queen];
      b = a[queen];
      while (b)
      {
	 sq = leadz (b);
	 CLEARBIT (b, sq);
	 *t |= MagicQueenAttack(board,sq);
      }

      /* King */
      t = &Ataks[side][king];
      b = a[king];
      while (b)
      {
         sq = leadz (b);
         CLEARBIT (b, sq);
         *t |= bitboards.MoveArray[king][sq];
      }

      /*  pawns  */
      t = &Ataks[side][pawn];
      if (side == white)
      {
         b = board->b[white][pawn] & ~bitboards.FileBit[0];
         *t |= (b >> 7);
         b = board->b[white][pawn] & ~bitboards.FileBit[7];
         *t |= (b >> 9);
      }
      else
      {
         b = board->b[black][pawn] & ~bitboards.FileBit[0];
         *t |= (b << 9);
         b = board->b[black][pawn] & ~bitboards.FileBit[7];
         *t |= (b << 7);
      }
      a0 = Ataks[side];
      a0[0] = a0[pawn] | a0[knight] | a0[bishop] | a0[rook] |
              a0[queen] | a0[king];
   }
}



BitBoard AttackTo (board_t *board, int sq, int side)
/***************************************************************************
 *
 *  Generate a bitboard of all squares with pieces belonging to side
 *  which attack sq.
 *
 ***************************************************************************/
{
   register BitBoard *a, e;
   
   a = board->b[side];

   /* Knights */
   e = (a[knight] & bitboards.MoveArray[knight][sq]); 	

   /* Kings */
   e |= (a[king] & bitboards.MoveArray[king][sq]); 	

   /* Pawns */
   e |= (a[pawn] & bitboards.MoveArray[ptype[1^side]][sq]);
      

   /* Bishops & Queen */

   e |= MagicBishopAttack(board,sq) & (a[bishop] | a[queen]);

   /* Rook & Queen */

   e |= MagicRookAttack(board,sq) & (a[rook] | a[queen]);

   return (e);
}




BitBoard AttackXTo (board_t *board, int sq, int side)
/***************************************************************************
 *
 *  Generate a bitboard of all squares with pieces belonging to side
 *  which attack sq.  This routine is slightly different from AttackTo
 *  as it includes X-ray attacks as well and these can go through the
 *  opponents pieces as well (e.g. a white R will attack the squares 
 *  beyond the black R). 
 *
 ***************************************************************************/
{
   register BitBoard *a, b, *c, *d, e, blocker;
   int t;
   
   a = board->b[side];
   d = board->b[1^side];

   /* Knights */
   e = (a[knight] & bitboards.MoveArray[knight][sq]); 	

   /* Kings */
   e |= (a[king] & bitboards.MoveArray[king][sq]); 	

   c = bitboards.FromToRay[sq];

   /* Bishops & Queen & Pawns */
   b = (a[pawn] & bitboards.MoveArray[ptype[1^side]][sq]);
   blocker = board->blocker;
   blocker &= ~(a[bishop] | a[queen] | d[bishop] | d[queen] | b);
   b |= (a[bishop] | a[queen]) & bitboards.MoveArray[bishop][sq];
   while (b)
   {
      t = leadz (b);
      CLEARBIT (b, t); 
      if (!(c[t] & blocker & bitboards.NotBitPosArray[t]))
	 e |= bitboards.BitPosArray[t];
   }

   /* Rooks & Queen */
   b = (a[rook] | a[queen]) & bitboards.MoveArray[rook][sq];
   blocker = board->blocker;
   blocker &= ~(a[rook] | a[queen] | d[rook] | d[queen]);
   while (b)
   {
      t = leadz (b);
      CLEARBIT (b, t); 
      if (!(c[t] & blocker & bitboards.NotBitPosArray[t]))
	 e |= bitboards.BitPosArray[t];
   }

   return (e);
}


BitBoard AttackFrom (board_t *board, int sq, int piece, int side)
/***************************************************************************
 *
 *  Generate a bitboard of all squares attacked by a piece on sq.
 *
 ***************************************************************************/
{
   switch (piece)
   {
      case pawn :
         return (bitboards.MoveArray[ptype[side]][sq]);
      case knight :
	 return (bitboards.MoveArray[knight][sq]);
      case bishop :
	return (MagicBishopAttack(board,sq));
      case rook :
	return (MagicRookAttack(board,sq));
      case queen :
	return (MagicQueenAttack(board,sq));
      case king :
	 return (bitboards.MoveArray[king][sq]);
   } 
   return (0);
}


BitBoard AttackXFrom (board_t *board, int sq, int side)
/***************************************************************************
 *
 *  Generate a bitboard of all squares attacked by a piece on sq.  This 
 *  routine is different from AttackFrom in that it includes Xray attacks.
 *  Caveat:  This routine does not take into account xrays through pawns.
 *
 ***************************************************************************/
{
   register BitBoard *a, b, blocker;
   int piece;

   a = board->b[side];
   piece = board->cboard[sq];
   blocker = board->blocker;
   b = 0;
   switch (piece)
   {
      case pawn :
         b = bitboards.MoveArray[ptype[side]][sq];
         break;
      case knight :
	 b = bitboards.MoveArray[knight][sq];
         break;
      case bishop : /* falls through as queens move diagnonally */
      case queen :
	 blocker &= ~(a[bishop] | a[queen]);
	 b|=MagicBishopAttackEx(sq,blocker);
	 if (piece == bishop) /* Queen falls through as they move like rooks */
	    break;
         blocker = board->blocker;
      case rook :
	 blocker &= ~(a[rook] | a[queen]);
	 b|=MagicRookAttackEx(sq,blocker);
	 break;
      case king :
	 b = bitboards.MoveArray[king][sq];
         break;
   } 
   return (b);
}


int PinnedOnKing (board_t *board, int sq, int side)
/***************************************************************************
 *
 *  Determine if the piece on sq is pinned against the King.
 *  Side is the color of the piece.  
 *  Caveat: PinnedOnKing should only be called by GenCheckEscapes().
 *  The more generic FindPins() function should be used for evaluating
 *  pins against other pieces.
 *
 ***************************************************************************/
{
   int xside;
   int KingSq, dir, sq1;
   BitBoard b, blocker;

   KingSq = board->king[side];
   if ((dir = directions[KingSq][sq]) == -1)
      return (false);

   xside = 1 ^ side;
   blocker = board->blocker;
 
   /*  Path from piece to king is blocked, so no pin */
   if (bitboards.FromToRay[KingSq][sq] & bitboards.NotBitPosArray[sq] & blocker)
      return (false);
   b = (bitboards.Ray[KingSq][dir] ^ bitboards.FromToRay[KingSq][sq]) & blocker;
   if (b == NULLBITBOARD)
      return (false);
   sq1 = (sq > KingSq ? leadz (b) : trailz (b));

   /*  If diagonal  */
   if (dir <= 3 && 
	bitboards.BitPosArray[sq1] & 
       (board->b[xside][queen] | board->b[xside][bishop]))
      return (true);
   
   /*  Rank / file  */  
   if (dir >= 4 && 
	bitboards.BitPosArray[sq1] & (board->b[xside][queen] | board->b[xside][rook]))
      return (true);

   return (false);
}


void FindPins (board_t *board, BitBoard *pin)
/***************************************************************************
 *
 *  This function creates a bitboard of all pieces which are pinned.
 *
 ***************************************************************************/
{
   int side, xside;
   int sq, sq1;
   BitBoard b, c, e, f, t, *p;
   
   *pin = NULLBITBOARD;
   t = board->friends[white] | board->friends[black];
   for (side = white; side <= black; side++)
   {
      xside = 1^side;
      p = board->b[xside];

      /*  Check if bishop is pinning anything */
      e = p[rook] | p[queen] | p[king];
      e |= (p[bishop] | p[knight]) & ~Ataks[xside][0];
      b = board->b[side][bishop];
      while (b)
      {
         sq = leadz (b);
         CLEARBIT (b, sq); 

	 c = bitboards.MoveArray[bishop][sq] & e;
         while (c)
         {
	    sq1 = leadz (c);
	    CLEARBIT (c, sq1);
	    f = t & bitboards.NotBitPosArray[sq] & bitboards.FromToRay[sq1][sq];
            if ((board->friends[xside] & f) && nbits (f) == 1)
	       *pin |= f;
         }
      }

      /*  Check if rook is pinning anything */
      e = p[queen] | p[king];
      e |= (p[rook] | p[bishop] | p[knight]) & ~Ataks[xside][0];
      b = board->b[side][rook];
      while (b)
      {
         sq = leadz (b);
         CLEARBIT (b, sq); 

	 c = bitboards.MoveArray[rook][sq] & e;
         while (c)
         {
	    sq1 = leadz (c);
	    CLEARBIT (c, sq1);
	    f = t & bitboards.NotBitPosArray[sq] & bitboards.FromToRay[sq1][sq];
            if ((board->friends[xside] & f) && nbits (f) == 1)
	       *pin |= f;
         }
      }

      /*  Check if queen is pinning anything */
      e = board->b[xside][king];
      e |= (p[queen] | p[rook] | p[bishop] | p[knight]) & ~Ataks[xside][0];
      b = board->b[side][queen];
      while (b)
      {
         sq = leadz (b);
         CLEARBIT (b, sq); 

	 c = bitboards.MoveArray[queen][sq] & e;
         while (c)
         {
	    sq1 = leadz (c);
	    CLEARBIT (c, sq1);
	    f = t & bitboards.NotBitPosArray[sq] & bitboards.FromToRay[sq1][sq];
            if ((board->friends[xside] & f) && nbits (f) == 1)

	       *pin |= f;
         }
      }
   }
      
   return ;
}


int MateScan (board_t *board, int side)
/***************************************************************************
 *
 *  This routine scans the squares around the king to see if a Q + piece
 *  is attacking any of them.  If none, return 0, else return 1.
 *  If the square is defended, there is no threat.
 *  Limitations:  Assume only 1 Q present.
 *
 ***************************************************************************/
{
   int KingSq, QueenSq, sq;
   int xside;
   BitBoard b;

   // XXX [VdB]

   return 0;

   xside = 1 ^ side;

   /*  Opponent has no queen, forget it  */
   if (board->b[xside][queen] == 0)
      return (0);

   KingSq = board->king[side];
   QueenSq = leadz (board->b[xside][queen]);
   b = MagicQueenAttack(board,QueenSq) & bitboards.MoveArray[king][KingSq];
   if (b == 0)
      return (0);

   while (b)
   {
      sq = leadz (b);
      if (AttackTo (board, sq, side) == board->b[side][king] &&
          AttackXTo (board, sq, xside) != board->b[xside][queen])
         return (1);
      CLEARBIT (b, sq);
   }
   
   return (0);
}
