// Copyright 1994, 1995, 1996 by Jon Dart.  All Rights Reserved.

#include "stdafx.h"
#include "board.h"
#include "chessio.h"
#include "rmove.h"
#include "constant.h"
#include "bhash.h"
#include "util.h"
#include "bearing.h" 
#include "debug.h"
#include "globals.h"
#include <strstrea.h>
#include <ctype.h>
#include <memory.h>

enum {BoardSize = 64};
enum {RepListSize = 500};

void Board::set_secondary_vars()
{
    int index[2], i;

    index[Black] = index[White] = 0;

    my_Material[White].clear();
    my_Material[Black].clear();
    pawn_bits[White].clear();
    pawn_bits[Black].clear();
    knight_bits[White].clear();
    knight_bits[Black].clear();
    bishop_bits[White].clear();
    bishop_bits[Black].clear();
    rook_bits[White].clear();
    rook_bits[Black].clear();
    rooksqueens[White].clear();
    rooksqueens[Black].clear();
    bishopsqueens[White].clear();
    bishopsqueens[Black].clear();
    queen_bits[White].clear();
    queen_bits[Black].clear();
    king_bits[White].clear();
    king_bits[Black].clear();
    occupied[White].clear();
    occupied[Black].clear();
    occupiedR90[White].clear();
    occupiedR90[Black].clear();
    occupiedDa1[White].clear();
    occupiedDa1[Black].clear();
    occupiedDa8[White].clear();
    occupiedDa8[Black].clear();
    for (i=0;i<8;i++)
    {
      my_PFileCount[i][White] = my_PFileCount[i][Black] = 0;
    }
    for (i=0;i<BoardSize;i++)
    {
        Square sq(i);
        if (!my_Contents[sq].IsEmpty())
        {
            const Piece piece = my_Contents[sq];
            const ColorType color = piece.Color();
            my_Material[color].add_piece(piece.Type());
            occupied[color].set(sq);
            occupiedR90[color].setR90(sq);
            occupiedDa1[color].setDa1(sq);
            occupiedDa8[color].setDa8(sq);
            switch(piece.Type())
            {
            case Piece::King:
               my_KingPos[color] = sq;
               king_bits[color].set(sq);
               break;
            case Piece::Pawn:
               my_PFileCount[sq.File()-1][color]++;
	       pawn_bits[color].set(sq);
               break;
            case Piece::Knight:
	       knight_bits[color].set(sq);
               break;
            case Piece::Bishop:
	       bishop_bits[color].set(sq);
               bishopsqueens[color].set(sq);
               break;
            case Piece::Rook:
               rook_bits[color].set(sq);
               rooksqueens[color].set(sq);
               break;
            case Piece::Queen:
               queen_bits[color].set(sq);
               rooksqueens[color].set(sq);
               bishopsqueens[color].set(sq);
               break;
            default:
               break;
            }
        }
    }
    my_HashCode = Board_Hash::HashCode(*this);
    m_pawn_hash = Board_Hash::pawn_hash(*this);
    move_count = 0;
}

void Board::Reset()
{
    static Piece::PieceType pieces[] =
    {
       Piece::Rook,
       Piece::Knight,
       Piece::Bishop,
       Piece::Queen,
       Piece::King,
       Piece::Bishop,
       Piece::Knight,
       Piece::Rook
    };

    my_Side = White;
    my_CheckStatus = Unknown;
    for (int i=0;i<BoardSize;i++)
    {
       const Square sq(i);
       if (sq.Rank(White) == 1)
           my_Contents[sq] = Piece( pieces[sq.File()-1], White );
       else if (sq.Rank(Black) == 1)
           my_Contents[sq] = Piece( pieces[sq.File()-1], Black );
       else if (sq.Rank(White) == 2)
           my_Contents[sq] = Piece( Piece::Pawn, White);
       else if (sq.Rank(Black) == 2)
           my_Contents[sq] = Piece( Piece::Pawn, Black);
       else
           my_Contents[sq] = Piece();
    }
    my_EnPassantSq[White] = my_EnPassantSq[Black] = Square::Invalid();
    my_CastleStatus[White] = my_CastleStatus[Black] = CanCastleEitherSide;
    set_secondary_vars();
    if (rep_list)
       delete [] rep_list;
    rep_list = rep_list_head = new hash_t[RepListSize];
    move_count = 0;
}

Board::Board()
: rep_list(NULL)
{
    Reset();
}

Board::Board(const Board &b)
{
    my_Side = b.my_Side;
    my_CheckStatus = b.my_CheckStatus;
    for (int i=0;i<BoardSize;i++)
    {
       const Square sq(i);
       my_Contents[sq] = b[sq];
    }
    my_EnPassantSq[White] = b.my_EnPassantSq[White];
    my_EnPassantSq[Black] = b.my_EnPassantSq[Black];
    my_CastleStatus[White] = b.my_CastleStatus[White];
    my_CastleStatus[Black] = b.my_CastleStatus[Black];
    set_secondary_vars();

    // Copy the repetition table
    move_count = b.move_count;
    rep_list = new hash_t[RepListSize];
    int rep_entries = b.rep_list_head - b.rep_list;
    for (i = 0; i < rep_entries; i++)
       rep_list[i] = b.rep_list[i];
    rep_list_head = rep_list + rep_entries;
}

Board &Board::operator =(const Board &b)
{
    if (&b != this)
    {
    my_Side = b.my_Side;
    my_CheckStatus = b.my_CheckStatus;
    for (int i=0;i<BoardSize;i++)
    {
       const Square sq(i);
       my_Contents[sq] = b[sq];
    }
    my_EnPassantSq[White] = b.my_EnPassantSq[White];
    my_EnPassantSq[Black] = b.my_EnPassantSq[Black];
    my_CastleStatus[White] = b.my_CastleStatus[White];
    my_CastleStatus[Black] = b.my_CastleStatus[Black];
    set_secondary_vars();

    // Copy the repetition table
    move_count = b.move_count;
    delete [] rep_list;
    rep_list = new hash_t[RepListSize];
    int rep_entries = b.rep_list_head - b.rep_list;
    for (i = 0; i < rep_entries; i++)
       rep_list[i] = b.rep_list[i];
    rep_list_head = rep_list + rep_entries;
    }
    return *this;
}

Board::~Board()
{
    delete [] rep_list;
}

#ifdef _DEBUG
const Piece &Board::operator[]( const Square sq ) const
{
     ASSERT(sq.OnBoard());
     return my_Contents[sq];
}
#endif

void Board::UpdateCastleStatus( const ColorType side, 
                                const Square sq )
// after a move of or capture of the rook on 'sq', update castle status
// for 'side'
{
     CastleType cs = CastleStatus(side);
     if ((cs != CastledKSide) && (cs != CastledQSide))
     {
         if (sq.File() == 1) // Queen Rook moved or captured
         {
             if (cs == CanCastleEitherSide)
                   my_CastleStatus[side] = CanCastleKSide;
             else if (cs == CanCastleQSide)
                   my_CastleStatus[side] = CantCastleEitherSide;
         }
         else if (sq.File() == 8) // King Rook moved or captured
         {
             if (cs == CanCastleEitherSide)
                   my_CastleStatus[side] = CanCastleQSide;
             else if (cs == CanCastleKSide)
                   my_CastleStatus[side] = CantCastleEitherSide;
         }
     }
}

int Board::Direction( const Square &sq1, const Square &sq2 )
{
     return Bearing::Directions[sq1][sq2];
}

int Board::Between( const Square &sq1, const Square &sq2, 
                Square *squares) const
{
     int offset = Board::Direction(sq1,sq2);
     Square sq(sq1);
     int n = 0;
     for (;;)
     {
         sq += offset;
         if (sq == sq2)
            break;
         squares[n++] = sq;
     }
     return n;
}


BOOL Board::Clear( const Square &sq1, const Square &sq2 ) const
{
     Square BtwnSquares[9];
     int m = Between(sq1,sq2,BtwnSquares);
     BOOL is_clear = TRUE;
     if (m == 0)
        return TRUE;
     else
     {
        int k = 0;
        do
        {
            is_clear = my_Contents[BtwnSquares[k++]].IsEmpty();
        } while (is_clear && (k<m));
     }
     return is_clear;
}

