Example #1
0
        /// PawnTable::pawn_info() takes a position object as input, computes
        /// a PawnInfo object, and returns a pointer to it. The result is also stored
        /// in an hash table, so we don't have to recompute everything when the same
        /// pawn structure occurs again.
        internal void probe(Position pos, out PawnEntry e)
        {
            Key key = pos.pawn_key();

            e = entries[((UInt32)key) & Constants.PawnTableMask];

            // If pi.key matches the position's pawn hash key, it means that we
            // have analysed this pawn structure before, and we can simply return
            // the information we found the last time instead of recomputing it.
            if (e.key == key)
            {
                return;
            }

            // Initialize PawnInfo entry
            e.key = key;
            e.passedPawnsWHITE   = e.passedPawnsBLACK = 0;
            e.kingSquaresWHITE   = e.kingSquaresBLACK = SquareC.SQ_NONE;
            e.halfOpenFilesWHITE = e.halfOpenFilesBLACK = 0xFF;

            // Calculate pawn attacks
            Bitboard wPawns = pos.pieces_PTC(PieceTypeC.PAWN, ColorC.WHITE);
            Bitboard bPawns = pos.pieces_PTC(PieceTypeC.PAWN, ColorC.BLACK);

            e.pawnAttacksWHITE = ((wPawns & ~Constants.FileHBB) << 9) | ((wPawns & ~Constants.FileABB) << 7);
            e.pawnAttacksBLACK = ((bPawns & ~Constants.FileHBB) >> 7) | ((bPawns & ~Constants.FileABB) >> 9);

            // Evaluate pawns for both colors and weight the result
            e.value = evaluate_pawns(ColorC.WHITE, pos, wPawns, bPawns, e)
                      - evaluate_pawns(ColorC.BLACK, pos, bPawns, wPawns, e);

            e.value = Utils.apply_weight(e.value, PawnStructureWeight);

            return;
        }
Example #2
0
 internal PawnTable()
 {
     for (int i = 0; i < Constants.PawnTableSize; i++)
     {
         entries[i] = new PawnEntry();
     }
 }
