- // Get weakerSide pawn that is closest to home rank
- Square weakerPawnSq = backmost_sq(weakerSide, pos.pieces(weakerSide, PAWN));
-
- Square strongerKingSq = pos.king_square(strongerSide);
- Square weakerKingSq = pos.king_square(weakerSide);
- Square bishopSq = pos.list<BISHOP>(strongerSide)[0];
-
- // Draw if weaker pawn is on rank 7, bishop can't attack the pawn, and
- // weaker king can stop opposing opponent's king from penetrating.
- if ( relative_rank(strongerSide, weakerPawnSq) == RANK_7
- && opposite_colors(bishopSq, weakerPawnSq)
- && square_distance(weakerPawnSq, weakerKingSq) <= square_distance(weakerPawnSq, strongerKingSq))
- return SCALE_FACTOR_DRAW;
+ // Get weakSide pawn that is closest to the home rank
+ Square weakPawnSq = backmost_sq(weakSide, pos.pieces(weakSide, PAWN));
+
+ Square strongKingSq = pos.square<KING>(strongSide);
+ Square weakKingSq = pos.square<KING>(weakSide);
+ Square bishopSq = pos.square<BISHOP>(strongSide);
+
+ // There's potential for a draw if our pawn is blocked on the 7th rank,
+ // the bishop cannot attack it or they only have one pawn left
+ if ( relative_rank(strongSide, weakPawnSq) == RANK_7
+ && (pos.pieces(strongSide, PAWN) & (weakPawnSq + pawn_push(weakSide)))
+ && (opposite_colors(bishopSq, weakPawnSq) || pos.count<PAWN>(strongSide) == 1))
+ {
+ int strongKingDist = distance(weakPawnSq, strongKingSq);
+ int weakKingDist = distance(weakPawnSq, weakKingSq);
+
+ // It's a draw if the weak king is on its back two ranks, within 2
+ // squares of the blocking pawn and the strong king is not
+ // closer. (I think this rule only fails in practically
+ // unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w
+ // and positions where qsearch will immediately correct the
+ // problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w)
+ if ( relative_rank(strongSide, weakKingSq) >= RANK_7
+ && weakKingDist <= 2
+ && weakKingDist <= strongKingDist)
+ return SCALE_FACTOR_DRAW;
+ }