//#pragma optimize("g", off)

void Board::MakeMove( const ExtendedMove &move )
{
     const ColorType oside = OppositeSide();
     const ColorType side = Side();
     Square kp,target;
     my_CheckStatus = Unknown;
     move_count++;
     if (move.IsNull())
     {
     	 my_Side = oside;
         Board_Hash::update_hash( *this, move, my_HashCode, m_pawn_hash);
         *rep_list_head++ = my_HashCode;
         UNCOND_ASSERT(rep_list_head-rep_list < 500);
         return;
     }
     else
         Board_Hash::update_hash( *this, move, my_HashCode, m_pawn_hash );

     ASSERT(!move.PieceMoved().IsEmpty());

     if (side == White)
     {
     if (move.Special() == ExtendedMove::KCastle)
     {
        move_count = 0;
	const Square kp = KingPos(White);
        const int newkp = kp + 2;
	my_KingPos[White] = newkp;
	my_CastleStatus[White] = CastledKSide;
	// find old square of rook
	Square oldrooksq = kp + 3;
	Square newrooksq = kp + 1;
	my_Contents[kp] = my_Contents[oldrooksq] = Piece();
	my_Contents[newrooksq] = Piece(Piece::Rook,White);
	my_Contents[newkp] = Piece(Piece::King,White);
        king_bits[White].clear(kp);
        rook_bits[White].clear(oldrooksq);
        rooksqueens[White].clear(oldrooksq);
        king_bits[White].set(newkp);
        rook_bits[White].set(newrooksq);
        rooksqueens[White].set(newrooksq);
        occupied[White].clear(kp);
        occupied[White].clear(oldrooksq);
        occupied[White].set(newkp);
        occupied[White].set(newrooksq);
        occupiedR90[White].clearR90(kp);
        occupiedDa8[White].clearDa8(kp);
        occupiedDa1[White].clearDa1(kp);
        occupiedR90[White].clearR90(oldrooksq);
        occupiedDa1[White].clearDa1(oldrooksq);
        occupiedDa8[White].clearDa8(oldrooksq);
        occupiedR90[White].setR90(newkp);
        occupiedDa8[White].setDa8(newkp);
        occupiedDa1[White].setDa1(newkp);
        occupiedR90[White].setR90(newrooksq);
        occupiedDa1[White].setDa1(newrooksq);
        occupiedDa8[White].setDa8(newrooksq);
     }
     else if (move.Special() == ExtendedMove::QCastle)
     {
        move_count = 0;
	const Square kp = KingPos(White);
        const int newkp = kp - 2;
	my_KingPos[White] = newkp;
	my_CastleStatus[White] = CastledQSide;
	// find old square of rook
	Square oldrooksq = kp - 4;
	Square newrooksq = kp - 1;
	my_Contents[kp] = my_Contents[oldrooksq] = Piece();
	my_Contents[newrooksq] = Piece(Piece::Rook,White);
	my_Contents[kp-2] = Piece(Piece::King,White);
        king_bits[White].clear(kp);
        rook_bits[White].clear(oldrooksq);
        rooksqueens[White].clear(oldrooksq);
        king_bits[White].set(newkp);
        rook_bits[White].set(newrooksq);
        rooksqueens[White].set(newrooksq);
        occupied[White].clear(kp);
        occupied[White].clear(oldrooksq);
        occupied[White].set(newkp);
        occupied[White].set(newrooksq);
        occupiedR90[White].clearR90(kp);
        occupiedDa1[White].clearDa1(kp);
        occupiedDa8[White].clearDa8(kp);
        occupiedR90[White].clearR90(oldrooksq);
        occupiedDa1[White].clearDa1(oldrooksq);
        occupiedDa8[White].clearDa8(oldrooksq);
        occupiedR90[White].setR90(newkp);
        occupiedDa1[White].setDa1(newkp);
        occupiedDa8[White].setDa8(newkp);
        occupiedR90[White].setR90(newrooksq);
        occupiedDa1[White].setDa1(newrooksq);
        occupiedDa8[White].setDa8(newrooksq);
     }
     else // not castling
     {
        if (move.Special() == ExtendedMove::EnPassant)
	    target = my_EnPassantSq[Black];
        else
	    target = move.DestSquare();
	if (move.Special() == ExtendedMove::Promotion)
	   my_Contents[move.DestSquare()] = Piece(move.PromoteTo(),side);
        else
	   my_Contents[move.DestSquare()] = move.PieceMoved();
	my_Contents[move.StartSquare()] = Piece();
        occupied[White].clear(move.StartSquare());
        occupiedR90[White].clearR90(move.StartSquare());
        occupiedDa1[White].clearDa1(move.StartSquare());
        occupiedDa8[White].clearDa8(move.StartSquare());
        occupied[White].set(move.DestSquare());
        occupiedR90[White].setR90(move.DestSquare());
        occupiedDa1[White].setDa1(move.DestSquare());
        occupiedDa8[White].setDa8(move.DestSquare());

	my_EnPassantSq[White] = Square::Invalid();
        switch (move.PieceMoved().Type())
        {
	    case Piece::King:
	       my_KingPos[White] = move.DestSquare();
	       if ((CastleStatus(side) != CastledQSide) &&
	         (CastleStatus(side) != CastledKSide))
	          my_CastleStatus[White] = CantCastleEitherSide;
               king_bits[White].clear(move.StartSquare());
               king_bits[White].set(move.DestSquare());
               break;
            case Piece::Rook:
               rook_bits[White].clear(move.StartSquare());
               rooksqueens[White].clear(move.StartSquare());
               rook_bits[White].set(move.DestSquare());
               rooksqueens[White].set(move.DestSquare());
	       UpdateCastleStatus(side,move.StartSquare());
               break;
	    case Piece::Pawn:
               move_count = 0;
  	       pawn_bits[White].clear(move.StartSquare());
               my_PFileCount[move.StartSquare().File()-1][White]--;
	       if (Util::Abs(move.StartSquare().Rank(side) -
	   	 	  move.DestSquare().Rank(side)) == 2)
               {
	          my_EnPassantSq[White] = move.DestSquare();
	       }
	       if (move.Special() == ExtendedMove::Promotion)
	       {
	          my_Material[White].remove_piece(Piece::Pawn);
	          my_Material[White].add_piece(move.PromoteTo());
                  switch(move.PromoteTo())
                  {
                     case Piece::Knight:
                        knight_bits[White].set(move.DestSquare());
                        break;
                     case Piece::Bishop:
                        bishop_bits[White].set(move.DestSquare());
			bishopsqueens[White].set(move.DestSquare());
                        break;
                     case Piece::Rook:
                        rook_bits[White].set(move.DestSquare());
			rooksqueens[White].set(move.DestSquare());
                        break;
                     case Piece::Queen:
                        queen_bits[White].set(move.DestSquare());
			bishopsqueens[White].set(move.DestSquare());
			rooksqueens[White].set(move.DestSquare());
                        break;
                     default:
                     break;
                  }
	       }
	       else // not promoting
               {
	          pawn_bits[White].set(move.DestSquare());
                  my_PFileCount[move.DestSquare().File()-1][White]++;
               }
               break;
            case Piece::Knight:
               knight_bits[White].clear(move.StartSquare());
               knight_bits[White].set(move.DestSquare());
               break;
            case Piece::Bishop:
               bishop_bits[White].clear(move.StartSquare());
               bishop_bits[White].set(move.DestSquare());
               bishopsqueens[White].clear(move.StartSquare());
               bishopsqueens[White].set(move.DestSquare());
               break;
            case Piece::Queen:
               queen_bits[White].clear(move.StartSquare());
               queen_bits[White].set(move.DestSquare());
               rooksqueens[White].clear(move.StartSquare());
               rooksqueens[White].set(move.DestSquare());
               bishopsqueens[White].clear(move.StartSquare());
               bishopsqueens[White].set(move.DestSquare());
               break;
            default:
               break;
	}
	if (!move.Capture().IsEmpty())
	{
            move_count = 0;
	    my_Material[Black].remove_piece(move.Capture().Type());
            ASSERT(!target.IsInvalid());
            occupied[Black].clear(target);
            occupiedR90[Black].clearR90(target);
            occupiedDa1[Black].clearDa1(target);
            occupiedDa8[Black].clearDa8(target);
            switch(move.Capture().Type())
            {
	       case Piece::Pawn:
	          my_PFileCount[target.File()-1][Black]--;
	          pawn_bits[Black].clear(target);
                  break;
               case Piece::Rook:
	          UpdateCastleStatus(Black,move.DestSquare());
                  rook_bits[Black].clear(target);
                  rooksqueens[Black].clear(target);
                  break;
               case Piece::Knight:
                  knight_bits[Black].clear(target);
                  break;
               case Piece::Bishop:
                  bishop_bits[Black].clear(target);
                  bishopsqueens[Black].clear(target);
                  break;
               case Piece::Queen:
                  queen_bits[Black].clear(target);
                  rooksqueens[Black].clear(target);
                  bishopsqueens[Black].clear(target);
                  break;
               case Piece::King:
                  ASSERT(FALSE);
                  king_bits[Black].clear(target);
                  my_KingPos[Black].SetInvalid();
	          my_CastleStatus[Black] = CantCastleEitherSide;
                  break;
               default: 
                  break;
	    }
	}
        if (move.Special() == ExtendedMove::EnPassant)
        {
     	    my_Contents[target] = Piece();
        }
     }
     my_EnPassantSq[Black] = Square::Invalid();
     
     }
     else // side == Black
     {
     if (move.Special() == ExtendedMove::KCastle)
     {
        move_count = 0;
	const Square kp = KingPos(Black);
        const int newkp = kp + 2;
	my_KingPos[Black] = newkp;
	my_CastleStatus[Black] = CastledKSide;
	// find old square of rook
	Square oldrooksq = kp + 3;
	Square newrooksq = kp + 1;
	my_Contents[kp] = my_Contents[oldrooksq] = Piece();
	my_Contents[newrooksq] = Piece(Piece::Rook,Black);
	my_Contents[kp+2] = Piece(Piece::King,Black);
        king_bits[Black].clear(kp);
        rook_bits[Black].clear(oldrooksq);
        rooksqueens[Black].clear(oldrooksq);
        king_bits[Black].set(newkp);
        rook_bits[Black].set(newrooksq);
        rooksqueens[Black].set(newrooksq);
        occupied[Black].clear(kp);
        occupied[Black].clear(oldrooksq);
        occupied[Black].set(newkp);
        occupied[Black].set(newrooksq);
        occupiedR90[Black].clearR90(kp);
        occupiedDa8[Black].clearDa8(kp);
        occupiedDa1[Black].clearDa1(kp);
        occupiedR90[Black].clearR90(oldrooksq);
        occupiedDa1[Black].clearDa1(oldrooksq);
        occupiedDa8[Black].clearDa8(oldrooksq);
        occupiedR90[Black].setR90(newkp);
        occupiedDa8[Black].setDa8(newkp);
        occupiedDa1[Black].setDa1(newkp);
        occupiedR90[Black].setR90(newrooksq);
        occupiedDa1[Black].setDa1(newrooksq);
        occupiedDa8[Black].setDa8(newrooksq);
     }
     else if (move.Special() == ExtendedMove::QCastle)
     {
        move_count = 0;
	const Square kp = KingPos(Black);
        const int newkp = kp - 2;
	my_KingPos[Black] = newkp;
	my_CastleStatus[Black] = CastledQSide;
	// find old square of rook
	Square oldrooksq = kp - 4;
	Square newrooksq = kp - 1;
	my_Contents[kp] = my_Contents[oldrooksq] = Piece();
	my_Contents[newrooksq] = Piece(Piece::Rook,Black);
	my_Contents[kp-2] = Piece(Piece::King,Black);
        king_bits[Black].clear(kp);
        rook_bits[Black].clear(oldrooksq);
        rooksqueens[Black].clear(oldrooksq);
        king_bits[Black].set(newkp);
        rook_bits[Black].set(newrooksq);
        rooksqueens[Black].set(newrooksq);
        occupied[Black].clear(kp);
        occupied[Black].clear(oldrooksq);
        occupied[Black].set(newkp);
        occupied[Black].set(newrooksq);
        occupiedR90[Black].clearR90(kp);
        occupiedDa1[Black].clearDa1(kp);
        occupiedDa8[Black].clearDa8(kp);
        occupiedR90[Black].clearR90(oldrooksq);
        occupiedDa1[Black].clearDa1(oldrooksq);
        occupiedDa8[Black].clearDa8(oldrooksq);
        occupiedR90[Black].setR90(newkp);
        occupiedDa1[Black].setDa1(newkp);
        occupiedDa8[Black].setDa8(newkp);
        occupiedR90[Black].setR90(newrooksq);
        occupiedDa1[Black].setDa1(newrooksq);
        occupiedDa8[Black].setDa8(newrooksq);
     }
     else // not castling
     {
        if (move.Special() == ExtendedMove::EnPassant)
	    target = my_EnPassantSq[White];
        else
	    target = move.DestSquare();
	if (move.Special() == ExtendedMove::Promotion)
	   my_Contents[move.DestSquare()] = Piece(move.PromoteTo(),side);
        else
	   my_Contents[move.DestSquare()] = move.PieceMoved();
	my_Contents[move.StartSquare()] = Piece();
        occupied[Black].clear(move.StartSquare());
        occupiedR90[Black].clearR90(move.StartSquare());
        occupiedDa1[Black].clearDa1(move.StartSquare());
        occupiedDa8[Black].clearDa8(move.StartSquare());
        occupied[Black].set(move.DestSquare());
        occupiedR90[Black].setR90(move.DestSquare());
        occupiedDa1[Black].setDa1(move.DestSquare());
        occupiedDa8[Black].setDa8(move.DestSquare());

	my_EnPassantSq[Black] = Square::Invalid();
        switch (move.PieceMoved().Type())
        {
	    case Piece::King:
	       my_KingPos[Black] = move.DestSquare();
	       if ((CastleStatus(side) != CastledQSide) &&
	         (CastleStatus(side) != CastledKSide))
	          my_CastleStatus[Black] = CantCastleEitherSide;
               king_bits[Black].clear(move.StartSquare());
               king_bits[Black].set(move.DestSquare());
               break;
            case Piece::Rook:
               rook_bits[Black].clear(move.StartSquare());
               rooksqueens[Black].clear(move.StartSquare());
               rook_bits[Black].set(move.DestSquare());
               rooksqueens[Black].set(move.DestSquare());
	       UpdateCastleStatus(side,move.StartSquare());
               break;
	    case Piece::Pawn:
               move_count = 0;
  	       pawn_bits[Black].clear(move.StartSquare());
               my_PFileCount[move.StartSquare().File()-1][Black]--;
	       if (Util::Abs(move.StartSquare().Rank(side) -
	   	 	  move.DestSquare().Rank(side)) == 2)
               {
	          my_EnPassantSq[Black] = move.DestSquare();
	       }
	       if (move.Special() == ExtendedMove::Promotion)
	       {
	          my_Material[Black].remove_piece(Piece::Pawn);
	          my_Material[Black].add_piece(move.PromoteTo());
                  switch(move.PromoteTo())
                  {
                     case Piece::Knight:
                        knight_bits[Black].set(move.DestSquare());
                        break;
                     case Piece::Bishop:
                        bishop_bits[Black].set(move.DestSquare());
			bishopsqueens[Black].set(move.DestSquare());
                        break;
                     case Piece::Rook:
                        rook_bits[Black].set(move.DestSquare());
			rooksqueens[Black].set(move.DestSquare());
                        break;
                     case Piece::Queen:
                        queen_bits[Black].set(move.DestSquare());
			bishopsqueens[Black].set(move.DestSquare());
			rooksqueens[Black].set(move.DestSquare());
                        break;
                     default:
                     break;
                  }
	       }
	       else // not promoting
               {
	          pawn_bits[Black].set(move.DestSquare());
                  my_PFileCount[move.DestSquare().File()-1][Black]++;
               }
               break;
            case Piece::Knight:
               knight_bits[Black].clear(move.StartSquare());
               knight_bits[Black].set(move.DestSquare());
               break;
            case Piece::Bishop:
               bishop_bits[Black].clear(move.StartSquare());
               bishop_bits[Black].set(move.DestSquare());
               bishopsqueens[Black].clear(move.StartSquare());
               bishopsqueens[Black].set(move.DestSquare());
               break;
            case Piece::Queen:
               queen_bits[Black].clear(move.StartSquare());
               queen_bits[Black].set(move.DestSquare());
               rooksqueens[Black].clear(move.StartSquare());
               rooksqueens[Black].set(move.DestSquare());
               bishopsqueens[Black].clear(move.StartSquare());
               bishopsqueens[Black].set(move.DestSquare());
               break;
            default:
               break;
	}
	if (!move.Capture().IsEmpty())
	{
            move_count = 0;
	    my_Material[White].remove_piece(move.Capture().Type());
            ASSERT(!target.IsInvalid());
            occupied[White].clear(target);
            occupiedR90[White].clearR90(target);
            occupiedDa1[White].clearDa1(target);
            occupiedDa8[White].clearDa8(target);
            switch(move.Capture().Type())
            {
	       case Piece::Pawn:
	          my_PFileCount[target.File()-1][White]--;
	          pawn_bits[White].clear(target);
                  break;
               case Piece::Rook:
	          UpdateCastleStatus(White,move.DestSquare());
                  rook_bits[White].clear(target);
                  rooksqueens[White].clear(target);
                  break;
               case Piece::Knight:
                  knight_bits[White].clear(target);
                  break;
               case Piece::Bishop:
                  bishop_bits[White].clear(target);
                  bishopsqueens[White].clear(target);
                  break;
               case Piece::Queen:
                  queen_bits[White].clear(target);
                  rooksqueens[White].clear(target);
                  bishopsqueens[White].clear(target);
                  break;
               case Piece::King:
                  ASSERT(FALSE);
                  king_bits[White].clear(target);
                  my_KingPos[White].SetInvalid();
	          my_CastleStatus[White] = CantCastleEitherSide;
                  break;
               default: 
                  break;
	    }
	}
        if (move.Special() == ExtendedMove::EnPassant)
        {
     	    my_Contents[target] = Piece();
        }
     }
     my_EnPassantSq[White] = Square::Invalid();
     }

     my_Side = OppositeSide();
     *rep_list_head++ = my_HashCode;
     UNCOND_ASSERT(rep_list_head-rep_list < 500);
     ASSERT(pawn_hash() == Board_Hash::pawn_hash(*this));
#ifdef _DEBUG
     // verify correct updating of bitmaps:
     Board copy = *this;
     copy.set_secondary_vars();
     ASSERT(pawn_bits[White] == copy.pawn_bits[White]);
     ASSERT(knight_bits[White] == copy.knight_bits[White]);
     ASSERT(bishop_bits[White] == copy.bishop_bits[White]);
     ASSERT(rook_bits[White] == copy.rook_bits[White]);
     ASSERT(queen_bits[White] == copy.queen_bits[White]);
     ASSERT(king_bits[White] == copy.king_bits[White]);
     ASSERT(bishopsqueens[White] == copy.bishopsqueens[White]);
     ASSERT(rooksqueens[White] == copy.rooksqueens[White]);
     ASSERT(occupied[White] == copy.occupied[White]);
     ASSERT(occupiedR90[White] == copy.occupiedR90[White]);
     ASSERT(occupiedDa1[White] == copy.occupiedDa1[White]);
     ASSERT(occupiedDa8[White] == copy.occupiedDa8[White]);
     
     ASSERT(pawn_bits[Black] == copy.pawn_bits[Black]);
     ASSERT(knight_bits[Black] == copy.knight_bits[Black]);
     ASSERT(bishop_bits[Black] == copy.bishop_bits[Black]);
     ASSERT(rook_bits[Black] == copy.rook_bits[Black]);
     ASSERT(queen_bits[Black] == copy.queen_bits[Black]);
     ASSERT(king_bits[Black] == copy.king_bits[Black]);
     ASSERT(bishopsqueens[Black] == copy.bishopsqueens[Black]);
     ASSERT(rooksqueens[Black] == copy.rooksqueens[Black]);
     ASSERT(occupied[Black] == copy.occupied[Black]);
     ASSERT(occupiedR90[Black] == copy.occupiedR90[Black]);
     ASSERT(occupiedDa1[Black] == copy.occupiedDa1[Black]);
     ASSERT(occupiedDa8[Black] == copy.occupiedDa8[Black]);
     for (int k = 0; k <8; ++k)
     {
        ASSERT(my_PFileCount[k][White] == copy.my_PFileCount[k][White]);
        ASSERT(my_PFileCount[k][Black] == copy.my_PFileCount[k][Black]);
     }
     ASSERT(my_Contents[my_KingPos[White]]==Piece(Piece::King,White));
     ASSERT(my_Contents[my_KingPos[Black]]==Piece(Piece::King,Black));
#endif     
     ASSERT(my_HashCode == Board_Hash::HashCode(*this));
}

