Esempio n. 1
0
    internal static ExtMoveArrayWrapper generate_castling(
        CastlingRight Cr,
        bool Checks,
        bool Chess960,
        Position pos,
        ExtMoveArrayWrapper moveList,
        ColorT us,
        CheckInfo ci)
    {
        var KingSide = (Cr == CastlingRight.WHITE_OO || Cr == CastlingRight.BLACK_OO);

        if (pos.castling_impeded(Cr) || !pos.can_castle(Cr))
        {
            return moveList;
        }

        // After castling, the rook and king final positions are the same in Chess960
        // as they would be in standard chess.
        var kfrom = pos.square(PieceType.KING, us);
        var rfrom = pos.castling_rook_square(Cr);
        var kto = Square.relative_square(us, KingSide ? Square.SQ_G1 : Square.SQ_C1);
        var enemies = pos.pieces_Ct(Color.opposite(us));

        Debug.Assert(pos.checkers() == 0);

        var K = Chess960 ? kto > kfrom ? Square.DELTA_W : Square.DELTA_E : KingSide ? Square.DELTA_W : Square.DELTA_E;

        for (var s = kto; s != kfrom; s += K)
        {
            if ((pos.attackers_to(s) & enemies) != 0)
            {
                return moveList;
            }
        }

        // Because we generate only legal castling moves we need to verify that
        // when moving the castling rook we do not discover some hidden checker.
        // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
        if (Chess960
            && ((Utils.attacks_bb_PtSBb(PieceType.ROOK, kto, Bitboard.XorWithSquare(pos.pieces(), rfrom))
                & pos.pieces_CtPtPt(Color.opposite(us), PieceType.ROOK, PieceType.QUEEN)))!= 0)
        {
            return moveList;
        }

        var m = Move.make(MoveType.CASTLING, kfrom, rfrom);

        if (Checks && !pos.gives_check(m, ci))
        {
            return moveList;
        }

        moveList.Add(m);
        return moveList;
    }
Esempio n. 2
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);
    }
Esempio n. 3
0
    // Map the square as if strongSide is white and strongSide's only pawn
    // is on the left half of the board.
    protected static SquareT normalize(Position pos, ColorT strongSide, SquareT sq)
    {
        Debug.Assert(pos.count(PieceType.PAWN, strongSide) == 1);

        if (Square.file_of(pos.square(PieceType.PAWN, strongSide)) >= File.FILE_E)
        {
            sq = Square.Create(sq ^ 7); // Mirror SQ_H1 -> SQ_A1
        }

        if (strongSide == Color.BLACK)
        {
            sq = Square.opposite(sq);
        }

        return sq;
    }
Esempio n. 4
0
    /// evaluate() is the main evaluation function. It returns a static evaluation
    /// of the position always from the point of view of the side to move.
    internal static ValueT evaluate(bool DoTrace, Position pos)
    {
        Debug.Assert(pos.checkers() == 0);

        var ei = new EvalInfo();
        ScoreT[] mobility = {Score.SCORE_ZERO, Score.SCORE_ZERO};

        // Initialize score by reading the incrementally updated scores included
        // in the position object (material + piece square tables).
        // Score is computed from the point of view of white.
        var score = pos.psq_score();

        // Probe the material hash table
        var me = Material.probe(pos);
        score += me.imbalance();

        // If we have a specialized evaluation function for the current material
        // configuration, call it and return.
        if (me.specialized_eval_exists())
        {
            return me.evaluate(pos);
        }

        // Probe the pawn hash table
        ei.pi = Pawns.probe(pos);
        score += Score.Multiply(ei.pi.pawns_score(), Weights[PawnStructure]);

        // Initialize attack and king safety bitboards
        ei.attackedBy[Color.WHITE, PieceType.ALL_PIECES] =
            ei.attackedBy[Color.BLACK, PieceType.ALL_PIECES] = Bitboard.Create(0);
        init_eval_info(Color.WHITE, pos, ei);
        init_eval_info(Color.BLACK, pos, ei);

        // Pawns blocked or on ranks 2 and 3. Will be excluded from the mobility area
        BitboardT[] blockedPawns =
        {
            pos.pieces_CtPt(Color.WHITE, PieceType.PAWN)
            & (Bitboard.shift_bb(Square.DELTA_S, pos.pieces()) | Bitboard.Rank2BB
               | Bitboard.Rank3BB),
            pos.pieces_CtPt(Color.BLACK, PieceType.PAWN)
            & (Bitboard.shift_bb(Square.DELTA_N, pos.pieces()) | Bitboard.Rank7BB
               | Bitboard.Rank6BB)
        };

        // Do not include in mobility squares protected by enemy pawns, or occupied
        // by our blocked pawns or king.
        BitboardT[] mobilityArea =
        {
            ~(Bitboard.OrWithSquare(ei.attackedBy[Color.BLACK, PieceType.PAWN] | blockedPawns[Color.WHITE]
              , pos.square(PieceType.KING, Color.WHITE))),
            ~(Bitboard.OrWithSquare(ei.attackedBy[Color.WHITE, PieceType.PAWN] | blockedPawns[Color.BLACK]
              , pos.square(PieceType.KING, Color.BLACK)))
        };

        // Evaluate pieces and mobility
        score += evaluate_pieces(PieceType.KNIGHT, Color.WHITE, DoTrace, pos, ei, mobility, mobilityArea);
        score += Score.Multiply(mobility[Color.WHITE] - mobility[Color.BLACK], Weights[Mobility]);

        // Evaluate kings after all other pieces because we need complete attack
        // information when computing the king safety evaluation.
        score += evaluate_king(Color.WHITE, DoTrace, pos, ei) - evaluate_king(Color.BLACK, DoTrace, pos, ei);

        // Evaluate tactical threats, we need full attack information including king
        score += evaluate_threats(Color.WHITE, DoTrace, pos, ei) - evaluate_threats(Color.BLACK, DoTrace, pos, ei);

        // Evaluate passed pawns, we need full attack information including king
        score += evaluate_passed_pawns(Color.WHITE, DoTrace, pos, ei)
                 - evaluate_passed_pawns(Color.BLACK, DoTrace, pos, ei);

        // If both sides have only pawns, score for potential unstoppable pawns
        if (pos.non_pawn_material(Color.WHITE) == 0 && pos.non_pawn_material(Color.BLACK) == 0)
        {
            BitboardT b;
            if ((b = ei.pi.passed_pawns(Color.WHITE)) != 0)
            {
                score += Rank.relative_rank_CtSt(Color.WHITE, Utils.frontmost_sq(Color.WHITE, b)) * Unstoppable;
            }

            if ((b = ei.pi.passed_pawns(Color.BLACK)) != 0)
            {
                score -= Rank.relative_rank_CtSt(Color.BLACK, Utils.frontmost_sq(Color.BLACK, b)) * Unstoppable;
            }
        }

        // Evaluate space for both sides, only during opening
        if (pos.non_pawn_material(Color.WHITE) + pos.non_pawn_material(Color.BLACK) >= 12222)
        {
            score += Score.Multiply(evaluate_space(Color.WHITE, pos, ei) - evaluate_space(Color.BLACK, pos, ei), Weights[Space]);
        }

        // Scale winning side if position is more drawish than it appears
        var strongSide = Score.eg_value(score) > Value.VALUE_DRAW ? Color.WHITE : Color.BLACK;
        var sf = me.scale_factor(pos, strongSide);

        // If we don't already have an unusual scale factor, check for certain
        // types of endgames, and use a lower scale for those.
        if (me.game_phase() < Phase.PHASE_MIDGAME
            && (sf == ScaleFactor.SCALE_FACTOR_NORMAL || sf == ScaleFactor.SCALE_FACTOR_ONEPAWN))
        {
            if (pos.opposite_bishops())
            {
                // Endgame with opposite-colored bishops and no other pieces (ignoring pawns)
                // is almost a draw, in case of KBP vs KB is even more a draw.
                if (pos.non_pawn_material(Color.WHITE) == Value.BishopValueMg
                    && pos.non_pawn_material(Color.BLACK) == Value.BishopValueMg)
                {
                    sf = Bitboard.more_than_one(pos.pieces_Pt(PieceType.PAWN)) ? (ScaleFactor) (31) : (ScaleFactor) (9);
                }

                // Endgame with opposite-colored bishops, but also other pieces. Still
                // a bit drawish, but not as drawish as with only the two bishops.
                else
                {
                    sf = (ScaleFactor) (46*(int) sf/(int) ScaleFactor.SCALE_FACTOR_NORMAL);
                }
            }
            // Endings where weaker side can place his king in front of the opponent's
            // pawns are drawish.
            else if (Math.Abs(Score.eg_value(score)) <= Value.BishopValueEg && ei.pi.pawn_span(strongSide) <= 1
                     && !pos.pawn_passed(Color.opposite(strongSide), pos.square(PieceType.KING, Color.opposite(strongSide))))
            {
                sf = ei.pi.pawn_span(strongSide) != 0 ? (ScaleFactor) (51) : (ScaleFactor) (37);
            }
        }

        // Scale endgame by number of pawns
        var p = pos.count(PieceType.PAWN, Color.WHITE) + pos.count(PieceType.PAWN, Color.BLACK);
        var vEg = 1 + Math.Abs(Score.eg_value(score));
        sf = (ScaleFactor) (Math.Max((int) sf/2, (int) sf - 8*(int) ScaleFactor.SCALE_FACTOR_NORMAL*(12 - p)/vEg));

        // Interpolate between a middlegame and a (scaled by 'sf') endgame score
        var v = Score.mg_value(score)*(int) (me.game_phase())
                + Score.eg_value(score)*(Phase.PHASE_MIDGAME - me.game_phase())*(int) sf
                /(int) ScaleFactor.SCALE_FACTOR_NORMAL;

        v /= (int) (Phase.PHASE_MIDGAME);

        // In case of tracing add all single evaluation terms
        if (DoTrace)
        {
            add_IdxSt((int) Term.MATERIAL, pos.psq_score());
            add_IdxSt((int) Term.IMBALANCE, me.imbalance());
            add_IdxSt(PieceType.PAWN, ei.pi.pawns_score());
            add_IdxStSt(
                (int) Term.MOBILITY,
                Score.Multiply(mobility[Color.WHITE], Weights[Mobility]),
                Score.Multiply(mobility[Color.BLACK], Weights[Mobility]));
            add_IdxStSt(
                (int) Term.SPACE,
                Score.Multiply(evaluate_space(Color.WHITE, pos, ei), Weights[Space]),
                Score.Multiply(evaluate_space(Color.BLACK, pos, ei), Weights[Space]));
            add_IdxSt((int) Term.TOTAL, score);
        }

        return (pos.side_to_move() == Color.WHITE ? v : -v) + Tempo; // Side to move point of view
    }
