Пример #1
0
        internal void CreateCheckInfo(Position pos)
        {
            Color them = pos.sideToMove ^ 1;
            ksq = pos.pieceList[them][PieceTypeC.KING][0];

            pinned = pos.pinned_pieces();
            dcCandidates = pos.discovered_check_candidates();

            checkSq[PieceTypeC.PAWN] = Utils.StepAttacksBB[((them << 3) | PieceTypeC.PAWN)][ksq];
            checkSq[PieceTypeC.KNIGHT] = Utils.StepAttacksBB_KNIGHT[ksq];
#if X64
            checkSq[PieceTypeC.BISHOP] = Utils.BAttacks[ksq][(((pos.occupied_squares & Utils.BMasks[ksq]) * Utils.BMagics[ksq]) >> Utils.BShifts[ksq])];
            checkSq[PieceTypeC.ROOK] = Utils.RAttacks[ksq][(((pos.occupied_squares & Utils.RMasks[ksq]) * Utils.RMagics[ksq]) >> Utils.RShifts[ksq])];
#else
            checkSq[PieceTypeC.BISHOP] = pos.attacks_from_BISHOP(ksq);
            checkSq[PieceTypeC.ROOK] = pos.attacks_from_ROOK(ksq);
#endif
            checkSq[PieceTypeC.QUEEN] = checkSq[PieceTypeC.BISHOP] | checkSq[PieceTypeC.ROOK];
            checkSq[PieceTypeC.KING] = 0;
        }
