+/// KBPPKBScalingFunction scales KBPP vs KB endgames. It detects a few basic
+/// draws with opposite-colored bishops.
+template<>
+ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) const {
+
+ assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
+ assert(pos.piece_count(strongerSide, BISHOP) == 1);
+ assert(pos.piece_count(strongerSide, PAWN) == 2);
+ assert(pos.non_pawn_material(weakerSide) == BishopValueMidgame);
+ assert(pos.piece_count(weakerSide, BISHOP) == 1);
+ assert(pos.piece_count(weakerSide, PAWN) == 0);
+
+ Square wbsq = pos.piece_list(strongerSide, BISHOP, 0);
+ Square bbsq = pos.piece_list(weakerSide, BISHOP, 0);
+
+ if (!opposite_color_squares(wbsq, bbsq))
+ return SCALE_FACTOR_NONE;
+
+ Square ksq = pos.king_square(weakerSide);
+ Square psq1 = pos.piece_list(strongerSide, PAWN, 0);
+ Square psq2 = pos.piece_list(strongerSide, PAWN, 1);
+ Rank r1 = square_rank(psq1);
+ Rank r2 = square_rank(psq2);
+ Square blockSq1, blockSq2;
+
+ if (relative_rank(strongerSide, psq1) > relative_rank(strongerSide, psq2))
+ {
+ blockSq1 = psq1 + pawn_push(strongerSide);
+ blockSq2 = make_square(square_file(psq2), square_rank(psq1));
+ }
+ else
+ {
+ blockSq1 = psq2 + pawn_push(strongerSide);
+ blockSq2 = make_square(square_file(psq1), square_rank(psq2));
+ }
+
+ switch (file_distance(psq1, psq2))
+ {
+ case 0:
+ // Both pawns are on the same file. Easy draw if defender firmly controls
+ // some square in the frontmost pawn's path.
+ if ( square_file(ksq) == square_file(blockSq1)
+ && relative_rank(strongerSide, ksq) >= relative_rank(strongerSide, blockSq1)
+ && opposite_color_squares(ksq, wbsq))
+ return SCALE_FACTOR_ZERO;
+ else
+ return SCALE_FACTOR_NONE;
+
+ case 1:
+ // Pawns on neighboring files. Draw if defender firmly controls the square
+ // in front of the frontmost pawn's path, and the square diagonally behind
+ // this square on the file of the other pawn.
+ if ( ksq == blockSq1
+ && opposite_color_squares(ksq, wbsq)
+ && ( bbsq == blockSq2
+ || (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(BISHOP, weakerSide))
+ || rank_distance(r1, r2) >= 2))
+ return SCALE_FACTOR_ZERO;
+
+ else if ( ksq == blockSq2
+ && opposite_color_squares(ksq, wbsq)
+ && ( bbsq == blockSq1
+ || (pos.attacks_from<BISHOP>(blockSq1) & pos.pieces(BISHOP, weakerSide))))
+ return SCALE_FACTOR_ZERO;
+ else
+ return SCALE_FACTOR_NONE;
+
+ default:
+ // The pawns are not on the same file or adjacent files. No scaling.
+ return SCALE_FACTOR_NONE;
+ }
+}
+
+
+/// KBPKNScalingFunction scales KBP vs KN endgames. There is a single rule: