//
// Slow Chess move generation functions
// by Jon Kreuzer
//
const int KnightMoves[8] = { -21, -19, -12, -8, 8, 12, 19, 21};
const int KingMoves[8] = {1, 9, 10, 11, -1, -9, -10, -11};
const int KingMoves2[8] = { -11, -10, -9, -1, 1, 9, 10, 11};
const int QueenMoves[8] = {1, -1, 9, -9, -10, 10, -11, 11};
const int RookMoves[4] = {1, -1,  -10, 10};
const int BishopMoves[4] = { 9, -9, -11, 11};

int inline normAttackedByWhite ( unsigned char *pSq  ) 
{
	if (*(pSq + 9)  == WPAWN) return 1;
	if (*(pSq + 11) == WPAWN) return 1;

	for (int i = 0; i < 8; i++) if (*(pSq + KnightMoves[i]) == WKNIGHT) return 1;

	unsigned char *pSlide = pSq + 1; 
	while (*pSlide == EMPTY) pSlide+=1;
	if (*pSlide == WROOK || *pSlide == WQUEEN) return 1;

	pSlide = pSq - 1; 
	while (*pSlide == EMPTY) pSlide-=1;
	if (*pSlide == WROOK || *pSlide == WQUEEN) return 1;

    pSlide = pSq + 10;
	while (*pSlide == EMPTY) pSlide+=10;
	if (*pSlide == WROOK || *pSlide == WQUEEN) return 1;

	pSlide = pSq - 10;
	while (*pSlide == EMPTY) pSlide-=10;
	if (*pSlide == WROOK || *pSlide == WQUEEN) return 1;

	pSlide = pSq + 9;
	while (*pSlide == EMPTY) pSlide+=9;
	if (*pSlide == WBISHOP || *pSlide == WQUEEN) return 1;

	pSlide = pSq - 9;
	while (*pSlide == EMPTY) pSlide-=9;
	if (*pSlide == WBISHOP || *pSlide == WQUEEN) return 1;

	pSlide = pSq + 11; 
	while (*pSlide == EMPTY) pSlide+=11;
	if (*pSlide == WBISHOP || *pSlide == WQUEEN) return 1;

	pSlide = pSq - 11; 
	while (*pSlide == EMPTY) pSlide-=11;
	if (*pSlide == WBISHOP || *pSlide == WQUEEN) return 1;

	return 0;
}

int inline normAttackedByBlack( unsigned char *pSq  ) 
{
	if (*(pSq - 9)  == BPAWN) return 1;
	if (*(pSq - 11) == BPAWN) return 1;

	for (int i = 0; i < 8; i++) if (*(pSq + KnightMoves[i]) == BKNIGHT) return 1;

	unsigned char *pSlide = pSq + 1; 
	while (*pSlide == EMPTY) pSlide+=1;
	if (*pSlide == BROOK || *pSlide == BQUEEN) return 1;

	pSlide = pSq - 1; 
	while (*pSlide == EMPTY) pSlide-=1;
	if (*pSlide == BROOK || *pSlide == BQUEEN) return 1;

    pSlide = pSq + 10;
	while (*pSlide == EMPTY) pSlide+=10;
	if (*pSlide == BROOK || *pSlide == BQUEEN) return 1;

	pSlide = pSq - 10;
	while (*pSlide == EMPTY) pSlide-=10;
	if (*pSlide == BROOK || *pSlide == BQUEEN) return 1;

	pSlide = pSq + 9;
	while (*pSlide == EMPTY) pSlide+=9;
	if (*pSlide == BBISHOP || *pSlide == BQUEEN) return 1;

	pSlide = pSq - 9;
	while (*pSlide == EMPTY) pSlide-=9;
	if (*pSlide == BBISHOP || *pSlide == BQUEEN) return 1;

	pSlide = pSq + 11; 
	while (*pSlide == EMPTY) pSlide+=11;
	if (*pSlide == BBISHOP || *pSlide == BQUEEN) return 1;

	pSlide = pSq - 11; 
	while (*pSlide == EMPTY) pSlide-=11;
	if (*pSlide == BBISHOP || *pSlide == BQUEEN) return 1;

	return 0;
}
// ----------------
// Returns 1 if a the piece on square is attacked by the opposite color
// ----------------
int IsAttacked (SBoard &Board, int square, int color)
    {
    if (color == WHITE) 
		{
		if (KingAttacks[ 128 + Board.BPiece[ 15 ] - square ] ) return 1;
 		return normAttackedByBlack (&Board.Sq[square]);
		}
    else 
		{
		if (KingAttacks[ 128 + Board.WPiece[ 15 ] - square ] ) return 1;
 		return normAttackedByWhite (&Board.Sq[square]);
		}
    }

