Пример #1
0
        // evaluate_pieces_of_color<>() assigns bonuses and penalties to all the
        // pieces of a given color.
        private static int evaluate_pieces_of_color(int Us, bool Trace, Position pos, EvalInfo ei, ref int mobility)
        {
            var Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);
            mobility = ScoreC.SCORE_ZERO;

            // Do not include in mobility squares protected by enemy pawns or occupied by our pieces
            var mobilityArea = ~(ei.attackedBy[Them][PieceTypeC.PAWN] | pos.byColorBB[Us]);

            #region Evaluate pieces

            ulong between = 0;
            var plPos = 0;
            int s, ksq;
            int mob;
            int f;
            int score, scores = ScoreC.SCORE_ZERO;

            var attackedByThemKing = ei.attackedBy[Them][PieceTypeC.KING];
            var attackedByThemPawn = ei.attackedBy[Them][PieceTypeC.PAWN];
            var kingRingThem = ei.kingRing[Them];

            for (var Piece = PieceTypeC.KNIGHT; Piece < PieceTypeC.KING; Piece++)
            {
                score = ScoreC.SCORE_ZERO;
                ei.attackedBy[Us][Piece] = 0;
                var pl = pos.pieceList[Us][Piece];
                plPos = 0;
                while ((s = pl[plPos++]) != SquareC.SQ_NONE)
                {
                    // Find attacked squares, including x-ray attacks for bishops and rooks
                    if (Piece == PieceTypeC.KNIGHT)
                    {
                        between = Utils.StepAttacksBB_KNIGHT[s];
                    }
                    else if (Piece == PieceTypeC.QUEEN)
                    {
#if X64
                        b = Utils.BAttacks[s][(((pos.occupied_squares & Utils.BMasks[s]) * Utils.BMagics[s]) >> Utils.BShifts[s])] | Utils.RAttacks[s][(((pos.occupied_squares & Utils.RMasks[s]) * Utils.RMagics[s]) >> Utils.RShifts[s])];
#else
                        between = Utils.bishop_attacks_bb(s, pos.occupied_squares)
                            | Utils.rook_attacks_bb(s, pos.occupied_squares);
#endif
                    }
                    else if (Piece == PieceTypeC.BISHOP)
                    {
#if X64
                        b = Utils.BAttacks[s][(((
                              (pos.occupied_squares ^ (pos.byTypeBB[PieceTypeC.QUEEN] & pos.byColorBB[Us]))
                            & Utils.BMasks[s]) * Utils.BMagics[s]) >> Utils.BShifts[s])];
#else
                        between = Utils.bishop_attacks_bb(s, pos.occupied_squares ^ pos.pieces_PTC(PieceTypeC.QUEEN, Us));
#endif
                    }
                    else if (Piece == PieceTypeC.ROOK)
                    {
#if X64
                        b = Utils.RAttacks[s][(((
                              (pos.occupied_squares ^ ((pos.byTypeBB[PieceTypeC.ROOK] | pos.byTypeBB[PieceTypeC.QUEEN]) & pos.byColorBB[Us]))
                            & Utils.RMasks[s]) * Utils.RMagics[s]) >> Utils.RShifts[s])];
#else
                        between = Utils.rook_attacks_bb(
                            s,
                            pos.occupied_squares ^ pos.pieces(PieceTypeC.ROOK, PieceTypeC.QUEEN, Us));
#endif
                    }

                    // Update attack info
                    ei.attackedBy[Us][Piece] |= between;

                    // King attacks
                    if ((between & kingRingThem) != 0)
                    {
                        ei.kingAttackersCount[Us]++;
                        ei.kingAttackersWeight[Us] += KingAttackWeights[Piece];
                        var bb = (between & attackedByThemKing); //ei.attackedBy[Them][PieceTypeC.KING]);
                        if (bb != 0)
                        {
#if X64
                            bb -= (bb >> 1) & 0x5555555555555555UL;
                            bb = ((bb >> 2) & 0x3333333333333333UL) + (bb & 0x3333333333333333UL);
                            ei.kingAdjacentZoneAttacksCount[Us] += (int)((bb * 0x1111111111111111UL) >> 60);
#else
                            ei.kingAdjacentZoneAttacksCount[Us] += Bitcount.popcount_1s_Max15(bb);
#endif
                        }
                    }

                    // Mobility
#if X64
                    Bitboard bmob = b & mobilityArea;
                    if (Piece != PieceTypeC.QUEEN)
                    {
                        bmob -= (bmob >> 1) & 0x5555555555555555UL;
                        bmob = ((bmob >> 2) & 0x3333333333333333UL) + (bmob & 0x3333333333333333UL);
                        mob = (int)((bmob * 0x1111111111111111UL) >> 60);
                    }
                    else
                    {
                        bmob -= ((bmob >> 1) & 0x5555555555555555UL);
                        bmob = ((bmob >> 2) & 0x3333333333333333UL) + (bmob & 0x3333333333333333UL);
                        bmob = ((bmob >> 4) + bmob) & 0x0F0F0F0F0F0F0F0FUL;
                        mob = (int)((bmob * 0x0101010101010101UL) >> 56);
                    }
#else
                    mob = (Piece != PieceTypeC.QUEEN
                               ? Bitcount.popcount_1s_Max15(between & mobilityArea)
                               : Bitcount.popcount_1s_Full(between & mobilityArea));
#endif
                    mobility += MobilityBonus[Piece][mob];

                    // Decrease score if we are attacked by an enemy pawn. Remaining part
                    // of threat evaluation must be done later when we have full attack info.
                    if ((attackedByThemPawn & Utils.SquareBB[s]) != 0)
                    {
                        score -= ThreatenedByPawnPenalty[Piece];
                    }
                    else if ((Piece == PieceTypeC.BISHOP)
                        && ((Utils.PseudoAttacks[Piece][pos.pieceList[Them][PieceTypeC.KING][0]] & Utils.SquareBB[s])
                            != 0))
                    {
                        between = Utils.BetweenBB[s][pos.pieceList[Them][PieceTypeC.KING][0]] & pos.occupied_squares;

                        if (!Utils.more_than_one(between))
                        {
                            score += Utils.make_score(15, 25);
                        }
                    }

                    // Bishop and knight outposts squares
                    if ((Piece == PieceTypeC.BISHOP || Piece == PieceTypeC.KNIGHT)
                        && (((pos.byTypeBB[PieceTypeC.PAWN] & pos.byColorBB[Them]) & Utils.AttackSpanMask[Us][s]) == 0))
                    {
                        #region Evaluate outposts inlined

                        // evaluate_outposts() evaluates bishop and knight outposts squares

                        // Initial bonus based on square
                        var bonus = OutpostBonus[Piece == PieceTypeC.BISHOP ? 1 : 0][s ^ (Us * 56)];

                        // Increase bonus if supported by pawn, especially if the opponent has
                        // no minor piece which can exchange the outpost piece.
                        if ((bonus != 0) && ((ei.attackedBy[Us][PieceTypeC.PAWN] & Utils.SquareBB[s]) != 0))
                        {
                            if (((pos.byTypeBB[PieceTypeC.KNIGHT] & pos.byColorBB[Them]) == 0)
                                && (((((0xAA55AA55AA55AA55UL & Utils.SquareBB[s]) != 0)
                                          ? 0xAA55AA55AA55AA55UL
                                          : ~0xAA55AA55AA55AA55UL)
                                     & (pos.byTypeBB[PieceTypeC.BISHOP] & pos.byColorBB[Them])) == 0))
                            {
                                bonus += bonus + bonus / 2;
                            }
                            else
                            {
                                bonus += bonus / 2;
                            }
                        }
                        score += ((bonus << 16) + bonus); // Utils.make_score(bonus, bonus);

                        #endregion
                    }

                    if ((Piece == PieceTypeC.ROOK || Piece == PieceTypeC.QUEEN) && Utils.relative_rank_CS(Us, s) >= RankC.RANK_5)
                    {
                        // Major piece on 7th rank
                        if (Utils.relative_rank_CS(Us, s) == RankC.RANK_7
                            && Utils.relative_rank_CS(Us, pos.king_square(Them)) == RankC.RANK_8)
                            score += (Piece == PieceTypeC.ROOK ? RookOn7thBonus : QueenOn7thBonus);

                        // Major piece attacking pawns on the same rank
                        Bitboard pawns = pos.pieces_PTC(PieceTypeC.PAWN, Them) & Utils.rank_bb_S(s);
                        if (pawns != 0)
                        {
                            score += (Piece == PieceTypeC.ROOK ? RookOnPawnBonus : QueenOnPawnBonus) * Bitcount.popcount_1s_Max15(pawns);
                        }
                    }

                    // Special extra evaluation for bishops
                    if (pos.chess960 && (Piece == PieceTypeC.BISHOP))
                    {
                        // 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 (s == Utils.relative_square(Us, SquareC.SQ_A1)
                            || s == Utils.relative_square(Us, SquareC.SQ_H1))
                        {
                            var d = Utils.pawn_push(Us)
                                    + (Utils.file_of(s) == FileC.FILE_A ? SquareC.DELTA_E : SquareC.DELTA_W);
                            if (pos.piece_on(s + d) == Utils.make_piece(Us, PieceTypeC.PAWN))
                            {
                                if (!pos.is_empty(s + d + Utils.pawn_push(Us)))
                                {
                                    score -= 2 * TrappedBishopA1H1Penalty;
                                }
                                else if (pos.piece_on(s + 2 * d) == Utils.make_piece(Us, PieceTypeC.PAWN))
                                {
                                    score -= TrappedBishopA1H1Penalty;
                                }
                                else
                                {
                                    score -= TrappedBishopA1H1Penalty / 2;
                                }
                            }
                        }
                    }

                    // Special extra evaluation for rooks
                    if (Piece == PieceTypeC.ROOK)
                    {
                        // Open and half-open files
                        f = (s & 7);

                        var halfOpenUs = ((Us == ColorC.WHITE)
                                              ? (ei.pi.halfOpenFilesWHITE & (1 << f))
                                              : (ei.pi.halfOpenFilesBLACK & (1 << f))) != 0;

                        if (halfOpenUs)
                        {
                            if (((Them == ColorC.WHITE)
                                     ? (ei.pi.halfOpenFilesWHITE & (1 << f))
                                     : (ei.pi.halfOpenFilesBLACK & (1 << f))) != 0)
                            {
                                score += RookOpenFileBonus;
                            }
                            else
                            {
                                score += RookHalfOpenFileBonus;
                            }
                        }

                        // Penalize rooks which are trapped inside a king. Penalize more if
                        // king has lost right to castle.
                        if (mob > 6 || halfOpenUs)
                        {
                            continue;
                        }

                        ksq = pos.pieceList[Us][PieceTypeC.KING][0];

                        if (((ksq >> 3) ^ (Us * 7)) == RankC.RANK_1 || (ksq >> 3) == (s >> 3))
                        {
                            if ((ksq & 7) >= FileC.FILE_E)
                            {
                                if (f > (ksq & 7))
                                {
                                    // Is there a half-open file between the king and the edge of the board?
                                    if (((Us == ColorC.WHITE)
                                             ? (ei.pi.halfOpenFilesWHITE & ~((1 << ((ksq & 7) + 1)) - 1))
                                             : (ei.pi.halfOpenFilesBLACK & ~((1 << ((ksq & 7) + 1)) - 1))) == 0)
                                    {
                                        score -= ((((pos.st.castleRights & (CastleRightC.WHITE_ANY << (Us << 1))) != 0)
                                                       ? (TrappedRookPenalty - mob * 16) / 2
                                                       : (TrappedRookPenalty - mob * 16)) << 16);
                                    }
                                }
                            }
                            else
                            {
                                if (f < (ksq & 7))
                                {
                                    // Is there a half-open file between the king and the edge of the board?
                                    if (((Us == ColorC.WHITE)
                                             ? (ei.pi.halfOpenFilesWHITE & ((1 << (ksq & 7)) - 1))
                                             : (ei.pi.halfOpenFilesBLACK & ((1 << (ksq & 7)) - 1))) == 0)
                                    {
                                        score -= ((((pos.st.castleRights & (CastleRightC.WHITE_ANY << (Us << 1))) != 0)
                                                       ? (TrappedRookPenalty - mob * 16) / 2
                                                       : (TrappedRookPenalty - mob * 16)) << 16);
                                    }
                                }
                            }
                        }
                    }
                }

                scores += score;

                if (Trace)
                {
                    TracedScores[Us][Piece] = score;
                }
            }

            #endregion

            // Sum up all attacked squares
            ei.attackedBy[Us][0] = ei.attackedBy[Us][PieceTypeC.PAWN] | ei.attackedBy[Us][PieceTypeC.KNIGHT]
                                   | ei.attackedBy[Us][PieceTypeC.BISHOP] | ei.attackedBy[Us][PieceTypeC.ROOK]
                                   | ei.attackedBy[Us][PieceTypeC.QUEEN] | ei.attackedBy[Us][PieceTypeC.KING];

            return scores;
        }
