internal static void init()
 {
     for (int i = 0; i < Constants.BROKER_SLOTS; i++)
     {
         _pool[i] = new CheckInfo[0];
     }
 }
 internal static CheckInfo GetObject()
 {
     int slotID = System.Threading.Thread.CurrentThread.ManagedThreadId & Constants.BROKER_SLOT_MASK;
     if (_cnt[slotID] == _pool[slotID].Length)
     {
         int poolLength = _pool[slotID].Length;
         CheckInfo[] temp = new CheckInfo[poolLength + Constants.BrokerCapacity];
         Array.Copy(_pool[slotID], temp, poolLength);
         for (int i = 0; i < Constants.BrokerCapacity; i++)
         {
             temp[poolLength + i] = new CheckInfo();
         }
         _pool[slotID] = temp;
     }
     return _pool[slotID][_cnt[slotID]++];
 }
Exemple #3
0
        private static void generate_all(
            GenType type,
            Position pos,
            MoveStack[] mlist,
            ref int mpos,
            int us,
            ulong target,
            CheckInfo ci)
        {
            var Checks = type == GenType.QUIET_CHECKS;

            generate_pawn_moves(us, type, pos, mlist, ref mpos, target, ci);

            generate_moves(PieceTypeC.KNIGHT, Checks, pos, mlist, ref mpos, us, target, ci);
            generate_moves(PieceTypeC.BISHOP, Checks, pos, mlist, ref mpos, us, target, ci);
            generate_moves(PieceTypeC.ROOK, Checks, pos, mlist, ref mpos, us, target, ci);
            generate_moves(PieceTypeC.QUEEN, Checks, pos, mlist, ref mpos, us, target, ci);

            if (!Checks && type != GenType.EVASIONS)
            {
                Square from = pos.king_square(us);
                Bitboard b = Position.attacks_from_KING(from) & target;
                // SERIALIZE(b);
                while (b != 0)
                {
#if X64
                    Bitboard bb = b;
                    b &= (b - 1);
                 mlist[mpos++].move = ((Utils.BSFTable[((bb & (0xffffffffffffffff - bb + 1)) * DeBruijn_64) >> 58]) | (from << 6));
#else
                    mlist[mpos++].move = Utils.make_move(from, Utils.pop_lsb(ref b));
#endif
                }
            }
            
            if (type != GenType.CAPTURES && type != GenType.EVASIONS && pos.can_castle_C(us) != 0)
            {
                generate_castle(CastlingSideC.KING_SIDE, Checks, pos, mlist, ref mpos, us);
                generate_castle(CastlingSideC.QUEEN_SIDE, Checks, pos, mlist, ref mpos, us);
            }
        }
Exemple #4
0
        private static void generate_moves(
            int Pt,
            bool Checks,
            Position pos,
            MoveStack[] mlist,
            ref int mpos,
            int us,
            ulong target,
            CheckInfo ci)
        {
            Debug.Assert(Pt != PieceTypeC.KING && Pt != PieceTypeC.PAWN);

            var pl = pos.pieceList[us][Pt];
            var plPos = 0;
            
            for (var from = pl[plPos]; from != SquareC.SQ_NONE; from = pl[++plPos])
            {
                if (Checks)
                {
                    if ((Pt == PieceTypeC.BISHOP || Pt == PieceTypeC.ROOK || Pt == PieceTypeC.QUEEN)
                        && ((Utils.PseudoAttacks[Pt][from] & (ulong)target & ci.checkSq[Pt]) == 0))
                    {
                        continue;
                    }

                    if ((ci.dcCandidates != 0) && (Utils.bit_is_set(ci.dcCandidates, from) != 0))
                    {
                        continue;
                    }
                }

                var b = pos.attacks_from_PTS(Pt, from) & (ulong)target;

                if (Checks)
                {
                    b &= ci.checkSq[Pt];
                }

                // SERIALIZE(b);
                while (b != 0)
                {
                    mlist[mpos++].move = Utils.make_move(from, Utils.pop_lsb(ref b));
                }
            }
        }
Exemple #5
0
        private static void generate_promotions(
            GenType Type,
            int Delta,
            MoveStack[] ms,
            ref int mpos,
            ulong pawnsOn7,
            ulong target,
            CheckInfo ci)
        {
            var b = move_pawns(Delta, pawnsOn7) & target;
            while (b != 0)
            {
                var to = Utils.pop_lsb(ref b);

                if (Type == GenType.CAPTURES || Type == GenType.EVASIONS || Type == GenType.NON_EVASIONS)
                {
                    ms[mpos++].move = Utils.make(to - Delta, to, MoveTypeC.PROMOTION, PieceTypeC.QUEEN);
                }

                if (Type == GenType.QUIETS || Type == GenType.EVASIONS || Type == GenType.NON_EVASIONS)
                {
                    ms[mpos++].move = Utils.make(to - Delta, to, MoveTypeC.PROMOTION, PieceTypeC.ROOK);
                    ms[mpos++].move = Utils.make(to - Delta, to, MoveTypeC.PROMOTION, PieceTypeC.BISHOP);
                    ms[mpos++].move = Utils.make(to - Delta, to, MoveTypeC.PROMOTION, PieceTypeC.KNIGHT);
                }

                // Knight-promotion is the only one that can give a direct check not
                // already included in the queen-promotion.
                if (Type == GenType.QUIET_CHECKS
                    && (Utils.bit_is_set(Utils.StepAttacksBB[PieceC.W_KNIGHT][to], ci.ksq) != 0))
                {
                    ms[mpos++].move = Utils.make(to - Delta, to, MoveTypeC.PROMOTION, PieceTypeC.KNIGHT);
                }
            }
        }
