Exemplo n.º 1
0
    internal CheckInfo(Position pos)
    {
        var them = Color.opposite(pos.side_to_move());
        ksq = pos.square(PieceType.KING, them);

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

        checkSquares[PieceType.PAWN] = pos.attacks_from_PS(PieceType.PAWN, ksq, them);
        checkSquares[PieceType.KNIGHT] = pos.attacks_from_PtS(PieceType.KNIGHT, ksq);
        checkSquares[PieceType.BISHOP] = pos.attacks_from_PtS(PieceType.BISHOP, ksq);
        checkSquares[PieceType.ROOK] = pos.attacks_from_PtS(PieceType.ROOK, ksq);
        checkSquares[PieceType.QUEEN] = checkSquares[PieceType.BISHOP] | checkSquares[PieceType.ROOK];
        checkSquares[PieceType.KING] = Bitboard.Create(0);
    }
Exemplo n.º 2
0
    internal override ScaleFactor GetScaleFactor(Position pos)
    {
        var pawnSq = pos.square(PieceType.PAWN, strongSide);
        var bishopSq = pos.square(PieceType.BISHOP, weakSide);
        var weakKingSq = pos.square(PieceType.KING, weakSide);

        // King needs to get close to promoting pawn to prevent knight from blocking.
        // Rules for this are very tricky, so just approximate.
        if ((Utils.forward_bb(strongSide, pawnSq) & pos.attacks_from_PtS(PieceType.BISHOP, bishopSq))!=0)
        {
            return (ScaleFactor) (Utils.distance_Square(weakKingSq, pawnSq));
        }

        return ScaleFactor.SCALE_FACTOR_NONE;
    }
Exemplo n.º 3
0
    internal override ScaleFactor GetScaleFactor(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.BishopValueMg, 2));
        Debug.Assert(verify_material(pos, weakSide, Value.BishopValueMg, 0));

        var wbsq = pos.square(PieceType.BISHOP, strongSide);
        var bbsq = pos.square(PieceType.BISHOP, weakSide);

        if (!Square.opposite_colors(wbsq, bbsq))
        {
            return ScaleFactor.SCALE_FACTOR_NONE;
        }

        var ksq = pos.square(PieceType.KING, weakSide);
        var psq1 = pos.square(PieceType.PAWN, strongSide, 0);
        var psq2 = pos.square(PieceType.PAWN, strongSide, 1);
        var r1 = Square.rank_of(psq1);
        var r2 = Square.rank_of(psq2);
        SquareT blockSq1, blockSq2;

        if (Rank.relative_rank_CtSt(strongSide, psq1) > Rank.relative_rank_CtSt(strongSide, psq2))
        {
            blockSq1 = psq1 + Square.pawn_push(strongSide);
            blockSq2 = Square.make_square(Square.file_of(psq2), Square.rank_of(psq1));
        }
        else
        {
            blockSq1 = psq2 + Square.pawn_push(strongSide);
            blockSq2 = Square.make_square(Square.file_of(psq1), Square.rank_of(psq2));
        }

        switch (Utils.distance_File(psq1, psq2))
        {
            case 0:
                // Both pawns are on the same file. It's an easy draw if the defender firmly
                // controls some square in the frontmost pawn's path.
                if (Square.file_of(ksq) == Square.file_of(blockSq1)
                    && Rank.relative_rank_CtSt(strongSide, ksq) >= Rank.relative_rank_CtSt(strongSide, blockSq1)
                    && Square.opposite_colors(ksq, wbsq))
                {
                    return ScaleFactor.SCALE_FACTOR_DRAW;
                }
                return ScaleFactor.SCALE_FACTOR_NONE;

            case 1:
                // Pawns on adjacent files. It's a draw if the defender firmly controls the
                // square in front of the frontmost pawn's path, and the square diagonally
                // behind this square on the file of the other pawn.
                if (ksq == blockSq1 && Square.opposite_colors(ksq, wbsq)
                    && (bbsq == blockSq2
                        || (pos.attacks_from_PtS(PieceType.BISHOP, blockSq2) & pos.pieces_CtPt(weakSide, PieceType.BISHOP))!=0
                        || Utils.distance_Rank(r1, r2) >= 2))
                {
                    return ScaleFactor.SCALE_FACTOR_DRAW;
                }

                if (ksq == blockSq2 && Square.opposite_colors(ksq, wbsq)
                    && (bbsq == blockSq1
                        || (pos.attacks_from_PtS(PieceType.BISHOP, blockSq1) & pos.pieces_CtPt(weakSide, PieceType.BISHOP))!=0))
                {
                    return ScaleFactor.SCALE_FACTOR_DRAW;
                }
                return ScaleFactor.SCALE_FACTOR_NONE;

            default:
                // The pawns are not on the same file or adjacent files. No scaling.
                return ScaleFactor.SCALE_FACTOR_NONE;
        }
    }
Exemplo n.º 4
0
    internal override ScaleFactor GetScaleFactor(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.BishopValueMg, 1));
        Debug.Assert(verify_material(pos, weakSide, Value.BishopValueMg, 0));

        var pawnSq = pos.square(PieceType.PAWN, strongSide);
        var strongBishopSq = pos.square(PieceType.BISHOP, strongSide);
        var weakBishopSq = pos.square(PieceType.BISHOP, weakSide);
        var weakKingSq = pos.square(PieceType.KING, weakSide);

        // Case 1: Defending king blocks the pawn, and cannot be driven away
        if (Square.file_of(weakKingSq) == Square.file_of(pawnSq)
            && Rank.relative_rank_CtSt(strongSide, pawnSq) < Rank.relative_rank_CtSt(strongSide, weakKingSq)
            && (Square.opposite_colors(weakKingSq, strongBishopSq)
                || Rank.relative_rank_CtSt(strongSide, weakKingSq) <= Rank.RANK_6))
        {
            return ScaleFactor.SCALE_FACTOR_DRAW;
        }

        // Case 2: Opposite colored bishops
        if (Square.opposite_colors(strongBishopSq, weakBishopSq))
        {
            // We assume that the position is drawn in the following three situations:
            //
            //   a. The pawn is on rank 5 or further back.
            //   b. The defending king is somewhere in the pawn's path.
            //   c. The defending bishop attacks some square along the pawn's path,
            //      and is at least three squares away from the pawn.
            //
            // These rules are probably not perfect, but in practice they work
            // reasonably well.

            if (Rank.relative_rank_CtSt(strongSide, pawnSq) <= Rank.RANK_5)
            {
                return ScaleFactor.SCALE_FACTOR_DRAW;
            }
            var path = Utils.forward_bb(strongSide, pawnSq);

            if ((path & pos.pieces_CtPt(weakSide, PieceType.KING))!=0)
            {
                return ScaleFactor.SCALE_FACTOR_DRAW;
            }

            if ((pos.attacks_from_PtS(PieceType.BISHOP, weakBishopSq) & path)!=0
                && Utils.distance_Square(weakBishopSq, pawnSq) >= 3)
            {
                return ScaleFactor.SCALE_FACTOR_DRAW;
            }
        }
        return ScaleFactor.SCALE_FACTOR_NONE;
    }
Exemplo n.º 5
0
    internal override ScaleFactor GetScaleFactor(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.QueenValueMg, 0));
        Debug.Assert(pos.count(PieceType.ROOK, weakSide) == 1);
        Debug.Assert(pos.count(PieceType.PAWN, weakSide) >= 1);

        var kingSq = pos.square(PieceType.KING, weakSide);
        var rsq = pos.square(PieceType.ROOK, weakSide);

        if (Rank.relative_rank_CtSt(weakSide, kingSq) <= Rank.RANK_2
            && Rank.relative_rank_CtSt(weakSide, pos.square(PieceType.KING, strongSide)) >= Rank.RANK_4
            && Rank.relative_rank_CtSt(weakSide, rsq) == Rank.RANK_3
            && (pos.pieces_CtPt(weakSide, PieceType.PAWN) & pos.attacks_from_PtS(PieceType.KING, kingSq)
                & pos.attacks_from_PS(PieceType.PAWN, rsq, strongSide))!=0)
        {
            return ScaleFactor.SCALE_FACTOR_DRAW;
        }

        return ScaleFactor.SCALE_FACTOR_NONE;
    }