Esempio n. 5
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;
    }
Esempio n. 6
0
    internal override ScaleFactor GetScaleFactor(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.BishopValueMg, 1));
        Debug.Assert(verify_material(pos, weakSide, Value.KnightValueMg, 0));

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

        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;
        }

        return ScaleFactor.SCALE_FACTOR_NONE;
    }
Esempio n. 7
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;
    }
Esempio n. 8
0
    internal override ScaleFactor GetScaleFactor(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.RookValueMg, 2));
        Debug.Assert(verify_material(pos, weakSide, Value.RookValueMg, 1));

        var wpsq1 = pos.square(PieceType.PAWN, strongSide, 0);
        var wpsq2 = pos.square(PieceType.PAWN, strongSide, 1);
        var bksq = pos.square(PieceType.KING, weakSide);

        // Does the stronger side have a passed pawn?
        if (pos.pawn_passed(strongSide, wpsq1) || pos.pawn_passed(strongSide, wpsq2))
        {
            return ScaleFactor.SCALE_FACTOR_NONE;
        }

        var r = Math.Max(Rank.relative_rank_CtSt(strongSide, wpsq1), Rank.relative_rank_CtSt(strongSide, wpsq2));

        if (Utils.distance_File(bksq, wpsq1) <= 1 && Utils.distance_File(bksq, wpsq2) <= 1
            && Rank.relative_rank_CtSt(strongSide, bksq) > r)
        {
            switch (r)
            {
                case 1 /*Rank.RANK_2*/:
                    return (ScaleFactor) (9);
                case 2 /*Rank.RANK_3*/:
                    return (ScaleFactor) (10);
                case 3 /*Rank.RANK_4*/:
                    return (ScaleFactor) (14);
                case 4 /*Rank.RANK_5*/:
                    return (ScaleFactor) (21);
                case 5 /*Rank.RANK_6*/:
                    return (ScaleFactor) (44);
                default:
                    Debug.Assert(false);
                    break;
            }
        }
        return ScaleFactor.SCALE_FACTOR_NONE;
    }
Esempio n. 9
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;
    }
