/*----------------------------------------------------------------------
 | MACRO.H							940420
 |
 | Contains all macro-definitions.
 +----------------------------------------------------------------------*/


#include "type.h"
#include <limits.h>

/* SquareType macros */
#define	IsEmpty( square )	(!(square))
#define	IsEdge( square )	((square) & Edge)
#define	IsWhite( piece )	((piece) & White)
#define IsBlack( piece )	(!IsWhite( piece ))
#define IsColor( piece, color )	\
  (color == White ? IsWhite( piece) : IsBlack( piece ))
#define	IsPawn( piece )		((piece) & Pawn)
#define	IsKnight( piece )	((piece) & Knight)
#define	IsBishop( piece )	((piece) & Bishop)
#define	IsRook( piece )		((piece) & Rook)
#define	IsQueen( piece )	((piece) & Queen)
#define	IsKing( piece )		((piece) & King)
#define Color( piece )		((piece) & White)

/* MoveType macros */
#define IsCaptureMove( type )	((type) & Capture)
#define IsEnPassantMove( type )	((type) & EnPassant)
#define IsPromotionMove( type )	((type) & Promotion)
#define IsDoubleMove( type )	((type) & Double)
#define IsShortCastleMove( type )	((type) & ShortCastle)
#define IsLongCastleMove( type )	((type) & LongCastle)

#define WhiteSquare( file, rank )	((file-A+rank-1)%2)

#define	MovesDiagonal( piece )	((piece) & (Bishop | Queen))
#define	MovesStraight( piece )	((piece) & (Rook | Queen))

#define	Square( file, rank )	(((rank)+1)*BoardLength + (file))
#define Rank( square )		((square)/BoardLength - 1)
#define File( square )		((square)%BoardLength)
#define OnSeventhRank( color, square ) \
	(Rank( square ) == (IsWhite( color ) ? 7 : 2))

#define IsCheckingDir( direction )	      \
	(checkingPiece[ 0 ].dir==direction || \
		checkingPiece[ 1 ].dir==direction)

/* Castling */
#define ShortCastlingPossible()					\
	(toMove==White ? (castling[ nrGamePlies ] & WhiteShort)	\
		: (castling[ nrGamePlies ] & BlackShort))

#define LongCastlingPossible()					\
	(toMove==White ? (castling[ nrGamePlies ] & WhiteLong)	\
		: (castling[ nrGamePlies ] & BlackLong))

/*
   #define NoCastling()               \
   castling[ nrGamePlies ] &= \
   toMove==White ? (BlackLong | BlackShort) : (WhiteLong | WhiteShort)
 */

#define NoShortCastling()          \
	castling[ nrGamePlies ] &= \
		toMove==White ? ~WhiteShort : ~BlackShort

#define NoLongCastling()           \
	castling[ nrGamePlies ] &= \
		toMove==White ? ~WhiteLong : ~BlackLong

#define GetEvalTable( table, color, piece )				\
        if (IsPawn( piece )) {						\
          table = pawnEvalTable[ color ];				\
        } else if (IsKnight( piece )) {					\
          table = knightEvalTable[ color ];				\
        } else if (IsBishop( piece )) {					\
          table = bishopEvalTable[ color ];				\
        } else if (IsRook( piece )) {					\
          table = rookEvalTable[ color ];				\
        } else if (IsQueen( piece )) {					\
          table = queenEvalTable[ color ];				\
        } else if (IsKing( piece )) {					\
          table = kingEvalTable[ color ];				\
	} else {							\
	  printf( "ERROR: wrong piece %d in GetEvalTable\n", piece );	\
	}

#define GetHashTable( table, color, piece ) 				\
        if (IsPawn( piece )) {              				\
          table = pawnHashTable[ color ];   				\
        } else if (IsKnight( piece )) {     				\
          table = knightHashTable[ color ]; 				\
        } else if (IsBishop( piece )) {     				\
          table = bishopHashTable[ color ]; 				\
        } else if (IsRook( piece )) {       				\
          table = rookHashTable[ color ];   				\
        } else if (IsQueen( piece )) {      				\
          table = queenHashTable[ color ];  				\
        } else if (IsKing( piece )) {       				\
          table = kingHashTable[ color ];   				\
	} else {							\
	  printf( "ERROR: wrong piece %d in GetHashTable\n", piece );	\
	}