//#pragma optimize( "g", on)

void Board::undo_castling(const Square &kp,
        const Square &oldkingsq, const Square &newrooksq,
        const Square &oldrooksq)
{
        my_Contents[kp] = Piece();
        my_Contents[oldrooksq] = Piece(Piece::Rook,my_Side);
        my_Contents[newrooksq] = Piece();
        my_Contents[oldkingsq] = Piece(Piece::King,my_Side);
        my_KingPos[my_Side] = oldkingsq;
        king_bits[my_Side].clear(kp);
        occupied[my_Side].clear(kp);
        occupiedR90[my_Side].clearR90(kp);
        occupiedDa1[my_Side].clearDa1(kp);
        occupiedDa8[my_Side].clearDa8(kp);
        king_bits[my_Side].set(oldkingsq);
        occupied[my_Side].set(oldkingsq);
        occupiedR90[my_Side].setR90(oldkingsq);
        occupiedDa1[my_Side].setDa1(oldkingsq);
        occupiedDa8[my_Side].setDa8(oldkingsq);
        
        rook_bits[my_Side].set(oldrooksq);
        rook_bits[my_Side].clear(newrooksq);
        rooksqueens[my_Side].set(oldrooksq);
        rooksqueens[my_Side].clear(newrooksq);
        occupied[my_Side].set(oldrooksq);
        occupiedR90[my_Side].setR90(oldrooksq);
        occupiedDa1[my_Side].setDa1(oldrooksq);
        occupiedDa8[my_Side].setDa8(oldrooksq);
        occupied[my_Side].clear(newrooksq);
        occupiedR90[my_Side].clearR90(newrooksq);
        occupiedDa1[my_Side].clearDa1(newrooksq);
        occupiedDa8[my_Side].clearDa8(newrooksq);
}