Esempio n. 10
0
    internal static ScoreT evaluate(ColorT Us, Position pos, Entry e)
    {
        var Them = (Us == Color.WHITE ? Color.BLACK : Color.WHITE);
        var Up = (Us == Color.WHITE ? Square.DELTA_N : Square.DELTA_S);
        var Right = (Us == Color.WHITE ? Square.DELTA_NE : Square.DELTA_SW);
        var Left = (Us == Color.WHITE ? Square.DELTA_NW : Square.DELTA_SE);

        BitboardT b;

        var score = Score.SCORE_ZERO;
        
        var ourPawns = pos.pieces_CtPt(Us, PieceType.PAWN);
        var theirPawns = pos.pieces_CtPt(Them, PieceType.PAWN);

        e.passedPawns[Us] = Bitboard.Create(0);
        e.kingSquares[Us] = Square.SQ_NONE;
        e.semiopenFiles[Us] = 0xFF;
        e.pawnAttacks[Us] = Bitboard.shift_bb(Right, ourPawns) | Bitboard.shift_bb(Left, ourPawns);
        e.pawnsOnSquares[Us, Color.BLACK] = Bitcount.popcount_Max15(ourPawns & Bitboard.DarkSquares);
        e.pawnsOnSquares[Us, Color.WHITE] = pos.count(PieceType.PAWN, Us) - e.pawnsOnSquares[Us, Color.BLACK];

        // Loop through all pawns of the current color and score each pawn
        for (var idx = 0; idx < 16; idx++)
        {
            var s = pos.square(PieceType.PAWN, Us, idx);
            if (s == Square.SQ_NONE)
            {
                break;
            }

            Debug.Assert(pos.piece_on(s) == Piece.make_piece(Us, PieceType.PAWN));

            var f = Square.file_of(s);

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

            // Flag the pawn
            var neighbours = ourPawns & Utils.adjacent_files_bb(f);
            var doubled = ourPawns & Utils.forward_bb(Us, s);
            bool opposed = (theirPawns & Utils.forward_bb(Us, s)) != 0;
            var passed = (theirPawns & Utils.passed_pawn_mask(Us, s)) == 0;
            bool lever = (theirPawns & Utils.StepAttacksBB[Piece.make_piece(Us, PieceType.PAWN), s]) != 0;
            var phalanx = neighbours & Utils.rank_bb_St(s);
            var supported = neighbours & Utils.rank_bb_St(s - Up);
            bool connected = (supported | phalanx) != 0;
            var isolated = neighbours == 0;

            // Test for backward pawn.
            // If the pawn is passed, isolated, lever or connected it cannot be
            // backward. If there are friendly pawns behind on adjacent files
            // or if it is sufficiently advanced, it cannot be backward either.
            bool backward;
            if ((passed | isolated | lever | connected) || (ourPawns & Utils.pawn_attack_span(Them, s)) != 0
                || (Rank.relative_rank_CtSt(Us, s) >= Rank.RANK_5))
            {
                backward = false;
            }
            else
            {
                // We now know 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 = Utils.pawn_attack_span(Us, s) & (ourPawns | theirPawns);
                b = Utils.pawn_attack_span(Us, s) & Utils.rank_bb_St(Utils.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(Up, b)) & theirPawns) != 0;
            }

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

            // 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 && doubled == 0)
            {
                e.passedPawns[Us] = Bitboard.OrWithSquare(e.passedPawns[Us], s);
            }

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

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

            else if (supported == 0)
            {
                score -= UnsupportedPawnPenalty;
            }

            if (connected)
            {
                score +=
                    Connected[
                        opposed ? 1 : 0,
                        phalanx != 0 ? 1 : 0,
                        Bitboard.more_than_one(supported) ? 1 : 0,
                        Rank.relative_rank_CtSt(Us, s)];
            }

            if (doubled != 0)
            {
                score -= Score.Divide(Doubled[f], Utils.distance_Rank_StSt(s, Utils.frontmost_sq(Us, doubled)));
            }

            if (lever)
            {
                score += Lever[Rank.relative_rank_CtSt(Us, s)];
            }
        }

        b = Bitboard.Create((uint) (e.semiopenFiles[Us] ^ 0xFF));
        e.pawnSpan[Us] = b != 0 ? Utils.msb(b) - (int)Utils.lsb(b) : 0;

        // Center binds: Two pawns controlling the same central square
        b = Bitboard.shift_bb(Right, ourPawns) & Bitboard.shift_bb(Left, ourPawns) & CenterBindMask[Us];
        score += Bitcount.popcount_Max15(b)*CenterBind;

        return score;
    }
Esempio n. 11
0
    /// generate
    /// LEGAL generates all the legal moves in the given position
    private static ExtMoveArrayWrapper generate_LEGAL(Position pos, ExtMoveArrayWrapper moveList)
    {
        var pinned = pos.pinned_pieces(pos.side_to_move());
        var ksq = pos.square(PieceType.KING, pos.side_to_move());
        var cur = moveList.current;

        moveList = pos.checkers() != 0
            ? generate(GenType.EVASIONS, pos, moveList)
            : generate(GenType.NON_EVASIONS, pos, moveList);

        while (cur != moveList.current)
        {
            if ((pinned != 0 || Move.from_sq(moveList[cur]) == ksq || Move.type_of(moveList[cur]) == MoveType.ENPASSANT)
                && !pos.legal(moveList[cur], pinned))
            {
                for (var idx = cur; idx < moveList.current; idx++)
                {
                    moveList.table[idx] = moveList.table[idx + 1];
                }
                --moveList;
            }
            else
            {
                ++cur;
            }
        }

        return moveList;
    }
Esempio n. 12
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);
    }
Esempio n. 13
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;
    }
Esempio n. 14
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;
    }
Esempio n. 15
0
    internal override ValueT GetValue(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.QueenValueMg, 0));
        Debug.Assert(verify_material(pos, weakSide, Value.RookValueMg, 0));

        var winnerKSq = pos.square(PieceType.KING, strongSide);
        var loserKSq = pos.square(PieceType.KING, weakSide);

        var result = Value.QueenValueEg - Value.RookValueEg + PushToEdges[loserKSq]
                     + PushClose[Utils.distance_Square(winnerKSq, loserKSq)];

        return strongSide == pos.side_to_move() ? result : -result;
    }
Esempio n. 16
0
    internal override ValueT GetValue(Position pos)
    {
        Debug.Assert(verify_material(pos, weakSide, Value.VALUE_ZERO, 0));
        Debug.Assert(pos.checkers()==0); // Eval is never called when in check

        // Stalemate detection with lone king
        if (pos.side_to_move() == weakSide && new MoveList(GenType.LEGAL, pos).size() == 0)
        {
            return Value.VALUE_DRAW;
        }

        var winnerKSq = pos.square(PieceType.KING, strongSide);
        var loserKSq = pos.square(PieceType.KING, weakSide);

        var result = pos.non_pawn_material(strongSide)
                     + pos.count(PieceType.PAWN, strongSide)*Value.PawnValueEg + PushToEdges[loserKSq]
                     + PushClose[Utils.distance_Square(winnerKSq, loserKSq)];

        if (pos.count(PieceType.QUEEN, strongSide) > 0 || pos.count(PieceType.ROOK, strongSide) > 0
            || (pos.count(PieceType.BISHOP, strongSide) > 0 && pos.count(PieceType.KNIGHT, strongSide) > 0)
            || (pos.count(PieceType.BISHOP, strongSide) > 1
                && Square.opposite_colors(
                    pos.square(PieceType.BISHOP, strongSide, 0),
                    pos.square(PieceType.BISHOP, strongSide, 1))))
        {
            result += Value.VALUE_KNOWN_WIN;
        }

        return strongSide == pos.side_to_move() ? result : -result;
    }