Exemplo n.º 6
0
    /// 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.
    private static ExtMoveArrayWrapper generate_EVASIONS(Position pos, ExtMoveArrayWrapper moveList)
    {
        Debug.Assert(pos.checkers() != 0);

        var us = pos.side_to_move();
        var ksq = pos.square(PieceType.KING, us);
        var sliderAttacks = Bitboard.Create(0);
        var sliders = pos.checkers() & ~pos.pieces_PtPt(PieceType.KNIGHT, PieceType.PAWN);

        // Find all the squares attacked by slider checkers. We will remove them from
        // the king evasions in order to skip known illegal moves, which avoids any
        // useless legality checks later on.
        while (sliders != 0)
        {
            var checksq1 = Utils.pop_lsb(ref sliders);
            sliderAttacks |= Bitboard.XorWithSquare(Utils.LineBB[checksq1, ksq], checksq1);
        }

        // Generate evasions for king, capture and non capture moves
        var b = pos.attacks_from_PtS(PieceType.KING, ksq) & ~pos.pieces_Ct(us) & ~sliderAttacks;
        while (b != 0)
        {
            (moveList).Add(Move.make_move(ksq, Utils.pop_lsb(ref b)));
        }

        if (Bitboard.more_than_one(pos.checkers()))
        {
            return moveList; // Double check, only a king move can save the day
        }

        // Generate blocking evasions or captures of the checking piece
        var checksq = Utils.lsb(pos.checkers());
        var target = Bitboard.OrWithSquare(Utils.between_bb(checksq, ksq), checksq);

        return us == Color.WHITE
            ? generate_all(Color.WHITE, GenType.EVASIONS, pos, moveList, target)
            : generate_all(Color.BLACK, GenType.EVASIONS, pos, moveList, target);
    }
Exemplo n.º 7
0
    /// generate
    /// QUIET_CHECKS
    ///     generates all pseudo-legal non-captures and knight
    ///     underpromotions that give check. Returns a pointer to the end of the move list.
    private static ExtMoveArrayWrapper generate_QUIET_CHECKS(Position pos, ExtMoveArrayWrapper moveList)
    {
        Debug.Assert(pos.checkers() == 0);

        var us = pos.side_to_move();
        var ci = new CheckInfo(pos);
        var dc = ci.dcCandidates;

        while (dc != 0)
        {
            var from = Utils.pop_lsb(ref dc);
            var pt = Piece.type_of(pos.piece_on(from));

            if (pt == PieceType.PAWN)
            {
                continue; // Will be generated together with direct checks
            }

            var b = pos.attacks_from_PtS(pt, from) & ~pos.pieces();

            if (pt == PieceType.KING)
            {
                b &= ~Utils.PseudoAttacks[PieceType.QUEEN, ci.ksq];
            }

            while (b != 0)
            {
                (moveList).Add(Move.make_move(from, Utils.pop_lsb(ref b)));
            }
        }

        return us == Color.WHITE
            ? generate_all(Color.WHITE, GenType.QUIET_CHECKS, pos, moveList, ~pos.pieces(), ci)
            : generate_all(Color.BLACK, GenType.QUIET_CHECKS, pos, moveList, ~pos.pieces(), ci);
    }