Пример #2
0
        // evaluate_king<>() assigns bonuses and penalties to a king of a given color
        private static int evaluate_king(
            int Us,
            bool Trace,
            Position pos,
            EvalInfo ei,
            ref Value marginsWHITE,
            ref Value marginsBLACK)
        {
            var Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);

            ulong undefended, b, b1, b2, safe;
            int attackUnits;
            int kingScore;
            var ksq = pos.pieceList[Us][PieceTypeC.KING][0];

            // King shelter and enemy pawns storm
            var score = ei.pi.king_safety(Us, pos, ksq);

            // King safety. This is quite complicated, and is almost certainly far
            // from optimally tuned.
            if (ei.kingAttackersCount[Them] >= 2 && (ei.kingAdjacentZoneAttacksCount[Them] != 0))
            {
                // Find the attacked squares around the king which has no defenders
                // apart from the king itself
                undefended = ei.attackedBy[Them][0] & ei.attackedBy[Us][PieceTypeC.KING];
                undefended &=
                    ~(ei.attackedBy[Us][PieceTypeC.PAWN] | ei.attackedBy[Us][PieceTypeC.KNIGHT]
                      | ei.attackedBy[Us][PieceTypeC.BISHOP] | ei.attackedBy[Us][PieceTypeC.ROOK]
                      | ei.attackedBy[Us][PieceTypeC.QUEEN]);

#if X64
    // Initialize the 'attackUnits' variable, which is used later on as an
    // index to the KingDangerTable[] array. The initial value is based on
    // the number and types of the enemy's attacking pieces, the number of
    // attacked and undefended squares around our king, the square of the
    // king, and the quality of the pawn shelter.
                b = undefended - ((undefended >> 1) & 0x5555555555555555UL);
                b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                attackUnits = Math.Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
                             + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + ((int)((b * 0x1111111111111111UL) >> 60)))
                             + InitKingDanger[(ksq ^ (Us * 56))]
                             - ((((score) + 32768) & ~0xffff) / 0x10000) / 32;

                // Analyse enemy's safe queen contact checks. First find undefended
                // squares around the king attacked by enemy queen...
                b = undefended & ei.attackedBy[Them][PieceTypeC.QUEEN] & ~(pos.byColorBB[Them]);
                if (b != 0)
                {
                    // ...then remove squares not supported by another enemy piece
                    b &= (ei.attackedBy[Them][PieceTypeC.PAWN] | ei.attackedBy[Them][PieceTypeC.KNIGHT]
                          | ei.attackedBy[Them][PieceTypeC.BISHOP] | ei.attackedBy[Them][PieceTypeC.ROOK]);
                    if (b != 0)
                    {
                        b -= (b >> 1) & 0x5555555555555555UL;
                        b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                        attackUnits += QueenContactCheckBonus
                                      * ((int)((b * 0x1111111111111111UL) >> 60))
                                      * (Them == pos.sideToMove ? 2 : 1);
                    }
                }

                // Analyse enemy's safe rook contact checks. First find undefended
                // squares around the king attacked by enemy rooks...
                b = undefended & ei.attackedBy[Them][PieceTypeC.ROOK] & ~pos.byColorBB[Them];

                // Consider only squares where the enemy rook gives check
                b &= Utils.PseudoAttacks_ROOK[ksq];

                if (b != 0)
                {
                    // ...then remove squares not supported by another enemy piece
                    b &= (ei.attackedBy[Them][PieceTypeC.PAWN] | ei.attackedBy[Them][PieceTypeC.KNIGHT]
                          | ei.attackedBy[Them][PieceTypeC.BISHOP] | ei.attackedBy[Them][PieceTypeC.QUEEN]);
                    if (b != 0)
                    {
                        b -= (b >> 1) & 0x5555555555555555UL;
                        b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                        attackUnits += RookContactCheckBonus
                                      * ((int)((b * 0x1111111111111111UL) >> 60))
                                      * (Them == pos.sideToMove ? 2 : 1);
                    }
                }

                // Analyse enemy's safe distance checks for sliders and knights
                safe = ~(pos.byColorBB[Them] | ei.attackedBy[Us][0]);

                b1 = (Utils.RAttacks[ksq][(((pos.occupied_squares & Utils.RMasks[ksq]) * Utils.RMagics[ksq]) >> Utils.RShifts[ksq])]) & safe;
                b2 = (Utils.BAttacks[ksq][(((pos.occupied_squares & Utils.BMasks[ksq]) * Utils.BMagics[ksq]) >> Utils.BShifts[ksq])]) & safe;

                // Enemy queen safe checks
                b = (b1 | b2) & ei.attackedBy[Them][PieceTypeC.QUEEN];
                if (b != 0)
                {
                    b -= (b >> 1) & 0x5555555555555555UL;
                    b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                    attackUnits += QueenCheckBonus * ((int)((b * 0x1111111111111111UL) >> 60));
                }

                // Enemy rooks safe checks
                b = b1 & ei.attackedBy[Them][PieceTypeC.ROOK];
                if (b != 0)
                {
                    b -= (b >> 1) & 0x5555555555555555UL;
                    b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                    attackUnits += RookCheckBonus * ((int)((b * 0x1111111111111111UL) >> 60));
                }

                // Enemy bishops safe checks
                b = b2 & ei.attackedBy[Them][PieceTypeC.BISHOP];
                if (b != 0)
                {
                    b -= (b >> 1) & 0x5555555555555555UL;
                    b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                    attackUnits += BishopCheckBonus * ((int)((b * 0x1111111111111111UL) >> 60));
                }

                // Enemy knights safe checks
                b = Utils.StepAttacksBB_KNIGHT[ksq] & ei.attackedBy[Them][PieceTypeC.KNIGHT] & safe;
                if (b != 0)
                {
                    b -= (b >> 1) & 0x5555555555555555UL;
                    b = ((b >> 2) & 0x3333333333333333UL) + (b & 0x3333333333333333UL);
                    attackUnits += KnightCheckBonus * ((int)((b * 0x1111111111111111UL) >> 60));
                }
