#include "win32compat.h"
#include "data.h"
#include "gui.h"
#include "search.h"
#include "transcript.h"
#include "moves.h"
// 
// Board Functions for Slow Chess
// (setting up board, copy&paste position, setting piece sq values, etc.)
//
char acDirec [128 * 128];
// -----------------------------
//
// Functions for Special Setup of the Board
//
// -----------------------------
void ClearBoard (SBoard &Board )
{
		Board.WCastle = 0; 
        Board.BCastle = 0; 
        Board.EnPassant = 120; 
        Board.SideToMove = WHITE; 
        Board.MatVal  = 0; 
        Board.GameTime = 1; 
		Board.LastReversible = 1; 
		Board.nWP = 0; 
		Board.nBP = 0;
		Board.nWPawns = 0;
		Board.nBPawns = 0;
		Board.nBMinors = 0;
		Board.nWMinors = 0;
		Board.WMat = 0;
		Board.BMat = 0;

		Board.TempValue = 0;

		for (int i = 0; i < 16; i++)
			{
			Board.WPiece [ i ] = CAPTURED;
			Board.BPiece [ i ] = CAPTURED;
			}

		int x,y;

        for (x = 0 ; x < 122; x++)  // Invalid Squares
             Board.Sq[x] = INVALID;

        for (y = 0; y < 8; y++) // Empty Squares
			for (x = 0; x < 8; x++)
				Board.Sq [ SQ (x,y) ] = EMPTY;
}

// -----------------------------
// Helper functions to add pieces
// -----------------------------
void CalculateBoardFlags (SBoard &Board )
{ 
	Board.TempValue = 0;
    Board.WMat = 0;
	Board.BMat = 0;
	char cPiece;
	int x, y;

	for (x = 0; x < 8; x++)
		for (y = 0; y < 8; y++)
			{
			cPiece = Board.Sq [ SQ (x,y) ];
			if ( cPiece != EMPTY ) 
				{
				if ( (cPiece&7) != WKING)	Board.TempValue += SquareVals [ cPiece * 128 + SQ (x,y) ];
				if ( cPiece < WKING )		Board.WMat += PieceValues [ cPiece & 7 ];
					else if ( (cPiece&7) != WKING) Board.BMat += PieceValues [ cPiece & 7 ];
				}
			}
	Board.MatVal = Board.WMat - Board.BMat;			
	Board.PawnHash = Pawn_HashBoard (Board);
}


int RemovePiece ( SBoard &Board, int x,  int y )
{
 if ( Board.Sq [ SQ (x,y) ] == EMPTY || Board.Sq [ SQ (x,y) ] == INVALID) return FALSE;
 int i;
 Board.Sq [ SQ (x,y) ] = EMPTY;
 for (i = 0; i < 16; i++) if (Board.WPiece[i] == SQ (x,y)) Board.WPiece[i] = CAPTURED;
 for (i = 0; i < 16; i++) if (Board.BPiece[i] == SQ (x,y)) Board.BPiece[i] = CAPTURED;
 CalculateBoardFlags ( Board );
 return TRUE;
}

int AddPawn ( SBoard &Board, int nSq, char cPiece )
{
	int n = 0;
	unsigned char *pPiece;
	if (cPiece < 8) pPiece = Board.WPiece; else pPiece = Board.BPiece;
	while ( pPiece [n] != CAPTURED && n<8) n++;
	if (n == 8) return FALSE;
	pPiece [ n ] = nSq;
	if (cPiece < 8) Board.nWPawns++; else Board.nBPawns++;
	Board.Sq [ nSq ] = cPiece;
	// Sort so leftmost is first
	for (int x = 0; x < 7; x++)
		for (int i = 6; i >= x; i--)
			if (SQFILE [pPiece[i]] > SQFILE [pPiece[i+1]] ) 
				{Swap (Board.Sq[i], Board.Sq[i+1]);
				 Swap (pPiece[i], pPiece[i+1]);
				}
	return TRUE;
}

int AddOnePiece ( SBoard &Board, int nSq, char cPiece, int nIndex )
	{
	unsigned char *pPiece;
	if (cPiece < 8) pPiece = Board.WPiece; else pPiece = Board.BPiece;

	if (nIndex < 0) // Pieces of this type are filled, so add this as a promoted pawn
		{
		nIndex = 0;
		while ( pPiece [nIndex] != CAPTURED && nIndex<8) nIndex++;
		if (nIndex == 8) return FALSE;
		}

	pPiece [ nIndex ] = nSq;
	if (cPiece < 8) 
		{if ( (cPiece&7) !=WKING ) Board.nWP++; 
		 if ( (cPiece&7) <=4 ) Board.nWMinors++;
		}
	else 
		{if ( (cPiece&7) !=WKING ) Board.nBP++; 
		 if ( (cPiece&7) <=4 ) Board.nBMinors++;
		}
	Board.Sq [ nSq ] = cPiece;
	return TRUE;
	}

//
//
//
void AddPiece (SBoard &Board, int x, int y, char piece)
	{
	int n;
	if (Board.Sq[ SQ (x,y ) ] != EMPTY) return;

	unsigned char *pPiece;
	if (piece < 8) pPiece = Board.WPiece; else pPiece = Board.BPiece;

	switch ( (piece&7) ) // &7 == use white piece numbers for black pieces too
		{
		case WPAWN:
			if ( y == 0 || y == 7) return; // Can't have a pawn on first or last rank
			AddPawn ( Board, SQ (x,y), piece );
		break;
		case WKNIGHT:
				n = 8;
				if (pPiece  [ n ] != CAPTURED) n++;
				if (pPiece  [ n ] != CAPTURED) AddOnePiece ( Board, SQ (x,y), piece, -1 );
					else AddOnePiece ( Board, SQ (x,y), piece, n );

		break;
		case WBISHOP:
				n = 10;
				if (pPiece  [ n ] != CAPTURED) n++;
				if (pPiece  [ n ] != CAPTURED) AddOnePiece ( Board, SQ (x,y), piece , -1);
					else AddOnePiece ( Board, SQ (x,y), piece , n);
		break;
		case WROOK:
				n = 12;
				if (pPiece  [ n ] != CAPTURED) n++;
				if (pPiece  [ n ] != CAPTURED) AddOnePiece ( Board, SQ (x,y), piece , -1);
					else AddOnePiece ( Board, SQ (x,y), piece, n);
		break;
		case WQUEEN:
				if (pPiece  [ 14 ] != CAPTURED) AddOnePiece ( Board, SQ (x,y), piece, -1 );
					else AddOnePiece ( Board, SQ (x,y), piece, 14 );
		break;
		case WKING:
				if (pPiece [ 15 ] != CAPTURED) return;
				AddOnePiece ( Board, SQ (x,y), piece, 15 );
		break;
		}

	CalculateBoardFlags ( Board );
    }

// -----------------
// Setup_Board
// Setup the starting position and flags on Board[]
// -----------------
void Setup_StartBoard (SBoard &Board, int reset)
        {
		char *sStartBoard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -";
		SetBoardFromText ( Board, sStartBoard, strlen (sStartBoard), 1 );
        }

// ------------------------
// Setup Board from a text position
// ------------------------
int SetBoardFromText ( SBoard &InBoard, char *Text, int nLen, int bStart )
	{
	 int i = 0, nFields = 0;
	 int sq = 0;
	 SBoard Board;

	 ClearBoard ( Board );
	 Board.SideToMove = NONE;

	 while (sq < 64 && i<nLen)
		{
		if ( Text[i]>='1' && Text[i]<='8'  ) sq+= Text[i]-'0' - 1;
		else if ( Text[i] == 'K') AddPiece (Board, sq%8, sq/8, WKING);
		else if ( Text[i] == 'k') AddPiece (Board, sq%8, sq/8, BKING);
		else if ( Text[i] == 'Q') AddPiece (Board, sq%8, sq/8, WQUEEN);
		else if ( Text[i] == 'q') AddPiece (Board, sq%8, sq/8, BQUEEN);
		else if ( Text[i] == 'R') AddPiece (Board, sq%8, sq/8, WROOK);
		else if ( Text[i] == 'r') AddPiece (Board, sq%8, sq/8, BROOK);
		else if ( Text[i] == 'B') AddPiece (Board, sq%8, sq/8, WBISHOP);
		else if ( Text[i] == 'b') AddPiece (Board, sq%8, sq/8, BBISHOP);
		else if ( Text[i] == 'N') AddPiece (Board, sq%8, sq/8, WKNIGHT);
		else if ( Text[i] == 'n') AddPiece (Board, sq%8, sq/8, BKNIGHT);
		else if ( Text[i] == 'P') AddPiece (Board, sq%8, sq/8, WPAWN);
		else if ( Text[i] == 'p') AddPiece (Board, sq%8, sq/8, BPAWN);
		else if ( Text[i] == '/') { while ( (sq&7) !=0 ) sq++;
									sq --;
									}
		else sq--;
		sq++;
		i++;
		}

	 Board.BCastle = 3;
	 Board.WCastle = 3;
	 while (i < nLen && Text[i]!=';' && nFields < 2)
		{
		 if ( Text[i] == 'w' && Board.SideToMove == NONE) { Board.SideToMove = WHITE; }
		 if ( Text[i] == 'b' && Board.SideToMove == NONE) { Board.SideToMove = BLACK; Board.GameTime++;}
		 if ( Text[i] == 'K') {	nFields = 1; Board.WCastle &= 1; if (Board.WPiece[13] != 99) Swap (Board.WPiece[12], Board.WPiece[13]);}
		 if ( Text[i] == 'Q') { nFields = 1; Board.WCastle &= 2; if (Board.WPiece[12] != 92) Swap (Board.WPiece[12], Board.WPiece[13]);}
		 if ( Text[i] == 'k') { nFields = 1; Board.BCastle &= 1; if (Board.BPiece[13] != 29) Swap (Board.BPiece[12], Board.BPiece[13]);}
		 if ( Text[i] == 'q') { nFields = 1; Board.BCastle &= 2; if (Board.BPiece[12] != 22) Swap (Board.BPiece[12], Board.BPiece[13]);}

		 if (i+1 < nLen && Text[i] >= 'a' && Text[i] <='h' && Text[i+1] >='1' && Text[i+1] <='8')
			 {
			 Board.EnPassant = SQ ( Text[i]-'a', '8'-Text[i+1]);
			 nFields = 2;
			 }
		 if (Text[i] == '-') nFields++;		 
		 i++;
		}
	  // Make sure castling flags are valid
	  if (Board.Sq [ SQ (4,7) ] != WKING)  Board.WCastle = 3;
	  if (Board.Sq [ SQ (4,0) ] != BKING)  Board.BCastle = 3;
	  if (Board.Sq [ 22 ] != BROOK)  Board.BCastle |=1;
	  if (Board.Sq [ 29 ] != BROOK)  Board.BCastle |=2;
	  if (Board.Sq [ 92 ] != WROOK)  Board.WCastle |=1;
	  if (Board.Sq [ 99 ] != WROOK)  Board.WCastle |=2;

	 if (sq <64 || Board.SideToMove == NONE || Board.WPiece [15]==CAPTURED || Board.BPiece[15]==CAPTURED)
		{
		return FALSE;
		}
	 if ( (Board.SideToMove == WHITE && IsCheck (BLACK, Board)) || (Board.SideToMove == BLACK && IsCheck (WHITE, Board)))
		{
		return FALSE;
		}

	 if (bStart) InBoard = Board;
	 else
		{
		NewGame ( );
		g_StartBoard = Board;
		InBoard = Board;
		}
	 return TRUE;
	}
// ------------------------
// Convert Board to a FEN string
// ------------------------
const char   cPieces[17]  = { '.', '.', 'P', 'B', 'N', 'R', 'Q', 'K','.', '.', 'p', 'b', 'n', 'r', 'q', 'k', '.' };   

int CopyPosition ( char *Text, SBoard Board )
	{
	int index = 0, empty;
	char cPiece;

	// Board
	for (int y = 0; y<8; y++)
		{
		empty = 0;
		for (int x = 0; x<8; x++)
			{
			cPiece = Board.Sq[ SQ(x,y)];
			if (cPiece == EMPTY) empty++;
			else
				{
				if ( empty!=0 ) Text[index++] = empty+'0';
				Text[index++] = cPieces [ cPiece  ];
				empty = 0;
				}
			}
		if (empty != 0) Text[index++] = empty+'0';
		if (y!=7) Text[index++] = '/';
		}

	// Castling Flags
	Text[index++] = ' ';
	if (Board.SideToMove == WHITE) Text[index++] = 'w'; else Text[index++] = 'b';
	Text[index++] = ' ';
	if (Board.WCastle == 3 ) if (Board.BCastle == 3) Text[index++] = '-';
	if (Board.WCastle == 2) Text[index++]  = 'Q';
	if (Board.WCastle == 1) Text[index++]  = 'K';
	if (Board.WCastle == 0) {Text[index++] = 'K';Text[index++] = 'Q';}
	if (Board.BCastle == 2) Text[index++]  = 'q';
	if (Board.BCastle == 1) Text[index++]  = 'k';
	if (Board.BCastle == 0) {Text[index++] = 'k'; Text[index++] = 'q';}
	Text[index++] = ' ';
	Text[index++] = '-';
	Text[index] = NULL;

	return index;
	}    

// -----------------------------
// Init Square Value Array
// -----------------------------
int SquareVals [ 128 * 16 ];
short BPawnValue[ 128 ];
short BPawnValueQS[ 128 ];
short BPawnValueOK[ 128 ];
short BPawnValueQSOK[ 128 ];
short BPawnValueEnd[ 128 ];
short BPawnIsolated[ 128 ];
//short BKnightPost[ 128 ];
unsigned int KnightAttacks [ 256 ];
unsigned int KingAttacks [ 256 ];
unsigned int TouchChecks [ 256 ];

