+
+ // 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.pieces(KING, weakerSide))
+ return ScaleFactor(0);
+ if( (pos.attacks_from<BISHOP>(weakerBishopSq) & ray)
+ && square_distance(weakerBishopSq, pawnSq) >= 3)
+ return ScaleFactor(0);
+ }
+ }
+ return SCALE_FACTOR_NONE;
+}
+
+
+/// KBPPKBScalingFunction scales KBPP vs KB endgames. It detects a few basic
+/// draws with opposite-colored bishops.
+template<>
+ScaleFactor ScalingFunction<KBPPKB>::apply(const Position& pos) {
+
+ 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 (square_color(wbsq) == square_color(bbsq))
+ // Not opposite-colored bishops, no scaling
+ 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)
+ && square_color(ksq) != square_color(wbsq))
+ return ScaleFactor(0);
+ 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
+ && square_color(ksq) != square_color(wbsq)
+ && ( bbsq == blockSq2
+ || (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(BISHOP, weakerSide))
+ || rank_distance(r1, r2) >= 2))