Exemple #6
0
        private static void generate_pawn_moves(
            int Us,
            GenType Type,
            Position pos,
            MoveStack[] ms,
            ref int mpos,
            ulong target,
            CheckInfo ci)
        {
            // Compute our parametrized parameters at compile time, named according to
            // the point of view of white side.
            var Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);
            var TRank8BB = (Us == ColorC.WHITE ? Constants.Rank8BB : Constants.Rank1BB);
            var TRank7BB = (Us == ColorC.WHITE ? Constants.Rank7BB : Constants.Rank2BB);
            var TRank3BB = (Us == ColorC.WHITE ? Constants.Rank3BB : Constants.Rank6BB);
            var UP = (Us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S);
            var RIGHT = (Us == ColorC.WHITE ? SquareC.DELTA_NE : SquareC.DELTA_SW);
            var LEFT = (Us == ColorC.WHITE ? SquareC.DELTA_NW : SquareC.DELTA_SE);

            ulong b1, b2, dc1, dc2, emptySquares = 0;
            int to;

            var pawnsOn7 = (pos.byTypeBB[PieceTypeC.PAWN] & pos.byColorBB[Us]) & TRank7BB;
            var pawnsNotOn7 = (pos.byTypeBB[PieceTypeC.PAWN] & pos.byColorBB[Us]) & ~TRank7BB;

            var enemies = (Type == GenType.EVASIONS
                               ? pos.byColorBB[Them] & target
                               : Type == GenType.CAPTURES ? target : pos.byColorBB[Them]);

            // Single and double pawn pushes, no promotions
            if (Type != GenType.CAPTURES)
            {
                emptySquares = (Type == GenType.QUIETS ? target : ~pos.occupied_squares);

                b1 = move_pawns(UP, pawnsNotOn7) & emptySquares;
                b2 = move_pawns(UP, b1 & TRank3BB) & emptySquares;

                if (Type == GenType.EVASIONS) // Consider only blocking squares
                {
                    b1 &= target;
                    b2 &= target;
                }

                if (Type == GenType.QUIET_CHECKS)
                {
                    b1 &= Utils.StepAttacksBB[((Them << 3) | PieceTypeC.PAWN)][ci.ksq];
                    b2 &= Utils.StepAttacksBB[((Them << 3) | PieceTypeC.PAWN)][ci.ksq];

                    // Add pawn pushes which give discovered check. This is possible only
                    // if the pawn is not on the same file as the enemy king, because we
                    // don't generate captures. Note that a possible discovery check
                    // promotion has been already generated among captures.
                    if ((pawnsNotOn7 & ci.dcCandidates) != 0) // Target is dc bitboard
                    {
                        dc1 = move_pawns(UP, pawnsNotOn7 & ci.dcCandidates) & emptySquares & ~(Utils.FileBB[ci.ksq & 7]);
                        dc2 = move_pawns(UP, dc1 & TRank3BB) & emptySquares;

                        b1 |= dc1;
                        b2 |= dc2;
                    }
                }

                while (b1 != 0)
                {
                    to = Utils.pop_lsb(ref b1);
                    ms[mpos++].move = (to | ((to - UP) << 6));
                }
                while (b2 != 0)
                {
                    to = Utils.pop_lsb(ref b2);
                    ms[mpos++].move = (to | ((to - UP - UP) << 6));
                }
            }

            // Promotions and underpromotions
            if ((pawnsOn7 != 0) && (Type != GenType.EVASIONS || ((target & TRank8BB) != 0)))
            {
                if (Type == GenType.CAPTURES)
                {
                    emptySquares = ~pos.occupied_squares;
                }

                if (Type == GenType.EVASIONS)
                {
                    emptySquares &= target;
                }

                generate_promotions(Type, RIGHT, ms, ref mpos, pawnsOn7, enemies, ci);
                generate_promotions(Type, LEFT, ms, ref mpos, pawnsOn7, enemies, ci);
                generate_promotions(Type, UP, ms, ref mpos, pawnsOn7, emptySquares, ci);
            }

            // Standard and en-passant captures
            if (Type == GenType.CAPTURES || Type == GenType.EVASIONS || Type == GenType.NON_EVASIONS)
            {
                b1 = move_pawns(RIGHT, pawnsNotOn7) & enemies;
                b2 = move_pawns(LEFT, pawnsNotOn7) & enemies;

                while (b1 != 0)
                {
                    to = Utils.pop_lsb(ref b1);
                    ms[mpos++].move = (to | ((to - RIGHT) << 6));
                }
                while (b2 != 0)
                {
                    to = Utils.pop_lsb(ref b2);
                    ms[mpos++].move = (to | ((to - LEFT) << 6));
                }

                if (pos.st.epSquare != SquareC.SQ_NONE)
                {
                    Debug.Assert(Utils.rank_of(pos.st.epSquare) == Utils.relative_rank_CR(Us, RankC.RANK_6));

                    // An en passant capture can be an evasion only if the checking piece
                    // is the double pushed pawn and so is in the target. Otherwise this
                    // is a discovery check and we are forced to do otherwise.
                    if (Type == GenType.EVASIONS && (((target & Utils.SquareBB[pos.st.epSquare - UP]) == 0)))
                    {
                        return;
                    }

                    b1 = pawnsNotOn7 & Utils.StepAttacksBB[((Them << 3) | PieceTypeC.PAWN)][pos.st.epSquare];

                    Debug.Assert(b1 != 0);

                    while (b1 != 0)
                    {
                        ms[mpos++].move = Utils.make(Utils.pop_lsb(ref b1), pos.st.epSquare, MoveTypeC.ENPASSANT);
                    }
                }
            }
        }