void Board::UndoMove( const ReversibleMove &rmove )
{
    my_Side = OppositeColor(my_Side);
    if (!rmove.IsNull())
    {
    const ColorType opp_side = OppositeColor(my_Side);
    if (rmove.Special() == ExtendedMove::KCastle)
    {
        Square kp = KingPos(my_Side);
	Square oldrooksq(kp+1);
	Square newrooksq(kp-1);
	Square oldkingsq(kp-2);
	undo_castling(kp,oldkingsq,newrooksq,oldrooksq);
     }
    else if (rmove.Special() == ExtendedMove::QCastle)
    {
        Square kp = KingPos(my_Side);
	Square oldrooksq(kp-2);
	Square newrooksq(kp+1);
	Square oldkingsq(kp+2);
	undo_castling(kp,oldkingsq,newrooksq,oldrooksq);
    }
    else if (my_Side == White)
    {
        // not castling
	Square target;
        if (rmove.Special() == ExtendedMove::EnPassant)
            target = rmove.DestSquare() + RankIncr;
        else
            target = rmove.DestSquare();
	// fix up start square:
	if (rmove.Special() == ExtendedMove::Promotion)
        {
	   my_Contents[rmove.StartSquare()] = Piece(Piece::Pawn,White);
        }
        else
        {
           my_Contents[rmove.StartSquare()] = rmove.PieceMoved();
        }
        occupied[White].set(rmove.StartSquare());
        occupiedR90[White].setR90(rmove.StartSquare());
        occupiedDa1[White].setDa1(rmove.StartSquare());
        occupiedDa8[White].setDa8(rmove.StartSquare());
        switch (rmove.PieceMoved().Type())
	{
	   case Piece::Pawn:
              if (rmove.Special() == ExtendedMove::Promotion)
              {
	         my_Material[White].add_piece(Piece::Pawn);
	         my_Material[White].remove_piece(rmove.PromoteTo());
	         my_PFileCount[rmove.StartSquare().File()-1][White]++;
                 switch(rmove.PromoteTo())
                 {
                 case Piece::Knight:
                    knight_bits[White].clear(rmove.DestSquare());
                    break;
                 case Piece::Bishop:
                    bishop_bits[White].clear(rmove.DestSquare());
                    bishopsqueens[White].clear(rmove.DestSquare());
                    break;
                 case Piece::Rook:
                    rook_bits[White].clear(rmove.DestSquare());
                    rooksqueens[White].clear(rmove.DestSquare());
                    break;
                 case Piece::Queen:
                    queen_bits[White].clear(rmove.DestSquare());
                    bishopsqueens[White].clear(rmove.DestSquare());
                    rooksqueens[White].clear(rmove.DestSquare());
                    break;
                 default:
                    break;
                 }
              }
              else
              {
	         pawn_bits[White].clear(rmove.DestSquare());
	         my_PFileCount[rmove.StartSquare().File()-1][White]++;
	         my_PFileCount[rmove.DestSquare().File()-1][White]--;
              }
              pawn_bits[White].set(rmove.StartSquare());
	      break;
           case Piece::Knight:
              knight_bits[White].clear(rmove.DestSquare());
              knight_bits[White].set(rmove.StartSquare());
              break;
           case Piece::Bishop:
              bishop_bits[White].clear(rmove.DestSquare());
              bishopsqueens[White].clear(rmove.DestSquare());
              bishop_bits[White].set(rmove.StartSquare());
              bishopsqueens[White].set(rmove.StartSquare());
              break;
	   case Piece::Rook:
              rook_bits[White].clear(rmove.DestSquare());
              rooksqueens[White].clear(rmove.DestSquare());
              rook_bits[White].set(rmove.StartSquare());
              rooksqueens[White].set(rmove.StartSquare());
	      break;
           case Piece::Queen:
              queen_bits[White].clear(rmove.DestSquare());
              rooksqueens[White].clear(rmove.DestSquare());
              bishopsqueens[White].clear(rmove.DestSquare());
              queen_bits[White].set(rmove.StartSquare());
              rooksqueens[White].set(rmove.StartSquare());
              bishopsqueens[White].set(rmove.StartSquare());
              break;
	   case Piece::King:
              king_bits[White].clear(rmove.DestSquare());
              king_bits[White].set(rmove.StartSquare());
	      my_KingPos[White] = rmove.StartSquare();
	      break;
	   default:
	      break;
        }
	// fix up dest square
        occupied[White].clear(rmove.DestSquare());
        occupiedR90[White].clearR90(rmove.DestSquare());
        occupiedDa1[White].clearDa1(rmove.DestSquare());
        occupiedDa8[White].clearDa8(rmove.DestSquare());
        my_Contents[rmove.DestSquare()] = Piece();
        my_Contents[target] = rmove.Capture();
 	my_EnPassantSq[Black] = Square::Invalid();
	if (!rmove.Capture().IsEmpty())
	{
	    my_Material[Black].add_piece(rmove.Capture().Type());
            switch(rmove.Capture().Type())
            {
               case Piece::Pawn:
  	          pawn_bits[Black].set(target);
	          my_PFileCount[rmove.DestSquare().File()-1][Black]++;
                  break;
               case Piece::Knight:
  	          knight_bits[Black].set(target);
                  break;
               case Piece::Bishop:
  	          bishop_bits[Black].set(target);
                  bishopsqueens[Black].set(target);
                  break;
               case Piece::Rook:
  	          rook_bits[Black].set(target);
                  rooksqueens[Black].set(target);
                  break;
               case Piece::Queen:
  	          queen_bits[Black].set(target);
                  bishopsqueens[Black].set(target);
                  rooksqueens[Black].set(target);
                  break;
               case Piece::King:
  	          king_bits[Black].set(target);
                  my_KingPos[Black] = target;
                  break;
               default:
                  break;
	    }
            occupied[Black].set(target);
            occupiedR90[Black].setR90(target);
            occupiedDa1[Black].setDa1(target);
            occupiedDa8[Black].setDa8(target);
	}
    }
    else // my_Side == Black
    {
        // not castling
	Square target;
        if (rmove.Special() == ExtendedMove::EnPassant)
            target = rmove.DestSquare() - RankIncr;
        else
            target = rmove.DestSquare();
	// fix up start square:
	if (rmove.Special() == ExtendedMove::Promotion)
        {
	   my_Contents[rmove.StartSquare()] = Piece(Piece::Pawn,Black);
        }
        else
        {
           my_Contents[rmove.StartSquare()] = rmove.PieceMoved();
        }
        occupied[Black].set(rmove.StartSquare());
        occupiedR90[Black].setR90(rmove.StartSquare());
        occupiedDa1[Black].setDa1(rmove.StartSquare());
        occupiedDa8[Black].setDa8(rmove.StartSquare());
        switch (rmove.PieceMoved().Type())
	{
	   case Piece::Pawn:
              if (rmove.Special() == ExtendedMove::Promotion)
              {
	         my_Material[Black].add_piece(Piece::Pawn);
	         my_Material[Black].remove_piece(rmove.PromoteTo());
	         my_PFileCount[rmove.StartSquare().File()-1][Black]++;
                 switch(rmove.PromoteTo())
                 {
                 case Piece::Knight:
                    knight_bits[Black].clear(rmove.DestSquare());
                    break;
                 case Piece::Bishop:
                    bishop_bits[Black].clear(rmove.DestSquare());
                    bishopsqueens[Black].clear(rmove.DestSquare());
                    break;
                 case Piece::Rook:
                    rook_bits[Black].clear(rmove.DestSquare());
                    rooksqueens[Black].clear(rmove.DestSquare());
                    break;
                 case Piece::Queen:
                    queen_bits[Black].clear(rmove.DestSquare());
                    bishopsqueens[Black].clear(rmove.DestSquare());
                    rooksqueens[Black].clear(rmove.DestSquare());
                    break;
                 default:
                    break;
                 }
              }
              else
              {
	         pawn_bits[Black].clear(rmove.DestSquare());
	         my_PFileCount[rmove.StartSquare().File()-1][Black]++;
	         my_PFileCount[rmove.DestSquare().File()-1][Black]--;
              }
              pawn_bits[Black].set(rmove.StartSquare());
	      break;
           case Piece::Knight:
              knight_bits[Black].clear(rmove.DestSquare());
              knight_bits[Black].set(rmove.StartSquare());
              break;
           case Piece::Bishop:
              bishop_bits[Black].clear(rmove.DestSquare());
              bishopsqueens[Black].clear(rmove.DestSquare());
              bishop_bits[Black].set(rmove.StartSquare());
              bishopsqueens[Black].set(rmove.StartSquare());
              break;
	   case Piece::Rook:
              rook_bits[Black].clear(rmove.DestSquare());
              rooksqueens[Black].clear(rmove.DestSquare());
              rook_bits[Black].set(rmove.StartSquare());
              rooksqueens[Black].set(rmove.StartSquare());
	      break;
           case Piece::Queen:
              queen_bits[Black].clear(rmove.DestSquare());
              rooksqueens[Black].clear(rmove.DestSquare());
              bishopsqueens[Black].clear(rmove.DestSquare());
              queen_bits[Black].set(rmove.StartSquare());
              rooksqueens[Black].set(rmove.StartSquare());
              bishopsqueens[Black].set(rmove.StartSquare());
              break;
	   case Piece::King:
              king_bits[Black].clear(rmove.DestSquare());
              king_bits[Black].set(rmove.StartSquare());
	      my_KingPos[Black] = rmove.StartSquare();
	      break;
	   default:
	      break;
        }
	// fix up dest square
        occupied[Black].clear(rmove.DestSquare());
        occupiedR90[Black].clearR90(rmove.DestSquare());
        occupiedDa1[Black].clearDa1(rmove.DestSquare());
        occupiedDa8[Black].clearDa8(rmove.DestSquare());
        my_Contents[rmove.DestSquare()] = Piece();
        my_Contents[target] = rmove.Capture();
 	my_EnPassantSq[White] = Square::Invalid();
	if (!rmove.Capture().IsEmpty())
	{
	    my_Material[White].add_piece(rmove.Capture().Type());
            switch(rmove.Capture().Type())
            {
               case Piece::Pawn:
  	          pawn_bits[White].set(target);
	          my_PFileCount[rmove.DestSquare().File()-1][White]++;
                  break;
               case Piece::Knight:
  	          knight_bits[White].set(target);
                  break;
               case Piece::Bishop:
  	          bishop_bits[White].set(target);
                  bishopsqueens[White].set(target);
                  break;
               case Piece::Rook:
  	          rook_bits[White].set(target);
                  rooksqueens[White].set(target);
                  break;
               case Piece::Queen:
  	          queen_bits[White].set(target);
                  bishopsqueens[White].set(target);
                  rooksqueens[White].set(target);
                  break;
               case Piece::King:
  	          king_bits[White].set(target);
                  my_KingPos[White] = target;
                  break;
               default:
                  break;
	    }
            occupied[White].set(target);
            occupiedR90[White].setR90(target);
            occupiedDa1[White].setDa1(target);
            occupiedDa8[White].setDa8(target);
	}
    }
    }
    my_EnPassantSq[my_Side] = rmove.Old_EnPassantSq(my_Side);
    my_EnPassantSq[OppositeColor(my_Side)] = rmove.Old_EnPassantSq(
    	OppositeColor(my_Side));
    my_CastleStatus[my_Side] = rmove.Old_CastleStatus(my_Side);
    my_CastleStatus[OppositeColor(my_Side)] = 
        rmove.Old_CastleStatus(OppositeColor(my_Side));
    my_CheckStatus = rmove.Old_CheckStatus();
    my_HashCode = rmove.Old_HashCode();
    m_pawn_hash = rmove.Old_PawnHash();
    move_count = rmove.Old_MoveCount();
    --rep_list_head;
    UNCOND_ASSERT(rep_list_head >= rep_list);
#ifdef _DEBUG
     // verify correct updating of bitmaps:
     Board copy = *this;
     copy.set_secondary_vars();
     ASSERT(pawn_bits[White] == copy.pawn_bits[White]);
     ASSERT(knight_bits[White] == copy.knight_bits[White]);
     ASSERT(bishop_bits[White] == copy.bishop_bits[White]);
     ASSERT(rook_bits[White] == copy.rook_bits[White]);
     ASSERT(queen_bits[White] == copy.queen_bits[White]);
     ASSERT(king_bits[White] == copy.king_bits[White]);
     ASSERT(bishopsqueens[White] == copy.bishopsqueens[White]);
     ASSERT(rooksqueens[White] == copy.rooksqueens[White]);
     ASSERT(occupied[White] == copy.occupied[White]);
     ASSERT(occupiedR90[White] == copy.occupiedR90[White]);
     ASSERT(occupiedDa1[White] == copy.occupiedDa1[White]);
     ASSERT(occupiedDa8[White] == copy.occupiedDa8[White]);
     
     ASSERT(pawn_bits[Black] == copy.pawn_bits[Black]);
     ASSERT(knight_bits[Black] == copy.knight_bits[Black]);
     ASSERT(bishop_bits[Black] == copy.bishop_bits[Black]);
     ASSERT(rook_bits[Black] == copy.rook_bits[Black]);
     ASSERT(queen_bits[Black] == copy.queen_bits[Black]);
     ASSERT(king_bits[Black] == copy.king_bits[Black]);
     ASSERT(bishopsqueens[Black] == copy.bishopsqueens[Black]);
     ASSERT(rooksqueens[Black] == copy.rooksqueens[Black]);
     ASSERT(occupied[Black] == copy.occupied[Black]);
     ASSERT(occupiedR90[Black] == copy.occupiedR90[Black]);
     ASSERT(occupiedDa1[Black] == copy.occupiedDa1[Black]);
     ASSERT(occupiedDa8[Black] == copy.occupiedDa8[Black]);
     for (int k = 0; k <8; ++k)
     {
        ASSERT(my_PFileCount[k][White] == copy.my_PFileCount[k][White]);
        ASSERT(my_PFileCount[k][Black] == copy.my_PFileCount[k][Black]);
     }
     ASSERT(my_Contents[my_KingPos[White]]==Piece(Piece::King,White));
     ASSERT(my_Contents[my_KingPos[Black]]==Piece(Piece::King,Black));
#endif     
}

