Exemplo n.º 1
0
extern void makeMove(Board_t self, int move)
{
        int to = to(move), from = from(move);

        pushList(self->hashHistory, self->hash);
        pushList(self->pkHashHistory, self->pawnKingHash);
        pushList(self->materialHistory, self->materialKey);

        preparePushList(self->undoStack, maxMoveUndo);
        signed char *sp = &self->undoStack.v[self->undoStack.len];
        *sp++ = sentinel;

        #define push(offset, value) Statement(                          \
                *sp++ = (value);                                        \
                *sp++ = (offset);                                       \
        )

        #define makeSimpleMove(from, to) Statement(                     \
                int _piece = self->squares[from];                       \
                int _victim = self->squares[to];                        \
                                                                        \
                /* Update the undo stack */                             \
                push(from, _piece);                                     \
                push(to, _victim); /* last for recaptureSquare */       \
                                                                        \
                /* Make the simple move */                              \
                self->squares[to] = _piece;                             \
                self->squares[from] = empty;                            \
                                                                        \
                /* Update the incremental hash */                       \
                self->hash ^= zobristPiece[_piece][from]                \
                            ^ zobristPiece[_piece][to]                  \
                            ^ zobristPiece[_victim][to];                \
                                                                        \
                /* And the pawn/king/etc hash */                        \
                self->pawnKingHash ^= subHash[_piece][from]             \
                                    ^ subHash[_piece][to]               \
                                    ^ subHash[_victim][to];             \
                                                                        \
                /* Update the material key */                           \
                self->materialKey -= materialKeys[_victim][squareColor(to)];\
        )

        // Always clear en passant info
        if (self->enPassantPawn) {
                push(offsetof_enPassantPawn, self->enPassantPawn);
                self->hash ^= hashEnPassant(self->enPassantPawn);
                self->enPassantPawn = 0;
        }

        // Handle special moves first
        if (move & specialMoveFlag) {
                switch (rank(from)) {
                case rank8:
                        // Black castles. Insert the corresponding rook move
                        if (to == g8)
                                makeSimpleMove(h8, f8);
                        else
                                makeSimpleMove(a8, d8);
                        break;

                case rank7:
                        if (self->squares[from] == blackPawn) { // Set en passant flag
                                push(offsetof_enPassantPawn, 0);
                                self->enPassantPawn = to;
                                self->hash ^= hashEnPassant(to);
                        } else {
                                push(from, self->squares[from]); // White promotes
                                int promoPiece = whiteQueen + ((move >> promotionBits) & 3);
                                self->squares[from] = promoPiece;
                                self->hash ^= zobristPiece[whitePawn][from]
                                            ^ zobristPiece[promoPiece][from];
                                self->pawnKingHash ^= zobristPiece[whitePawn][from];
                                self->materialKey += materialKeys[promoPiece][squareColor(to)]
                                                   - materialKeys[whitePawn][0];
                        }
                        break;

                case rank5: // White captures en passant
                case rank4: { // Black captures en passant
                        int square = square(file(to), rank(from));
                        int victim = self->squares[square];
                        push(square, victim);
                        self->squares[square] = empty;
                        self->hash ^= zobristPiece[victim][square];
                        self->pawnKingHash ^= zobristPiece[victim][square];
                        self->materialKey -= materialKeys[victim][0];
                        break;
                }
                case rank2:
                        if (self->squares[from] == whitePawn) { // Set en passant flag
                                push(offsetof_enPassantPawn, 0);
                                self->enPassantPawn = to;
                                self->hash ^= hashEnPassant(to);
                        } else {
                                push(from, self->squares[from]); // Black promotes
                                int promoPiece = blackQueen + ((move >> promotionBits) & 3);
                                self->squares[from] = promoPiece;
                                self->hash ^= zobristPiece[blackPawn][from]
                                            ^ zobristPiece[promoPiece][from];
                                self->pawnKingHash ^= zobristPiece[blackPawn][from];
                                self->materialKey += materialKeys[promoPiece][squareColor(to)]
                                                   - materialKeys[blackPawn][0];
                        }
                        break;

                case rank1:
                        // White castles. Insert the corresponding rook move
                        if (to == g1)
                                makeSimpleMove(h1, f1);
                        else
                                makeSimpleMove(a1, d1);
                        break;

                default:
                        break;
                }
        }

        self->plyNumber++;
        self->hash ^= zobristTurn[0];

        if (self->squares[to] != empty
         || self->squares[from] == whitePawn
         || self->squares[from] == blackPawn) {
                push(offsetof_halfmoveClock, self->halfmoveClock); // This is why it is a byte
                self->halfmoveClock = 0;
        } else
                self->halfmoveClock++; // Can overflow the byte, but don't worry

        int flagsToClear = (castleFlagsClear[from] | castleFlagsClear[to]) & self->castleFlags;
        if (flagsToClear) {
                push(offsetof_castleFlags, self->castleFlags);
                self->castleFlags ^= flagsToClear;
                uint64_t deltaHash = hashCastleFlags(flagsToClear);
                self->hash ^= deltaHash;
                self->pawnKingHash ^= deltaHash;
        }

        // The real move always as last
        makeSimpleMove(from, to);
        self->undoStack.len = sp - self->undoStack.v;

        // Finalize en passant (this is only safe after the update of self->undoStack.len)
        if (self->enPassantPawn)
                normalizeEnPassantStatus(self);
}
Exemplo n.º 2
0
extern void boardToFen(Board_t self, char *fen)
{
        /*
         *  Squares
         */
        for (int rank=rank8; rank!=rank1-rankStep; rank-=rankStep) {
                int emptySquares = 0;
                for (int file=fileA; file!=fileH+fileStep; file+=fileStep) {
                        int square = square(file, rank);
                        int piece = self->squares[square];

                        if (piece != empty) {
                                if (emptySquares > 0) *fen++ = '0' + emptySquares;
                                *fen++ = pieceToChar[piece];
                                emptySquares = 0;
                        } else
                                emptySquares++;
                }
                if (emptySquares > 0) *fen++ = '0' + emptySquares;
                if (rank != rank1) *fen++ = '/';
        }

        /*
         *  Side to move
         */
        *fen++ = ' ';
        *fen++ = (sideToMove(self) == white) ? 'w' : 'b';

        /*
         *  Castling flags
         */
        *fen++ = ' ';
        if (self->castleFlags) {
                if (self->castleFlags & castleFlagWhiteKside) *fen++ = 'K';
                if (self->castleFlags & castleFlagWhiteQside) *fen++ = 'Q';
                if (self->castleFlags & castleFlagBlackKside) *fen++ = 'k';
                if (self->castleFlags & castleFlagBlackQside) *fen++ = 'q';
        } else
                *fen++ = '-';

        /*
         *  En-passant square
         */
        *fen++ = ' ';
        normalizeEnPassantStatus(self);
        if (self->enPassantPawn) {
                *fen++ = fileToChar(file(self->enPassantPawn));
                *fen++ = rankToChar((sideToMove(self) == white) ? rank6 : rank3);
        } else
                *fen++ = '-';

        /*
         *  Move number (TODO)
         */

        /*
         *  Halfmove clock (TODO)
         */

        *fen = '\0';
}
Exemplo n.º 3
0
extern int setupBoard(Board_t self, const char *fen)
{
        int ix = 0;

        /*
         *  Squares
         */

        while (isspace(fen[ix])) ix++;

        int file = fileA, rank = rank8;
        int nrWhiteKings = 0, nrBlackKings = 0;
        memset(self->squares, empty, boardSize);
        self->materialKey = 0;
        while (rank != rank1 || file != fileH + fileStep) {
                int piece = empty;
                int count = 1;

                switch (fen[ix]) {
                case 'K': piece = whiteKing; nrWhiteKings++; break;
                case 'Q': piece = whiteQueen; break;
                case 'R': piece = whiteRook; break;
                case 'B': piece = whiteBishop; break;
                case 'N': piece = whiteKnight; break;
                case 'P': piece = whitePawn; break;
                case 'k': piece = blackKing; nrBlackKings++; break;
                case 'r': piece = blackRook; break;
                case 'q': piece = blackQueen; break;
                case 'b': piece = blackBishop; break;
                case 'n': piece = blackKnight; break;
                case 'p': piece = blackPawn; break;
                case '/': rank -= rankStep; file = fileA; ix++; continue;
                case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8':
                        count = fen[ix] - '0';
                        break;
                default:
                        return 0; // FEN error
                }
                int squareColor = squareColor(square(file,rank));
                self->materialKey += materialKeys[piece][squareColor];
                do {
                        self->squares[square(file,rank)] = piece;
                        file += fileStep;
                } while (--count && file != fileH + fileStep);
                ix++;
        }
        if (nrWhiteKings != 1 || nrBlackKings != 1) return 0;

        /*
         *  Side to move
         */

        self->plyNumber = 2 + (fen[ix+1] == 'b'); // 2 means full move number starts at 1
        //self->lastZeroing = self->plyNumber;
        ix += 2;

        /*
         *  Castling flags
         */

        while (isspace(fen[ix])) ix++;

        self->castleFlags = 0;
        for (;; ix++) {
                switch (fen[ix]) {
                case 'K': self->castleFlags |= castleFlagWhiteKside; continue;
                case 'Q': self->castleFlags |= castleFlagWhiteQside; continue;
                case 'k': self->castleFlags |= castleFlagBlackKside; continue;
                case 'q': self->castleFlags |= castleFlagBlackQside; continue;
                case '-': ix++; break;
                default: break;
                }
                break;
        }

        /*
         *  En passant square
         */

        while (isspace(fen[ix])) ix++;

        if ('a' <= fen[ix] && fen[ix] <= 'h') {
                file = charToFile(fen[ix]);
                ix++;

                rank = (sideToMove(self) == white) ? rank5 : rank4;
                if (isdigit(fen[ix])) ix++; // ignore what it says

                self->enPassantPawn = square(file, rank);
        } else {
                self->enPassantPawn = 0;
                if (fen[ix] == '-')
                        ix++;
        }

        // Eat move number and halfmove clock. TODO: process this properly
        while (isspace(fen[ix])) ix++;
        while (isdigit(fen[ix])) ix++;
        while (isspace(fen[ix])) ix++;
        while (isdigit(fen[ix])) ix++;

        self->sideInfoPlyNumber = -1; // side info is invalid now

        // Reset the undo stack
        self->undoStack.len = 0;

        // Initialize hash and its history
        self->hash = hash(self);
        self->hashHistory.len = 0;

        self->pawnKingHash = pawnKingHash(self);
        self->pkHashHistory.len = 0;

        normalizeEnPassantStatus(self); // Only safe after update of hash

        self->eloDiff = 0;

        return ix;
}