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