// -----------------
// Add a Move to Movelist
// -----------------
void inline AddMove ( Movestruct &Movelist,  const int &dst, const int &type)
	{
    Movelist.Moves[ (++Movelist.nummoves) + 50 ] = (dst<<7) + type;
    }

void inline AddAtkMove ( Movestruct &Movelist,  const int &dst, const int &type)
	{
    Movelist.Moves[ (++Movelist.numAttackmoves) ] = (dst<<7) + type;
    }

// -----------------
// Add All Moves possible for nDirec
// -----------------
void inline SlideDirecW (  Movestruct &Moves, unsigned char *pSq, const int x, const int nDirec, const int nMove)
{
	int nSlide = x + nDirec;
	while (pSq [ nSlide ] == EMPTY) 
		{AddMove (Moves, nSlide, nMove ); nSlide+= nDirec;}
	if (pSq [ nSlide ] > 8) AddAtkMove (Moves, nSlide, nMove ); 
}

void inline SlideDirecB (  Movestruct &Moves, unsigned char *pSq, const int x, const int nDirec, const int nMove)
{
	int nSlide = x + nDirec;
	while (pSq [ nSlide ] == EMPTY) 
		{AddMove (Moves, nSlide, nMove ); nSlide+= nDirec;}
	if (pSq [ nSlide ] < 8) AddAtkMove (Moves, nSlide, nMove ); 
}
// -----------------
// Add Attack Moves for nDirec
// -----------------
void inline SlideDirecAtkW (  Movestruct &Moves, const unsigned char *pSq, const int x, const int nDirec, const int nMove)
{
	int nSlide = x + nDirec;
	while (pSq [ nSlide ] == EMPTY) nSlide+= nDirec;
	if (pSq [ nSlide ] > 8) AddAtkMove (Moves, nSlide, nMove ); 
}

void inline SlideDirecAtkB (  Movestruct &Moves, const unsigned char *pSq, const int x, const int nDirec, const int nMove)
{
	int nSlide = x + nDirec;
	while (pSq [ nSlide ] == EMPTY) nSlide+= nDirec;
	if (pSq [ nSlide ] < 8) AddAtkMove (Moves, nSlide, nMove ); 
}
//------------------
// Add Move for nSq if possible
//------------------
void inline AddSquareB ( const int nSq, Movestruct &Moves,  const unsigned char *pSq,  const int nMove)
{
	if ( pSq[ nSq ] == EMPTY) AddMove    (Moves, nSq, nMove );
	else if ( pSq[ nSq ] < 8) AddAtkMove (Moves, nSq, nMove );
}

void inline AddSquareW ( const int nSq, Movestruct &Moves,  const unsigned char *pSq,   const int nMove)
{
	if ( pSq[ nSq ] == EMPTY) AddMove    (Moves, nSq, nMove );
	else if ( pSq[ nSq ] > 8) AddAtkMove (Moves, nSq, nMove );
}

// ----------------
// Find ROOK Moves
// ----------------
void FindMovesBlackRook( Movestruct &Moves, unsigned char *pSq, int x, int nMove)
{
	for (int i = 0; i < 4; i++) SlideDirecB ( Moves, pSq, x, RookMoves[i], nMove);
}

void FindMovesWhiteRook( Movestruct &Moves, unsigned char *pSq, int x, int nMove)
{
	for (int i = 0; i < 4; i++) SlideDirecW ( Moves, pSq, x, RookMoves[i], nMove);
}