Exemplo n.º 8
0
    internal static ExtMoveArrayWrapper generate_all(
        ColorT Us,
        GenType Type,
        Position pos,
        ExtMoveArrayWrapper moveList,
        BitboardT target,
        CheckInfo ci = null)
    {
        var Checks = Type == GenType.QUIET_CHECKS;

        moveList = generate_pawn_moves(Us, Type, pos, moveList, target, ci);
        moveList = generate_moves(PieceType.KNIGHT, Checks, pos, moveList, Us, target, ci);
        moveList = generate_moves(PieceType.BISHOP, Checks, pos, moveList, Us, target, ci);
        moveList = generate_moves(PieceType.ROOK, Checks, pos, moveList, Us, target, ci);
        moveList = generate_moves(PieceType.QUEEN, Checks, pos, moveList, Us, target, ci);

        if (Type != GenType.QUIET_CHECKS && Type != GenType.EVASIONS)
        {
            var ksq = pos.square(PieceType.KING, Us);
            var b = pos.attacks_from_PtS(PieceType.KING, ksq) & target;
            while (b != 0)
            {
                (moveList).Add(Move.make_move(ksq, Utils.pop_lsb(ref b)));
            }
        }

        if (Type != GenType.CAPTURES && Type != GenType.EVASIONS && pos.can_castle(Us) != 0)
        {
            if (pos.is_chess960())
            {
                moveList = generate_castling(
                    MakeCastling(Us, CastlingSide.KING_SIDE),
                    Checks,
                    true,
                    pos,
                    moveList,
                    Us,
                    ci);
                moveList = generate_castling(
                    MakeCastling(Us, CastlingSide.QUEEN_SIDE),
                    Checks,
                    true,
                    pos,
                    moveList,
                    Us,
                    ci);
            }
            else
            {
                moveList = generate_castling(
                    MakeCastling(Us, CastlingSide.KING_SIDE),
                    Checks,
                    false,
                    pos,
                    moveList,
                    Us,
                    ci);
                moveList = generate_castling(
                    MakeCastling(Us, CastlingSide.QUEEN_SIDE),
                    Checks,
                    false,
                    pos,
                    moveList,
                    Us,
                    ci);
            }
        }

        return moveList;
    }
Exemplo n.º 9
0
    internal static ExtMoveArrayWrapper generate_moves(
        PieceTypeT pieceType,
        bool Checks,
        Position pos,
        ExtMoveArrayWrapper moveList,
        ColorT us,
        BitboardT target,
        CheckInfo ci)
    {
        var Pt = (int) pieceType;
        Debug.Assert(Pt != PieceType.KING && Pt != PieceType.PAWN);

        for(var idx=0; idx<16;idx++)
        {
            var square = pos.square(pieceType, us, idx);
            if (square == Square.SQ_NONE)
            {
                break;
            }

            if (Checks)
            {
                if ((Pt == PieceType.BISHOP || Pt == PieceType.ROOK || Pt == PieceType.QUEEN)
                    && (Utils.PseudoAttacks[Pt, square] & target & ci.checkSquares[Pt]) == 0)
                {
                    continue;
                }

                if (ci.dcCandidates != 0 && Bitboard.AndWithSquare(ci.dcCandidates, square)!=0)
                {
                    continue;
                }
            }

            var b = pos.attacks_from_PtS(pieceType, square) & target;

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

            while (b != 0)
            {
                (moveList).Add(Move.make_move(square, Utils.pop_lsb(ref b)));
            }
        }

        return moveList;
    }