BOOL Board::any_attacks(const Square &sq, const ColorType side) const
{
    if (sq.IsInvalid())
       return FALSE;

    Bitmap patcks(Bearing::pawn_attacks[sq][side]);
    patcks.and(pawn_bits[side]);
    if (!patcks.is_clear())
       return TRUE;

    Bitmap natcks(Bearing::knight_attacks[sq]);
    natcks.and(knight_bits[side]);
    if (!natcks.is_clear())
       return TRUE;

    Bitmap katcks(Bearing::king_attacks[sq]);
    katcks.and(king_bits[side]);
    if (!katcks.is_clear())
       return TRUE;

    // Find attacks on the rank
    const int r = sq.Rank(Black)-1;
    const int f = sq.File()-1;
    Bitmap occ = Bitmap::or(occupied[Black],occupied[White]);
    // shift the occupied bits so that the rank that sq occupies is
    // in bits 0-7.
#ifdef FAST_SHIFT
    byte atcks = (FAST_SHIFT_R(occ,r<<3)).byte_value();
    occ = Bitmap::shl_byte(Bearing::rank_attacks[atcks][f],r);
#else    
    byte atcks = Bitmap::shr(occ,(r<<3)).byte_value();
    occ = Bitmap::shl(Bitmap(Bearing::rank_attacks[atcks][f]),r<<3);
#endif    
    // See if any rooks or queens are there
    if (!Bitmap::and(occ,rooksqueens[side]).is_clear())
       return TRUE;
    
    Bitmap result;
    int x;
    // To find attacks on the file, use the 90-degree rotated bitmaps.
    // Same procedure as for ranks, above.
    occ = Bitmap::or(occupiedR90[Black],occupiedR90[White]);
    // shift the occupied bits so that the file that sq occupies are
    // in bits 0-7.
    int shift = (7-f)<<3;
#ifdef FAST_SHIFT
    atcks = Bitmap(FAST_SHIFT_R(occ,shift)).byte_value();
#else    
    atcks = Bitmap::shr(occ,shift).byte_value();
#endif    
    // find the pieces nearest to sq on the file, then
    // "unrotate" the result and shift it back up
    result = Bearing::unrot90[Bearing::rank_attacks[atcks][r]][7-f];
    // See if any rooks or queens are there
    if (!Bitmap::and(result,rooksqueens[side]).is_clear())
        return TRUE;

    // Now find attacks on the a1-h8 diagonal
    occ = Bitmap::or(occupiedDa1[Black],occupiedDa1[White]);
    // Shift so that the relevant bits are in bits 0-7 of the bitmap.
    // Note that we also need to mask out only those bits that are in
    // the diagonal occupied by 'sq'.
    shift = Bitmap::da1[sq]>>3;
    int val;
#ifdef FAST_SHIFT
    val = (FAST_SHIFT_R(occ,8*shift)).byte_value()
                & Bitmap::da1_mask[sq];
#else    
    occ = Bitmap::and(Bitmap::shr(occ,8*shift),Bitmap::da1_mask[sq]);
    val = occ.value();
#endif    
    // find the pieces nearest to sq on the diagonal    
    x = Bitmap::da1[sq] % 8;
    // Now we need to unrotate the bits
    result = Bearing::unrotda1[Bearing::rank_attacks[val][x]][shift];
    // See if any bishops or queens are there
    if (!Bitmap::and(result,bishopsqueens[side]).is_clear())
       return TRUE;

    // Now find attacks on the a8-h1 diagonal
    occ = Bitmap::or(occupiedDa8[Black],occupiedDa8[White]);
    // Shift so that the relevant bits are in bits 0-7 of the bitmap.
    // Note that we also need to mask out only those bits that are in
    // the diagonal occupied by 'sq'.
    shift = Bitmap::da8[sq]>>3;
#ifdef FAST_SHIFT
    val = (FAST_SHIFT_R(occ,8*shift)).byte_value()
             & Bitmap::da8_mask[sq];
#else    
    occ = Bitmap::and(Bitmap::shr(occ,8*shift),Bitmap::da8_mask[sq]);
    val = occ.value();
#endif    
    // find the pieces nearest to sq on the diagonal    
    x = Bitmap::da8[sq] % 8;
    // Now we need to unrotate the bits
    result = Bearing::unrotda8[Bearing::rank_attacks[val][x]][shift];
    // See if any bishops or queens are there
    if (!Bitmap::and(result,bishopsqueens[side]).is_clear())
       return TRUE;
    return FALSE;
}