// ----------------
// Find BISHOP Moves
// ----------------
void inline FindMovesBlackBishop( Movestruct &Moves, unsigned char *pSq, int x, int nMove)
{
	for (int i = 0; i < 4; i++) SlideDirecB ( Moves, pSq, x, BishopMoves[i], nMove);
}

void inline FindMovesWhiteBishop( Movestruct &Moves, unsigned char *pSq, int x, int nMove)
{
	for (int i = 0; i < 4; i++) SlideDirecW ( Moves, pSq, x, BishopMoves[i], nMove);
}

// ----------------
// Find QUEEN Moves
// ----------------
void FindMovesBlackQueen( Movestruct &Moves, unsigned char *pSq, int x, int nMove)
{
	for (int i = 0; i < 8; i++) SlideDirecB ( Moves, pSq, x, QueenMoves[i], nMove);
}

void FindMovesWhiteQueen( Movestruct &Moves, unsigned char *pSq, int x, int nMove)
{
	for (int i = 0; i < 8; i++) SlideDirecW ( Moves, pSq, x, QueenMoves[i], nMove);
}

// ----------------
// Find KING Moves
// ----------------
void inline FindMovesBlackKing( Movestruct &Moves, unsigned char *pSq, int x, int nMove)
{
	for (int i = 0; i < 8; i++) AddSquareB ( x + KingMoves[i], Moves, pSq, nMove);
}

void inline FindMovesWhiteKing ( Movestruct &Moves, unsigned char *pSq, int x, int nMove)
{
	for (int i = 0; i < 8; i++) AddSquareW ( x + KingMoves[i], Moves, pSq, nMove);
}

// ----------------
// Find KNIGHT Moves
// ----------------
void inline FindMovesBlackKnight( Movestruct &Moves, unsigned char *pSq, int x, int nMove)
{
	for (int i = 0; i < 8; i++) AddSquareB ( x + KnightMoves[i], Moves, pSq, nMove);
}

void inline FindMovesWhiteKnight ( Movestruct &Moves, unsigned char *pSq, int x, int nMove)
{
	for (int i = 0; i < 8; i++) AddSquareW ( x + KnightMoves[i], Moves, pSq, nMove);
}

// ----------------
// Find LEGAL KING Moves
// ----------------
void inline AddIfLegalB ( Movestruct &Moves, SBoard &Board, const int &nSrc, const int &nDst, const int &piece, const int color, const int nMove )
{
if (Board.Sq [ nDst ] == EMPTY)
	{
	Board.Sq [ nSrc ] = EMPTY;
	if ( IsAttacked ( Board, nDst, color) == 0 ) AddMove (Moves, nDst, nMove);		
	Board.Sq [ nSrc ] = piece;
	}
else if (Board.Sq [ nDst ] < 8)
	{
	Board.Sq [ nSrc ] = EMPTY;
	if ( IsAttacked ( Board, nDst, color) == 0 ) AddAtkMove (Moves, nDst, nMove);		
	Board.Sq [ nSrc ] = piece;
	}
}

void inline AddIfLegalW ( Movestruct &Moves, SBoard &Board, const int &nSrc, const int &nDst, const int piece, const int color, const int nMove )
{
if (Board.Sq [ nDst ] == EMPTY)
	{
	Board.Sq [ nSrc ] = EMPTY;
	if ( IsAttacked ( Board, nDst, color) == 0 ) AddMove (Moves, nDst, nMove);		
	Board.Sq [ nSrc ] = piece;
	}
else if (Board.Sq [ nDst ] > 8)
	{
	Board.Sq [ nSrc ] = EMPTY;
	if ( IsAttacked ( Board, nDst, color) == 0 ) AddAtkMove (Moves, nDst, nMove);	
	Board.Sq [ nSrc ] = piece;
	}
}

void inline FindLegalMovesBlackKing( Movestruct &Moves, SBoard &Board, int x, int nMove)
{
	for (int i = 0; i < 8; i++) AddIfLegalB    (Moves, Board, x, x+KingMoves[i],  BKING, BLACK, nMove );
}

void inline FindLegalMovesWhiteKing ( Movestruct &Moves, SBoard &Board, int x, int nMove)
{
	for (int i = 0; i < 8; i++) AddIfLegalW   (Moves, Board, x, x+KingMoves[i],  WKING, WHITE, nMove );
}