#define SPrintSquare( s, square ) \
	sprintf( s, "%c%d", File( square )-A+'a', Rank( square ) )

#define SPrintMove( s, move ) 			  	       	       \
	if (IsShortCastleMove( (move).type )) {                        \
	  sprintf( s, "  0-0  " );                                     \
	} else if (IsLongCastleMove( (move).type )) {                  \
	  sprintf( s, " 0-0-0 " );                                     \
	} else {                                                       \
	  sprintf( s, "%c%c%d%c%c%d%c",                                \
		IsPawn( board[ (move).from ] ) ? ' '		       \
			: pieceSymbol[ board[ (move).from ] | White ], \
		File( (move).from )-A+'a', Rank( (move).from ),        \
		(move).capturedPiece ? 'x' : '-',                      \
		File( (move).to )-A+'a', Rank( (move).to ),            \
		(move).promotionPiece                                  \
			? pieceSymbol[ (move).promotionPiece | White ] \
			: ' ' );				       \
	}

#ifdef Debug
#define PutMoveInTable( mFrom, mTo, mCapturedPiece, mPromotionPiece, \
			mType, mList, mNr ) 			     \
	{ 					 	   	     \
	  MoveType	*move; 			 	  	     \
	  move = &(mList[ mNr ]); 		          	     \
	  move->from = mFrom; 			 	  	     \
	  move->to = mTo;			       	 	     \
	  move->capturedPiece = mCapturedPiece;		  	     \
	  move->promotionPiece = mPromotionPiece;		     \
	  move->type = mType;				 	     \
	  ++mNr;						     \
	  if ((IsCaptureMove( mType ) && !(mCapturedPiece)) ||         \
		(!IsCaptureMove( mType ) && (mCapturedPiece))) {       \
	    printf( "ERROR: strange capture move (%d %d)\n",	     \
		mType, mCapturedPiece );               		     \
	  }                                                          \
	}
#else
#define PutMoveInTable( mFrom, mTo, mCapturedPiece, mPromotionPiece, \
			mType, mList, mNr ) 			     \
	{ 					 	   	     \
	  MoveType	*move; 			 	  	     \
	  move = &(mList[ mNr ]); 		          	     \
	  move->from = mFrom; 			 	  	     \
	  move->to = mTo;			       	 	     \
	  move->capturedPiece = mCapturedPiece;		  	     \
	  move->promotionPiece = mPromotionPiece;		     \
	  move->type = mType;				 	     \
	  ++mNr;						     \
	}
#endif

/* Allocation routines */
#define Malloc( ptr, type, nr )				    \
	{						    \
	  if (nr > 0) {					    \
	    ptr = (type *) malloc( (nr) * sizeof( type ) ); \
	    if (ptr == (type *) NULL) {			    \
	      printf( "ERROR: malloc van ptr mislukt\n" );  \
	      exit( 0 );				    \
	    }						    \
	  }						    \
	}

#define AllocateMoveList( list, nr )	\
	{				\
	  Malloc( list, MoveType, nr );	\
	  nrAllocMoveLists++;		\
	}

#define FreeMoveList( list )  \
	{		      \
	  free( list );	      \
	  nrAllocMoveLists--; \
	}

#define AllocatePathMove( path )       \
	{                              \
	  Malloc( path, PathType, 1 ); \
	  (path)->next = NULL;         \
	  nrAllocPathMoves++;          \
	}


#define FileExists( name )	(fopen( name, "r" )==NULL ? False : True)

#define SkipSpaces( ptr )	while (*(ptr)==' ') (ptr)++

/* time macro's */
#ifdef Gcc
#define StartTime()                                                   \
	{                                                             \
	  struct tms	mT;                                           \
	  times( &mT );                                               \
	  startingTime = (double) (mT.tms_utime + mT.tms_stime) / HZ; \
	}

#define StopTime( timeUsed )                                                \
	{                                                                   \
	  struct tms	mT;                                                 \
	  times( &mT );                                                     \
	  timeUsed = (double)(mT.tms_utime + mT.tms_stime)/HZ-startingTime; \
	}
#else
#define StartTime()                                   \
	{                                             \
	  struct timeb	mT;                           \
	  ftime( &mT );                               \
	  startingTime = mT.time + mT.millitm/1000.0; \
	}