BOOL Board::any_attacks(const Square &sq, const ColorType side,
 Bitmap &source) const
{
    if (sq.IsInvalid())
       return FALSE;

    source = Bearing::pawn_attacks[sq][side];
    source.and(pawn_bits[side]);
    if (!source.is_clear())
       return TRUE;

    source = Bearing::knight_attacks[sq];
    source.and(knight_bits[side]);
    if (!source.is_clear())
       return TRUE;

    source = Bearing::king_attacks[sq];
    source.and(king_bits[side]);
    if (!source.is_clear())
       return TRUE;

    // Find attacks on the rank
    const int r = sq.Rank(Black)-1;
    const int f = sq.File()-1;
    Bitmap occ(Bitmap::or(occupied[Black],occupied[White]));
    // shift the occupied bits so that the rank that sq occupies is
    // in bits 0-7.
#ifdef FAST_SHIFT
    byte atcks = (FAST_SHIFT_R(occ,r<<3)).byte_value();
    occ = Bitmap::shl_byte(Bearing::rank_attacks[atcks][f],r);
#else    
    byte atcks = Bitmap::shr(occ,(r<<3)).byte_value();
    occ = Bitmap::shl(Bitmap(Bearing::rank_attacks[atcks][f]),r<<3);
#endif    
    // See if any rooks or queens are there
    source = Bitmap::and(occ,rooksqueens[side]);
    if (!source.is_clear())
       return TRUE;
    
    Bitmap result;
    int x;
    // To find attacks on the file, use the 90-degree rotated bitmaps.
    // Same procedure as for ranks, above.
    occ = Bitmap::or(occupiedR90[Black],occupiedR90[White]);
    // shift the occupied bits so that the file that sq occupies are
    // in bits 0-7.
    int shift = (7-f)<<3;
#ifdef FAST_SHIFT
    atcks = Bitmap(FAST_SHIFT_R(occ,shift)).byte_value();
#else    
    atcks = Bitmap::shr(occ,shift).byte_value();
#endif    
    // find the pieces nearest to sq on the file, then
    // "unrotate" the result and shift it back up
    result = Bearing::unrot90[Bearing::rank_attacks[atcks][r]][7-f];
    // See if any rooks or queens are there
    source = Bitmap::and(result,rooksqueens[side]);
    if (!source.is_clear())
        return TRUE;

    // Now find attacks on the a1-h8 diagonal
    occ = Bitmap::or(occupiedDa1[Black],occupiedDa1[White]);
    // Shift so that the relevant bits are in bits 0-7 of the bitmap.
    // Note that we also need to mask out only those bits that are in
    // the diagonal occupied by 'sq'.
    shift = Bitmap::da1[sq]>>3;
#ifdef FAST_SHIFT
    int val = (FAST_SHIFT_R(occ,8*shift)).byte_value()
                & Bitmap::da1_mask[sq];
#else    
    occ = Bitmap::and(Bitmap::shr(occ,8*shift),Bitmap::da1_mask[sq]);
    int val = occ.value();
#endif    
    // find the pieces nearest to sq on the diagonal    
    x = Bitmap::da1[sq] % 8;
    // Now we need to unrotate the bits
    result = Bearing::unrotda1[Bearing::rank_attacks[val][x]][shift];
    // See if any bishops or queens are there
    source = Bitmap::and(result,bishopsqueens[side]);
    if (!source.is_clear())
       return TRUE;

    // Now find attacks on the a8-h1 diagonal
    occ = Bitmap::or(occupiedDa8[Black],occupiedDa8[White]);
    // Shift so that the relevant bits are in bits 0-7 of the bitmap.
    // Note that we also need to mask out only those bits that are in
    // the diagonal occupied by 'sq'.
    shift = Bitmap::da8[sq]>>3;
#ifdef FAST_SHIFT
    val = (FAST_SHIFT_R(occ,8*shift)).byte_value()
             & Bitmap::da8_mask[sq];
#else    
    occ = Bitmap::and(Bitmap::shr(occ,8*shift),Bitmap::da8_mask[sq]);
    val = occ.value();
#endif    
    // find the pieces nearest to sq on the diagonal    
    x = Bitmap::da8[sq] % 8;
    // Now we need to unrotate the bits
    result = Bearing::unrotda8[Bearing::rank_attacks[val][x]][shift];
    // See if any bishops or queens are there
    source = Bitmap::and(result,bishopsqueens[side]);
    if (!source.is_clear())
       return TRUE;
    return FALSE;
}

