Exemple #1
0
    internal Position(Position other, Thread thread)
    {
        Array.Copy(other.board, board, other.board.Length);
        Array.Copy(other.byColorBB, byColorBB, other.byColorBB.Length);
        Array.Copy(other.byTypeBB, byTypeBB, other.byTypeBB.Length);
        Array.Copy(other.castlingPath, castlingPath, other.castlingPath.Length);
        Array.Copy(other.castlingRightsMask, castlingRightsMask, other.castlingRightsMask.Length);
        Array.Copy(other.castlingRookSquare, castlingRookSquare, other.castlingRookSquare.Length);
        Array.Copy(other.index, index, other.index.Length);
        Array.Copy(other.pieceCount, pieceCount, other.pieceCount.Length);
        Array.Copy(other.pieceList, pieceList, other.pieceList.Length);

        chess960 = other.chess960;
        gamePly = other.gamePly;
        sideToMove = other.sideToMove;

        thisThread = thread;
        startState = new StateInfo();
        startState.copyFrom(other.st);
        st = startState;

        nodes = 0;
        Debug.Assert(pos_is_ok());
    }
Exemple #2
0
    /// Position::do_move() makes a move, and saves all information necessary
    /// to a StateInfo object. The move is assumed to be legal. Pseudo-legal
    /// moves should be filtered out before this function is called.
    internal void do_move(MoveT m, StateInfo newSt, bool givesCheck)
    {
        Debug.Assert(Move.is_ok(m));
        Debug.Assert(newSt != st);

        ++nodes;
        var k = st.key ^ Zobrist.side;

        // Copy some fields of the old state to our new StateInfo object except the
        // ones which are going to be recalculated from scratch anyway and then switch
        // our state pointer to point to the new (ready to be updated) state.
        newSt.copyFrom(st);

        newSt.previous = st;
        st = newSt;

        // Increment ply counters. In particular, rule50 will be reset to zero later on
        // in case of a capture or a pawn move.
        ++gamePly;
        ++st.rule50;
        ++st.pliesFromNull;

        var us = sideToMove;
        var them = Color.opposite(us);
        var from = Move.from_sq(m);
        var to = Move.to_sq(m);
        var pt = (int)Piece.type_of(piece_on(from));
        var captured = Move.type_of(m) == MoveType.ENPASSANT ? PieceType.PAWN : Piece.type_of(piece_on(to));

        Debug.Assert(Piece.color_of(piece_on(from)) == us);
        Debug.Assert(
            piece_on(to) == Piece.NO_PIECE
            || Piece.color_of(piece_on(to)) == (Move.type_of(m) != MoveType.CASTLING ? them : us));
        Debug.Assert(captured != PieceType.KING);

        if (Move.type_of(m) == MoveType.CASTLING)
        {
            Debug.Assert(pt == PieceType.KING);

            SquareT rfrom, rto;
            do_castling(true, us, from, ref to, out rfrom, out rto);

            captured = PieceType.NO_PIECE_TYPE;
            st.psq += PSQT.psq[us, PieceType.ROOK, rto] - PSQT.psq[us, PieceType.ROOK, rfrom];
            k ^= Zobrist.psq[us, PieceType.ROOK, rfrom] ^ Zobrist.psq[us, PieceType.ROOK, rto];
        }

        if (captured != 0)
        {
            var capsq = to;

            // If the captured piece is a pawn, update pawn hash key, otherwise
            // update non-pawn material.
            if (captured == PieceType.PAWN)
            {
                if (Move.type_of(m) == MoveType.ENPASSANT)
                {
                    capsq -= Square.pawn_push(us);

                    Debug.Assert(pt == PieceType.PAWN);
                    Debug.Assert(to == st.epSquare);
                    Debug.Assert(Rank.relative_rank_CtSt(us, to) == Rank.RANK_6);
                    Debug.Assert(piece_on(to) == Piece.NO_PIECE);
                    Debug.Assert(piece_on(capsq) == Piece.make_piece(them, PieceType.PAWN));

                    board[capsq] = Piece.NO_PIECE; // Not done by remove_piece()
                }

                st.pawnKey ^= Zobrist.psq[them, PieceType.PAWN, capsq];
            }
            else
            {
                st.nonPawnMaterial[them] -= Value.PieceValue[(int) Phase.MG][captured];
            }

            // Update board and piece lists
            remove_piece(them, PieceType.Create(captured), capsq);

            // Update material hash key and prefetch access to materialTable
            k ^= Zobrist.psq[them, captured, capsq];
            st.materialKey ^= Zobrist.psq[them, captured, pieceCount[them, captured]];

            // Update incremental scores
            st.psq -= PSQT.psq[them, captured, capsq];

            // Reset rule 50 counter
            st.rule50 = 0;
        }

        // Update hash key
        k ^= Zobrist.psq[us, pt, @from] ^ Zobrist.psq[us, pt, to];

        // Reset en passant square
        if (st.epSquare != Square.SQ_NONE)
        {
            k ^= Zobrist.enpassant[Square.file_of(st.epSquare)];
            st.epSquare = Square.SQ_NONE;
        }

        // Update castling rights if needed
        if (st.castlingRights != 0 && ((castlingRightsMask[@from] | castlingRightsMask[to]) != 0))
        {
            var cr = castlingRightsMask[@from] | castlingRightsMask[to];
            k ^= Zobrist.castling[st.castlingRights & cr];
            st.castlingRights &= ~cr;
        }

        // Move the piece. The tricky Chess960 castling is handled earlier
        if (Move.type_of(m) != MoveType.CASTLING)
        {
            move_piece(us, PieceType.Create(pt), from, to);
        }

        // If the moving piece is a pawn do some special extra work
        if (pt == PieceType.PAWN)
        {
            // Set en-passant square if the moved pawn can be captured
            if ((to ^ from) == 16
                && (attacks_from_PS(PieceType.PAWN, to - Square.pawn_push(us), us) & pieces_CtPt(them, PieceType.PAWN)) != 0)
            {
                st.epSquare = (from + to)/2;
                k ^= Zobrist.enpassant[Square.file_of(st.epSquare)];
            }

            else if (Move.type_of(m) == MoveType.PROMOTION)
            {
                var promotion = (int)Move.promotion_type(m);

                Debug.Assert(Rank.relative_rank_CtSt(us, to) == Rank.RANK_8);
                Debug.Assert(promotion >= PieceType.KNIGHT && promotion <= PieceType.QUEEN);

                remove_piece(us, PieceType.PAWN, to);
                put_piece(us, PieceType.Create(promotion), to);

                // Update hash keys
                k ^= Zobrist.psq[us, PieceType.PAWN, to] ^ Zobrist.psq[us, promotion, to];
                st.pawnKey ^= Zobrist.psq[us, PieceType.PAWN, to];
                st.materialKey ^= Zobrist.psq[us, promotion, pieceCount[us, promotion] - 1]
                                  ^ Zobrist.psq[us, PieceType.PAWN, pieceCount[us, PieceType.PAWN]];

                // Update incremental score
                st.psq += PSQT.psq[us, promotion, to] - PSQT.psq[us, PieceType.PAWN, to];

                // Update material
                st.nonPawnMaterial[us] += Value.PieceValue[(int) Phase.MG][promotion];
            }

            // Update pawn hash key and prefetch access to pawnsTable
            st.pawnKey ^= Zobrist.psq[us, PieceType.PAWN, from] ^ Zobrist.psq[us, PieceType.PAWN, to];

            // Reset rule 50 draw counter
            st.rule50 = 0;
        }

        // Update incremental scores
        st.psq += PSQT.psq[us, pt, to] - PSQT.psq[us, pt, @from];

        // Set capture piece
        st.capturedType = PieceType.Create(captured);

        // Update the key with the final value
        st.key = k;

        // Calculate checkers bitboard (if move gives check)
        st.checkersBB = givesCheck
            ? attackers_to(square(PieceType.KING, them)) & pieces_Ct(us)
            : Bitboard.Create(0);

        sideToMove = Color.opposite(sideToMove);

        Debug.Assert(pos_is_ok());
    }
Exemple #3
0
    /// Position::do(undo)_null_move() is used to do(undo) a "null move": It flips
    /// the side to move without executing any move on the board.
    internal void do_null_move(StateInfo newSt)
    {
        Debug.Assert(checkers() == 0);
        Debug.Assert(newSt != st);

        newSt.copyFrom(st);

        newSt.previous = st;
        st = newSt;

        if (st.epSquare != Square.SQ_NONE)
        {
            st.key ^= Zobrist.enpassant[Square.file_of(st.epSquare)];
            st.epSquare = Square.SQ_NONE;
        }

        st.key ^= Zobrist.side;

        ++st.rule50;
        st.pliesFromNull = 0;

        sideToMove = Color.opposite(sideToMove);

        Debug.Assert(pos_is_ok());
    }