#else
                // Initialize the 'attackUnits' variable, which is used later on as an
                // index to the KingDangerTable[] array. The initial value is based on
                // the number and types of the enemy's attacking pieces, the number of
                // attacked and undefended squares around our king, the square of the
                // king, and the quality of the pawn shelter.
                attackUnits = Math.Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
                              + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + Bitcount.popcount_1s_Max15(undefended))
                              + InitKingDanger[(ksq ^ (Us * 56))] - ((((score) + 32768) & ~0xffff) / 0x10000) / 32;

                // Analyse enemy's safe queen contact checks. First find undefended
                // squares around the king attacked by enemy queen...
                b = undefended & ei.attackedBy[Them][PieceTypeC.QUEEN] & ~(pos.byColorBB[Them]);
                if (b != 0)
                {
                    // ...then remove squares not supported by another enemy piece
                    b &= (ei.attackedBy[Them][PieceTypeC.PAWN] | ei.attackedBy[Them][PieceTypeC.KNIGHT]
                          | ei.attackedBy[Them][PieceTypeC.BISHOP] | ei.attackedBy[Them][PieceTypeC.ROOK]);
                    if (b != 0)
                    {
                        attackUnits += QueenContactCheckBonus * Bitcount.popcount_1s_Max15(b)
                                       * (Them == pos.sideToMove ? 2 : 1);
                    }
                }

                // Analyse enemy's safe rook contact checks. First find undefended
                // squares around the king attacked by enemy rooks...
                b = undefended & ei.attackedBy[Them][PieceTypeC.ROOK] & ~pos.byColorBB[Them];

                // Consider only squares where the enemy rook gives check
                b &= Utils.PseudoAttacks_ROOK[ksq];

                if (b != 0)
                {
                    // ...then remove squares not supported by another enemy piece
                    b &= (ei.attackedBy[Them][PieceTypeC.PAWN] | ei.attackedBy[Them][PieceTypeC.KNIGHT]
                          | ei.attackedBy[Them][PieceTypeC.BISHOP] | ei.attackedBy[Them][PieceTypeC.QUEEN]);
                    if (b != 0)
                    {
                        attackUnits += RookContactCheckBonus * Bitcount.popcount_1s_Max15(b)
                                       * (Them == pos.sideToMove ? 2 : 1);
                    }
                }

                // Analyse enemy's safe distance checks for sliders and knights
                safe = ~(pos.byColorBB[Them] | ei.attackedBy[Us][0]);

                b1 = pos.attacks_from_ROOK(ksq) & safe;
                b2 = pos.attacks_from_BISHOP(ksq) & safe;

                // Enemy queen safe checks
                b = (b1 | b2) & ei.attackedBy[Them][PieceTypeC.QUEEN];
                if (b != 0)
                {
                    attackUnits += QueenCheckBonus * Bitcount.popcount_1s_Max15(b);
                }

                // Enemy rooks safe checks
                b = b1 & ei.attackedBy[Them][PieceTypeC.ROOK];
                if (b != 0)
                {
                    attackUnits += RookCheckBonus * Bitcount.popcount_1s_Max15(b);
                }

                // Enemy bishops safe checks
                b = b2 & ei.attackedBy[Them][PieceTypeC.BISHOP];
                if (b != 0)
                {
                    attackUnits += BishopCheckBonus * Bitcount.popcount_1s_Max15(b);
                }

                // Enemy knights safe checks
                b = Utils.StepAttacksBB_KNIGHT[ksq] & ei.attackedBy[Them][PieceTypeC.KNIGHT] & safe;
                if (b != 0)
                {
                    attackUnits += KnightCheckBonus * Bitcount.popcount_1s_Max15(b);
                }
#endif

                // To index KingDangerTable[] attackUnits must be in [0, 99] range
                attackUnits = Math.Min(99, Math.Max(0, attackUnits));

                // Finally, extract the king danger score from the KingDangerTable[]
                // array and subtract the score from evaluation. Set also margins[]
                // value that will be used for pruning because this value can sometimes
                // be very big, and so capturing a single attacking piece can therefore
                // result in a score change far bigger than the value of the captured piece.
                kingScore = KingDangerTable[Us == Search.RootColor ? 1 : 0][attackUnits];
                score -= kingScore;
                if (Us == ColorC.WHITE)
                {
                    marginsWHITE += (((kingScore + 32768) & ~0xffff) / 0x10000);
                }
                else
                {
                    marginsBLACK += (((kingScore + 32768) & ~0xffff) / 0x10000);
                }
            }

            if (Trace)
            {
                TracedScores[Us][PieceTypeC.KING] = score;
            }

            return score;
        }