Esempio n. 17
0
    internal override ScaleFactor GetScaleFactor(Position pos)
    {
        Debug.Assert(pos.non_pawn_material(strongSide) == Value.BishopValueMg);
        Debug.Assert(pos.count(PieceType.PAWN, strongSide) >= 1);

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

        var pawns = pos.pieces_CtPt(strongSide, PieceType.PAWN);
        var pawnsFile = Square.file_of(Utils.lsb(pawns));

        // All pawns are on a single rook file?
        if ((pawnsFile == File.FILE_A || pawnsFile == File.FILE_H) && (pawns & ~Utils.file_bb_Ft(pawnsFile))==0)
        {
            var bishopSq = pos.square(PieceType.BISHOP, strongSide);
            var queeningSq = Square.relative_square(strongSide, Square.make_square(pawnsFile, Rank.RANK_8));
            var kingSq = pos.square(PieceType.KING, weakSide);

            if (Square.opposite_colors(queeningSq, bishopSq) && Utils.distance_Square(queeningSq, kingSq) <= 1)
            {
                return ScaleFactor.SCALE_FACTOR_DRAW;
            }
        }

        // If all the pawns are on the same B or G file, then it's potentially a draw
        if ((pawnsFile == File.FILE_B || pawnsFile == File.FILE_G)
            && (pos.pieces_Pt(PieceType.PAWN) & ~Utils.file_bb_Ft(pawnsFile))==0 && pos.non_pawn_material(weakSide) == 0
            && pos.count(PieceType.PAWN, weakSide) >= 1)
        {
            // Get weakSide pawn that is closest to the home rank
            var weakPawnSq = Utils.backmost_sq(weakSide, pos.pieces_CtPt(weakSide, PieceType.PAWN));

            var strongKingSq = pos.square(PieceType.KING, strongSide);
            var weakKingSq = pos.square(PieceType.KING, weakSide);
            var bishopSq = pos.square(PieceType.BISHOP, strongSide);

            // 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 (Rank.relative_rank_CtSt(strongSide, weakPawnSq) == Rank.RANK_7
                && Bitboard.AndWithSquare(pos.pieces_CtPt(strongSide, PieceType.PAWN), (weakPawnSq + Square.pawn_push(weakSide)))!=0
                && (Square.opposite_colors(bishopSq, weakPawnSq) || pos.count(PieceType.PAWN, strongSide) == 1))
            {
                var strongKingDist = Utils.distance_Square(weakPawnSq, strongKingSq);
                var weakKingDist = Utils.distance_Square(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 (Rank.relative_rank_CtSt(strongSide, weakKingSq) >= Rank.RANK_7 && weakKingDist <= 2
                    && weakKingDist <= strongKingDist)
                {
                    return ScaleFactor.SCALE_FACTOR_DRAW;
                }
            }
        }

        return ScaleFactor.SCALE_FACTOR_NONE;
    }
Esempio n. 18
0
    internal override ValueT GetValue(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.KnightValueMg + Value.BishopValueMg, 0));
        Debug.Assert(verify_material(pos, weakSide, Value.VALUE_ZERO, 0));

        var winnerKSq = pos.square(PieceType.KING, strongSide);
        var loserKSq = pos.square(PieceType.KING, weakSide);
        var bishopSq = pos.square(PieceType.BISHOP, strongSide);

        // kbnk_mate_table() tries to drive toward corners A1 or H8. If we have a
        // bishop that cannot reach the above squares, we flip the kings in order
        // to drive the enemy toward corners A8 or H1.
        if (Square.opposite_colors(bishopSq, Square.SQ_A1))
        {
            winnerKSq = Square.opposite(winnerKSq);
            loserKSq = Square.opposite(loserKSq);
        }

        var result = Value.VALUE_KNOWN_WIN + PushClose[Utils.distance_Square(winnerKSq, loserKSq)]
                     + PushToCorners[loserKSq];

        return strongSide == pos.side_to_move() ? result : -result;
    }