#define StopTime( timeUsed )                                     \
	{                                                        \
	  struct timeb	mT;                                      \
	  ftime( &mT );                                          \
	  timeUsed = mT.time + mT.millitm/1000.0 - startingTime; \
	}
#endif

/* value macro's */
#define PrintValue( value )						      \
        (value) >= MateValue ? printf( " Mate%02d ", ((Mate-(value))+1)/2 ) : \
        (value) <= -MateValue ? printf( "-Mate%02d ", (Mate+value)/2 ) :      \
	printf( "%7.3f ", value*1.0/pieceValue[ WhitePawn ] )

/* hash macro's */
#define HashMakeZero( var ) \
	var[ 0 ] = var[ 1 ] = 0

#define HashXorIs( dest, src ) \
	{ dest[ 0 ] ^= src[ 0 ]; dest[ 1 ] ^= src[ 1 ]; }


#define SetRandomHash( var )                    \
	{                                       \
          while ((var[ 0 ] = drand48()*ULONG_MAX) == 0) ; \
          while ((var[ 1 ] = drand48()*ULONG_MAX) == 0) ; \
	}

#define HashIs( dest, src ) \
	{ dest[ 0 ] = src[ 0 ]; dest[ 1 ] = src[ 1 ]; }

#define HashEqual( hash1, hash2 ) \
	(hash1[ 0 ]==hash2[ 0 ] && hash1[ 1 ]==hash2[ 1 ])

#define EqualMoves( move1, move2 )                                       \
	((move1)->from == (move2)->from && (move1)->to == (move2)->to && \
	 (move1)->capturedPiece == (move2)->capturedPiece &&             \
	 (move1)->promotionPiece == (move2)->promotionPiece &&           \
	 (move1)->type == (move2)->type)

#define PrintSearchInfo( timeUsed, depth, value, path )	\
	{						\
	  StopTime( timeUsed );				\
	  if (depth == 0) {				\
	    printf( "  " );				\
	  } else {					\
	    printf( "%2d", depth );			\
	  }						\
	  printf( " %8.2fs ", timeUsed );		\
	  if (value == Infinity) {			\
	    printf( "    >>  " );			\
	  } else if (value == -Infinity) {		\
	    printf( "    <<  " );			\
	  } else {					\
	    PrintValue( value );			\
	  }						\
	  PrintPath( path );				\
	  printf( "\n" );				\
	  fflush( stdout );				\
	}

/* transposition table macro's */
#define GetPly( entry ) \
	((entry)->ply)

/* VOOR 1024K
   #define GetPly( entry ) \
   (((entry)->lockPlyDepthFlag & ((1L<<15)-1)) >> 7)
 */

#define GetDepth( entry ) \
	(((entry)->lockPlyDepthFlag & ((1L<<7)-1)) >> 2)

#define GetFlag( entry ) \
	((entry)->lockPlyDepthFlag & ((1L<<2)-1))

#define GetFrom( entry ) \
	((entry)->fromToPromTypeVal >> 26)

#define GetTo( entry ) \
	(((entry)->fromToPromTypeVal & ((1L<<26)-1)) >> 20)

#define GetPiece( entry ) \
	(((entry)->fromToPromTypeVal & ((1L<<20)-1)) >> 18)

#define GetType( entry ) \
	(((entry)->fromToPromTypeVal & ((1L<<18)-1)) >> 15)

#define GetValue( entry ) \
	(((entry)->fromToPromTypeVal & ((1L<<15)-1)) - Infinity)

#define ClearEntry( entry )	(entry)->lockPlyDepthFlag = NoEntry

#define SamePosition( entry )						\
	((entry)->lockRemainder==hashValue[ nrGamePlies ][ 1 ] &&	\
		((entry)->lockPlyDepthFlag>>nrTtBits) ==		\
		(hashValue[ nrGamePlies ][ 0 ]>>nrTtBits))