Exemplo n.º 10
0
    // evaluate_passed_pawns() evaluates the passed pawns of the given color
    private static ScoreT evaluate_passed_pawns(ColorT Us, bool DoTrace, Position pos, EvalInfo ei)
    {
        var Them = (Us == Color.WHITE ? Color.BLACK : Color.WHITE);

        var score = Score.SCORE_ZERO;

        var b = ei.pi.passed_pawns(Us);

        while (b!=0)
        {
            var s = Utils.pop_lsb(ref b);

            Debug.Assert(pos.pawn_passed(Us, s));

            int r = Rank.relative_rank_CtSt(Us, s) - Rank.RANK_2;
            var rr = r*(r - 1);

            ValueT mbonus = Passed[(int) Phase.MG][r], ebonus = Passed[(int) Phase.EG][r];

            if (rr != 0)
            {
                var blockSq = s + Square.pawn_push(Us);

                // Adjust bonus based on the king's proximity
                ebonus += Utils.distance_Square(pos.square(PieceType.KING, Them), blockSq)*5*rr
                          - Utils.distance_Square(pos.square(PieceType.KING, Us), blockSq)*2*rr;

                // If blockSq is not the queening square then consider also a second push
                if (Rank.relative_rank_CtSt(Us, blockSq) != Rank.RANK_8)
                {
                    ebonus -= Utils.distance_Square(pos.square(PieceType.KING, Us), blockSq + Square.pawn_push(Us))*rr;
                }

                // If the pawn is free to advance, then increase the bonus
                if (pos.empty(blockSq))
                {
                    // If there is a rook or queen attacking/defending the pawn from behind,
                    // consider all the squaresToQueen. Otherwise consider only the squares
                    // in the pawn's path attacked or occupied by the enemy.
                    BitboardT squaresToQueen;
                    BitboardT unsafeSquares;
                    var defendedSquares = unsafeSquares = squaresToQueen = Utils.forward_bb(Us, s);

                    var bb = Utils.forward_bb(Them, s) & pos.pieces_PtPt(PieceType.ROOK, PieceType.QUEEN)
                             & pos.attacks_from_PtS(PieceType.ROOK, s);

                    if ((pos.pieces_Ct(Us) & bb)==0)
                    {
                        defendedSquares &= ei.attackedBy[Us, PieceType.ALL_PIECES];
                    }

                    if ((pos.pieces_Ct(Them) & bb) == 0)
                    {
                        unsafeSquares &= ei.attackedBy[Them, PieceType.ALL_PIECES] | pos.pieces_Ct(Them);
                    }

                    // If there aren't any enemy attacks, assign a big bonus. Otherwise
                    // assign a smaller bonus if the block square isn't attacked.
                    var k = unsafeSquares == 0 ? 18 : Bitboard.AndWithSquare(unsafeSquares, blockSq)==0 ? 8 : 0;

                    // If the path to queen is fully defended, assign a big bonus.
                    // Otherwise assign a smaller bonus if the block square is defended.
                    if (defendedSquares == squaresToQueen)
                    {
                        k += 6;
                    }

                    else if (Bitboard.AndWithSquare(defendedSquares, blockSq)!=0)
                    {
                        k += 4;
                    }

                    mbonus += k*rr;
                    ebonus += k*rr;
                }
                else if (Bitboard.AndWithSquare(pos.pieces_Ct(Us), blockSq)!=0)
                {
                    mbonus += rr*3 + r*2 + 3;
                    ebonus += rr + r*2;
                }
            } // rr != 0

            if (pos.count(PieceType.PAWN, Us) < pos.count(PieceType.PAWN, Them))
            {
                ebonus += ebonus/4;
            }

            score += Score.make_score(mbonus, ebonus) + PassedFile[Square.file_of(s)];
        }

        if (DoTrace)
        {
            add_IdxCtSt((int) Term.PASSED, Us, Score.Multiply(score, Weights[PassedPawns]));
        }

        // Add the scores to the middlegame and endgame eval
        return Score.Multiply(score, Weights[PassedPawns]);
    }