Esempio n. 19
0
    internal override ScaleFactor GetScaleFactor(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.RookValueMg, 1));
        Debug.Assert(verify_material(pos, weakSide, Value.RookValueMg, 0));

        // Assume strongSide is white and the pawn is on files A-D
        var wksq = normalize(pos, strongSide, pos.square(PieceType.KING, strongSide));
        var bksq = normalize(pos, strongSide, pos.square(PieceType.KING, weakSide));
        var wrsq = normalize(pos, strongSide, pos.square(PieceType.ROOK, strongSide));
        var wpsq = normalize(pos, strongSide, pos.square(PieceType.PAWN, strongSide));
        var brsq = normalize(pos, strongSide, pos.square(PieceType.ROOK, weakSide));

        var f = Square.file_of(wpsq);
        var r = Square.rank_of(wpsq);
        var queeningSq = Square.make_square(f, Rank.RANK_8);
        var tempo = (pos.side_to_move() == strongSide) ? 1 : 0;

        // If the pawn is not too far advanced and the defending king defends the
        // queening square, use the third-rank defence.
        if (r <= Rank.RANK_5 && Utils.distance_Square(bksq, queeningSq) <= 1 && wksq <= Square.SQ_H5
            && (Square.rank_of(brsq) == Rank.RANK_6 || (r <= Rank.RANK_3 && Square.rank_of(wrsq) != Rank.RANK_6)))
        {
            return ScaleFactor.SCALE_FACTOR_DRAW;
        }

        // The defending side saves a draw by checking from behind in case the pawn
        // has advanced to the 6th rank with the king behind.
        if (r == Rank.RANK_6 && Utils.distance_Square(bksq, queeningSq) <= 1
            && (int)Square.rank_of(wksq) + tempo <= Rank.RANK_6
            && (Square.rank_of(brsq) == Rank.RANK_1 || (tempo == 0 && Utils.distance_File(brsq, wpsq) >= 3)))
        {
            return ScaleFactor.SCALE_FACTOR_DRAW;
        }

        if (r >= Rank.RANK_6 && bksq == queeningSq && Square.rank_of(brsq) == Rank.RANK_1
            && (tempo == 0 || Utils.distance_Square(wksq, wpsq) >= 2))
        {
            return ScaleFactor.SCALE_FACTOR_DRAW;
        }

        // White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7
        // and the black rook is behind the pawn.
        if (wpsq == Square.SQ_A7 && wrsq == Square.SQ_A8 && (bksq == Square.SQ_H7 || bksq == Square.SQ_G7)
            && Square.file_of(brsq) == File.FILE_A
            && (Square.rank_of(brsq) <= Rank.RANK_3 || Square.file_of(wksq) >= File.FILE_D
                || Square.rank_of(wksq) <= Rank.RANK_5))
        {
            return ScaleFactor.SCALE_FACTOR_DRAW;
        }

        // If the defending king blocks the pawn and the attacking king is too far
        // away, it's a draw.
        if (r <= Rank.RANK_5 && bksq == wpsq + Square.DELTA_N && Utils.distance_Square(wksq, wpsq) - tempo >= 2
            && Utils.distance_Square(wksq, brsq) - tempo >= 2)
        {
            return ScaleFactor.SCALE_FACTOR_DRAW;
        }

        // Pawn on the 7th rank supported by the rook from behind usually wins if the
        // attacking king is closer to the queening square than the defending king,
        // and the defending king cannot gain tempi by threatening the attacking rook.
        if (r == Rank.RANK_7 && f != File.FILE_A && Square.file_of(wrsq) == f && wrsq != queeningSq
            && (Utils.distance_Square(wksq, queeningSq) < Utils.distance_Square(bksq, queeningSq) - 2 + tempo)
            && (Utils.distance_Square(wksq, queeningSq) < Utils.distance_Square(bksq, wrsq) + tempo))
        {
            return ScaleFactor.SCALE_FACTOR_MAX - 2*Utils.distance_Square(wksq, queeningSq);
        }

        // Similar to the above, but with the pawn further back
        if (f != File.FILE_A && Square.file_of(wrsq) == f && wrsq < wpsq
            && (Utils.distance_Square(wksq, queeningSq) < Utils.distance_Square(bksq, queeningSq) - 2 + tempo)
            && (Utils.distance_Square(wksq, wpsq + Square.DELTA_N)
                < Utils.distance_Square(bksq, wpsq + Square.DELTA_N) - 2 + tempo)
            && (Utils.distance_Square(bksq, wrsq) + tempo >= 3
                || (Utils.distance_Square(wksq, queeningSq) < Utils.distance_Square(bksq, wrsq) + tempo
                    && (Utils.distance_Square(wksq, wpsq + Square.DELTA_N) < Utils.distance_Square(bksq, wrsq) + tempo))))
        {
            return ScaleFactor.SCALE_FACTOR_MAX - 8*Utils.distance_Square(wpsq, queeningSq)
                   - 2*Utils.distance_Square(wksq, queeningSq);
        }

        // If the pawn is not far advanced and the defending king is somewhere in
        // the pawn's path, it's probably a draw.
        if (r <= Rank.RANK_4 && bksq > wpsq)
        {
            if (Square.file_of(bksq) == Square.file_of(wpsq))
            {
                return (ScaleFactor) (10);
            }
            if (Utils.distance_File(bksq, wpsq) == 1 && Utils.distance_Square(wksq, bksq) > 2)
            {
                return (ScaleFactor) (24 - 2*Utils.distance_Square(wksq, bksq));
            }
        }
        return ScaleFactor.SCALE_FACTOR_NONE;
    }