#define ComposeMove( entry, ttMove )					\
	{								\
	  (ttMove).from = unpackSquare[ GetFrom( entry ) ];		\
	  (ttMove).to   = unpackSquare[ GetTo( entry ) ];		\
	  (ttMove).type = unpackType[ GetType( entry ) ];		\
	  (ttMove).promotionPiece = IsPromotionMove( (ttMove).type ) ?	\
		unpackPiece[ GetPiece( entry ) ] | toMove : 0;		\
          if (IsCaptureMove( (ttMove).type )) {				\
	    if (IsEnPassantMove( (ttMove).type )) {			\
	      ttMove.capturedPiece = Pawn | !toMove;			\
	    } else {							\
	      ttMove.capturedPiece = board[ (ttMove).to ];		\
	    }								\
	  } else {							\
	    ttMove.capturedPiece = 0;					\
	  }								\
	}

#define FillEntry( mTtEntry, ttDepth, ttFlag, ttMove, ttValue, ttNodes )  \
	{								  \
	  Signed1 mDepth;						  \
	  if (ttDepth > 31) {						  \
	    mDepth = 31;						  \
	  } else {							  \
	    mDepth = ttDepth;						  \
	  }								  \
	    /* lock is 49 bits -> ttBits >= 15 */			  \
	    /* ply is 8 bits: max. = 255 */				  \
	    /* depth is 5 bits: max = 31 */				  \
	    /* flag is 2 bits: Lower, Upper, Valid and NoEntry */	  \
	  mTtEntry->lockPlyDepthFlag =					  \
		(hashValue[ nrGamePlies ][ 0 ] & ~((1L<<nrTtBits)-1)) |	  \
		(mDepth)<<2 | (ttFlag);					  \
/*\
		startPly<<7 | (mDepth)<<2 | (ttFlag);			  \
*/\
	  mTtEntry->lockRemainder = hashValue[ nrGamePlies ][ 1 ];	  \
	    /* promotionPiece is 2 bits */				  \
	    /* type is 3 bits */					  \
	    /* value is 15 bits: -16384..16384 */			  \
	  mTtEntry->fromToPromTypeVal = 				  \
		(Unsigned4)(packSquare[ (ttMove).from ])<<26 | 		  \
		(Unsigned4)(packSquare[ (ttMove).to ])<<20 |		  \
		(Unsigned4)(packPiece[ (ttMove).promotionPiece ])<<18 |	  \
		(Unsigned4)(packType[ (ttMove).type ])<<15 | (ttValue+Infinity);	  \
	  mTtEntry->nrNodes = ttNodes;					  \
          mTtEntry->ply = startPly;					  \
	}

#define PutMoveInTransTable( ttMove, ttDepth, ttValue, ttFlag, ttNodes )     \
	{								     \
	  Unsigned4	mIndex;						     \
	  TtEntry	*mTtEntry;					     \
	  ValueType	realValue;					     \
	  if (useTransTable) {						     \
	    nrWrites++;							     \
	    if (ttValue >= MateValue) {					     \
	      realValue = ttValue+nrGamePlies-startPly;			     \
            } else if (ttValue <= -MateValue) {				     \
	      realValue = ttValue-nrGamePlies+startPly;			     \
            } else {							     \
              realValue = ttValue;					     \
            }								     \
	    mIndex = hashValue[ nrGamePlies ][ 0 ] & ((1L<<nrTtBits)-1);     \
	    mTtEntry = &transTable[ mIndex ];				     \
	    if (GetFlag( mTtEntry )==NoEntry || SamePosition( mTtEntry )) {  \
              FillEntry( mTtEntry, ttDepth, ttFlag, ttMove,		     \
		ttValue, ttNodes );					     \
	    } else if (useTwoLevelTable) {				     \
	      if (timeStamp &&						     \
			GetPly( mTtEntry )+keepPly<startPly) { /* old */     \
		transTable[ mIndex+(1L<<nrTtBits) ] = transTable[ mIndex ];  \
		FillEntry( mTtEntry, ttDepth, ttFlag, ttMove,		     \
			ttValue, ttNodes );				     \
	      } else {							     \
		++nrCollisions;						     \
		if ((keepMethod==Deep && ttDepth>=GetDepth( mTtEntry )) ||   \
		  ((keepMethod==Big1 || keepMethod==BigAll) &&		     \
		  ttNodes>=mTtEntry->nrNodes)) {			     \
		    transTable[ mIndex+(1L<<nrTtBits) ] = transTable[ mIndex ];\
		    FillEntry( mTtEntry, ttDepth, ttFlag, ttMove,	     \
			  ttValue, ttNodes );				     \
		} else {						     \
		  mIndex += 1L<<nrTtBits;				     \
		  mTtEntry = &transTable[ mIndex ];			     \
		  FillEntry( mTtEntry, ttDepth, ttFlag, ttMove,		     \
			  ttValue, ttNodes );				     \
		}							     \
	      }								     \
	    } else if (timeStamp &&					     \
			GetPly( mTtEntry )+keepPly<startPly) { /* old */     \
	      FillEntry( mTtEntry, ttDepth, ttFlag, ttMove,		     \
		ttValue, ttNodes );					     \
            } else {							     \
	      ++nrCollisions;						     \
	      if ((useFlag && ttFlag==Valid && GetFlag( mTtEntry )!=Valid) ||\
		 keepMethod==New ||					     \
		(keepMethod==Deep && ttDepth>=GetDepth( mTtEntry )) ||       \
		((keepMethod==Big1 || keepMethod==BigAll) &&		     \
		ttNodes>=mTtEntry->nrNodes)) {				     \
		FillEntry( mTtEntry, ttDepth, ttFlag, ttMove,		     \
			ttValue, ttNodes );				     \
	      }								     \
	    }								     \
	  } /* if useTransTable */					     \
	}