// ----------------
// Find PAWN Moves
// ----------------   
void inline FindMovesWhitePawn( Movestruct &Moves, unsigned char *pSq, const int x, const int nMove, const int nSqEnPassant)
{
 if (pSq [ x-10 ] == EMPTY) 
	{
	 if (SQRANK[x] == 7) AddAtkMove(Moves, x - 10, nMove ); 
	 else  {AddMove (Moves, x - 10, nMove );
		    if (x > 81 && pSq [x - 20] == EMPTY) AddMove (Moves, x - 20, nMove );
			}
	}
 if (pSq [ x-11 ] >8 || (x-11) == nSqEnPassant)  AddAtkMove (Moves, x-11, nMove );
 if (pSq [ x-9 ]  >8 || (x-9)  == nSqEnPassant)  AddAtkMove (Moves, x-9, nMove );
}

void inline FindMovesBlackPawn( Movestruct &Moves, unsigned char *pSq, const int x, const int nMove, const int nSqEnPassant)
{
 if (pSq [ x+10 ] == EMPTY) 
	{
	 if (SQRANK[x] == 2) AddAtkMove (Moves, x+10, nMove ); 
	 else	{AddMove (Moves, x+10, nMove );
			 if (x < 42 && pSq [x+20] == EMPTY) AddMove (Moves, x+20, nMove );
			}
	}
 if ((pSq [ x+11 ] < 8 && pSq [ x+11 ] > 0) || (x+11) == nSqEnPassant)  AddAtkMove (Moves, x+11, nMove );
 if ((pSq [ x+9 ] < 8  && pSq [ x+9 ] > 0)  || (x+9)  == nSqEnPassant)  AddAtkMove (Moves, x+9, nMove );
}

// ----------------
// Find KNIGHT Attack Moves
// ----------------
void inline FindAMovesBlackKnight( Movestruct &Moves, const unsigned char *pSq, const int x, const int nMove)
{
	for (int i = 0; i < 8; i++)
		if ( pSq[ x + KnightMoves[i] ] < 8 && pSq[ x + KnightMoves[i]  ] > 0) AddAtkMove (Moves, x + KnightMoves[i], nMove );
}

void inline FindAMovesWhiteKnight ( Movestruct &Moves, const unsigned char *pSq, const int x, const int nMove)
{
	for (int i = 0; i < 8; i++)
		if ( pSq[ x + KnightMoves[i] ] > 8) AddAtkMove (Moves, x + KnightMoves[i], nMove );
}

// ----------------
// Find KING Attack Moves
// ----------------
void inline FindAMovesBlackKing ( Movestruct &Moves, const unsigned char *pSq, const int x, const int nMove)
{
	for (int i = 0; i < 8; i++)
		if ( pSq[ x + KingMoves[i] ] < 8 && pSq[ x + KingMoves[i]  ] > 0) AddAtkMove (Moves, x + KingMoves[i], nMove );
}

void inline FindAMovesWhiteKing ( Movestruct &Moves, const unsigned char *pSq, const int x, const int nMove)
{
	for (int i = 0; i < 8; i++)
		if ( pSq[ x + KingMoves[i] ] > 8) AddAtkMove (Moves, x + KingMoves[i], nMove );
}

// ----------------
// Find PAWN Attack Moves ( & Promotions )
// ----------------   
void inline FindAMovesWhitePawn( Movestruct &Moves, const unsigned char *pSq, const int x, const int nMove, const int nSqEnPassant)
{
 if (pSq [ x-11 ] >8 || (x-11) == nSqEnPassant)  AddAtkMove (Moves, x-11, nMove );
 if (pSq [ x-9 ]  >8 || (x-9)  == nSqEnPassant)  AddAtkMove (Moves, x-9, nMove );
 if ( SQRANK [ x ] == 7 && pSq[ x - 10] == EMPTY) AddAtkMove (Moves, x-10, nMove);
}