Esempio n. 20
0
    internal override ValueT GetValue(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.VALUE_ZERO, 1));
        Debug.Assert(verify_material(pos, weakSide, Value.VALUE_ZERO, 0));

        // Assume strongSide is white and the pawn is on files A-D
        var wksq = normalize(pos, strongSide, pos.square(PieceType.KING, strongSide));
        var bksq = normalize(pos, strongSide, pos.square(PieceType.KING, weakSide));
        var psq = normalize(pos, strongSide, pos.square(PieceType.PAWN, strongSide));

        var us = strongSide == pos.side_to_move() ? Color.WHITE : Color.BLACK;

        if (!Bitbases.probe(wksq, psq, bksq, us))
        {
            return Value.VALUE_DRAW;
        }

        var result = Value.VALUE_KNOWN_WIN + Value.PawnValueEg + Value.Create(Square.rank_of(psq));

        return strongSide == pos.side_to_move() ? result : -result;
    }
Esempio n. 21
0
    internal override ScaleFactor GetScaleFactor(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.RookValueMg, 1));
        Debug.Assert(verify_material(pos, weakSide, Value.BishopValueMg, 0));

        // Test for a rook pawn
        if ((pos.pieces_Pt(PieceType.PAWN) & (Bitboard.FileABB | Bitboard.FileHBB))!=0)
        {
            var ksq = pos.square(PieceType.KING, weakSide);
            var bsq = pos.square(PieceType.BISHOP, weakSide);
            var psq = pos.square(PieceType.PAWN, strongSide);
            var rk = Rank.relative_rank_CtSt(strongSide, psq);
            var push = Square.pawn_push(strongSide);

            // If the pawn is on the 5th rank and the pawn (currently) is on
            // the same color square as the bishop then there is a chance of
            // a fortress. Depending on the king position give a moderate
            // reduction or a stronger one if the defending king is near the
            // corner but not trapped there.
            if (rk == Rank.RANK_5 && !Square.opposite_colors(bsq, psq))
            {
                var d = Utils.distance_Square(psq + 3*push, ksq);

                if (d <= 2 && !(d == 0 && ksq == pos.square(PieceType.KING, strongSide) + 2*push))
                {
                    return (ScaleFactor) (24);
                }
                return (ScaleFactor) (48);
            }

            // When the pawn has moved to the 6th rank we can be fairly sure
            // it's drawn if the bishop attacks the square in front of the
            // pawn from a reasonable distance and the defending king is near
            // the corner
            if (rk == Rank.RANK_6 && Utils.distance_Square(psq + 2*push, ksq) <= 1
                && Bitboard.AndWithSquare(Utils.PseudoAttacks[PieceType.BISHOP, bsq], (psq + push))!=0 && Utils.distance_File(bsq, psq) >= 2)
            {
                return (ScaleFactor) (8);
            }
        }

        return ScaleFactor.SCALE_FACTOR_NONE;
    }
Esempio n. 22
0
    internal override ValueT GetValue(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.RookValueMg, 0));
        Debug.Assert(verify_material(pos, weakSide, Value.VALUE_ZERO, 1));

        var wksq = Square.relative_square(strongSide, pos.square(PieceType.KING, strongSide));
        var bksq = Square.relative_square(strongSide, pos.square(PieceType.KING, weakSide));
        var rsq = Square.relative_square(strongSide, pos.square(PieceType.ROOK, strongSide));
        var psq = Square.relative_square(strongSide, pos.square(PieceType.PAWN, weakSide));

        var queeningSq = Square.make_square(Square.file_of(psq), Rank.RANK_1);
        ValueT result;

        // If the stronger side's king is in front of the pawn, it's a win
        if (wksq < psq && Square.file_of(wksq) == Square.file_of(psq))
        {
            result = Value.RookValueEg - Utils.distance_Square(wksq, psq);
        }

        // If the weaker side's king is too far from the pawn and the rook,
        // it's a win.
        else if (Utils.distance_Square(bksq, psq) >= 3 + (pos.side_to_move() == weakSide ? 1 : 0)
                 && Utils.distance_Square(bksq, rsq) >= 3)
        {
            result = Value.RookValueEg - Utils.distance_Square(wksq, psq);
        }

        // If the pawn is far advanced and supported by the defending king,
        // the position is drawish
        else if (Square.rank_of(bksq) <= Rank.RANK_3 && Utils.distance_Square(bksq, psq) == 1
                 && Square.rank_of(wksq) >= Rank.RANK_4
                 && Utils.distance_Square(wksq, psq) > 2 + (pos.side_to_move() == strongSide ? 1 : 0))
        {
            result = Value.Create(80) - 8*Utils.distance_Square(wksq, psq);
        }

        else
        {
            result = Value.Create(200)
                     - 8
                     *(Utils.distance_Square(wksq, psq + Square.DELTA_S)
                       - Utils.distance_Square(bksq, psq + Square.DELTA_S)
                       - Utils.distance_Square(psq, queeningSq));
        }

        return strongSide == pos.side_to_move() ? result : -result;
    }
