예제 #1
0
        public static int CalculateSpace(ChessBoard cb)
        {
            if (!MaterialUtil.HasPawns(cb.MaterialKey))
            {
                return(0);
            }

            var score = 0;

            score += EvalConstants.OtherScores[EvalConstants.IxSpace]
                     * BitOperations.PopCount((ulong)(Util.RightTripleShift(cb.Pieces[White][Pawn], 8) &
                                                      (cb.Pieces[White][Knight] | cb.Pieces[White][Bishop]) &
                                                      Bitboard.Rank234));
            score -= EvalConstants.OtherScores[EvalConstants.IxSpace]
                     * BitOperations.PopCount((ulong)((cb.Pieces[Black][Pawn] << 8) &
                                                      (cb.Pieces[Black][Knight] | cb.Pieces[Black][Bishop]) &
                                                      Bitboard.Rank567));

            // idea taken from Laser
            var space = Util.RightTripleShift(cb.Pieces[White][Pawn], 8);

            space |= Util.RightTripleShift(space, 8) | Util.RightTripleShift(space, 16);
            score += EvalConstants.Space[BitOperations.PopCount((ulong)cb.Pieces[White][All])]
                     * BitOperations.PopCount((ulong)(space & ~cb.Pieces[White][Pawn] & ~cb.Attacks[Black][Pawn] &
                                                      Bitboard.FileCdef));
            space  = cb.Pieces[Black][Pawn] << 8;
            space |= (space << 8) | (space << 16);
            score -= EvalConstants.Space[BitOperations.PopCount((ulong)cb.Pieces[Black][All])]
                     * BitOperations.PopCount((ulong)(space & ~cb.Pieces[Black][Pawn] & ~cb.Attacks[White][Pawn] &
                                                      Bitboard.FileCdef));

            return(score);
        }
예제 #2
0
        private static int CalculateScaleFactor(ChessBoard cb)
        {
            // opposite bishops endgame?
            if (!MaterialUtil.OppositeBishops(cb.MaterialKey))
            {
                return(1);
            }
            return((cb.Pieces[White][Bishop] & Bitboard.BlackSquares) == 0 ==
                   ((cb.Pieces[Black][Bishop] & Bitboard.WhiteSquares) == 0)
                ? 2
                : 1);

            // TODO rook and pawns without passed pawns
        }
예제 #3
0
        public static int CalculateScore(ChessBoard cb, ThreadData threadData)
        {
            var score = MaterialUtil.ScoreUnknown;

            if (BitOperations.PopCount((ulong)cb.AllPieces) <= 5)
            {
                score = MaterialUtil.IsDrawByMaterial(cb)
                    ? EvalConstants.ScoreDraw
                    : MaterialUtil.CalculateEndgameScore(cb);
            }

            if (score == MaterialUtil.ScoreUnknown)
            {
                score = TaperedEval(cb, threadData);
                if (score > 25)
                {
                    score = AdjustEndgame(cb, score, White, threadData.MaterialCache);
                }
                else if (score < -25)
                {
                    score = AdjustEndgame(cb, score, Black, threadData.MaterialCache);
                }
            }

            score *= ColorFactor[cb.ColorToMove];
            if (EngineConstants.TestEvalCaches)
            {
                var cachedScore = EvalCacheUtil.GetScore(cb.ZobristKey, threadData.EvalCache);
                if (cachedScore != CacheMiss)
                {
                    if (cachedScore != score)
                    {
                        throw new ArgumentException($"Cached eval score != score: {cachedScore}, {score}");
                    }
                }
            }

            EvalCacheUtil.AddValue(cb.ZobristKey, score, threadData.EvalCache);

            if (EngineConstants.TestEvalValues)
            {
                ChessBoardTestUtil.CompareScores(cb);
            }

            return(score);
        }
예제 #4
0
        public static int CalculatePawnShieldBonus(ChessBoard cb)
        {
            if (!MaterialUtil.HasPawns(cb.MaterialKey))
            {
                return(0);
            }

            int file;

            var whiteScore = 0;
            var piece      = cb.Pieces[White][Pawn] & KingArea[cb.KingIndex[White]] & ~cb.Attacks[Black][Pawn];

            while (piece != 0)
            {
                file        = BitOperations.TrailingZeroCount(piece) & 7;
                whiteScore +=
                    EvalConstants.ShieldBonus[Math.Min(7 - file, file)][
                        Util.RightTripleShift(BitOperations.TrailingZeroCount(piece), 3)];
                piece &= ~Bitboard.Files[file];
            }

            if (cb.Pieces[Black][Queen] == 0)
            {
                whiteScore /= 2;
            }

            var blackScore = 0;

            piece = cb.Pieces[Black][Pawn] & KingArea[cb.KingIndex[Black]] & ~cb.Attacks[White][Pawn];
            while (piece != 0)
            {
                file        = (63 - BitOperations.LeadingZeroCount((ulong)piece)) & 7;
                blackScore +=
                    EvalConstants.ShieldBonus[Math.Min(7 - file, file)]
                    [7 - (63 - BitOperations.LeadingZeroCount((ulong)piece)) / 8];
                piece &= ~Bitboard.Files[file];
            }

            if (cb.Pieces[White][Queen] == 0)
            {
                blackScore /= 2;
            }

            return(whiteScore - blackScore);
        }
