예제 #1
0
            /// Entry::shelter_storm() calculates shelter and storm penalties for the file
            /// the king is on, as well as the two adjacent files.
            public Value shelter_storm(Position pos, Square ksq, Color Us)
            {
                Color Them = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);

                Value    safety = Pawns.MaxSafetyBonus;
                Bitboard b = pos.pieces_piecetype(PieceTypeS.PAWN) & (BitBoard.in_front_bb(Us, Types.rank_of(ksq)) | BitBoard.rank_bb_square(ksq));
                Bitboard ourPawns = b & pos.pieces_color(Us);
                Bitboard theirPawns = b & pos.pieces_color(Them);
                Rank     rkUs, rkThem;
                File     kf = Math.Max(FileS.FILE_B, Math.Min(FileS.FILE_G, Types.file_of(ksq)));

                for (File f = kf - 1; f <= kf + 1; ++f)
                {
                    b    = ourPawns & BitBoard.file_bb_file(f);
                    rkUs = b != 0 ? Types.relative_rank_square(Us, BitBoard.backmost_sq(Us, b)) : RankS.RANK_1;

                    b      = theirPawns & BitBoard.file_bb_file(f);
                    rkThem = b != 0 ? Types.relative_rank_square(Us, BitBoard.frontmost_sq(Them, b)) : RankS.RANK_1;

                    if ((MiddleEdges & BitBoard.SquareBB[Types.make_square(f, rkThem)]) != 0 &&
                        Types.file_of(ksq) == f &&
                        Types.relative_rank_square(Us, ksq) == rkThem - 1)
                    {
                        safety += 200;
                    }
                    else
                    {
                        safety -= ShelterWeakness[rkUs]
                                  + StormDanger[rkUs == RankS.RANK_1 ? 0 : rkThem == rkUs + 1 ? 2 : 1][rkThem];
                    }
                }

                return(safety);
            }