Example #3
0
        /// PawnTable::evaluate_pawns() evaluates each pawn of the given color
        internal static Score evaluate_pawns(Color Us, Position pos, Bitboard ourPawns, Bitboard theirPawns, PawnEntry e)
        {
            Color Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);

            Bitboard b;
            Square s;
            File f;
            Rank r;
            bool passed, isolated, doubled, opposed, chain, backward, candidate;
            Score value = ScoreC.SCORE_ZERO;
            Square[] pl = pos.pieceList[Us][PieceTypeC.PAWN];
            int plPos = 0;

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

                f = (s & 7);
                r = (s >> 3);

                // This file cannot be half open
                if (Us == ColorC.WHITE)
                {
                    e.halfOpenFilesWHITE &= ~(1 << f);
                }
                else
                {
                    e.halfOpenFilesBLACK &= ~(1 << f);
                }

                // Our rank plus previous one. Used for chain detection
                b = Utils.RankBB[r] | Utils.RankBB[Us == ColorC.WHITE ? r - 1 : r + 1];

                // Flag the pawn as passed, isolated, doubled or member of a pawn
                // chain (but not the backward one).
                chain = (ourPawns & Utils.AdjacentFilesBB[f] & b) != 0;
                isolated = (ourPawns & Utils.AdjacentFilesBB[f]) == 0;
                doubled = (ourPawns & Utils.ForwardBB[Us][s]) != 0;
                opposed = (theirPawns & Utils.ForwardBB[Us][s]) != 0;
                passed = (theirPawns & Utils.PassedPawnMask[Us][s]) == 0;

                // Test for backward pawn
                backward = false;

                // If the pawn is passed, isolated, or member of a pawn chain it cannot
                // be backward. If there are friendly pawns behind on adjacent files
                // or if can capture an enemy pawn it cannot be backward either.
                if (!(passed | isolated | chain)
                    && (((ourPawns & Utils.AttackSpanMask[Them][s])) == 0)
                    && ((((Utils.StepAttacksBB[((Us << 3) | PieceTypeC.PAWN)][s]) & theirPawns)) == 0))
                {
                    // We now know that there are no friendly pawns beside or behind this
                    // pawn on adjacent files. We now check whether the pawn is
                    // backward by looking in the forward direction on the adjacent
                    // files, and seeing whether we meet a friendly or an enemy pawn first.
                    b = Utils.StepAttacksBB[((Us << 3) | PieceTypeC.PAWN)][s];

                    // Note that we are sure to find something because pawn is not passed
                    // nor isolated, so loop is potentially infinite, but it isn't.
                    while ((b & (ourPawns | theirPawns)) == 0)
                    {
                        if (Us == ColorC.WHITE) { b <<= 8; } else { b >>= 8; }
                    }

                    // The friendly pawn needs to be at least two ranks closer than the
                    // enemy pawn in order to help the potentially backward pawn advance.
                    backward = (((b | (Us == ColorC.WHITE ? b << 8 : b >> 8)) & theirPawns) != 0);
                }

                Debug.Assert(opposed | passed | (((Utils.AttackSpanMask[Us][s] & theirPawns)) != 0));

                // A not passed pawn is a candidate to become passed if it is free to
                // advance and if the number of friendly pawns beside or behind this
                // pawn on adjacent files is higher or equal than the number of
                // enemy pawns in the forward direction on the adjacent files.
                candidate = !(opposed | passed | backward | isolated)
                           && (b = Utils.AttackSpanMask[Them][s + (Us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S)] & ourPawns) != 0
                           && Bitcount.popcount_1s_Max15(b) >= Bitcount.popcount_1s_Max15(Utils.AttackSpanMask[Us][s] & theirPawns);

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

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

                if (doubled)
                    value -= DoubledPawnPenalty[opposed ? 1 : 0][f];

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

                if (chain)
                    value += ChainBonus[f];

                if (candidate)
                    value += CandidateBonus[((s >> 3) ^ (Us * 7))];
            }
            return value;
        }
Example #4
0
        /// PawnTable::pawn_info() takes a position object as input, computes
        /// a PawnInfo object, and returns a pointer to it. The result is also stored
        /// in an hash table, so we don't have to recompute everything when the same
        /// pawn structure occurs again.
        internal void probe(Position pos, out PawnEntry e)
        {
            Key key = pos.pawn_key();
            e = entries[((UInt32)key) & Constants.PawnTableMask];

            // If pi.key matches the position's pawn hash key, it means that we
            // have analysed this pawn structure before, and we can simply return
            // the information we found the last time instead of recomputing it.
            if (e.key == key) return;

            // Initialize PawnInfo entry
            e.key = key;
            e.passedPawnsWHITE = e.passedPawnsBLACK = 0;
            e.kingSquaresWHITE = e.kingSquaresBLACK = SquareC.SQ_NONE;
            e.halfOpenFilesWHITE = e.halfOpenFilesBLACK = 0xFF;

            // Calculate pawn attacks
            Bitboard wPawns = pos.pieces_PTC(PieceTypeC.PAWN, ColorC.WHITE);
            Bitboard bPawns = pos.pieces_PTC(PieceTypeC.PAWN, ColorC.BLACK);

            e.pawnAttacksWHITE = ((wPawns & ~Constants.FileHBB) << 9) | ((wPawns & ~Constants.FileABB) << 7);
            e.pawnAttacksBLACK = ((bPawns & ~Constants.FileHBB) >> 7) | ((bPawns & ~Constants.FileABB) >> 9);

            // Evaluate pawns for both colors and weight the result
            e.value = evaluate_pawns(ColorC.WHITE, pos, wPawns, bPawns, e)
                       - evaluate_pawns(ColorC.BLACK, pos, bPawns, wPawns, e);

            e.value = Utils.apply_weight(e.value, PawnStructureWeight);

            return;
        }
Example #5
0
 internal PawnTable()
 {
     for (int i = 0; i < Constants.PawnTableSize; i++)
     {
         entries[i] = new PawnEntry();
     }
 }