Exemple #7
0
        private static void generate_direct_checks(PieceType Pt, Position pos, MoveStack[] ms, ref int mpos, Color us, CheckInfo ci)
        {
            Debug.Assert(Pt != PieceTypeC.KING && Pt != PieceTypeC.PAWN);

            Bitboard b, target;

            Square[] pl = pos.pieceList[us][Pt];
            int plPos = 0;
            Square from = pl[plPos];

            if ((from = pl[plPos]) != SquareC.SQ_NONE)
            {
                target = ci.checkSq[Pt] & ~pos.occupied_squares; // Non capture checks only

                do
                {
                    if ((Pt == PieceTypeC.BISHOP || Pt == PieceTypeC.ROOK || Pt == PieceTypeC.QUEEN)
                        && ((Utils.PseudoAttacks[Pt][from] & target) == 0))
                        continue;

                    if ((ci.dcCandidates != 0) && (Utils.bit_is_set(ci.dcCandidates, from) != 0))
                        continue;

                    b = pos.attacks_from_PTS(Pt, from) & target;
                    while (b != 0) { ms[mpos++].move = Utils.make_move(from, Utils.pop_1st_bit(ref b)); }

                } while ((from = pl[++plPos]) != SquareC.SQ_NONE);
            }
        }
Exemple #8
0
        internal void do_move(Move m, StateInfo newSt, CheckInfo ci, bool moveIsCheck)
        {
            Debug.Assert(Utils.is_ok_M(m));
            Debug.Assert(newSt != st);

            nodes++;
            Key k = st.key;

            newSt.pawnKey = st.pawnKey;
            newSt.materialKey = st.materialKey;
            newSt.npMaterialWHITE = st.npMaterialWHITE;
            newSt.npMaterialBLACK = st.npMaterialBLACK;
            newSt.castleRights = st.castleRights;
            newSt.rule50 = st.rule50;
            newSt.pliesFromNull = st.pliesFromNull;
            newSt.psqScore = st.psqScore;
            newSt.epSquare = st.epSquare;

            newSt.previous = st;
            st = newSt;

            // Update side to move
            k ^= zobSideToMove;

            // Increment the 50 moves rule draw counter. Resetting it to zero in the
            // case of a capture or a pawn move is taken care of later.
            st.rule50++;
            st.pliesFromNull++;

            if ((m & (3 << 14)) == (3 << 14))
            {
                st.key = k;
                do_castle_move(true, m);
                return;
            }

            Color us = sideToMove;
            Color them = us ^ 1;
            Square from = ((m >> 6) & 0x3F);
            Square to = (m & 0x3F);
            Piece piece = board[from];
            PieceType pt = (piece & 7);
            PieceType capture = ((m & (3 << 14)) == (2 << 14)) ? PieceTypeC.PAWN : (board[to] & 7);

            Debug.Assert(Utils.color_of(piece) == us);
            Debug.Assert(Utils.color_of(piece_on(to)) != us);
            Debug.Assert(capture != PieceTypeC.KING);

            if (capture != 0)
            {
                Square capsq = to;

                // If the captured piece is a pawn, update pawn hash key, otherwise
                // update non-pawn material.
                if (capture == PieceTypeC.PAWN)
                {
                    if ((m & (3 << 14)) == (2 << 14))
                    {
                        capsq += (them == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S);

                        Debug.Assert(pt == PieceTypeC.PAWN);
                        Debug.Assert(to == st.epSquare);
                        Debug.Assert(Utils.relative_rank_CS(us, to) == RankC.RANK_6);
                        Debug.Assert(piece_on(to) == PieceC.NO_PIECE);
                        Debug.Assert(piece_on(capsq) == Utils.make_piece(them, PieceTypeC.PAWN));

                        board[capsq] = PieceC.NO_PIECE;
                    }

                    st.pawnKey ^= zobrist[them][PieceTypeC.PAWN][capsq];
                }
                else
                {
                    if (them == 0) { st.npMaterialWHITE -= PieceValueMidgame[capture]; } else { st.npMaterialBLACK -= PieceValueMidgame[capture]; }
                }

                // Remove the captured piece
                Bitboard capPieceMask = Utils.SquareBB[capsq];
                occupied_squares ^= capPieceMask;
                byTypeBB[capture] ^= capPieceMask;
                byColorBB[them] ^= capPieceMask;

                // Update piece list, move the last piece at index[capsq] position and
                // shrink the list.
                //
                // WARNING: This is a not revresible operation. When we will reinsert the
                // captured piece in undo_move() we will put it at the end of the list and
                // not in its original place, it means index[] and pieceList[] are not
                // guaranteed to be invariant to a do_move() + undo_move() sequence.
                int[] plThemCapture = pieceList[them][capture];
                int pcThemCapture = --pieceCount[them][capture];
                Square lastSquare = plThemCapture[pcThemCapture];
                index[lastSquare] = index[capsq];
                plThemCapture[index[lastSquare]] = lastSquare;
                plThemCapture[pcThemCapture] = SquareC.SQ_NONE;

                // Update hash keys
                k ^= zobrist[them][capture][capsq];
                st.materialKey ^= zobrist[them][capture][pcThemCapture];

                // Update incremental scores
                st.psqScore -= pieceSquareTable[((them << 3) | capture)][capsq];

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

            // Update hash key
            k ^= zobrist[us][pt][from] ^ zobrist[us][pt][to];

            // Reset en passant square
            if (st.epSquare != SquareC.SQ_NONE)
            {
                k ^= zobEp[st.epSquare & 7];
                st.epSquare = SquareC.SQ_NONE;
            }

            // Update castle rights if needed
            if ((st.castleRights != 0) && ((castleRightsMask[from] | castleRightsMask[to]) != 0))
            {
                int cr = castleRightsMask[from] | castleRightsMask[to];
                k ^= zobCastle[st.castleRights & cr];
                st.castleRights &= ~cr;
            }

            // Move the piece
            Bitboard from_to_bb = Utils.SquareBB[from] ^ Utils.SquareBB[to];
            occupied_squares ^= from_to_bb;
            byTypeBB[pt] ^= from_to_bb;
            byColorBB[us] ^= from_to_bb;

            board[to] = board[from];
            board[from] = PieceC.NO_PIECE;

            // Update piece lists, index[from] is not updated and becomes stale. This
            // works as long as index[] is accessed just by known occupied squares.
            index[to] = index[from];
            pieceList[us][pt][index[to]] = to;

            // If the moving piece is a pawn do some special extra work
            if (pt == PieceTypeC.PAWN)
            {
                // Set en-passant square, only if moved pawn can be captured
                if ((to ^ from) == 16
                    && ((((Utils.StepAttacksBB[((us << 3) | PieceTypeC.PAWN)][from + (us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S)]) & (byTypeBB[PieceTypeC.PAWN] & byColorBB[them]))) != 0))
                {
                    st.epSquare = ((from + to) / 2);
                    k ^= zobEp[st.epSquare & 7];
                }

                if ((m & (3 << 14)) == (1 << 14))
                {
                    PieceType promotion = (((m >> 12) & 3) + 2);

                    Debug.Assert(Utils.relative_rank_CS(us, to) == RankC.RANK_8);
                    Debug.Assert(promotion >= PieceTypeC.KNIGHT && promotion <= PieceTypeC.QUEEN);

                    // Replace the pawn with the promoted piece
                    byTypeBB[PieceTypeC.PAWN] ^= Utils.SquareBB[to];
                    byTypeBB[promotion] |= Utils.SquareBB[to];
                    board[to] = ((us << 3) | promotion);

                    // Update piece lists, move the last pawn at index[to] position
                    // and shrink the list. Add a new promotion piece to the list.
                    int[] plUsPawn = pieceList[us][PieceTypeC.PAWN];
                    Square lastSquare = plUsPawn[--pieceCount[us][PieceTypeC.PAWN]];
                    index[lastSquare] = index[to];
                    plUsPawn[index[lastSquare]] = lastSquare;
                    plUsPawn[pieceCount[us][PieceTypeC.PAWN]] = SquareC.SQ_NONE;
                    index[to] = pieceCount[us][promotion];
                    pieceList[us][promotion][index[to]] = to;

                    // Update hash keys
                    k ^= zobrist[us][PieceTypeC.PAWN][to] ^ zobrist[us][promotion][to];
                    st.pawnKey ^= zobrist[us][PieceTypeC.PAWN][to];
                    st.materialKey ^= zobrist[us][promotion][pieceCount[us][promotion]++]
                                      ^ zobrist[us][PieceTypeC.PAWN][pieceCount[us][PieceTypeC.PAWN]];

                    // Update incremental score
                    st.psqScore += pieceSquareTable[((us << 3) | promotion)][to] - pieceSquareTable[((us << 3) | PieceTypeC.PAWN)][to];

                    // Update material
                    if (us == 0) { st.npMaterialWHITE += PieceValueMidgame[promotion]; }
                    else { st.npMaterialBLACK += PieceValueMidgame[promotion]; }
                }

                // Update pawn hash key
                st.pawnKey ^= zobrist[us][PieceTypeC.PAWN][from] ^ zobrist[us][PieceTypeC.PAWN][to];

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

            // Update incremental scores
            st.psqScore += (pieceSquareTable[piece][to] - pieceSquareTable[piece][from]);

            // Set capture piece
            st.capturedType = capture;

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

            // Update checkers bitboard, piece must be already moved
            st.checkersBB = 0;

            if (moveIsCheck)
            {
                if ((m & (3 << 14)) != 0)
                    st.checkersBB = attackers_to(pieceList[them][PieceTypeC.KING][0]) & byColorBB[us];
                else
                {
                    // Direct checks
                    if ((ci.checkSq[pt] & Utils.SquareBB[to]) != 0)
                    {
                        st.checkersBB |= Utils.SquareBB[to];
                    }

                    // Discovery checks
                    if ((ci.dcCandidates != 0) && ((ci.dcCandidates & Utils.SquareBB[from]) != 0))
                    {
                        if (pt != PieceTypeC.ROOK)
                            st.checkersBB |= attacks_from_ROOK(pieceList[them][PieceTypeC.KING][0]) & ((byTypeBB[PieceTypeC.ROOK] | byTypeBB[PieceTypeC.QUEEN]) & byColorBB[us]);

                        if (pt != PieceTypeC.BISHOP)
                            st.checkersBB |= attacks_from_BISHOP(pieceList[them][PieceTypeC.KING][0]) & ((byTypeBB[PieceTypeC.BISHOP] | byTypeBB[PieceTypeC.QUEEN]) & byColorBB[us]);
                    }
                }
            }

            // Finish
            sideToMove = sideToMove ^ 1;

            Debug.Assert(pos_is_ok());
        }
Exemple #9
0
        /// move_gives_check() tests whether a pseudo-legal move gives a check
        internal bool move_gives_check(Move m, CheckInfo ci)
        {
            Debug.Assert(Utils.is_ok_M(m));
            Debug.Assert(ci.dcCandidates == discovered_check_candidates());
            Debug.Assert(Utils.color_of(piece_moved(m)) == sideToMove);

            Square from = (m >> 6) & 0x3F;
            Square to = m & 0x3F;
            PieceType pt = board[from] & 7;

            // Direct check ?
            if ((ci.checkSq[pt] & Utils.SquareBB[to]) != 0)
                return true;

            // Discovery check ?
            if ((ci.dcCandidates != 0) && ((ci.dcCandidates & Utils.SquareBB[from]) != 0))
            {
                // For pawn and king moves we need to verify also direction
                if ((pt != PieceTypeC.PAWN && pt != PieceTypeC.KING)
                    || (((Utils.BetweenBB[from][to] | Utils.BetweenBB[from][pieceList[sideToMove ^ 1][PieceTypeC.KING][0]] | Utils.BetweenBB[to][pieceList[sideToMove ^ 1][PieceTypeC.KING][0]]) & (Utils.SquareBB[from] | Utils.SquareBB[to] | Utils.SquareBB[pieceList[sideToMove ^ 1][PieceTypeC.KING][0]])) == 0))
                    return true;
            }

            // Can we skip the ugly special cases ?
            if ((m & (3 << 14)) == 0)
                return false;

            Color us = sideToMove;
            Square ksq = pieceList[sideToMove ^ 1][PieceTypeC.KING][0];

            // Promotion with check ?
            if ((m & (3 << 14)) == (1 << 14))
            {
                return (attacks_from((((m >> 12) & 3) + 2), to, occupied_squares ^ Utils.SquareBB[from]) & Utils.SquareBB[ksq]) != 0;
            }

            // En passant capture with check ? We have already handled the case
            // of direct checks and ordinary discovered check, the only case we
            // need to handle is the unusual case of a discovered check through
            // the captured pawn.
            if ((m & (3 << 14)) == (2 << 14))
            {
                Square capsq = (((from >> 3) << 3) | (to & 7));
                Bitboard b = (occupied_squares ^ Utils.SquareBB[from] ^ Utils.SquareBB[capsq]) | Utils.SquareBB[to];
                return ((Utils.rook_attacks_bb(ksq, b) & ((byTypeBB[PieceTypeC.ROOK] | byTypeBB[PieceTypeC.QUEEN]) & byColorBB[us])) != 0)
                      || ((Utils.bishop_attacks_bb(ksq, b) & ((byTypeBB[PieceTypeC.BISHOP] | byTypeBB[PieceTypeC.QUEEN]) & byColorBB[us])) != 0);
            }

            // Castling with check ?
            if ((m & (3 << 14)) == (3 << 14))
            {
                Square kfrom = from;
                Square rfrom = to; // 'King captures the rook' notation
                Square kto = ((rfrom > kfrom ? SquareC.SQ_G1 : SquareC.SQ_C1) ^ (us * 56));
                Square rto = ((rfrom > kfrom ? SquareC.SQ_F1 : SquareC.SQ_D1) ^ (us * 56));
                Bitboard b = (occupied_squares ^ Utils.SquareBB[kfrom] ^ Utils.SquareBB[rfrom]) | Utils.SquareBB[rto] | Utils.SquareBB[kto];
                return (Utils.rook_attacks_bb(rto, b) & Utils.SquareBB[ksq]) != 0;
            }

            return false;
        }
Exemple #10
0
        internal void do_move(int m, StateInfo newSt, CheckInfo ci, bool moveIsCheck)
        {
            Debug.Assert(Utils.is_ok_M(m));
            Debug.Assert(newSt != this.st);

            this.nodes++;
            var k = this.st.key;

            newSt.pawnKey = this.st.pawnKey;
            newSt.materialKey = this.st.materialKey;
            newSt.npMaterialWHITE = this.st.npMaterialWHITE;
            newSt.npMaterialBLACK = this.st.npMaterialBLACK;
            newSt.castleRights = this.st.castleRights;
            newSt.rule50 = this.st.rule50;
            newSt.pliesFromNull = this.st.pliesFromNull;
            newSt.psqScore = this.st.psqScore;
            newSt.epSquare = this.st.epSquare;

            newSt.previous = this.st;
            this.st = newSt;

            // Update side to move
            k ^= Zobrist.side;

            // Increment the 50 moves rule draw counter. Resetting it to zero in the
            // case of a capture or a pawn move is taken care of later.
            this.st.rule50++;
            this.st.pliesFromNull++;

            var us = this.sideToMove;
            var them = us ^ 1;
            Square from = Utils.from_sq(m);
            Square to = Utils.to_sq(m);
            Piece piece = piece_on(from);
            PieceType pt = Utils.type_of(piece);
            PieceType capture = Utils.type_of_move(m) == MoveTypeC.ENPASSANT ? PieceTypeC.PAWN : Utils.type_of(piece_on(to));

            Debug.Assert(Utils.color_of(piece) == us);
            Debug.Assert(piece_on(to) == PieceC.NO_PIECE || Utils.color_of(piece_on(to)) == them || Utils.type_of_move(m) == MoveTypeC.CASTLING);
            Debug.Assert(capture != PieceTypeC.KING);

            if (Utils.type_of_move(m) == MoveTypeC.CASTLING)
            {
                Debug.Assert(piece == Utils.make_piece(us, PieceTypeC.KING));
                
                bool kingSide = to > from;
                Square rfrom = to; // Castle is encoded as "king captures friendly rook"
                Square rto = Utils.relative_square(us, kingSide ? SquareC.SQ_F1 : SquareC.SQ_D1);
                to = Utils.relative_square(us, kingSide ? SquareC.SQ_G1 : SquareC.SQ_C1);
                capture = PieceTypeC.NO_PIECE_TYPE;
                
                do_castle(from, to, rfrom, rto);
                
                st.psqScore += psq_delta(Utils.make_piece(us, PieceTypeC.ROOK), rfrom, rto);
                k ^= Zobrist.psq[us][PieceTypeC.ROOK][rfrom] ^ Zobrist.psq[us][PieceTypeC.ROOK][rto];
            }

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

                // If the captured piece is a pawn, update pawn hash key, otherwise
                // update non-pawn material.
                if (capture == PieceTypeC.PAWN)
                {
                    if (Utils.type_of_move(m) == MoveTypeC.ENPASSANT)
                    {
                        capsq += (them == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S);

                        Debug.Assert(pt == PieceTypeC.PAWN);
                        Debug.Assert(to == this.st.epSquare);
                        Debug.Assert(Utils.relative_rank_CS(us, to) == RankC.RANK_6);
                        Debug.Assert(this.piece_on(to) == PieceC.NO_PIECE);
                        Debug.Assert(this.piece_on(capsq) == Utils.make_piece(them, PieceTypeC.PAWN));

                        this.board[capsq] = PieceC.NO_PIECE;
                    }

                    this.st.pawnKey ^= Zobrist.psq[them][PieceTypeC.PAWN][capsq];
                }
                else
                {
                    if (them == 0)
                    {
                        this.st.npMaterialWHITE -= PieceValue[PhaseC.MG][capture];
                    }
                    else
                    {
                        this.st.npMaterialBLACK -= PieceValue[PhaseC.MG][capture];
                    }
                }

                // Remove the captured piece
                var capPieceMask = Utils.SquareBB[capsq];
                this.occupied_squares ^= capPieceMask;
                this.byTypeBB[capture] ^= capPieceMask;
                this.byColorBB[them] ^= capPieceMask;

                // Update piece list, move the last piece at index[capsq] position and
                // shrink the list.
                //
                // WARNING: This is a not revresible operation. When we will reinsert the
                // captured piece in undo_move() we will put it at the end of the list and
                // not in its original place, it means index[] and pieceList[] are not
                // guaranteed to be invariant to a do_move() + undo_move() sequence.
                var plThemCapture = this.pieceList[them][capture];
                var pcThemCapture = --this.pieceCount[them][capture];
                var lastSquare = plThemCapture[pcThemCapture];
                this.index[lastSquare] = this.index[capsq];
                plThemCapture[this.index[lastSquare]] = lastSquare;
                plThemCapture[pcThemCapture] = SquareC.SQ_NONE;

                // Update hash keys
                k ^= Zobrist.psq[them][capture][capsq];
                this.st.materialKey ^= Zobrist.psq[them][capture][pcThemCapture];

                // Update incremental scores
                this.st.psqScore -= Zobrist.PieceSquareTable[((them << 3) | capture)][capsq];

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

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

            // Reset en passant square
            if (this.st.epSquare != SquareC.SQ_NONE)
            {
                k ^= Zobrist.enpassant[this.st.epSquare & 7];
                this.st.epSquare = SquareC.SQ_NONE;
            }

            // Update castle rights if needed
            if ((this.st.castleRights != 0) && ((this.castleRightsMask[from] | this.castleRightsMask[to]) != 0))
            {
                var cr = this.castleRightsMask[from] | this.castleRightsMask[to];
                k ^= Zobrist.castle[this.st.castleRights & cr];
                this.st.castleRights &= ~cr;
            }

            // Move the piece. The tricky Chess960 castle is handled earlier
            if (Utils.type_of_move(m) != MoveTypeC.CASTLING)
            {
                Bitboard from_to_bb = Utils.SquareBB[from] ^ Utils.SquareBB[to];
                occupied_squares ^= from_to_bb;
                byTypeBB[pt] ^= from_to_bb;
                byColorBB[us] ^= from_to_bb;
                
                board[from] = PieceC.NO_PIECE;
                board[to] = piece;
                
                      // Update piece lists, index[from] is not updated and becomes stale. This
                      // works as long as index[] is accessed just by known occupied squares.
                index[to] = index[from];
                pieceList[us][pt][index[to]] = to;
            }

            // If the moving piece is a pawn do some special extra work
            if (pt == PieceTypeC.PAWN)
            {
                // Set en-passant square, only if moved pawn can be captured
                if ((to ^ from) == 16
                    && ((((Utils.StepAttacksBB[((us << 3) | PieceTypeC.PAWN)][
                        from + (us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S)])
                          & (this.byTypeBB[PieceTypeC.PAWN] & this.byColorBB[them]))) != 0))
                {
                    this.st.epSquare = ((from + to) / 2);
                    k ^= Zobrist.enpassant[this.st.epSquare & 7];
                }

                if (Utils.type_of_move(m) == MoveTypeC.PROMOTION)
                {
                    var promotion = (((m >> 12) & 3) + 2);

                    Debug.Assert(Utils.relative_rank_CS(us, to) == RankC.RANK_8);
                    Debug.Assert(promotion >= PieceTypeC.KNIGHT && promotion <= PieceTypeC.QUEEN);

                    // Replace the pawn with the promoted piece
                    this.byTypeBB[PieceTypeC.PAWN] ^= Utils.SquareBB[to];
                    this.byTypeBB[promotion] |= Utils.SquareBB[to];
                    this.board[to] = ((us << 3) | promotion);

                    // Update piece lists, move the last pawn at index[to] position
                    // and shrink the list. Add a new promotion piece to the list.
                    var plUsPawn = this.pieceList[us][PieceTypeC.PAWN];
                    var lastSquare = plUsPawn[--this.pieceCount[us][PieceTypeC.PAWN]];
                    this.index[lastSquare] = this.index[to];
                    plUsPawn[this.index[lastSquare]] = lastSquare;
                    plUsPawn[this.pieceCount[us][PieceTypeC.PAWN]] = SquareC.SQ_NONE;
                    this.index[to] = this.pieceCount[us][promotion];
                    this.pieceList[us][promotion][this.index[to]] = to;

                    // Update hash keys
                    k ^= Zobrist.psq[us][PieceTypeC.PAWN][to] ^ Zobrist.psq[us][promotion][to];
                    this.st.pawnKey ^= Zobrist.psq[us][PieceTypeC.PAWN][to];
                    this.st.materialKey ^= Zobrist.psq[us][promotion][this.pieceCount[us][promotion]++]
                                           ^ Zobrist.psq[us][PieceTypeC.PAWN][this.pieceCount[us][PieceTypeC.PAWN]];

                    // Update incremental score
                    this.st.psqScore += Zobrist.PieceSquareTable[((us << 3) | promotion)][to]
                                        - Zobrist.PieceSquareTable[((us << 3) | PieceTypeC.PAWN)][to];

                    // Update material
                    if (us == 0)
                    {
                        this.st.npMaterialWHITE += PieceValue[PhaseC.MG][promotion];
                    }
                    else
                    {
                        this.st.npMaterialBLACK += PieceValue[PhaseC.MG][promotion];
                    }
                }

                // Update pawn hash key
                this.st.pawnKey ^= Zobrist.psq[us][PieceTypeC.PAWN][from] ^ Zobrist.psq[us][PieceTypeC.PAWN][to];

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

            // Update incremental scores
            this.st.psqScore += (Zobrist.PieceSquareTable[piece][to] - Zobrist.PieceSquareTable[piece][from]);

            // Set capture piece
            this.st.capturedType = capture;

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

            // Update checkers bitboard, piece must be already moved
            this.st.checkersBB = 0;

            if (moveIsCheck)
            {
                if (Utils.type_of_move(m) != MoveTypeC.NORMAL)
                {
                    this.st.checkersBB = this.attackers_to(this.pieceList[them][PieceTypeC.KING][0])
                                         & this.byColorBB[us];
                }
                else
                {
                    // Direct checks
                    if ((ci.checkSq[pt] & Utils.SquareBB[to]) != 0)
                    {
                        this.st.checkersBB |= Utils.SquareBB[to];
                    }

                    // Discovery checks
                    if ((ci.dcCandidates != 0) && ((ci.dcCandidates & Utils.SquareBB[from]) != 0))
                    {
                        if (pt != PieceTypeC.ROOK)
                        {
                            this.st.checkersBB |= this.attacks_from_ROOK(this.pieceList[them][PieceTypeC.KING][0])
                                                  & ((this.byTypeBB[PieceTypeC.ROOK] | this.byTypeBB[PieceTypeC.QUEEN])
                                                     & this.byColorBB[us]);
                        }

                        if (pt != PieceTypeC.BISHOP)
                        {
                            this.st.checkersBB |= this.attacks_from_BISHOP(this.pieceList[them][PieceTypeC.KING][0])
                                                  & ((this.byTypeBB[PieceTypeC.BISHOP] | this.byTypeBB[PieceTypeC.QUEEN])
                                                     & this.byColorBB[us]);
                        }
                    }
                }
            }

            // Finish
            this.sideToMove = this.sideToMove ^ 1;

            Debug.Assert(this.pos_is_ok());
        }
Exemple #11
0
        /// move_gives_check() tests whether a pseudo-legal move gives a check
        internal bool move_gives_check(int m, CheckInfo ci)
        {
            Debug.Assert(Utils.is_ok_M(m));
            Debug.Assert(ci.dcCandidates == this.discovered_check_candidates());
            Debug.Assert(Utils.color_of(this.piece_moved(m)) == this.sideToMove);

            var from = (m >> 6) & 0x3F;
            var to = m & 0x3F;
            var pt = this.board[from] & 7;

            // Direct check ?
            if ((ci.checkSq[pt] & Utils.SquareBB[to]) != 0)
            {
                return true;
            }

            // Discovery check ?
            if ((ci.dcCandidates != 0) && ((ci.dcCandidates & Utils.SquareBB[from]) != 0))
            {
                // For pawn and king moves we need to verify also direction
                if ((pt != PieceTypeC.PAWN && pt != PieceTypeC.KING)
                    || (((Utils.BetweenBB[from][to]
                          | Utils.BetweenBB[from][this.pieceList[this.sideToMove ^ 1][PieceTypeC.KING][0]]
                          | Utils.BetweenBB[to][this.pieceList[this.sideToMove ^ 1][PieceTypeC.KING][0]])
                         & (Utils.SquareBB[from] | Utils.SquareBB[to]
                            | Utils.SquareBB[this.pieceList[this.sideToMove ^ 1][PieceTypeC.KING][0]])) == 0))
                {
                    return true;
                }
            }

            // Can we skip the ugly special cases ?
            if (Utils.type_of_move(m) == MoveTypeC.NORMAL)
            {
                return false;
            }

            var us = this.sideToMove;
            var ksq = this.pieceList[this.sideToMove ^ 1][PieceTypeC.KING][0];

            switch (Utils.type_of_move(m))
            {
                case MoveTypeC.PROMOTION:
                    return (attacks_from((((m >> 12) & 3) + 2), to, this.occupied_squares ^ Utils.SquareBB[from]) & Utils.SquareBB[ksq]) != 0;
                
                    // En passant capture with check ? We have already handled the case
                // of direct checks and ordinary discovered check, the only case we
                // need to handle is the unusual case of a discovered check through
                // the captured pawn.
                case MoveTypeC.ENPASSANT:
                    {
                        var capsq = (((from >> 3) << 3) | (to & 7));
                        var b = (this.occupied_squares ^ Utils.SquareBB[from] ^ Utils.SquareBB[capsq]) | Utils.SquareBB[to];
                        return ((Utils.rook_attacks_bb(ksq, b)
                                 & ((this.byTypeBB[PieceTypeC.ROOK] | this.byTypeBB[PieceTypeC.QUEEN]) & this.byColorBB[us]))
                                != 0)
                               || ((Utils.bishop_attacks_bb(ksq, b)
                                    & ((this.byTypeBB[PieceTypeC.BISHOP] | this.byTypeBB[PieceTypeC.QUEEN]) & this.byColorBB[us]))
                                   != 0);
                    }
                case MoveTypeC.CASTLING:
                    if (Utils.type_of_move(m) == MoveTypeC.CASTLING)
                    {
                        var kfrom = from;
                        var rfrom = to; // 'King captures the rook' notation
                        var kto = ((rfrom > kfrom ? SquareC.SQ_G1 : SquareC.SQ_C1) ^ (us * 56));
                        var rto = ((rfrom > kfrom ? SquareC.SQ_F1 : SquareC.SQ_D1) ^ (us * 56));
                        var b = (this.occupied_squares ^ Utils.SquareBB[kfrom] ^ Utils.SquareBB[rfrom]) | Utils.SquareBB[rto]
                                | Utils.SquareBB[kto];
                        return (Utils.rook_attacks_bb(rto, b) & Utils.SquareBB[ksq]) != 0;
                    }

                    Debug.Assert(false);
                    return false;
                default:
                    Debug.Assert(false);
                    return false;
            }
        }