Exemplo n.º 11
0
    // evaluate_king() assigns bonuses and penalties to a king of a given color

    private static ScoreT evaluate_king(ColorT Us, bool DoTrace, Position pos, EvalInfo ei)
    {
        var Them = (Us == Color.WHITE ? Color.BLACK : Color.WHITE);

        var ksq = pos.square(PieceType.KING, Us);

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

        // Main king safety evaluation
        if (ei.kingAttackersCount[Them] != 0)
        {
            // Find the attacked squares around the king which have no defenders
            // apart from the king itself
            var undefended = ei.attackedBy[Them, PieceType.ALL_PIECES] & ei.attackedBy[Us, PieceType.KING]
                                  & ~(ei.attackedBy[Us, PieceType.PAWN] | ei.attackedBy[Us, PieceType.KNIGHT]
                                      | ei.attackedBy[Us, PieceType.BISHOP] | ei.attackedBy[Us, PieceType.ROOK]
                                      | ei.attackedBy[Us, PieceType.QUEEN]);

            // Initialize the 'attackUnits' variable, which is used later on as an
            // index into the KingDanger[] 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 and the quality of
            // the pawn shelter (current 'score' value).
            var attackUnits = Math.Min(72, ei.kingAttackersCount[Them] *ei.kingAttackersWeight[Them])
                              + 9*ei.kingAdjacentZoneAttacksCount[Them] + 27*Bitcount.popcount_Max15(undefended)
                              + 11*((ulong)ei.pinnedPieces[Us] != 0 ? 1 : 0)
                              - 64*(pos.count(PieceType.QUEEN, Them) == 0 ? 1 : 0) - Score.mg_value(score)/8;

            // Analyse the enemy's safe queen contact checks. Firstly, find the
            // undefended squares around the king reachable by the enemy queen...
            var b = undefended & ei.attackedBy[Them, PieceType.QUEEN] & ~pos.pieces_Ct(Them);
            if (b!=0)
            {
                // ...and then remove squares not supported by another enemy piece
                b &= ei.attackedBy[Them, PieceType.PAWN] | ei.attackedBy[Them, PieceType.KNIGHT]
                     | ei.attackedBy[Them, PieceType.BISHOP] | ei.attackedBy[Them, PieceType.ROOK];

                if (b!=0)
                {
                    attackUnits += QueenContactCheck*Bitcount.popcount_Max15(b);
                }
            }

            // Analyse the enemy's safe distance checks for sliders and knights
            var safe = ~(ei.attackedBy[Us, PieceType.ALL_PIECES] | pos.pieces_Ct(Them));

            var b1 = pos.attacks_from_PtS(PieceType.ROOK, ksq) & safe;
            var b2 = pos.attacks_from_PtS(PieceType.BISHOP, ksq) & safe;

            // Enemy queen safe checks
            b = (b1 | b2) & ei.attackedBy[Them, PieceType.QUEEN];
            if (b!=0)
            {
                attackUnits += QueenCheck*Bitcount.popcount_Max15(b);
                score -= Checked;
            }

            // Enemy rooks safe checks
            b = b1 & ei.attackedBy[Them, PieceType.ROOK];
            if (b!=0)
            {
                attackUnits += RookCheck*Bitcount.popcount_Max15(b);
                score -= Checked;
            }

            // Enemy bishops safe checks
            b = b2 & ei.attackedBy[Them, PieceType.BISHOP];
            if (b!=0)
            {
                attackUnits += BishopCheck*Bitcount.popcount_Max15(b);
                score -= Checked;
            }

            // Enemy knights safe checks
            b = pos.attacks_from_PtS(PieceType.KNIGHT, ksq) & ei.attackedBy[Them, PieceType.KNIGHT] & safe;
            if (b!=0)
            {
                attackUnits += KnightCheck*Bitcount.popcount_Max15(b);
                score -= Checked;
            }

            // Finally, extract the king danger score from the KingDanger[]
            // array and subtract the score from evaluation.
            score -= KingDanger[Math.Max(Math.Min(attackUnits, 399), 0)];
        }

        if (DoTrace)
        {
            add_IdxCtSt(PieceType.KING, Us, score);
        }

        return score;
    }
