2 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3 Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
4 Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
5 Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
7 Stockfish is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Stockfish is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
31 // Used to drive the king towards the edge of the board
32 // in KX vs K and KQ vs KR endgames.
33 inline int push_to_edge(Square s) {
34 int rd = edge_distance(rank_of(s)), fd = edge_distance(file_of(s));
35 return 90 - (7 * fd * fd / 2 + 7 * rd * rd / 2);
38 // Used to drive the king towards A1H8 corners in KBN vs K endgames.
39 inline int push_to_corner(Square s) {
40 return abs(7 - rank_of(s) - file_of(s));
43 // Drive a piece close to or away from another piece
44 inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); }
45 inline int push_away(Square s1, Square s2) { return 120 - push_close(s1, s2); }
48 bool verify_material(const Position& pos, Color c, Value npm, int pawnsCnt) {
49 return pos.non_pawn_material(c) == npm && pos.count<PAWN>(c) == pawnsCnt;
53 // Map the square as if strongSide is white and strongSide's only pawn
54 // is on the left half of the board.
55 Square normalize(const Position& pos, Color strongSide, Square sq) {
57 assert(pos.count<PAWN>(strongSide) == 1);
59 if (file_of(pos.square<PAWN>(strongSide)) >= FILE_E)
62 return strongSide == WHITE ? sq : flip_rank(sq);
70 std::pair<Map<Value>, Map<ScaleFactor>> maps;
90 add<KBPPKB>("KBPPKB");
91 add<KRPPKRP>("KRPPKRP");
96 /// Mate with KX vs K. This function is used to evaluate positions with
97 /// king and plenty of material vs a lone king. It simply gives the
98 /// attacking side a bonus for driving the defending king towards the edge
99 /// of the board, and for keeping the distance between the two kings small.
101 Value Endgame<KXK>::operator()(const Position& pos) const {
103 assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
104 assert(!pos.checkers()); // Eval is never called when in check
106 // Stalemate detection with lone king
107 if (pos.side_to_move() == weakSide && !MoveList<LEGAL>(pos).size())
110 Square winnerKSq = pos.square<KING>(strongSide);
111 Square loserKSq = pos.square<KING>(weakSide);
113 Value result = pos.non_pawn_material(strongSide)
114 + pos.count<PAWN>(strongSide) * PawnValueEg
115 + push_to_edge(loserKSq)
116 + push_close(winnerKSq, loserKSq);
118 if ( pos.count<QUEEN>(strongSide)
119 || pos.count<ROOK>(strongSide)
120 ||(pos.count<BISHOP>(strongSide) && pos.count<KNIGHT>(strongSide))
121 || ( (pos.pieces(strongSide, BISHOP) & ~DarkSquares)
122 && (pos.pieces(strongSide, BISHOP) & DarkSquares)))
123 result = std::min(result + VALUE_KNOWN_WIN, VALUE_TB_WIN_IN_MAX_PLY - 1);
125 return strongSide == pos.side_to_move() ? result : -result;
129 /// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the
130 /// defending king towards a corner square that our bishop attacks.
132 Value Endgame<KBNK>::operator()(const Position& pos) const {
134 assert(verify_material(pos, strongSide, KnightValueMg + BishopValueMg, 0));
135 assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
137 Square winnerKSq = pos.square<KING>(strongSide);
138 Square loserKSq = pos.square<KING>(weakSide);
139 Square bishopSq = pos.square<BISHOP>(strongSide);
141 // If our bishop does not attack A1/H8, we flip the enemy king square
142 // to drive to opposite corners (A8/H1).
144 Value result = (VALUE_KNOWN_WIN + 3520)
145 + push_close(winnerKSq, loserKSq)
146 + 420 * push_to_corner(opposite_colors(bishopSq, SQ_A1) ? flip_file(loserKSq) : loserKSq);
148 assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY);
149 return strongSide == pos.side_to_move() ? result : -result;
153 /// KP vs K. This endgame is evaluated with the help of a bitbase
155 Value Endgame<KPK>::operator()(const Position& pos) const {
157 assert(verify_material(pos, strongSide, VALUE_ZERO, 1));
158 assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
160 // Assume strongSide is white and the pawn is on files A-D
161 Square wksq = normalize(pos, strongSide, pos.square<KING>(strongSide));
162 Square bksq = normalize(pos, strongSide, pos.square<KING>(weakSide));
163 Square psq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
165 Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
167 if (!Bitbases::probe(wksq, psq, bksq, us))
170 Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(psq));
172 return strongSide == pos.side_to_move() ? result : -result;
176 /// KR vs KP. This is a somewhat tricky endgame to evaluate precisely without
177 /// a bitbase. The function below returns drawish scores when the pawn is
178 /// far advanced with support of the king, while the attacking king is far
181 Value Endgame<KRKP>::operator()(const Position& pos) const {
183 assert(verify_material(pos, strongSide, RookValueMg, 0));
184 assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
186 Square wksq = relative_square(strongSide, pos.square<KING>(strongSide));
187 Square bksq = relative_square(strongSide, pos.square<KING>(weakSide));
188 Square rsq = relative_square(strongSide, pos.square<ROOK>(strongSide));
189 Square psq = relative_square(strongSide, pos.square<PAWN>(weakSide));
191 Square queeningSq = make_square(file_of(psq), RANK_1);
194 // If the stronger side's king is in front of the pawn, it's a win
195 if (forward_file_bb(WHITE, wksq) & psq)
196 result = RookValueEg - distance(wksq, psq);
198 // If the weaker side's king is too far from the pawn and the rook,
200 else if ( distance(bksq, psq) >= 3 + (pos.side_to_move() == weakSide)
201 && distance(bksq, rsq) >= 3)
202 result = RookValueEg - distance(wksq, psq);
204 // If the pawn is far advanced and supported by the defending king,
205 // the position is drawish
206 else if ( rank_of(bksq) <= RANK_3
207 && distance(bksq, psq) == 1
208 && rank_of(wksq) >= RANK_4
209 && distance(wksq, psq) > 2 + (pos.side_to_move() == strongSide))
210 result = Value(80) - 8 * distance(wksq, psq);
213 result = Value(200) - 8 * ( distance(wksq, psq + SOUTH)
214 - distance(bksq, psq + SOUTH)
215 - distance(psq, queeningSq));
217 return strongSide == pos.side_to_move() ? result : -result;
221 /// KR vs KB. This is very simple, and always returns drawish scores. The
222 /// score is slightly bigger when the defending king is close to the edge.
224 Value Endgame<KRKB>::operator()(const Position& pos) const {
226 assert(verify_material(pos, strongSide, RookValueMg, 0));
227 assert(verify_material(pos, weakSide, BishopValueMg, 0));
229 Value result = Value(push_to_edge(pos.square<KING>(weakSide)));
230 return strongSide == pos.side_to_move() ? result : -result;
234 /// KR vs KN. The attacking side has slightly better winning chances than
235 /// in KR vs KB, particularly if the king and the knight are far apart.
237 Value Endgame<KRKN>::operator()(const Position& pos) const {
239 assert(verify_material(pos, strongSide, RookValueMg, 0));
240 assert(verify_material(pos, weakSide, KnightValueMg, 0));
242 Square bksq = pos.square<KING>(weakSide);
243 Square bnsq = pos.square<KNIGHT>(weakSide);
244 Value result = Value(push_to_edge(bksq) + push_away(bksq, bnsq));
245 return strongSide == pos.side_to_move() ? result : -result;
249 /// KQ vs KP. In general, this is a win for the stronger side, but there are a
250 /// few important exceptions. A pawn on 7th rank and on the A,C,F or H files
251 /// with a king positioned next to it can be a draw, so in that case, we only
252 /// use the distance between the kings.
254 Value Endgame<KQKP>::operator()(const Position& pos) const {
256 assert(verify_material(pos, strongSide, QueenValueMg, 0));
257 assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
259 Square winnerKSq = pos.square<KING>(strongSide);
260 Square loserKSq = pos.square<KING>(weakSide);
261 Square pawnSq = pos.square<PAWN>(weakSide);
263 Value result = Value(push_close(winnerKSq, loserKSq));
265 if ( relative_rank(weakSide, pawnSq) != RANK_7
266 || distance(loserKSq, pawnSq) != 1
267 || ((FileBBB | FileDBB | FileEBB | FileGBB) & pawnSq))
268 result += QueenValueEg - PawnValueEg;
270 return strongSide == pos.side_to_move() ? result : -result;
274 /// KQ vs KR. This is almost identical to KX vs K: We give the attacking
275 /// king a bonus for having the kings close together, and for forcing the
276 /// defending king towards the edge. If we also take care to avoid null move for
277 /// the defending side in the search, this is usually sufficient to win KQ vs KR.
279 Value Endgame<KQKR>::operator()(const Position& pos) const {
281 assert(verify_material(pos, strongSide, QueenValueMg, 0));
282 assert(verify_material(pos, weakSide, RookValueMg, 0));
284 Square winnerKSq = pos.square<KING>(strongSide);
285 Square loserKSq = pos.square<KING>(weakSide);
287 Value result = QueenValueEg
289 + push_to_edge(loserKSq)
290 + push_close(winnerKSq, loserKSq);
292 return strongSide == pos.side_to_move() ? result : -result;
296 /// KNN vs KP. Very drawish, but there are some mate opportunities if we can
297 // press the weakSide King to a corner before the pawn advances too much.
299 Value Endgame<KNNKP>::operator()(const Position& pos) const {
301 assert(verify_material(pos, strongSide, 2 * KnightValueMg, 0));
302 assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
304 Value result = PawnValueEg
305 + 2 * push_to_edge(pos.square<KING>(weakSide))
306 - 10 * relative_rank(weakSide, pos.square<PAWN>(weakSide));
308 return strongSide == pos.side_to_move() ? result : -result;
312 /// Some cases of trivial draws
313 template<> Value Endgame<KNNK>::operator()(const Position&) const { return VALUE_DRAW; }
316 /// KB and one or more pawns vs K. It checks for draws with rook pawns and
317 /// a bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_DRAW
318 /// is returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
321 ScaleFactor Endgame<KBPsK>::operator()(const Position& pos) const {
323 assert(pos.non_pawn_material(strongSide) == BishopValueMg);
324 assert(pos.count<PAWN>(strongSide) >= 1);
326 // No assertions about the material of weakSide, because we want draws to
327 // be detected even when the weaker side has some pawns.
329 Bitboard strongpawns = pos.pieces(strongSide, PAWN);
330 Bitboard allpawns = pos.pieces(PAWN);
332 // All strongSide pawns are on a single rook file?
333 if (!(strongpawns & ~FileABB) || !(strongpawns & ~FileHBB))
335 Square bishopSq = pos.square<BISHOP>(strongSide);
336 Square queeningSq = relative_square(strongSide, make_square(file_of(lsb(strongpawns)), RANK_8));
337 Square weakkingSq = pos.square<KING>(weakSide);
339 if ( opposite_colors(queeningSq, bishopSq)
340 && distance(queeningSq, weakkingSq) <= 1)
341 return SCALE_FACTOR_DRAW;
344 // If all the pawns are on the same B or G file, then it's potentially a draw
345 if ((!(allpawns & ~FileBBB) || !(allpawns & ~FileGBB))
346 && pos.non_pawn_material(weakSide) == 0
347 && pos.count<PAWN>(weakSide) >= 1)
349 // Get the least advanced weakSide pawn
350 Square weakPawnSq = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN));
352 Square strongKingSq = pos.square<KING>(strongSide);
353 Square weakKingSq = pos.square<KING>(weakSide);
354 Square bishopSq = pos.square<BISHOP>(strongSide);
356 // There's potential for a draw if our pawn is blocked on the 7th rank,
357 // the bishop cannot attack it or they only have one pawn left
358 if ( relative_rank(strongSide, weakPawnSq) == RANK_7
359 && (strongpawns & (weakPawnSq + pawn_push(weakSide)))
360 && (opposite_colors(bishopSq, weakPawnSq) || !more_than_one(strongpawns)))
362 int strongKingDist = distance(weakPawnSq, strongKingSq);
363 int weakKingDist = distance(weakPawnSq, weakKingSq);
365 // It's a draw if the weak king is on its back two ranks, within 2
366 // squares of the blocking pawn and the strong king is not
367 // closer. (I think this rule only fails in practically
368 // unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w
369 // and positions where qsearch will immediately correct the
370 // problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w)
371 if ( relative_rank(strongSide, weakKingSq) >= RANK_7
373 && weakKingDist <= strongKingDist)
374 return SCALE_FACTOR_DRAW;
378 return SCALE_FACTOR_NONE;
382 /// KQ vs KR and one or more pawns. It tests for fortress draws with a rook on
383 /// the third rank defended by a pawn.
385 ScaleFactor Endgame<KQKRPs>::operator()(const Position& pos) const {
387 assert(verify_material(pos, strongSide, QueenValueMg, 0));
388 assert(pos.count<ROOK>(weakSide) == 1);
389 assert(pos.count<PAWN>(weakSide) >= 1);
391 Square kingSq = pos.square<KING>(weakSide);
392 Square rsq = pos.square<ROOK>(weakSide);
394 if ( relative_rank(weakSide, kingSq) <= RANK_2
395 && relative_rank(weakSide, pos.square<KING>(strongSide)) >= RANK_4
396 && relative_rank(weakSide, rsq) == RANK_3
397 && ( pos.pieces(weakSide, PAWN)
398 & pos.attacks_from<KING>(kingSq)
399 & pos.attacks_from<PAWN>(rsq, strongSide)))
400 return SCALE_FACTOR_DRAW;
402 return SCALE_FACTOR_NONE;
406 /// KRP vs KR. This function knows a handful of the most important classes of
407 /// drawn positions, but is far from perfect. It would probably be a good idea
408 /// to add more knowledge in the future.
410 /// It would also be nice to rewrite the actual code for this function,
411 /// which is mostly copied from Glaurung 1.x, and isn't very pretty.
413 ScaleFactor Endgame<KRPKR>::operator()(const Position& pos) const {
415 assert(verify_material(pos, strongSide, RookValueMg, 1));
416 assert(verify_material(pos, weakSide, RookValueMg, 0));
418 // Assume strongSide is white and the pawn is on files A-D
419 Square wksq = normalize(pos, strongSide, pos.square<KING>(strongSide));
420 Square bksq = normalize(pos, strongSide, pos.square<KING>(weakSide));
421 Square wrsq = normalize(pos, strongSide, pos.square<ROOK>(strongSide));
422 Square wpsq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
423 Square brsq = normalize(pos, strongSide, pos.square<ROOK>(weakSide));
425 File f = file_of(wpsq);
426 Rank r = rank_of(wpsq);
427 Square queeningSq = make_square(f, RANK_8);
428 int tempo = (pos.side_to_move() == strongSide);
430 // If the pawn is not too far advanced and the defending king defends the
431 // queening square, use the third-rank defence.
433 && distance(bksq, queeningSq) <= 1
435 && (rank_of(brsq) == RANK_6 || (r <= RANK_3 && rank_of(wrsq) != RANK_6)))
436 return SCALE_FACTOR_DRAW;
438 // The defending side saves a draw by checking from behind in case the pawn
439 // has advanced to the 6th rank with the king behind.
441 && distance(bksq, queeningSq) <= 1
442 && rank_of(wksq) + tempo <= RANK_6
443 && (rank_of(brsq) == RANK_1 || (!tempo && distance<File>(brsq, wpsq) >= 3)))
444 return SCALE_FACTOR_DRAW;
447 && bksq == queeningSq
448 && rank_of(brsq) == RANK_1
449 && (!tempo || distance(wksq, wpsq) >= 2))
450 return SCALE_FACTOR_DRAW;
452 // White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7
453 // and the black rook is behind the pawn.
456 && (bksq == SQ_H7 || bksq == SQ_G7)
457 && file_of(brsq) == FILE_A
458 && (rank_of(brsq) <= RANK_3 || file_of(wksq) >= FILE_D || rank_of(wksq) <= RANK_5))
459 return SCALE_FACTOR_DRAW;
461 // If the defending king blocks the pawn and the attacking king is too far
462 // away, it's a draw.
464 && bksq == wpsq + NORTH
465 && distance(wksq, wpsq) - tempo >= 2
466 && distance(wksq, brsq) - tempo >= 2)
467 return SCALE_FACTOR_DRAW;
469 // Pawn on the 7th rank supported by the rook from behind usually wins if the
470 // attacking king is closer to the queening square than the defending king,
471 // and the defending king cannot gain tempi by threatening the attacking rook.
474 && file_of(wrsq) == f
475 && wrsq != queeningSq
476 && (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo)
477 && (distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo))
478 return ScaleFactor(SCALE_FACTOR_MAX - 2 * distance(wksq, queeningSq));
480 // Similar to the above, but with the pawn further back
482 && file_of(wrsq) == f
484 && (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo)
485 && (distance(wksq, wpsq + NORTH) < distance(bksq, wpsq + NORTH) - 2 + tempo)
486 && ( distance(bksq, wrsq) + tempo >= 3
487 || ( distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo
488 && (distance(wksq, wpsq + NORTH) < distance(bksq, wrsq) + tempo))))
489 return ScaleFactor( SCALE_FACTOR_MAX
490 - 8 * distance(wpsq, queeningSq)
491 - 2 * distance(wksq, queeningSq));
493 // If the pawn is not far advanced and the defending king is somewhere in
494 // the pawn's path, it's probably a draw.
495 if (r <= RANK_4 && bksq > wpsq)
497 if (file_of(bksq) == file_of(wpsq))
498 return ScaleFactor(10);
499 if ( distance<File>(bksq, wpsq) == 1
500 && distance(wksq, bksq) > 2)
501 return ScaleFactor(24 - 2 * distance(wksq, bksq));
503 return SCALE_FACTOR_NONE;
507 ScaleFactor Endgame<KRPKB>::operator()(const Position& pos) const {
509 assert(verify_material(pos, strongSide, RookValueMg, 1));
510 assert(verify_material(pos, weakSide, BishopValueMg, 0));
512 // Test for a rook pawn
513 if (pos.pieces(PAWN) & (FileABB | FileHBB))
515 Square ksq = pos.square<KING>(weakSide);
516 Square bsq = pos.square<BISHOP>(weakSide);
517 Square psq = pos.square<PAWN>(strongSide);
518 Rank rk = relative_rank(strongSide, psq);
519 Direction push = pawn_push(strongSide);
521 // If the pawn is on the 5th rank and the pawn (currently) is on
522 // the same color square as the bishop then there is a chance of
523 // a fortress. Depending on the king position give a moderate
524 // reduction or a stronger one if the defending king is near the
525 // corner but not trapped there.
526 if (rk == RANK_5 && !opposite_colors(bsq, psq))
528 int d = distance(psq + 3 * push, ksq);
530 if (d <= 2 && !(d == 0 && ksq == pos.square<KING>(strongSide) + 2 * push))
531 return ScaleFactor(24);
533 return ScaleFactor(48);
536 // When the pawn has moved to the 6th rank we can be fairly sure
537 // it's drawn if the bishop attacks the square in front of the
538 // pawn from a reasonable distance and the defending king is near
541 && distance(psq + 2 * push, ksq) <= 1
542 && (PseudoAttacks[BISHOP][bsq] & (psq + push))
543 && distance<File>(bsq, psq) >= 2)
544 return ScaleFactor(8);
547 return SCALE_FACTOR_NONE;
550 /// KRPP vs KRP. There is just a single rule: if the stronger side has no passed
551 /// pawns and the defending king is actively placed, the position is drawish.
553 ScaleFactor Endgame<KRPPKRP>::operator()(const Position& pos) const {
555 assert(verify_material(pos, strongSide, RookValueMg, 2));
556 assert(verify_material(pos, weakSide, RookValueMg, 1));
558 Square wpsq1 = pos.squares<PAWN>(strongSide)[0];
559 Square wpsq2 = pos.squares<PAWN>(strongSide)[1];
560 Square bksq = pos.square<KING>(weakSide);
562 // Does the stronger side have a passed pawn?
563 if (pos.pawn_passed(strongSide, wpsq1) || pos.pawn_passed(strongSide, wpsq2))
564 return SCALE_FACTOR_NONE;
566 Rank r = std::max(relative_rank(strongSide, wpsq1), relative_rank(strongSide, wpsq2));
568 if ( distance<File>(bksq, wpsq1) <= 1
569 && distance<File>(bksq, wpsq2) <= 1
570 && relative_rank(strongSide, bksq) > r)
572 assert(r > RANK_1 && r < RANK_7);
573 return ScaleFactor(7 * r);
575 return SCALE_FACTOR_NONE;
579 /// K and two or more pawns vs K. There is just a single rule here: If all pawns
580 /// are on the same rook file and are blocked by the defending king, it's a draw.
582 ScaleFactor Endgame<KPsK>::operator()(const Position& pos) const {
584 assert(pos.non_pawn_material(strongSide) == VALUE_ZERO);
585 assert(pos.count<PAWN>(strongSide) >= 2);
586 assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
588 Square ksq = pos.square<KING>(weakSide);
589 Bitboard pawns = pos.pieces(strongSide, PAWN);
591 // If all pawns are ahead of the king, on a single rook file and
592 // the king is within one file of the pawns, it's a draw.
593 if ( !(pawns & ~forward_ranks_bb(weakSide, ksq))
594 && !((pawns & ~FileABB) && (pawns & ~FileHBB))
595 && distance<File>(ksq, lsb(pawns)) <= 1)
596 return SCALE_FACTOR_DRAW;
598 return SCALE_FACTOR_NONE;
602 /// KBP vs KB. There are two rules: if the defending king is somewhere along the
603 /// path of the pawn, and the square of the king is not of the same color as the
604 /// stronger side's bishop, it's a draw. If the two bishops have opposite color,
605 /// it's almost always a draw.
607 ScaleFactor Endgame<KBPKB>::operator()(const Position& pos) const {
609 assert(verify_material(pos, strongSide, BishopValueMg, 1));
610 assert(verify_material(pos, weakSide, BishopValueMg, 0));
612 Square pawnSq = pos.square<PAWN>(strongSide);
613 Square strongBishopSq = pos.square<BISHOP>(strongSide);
614 Square weakBishopSq = pos.square<BISHOP>(weakSide);
615 Square weakKingSq = pos.square<KING>(weakSide);
617 // Case 1: Defending king blocks the pawn, and cannot be driven away
618 if ( file_of(weakKingSq) == file_of(pawnSq)
619 && relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq)
620 && ( opposite_colors(weakKingSq, strongBishopSq)
621 || relative_rank(strongSide, weakKingSq) <= RANK_6))
622 return SCALE_FACTOR_DRAW;
624 // Case 2: Opposite colored bishops
625 if (opposite_colors(strongBishopSq, weakBishopSq))
626 return SCALE_FACTOR_DRAW;
628 return SCALE_FACTOR_NONE;
632 /// KBPP vs KB. It detects a few basic draws with opposite-colored bishops
634 ScaleFactor Endgame<KBPPKB>::operator()(const Position& pos) const {
636 assert(verify_material(pos, strongSide, BishopValueMg, 2));
637 assert(verify_material(pos, weakSide, BishopValueMg, 0));
639 Square wbsq = pos.square<BISHOP>(strongSide);
640 Square bbsq = pos.square<BISHOP>(weakSide);
642 if (!opposite_colors(wbsq, bbsq))
643 return SCALE_FACTOR_NONE;
645 Square ksq = pos.square<KING>(weakSide);
646 Square psq1 = pos.squares<PAWN>(strongSide)[0];
647 Square psq2 = pos.squares<PAWN>(strongSide)[1];
648 Square blockSq1, blockSq2;
650 if (relative_rank(strongSide, psq1) > relative_rank(strongSide, psq2))
652 blockSq1 = psq1 + pawn_push(strongSide);
653 blockSq2 = make_square(file_of(psq2), rank_of(psq1));
657 blockSq1 = psq2 + pawn_push(strongSide);
658 blockSq2 = make_square(file_of(psq1), rank_of(psq2));
661 switch (distance<File>(psq1, psq2))
664 // Both pawns are on the same file. It's an easy draw if the defender firmly
665 // controls some square in the frontmost pawn's path.
666 if ( file_of(ksq) == file_of(blockSq1)
667 && relative_rank(strongSide, ksq) >= relative_rank(strongSide, blockSq1)
668 && opposite_colors(ksq, wbsq))
669 return SCALE_FACTOR_DRAW;
671 return SCALE_FACTOR_NONE;
674 // Pawns on adjacent files. It's a draw if the defender firmly controls the
675 // square in front of the frontmost pawn's path, and the square diagonally
676 // behind this square on the file of the other pawn.
678 && opposite_colors(ksq, wbsq)
679 && ( bbsq == blockSq2
680 || (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(weakSide, BISHOP))
681 || distance<Rank>(psq1, psq2) >= 2))
682 return SCALE_FACTOR_DRAW;
684 else if ( ksq == blockSq2
685 && opposite_colors(ksq, wbsq)
686 && ( bbsq == blockSq1
687 || (pos.attacks_from<BISHOP>(blockSq1) & pos.pieces(weakSide, BISHOP))))
688 return SCALE_FACTOR_DRAW;
690 return SCALE_FACTOR_NONE;
693 // The pawns are not on the same file or adjacent files. No scaling.
694 return SCALE_FACTOR_NONE;
699 /// KBP vs KN. There is a single rule: If the defending king is somewhere along
700 /// the path of the pawn, and the square of the king is not of the same color as
701 /// the stronger side's bishop, it's a draw.
703 ScaleFactor Endgame<KBPKN>::operator()(const Position& pos) const {
705 assert(verify_material(pos, strongSide, BishopValueMg, 1));
706 assert(verify_material(pos, weakSide, KnightValueMg, 0));
708 Square pawnSq = pos.square<PAWN>(strongSide);
709 Square strongBishopSq = pos.square<BISHOP>(strongSide);
710 Square weakKingSq = pos.square<KING>(weakSide);
712 if ( file_of(weakKingSq) == file_of(pawnSq)
713 && relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq)
714 && ( opposite_colors(weakKingSq, strongBishopSq)
715 || relative_rank(strongSide, weakKingSq) <= RANK_6))
716 return SCALE_FACTOR_DRAW;
718 return SCALE_FACTOR_NONE;
722 /// KNP vs K. There is a single rule: if the pawn is a rook pawn on the 7th rank
723 /// and the defending king prevents the pawn from advancing, the position is drawn.
725 ScaleFactor Endgame<KNPK>::operator()(const Position& pos) const {
727 assert(verify_material(pos, strongSide, KnightValueMg, 1));
728 assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
730 // Assume strongSide is white and the pawn is on files A-D
731 Square pawnSq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
732 Square weakKingSq = normalize(pos, strongSide, pos.square<KING>(weakSide));
734 if (pawnSq == SQ_A7 && distance(SQ_A8, weakKingSq) <= 1)
735 return SCALE_FACTOR_DRAW;
737 return SCALE_FACTOR_NONE;
741 /// KNP vs KB. If knight can block bishop from taking pawn, it's a win.
742 /// Otherwise the position is drawn.
744 ScaleFactor Endgame<KNPKB>::operator()(const Position& pos) const {
746 assert(verify_material(pos, strongSide, KnightValueMg, 1));
747 assert(verify_material(pos, weakSide, BishopValueMg, 0));
749 Square pawnSq = pos.square<PAWN>(strongSide);
750 Square bishopSq = pos.square<BISHOP>(weakSide);
751 Square weakKingSq = pos.square<KING>(weakSide);
753 // King needs to get close to promoting pawn to prevent knight from blocking.
754 // Rules for this are very tricky, so just approximate.
755 if (forward_file_bb(strongSide, pawnSq) & pos.attacks_from<BISHOP>(bishopSq))
756 return ScaleFactor(distance(weakKingSq, pawnSq));
758 return SCALE_FACTOR_NONE;
762 /// KP vs KP. This is done by removing the weakest side's pawn and probing the
763 /// KP vs K bitbase: If the weakest side has a draw without the pawn, it probably
764 /// has at least a draw with the pawn as well. The exception is when the stronger
765 /// side's pawn is far advanced and not on a rook file; in this case it is often
766 /// possible to win (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
768 ScaleFactor Endgame<KPKP>::operator()(const Position& pos) const {
770 assert(verify_material(pos, strongSide, VALUE_ZERO, 1));
771 assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
773 // Assume strongSide is white and the pawn is on files A-D
774 Square wksq = normalize(pos, strongSide, pos.square<KING>(strongSide));
775 Square bksq = normalize(pos, strongSide, pos.square<KING>(weakSide));
776 Square psq = normalize(pos, strongSide, pos.square<PAWN>(strongSide));
778 Color us = strongSide == pos.side_to_move() ? WHITE : BLACK;
780 // If the pawn has advanced to the fifth rank or further, and is not a
781 // rook pawn, it's too dangerous to assume that it's at least a draw.
782 if (rank_of(psq) >= RANK_5 && file_of(psq) != FILE_A)
783 return SCALE_FACTOR_NONE;
785 // Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw,
786 // it's probably at least a draw even with the pawn.
787 return Bitbases::probe(wksq, psq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW;