
// FromFEN()

void Board::FromFEN(char *fen) {

	// init
	int square, colour;
	BitBoard sq_bit;
	char c;

	Clear();
	
	for(square = a8; square >= a1; fen++) {
		ASSERT(*fen != '\0');

		if(isdigit(*fen)) {
			square += *fen - '0';
			continue;
		}
		if(*fen == '/') {			
			square -= File(square) + 16;
			continue;
		}
		if(*fen == ' ')		break;			
		
		colour = isupper(*fen) ? WHITE : BLACK;
		c = toupper(*fen);
		sq_bit = BIT(square); 
		occupied_by[colour]	|= sq_bit;		
		switch(c) {
			case 'P':	type[square] = PAWN;	piece[PAWN]	 |= sq_bit;		break;
			case 'N':	type[square] = KNIGHT;	piece[KNIGHT]|= sq_bit;		break;
			case 'B':	type[square] = BISHOP;	piece[BISHOP]|= sq_bit;		break;
			case 'R':	type[square] = ROOK;	piece[ROOK]	 |= sq_bit;		break;
			case 'Q':	type[square] = QUEEN;	piece[QUEEN] |= sq_bit;		break;
			case 'K':	type[square] = KING;	piece[KING]	 |= sq_bit;		ksq[colour] = square;	break;			
			default:	ASSERT(false);
		}
		square++;
	}
	// stm	
	ASSERT(*fen == ' ');
	fen++;
	switch(*fen) {
		case 'w': stm = WHITE;	break;
		case 'b': stm = BLACK;  break;
		default:	ASSERT(false);
	}
	fen++;
	ASSERT(*fen == ' ');

	// castle
	for(fen++, castle = EMPTY; *fen != ' '; fen++)
		switch(*fen) {
			case '-':	break;
			case 'K':	castle |= WHITE_OO_FLAG;	ASSERT((type[e1] == KING) && (type[h1] == ROOK));	break;
			case 'Q':	castle |= WHITE_OOO_FLAG;	ASSERT((type[e1] == KING) && (type[a1] == ROOK));	break;
			case 'k':	castle |= BLACK_OO_FLAG;	ASSERT((type[e8] == KING) && (type[h8] == ROOK));	break;
			case 'q':	castle |= BLACK_OOO_FLAG;	ASSERT((type[e8] == KING) && (type[a8] == ROOK));	break;
			default:	ASSERT(false);
		}	
	ASSERT(*fen == ' ');

	// EP & Fifty moves rule
	ep_file = EMPTY;
	fifty = 0;
	
	fen++;
	c = *fen;
	if((c != '\0') && (c != '-')) {			
		ep_file = (c - 'a') + 1;
		ASSERT((c >= 'a') && (c <= 'h'));			
	}

	// other
	occupied = White() | Black();
	for(square = a1; square <= h8; square++) {
		if(BIT(square) & occupied) {
			occupied_rl90 |= BIT_L90(square);
			occupied_rl45 |= BIT_L45(square);
			occupied_rr45 |= BIT_R45(square);
		}		
	}
	ResetPST();

	// material
	int wp, wn, wb, wr, wq, 
		bp, bn, bb, br, bq;
	wp = CountBits(White() & piece[PAWN]);
	bp = CountBits(Black() & piece[PAWN]);
	wn = CountBits(White() & piece[KNIGHT]);
	bn = CountBits(Black() & piece[KNIGHT]);
	wb = CountBits(White() & piece[BISHOP]);
	bb = CountBits(Black() & piece[BISHOP]);
	wr = CountBits(White() & piece[ROOK]);
	br = CountBits(Black() & piece[ROOK]);
	wq = CountBits(White() & piece[QUEEN]);
	bq = CountBits(Black() & piece[QUEEN]);	
	mat_diff = PAWN_VALUE*(wp-bp) + KNIGHT_VALUE*(wn-bn) + BISHOP_VALUE*(wb-bb) + ROOK_VALUE*(wr-br) + QUEEN_VALUE*(wq-bq);

	// keys
	key = InitHashKey();
	pawn_key = InitPawnHashKey();
	mat_key = MATERIAL_KEY(wp,wn,wb,wr,wq,bp,bn,bb,br,bq);
	
	//if(DEBUG)	Print();	
}

void Board::ResetPST() {

	int square, colour;
	opening = endgame = 0;
	BitBoard occ = White() | Black();
	
	for(square = a1; square <= h8; square++) {
		if(BIT(square) & occ) {			
			colour = WHITE;
			if(BIT(square) & Black())	colour = BLACK;
			opening += PST_OP(colour, type[square], square);
			endgame += PST_EG(colour, type[square], square);
		}		
	}
}

// ToFen()

char *Board::ToFen() {

	// init	
	int empty, file, rank, square, pos = 0, colour;
	char piece_str[] = " pnbrqkPNBRQK";	
	char colour_str[] = "wb";
	static char str[256]={0}, tmp[16]={0};	
	
	// pieces
	for(rank = 0; rank < 8; rank++) {
		empty = 0;
		for(file = 0; file < 8; file++) {
			square = (56 - 8*rank) + file;
			if(type[square] == EMPTY)	empty++;
			else {
				if(empty > 0) {
					sprintf(str + pos++, "%d", empty);
					empty = 0;
				}
				colour = 6 * (White() & BIT(square) ? 1 : 0);
				sprintf(str + pos++, "%c", piece_str[type[square] + colour]);
			}
		}		
		if(empty > 0)	sprintf(str + pos++, "%d", empty);
		if(rank < 7)	sprintf(str + pos++, "/");
	}
	// stm
	sprintf(str + pos++, " %c ", colour_str[stm]);
	pos += 2;
	// castle	
	if(castle == 0)		sprintf(str + pos++, "%c", '-');
	if(castle & WHITE_OO_FLAG )		sprintf(str + pos++, "%c", 'K');
	if(castle & WHITE_OOO_FLAG )	sprintf(str + pos++, "%c", 'Q');
	if(castle & BLACK_OO_FLAG )		sprintf(str + pos++, "%c", 'k');
	if(castle & BLACK_OOO_FLAG )	sprintf(str + pos++, "%c", 'q');
	// En Passant	
	if(ep_file)	{
		const uint h5_h2[] = {h5, h2};
		int ep_sq = h5_h2[stm] + ep_file;
		SQUARE_TO_STRING(ep_sq, tmp);
		sprintf(str + pos++, " %s ", tmp);
		pos++;
	}
	else sprintf(str + pos++, " %c", '-');
	
	// fifty moves rule
	pos++;
	sprintf(str + pos++, " %d", fifty);	
	// move number
	pos++;
	sprintf(str + pos++, " %d", ply/2 + 1);	

	return str;
}

void Board::PrintFen() {
	printf("%s\n", ToFen());
}