Esempio n. 23
0
    internal override ScaleFactor GetScaleFactor(Position pos)
    {
        Debug.Assert(pos.non_pawn_material(strongSide) == Value.VALUE_ZERO);
        Debug.Assert(pos.count(PieceType.PAWN, strongSide) >= 2);
        Debug.Assert(verify_material(pos, weakSide, Value.VALUE_ZERO, 0));

        var ksq = pos.square(PieceType.KING, weakSide);
        var pawns = pos.pieces_CtPt(strongSide, PieceType.PAWN);

        // If all pawns are ahead of the king, on a single rook file and
        // the king is within one file of the pawns, it's a draw.
        if ((pawns & ~Utils.in_front_bb(weakSide, Square.rank_of(ksq)))==0
            && !((pawns & ~Bitboard.FileABB)!=0 && (pawns & ~Bitboard.FileHBB)!=0)
            && Utils.distance_File(ksq, Utils.lsb(pawns)) <= 1)
        {
            return ScaleFactor.SCALE_FACTOR_DRAW;
        }

        return ScaleFactor.SCALE_FACTOR_NONE;
    }
Esempio n. 24
0
    internal override ValueT GetValue(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.RookValueMg, 0));
        Debug.Assert(verify_material(pos, weakSide, Value.BishopValueMg, 0));

        var result = Value.Create(PushToEdges[pos.square(PieceType.KING, weakSide)]);
        return strongSide == pos.side_to_move() ? result : -result;
    }
Esempio n. 25
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;
        }
    }
Esempio n. 26
0
    internal override ValueT GetValue(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.RookValueMg, 0));
        Debug.Assert(verify_material(pos, weakSide, Value.KnightValueMg, 0));

        var bksq = pos.square(PieceType.KING, weakSide);
        var bnsq = pos.square(PieceType.KNIGHT, weakSide);
        var result = Value.Create(PushToEdges[bksq] + PushAway[Utils.distance_Square(bksq, bnsq)]);
        return strongSide == pos.side_to_move() ? result : -result;
    }
Esempio n. 27
0
    internal override ScaleFactor GetScaleFactor(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.KnightValueMg, 1));
        Debug.Assert(verify_material(pos, weakSide, Value.VALUE_ZERO, 0));

        // Assume strongSide is white and the pawn is on files A-D
        var pawnSq = normalize(pos, strongSide, pos.square(PieceType.PAWN, strongSide));
        var weakKingSq = normalize(pos, strongSide, pos.square(PieceType.KING, weakSide));

        if (pawnSq == Square.SQ_A7 && Utils.distance_Square(Square.SQ_A8, weakKingSq) <= 1)
        {
            return ScaleFactor.SCALE_FACTOR_DRAW;
        }

        return ScaleFactor.SCALE_FACTOR_NONE;
    }
Esempio n. 28
0
    internal override ValueT GetValue(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.QueenValueMg, 0));
        Debug.Assert(verify_material(pos, weakSide, Value.VALUE_ZERO, 1));

        var winnerKSq = pos.square(PieceType.KING, strongSide);
        var loserKSq = pos.square(PieceType.KING, weakSide);
        var pawnSq = pos.square(PieceType.PAWN, weakSide);

        var result = Value.Create(PushClose[Utils.distance_Square(winnerKSq, loserKSq)]);

        if (Rank.relative_rank_CtSt(weakSide, pawnSq) != Rank.RANK_7 || Utils.distance_Square(loserKSq, pawnSq) != 1
            || Bitboard.AndWithSquare((Bitboard.FileABB | Bitboard.FileCBB | Bitboard.FileFBB | Bitboard.FileHBB), pawnSq)==0)
        {
            result += Value.QueenValueEg - Value.PawnValueEg;
        }

        return strongSide == pos.side_to_move() ? result : -result;
    }
Esempio n. 29
0
    internal override ScaleFactor GetScaleFactor(Position pos)
    {
        Debug.Assert(verify_material(pos, strongSide, Value.VALUE_ZERO, 1));
        Debug.Assert(verify_material(pos, weakSide, Value.VALUE_ZERO, 1));

        // Assume strongSide is white and the pawn is on files A-D
        var wksq = normalize(pos, strongSide, pos.square(PieceType.KING, strongSide));
        var bksq = normalize(pos, strongSide, pos.square(PieceType.KING, weakSide));
        var psq = normalize(pos, strongSide, pos.square(PieceType.PAWN, strongSide));

        var us = strongSide == pos.side_to_move() ? Color.WHITE : Color.BLACK;

        // If the pawn has advanced to the fifth rank or further, and is not a
        // rook pawn, it's too dangerous to assume that it's at least a draw.
        if (Square.rank_of(psq) >= Rank.RANK_5 && Square.file_of(psq) != File.FILE_A)
        {
            return ScaleFactor.SCALE_FACTOR_NONE;
        }

        // Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw,
        // it's probably at least a draw even with the pawn.
        return Bitbases.probe(wksq, psq, bksq, us) ? ScaleFactor.SCALE_FACTOR_NONE : ScaleFactor.SCALE_FACTOR_DRAW;
    }
Esempio n. 30
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]);
    }