#define GetMoveFromTransTable( ttMove, ttDepth, ttValue, ttFlag, ttNodes ) \
	{								   \
	  Unsigned4	mIndex;						   \
	  TtEntry	*mTtEntry;					   \
	  if (!useTransTable) {						   \
	    ttDepth = -1;						   \
	  } else {							   \
	    nrReads++;							   \
	    mIndex = hashValue[ nrGamePlies ][ 0 ] & ((1L<<nrTtBits)-1);   \
	    mTtEntry = &transTable[ mIndex ];				   \
	    if (GetFlag( mTtEntry ) != NoEntry) {			   \
	      if (SamePosition( mTtEntry )) {				   \
		nrHits++;						   \
		ComposeMove( mTtEntry, ttMove );			   \
		ttFlag = (Unsigned1) GetFlag( mTtEntry );		   \
		ttDepth = (Signed1) GetDepth( mTtEntry );		   \
		ttNodes = mTtEntry->nrNodes;				   \
		ttValue = (ValueType) GetValue( mTtEntry );		   \
		if (ttValue >= MateValue) {				   \
		  ttValue -= nrGamePlies-startPly;			   \
		} else if (ttValue <= -MateValue) {			   \
		  ttValue += nrGamePlies-startPly;			   \
		}							   \
              } else if (useTwoLevelTable) {                               \
		nrReads++;						   \
		mIndex += 1L<<nrTtBits;                                    \
                mTtEntry = &transTable[ mIndex ];                          \
                if (GetFlag( mTtEntry ) != NoEntry) {                      \
                  if (SamePosition( mTtEntry )) {                          \
                    nrHits++;                                              \
                    ComposeMove( mTtEntry, ttMove );                       \
                    ttFlag = (Unsigned1) GetFlag( mTtEntry );		   \
                    ttDepth = (Signed1) GetDepth( mTtEntry );		   \
		    ttNodes = mTtEntry->nrNodes;			   \
                    ttValue = (ValueType) GetValue( mTtEntry );            \
                    if (ttValue >= MateValue) {                            \
                      ttValue -= nrGamePlies-startPly;                     \
                    } else if (ttValue <= -MateValue) {                    \
                      ttValue += nrGamePlies-startPly;                     \
                    }                                                      \
                  } else {                                                 \
                    ttDepth = -1;                                          \
                  }                                                        \
                } else {                                                   \
                  ttDepth = -1;                                            \
                }                                                          \
              } else {                                                     \
                ttDepth = -1;                                              \
              }                                                            \
	    } else {							   \
	      ttDepth = -1;						   \
	    }								   \
	  }								   \
	}

#define IsIllegal( move )						\
	(IsEmpty( board[ (move).from ] ) ||				\
	!IsColor( board[ (move).from ], toMove ) ||			\
	((move).capturedPiece==0 && !IsEmpty( board[ (move).to ] )) ||	\
	((move).capturedPiece!=0 && IsEmpty( board[ (move).to ] ) &&	\
		!IsEnPassantMove( (move).type )) ||			\
	(!IsEmpty( board[ (move).to ] ) && IsColor( board[ (move).to ], toMove )))
