internal static Value Endgame_KBBKN(Color strongerSide, Position pos) { Color weakerSide = strongerSide ^ 1; Debug.Assert(pos.piece_count(strongerSide, PieceTypeC.BISHOP) == 2); Debug.Assert(pos.non_pawn_material(strongerSide) == 2 * Constants.BishopValueMidgame); Debug.Assert(pos.piece_count(weakerSide, PieceTypeC.KNIGHT) == 1); Debug.Assert(pos.non_pawn_material(weakerSide) == Constants.KnightValueMidgame); Debug.Assert(pos.pieces_PT(PieceTypeC.PAWN) == 0); Value result = Constants.BishopValueEndgame; Square wksq = pos.king_square(strongerSide); Square bksq = pos.king_square(weakerSide); Square nsq = pos.pieceList[weakerSide][PieceTypeC.KNIGHT][0]; // Bonus for attacking king close to defending king result += (DistanceBonus[Utils.square_distance(wksq, bksq)]); // Bonus for driving the defending king and knight apart result += (Utils.square_distance(bksq, nsq) * 32); // Bonus for restricting the knight's mobility result += ((8 - Bitcount.popcount_1s_Max15(Position.attacks_from_KNIGHT(nsq))) * 8); return(strongerSide == pos.sideToMove ? result : -result); }
/// 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); }