/* swap.c

   GNU Chess frontend

   Copyright (C) 2001-2011 Free Software Foundation, Inc.

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

   This program 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 3 of the License, or
   (at your option) any later version.

   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

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

#include <stdio.h>
#include <string.h>
#include "common.h"

static const int xray[7] = { 0, 1, 0, 1, 1, 1, 0 };

int SwapOff (int move)
/****************************************************************************
 *
 *  A Static Exchange Evaluator (or SEE for short).
 *  First determine the target square.  Create a bitboard of all squares
 *  attacking the target square for both sides.  Using these 2 bitboards,
 *  we take turn making captures from smallest piece to largest piece.
 *  When a sliding piece makes a capture, we check behind it to see if
 *  another attacker piece has been exposed.  If so, add this to the bitboard
 *  as well.  When performing the "captures", we stop if one side is ahead
 *  and doesn't need to capture, a form of pseudo-minimaxing.
 *
 ****************************************************************************/
{
   int f, t, sq, piece, lastval;
   int side, xside;
   int swaplist[MAXPLYDEPTH], n;
   BitBoard b, c, *d, *e, r;

   f = FROMSQ (move);
   t = TOSQ (move);
   side = ((board.friends[white] & BitPosArray[f]) ? white : black);
   xside = 1^side;

   /*  Squares attacking t for side and xside  */
   b = AttackTo (t, side);
   c = AttackTo (t, xside);
   CLEARBIT(b, f);
   if (xray[cboard[f]])
      AddXrayPiece (t, f, side, &b, &c);

   d = board.b[side];
   e = board.b[xside];
   if (move & PROMOTION)
   {
      swaplist[0] = Value[PROMOTEPIECE (move)] - ValueP;
      lastval = -Value[PROMOTEPIECE (move)];
   }
   else
   {
      swaplist[0] = (move & ENPASSANT ? ValueP : Value[cboard[t]]);
      lastval = -Value[cboard[f]];
   }
   n = 1;
   while (1)
   {
      if (c == NULLBITBOARD)
         break;
      for (piece = pawn; piece <= king; piece++)
      {
         r = c & e[piece];
	 if (r)
         {
	    sq = leadz (r);
	    CLEARBIT (c, sq);
	    if (xray[piece])
	       AddXrayPiece (t, sq, xside, &c, &b);
	    swaplist[n] = swaplist[n-1] + lastval;
            n++;
	    lastval = Value[piece];
	    break;
         }
      }

      if (b == NULLBITBOARD)
         break;
      for (piece = pawn; piece <= king; piece++)
      {
         r = b & d[piece];
	 if (r)
         {
	    sq = leadz (r);
	    CLEARBIT (b, sq);
	    if (xray[piece])
	       AddXrayPiece (t, sq, side, &b, &c);
	    swaplist[n] = swaplist[n-1] + lastval;
            n++;
	    lastval = -Value[piece];
	    break;
         }
      }
   }

/****************************************************************************
 *
 *  At this stage, we have the swap scores in a list.  We just need to
 *  mini-max the scores from the bottom up to the top of the list.
 *
 ****************************************************************************/
   --n;
   while (n)
   {
      if (n & 1)
      {
         if (swaplist[n] <= swaplist[n-1])
	    swaplist[n-1] = swaplist[n];
      }
      else
      {
         if (swaplist[n] >= swaplist[n-1])
	    swaplist[n-1] = swaplist[n];
      }
      --n;
   }
   return (swaplist[0]);
}


void AddXrayPiece (int t, int sq, int side, BitBoard *b, BitBoard *c)
/***************************************************************************
 *
 *  The purpose of this routine is to find a piece which attack through
 *  another piece (e.g. two rooks, Q+B, B+P, etc.)  Side is the side attacking
 *  the square where the swapping is to be done.
 *
 ***************************************************************************/
{
   int dir, nsq, piece;
   BitBoard a;

   dir = directions[t][sq];
   a = Ray[sq][dir] & board.blocker;
   if (a == NULLBITBOARD)
      return;
   nsq = (t < sq ? leadz (a) : trailz (a));
   piece = cboard[nsq];
   if ((piece == queen) || (piece == rook && dir > 3) ||
			    (piece == bishop && dir < 4))
   {
      if (BitPosArray[nsq] & board.friends[side])
         *b |= BitPosArray[nsq];
      else
         *c |= BitPosArray[nsq];
   }
   return;
}