예제 #2
0
        public static Score evaluate(Position pos, Pawns.Entry e, Color Us)
        {
            Color  Them  = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);
            Square Up    = (Us == ColorS.WHITE ? SquareS.DELTA_N : SquareS.DELTA_S);
            Square Right = (Us == ColorS.WHITE ? SquareS.DELTA_NE : SquareS.DELTA_SW);
            Square Left  = (Us == ColorS.WHITE ? SquareS.DELTA_NW : SquareS.DELTA_SE);

            Bitboard b, p, doubled;
            Square   s;
            File     f;
            Rank     r;
            bool     passed, isolated, opposed, connected, backward, candidate, unsupported;
            Score    value = ScoreS.SCORE_ZERO;

            Square[] pl    = pos.list(Us, PieceTypeS.PAWN);
            int      plPos = 0;

            Bitboard ourPawns   = pos.pieces_color_piecetype(Us, PieceTypeS.PAWN);
            Bitboard theirPawns = pos.pieces_color_piecetype(Them, PieceTypeS.PAWN);

            e.passedPawns[Us]   = e.candidatePawns[Us] = 0;
            e.kingSquares[Us]   = SquareS.SQ_NONE;
            e.semiopenFiles[Us] = 0xFF;
            e.pawnAttacks[Us]   = BitBoard.shift_bb(ourPawns, Right) | BitBoard.shift_bb(ourPawns, Left);
            e.pawnsOnSquares[Us][ColorS.BLACK] = Bitcount.popcount_Max15(ourPawns & BitBoard.DarkSquares);
            e.pawnsOnSquares[Us][ColorS.WHITE] = pos.count(Us, PieceTypeS.PAWN) - e.pawnsOnSquares[Us][ColorS.BLACK];

            // Loop through all pawns of the current color and score each pawn
            while ((s = pl[plPos++]) != SquareS.SQ_NONE)
            {
                Debug.Assert(pos.piece_on(s) == Types.make_piece(Us, PieceTypeS.PAWN));

                f = Types.file_of(s);


                // This file cannot be semi-open
                e.semiopenFiles[Us] &= ~(1 << f);

                // Previous rank
                p = BitBoard.rank_bb_square(s - Types.pawn_push(Us));

                // Our rank plus previous one
                b = BitBoard.rank_bb_square(s) | p;

                // Flag the pawn as passed, isolated, doubled,
                // unsupported or connected (but not the backward one).
                connected   = (ourPawns & BitBoard.adjacent_files_bb(f) & b) != 0;
                unsupported = (0 == (ourPawns & BitBoard.adjacent_files_bb(f) & p));
                isolated    = (0 == (ourPawns & BitBoard.adjacent_files_bb(f)));
                doubled     = ourPawns & BitBoard.forward_bb(Us, s);
                opposed     = (theirPawns & BitBoard.forward_bb(Us, s)) != 0;
                passed      = (0 == (theirPawns & BitBoard.passed_pawn_mask(Us, s)));

                // Test for backward pawn.
                // If the pawn is passed, isolated, or connected it cannot be
                // backward. If there are friendly pawns behind on adjacent files
                // or if it can capture an enemy pawn it cannot be backward either.
                if ((passed | isolated | connected) ||
                    (ourPawns & BitBoard.pawn_attack_span(Them, s)) != 0 ||
                    (pos.attacks_from_pawn(s, Us) & theirPawns) != 0)
                {
                    backward = false;
                }
                else
                {
                    // We now know that there are no friendly pawns beside or behind this
                    // pawn on adjacent files. We now check whether the pawn is
                    // backward by looking in the forward direction on the adjacent
                    // files, and picking the closest pawn there.
                    b = BitBoard.pawn_attack_span(Us, s) & (ourPawns | theirPawns);
                    b = BitBoard.pawn_attack_span(Us, s) & BitBoard.rank_bb_square(BitBoard.backmost_sq(Us, b));

                    // If we have an enemy pawn in the same or next rank, the pawn is
                    // backward because it cannot advance without being captured.
                    backward = ((b | BitBoard.shift_bb(b, Up)) & theirPawns) != 0;
                }

                Debug.Assert(opposed | passed | (BitBoard.pawn_attack_span(Us, s) & theirPawns) != 0);

                // A not-passed pawn is a candidate to become passed, if it is free to
                // advance and if the number of friendly pawns beside or behind this
                // pawn on adjacent files is higher than or equal to the number of
                // enemy pawns in the forward direction on the adjacent files.
                candidate = !(opposed | passed | backward | isolated) &&
                            (b = BitBoard.pawn_attack_span(Them, s + Types.pawn_push(Us)) & ourPawns) != 0 &&
                            Bitcount.popcount_Max15(b) >= Bitcount.popcount_Max15(BitBoard.pawn_attack_span(Us, s) & theirPawns);

                // Passed pawns will be properly scored in evaluation because we need
                // full attack info to evaluate passed pawns. Only the frontmost passed
                // pawn on each file is considered a true passed pawn.
                if (passed && 0 == doubled)
                {
                    e.passedPawns[Us] |= BitBoard.SquareBB[s];
                }

                // Score this pawn
                if (isolated)
                {
                    value -= Isolated[opposed ? 1 : 0][f];
                }

                if (unsupported && !isolated)
                {
                    value -= UnsupportedPawnPenalty;
                }

                if (doubled != 0)
                {
                    value -= Types.divScore(Doubled[f], BitBoard.rank_distance(s, BitBoard.lsb(doubled)));
                }

                if (backward)
                {
                    value -= Backward[opposed ? 1 : 0][f];
                }

                if (connected)
                {
                    value += Connected[f][Types.relative_rank_square(Us, s)];
                }

                if (candidate)
                {
                    value += CandidatePassed[Types.relative_rank_square(Us, s)];

                    if (0 == doubled)
                    {
                        e.candidatePawns[Us] |= BitBoard.SquareBB[s];
                    }
                }
            }

            // In endgame it's better to have pawns on both wings. So give a bonus according
            // to file distance between left and right outermost pawns.
            if (pos.count(Us, PieceTypeS.PAWN) > 1)
            {
                b      = (Bitboard)(e.semiopenFiles[Us] ^ 0xFF);
                value += PawnsFileSpan * (BitBoard.msb(b) - BitBoard.lsb(b));
            }

            return(value);
        }