Exemplo n.º 12
0
    // evaluate_pieces() assigns bonuses and penalties to the pieces of a given color

    private static ScoreT evaluate_pieces(
        PieceTypeT pieceType,
        ColorT Us,
        bool DoTrace,
        Position pos,
        EvalInfo ei,
        ScoreT[] mobility,
        BitboardT[] mobilityArea)
    {
        int Pt = pieceType;
        if (Pt == PieceType.KING)
        {
            return Score.SCORE_ZERO;
        }
        var score = Score.SCORE_ZERO;

        var NextPt = (Us == Color.WHITE ? pieceType : pieceType + 1);
        var Them = (Us == Color.WHITE ? Color.BLACK : Color.WHITE);
        
        ei.attackedBy[Us, Pt] = Bitboard.Create(0);

        for(var idx=0; idx<16;idx++)
        {
            var s = pos.square(pieceType, Us, idx);
            if (s == Square.SQ_NONE)
            {
                break;
            }
            // Find attacked squares, including x-ray attacks for bishops and rooks
            var b = Pt == PieceType.BISHOP
                ? Utils.attacks_bb_PtSBb(PieceType.BISHOP, s, pos.pieces() ^ pos.pieces_CtPt(Us, PieceType.QUEEN))
                : Pt == PieceType.ROOK
                    ? Utils.attacks_bb_PtSBb(
                        PieceType.ROOK,
                        s,
                        pos.pieces() ^ pos.pieces_CtPtPt(Us, PieceType.ROOK, PieceType.QUEEN))
                    : pos.attacks_from_PtS(pieceType, s);

            if (Bitboard.AndWithSquare(ei.pinnedPieces[Us], s)!=0)
            {
                b &= Utils.LineBB[pos.square(PieceType.KING, Us), s];
            }

            ei.attackedBy[Us, PieceType.ALL_PIECES] |= ei.attackedBy[Us, Pt] |= b;

            if ((b & ei.kingRing[Them])!=0)
            {
                ei.kingAttackersCount[Us]++;
                ei.kingAttackersWeight[Us] += KingAttackWeights[Pt];
                var bb = b & ei.attackedBy[Them, PieceType.KING];
                if (bb!=0)
                {
                    ei.kingAdjacentZoneAttacksCount[Us] += Bitcount.popcount_Max15(bb);
                }
            }

            if (Pt == PieceType.QUEEN)
            {
                b &=
                    ~(ei.attackedBy[Them, PieceType.KNIGHT] | ei.attackedBy[Them, PieceType.BISHOP]
                      | ei.attackedBy[Them, PieceType.ROOK]);
            }

            var mob = Pt == PieceType.QUEEN
                ? Bitcount.popcount_Full(b & mobilityArea[Us])
                : Bitcount.popcount_Max15(b & mobilityArea[Us]);

            mobility[Us] += MobilityBonus[Pt][mob];

            if (Pt == PieceType.BISHOP || Pt == PieceType.KNIGHT)
            {
                // Bonus for outpost square
                if (Rank.relative_rank_CtSt(Us, s) >= Rank.RANK_4 && Rank.relative_rank_CtSt(Us, s) <= Rank.RANK_6
                    && (pos.pieces_CtPt(Them, PieceType.PAWN) & Utils.pawn_attack_span(Us, s))==0)
                {
                    score +=
                        Outpost[Pt == PieceType.BISHOP ? 1 : 0][Bitboard.AndWithSquare(ei.attackedBy[Us, PieceType.PAWN], s)!=0 ? 1 : 0];
                }

                // Bonus when behind a pawn
                if (Rank.relative_rank_CtSt(Us, s) < Rank.RANK_5 && Bitboard.AndWithSquare(pos.pieces_Pt(PieceType.PAWN), (s + Square.pawn_push(Us)))!=0)
                {
                    score += MinorBehindPawn;
                }

                // Penalty for pawns on same color square of bishop
                if (Pt == PieceType.BISHOP)
                {
                    score -= BishopPawns*ei.pi.pawns_on_same_color_squares(Us, s);
                }

                // An important Chess960 pattern: A cornered bishop blocked by a friendly
                // pawn diagonally in front of it is a very serious problem, especially
                // when that pawn is also blocked.
                if (Pt == PieceType.BISHOP && pos.is_chess960()
                    && (s == Square.relative_square(Us, Square.SQ_A1) || s == Square.relative_square(Us, Square.SQ_H1)))
                {
                    var d = Square.pawn_push(Us) + (Square.file_of(s) == File.FILE_A ? Square.DELTA_E : Square.DELTA_W);
                    if (pos.piece_on(s + d) == Piece.make_piece(Us, PieceType.PAWN))
                    {
                        score -= !pos.empty(s + d + Square.pawn_push(Us))
                            ? TrappedBishopA1H1*4
                            : pos.piece_on(s + d + d) == Piece.make_piece(Us, PieceType.PAWN)
                                ? TrappedBishopA1H1*2
                                : TrappedBishopA1H1;
                    }
                }
            }

            if (Pt == PieceType.ROOK)
            {
                // Bonus for aligning with enemy pawns on the same rank/file
                if (Rank.relative_rank_CtSt(Us, s) >= Rank.RANK_5)
                {
                    var alignedPawns = pos.pieces_CtPt(Them, PieceType.PAWN) & Utils.PseudoAttacks[PieceType.ROOK, s];
                    if (alignedPawns!=0)
                    {
                        score += Bitcount.popcount_Max15(alignedPawns)*RookOnPawn;
                    }
                }

                // Bonus when on an open or semi-open file
                if (ei.pi.semiopen_file(Us, Square.file_of(s)) != 0)
                {
                    score += ei.pi.semiopen_file(Them, Square.file_of(s)) != 0 ? RookOnOpenFile : RookOnSemiOpenFile;
                }

                // Penalize when trapped by the king, even more if king cannot castle
                if (mob <= 3 && 0 == ei.pi.semiopen_file(Us, Square.file_of(s)))
                {
                    var ksq = pos.square(PieceType.KING, Us);

                    if (((Square.file_of(ksq) < File.FILE_E) == (Square.file_of(s) < Square.file_of(ksq)))
                        && (Square.rank_of(ksq) == Square.rank_of(s) || Rank.relative_rank_CtSt(Us, ksq) == Rank.RANK_1)
                        && 0 == ei.pi.semiopen_side(Us, Square.file_of(ksq), Square.file_of(s) < Square.file_of(ksq)))
                    {
                        score -= (TrappedRook - Score.make_score(mob*22, 0))*(1 + (pos.can_castle(Us) == 0 ? 1 : 0));
                    }
                }
            }
        }

        if (DoTrace)
        {
            add_IdxCtSt(Pt, Us, score);
        }
        // Recursively call evaluate_pieces() of next piece type until KING excluded
        return score - evaluate_pieces(NextPt, Them, DoTrace, pos, ei, mobility, mobilityArea);
    }