예제 #5
0
        private static int AdjustEndgame(ChessBoard cb, int score, int color, int[] materialCache)
        {
            if (BitOperations.PopCount((ulong)cb.Pieces[color][All]) > 3)
            {
                return(score);
            }

            if (MaterialUtil.HasPawnsOrQueens(cb.MaterialKey, color))
            {
                return(score);
            }

            switch (BitOperations.PopCount((ulong)cb.Pieces[color][All]))
            {
            case 1:
                return(EvalConstants.ScoreDraw);

            case 2:
                if (cb.Pieces[color][Rook] == 0)
                {
                    return(EvalConstants.ScoreDraw);
                }

                goto case 3;

            // fall-through
            case 3:
                if (MaterialUtil.HasOnlyNights(cb.MaterialKey, color))
                {
                    return(EvalConstants.ScoreDraw);
                }

                if (GetImbalances(cb, materialCache) * ColorFactor[color] <
                    EvalConstants.OtherScores[EvalConstants.IxDrawish])
                {
                    return(score / 8);
                }

                break;
            }

            return(score);
        }
예제 #6
0
        private static int GetWhitePromotionDistance(ChessBoard cb, int index)
        {
            // check if it cannot be stopped
            var promotionDistance = 7 - index / 8;

            if (promotionDistance == 1 && cb.ColorToMove == White)
            {
                if ((Util.PowerLookup[index + 8] & (cb.Attacks[Black][All] | cb.AllPieces)) != 0)
                {
                    return(Util.ShortMax);
                }
                if ((Util.PowerLookup[index] & cb.Attacks[Black][All]) == 0)
                {
                    return(1);
                }
            }
            else if (MaterialUtil.OnlyBlackPawnsOrOneNightOrBishop(cb.MaterialKey))
            {
                // check if it is my turn
                if (cb.ColorToMove == Black)
                {
                    promotionDistance++;
                }

                // check if own pieces are blocking the path
                if (63 - BitOperations.LeadingZeroCount((ulong)(cb.Pieces[White][All] & Bitboard.Files[index & 7])) >
                    index)
                {
                    promotionDistance++;
                }

                // TODO maybe the enemy king can capture the pawn!!
                // check if own king is defending the promotion square (including square just below)
                if ((StaticMoves.KingMoves[cb.KingIndex[White]] & KingArea[index] & Bitboard.Rank78) != 0)
                {
                    promotionDistance--;
                }

                // check distance of enemy king to promotion square
                if (promotionDistance >= Math.Max(7 - cb.KingIndex[Black] / 8,
                                                  Math.Abs((index & 7) - (cb.KingIndex[Black] & 7))))
                {
                    return(Util.ShortMax);
                }
                if (!MaterialUtil.HasBlackNonPawnPieces(cb.MaterialKey))
                {
                    return(promotionDistance);
                }

                if (cb.Pieces[Black][Knight] != 0)
                {
                    // check distance of enemy night
                    if (promotionDistance <
                        Util.GetDistance(BitOperations.TrailingZeroCount(cb.Pieces[Black][Knight]), index))
                    {
                        return(promotionDistance);
                    }
                }
                else
                {
                    // can bishop stop the passed pawn?
                    if (Util.RightTripleShift(index, 3) != 6)
                    {
                        return(Util.ShortMax);
                    }
                    // rank 7
                    if ((Util.PowerLookup[index] & Bitboard.WhiteSquares) == 0 !=
                        ((cb.Pieces[Black][Bishop] & Bitboard.WhiteSquares) == 0))
                    {
                        return(Util.ShortMax);
                    }
                    // other color than promotion square
                    if ((cb.Attacks[Black][All] & Util.PowerLookup[index]) == 0)
                    {
                        return(promotionDistance);
                    }
                }
            }

            return(Util.ShortMax);
        }