예제 #3
0
        /// KB and one or more pawns vs K. It checks for draws with rook pawns and
        /// a bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_DRAW
        /// is returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
        /// will be used.
        public ScaleFactor KBPsK(Position pos)
        {
            Debug.Assert(pos.non_pawn_material(strongSide) == ValueS.BishopValueMg);
            Debug.Assert(pos.count(strongSide, PieceTypeS.PAWN) >= 1);

            // No assertions about the material of weakSide, because we want draws to
            // be detected even when the weaker side has some pawns.

            Bitboard pawns    = pos.pieces_color_piecetype(strongSide, PieceTypeS.PAWN);
            File     pawnFile = Types.file_of(pos.list(strongSide, PieceTypeS.PAWN)[0]);

            // All pawns are on a single rook file ?
            if ((pawnFile == FileS.FILE_A || pawnFile == FileS.FILE_H) &&
                0 == (pawns & ~BitBoard.file_bb_file(pawnFile)))
            {
                Square bishopSq   = pos.list(strongSide, PieceTypeS.BISHOP)[0];
                Square queeningSq = Types.relative_square(strongSide, Types.make_square(pawnFile, RankS.RANK_8));
                Square kingSq     = pos.king_square(weakSide);

                if (Types.opposite_colors(queeningSq, bishopSq) &&
                    BitBoard.square_distance(queeningSq, kingSq) <= 1)
                {
                    return(ScaleFactorS.SCALE_FACTOR_DRAW);
                }
            }

            // If all the pawns are on the same B or G file, then it's potentially a draw
            if ((pawnFile == FileS.FILE_B || pawnFile == FileS.FILE_G) &&
                0 == (pos.pieces_piecetype(PieceTypeS.PAWN) & ~BitBoard.file_bb_file(pawnFile)) &&
                pos.non_pawn_material(weakSide) == 0 &&
                pos.count(weakSide, PieceTypeS.PAWN) >= 1)
            {
                // Get weakSide pawn that is closest to the home rank
                Square weakPawnSq = BitBoard.backmost_sq(weakSide, pos.pieces_color_piecetype(weakSide, PieceTypeS.PAWN));

                Square strongKingSq = pos.king_square(strongSide);
                Square weakKingSq   = pos.king_square(weakSide);
                Square bishopSq     = pos.list(strongSide, PieceTypeS.BISHOP)[0];

                // There's potential for a draw if our pawn is blocked on the 7th rank,
                // the bishop cannot attack it or they only have one pawn left
                if (Types.relative_rank_square(strongSide, weakPawnSq) == RankS.RANK_7 &&
                    (pos.pieces_color_piecetype(strongSide, PieceTypeS.PAWN) & BitBoard.SquareBB[(weakPawnSq + Types.pawn_push(weakSide))]) != 0 &&
                    (Types.opposite_colors(bishopSq, weakPawnSq) || pos.count(strongSide, PieceTypeS.PAWN) == 1))
                {
                    int strongKingDist = BitBoard.square_distance(weakPawnSq, strongKingSq);
                    int weakKingDist   = BitBoard.square_distance(weakPawnSq, weakKingSq);

                    // It's a draw if the weak king is on its back two ranks, within 2
                    // squares of the blocking pawn and the strong king is not
                    // closer. (I think this rule only fails in practically
                    // unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w
                    // and positions where qsearch will immediately correct the
                    // problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w)
                    if (Types.relative_rank_square(strongSide, weakKingSq) >= RankS.RANK_7 &&
                        weakKingDist <= 2 &&
                        weakKingDist <= strongKingDist)
                    {
                        return(ScaleFactorS.SCALE_FACTOR_DRAW);
                    }
                }
            }

            return(ScaleFactorS.SCALE_FACTOR_NONE);
        }