Example #6
0
        /// PawnTable::evaluate_pawns() evaluates each pawn of the given color
        internal static Score evaluate_pawns(Color Us, Position pos, Bitboard ourPawns, Bitboard theirPawns, PawnEntry e)
        {
            Color Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);

            Bitboard b;
            Square   s;
            File     f;
            Rank     r;
            bool     passed, isolated, doubled, opposed, chain, backward, candidate;
            Score    value = ScoreC.SCORE_ZERO;

            Square[] pl    = pos.pieceList[Us][PieceTypeC.PAWN];
            int      plPos = 0;

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

                f = (s & 7);
                r = (s >> 3);

                // This file cannot be half open
                if (Us == ColorC.WHITE)
                {
                    e.halfOpenFilesWHITE &= ~(1 << f);
                }
                else
                {
                    e.halfOpenFilesBLACK &= ~(1 << f);
                }

                // Our rank plus previous one. Used for chain detection
                b = Utils.RankBB[r] | Utils.RankBB[Us == ColorC.WHITE ? r - 1 : r + 1];

                // Flag the pawn as passed, isolated, doubled or member of a pawn
                // chain (but not the backward one).
                chain    = (ourPawns & Utils.AdjacentFilesBB[f] & b) != 0;
                isolated = (ourPawns & Utils.AdjacentFilesBB[f]) == 0;
                doubled  = (ourPawns & Utils.ForwardBB[Us][s]) != 0;
                opposed  = (theirPawns & Utils.ForwardBB[Us][s]) != 0;
                passed   = (theirPawns & Utils.PassedPawnMask[Us][s]) == 0;

                // Test for backward pawn
                backward = false;

                // If the pawn is passed, isolated, or member of a pawn chain it cannot
                // be backward. If there are friendly pawns behind on adjacent files
                // or if can capture an enemy pawn it cannot be backward either.
                if (!(passed | isolated | chain) &&
                    (((ourPawns & Utils.AttackSpanMask[Them][s])) == 0) &&
                    ((((Utils.StepAttacksBB[((Us << 3) | PieceTypeC.PAWN)][s]) & theirPawns)) == 0))
                {
                    // We now know that there are no friendly pawns beside or behind this
                    // pawn on adjacent files. We now check whether the pawn is
                    // backward by looking in the forward direction on the adjacent
                    // files, and seeing whether we meet a friendly or an enemy pawn first.
                    b = Utils.StepAttacksBB[((Us << 3) | PieceTypeC.PAWN)][s];

                    // Note that we are sure to find something because pawn is not passed
                    // nor isolated, so loop is potentially infinite, but it isn't.
                    while ((b & (ourPawns | theirPawns)) == 0)
                    {
                        if (Us == ColorC.WHITE)
                        {
                            b <<= 8;
                        }
                        else
                        {
                            b >>= 8;
                        }
                    }

                    // The friendly pawn needs to be at least two ranks closer than the
                    // enemy pawn in order to help the potentially backward pawn advance.
                    backward = (((b | (Us == ColorC.WHITE ? b << 8 : b >> 8)) & theirPawns) != 0);
                }

                Debug.Assert(opposed | passed | (((Utils.AttackSpanMask[Us][s] & theirPawns)) != 0));

                // A not passed pawn is a candidate to become passed if it is free to
                // advance and if the number of friendly pawns beside or behind this
                // pawn on adjacent files is higher or equal than the number of
                // enemy pawns in the forward direction on the adjacent files.
                candidate = !(opposed | passed | backward | isolated) &&
                            (b = Utils.AttackSpanMask[Them][s + (Us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S)] & ourPawns) != 0 &&
                            Bitcount.popcount_1s_Max15(b) >= Bitcount.popcount_1s_Max15(Utils.AttackSpanMask[Us][s] & theirPawns);

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

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

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

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

                if (chain)
                {
                    value += ChainBonus[f];
                }

                if (candidate)
                {
                    value += CandidateBonus[((s >> 3) ^ (Us * 7))];
                }
            }
            return(value);
        }