void inline FindAMovesBlackPawn( Movestruct &Moves, const unsigned char *pSq, const int x, const int nMove, const int nSqEnPassant)
{
 if ( (pSq [ x+11 ] < 8 && pSq [ x+11 ] > 0) || (x+11) == nSqEnPassant)  AddAtkMove (Moves, x+11, nMove );
 if ( (pSq [ x+9 ]  < 8 && pSq [ x+9  ] > 0) || (x+9)  == nSqEnPassant)  AddAtkMove (Moves, x+9, nMove );
 if ( SQRANK [ x ] == 2 && pSq[ x + 10] == EMPTY) AddAtkMove (Moves, x+10, nMove);
}

// ----------------
// Find ROOK Attack Moves
// ----------------
void inline FindAMovesBlackRook( Movestruct &Moves, const unsigned char *pSq, const int x, const int nMove)
{
	for (int i = 0; i < 4; i++) SlideDirecAtkB ( Moves, pSq, x, RookMoves[i], nMove);
}

void inline FindAMovesWhiteRook( Movestruct &Moves, const unsigned char *pSq, const int x, const int nMove)
{
	for (int i = 0; i < 4; i++) SlideDirecAtkW ( Moves, pSq, x, RookMoves[i], nMove);
}

// ----------------
// Find BISHOP Attack Moves
// ----------------
void FindAMovesBlackBishop( Movestruct &Moves, const unsigned char *pSq, const int x, const int nMove)
{
	for (int i = 0; i < 4; i++) SlideDirecAtkB ( Moves, pSq, x, BishopMoves[i], nMove);
}

void FindAMovesWhiteBishop( Movestruct &Moves, const unsigned char *pSq, const int x, const int nMove)
{
	for (int i = 0; i < 4; i++) SlideDirecAtkW ( Moves, pSq, x, BishopMoves[i], nMove);
}

// ----------------
// Find QUEEN Attack Moves
// ----------------
void FindAMovesBlackQueen( Movestruct &Moves, const unsigned char *pSq, const int x, const int nMove)
{
	for (int i = 0; i < 8; i++) SlideDirecAtkB ( Moves, pSq, x, QueenMoves[i], nMove);
}

void FindAMovesWhiteQueen( Movestruct &Moves, const unsigned char *pSq, const int x, const int nMove)
{
	for (int i = 0; i < 8; i++) SlideDirecAtkW ( Moves, pSq, x, QueenMoves[i], nMove);
}

// -------------------------
//
// Generate Legal Responses to a Check
//
// -------------------------
void inline AddMoveW (SBoard &Board, const int src, const int nDstSq, Movestruct &Moves, const int bAttack)
	{
	register int nPiece;
	for (nPiece = 0; nPiece < 14; nPiece++) if (Board.WPiece[ nPiece ] == src) break;
	int MMove = (nPiece<<16) + (nDstSq<<7) + src;
	if ( bAttack == 2 || !DiscoveredCheck (WHITE, Board, MMove) ) 
		{
		if (bAttack) Moves.Moves[ ++Moves.numAttackmoves ] = MMove;
			else Moves.Moves[ (++Moves.nummoves)+50  ] = MMove;
		}
	}

