Beispiel #1
0
// Initialize board with given string
//   NOTE:  Last two fields of FEN (half-move count and move number) are optional.  This allows
//   Function to work with a string consisting of the first four fields of an EPD record
fenErr_t setBoard(board_t *brd, const char *FEN)
{


	 // Local copy of a board upon which to do all operations...
	 board_t b;

	 // Index into the 64 squares of the board...
	 int index = 0;

	 setBoardEmpty(&b);


    if (FEN == NULL) FEN = startString;

	 // parse piece placement field...
	 while(index < 64)
	 {
	 	switch(*FEN)
	 	{
	 		case '1':
	 		case '2':
	 		case '3':
	 		case '4':
	 		case '5':
	 		case '6':
	 		case '7':
	 		case '8':
	 			// Skip over the number of squares
	 			index += (*FEN - '0'); break;
	 		// For each possible piece, add it at the given offset...
	 		case 'B': addPiece(&b, index++, BISHOP, WHITE); break;
	 		case 'K': addPiece(&b, index++, KING,   WHITE); break;
	 		case 'N': addPiece(&b, index++, KNIGHT, WHITE); break;
	 		case 'P': addPiece(&b, index++, PAWN,   WHITE); break;
	 		case 'Q': addPiece(&b, index++, QUEEN,  WHITE); break;
	 		case 'R': addPiece(&b, index++, ROOK,   WHITE); break;
	 		case 'b': addPiece(&b, index++, BISHOP, BLACK); break;
	 		case 'k': addPiece(&b, index++, KING,   BLACK); break;
	 		case 'n': addPiece(&b, index++, KNIGHT, BLACK); break;
	 		case 'p': addPiece(&b, index++, PAWN,   BLACK); break;
	 		case 'q': addPiece(&b, index++, QUEEN,  BLACK); break;
	 		case 'r': addPiece(&b, index++, ROOK,   BLACK); break;

			// This is just to make the string more readable... just ignore.
	 		case '/': break;

			// Any other characters denote an error
	 		default: return FEN_ILLEGAL_CHARACTER_FIELD_1; break;

	 	}
	 	FEN++; // move to next character.
	 }

	 // Make sure we counted 64 positions
	 if(index != 64) return FEN_PARSE_ERR_FIELD_1;

	 // Make sure we have no more characters in FIELD 1
	 if(*FEN != ' ') return FEN_PARSE_ERR_FIELD_1;

	 // Move pointer to start of field 2
	 FEN++;

	 // Should be either w or b
	 if(*FEN == 'w')
	 {
	 	// Update the position hash
	 	b.toMove = WHITE;
	 	b.hash ^= Z_WHITE_TURN_KEY;
	 }
	 else if (*FEN == 'b')
	 {
	 	b.toMove = BLACK;
	 }
	 else if (*FEN == ' ')
	 {
	 	// too many spaces between....
	 	return FEN_BAD_SEPARATOR;
	 }
	 else
	 {
	 	// found an unexpected character
	 	return FEN_INVALID_FIELD_2;
	 }

	 // Move to separator between field 2 and 3
	 FEN++;

	 // If not a space, we have an error because field 2 is longer than 1 byte
	 if(*FEN != ' ') return FEN_INVALID_FIELD_2;

	 // Move to start of field 3 (castling squares)
	 FEN++;

	 // check for too many spaces....
	 if(*FEN == ' ')
	 {
	 	return FEN_BAD_SEPARATOR;
	 }

	 // if a dash, all castle bits should be zero
	 if(*FEN == '-')
	 {
	 	FEN++;
	 	// make sure we have a proper separator.
	 	if (*FEN != ' ')
	 	{
	 		return FEN_INVALID_FIELD_3;
	 	}
	 }
	 // otherwise, check for valid castle bits
	 //  NOTE: the following allows bits to occur in any order.  May not be
	 //  strictly allowable by FEN specification.
    // TODO CHESS960
    else
	 {
		 while(*FEN != ' ')
		 {
			if(*FEN == 'K' && !(b.castleBits & WHITE_CASTLE_SHORT) )
			{
				b.castleBits |= WHITE_CASTLE_SHORT;
				b.hash ^= Z_WHITE_SHORT_KEY;
			}
			else if(*FEN == 'Q' && !(b.castleBits & WHITE_CASTLE_LONG) )
			{
				b.castleBits |= WHITE_CASTLE_LONG;
				b.hash ^= Z_WHITE_LONG_KEY;
			}
			else if(*FEN == 'k' && !(b.castleBits & BLACK_CASTLE_SHORT) )
			{
				b.castleBits |= BLACK_CASTLE_SHORT;
				b.hash ^= Z_BLACK_SHORT_KEY;
			}
			else if(*FEN == 'q' && !(b.castleBits & BLACK_CASTLE_LONG) )
			{
				b.castleBits |= BLACK_CASTLE_LONG;
				b.hash ^= Z_BLACK_LONG_KEY;
			}
			else
			{
				return FEN_INVALID_FIELD_3;
			}
			FEN++;
		 }
	 }

	 // Separator already confirmed at this point
	 FEN++;

	 // Check for no enPassant...
	 if(*FEN == '-')
	 {
	 	FEN++;
	 }

	 // else should be a-f
	 else if(*FEN >='a' && *FEN <= 'h')
	 {
	    int targetSquare;

	 	b.enPassantCol = *FEN - 'a';

    	targetSquare = b.enPassantCol + (b.toMove == WHITE ? 40 : 16);

		if( (shiftE(squareMask[targetSquare]) & b.pieces[PAWN] & b.colors[b.toMove == WHITE ? BLACK : WHITE]) ||
		    (shiftW(squareMask[targetSquare]) & b.pieces[PAWN] & b.colors[b.toMove == WHITE ? BLACK : WHITE]))
		{
		    b.zobristEnPassantCol = *FEN - 'a';
	 	    b.hash ^= Z_ENPASSANT_COL_KEY(b.enPassantCol);
	 	}


	 	FEN++;
	 	if( !(*FEN == '3' && b.toMove == BLACK) && !(*FEN == '6' && b.toMove == WHITE) )
	 	{
	 		return FEN_INVALID_FIELD_4;
	 	}
	 	else
	 	{
	 		FEN++;
	 	}
	 }
	 else if (*FEN == ' ')
	 {
	 	return FEN_BAD_SEPARATOR;
	 }
	 else
	 {
	 	return FEN_INVALID_FIELD_4;
	 }

	 // At this point, and EPD record will end.  What follows then is optional....

	 // If string ends here, leave defaults...
	 if(*FEN != '\0')
	 {

         b.moveNumber = 0; // Since string didn't end, assume moveNumber will be included.
                           // Set to zero so logic below will work correctly...

         // Move to next character
         FEN++;

         // Should be a separator
         if(*FEN == ' ')
         {
            return FEN_BAD_SEPARATOR;
         }

         // This is the half-move counter... should be a digit...
         if(*FEN <'0' && *FEN >'9')
         {
            return FEN_INVALID_FIELD_5;
         }

         while(1)
         {
            b.halfMoves *= 10;
            b.halfMoves += *FEN - '0';
            FEN++;

            if(*FEN == ' ') break;

            if(*FEN <'0' || *FEN >'9')
            {
                return FEN_INVALID_FIELD_5;
            }
         }

         // We hit a separator, so move to next character
         FEN++;

         // This is the first digit of the move number... should be a non-zero digit...
         if(*FEN <'1' || *FEN >'9')
         {
            return FEN_INVALID_FIELD_6;
         }

         while(1)
         {
            b.moveNumber *= 10;
            b.moveNumber += *FEN - '0';

            FEN++;

            if(*FEN == '\0') break;

            if(*FEN <'0' || *FEN >'9')
            {
                return FEN_INVALID_FIELD_6;
            }
         }
    }
	memcpy(brd, &b, sizeof(board_t));

	positionHistory[0] = brd->hash;
    positionIndex = 1;

 	return FEN_OK;
}
Beispiel #2
0
U64 knightSEE(){ return shiftSE(shiftE(pieces[KNIGHT])); }
Beispiel #3
0
// Move assumed valid for this board.
// Add/remove functions will ASSERT adds are to empty squares and removes have expected piece there...
// Castling moves assumed legal (if to/from square and piece moved match a castle for king), rook is also moved with king
revMove_t move(board_t *b, const move_t m)
{

	unsigned char to = m.to;
	unsigned char from = m.from;

	int offset = 0;

	revMove_t retValue;

	// A place holder for the side to move (saves repeated pointer access)
	color_t toMove = b->toMove;

	// A place to hold the "opposite color" calculation
	color_t oppositeColor = (toMove == WHITE ? BLACK : WHITE);

	// promotion piece (if any)
	piece_t promote = (piece_t)(m.promote);

	// handy marker for piece moved
	piece_t pieceMoved = ( (b->pieces[PAWN]   & squareMask[from]) ? PAWN : (
						   (b->pieces[KNIGHT] & squareMask[from]) ? KNIGHT : (
						   (b->pieces[BISHOP] & squareMask[from]) ? BISHOP : (
						   (b->pieces[ROOK]   & squareMask[from]) ? ROOK : (
						   (b->pieces[QUEEN]  & squareMask[from]) ? QUEEN : KING)))));



	// Test that side to move has proper value
	ASSERT( (toMove == WHITE) || (toMove == BLACK) );

	// Check that a piece of the side to move exists at the origin
	ASSERT( (b->colors[toMove] & squareMask[from]) != 0);




	// Prepare the return value...
	retValue.move.from    = from;
	retValue.move.to      = to;
	retValue.move.promote = promote;
	retValue.priorCastleBits = b->castleBits;
	retValue.priorEnPassant  = b->enPassantCol;
	retValue.priorHalfMoveCnt = b->halfMoves;
	retValue.priorZobristEnPassantCol = b->zobristEnPassantCol;

	retValue.captured = b->colors[oppositeColor] & squareMask[to] ?
							( (b->pieces[PAWN]   & squareMask[to]) ? PAWN : (
						     (b->pieces[KNIGHT] & squareMask[to]) ? KNIGHT : (
						     (b->pieces[BISHOP] & squareMask[to]) ? BISHOP : (
						     (b->pieces[ROOK]   & squareMask[to]) ? ROOK : QUEEN)))) : PIECE_NONE;

	// Check for capture enPassant...
	if( (pieceMoved == PAWN)       &&  // moved a pawn
	    ( (to % 8) != (from % 8) ) &&  // to and from files are different
	    ( (squareMask[to] & b->colors[oppositeColor]) == 0) // target square doesn't have enemy piece
	  )
	{
		offset = (toMove == WHITE ? 8 : -8);
		retValue.captured = PAWN;
	}

	// First remove any captured piece from the board
	if(retValue.captured != PIECE_NONE)
	{
		removePiece(b, to + offset, retValue.captured, oppositeColor );
	}

	if(promote == PIECE_NONE)
	{
		// Simply move the piece back
		movePiece(b, from, to, pieceMoved, toMove);
	}
	else
	{
		ASSERT( ( ( (to < 8) && toMove) == WHITE) || ( (to > 55) && toMove == BLACK ) );

		ASSERT( pieceMoved == PAWN);

		// Remove pawn
		removePiece(b, from, pieceMoved, toMove);

		// Add promoted piece
		addPiece(b, to, promote, toMove);

	}

	// If this was a castling move, move the rook too...
	if(pieceMoved == KING)
	{
		if(from == E1)
		{
			if(to == C1)
			{
				movePiece(b, A1, D1, ROOK, toMove);
			}
			else if(to == G1)
			{
				movePiece(b, H1, F1, ROOK, toMove);
			}
		}
		else if(from == E8)
		{
			if(to == C8)
			{
				movePiece(b, A8, D8, ROOK, toMove);
			}
			else if(to == G8)
			{
				movePiece(b, H8, F8, ROOK, toMove);
			}
		}
	}

   // TODO CHESS960
	// Adjust Castling possibilities if needed
	if( pieceMoved == KING )
	{
		if( toMove == WHITE)
		{
			if(b->castleBits & WHITE_CASTLE_LONG)
			{
				b->hash ^= Z_WHITE_LONG_KEY;
			}
			if(b->castleBits & WHITE_CASTLE_SHORT)
			{
				b->hash ^= Z_WHITE_SHORT_KEY;
			}
			b->castleBits &= ~(WHITE_CASTLE_LONG | WHITE_CASTLE_SHORT);
		}
		else
		{
			if(b->castleBits & BLACK_CASTLE_LONG)
			{
				b->hash ^= Z_BLACK_LONG_KEY;
			}
			if(b->castleBits & BLACK_CASTLE_SHORT)
			{
				b->hash ^= Z_BLACK_SHORT_KEY;
			}
			b->castleBits &= ~(BLACK_CASTLE_LONG | BLACK_CASTLE_SHORT);
		}
	}

	if( pieceMoved == ROOK )
	{
		if(from == A1 && b->castleBits & WHITE_CASTLE_LONG)
		{
			b->hash ^= Z_WHITE_LONG_KEY;
			b->castleBits &= ~WHITE_CASTLE_LONG;
		}
		else if (from == H1 && b->castleBits & WHITE_CASTLE_SHORT)
		{
			b->hash ^= Z_WHITE_SHORT_KEY;
			b->castleBits &= ~WHITE_CASTLE_SHORT;
		}
		else if(from == A8 && b->castleBits & BLACK_CASTLE_LONG)
		{
			b->hash ^= Z_BLACK_LONG_KEY;
			b->castleBits &= ~BLACK_CASTLE_LONG;
		}
		else if (from == H8 && b->castleBits & BLACK_CASTLE_SHORT)
		{
			b->hash ^= Z_BLACK_SHORT_KEY;
			b->castleBits &= ~BLACK_CASTLE_SHORT;
		}
	}

	// If a rook was captured, that affects castling too...
	if( retValue.captured == ROOK)
	{
		if( (to == A1) &&  (b->castleBits & WHITE_CASTLE_LONG) )
		{
			b->hash ^= Z_WHITE_LONG_KEY;
			b->castleBits &= ~WHITE_CASTLE_LONG;
		}
		else if( (to == H1) &&  (b->castleBits & WHITE_CASTLE_SHORT) )
		{
			b->hash ^= Z_WHITE_SHORT_KEY;
			b->castleBits &= ~WHITE_CASTLE_SHORT;
		}
		else if( (to == A8) &&  (b->castleBits & BLACK_CASTLE_LONG) )
		{
			b->hash ^= Z_BLACK_LONG_KEY;
			b->castleBits &= ~BLACK_CASTLE_LONG;
		}
		else if( (to == H8) &&  (b->castleBits & BLACK_CASTLE_SHORT) )
		{
			b->hash ^= Z_BLACK_SHORT_KEY;
			b->castleBits &= ~BLACK_CASTLE_SHORT;
		}
	}

	// Adjust halfmove count
	if( (pieceMoved == PAWN) || (retValue.captured != PIECE_NONE) )
	{
		b->halfMoves = 0;
	}
	else
	{
		b->halfMoves++;
	}

	// Adjust move number if black just moved
	if(toMove == BLACK)
	{
		b->moveNumber++;
	}

	// Adjust side to move
	b->toMove = oppositeColor;
	b->hash ^= Z_WHITE_TURN_KEY; // Either side to move will trigger this toggle.

	// Adjust enPassant col if we moved a pawn forward two

	if ( (pieceMoved == PAWN) && (abs(from - to) == 16) )
	{
		b->enPassantCol = to & 0x07;
		if( (shiftE(squareMask[to]) & b->pieces[PAWN] & b->colors[oppositeColor]) ||
		    (shiftW(squareMask[to]) & b->pieces[PAWN] & b->colors[oppositeColor]))
		{
		    b->zobristEnPassantCol = to & 0x07;
		}
		else
		{
		    b->zobristEnPassantCol = 8;
		}
	}
	else
	{
		b->enPassantCol = 8;
	    b->zobristEnPassantCol = 8;
	}

    if(retValue.priorZobristEnPassantCol != b->zobristEnPassantCol)
    {

        if(retValue.priorZobristEnPassantCol != 8)
	    {
	        b->hash  ^= Z_ENPASSANT_COL_KEY(retValue.priorZobristEnPassantCol);
	    }

        if( b->zobristEnPassantCol != 8)
        {
	        b->hash  ^= Z_ENPASSANT_COL_KEY(b->zobristEnPassantCol);
        }

    }

    ASSERT(positionIndex < POSITION_HISTORY_SIZE);
    ASSERT(positionIndex >= 0);


	positionHistory[positionIndex++] = b->hash;

	if(positionIndex == POSITION_HISTORY_SIZE)
	{
	    positionIndex = 0;
	}

	return retValue;
}