Exemplo n.º 13
0
    // init_eval_info() initializes king bitboards for given color adding
    // pawn attacks. To be done at the beginning of the evaluation.

    private static void init_eval_info(ColorT Us, Position pos, EvalInfo ei)
    {
        var Them = (Us == Color.WHITE ? Color.BLACK : Color.WHITE);
        var Down = (Us == Color.WHITE ? Square.DELTA_S : Square.DELTA_N);

        ei.pinnedPieces[Us] = pos.pinned_pieces(Us);
        var b = ei.attackedBy[Them, PieceType.KING] = pos.attacks_from_PtS(PieceType.KING, pos.square(PieceType.KING, Them));
        ei.attackedBy[Them, PieceType.ALL_PIECES] |= b;
        ei.attackedBy[Us, PieceType.ALL_PIECES] |= ei.attackedBy[Us, PieceType.PAWN] = ei.pi.pawn_attacks(Us);

        // Init king safety tables only if we are going to use them
        if (pos.non_pawn_material(Us) >= Value.QueenValueMg)
        {
            ei.kingRing[Them] = b | Bitboard.shift_bb(Down, b);
            b &= ei.attackedBy[Us, PieceType.PAWN];
            ei.kingAttackersCount[Us] = b!=0 ? Bitcount.popcount_Max15(b) : 0;
            ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0;
        }
        else
        {
            ei.kingRing[Them] = Bitboard.Create(0);
            ei.kingAttackersCount[Us] = 0;
        }
    }