Bitmap Board::calc_attacks(const Square &sq, const ColorType side) const
{
    Bitmap retval;

    Bitmap patcks(Bearing::pawn_attacks[sq][side]);
    patcks.and(pawn_bits[side]);
    retval.or(patcks);

    Bitmap natcks(Bearing::knight_attacks[sq]);
    natcks.and(knight_bits[side]);
    retval.or(natcks);

    Bitmap katcks(Bearing::king_attacks[sq]);
    katcks.and(king_bits[side]);
    retval.or(katcks);

    const int r = sq.Rank(Black)-1;
    const int f = sq.File()-1;
    Bitmap occ = Bitmap::or(occupied[Black],occupied[White]);
    // shift the occupied bits so that the rank that sq occupies is
    // in bits 0-7.
#ifdef FAST_SHIFT
    byte atcks = (FAST_SHIFT_R(occ,r<<3)).byte_value();
    occ = Bitmap::shl_byte(Bearing::rank_attacks[atcks][f],r);
#else    
    byte atcks = Bitmap::shr(occ,(r<<3)).byte_value();
    occ = Bitmap::shl(Bitmap(Bearing::rank_attacks[atcks][f]),r<<3);
#endif    
    // See if any rooks or queens are there
    retval.or(Bitmap::and(occ,rooksqueens[side]));

    // To find attacks on the file, use the 90-degree rotated bitmaps.
    // Same procedure as for ranks, above.
    occ = Bitmap::or(occupiedR90[Black],occupiedR90[White]);
    // shift the occupied bits so that the file that sq occupies are
    // in bits 0-7.
    int shift = (7-f)<<3;
#ifdef FAST_SHIFT
    atcks = Bitmap(FAST_SHIFT_R(occ,shift)).byte_value();
#else    
    atcks = Bitmap::shr(occ,shift).byte_value();
#endif    
    // find the pieces nearest to sq on the file, then
    // "unrotate" the result and shift it back up.
    // See if any rooks or queens are there
    retval.or(Bitmap::and(Bearing::unrot90[Bearing::rank_attacks[atcks][r]][7-f],rooksqueens[side]));

    // Now find attacks on the a1-h8 diagonal
    occ = Bitmap::or(occupiedDa1[Black],occupiedDa1[White]);
    // Shift so that the relevant bits are in bits 0-7 of the bitmap.
    // Note that we also need to mask out only those bits that are in
    // the diagonal occupied by 'sq'.
    shift = Bitmap::da1[sq]>>3;
#ifdef FAST_SHIFT
    int val = (FAST_SHIFT_R(occ,8*shift)).byte_value()
         & Bitmap::da1_mask[sq];
#else    
    int val = Bitmap::and(Bitmap::shr(occ,8*shift),Bitmap::da1_mask[sq]).byte_value();
#endif    
    // find the pieces nearest to sq on the diagonal    
    int x = Bitmap::da1[sq] % 8;
    // Now we need to unrotate the bits
    // See if any bishops or queens are there
    retval.or(Bitmap::and(Bearing::unrotda1[Bearing::rank_attacks[val][x]][shift],bishopsqueens[side]));

    // Now find attacks on the a8-h1 diagonal
    occ = Bitmap::or(occupiedDa8[Black],occupiedDa8[White]);
    // Shift so that the relevant bits are in bits 0-7 of the bitmap.
    // Note that we also need to mask out only those bits that are in
    // the diagonal occupied by 'sq'.
    shift = Bitmap::da8[sq]>>3;
#ifdef FAST_SHIFT
    val = (FAST_SHIFT_R(occ,8*shift)).byte_value() &
            Bitmap::da8_mask[sq];
#else    
    val = Bitmap::and(Bitmap::shr(occ,8*shift),Bitmap::da8_mask[sq]).byte_value();
#endif    
    // find the pieces nearest to sq on the diagonal    
    x = Bitmap::da8[sq] % 8;
    // Now we need to unrotate the bits
    // See if any bishops or queens are there
    retval.or(Bitmap::and(Bearing::unrotda8[Bearing::rank_attacks[val][x]][shift],bishopsqueens[side]));

    return retval;
}