void InitSquareArray ( )
{
int i, x, y;

i = WPAWN;
for (x = 0; x < 120; x++)
	SquareVals [ x + i*128] = 0;

i = WKNIGHT;
for (x = 0; x < 120; x++)
	SquareVals [ x + i*128] = WKnightValue [ x ];

i = WBISHOP;
for (x = 0; x < 120; x++)
	SquareVals [ x + i*128] = WBishopValue [ x ];

i = WROOK;
for (x = 0; x < 120; x++)
	SquareVals [ x + i*128] = WRookValue [ x ];

i = WQUEEN;
for (x = 0; x < 120; x++)
	SquareVals [ x + i*128] = WQueenValue [ x ];

i = WKING;
for (x = 0; x < 120; x++)
	SquareVals [ x + i*128] = WKingValue [ x ];


i = BPAWN;
for ( x = 0; x < 8; x++)
	for (y = 0; y < 8; y++)
	{
	BPawnValue [ SQ (x,y) ]    = -WPawnValue [ SQ(x,7-y) ];
	BPawnValueEnd [ SQ (x,y) ] = -WPawnValueEnd [ SQ(x,7-y) ];
	BPawnValueQS [ SQ (x,y) ]  = -WPawnValueQS [ SQ(x,7-y) ];
	BPawnValueQSOK [ SQ (x,y) ]  = -WPawnValueQSOK [ SQ(x,7-y) ];
	BPawnValueOK [ SQ (x,y) ]  = -WPawnValueOK [ SQ(x,7-y) ];
	BPawnIsolated [ SQ (x,y) ]  = WPawnIsolated [ SQ(x,7-y) ];
	SquareVals [ SQ (x,y) + i*128] = -0;
	}

i = BKNIGHT;
for ( x = 0; x < 8; x++)
	for ( y = 0; y < 8; y++)
	{
	SquareVals [ SQ (x,y) + i*128] = -WKnightValue [ SQ (x, 7-y) ];
//	BKnightPost [ SQ (x,y) ] = -WKnightPost [ SQ (x, 7-y) ];
	}

i = BBISHOP;
for ( x = 0; x < 8; x++)
	for ( y = 0; y < 8; y++)
	SquareVals [ SQ (x,y) + i*128] = -WBishopValue [ SQ (x, 7-y) ];

i = BROOK;
for ( x = 0; x < 8; x++)
	for ( y = 0; y < 8; y++)
	SquareVals [ SQ (x,y) + i*128] = -WRookValue [ SQ (x, 7-y) ];

i = BQUEEN;
for ( x = 0; x < 8; x++)
	for ( y = 0; y < 8; y++)
	SquareVals [ SQ (x,y) + i*128] = -WQueenValue [ SQ (x, 7-y) ];

i = BKING;
for ( x = 0; x < 8; x++)
	for ( y = 0; y < 8; y++)
	SquareVals [ SQ (x,y) + i*128] = -WKingValue [ SQ (x, 7-y) ];

int sq, sq2;

// Init Direction array
ZeroMemory ( acDirec, 128*128 * sizeof (char));
for (sq = 10; sq < 120; sq++)
	for (sq2 = 10; sq2 < 120; sq2++)
		{
		if (SQRANK[sq] == SQRANK[sq2])
			{
			if (sq2 > sq) acDirec [ sq + sq2*128 ] =  1;
			if (sq2 < sq) acDirec [ sq + sq2*128 ] = -1;
			}
		if (SQFILE[sq] == SQFILE[sq2])
			{
			if (sq2 > sq) acDirec [ sq + sq2*128 ] =  10;
			if (sq2 < sq) acDirec [ sq + sq2*128 ] = -10;
			}
		if (SQDIAG1[sq] == SQDIAG1[sq2])
			{
			if (sq2 > sq) acDirec [ sq + sq2*128 ] =  11;
			if (sq2 < sq) acDirec [ sq + sq2*128 ] = -11;
			}
		if (SQDIAG2[sq] == SQDIAG2[sq2])
			{
			if (sq2 > sq) acDirec [ sq + sq2*128 ] =  9;
			if (sq2 < sq) acDirec [ sq + sq2*128 ] = -9;
			}
		}

// Initalize Knight Attacks
ZeroMemory ( KnightAttacks, sizeof (int) * 256);
ZeroMemory ( KingAttacks, sizeof (int) * 256);
ZeroMemory ( TouchChecks, sizeof (int) * 256);
const int KN[8] = {8, 12, 19, 21, -8, -12, -19, -21 };
const int KG[8] = {1, 9, 10, 11, -1, -9, -10, -11 };
for (i = 0; i < 8; i++) KnightAttacks [ 128 + KN[i] ] = 1;
for (i = 0; i < 8; i++) KingAttacks [ 128 + KG[i] ] = 1;
for (i = 0; i < 8; i++) 
	{TouchChecks [ 128 + KG[i] ] = 1;
	 TouchChecks [ 128 + KN[i] ] = 1;
	}
}