Пример #3
0
        // evaluate_passed_pawns<>() evaluates the passed pawns of the given color
        private static int evaluate_passed_pawns(int Us, Position pos, EvalInfo ei)
        {
            var Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);

            ulong b, squaresToQueen, defendedSquares, unsafeSquares, supportingPawns;
            var score = ScoreC.SCORE_ZERO;

            b = (Us == ColorC.WHITE) ? ei.pi.passedPawnsWHITE : ei.pi.passedPawnsBLACK;

            if (b == 0)
            {
                return ScoreC.SCORE_ZERO;
            }

            do
            {
#if X64
                Bitboard bb = b;
                b &= (b - 1);
                Square s = (Utils.BSFTable[((bb & (0xffffffffffffffff - bb + 1)) * DeBruijn_64) >> 58]);
#else
                var s = Utils.pop_lsb(ref b);
#endif
                Debug.Assert(pos.pawn_is_passed(Us, s));

                var r = ((s >> 3) ^ (Us * 7)) - RankC.RANK_2;
                var rr = r * (r - 1);

                // Base bonus based on rank
                var mbonus = (20 * rr);
                var ebonus = (10 * (rr + r + 1));

                if (rr != 0)
                {
                    var blockSq = s + (Us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S);

                    // Adjust bonus based on kings proximity
                    ebonus += (Utils.SquareDistance[pos.pieceList[Them][PieceTypeC.KING][0]][blockSq] * 5 * rr);
                    ebonus -= (Utils.SquareDistance[pos.pieceList[Us][PieceTypeC.KING][0]][blockSq] * 2 * rr);

                    // If blockSq is not the queening square then consider also a second push
                    if ((blockSq >> 3) != (Us == ColorC.WHITE ? RankC.RANK_8 : RankC.RANK_1))
                    {
                        ebonus -=
                            (Utils.SquareDistance[pos.pieceList[Us][PieceTypeC.KING][0]][
                                blockSq + (Us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S)] * rr);
                    }

                    // If the pawn is free to advance, increase bonus
                    if (pos.board[blockSq] == PieceC.NO_PIECE)
                    {
                        squaresToQueen = Utils.ForwardBB[Us][s];
                        defendedSquares = squaresToQueen & ei.attackedBy[Us][0];

                        // If there is an enemy rook or queen attacking the pawn from behind,
                        // add all X-ray attacks by the rook or queen. Otherwise consider only
                        // the squares in the pawn's path attacked or occupied by the enemy.
                        if (((Utils.ForwardBB[Them][s]
                              & ((pos.byTypeBB[PieceTypeC.ROOK] | pos.byTypeBB[PieceTypeC.QUEEN]) & pos.byColorBB[Them]))
                             != 0)
                            && ((Utils.ForwardBB[Them][s]
                                 & ((pos.byTypeBB[PieceTypeC.ROOK] | pos.byTypeBB[PieceTypeC.QUEEN])
                                    & pos.byColorBB[Them]) & pos.attacks_from_ROOK(s)) != 0))
                        {
                            unsafeSquares = squaresToQueen;
                        }
                        else
                        {
                            unsafeSquares = squaresToQueen & (ei.attackedBy[Them][0] | pos.byColorBB[Them]);
                        }

                        // If there aren't enemy attacks or pieces along the path to queen give
                        // huge bonus. Even bigger if we protect the pawn's path.
                        if (unsafeSquares == 0)
                        {
                            ebonus += (rr * (squaresToQueen == defendedSquares ? 17 : 15));
                        }
                        else
                        {
                            // OK, there are enemy attacks or pieces (but not pawns). Are those
                            // squares which are attacked by the enemy also attacked by us ?
                            // If yes, big bonus (but smaller than when there are no enemy attacks),
                            // if no, somewhat smaller bonus.
                            ebonus += (rr * ((unsafeSquares & defendedSquares) == unsafeSquares ? 13 : 8));
                        }
                    }
                } // rr != 0

                // Increase the bonus if the passed pawn is supported by a friendly pawn
                // on the same rank and a bit smaller if it's on the previous rank.
                supportingPawns = (pos.byTypeBB[PieceTypeC.PAWN] & pos.byColorBB[Us]) & Utils.AdjacentFilesBB[s & 7];
                if ((supportingPawns & Utils.RankBB[s >> 3]) != 0)
                {
                    ebonus += (r * 20);
                }
                else if ((supportingPawns
                          & Utils.RankBB[(s - (Us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S)) >> 3]) != 0)
                {
                    ebonus += (r * 12);
                }

                // Rook pawns are a special case: They are sometimes worse, and
                // sometimes better than other passed pawns. It is difficult to find
                // good rules for determining whether they are good or bad. For now,
                // we try the following: Increase the value for rook pawns if the
                // other side has no pieces apart from a knight, and decrease the
                // value if the other side has a rook or queen.
                if ((s & 7) == FileC.FILE_A || (s & 7) == FileC.FILE_H)
                {
                    if ((Them == 0 ? pos.st.npMaterialWHITE : pos.st.npMaterialBLACK) <= Constants.KnightValueMidgame)
                    {
                        ebonus += ebonus / 4;
                    }
                    else if (((pos.byTypeBB[PieceTypeC.ROOK] | pos.byTypeBB[PieceTypeC.QUEEN]) & pos.byColorBB[Them])
                             != 0)
                    {
                        ebonus -= ebonus / 4;
                    }
                }
                score += ((mbonus << 16) + ebonus);
            }
            while (b != 0);

            // Add the scores to the middle game and endgame eval
            return Utils.apply_weight(score, Weights[EvalWeightC.PassedPawns]);
        }