void inline TestAddDirecW (  SBoard &Board, Movestruct &Moves, const int sq, const int nDirec, const int piece1, const int piece2, const int bAttack )
{
	int tempSq = sq + nDirec;
	while (Board.Sq [tempSq] == EMPTY)	tempSq+= nDirec;
	if (Board.Sq [ tempSq ] == piece1 || Board.Sq [ tempSq ] == piece2) {AddMoveW (Board,  tempSq, sq, Moves, bAttack );}
}
//
// Find the moves
//
void inline FindWhiteMovesToSq ( Movestruct &Moves, int sq, SBoard &Board, int bAtk)
{
if (bAtk)
	{
	if (Board.Sq [ sq+11 ] == WPAWN) {AddMoveW (Board, sq+11, (sq+(3<<7)), Moves, 1 ); }
	if (Board.Sq [ sq+9  ] == WPAWN) {AddMoveW (Board, sq+9,  (sq+(3<<7)), Moves, 1 ); }
	if (Board.EnPassant == (sq-10))
		{
		if (Board.Sq [ sq-1 ] == WPAWN) {AddMoveW (Board, sq-1, sq-10, Moves, 1 ); }
		if (Board.Sq [ sq+1 ] == WPAWN) {AddMoveW (Board, sq+1, sq-10, Moves, 1 ); }
		}
	}
else
	{
	if (Board.Sq [ sq+10 ] == WPAWN) {AddMoveW (Board, sq+10, (sq+(3<<7)), Moves, 0 ); }
	if (SQRANK[sq] == 4 && Board.Sq [ sq+20 ] == WPAWN && Board.Sq [ sq+10 ] == EMPTY) {AddMoveW (Board, sq+20, (sq+(3<<7)), Moves, 0 ); }
	}

int i;
for (i = 0; i < 8; i++) 
	if (Board.Sq [ sq + KnightMoves[i] ] == WKNIGHT ) AddMoveW (Board, sq + KnightMoves[i] , sq, Moves, bAtk );

for (i = 0; i < 4; i++)
	TestAddDirecW ( Board,  Moves, sq, BishopMoves[i], WBISHOP, WQUEEN, bAtk);

for (i = 0; i < 4; i++)
	TestAddDirecW ( Board,  Moves, sq, RookMoves[i],   WROOK, WQUEEN, bAtk);
}
//-------------
// Now for BLACK
//-------------
void inline AddMoveB (SBoard &Board, const int src, const int nDstSq, Movestruct &Moves, const int bAttack)
	{
	register int nPiece;
	for (nPiece = 0; nPiece < 14; nPiece++) if (Board.BPiece[ nPiece ] == src) break;
	int MMove = (nPiece<<16) + (nDstSq<<7) + src;
	if ( bAttack == 2 || !DiscoveredCheck (BLACK, Board, MMove) ) 
		{
		if (bAttack) Moves.Moves[ ++Moves.numAttackmoves ] = MMove;
			else Moves.Moves[ (++Moves.nummoves)+50  ] = MMove;
		}
	}

void inline TestAddDirecB (  SBoard &Board, Movestruct &Moves, const int sq, const int nDirec, const int piece1, const int piece2, const int bAttack )
{
	int tempSq = sq + nDirec;
	while (Board.Sq [tempSq] == EMPTY)	tempSq+= nDirec;
	if (Board.Sq [ tempSq ] == piece1 || Board.Sq [ tempSq ] == piece2) {AddMoveB (Board,  tempSq, sq, Moves, bAttack );}
}

void inline FindBlackMovesToSq ( Movestruct &Moves, int sq, SBoard &Board, int bAtk)
{
if (bAtk)
	{
	if (Board.Sq [ sq-11 ] == BPAWN) {AddMoveB (Board, sq-11, (sq+(3<<7)), Moves, 1 ); }
	if (Board.Sq [ sq-9  ] == BPAWN) {AddMoveB (Board, sq-9,  (sq+(3<<7)), Moves, 1 ); }
	if (Board.EnPassant == (sq+10))
		{
		if (Board.Sq [ sq-1 ] == BPAWN) {AddMoveB (Board, sq-1, sq+10, Moves, 1 ); }
		if (Board.Sq [ sq+1 ] == BPAWN) {AddMoveB (Board, sq+1, sq+10, Moves, 1 ); }
		}
	}
else
	{
	if (Board.Sq [ sq-10 ] == BPAWN) {AddMoveB (Board, sq-10, (sq+(3<<7)), Moves, 0 ); }
	if (SQRANK[sq] == 5 && Board.Sq [ sq-20 ] == BPAWN && Board.Sq [ sq-10 ] == EMPTY) {AddMoveB (Board, sq-20,  (sq+(3<<7)), Moves, 0 ); }
	}

int i;
for (i = 0; i < 8; i++) 
	if (Board.Sq [ sq + KnightMoves[i] ] == BKNIGHT ) AddMoveB (Board, sq + KnightMoves[i] , sq, Moves, bAtk );

for (i = 0; i < 4; i++)
	TestAddDirecB ( Board,  Moves, sq, BishopMoves[i], BBISHOP, BQUEEN, bAtk);

for (i = 0; i < 4; i++)
	TestAddDirecB ( Board,  Moves, sq, RookMoves[i],   BROOK, BQUEEN, bAtk);
}