예제 #7
0
        public static int CalculateThreats(ChessBoard cb)
        {
            var score             = 0;
            var whites            = cb.Pieces[White][All];
            var whitePawns        = cb.Pieces[White][Pawn];
            var blacks            = cb.Pieces[Black][All];
            var blackPawns        = cb.Pieces[Black][Pawn];
            var whiteAttacks      = cb.Attacks[White][All];
            var whitePawnAttacks  = cb.Attacks[White][Pawn];
            var whiteMinorAttacks = cb.Attacks[White][Knight] | cb.Attacks[White][Bishop];
            var blackAttacks      = cb.Attacks[Black][All];
            var blackPawnAttacks  = cb.Attacks[Black][Pawn];
            var blackMinorAttacks = cb.Attacks[Black][Knight] | cb.Attacks[Black][Bishop];

            // double attacked pieces
            var piece = cb.DoubleAttacks[White] & blacks;

            while (piece != 0)
            {
                score += EvalConstants.DoubleAttacked[cb.PieceIndexes[BitOperations.TrailingZeroCount(piece)]];
                piece &= piece - 1;
            }

            piece = cb.DoubleAttacks[Black] & whites;
            while (piece != 0)
            {
                score -= EvalConstants.DoubleAttacked[cb.PieceIndexes[BitOperations.TrailingZeroCount(piece)]];
                piece &= piece - 1;
            }

            if (MaterialUtil.HasPawns(cb.MaterialKey))
            {
                // unused outposts
                score += BitOperations.PopCount((ulong)(cb.PassedPawnsAndOutposts & cb.EmptySpaces &
                                                        whiteMinorAttacks & whitePawnAttacks))
                         * EvalConstants.Threats[EvalConstants.IxUnusedOutpost];
                score -= BitOperations.PopCount((ulong)(cb.PassedPawnsAndOutposts & cb.EmptySpaces &
                                                        blackMinorAttacks & blackPawnAttacks))
                         * EvalConstants.Threats[EvalConstants.IxUnusedOutpost];

                // pawn push threat
                piece  = (whitePawns << 8) & cb.EmptySpaces & ~blackAttacks;
                score += BitOperations.PopCount((ulong)(Bitboard.GetWhitePawnAttacks(piece) & blacks)) *
                         EvalConstants.Threats[EvalConstants.IxPawnPushThreat];
                piece  = Util.RightTripleShift(blackPawns, 8) & cb.EmptySpaces & ~whiteAttacks;
                score -= BitOperations.PopCount((ulong)(Bitboard.GetBlackPawnAttacks(piece) & whites)) *
                         EvalConstants.Threats[EvalConstants.IxPawnPushThreat];

                // piece attacked by pawn
                score += BitOperations.PopCount((ulong)(whitePawnAttacks & blacks & ~blackPawns)) *
                         EvalConstants.Threats[EvalConstants.IxPawnAttacks];
                score -= BitOperations.PopCount((ulong)(blackPawnAttacks & whites & ~whitePawns)) *
                         EvalConstants.Threats[EvalConstants.IxPawnAttacks];

                // multiple pawn attacks possible
                if (BitOperations.PopCount((ulong)(whitePawnAttacks & blacks)) > 1)
                {
                    score += EvalConstants.Threats[EvalConstants.IxMultiplePawnAttacks];
                }

                if (BitOperations.PopCount((ulong)(blackPawnAttacks & whites)) > 1)
                {
                    score -= EvalConstants.Threats[EvalConstants.IxMultiplePawnAttacks];
                }

                // pawn attacked
                score += BitOperations.PopCount((ulong)(whiteAttacks & blackPawns)) *
                         EvalConstants.Threats[EvalConstants.IxPawnAttacked];
                score -= BitOperations.PopCount((ulong)(blackAttacks & whitePawns)) *
                         EvalConstants.Threats[EvalConstants.IxPawnAttacked];
            }

            // minors attacked and not defended by a pawn
            score += BitOperations.PopCount((ulong)(whiteAttacks &
                                                    (cb.Pieces[Black][Knight] |
                                                     (cb.Pieces[Black][Bishop] & ~blackAttacks))))
                     * EvalConstants.Threats[EvalConstants.IxMajorAttacked];
            score -= BitOperations.PopCount((ulong)(blackAttacks &
                                                    (cb.Pieces[White][Knight] |
                                                     (cb.Pieces[White][Bishop] & ~whiteAttacks))))
                     * EvalConstants.Threats[EvalConstants.IxMajorAttacked];

            if (cb.Pieces[Black][Queen] != 0)
            {
                // queen attacked by rook
                score += BitOperations.PopCount((ulong)(cb.Attacks[White][Rook] & cb.Pieces[Black][Queen])) *
                         EvalConstants.Threats[EvalConstants.IxQueenAttacked];
                // queen attacked by minors
                score += BitOperations.PopCount((ulong)(whiteMinorAttacks & cb.Pieces[Black][Queen])) *
                         EvalConstants.Threats[EvalConstants.IxQueenAttackedMinor];
            }

            if (cb.Pieces[White][Queen] != 0)
            {
                // queen attacked by rook
                score -= BitOperations.PopCount((ulong)(cb.Attacks[Black][Rook] & cb.Pieces[White][Queen])) *
                         EvalConstants.Threats[EvalConstants.IxQueenAttacked];
                // queen attacked by minors
                score -= BitOperations.PopCount((ulong)(blackMinorAttacks & cb.Pieces[White][Queen])) *
                         EvalConstants.Threats[EvalConstants.IxQueenAttackedMinor];
            }

            // rook attacked by minors
            score += BitOperations.PopCount((ulong)(whiteMinorAttacks & cb.Pieces[Black][Rook])) *
                     EvalConstants.Threats[EvalConstants.IxRookAttacked];
            score -= BitOperations.PopCount((ulong)(blackMinorAttacks & cb.Pieces[White][Rook])) *
                     EvalConstants.Threats[EvalConstants.IxRookAttacked];

            return(score);
        }