+-------+
| o . . | o their pawns
| x . . | x our pawns
| . x . | <- Can sacrifice to create passer?
+-------+
yes
1 2 3 4 5
+-------+ +-------+ +-------+ +-------+ +-------+
| o . . | | o r . | | o r . | | o . b | | o . b | lowercase: theirs
| x b . | | x . . | | x . R | | x . R | | x . . | uppercase: ours
| . x . | | . x . | | . x . | | . x . | | . x B |
+-------+ +-------+ +-------+ +-------+ +-------+
no no yes no yes
The value of our top pawn depends on our ability to advance our bottom
pawn, levering their blocker. Previously, this pawn configuration was
always scored as passer (although a blocked one).
Add requirements for the square s above our (possibly) sacrificed pawn:
- s must not be occupied by them (1).
- If they attack s (2), we must attack s (3).
- If they attack s with a minor (4), we must attack s with a minor (5).
The attack from their blocker is ignored because it is inherent in the
structure; we are ok with sacrificing our bottom pawn.
LTC
LLR: 2.95 (-2.94,2.94) {0.25,1.75}
Total: 37030 W: 4962 L: 4682 D: 27386
Ptnml(0-2): 266, 3445, 10863, 3625, 316
https://tests.stockfishchess.org/tests/view/
5e92a2b4be6ede5b954bf239
STC
LLR: 2.94 (-2.94,2.94) {-0.50,1.50}
Total: 40874 W: 8066 L: 7813 D: 24995
Ptnml(0-2): 706, 4753, 9324, 4890, 764
https://tests.stockfishchess.org/tests/view/
5e922199af0a0143109dc90e
closes https://github.com/official-stockfish/Stockfish/pull/2624
Bench:
4828294
constexpr Color Them = ~Us;
constexpr Direction Up = pawn_push(Us);
+ constexpr Direction Down = -Up;
auto king_proximity = [&](Color c, Square s) {
return std::min(distance(pos.square<KING>(c), s), 5);
};
- Bitboard b, bb, squaresToQueen, unsafeSquares;
+ Bitboard b, bb, squaresToQueen, unsafeSquares, candidatePassers, leverable;
Score score = SCORE_ZERO;
b = pe->passed_pawns(Us);
+ candidatePassers = b & shift<Down>(pos.pieces(Them, PAWN));
+ if (candidatePassers)
+ {
+ // Can we lever the blocker of a candidate passer?
+ leverable = shift<Up>(pos.pieces(Us, PAWN))
+ & ~pos.pieces(Them)
+ & (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES])
+ & (~(attackedBy[Them][KNIGHT] | attackedBy[Them][BISHOP])
+ | (attackedBy[Us ][KNIGHT] | attackedBy[Us ][BISHOP]));
+
+ // Remove candidate otherwise
+ b &= ~candidatePassers
+ | shift<WEST>(leverable)
+ | shift<EAST>(leverable);
+ }
+
while (b)
{
Square s = pop_lsb(&b);
// (a) there is no stoppers except some levers
// (b) the only stoppers are the leverPush, but we outnumber them
// (c) there is only one front stopper which can be levered.
+ // (Refined in Evaluation::passed)
passed = !(stoppers ^ lever)
|| ( !(stoppers ^ leverPush)
&& popcount(phalanx) >= popcount(leverPush))