-/// KBPKBScalingFunction scales KBP vs KB endgames. There are two rules:
-/// If the defending king is somewhere along the path of the pawn, and the
-/// square of the king is not of the same color as the stronger side's bishop,
-/// it's a draw. If the two bishops have opposite color, it's almost always
-/// a draw.
-
-ScaleFactor KBPKBScalingFunction::apply(const Position &pos) {
- assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
- assert(pos.piece_count(strongerSide, BISHOP) == 1);
- assert(pos.piece_count(strongerSide, PAWN) == 1);
- assert(pos.non_pawn_material(weakerSide) == BishopValueMidgame);
- assert(pos.piece_count(weakerSide, BISHOP) == 1);
- assert(pos.piece_count(weakerSide, PAWN) == 0);
-
- Square pawnSq = pos.piece_list(strongerSide, PAWN, 0);
- Square strongerBishopSq = pos.piece_list(strongerSide, BISHOP, 0);
- Square weakerBishopSq = pos.piece_list(weakerSide, BISHOP, 0);
- Square weakerKingSq = pos.king_square(weakerSide);
-
- // Case 1: Defending king blocks the pawn, and cannot be driven away.
- if(square_file(weakerKingSq) == square_file(pawnSq)
- && relative_rank(strongerSide, pawnSq) < relative_rank(strongerSide, weakerKingSq)
- && (square_color(weakerKingSq) != square_color(strongerBishopSq)
- || relative_rank(strongerSide, weakerKingSq) <= RANK_6))
- return ScaleFactor(0);
-
- // Case 2: Opposite colored bishops.
- if(square_color(strongerBishopSq) != square_color(weakerBishopSq)) {
-
- // We assume that the position is drawn in the following three situations:
- //
- // a. The pawn is on rank 5 or further back.
- // b. The defending king is somewhere in the pawn's path.
- // c. The defending bishop attacks some square along the pawn's path,
- // and is at least three squares away from the pawn.
- //
- // These rules are probably not perfect, but in practice they work
- // reasonably well.
-
- if(relative_rank(strongerSide, pawnSq) <= RANK_5)
- return ScaleFactor(0);
- else {
- Bitboard ray =
- ray_bb(pawnSq, (strongerSide == WHITE)? SIGNED_DIR_N : SIGNED_DIR_S);
- if(ray & pos.kings(weakerSide))
- return ScaleFactor(0);
- if((pos.piece_attacks<BISHOP>(weakerBishopSq) & ray)
- && square_distance(weakerBishopSq, pawnSq) >= 3)
- return ScaleFactor(0);
- }
- }