Пример #2
0
        // refutes() tests whether a 'first' move is able to defend against a 'second'
        // opponent's move. In this case will not be pruned. Normally the second move
        // is the threat (the best move returned from a null search that fails low).
        private static bool refutes(Position pos, int move, int threat)
        {
            Debug.Assert(Utils.is_ok_M(move));
            Debug.Assert(Utils.is_ok_M(threat));
            
            Square mfrom = Utils.from_sq(move);
            Square mto = Utils.to_sq(move);
            Square tfrom = Utils.from_sq(threat);
            Square tto = Utils.to_sq(threat);

            // Don't prune moves of the threatened piece
            if (mfrom == tto)
            {
                return true;
            }

            // If the threatened piece has value less than or equal to the value of the
            // threat piece, don't prune moves which defend it.
            if (pos.is_capture(threat)
                && (Position.PieceValue[PhaseC.MG][pos.piece_on(tfrom)] >= Position.PieceValue[PhaseC.MG][pos.piece_on(tto)]
                    || Utils.type_of(pos.piece_on(tfrom)) == PieceTypeC.KING))
            {
                // Update occupancy as if the piece and the threat are moving
                var occ = Utils.xor_bit(Utils.xor_bit(Utils.xor_bit(pos.occupied_squares, mfrom), mto), tfrom);
                Piece piece = pos.piece_on(mfrom);

                // The piece moved in 'to' attacks the square 's' ?
                if (Utils.bit_is_set(Position.attacks_from(piece, mto, occ), tto) != 0)
                {
                    return true;
                }

                // Scan for possible X-ray attackers behind the moved piece
                var xray = (Utils.rook_attacks_bb(tto, occ)
                        & pos.pieces(PieceTypeC.ROOK, PieceTypeC.QUEEN, Utils.color_of(piece)))
                        | (Utils.bishop_attacks_bb(tto, occ)
                            & pos.pieces(PieceTypeC.BISHOP, PieceTypeC.QUEEN, Utils.color_of(piece)));

                // Verify attackers are triggered by our move and not already existing
                if ((xray != 0) && ((xray ^ (xray & pos.attacks_from_QUEEN(tto))) != 0))
                {
                    return true;
                }
            }

            // Don't prune safe moves which block the threat path
            if ((Utils.bit_is_set(Utils.between_bb(tfrom, tto), mto) != 0) && pos.see(move, true) >= 0)
            {
                return true;
            }

            return false;
        }