Пример #4
0
        internal static void generate_evasion(Position pos, MoveStack[] ms, ref int mpos)
        {
            /// generate<EVASIONS> generates all pseudo-legal check evasions when the side
            /// to move is in check. Returns a pointer to the end of the move list.
            Debug.Assert(pos.in_check());

            ulong b;
            int from, checksq;
            var checkersCnt = 0;
            var us = pos.sideToMove;
            var ksq = pos.king_square(us);
            ulong sliderAttacks = 0;
            var checkers = pos.st.checkersBB;

            Debug.Assert(checkers != 0);

            // Find squares attacked by slider checkers, we will remove them from the king
            // evasions so to skip known illegal moves avoiding useless legality check later.
            b = checkers;
            do
            {
                checkersCnt++;
                checksq = Utils.pop_lsb(ref b);

                Debug.Assert(Utils.color_of(pos.piece_on(checksq)) == Utils.flip_C(us));

                switch (Utils.type_of(pos.piece_on(checksq)))
                {
                    case PieceTypeC.BISHOP:
                        sliderAttacks |= Utils.PseudoAttacks[PieceTypeC.BISHOP][checksq];
                        break;
                    case PieceTypeC.ROOK:
                        sliderAttacks |= Utils.PseudoAttacks[PieceTypeC.ROOK][checksq];
                        break;
                    case PieceTypeC.QUEEN:
                        // If queen and king are far or not on a diagonal line we can safely
                        // remove all the squares attacked in the other direction becuase are
                        // not reachable by the king anyway.
                        if ((Utils.between_bb(ksq, checksq) != 0)
                            || ((Utils.bit_is_set(Utils.PseudoAttacks[PieceTypeC.BISHOP][checksq], ksq)) == 0))
                        {
                            sliderAttacks |= Utils.PseudoAttacks[PieceTypeC.QUEEN][checksq];
                        }

                        // Otherwise we need to use real rook attacks to check if king is safe
                        // to move in the other direction. For example: king in B2, queen in A1
                        // a knight in B1, and we can safely move to C1.
                        else
                        {
                            sliderAttacks |= Utils.PseudoAttacks[PieceTypeC.BISHOP][checksq]
                                             | pos.attacks_from_ROOK(checksq);
                        }
                        break;
                    default:
                        break;
                }
            }
            while (b != 0);

            // Generate evasions for king, capture and non capture moves
            b = Position.attacks_from_KING(ksq) & ~pos.pieces_C(us) & ~sliderAttacks;
            from = ksq;
            while (b != 0)
            {
                ms[mpos++].move = Utils.make_move(from, Utils.pop_lsb(ref b));
            }

            // Generate evasions for other pieces only if not under a double check
            if (checkersCnt > 1)
            {
                return;
            }

            // Blocking evasions or captures of the checking piece
            var target = Utils.between_bb(checksq, ksq) | checkers;

            generate_all(GenType.EVASIONS, pos, ms, ref mpos, us, target, null);
        }