Bitmap Board::min_attacker(const Bitmap &atcks, const ColorType side)
const
{
    Bitmap retval;
    if (side == White)
    {
        retval = Bitmap::and(atcks,pawn_bits[White]);
        if (!retval.is_clear())
            return retval;
        retval = Bitmap::and(atcks,knight_bits[White]);
        if (!retval.is_clear())
            return retval;
        retval = Bitmap::and(atcks,bishop_bits[White]);
        if (!retval.is_clear())
            return retval;
        retval = Bitmap::and(atcks,rook_bits[White]);
        if (!retval.is_clear())
            return retval;
        retval = Bitmap::and(atcks,queen_bits[White]);
        if (!retval.is_clear())
            return retval;
        retval = Bitmap::and(atcks,king_bits[White]);
    }
    else
    {
        retval = Bitmap::and(atcks,pawn_bits[Black]);
        if (!retval.is_clear())
            return retval;
        retval = Bitmap::and(atcks,knight_bits[Black]);
        if (!retval.is_clear())
            return retval;
        retval = Bitmap::and(atcks,bishop_bits[Black]);
        if (!retval.is_clear())
            return retval;
        retval = Bitmap::and(atcks,rook_bits[Black]);
        if (!retval.is_clear())
            return retval;
        retval = Bitmap::and(atcks,queen_bits[Black]);
        if (!retval.is_clear())
            return retval;
        retval = Bitmap::and(atcks,king_bits[Black]);
    }    
    return retval;
}

Bitmap Board::pawn_attacks( const Square &sq, const ColorType side) const
{
    Bitmap patcks(Bearing::pawn_attacks[sq][side]);
    patcks.and(pawn_bits[side]);
    return patcks;
}

Bitmap Board::all_pawn_attacks( const ColorType side) const
{
    if (side == White)
    {
       Bitmap pawns1(pawn_bits[White]);
       Bitmap pawns2(pawns1);
       pawns1.shr(7);
       pawns1.andNot(Bitmap(0x0101010101010101));
       pawns2.shr(9);
       pawns2.andNot(Bitmap(0x8080808080808080));
       return Bitmap::or(pawns1,pawns2);
    }
    else
    {
       Bitmap pawns1(pawn_bits[Black]);
       Bitmap pawns2(pawns1);
       pawns1.shl(7);
       pawns1.andNot(Bitmap(0x8080808080808080));
       pawns2.shl(9);
       pawns2.andNot(Bitmap(0x0101010101010101));
       return Bitmap::or(pawns1,pawns2);
    }
}

int Board::bishop_mobility( const Square &sq ) const
{
    int mobl;
    // do the a1-h8 diagonal
    Bitmap occ = Bitmap::or(occupiedDa1[Black],occupiedDa1[White]);
    // Shift so that the relevant bits are in bits 0-7 of the bitmap.
    // Note that we also set bits that are not in the
    // diagonal occupied by 'sq'.
    int shift = Bitmap::da1[sq]>>3;
#ifdef FAST_SHIFT
    int val = (FAST_SHIFT_R(occ,(8*shift))).byte_value()
             | ~Bitmap::da1_mask[(int)sq];
#else    
    occ = Bitmap::orNot(Bitmap::shr(occ,8*shift),Bitmap(Bitmap::da1_mask[sq]));
    int val = occ.byte_value();
#endif 
    int x = Bitmap::da1[sq] % 8;
    mobl = Bearing::mobility[val & 0xff][x];

    // Now find attacks on the a8-h1 diagonal
    occ = Bitmap::or(occupiedDa8[Black],occupiedDa8[White]);
    // Shift so that the relevant bits are in bits 0-7 of the bitmap.
    // Note that we also need to mask out only those bits that are in
    // the diagonal occupied by 'sq'.
    shift = Bitmap::da8[sq]>>3;
#ifdef FAST_SHIFT
     val = (FAST_SHIFT_R(occ,(8*shift))).byte_value()
           | ~Bitmap::da8_mask[(int)sq];
#else    
    occ = Bitmap::orNot(Bitmap::shr(occ,8*shift),Bitmap(Bitmap::da8_mask[sq]));
    val = occ.byte_value();
#endif    
    // find the pieces nearest to sq on the diagonal    
    x = Bitmap::da8[sq] % 8;
    return mobl + Bearing::mobility[val & 0xff][x];
}

int Board::rook_mobility(const Square &sq) const
{
    // We consider only horizontal mobility (for now)
    int mobl;
    Bitmap occ = Bitmap::or(occupied[Black],occupied[White]);
    // Shift so that the relevant bits are in bits 0-7 of the bitmap.
    int r = sq.Rank(Black)-1;
    int shift = r<<3;
    int val = (FAST_SHIFT_R(occ,(shift))).byte_value();
    mobl = Bearing::mobility[val & 0xff][sq.File()-1];
    return mobl;
}

Board::CheckStatusType Board::CheckStatus() const
{
     if (my_CheckStatus != Unknown)
     {
        return my_CheckStatus;
     }
     else if (any_attacks(KingPos(Side()),OppositeSide()))
     {
        // This is a const function, but we cache its result
        Board &b = (Board&)*this;
        b.my_CheckStatus = InCheck;
     }
     else
     {
        // This is a const function, but we cache its result
        Board &b = (Board&)*this;
        b.my_CheckStatus = NotInCheck;
     }
     return my_CheckStatus;
}

static void set_bad( istream &i )
{
    i.clear( ios::badbit | i.rdstate() );
}

istream & operator >> (istream &i, Board &board)
{
    // read in a board position in Forsythe-Edwards (FEN) notation.
    static char buf[128];

    char *bp = buf;
    int c;
    int fields = 0; int count = 0;
    while (i.good() && fields < 4 && (c = i.get()) != '\n' && 
           ++count < 128)
    {
       *bp++ = c;
       if (isspace(c))
          fields++;
    }
    *bp = '\0';
    if (!i)
      return i;
    if (!ChessIO::read_fen(board, buf))
      set_bad(i);
    return i;
}

ostream & operator << (ostream &o, const Board &board)
{
    char buf[128];
    memset(buf,'\0',128);
    ChessIO::write_fen(board,buf,TRUE);
    o << buf;
    return o;
}

