Document where we want a uint16_t instead of a uint64_t
[glaurung_clone.git] / src / endgame.cpp
blobc320ba309dd120010dbd808bd6345e2d9935fa01
1 /*
2 Glaurung, a UCI chess playing engine.
3 Copyright (C) 2004-2008 Tord Romstad
5 Glaurung is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 Glaurung is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ////
21 //// Includes
22 ////
24 #include <cassert>
26 #include "bitbase.h"
27 #include "endgame.h"
30 ////
31 //// Constants and variables
32 ////
34 /// Evaluation functions
36 // Generic "mate lone king" eval:
37 KXKEvaluationFunction EvaluateKXK = KXKEvaluationFunction(WHITE);
38 KXKEvaluationFunction EvaluateKKX = KXKEvaluationFunction(BLACK);
40 // KBN vs K:
41 KBNKEvaluationFunction EvaluateKBNK = KBNKEvaluationFunction(WHITE);
42 KBNKEvaluationFunction EvaluateKKBN = KBNKEvaluationFunction(BLACK);
44 // KP vs K:
45 KPKEvaluationFunction EvaluateKPK = KPKEvaluationFunction(WHITE);
46 KPKEvaluationFunction EvaluateKKP = KPKEvaluationFunction(BLACK);
48 // KR vs KP:
49 KRKPEvaluationFunction EvaluateKRKP = KRKPEvaluationFunction(WHITE);
50 KRKPEvaluationFunction EvaluateKPKR = KRKPEvaluationFunction(BLACK);
52 // KR vs KB:
53 KRKBEvaluationFunction EvaluateKRKB = KRKBEvaluationFunction(WHITE);
54 KRKBEvaluationFunction EvaluateKBKR = KRKBEvaluationFunction(BLACK);
56 // KR vs KN:
57 KRKNEvaluationFunction EvaluateKRKN = KRKNEvaluationFunction(WHITE);
58 KRKNEvaluationFunction EvaluateKNKR = KRKNEvaluationFunction(BLACK);
60 // KQ vs KR:
61 KQKREvaluationFunction EvaluateKQKR = KQKREvaluationFunction(WHITE);
62 KQKREvaluationFunction EvaluateKRKQ = KQKREvaluationFunction(BLACK);
65 /// Scaling functions
67 // KBP vs K:
68 KBPKScalingFunction ScaleKBPK = KBPKScalingFunction(WHITE);
69 KBPKScalingFunction ScaleKKBP = KBPKScalingFunction(BLACK);
71 // KQ vs KRP:
72 KQKRPScalingFunction ScaleKQKRP = KQKRPScalingFunction(WHITE);
73 KQKRPScalingFunction ScaleKRPKQ = KQKRPScalingFunction(BLACK);
75 // KRP vs KR:
76 KRPKRScalingFunction ScaleKRPKR = KRPKRScalingFunction(WHITE);
77 KRPKRScalingFunction ScaleKRKRP = KRPKRScalingFunction(BLACK);
79 // KRPP vs KRP:
80 KRPPKRPScalingFunction ScaleKRPPKRP = KRPPKRPScalingFunction(WHITE);
81 KRPPKRPScalingFunction ScaleKRPKRPP = KRPPKRPScalingFunction(BLACK);
83 // King and pawns vs king:
84 KPsKScalingFunction ScaleKPsK = KPsKScalingFunction(WHITE);
85 KPsKScalingFunction ScaleKKPs = KPsKScalingFunction(BLACK);
87 // KBP vs KB:
88 KBPKBScalingFunction ScaleKBPKB = KBPKBScalingFunction(WHITE);
89 KBPKBScalingFunction ScaleKBKBP = KBPKBScalingFunction(BLACK);
91 // KBP vs KN:
92 KBPKNScalingFunction ScaleKBPKN = KBPKNScalingFunction(WHITE);
93 KBPKNScalingFunction ScaleKNKBP = KBPKNScalingFunction(BLACK);
95 // KNP vs K:
96 KNPKScalingFunction ScaleKNPK = KNPKScalingFunction(WHITE);
97 KNPKScalingFunction ScaleKKNP = KNPKScalingFunction(BLACK);
99 // KPKP
100 KPKPScalingFunction ScaleKPKPw = KPKPScalingFunction(WHITE);
101 KPKPScalingFunction ScaleKPKPb = KPKPScalingFunction(BLACK);
104 ////
105 //// Local definitions
106 ////
108 namespace {
110 // Table used to drive the defending king towards the edge of the board
111 // in KX vs K and KQ vs KR endgames:
112 const uint8_t MateTable[64] = {
113 100, 90, 80, 70, 70, 80, 90, 100,
114 90, 70, 60, 50, 50, 60, 70, 90,
115 80, 60, 40, 30, 30, 40, 60, 80,
116 70, 50, 30, 20, 20, 30, 50, 70,
117 70, 50, 30, 20, 20, 30, 50, 70,
118 80, 60, 40, 30, 30, 40, 60, 80,
119 90, 70, 60, 50, 50, 60, 70, 90,
120 100, 90, 80, 70, 70, 80, 90, 100,
123 // Table used to drive the defending king towards a corner square of the
124 // right color in KBN vs K endgames:
125 const uint8_t KBNKMateTable[64] = {
126 200, 190, 180, 170, 160, 150, 140, 130,
127 190, 180, 170, 160, 150, 140, 130, 140,
128 180, 170, 155, 140, 140, 125, 140, 150,
129 170, 160, 140, 120, 110, 140, 150, 160,
130 160, 150, 140, 110, 120, 140, 160, 170,
131 150, 140, 125, 140, 140, 155, 170, 180,
132 140, 130, 140, 150, 160, 170, 180, 190,
133 130, 140, 150, 160, 170, 180, 190, 200
136 // The attacking side is given a descending bonus based on distance between
137 // the two kings in basic endgames:
138 const int DistanceBonus[8] = {0, 0, 100, 80, 60, 40, 20, 10};
140 // Bitbase for KP vs K:
141 uint8_t KPKBitbase[24576];
143 // Penalty for big distance between king and knight for the defending king
144 // and knight in KR vs KN endgames:
145 const int KRKNKingKnightDistancePenalty[8] = { 0, 0, 4, 10, 20, 32, 48, 70 };
147 // Various inline functions for accessing the above arrays:
149 inline Value mate_table(Square s) {
150 return Value(MateTable[s]);
153 inline Value kbnk_mate_table(Square s) {
154 return Value(KBNKMateTable[s]);
157 inline Value distance_bonus(int d) {
158 return Value(DistanceBonus[d]);
161 inline Value krkn_king_knight_distance_penalty(int d) {
162 return Value(KRKNKingKnightDistancePenalty[d]);
165 // Function for probing the KP vs K bitbase:
166 int probe_kpk(Square wksq, Square wpsq, Square bksq, Color stm);
171 ////
172 //// Functions
173 ////
175 /// Constructors
177 EndgameEvaluationFunction::EndgameEvaluationFunction(Color c) {
178 strongerSide = c;
179 weakerSide = opposite_color(strongerSide);
182 KXKEvaluationFunction::KXKEvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
183 KBNKEvaluationFunction::KBNKEvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
184 KPKEvaluationFunction::KPKEvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
185 KRKPEvaluationFunction::KRKPEvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
186 KRKBEvaluationFunction::KRKBEvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
187 KRKNEvaluationFunction::KRKNEvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
188 KQKREvaluationFunction::KQKREvaluationFunction(Color c) : EndgameEvaluationFunction(c) { }
191 ScalingFunction::ScalingFunction(Color c) {
192 strongerSide = c;
193 weakerSide = opposite_color(c);
196 KBPKScalingFunction::KBPKScalingFunction(Color c) : ScalingFunction(c) { }
197 KQKRPScalingFunction::KQKRPScalingFunction(Color c) : ScalingFunction(c) { }
198 KRPKRScalingFunction::KRPKRScalingFunction(Color c) : ScalingFunction(c) { }
199 KRPPKRPScalingFunction::KRPPKRPScalingFunction(Color c) : ScalingFunction(c) { }
200 KPsKScalingFunction::KPsKScalingFunction(Color c) : ScalingFunction(c) { }
201 KBPKBScalingFunction::KBPKBScalingFunction(Color c) : ScalingFunction(c) { }
202 KBPKNScalingFunction::KBPKNScalingFunction(Color c) : ScalingFunction(c) { }
203 KNPKScalingFunction::KNPKScalingFunction(Color c) : ScalingFunction(c) { }
204 KPKPScalingFunction::KPKPScalingFunction(Color c) : ScalingFunction(c) { }
207 /// Mate with KX vs K. This function is used to evaluate positions with
208 /// King and plenty of material vs a lone king. It simply gives the
209 /// attacking side a bonus for driving the defending king towards the edge
210 /// of the board, and for keeping the distance between the two kings small.
212 Value KXKEvaluationFunction::apply(const Position &pos) {
214 assert(pos.non_pawn_material(weakerSide) == Value(0));
215 assert(pos.pawn_count(weakerSide) == Value(0));
217 Square winnerKSq = pos.king_square(strongerSide);
218 Square loserKSq = pos.king_square(weakerSide);
220 Value result =
221 pos.non_pawn_material(strongerSide) +
222 pos.pawn_count(strongerSide) * PawnValueEndgame +
223 mate_table(loserKSq) +
224 distance_bonus(square_distance(winnerKSq, loserKSq));
226 if(pos.queen_count(strongerSide) > 0 || pos.rook_count(strongerSide) > 0 ||
227 pos.bishop_count(strongerSide) > 1)
228 // TODO: check for two equal-colored bishops!
229 result += VALUE_KNOWN_WIN;
231 return (strongerSide == pos.side_to_move())? result : -result;
235 /// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the
236 /// defending king towards a corner square of the right color.
238 Value KBNKEvaluationFunction::apply(const Position &pos) {
240 assert(pos.non_pawn_material(weakerSide) == Value(0));
241 assert(pos.pawn_count(weakerSide) == Value(0));
242 assert(pos.non_pawn_material(strongerSide) ==
243 KnightValueMidgame + BishopValueMidgame);
244 assert(pos.bishop_count(strongerSide) == 1);
245 assert(pos.knight_count(strongerSide) == 1);
246 assert(pos.pawn_count(strongerSide) == 0);
248 Square winnerKSq = pos.king_square(strongerSide);
249 Square loserKSq = pos.king_square(weakerSide);
250 Square bishopSquare = pos.bishop_list(strongerSide, 0);
252 if(square_color(bishopSquare) == BLACK) {
253 winnerKSq = flop_square(winnerKSq);
254 loserKSq = flop_square(loserKSq);
257 Value result =
258 VALUE_KNOWN_WIN + distance_bonus(square_distance(winnerKSq, loserKSq)) +
259 kbnk_mate_table(loserKSq);
261 return (strongerSide == pos.side_to_move())? result : -result;
265 /// KP vs K. This endgame is evaluated with the help of a bitbase.
267 Value KPKEvaluationFunction::apply(const Position &pos) {
269 assert(pos.non_pawn_material(strongerSide) == Value(0));
270 assert(pos.non_pawn_material(weakerSide) == Value(0));
271 assert(pos.pawn_count(strongerSide) == 1);
272 assert(pos.pawn_count(weakerSide) == 0);
274 Square wksq, bksq, wpsq;
275 Color stm;
277 if(strongerSide == WHITE) {
278 wksq = pos.king_square(WHITE);
279 bksq = pos.king_square(BLACK);
280 wpsq = pos.pawn_list(WHITE, 0);
281 stm = pos.side_to_move();
283 else {
284 wksq = flip_square(pos.king_square(BLACK));
285 bksq = flip_square(pos.king_square(WHITE));
286 wpsq = flip_square(pos.pawn_list(BLACK, 0));
287 stm = opposite_color(pos.side_to_move());
290 if(square_file(wpsq) >= FILE_E) {
291 wksq = flop_square(wksq);
292 bksq = flop_square(bksq);
293 wpsq = flop_square(wpsq);
296 if(probe_kpk(wksq, wpsq, bksq, stm)) {
297 Value result =
298 VALUE_KNOWN_WIN + PawnValueEndgame + Value(square_rank(wpsq));
299 return (strongerSide == pos.side_to_move())? result : -result;
302 return VALUE_DRAW;
306 /// KR vs KP. This is a somewhat tricky endgame to evaluate precisely without
307 /// a bitbase. The function below returns drawish scores when the pawn is
308 /// far advanced with support of the king, while the attacking king is far
309 /// away.
311 Value KRKPEvaluationFunction::apply(const Position &pos) {
313 assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
314 assert(pos.pawn_count(strongerSide) == 0);
315 assert(pos.non_pawn_material(weakerSide) == 0);
316 assert(pos.pawn_count(weakerSide) == 1);
318 Square wksq, wrsq, bksq, bpsq;
319 int tempo = (pos.side_to_move() == strongerSide);
321 wksq = pos.king_square(strongerSide);
322 wrsq = pos.rook_list(strongerSide, 0);
323 bksq = pos.king_square(weakerSide);
324 bpsq = pos.pawn_list(weakerSide, 0);
326 if(strongerSide == BLACK) {
327 wksq = flip_square(wksq);
328 wrsq = flip_square(wrsq);
329 bksq = flip_square(bksq);
330 bpsq = flip_square(bpsq);
333 Square queeningSq = make_square(square_file(bpsq), RANK_1);
334 Value result;
336 // If the stronger side's king is in front of the pawn, it's a win:
337 if(wksq < bpsq && square_file(wksq) == square_file(bpsq))
338 result = RookValueEndgame - Value(square_distance(wksq, bpsq));
340 // If the weaker side's king is too far from the pawn and the rook,
341 // it's a win:
342 else if(square_distance(bksq, bpsq) - (tempo^1) >= 3 &&
343 square_distance(bksq, wrsq) >= 3)
344 result = RookValueEndgame - Value(square_distance(wksq, bpsq));
346 // If the pawn is far advanced and supported by the defending king,
347 // the position is drawish:
348 else if(square_rank(bksq) <= RANK_3 && square_distance(bksq, bpsq) == 1 &&
349 square_rank(wksq) >= RANK_4 &&
350 square_distance(wksq, bpsq) - tempo > 2)
351 result = Value(80 - square_distance(wksq, bpsq) * 8);
353 else
354 result = Value(200)
355 - Value(square_distance(wksq, bpsq + DELTA_S) * 8)
356 + Value(square_distance(bksq, bpsq + DELTA_S) * 8)
357 + Value(square_distance(bpsq, queeningSq) * 8);
359 return (strongerSide == pos.side_to_move())? result : -result;
363 /// KR vs KB. This is very simple, and always returns drawish scores. The
364 /// score is slightly bigger when the defending king is close to the edge.
366 Value KRKBEvaluationFunction::apply(const Position &pos) {
368 assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
369 assert(pos.pawn_count(strongerSide) == 0);
370 assert(pos.non_pawn_material(weakerSide) == BishopValueMidgame);
371 assert(pos.pawn_count(weakerSide) == 0);
372 assert(pos.bishop_count(weakerSide) == 1);
374 Value result = mate_table(pos.king_square(weakerSide));
375 return (pos.side_to_move() == strongerSide)? result : -result;
379 /// KR vs KN. The attacking side has slightly better winning chances than
380 /// in KR vs KB, particularly if the king and the knight are far apart.
382 Value KRKNEvaluationFunction::apply(const Position &pos) {
384 assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
385 assert(pos.pawn_count(strongerSide) == 0);
386 assert(pos.non_pawn_material(weakerSide) == KnightValueMidgame);
387 assert(pos.pawn_count(weakerSide) == 0);
388 assert(pos.knight_count(weakerSide) == 1);
390 Square defendingKSq = pos.king_square(weakerSide);
391 Square nSq = pos.knight_list(weakerSide, 0);
393 Value result = Value(10) + mate_table(defendingKSq) +
394 krkn_king_knight_distance_penalty(square_distance(defendingKSq, nSq));
396 return (strongerSide == pos.side_to_move())? result : -result;
400 /// KQ vs KR. This is almost identical to KX vs K: We give the attacking
401 /// king a bonus for having the kings close together, and for forcing the
402 /// defending king towards the edge. If we also take care to avoid null move
403 /// for the defending side in the search, this is usually sufficient to be
404 /// able to win KQ vs KR.
406 Value KQKREvaluationFunction::apply(const Position &pos) {
407 assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame);
408 assert(pos.pawn_count(strongerSide) == 0);
409 assert(pos.non_pawn_material(weakerSide) == RookValueMidgame);
410 assert(pos.pawn_count(weakerSide) == 0);
412 Square winnerKSq = pos.king_square(strongerSide);
413 Square loserKSq = pos.king_square(weakerSide);
415 Value result = QueenValueEndgame - RookValueEndgame +
416 mate_table(loserKSq) + distance_bonus(square_distance(winnerKSq, loserKSq));
418 return (strongerSide == pos.side_to_move())? result : -result;
422 /// KBPKScalingFunction scales endgames where the stronger side has king,
423 /// bishop and one or more pawns. It checks for draws with rook pawns and a
424 /// bishop of the wrong color. If such a draw is detected, ScaleFactor(0) is
425 /// returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling
426 /// will be used.
428 ScaleFactor KBPKScalingFunction::apply(const Position &pos) {
429 assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
430 assert(pos.bishop_count(strongerSide) == 1);
431 assert(pos.pawn_count(strongerSide) >= 1);
433 // No assertions about the material of weakerSide, because we want draws to
434 // be detected even when the weaker side has some pawns.
436 Bitboard pawns = pos.pawns(strongerSide);
437 File pawnFile = square_file(pos.pawn_list(strongerSide, 0));
439 if((pawnFile == FILE_A || pawnFile == FILE_H) &&
440 (pawns & ~file_bb(pawnFile)) == EmptyBoardBB) {
441 // All pawns are on a single rook file.
443 Square bishopSq = pos.bishop_list(strongerSide, 0);
444 Square queeningSq =
445 relative_square(strongerSide, make_square(pawnFile, RANK_8));
446 Square kingSq = pos.king_square(weakerSide);
448 if(square_color(queeningSq) != square_color(bishopSq) &&
449 file_distance(square_file(kingSq), pawnFile) <= 1) {
450 // The bishop has the wrong color, and the defending king is on the
451 // file of the pawn(s) or the neighboring file. Find the rank of the
452 // frontmost pawn:
454 Rank rank;
455 if(strongerSide == WHITE) {
456 for(rank = RANK_7; (rank_bb(rank) & pawns) == EmptyBoardBB; rank--);
457 assert(rank >= RANK_2 && rank <= RANK_7);
459 else {
460 for(rank = RANK_2; (rank_bb(rank) & pawns) == EmptyBoardBB; rank++);
461 rank = Rank(rank^7); // HACK
462 assert(rank >= RANK_2 && rank <= RANK_7);
464 // If the defending king has distance 1 to the promotion square or
465 // is placed somewhere in front of the pawn, it's a draw.
466 if(square_distance(kingSq, queeningSq) <= 1 ||
467 pawn_rank(strongerSide, kingSq) >= rank)
468 return ScaleFactor(0);
471 return SCALE_FACTOR_NONE;
475 /// KQKRPScalingFunction scales endgames where the stronger side has only
476 /// king and queen, while the weaker side has at least a rook and a pawn.
477 /// It tests for fortress draws with a rook on the third rank defended by
478 /// a pawn.
480 ScaleFactor KQKRPScalingFunction::apply(const Position &pos) {
481 assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame);
482 assert(pos.queen_count(strongerSide) == 1);
483 assert(pos.pawn_count(strongerSide) == 0);
484 assert(pos.rook_count(weakerSide) == 1);
485 assert(pos.pawn_count(weakerSide) >= 1);
487 Square kingSq = pos.king_square(weakerSide);
488 if(pawn_rank(weakerSide, kingSq) <= RANK_2 &&
489 pawn_rank(weakerSide, pos.king_square(strongerSide)) >= RANK_4 &&
490 (pos.rooks(weakerSide) & relative_rank_bb(weakerSide, RANK_3)) &&
491 (pos.pawns(weakerSide) & relative_rank_bb(weakerSide, RANK_2)) &&
492 (pos.king_attacks(kingSq) & pos.pawns(weakerSide))) {
493 Square rsq = pos.rook_list(weakerSide, 0);
494 if(pos.pawn_attacks(strongerSide, rsq) & pos.pawns(weakerSide))
495 return ScaleFactor(0);
497 return SCALE_FACTOR_NONE;
501 /// KRPKRScalingFunction scales KRP vs KR endgames. This function knows a
502 /// handful of the most important classes of drawn positions, but is far
503 /// from perfect. It would probably be a good idea to add more knowledge
504 /// in the future.
506 /// It would also be nice to rewrite the actual code for this function,
507 /// which is mostly copied from Glaurung 1.x, and not very pretty.
509 ScaleFactor KRPKRScalingFunction::apply(const Position &pos) {
510 assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
511 assert(pos.pawn_count(strongerSide) == 1);
512 assert(pos.non_pawn_material(weakerSide) == RookValueMidgame);
513 assert(pos.pawn_count(weakerSide) == 0);
515 Square wksq = pos.king_square(strongerSide);
516 Square wrsq = pos.rook_list(strongerSide, 0);
517 Square wpsq = pos.pawn_list(strongerSide, 0);
518 Square bksq = pos.king_square(weakerSide);
519 Square brsq = pos.rook_list(weakerSide, 0);
521 // Orient the board in such a way that the stronger side is white, and the
522 // pawn is on the left half of the board:
523 if(strongerSide == BLACK) {
524 wksq = flip_square(wksq);
525 wrsq = flip_square(wrsq);
526 wpsq = flip_square(wpsq);
527 bksq = flip_square(bksq);
528 brsq = flip_square(brsq);
530 if(square_file(wpsq) > FILE_D) {
531 wksq = flop_square(wksq);
532 wrsq = flop_square(wrsq);
533 wpsq = flop_square(wpsq);
534 bksq = flop_square(bksq);
535 brsq = flop_square(brsq);
538 File f = square_file(wpsq);
539 Rank r = square_rank(wpsq);
540 Square queeningSq = make_square(f, RANK_8);
541 int tempo = (pos.side_to_move() == strongerSide);
543 // If the pawn is not too far advanced and the defending king defends the
544 // queening square, use the third-rank defence:
545 if(r <= RANK_5 && square_distance(bksq, queeningSq) <= 1 && wksq <= SQ_H5 &&
546 (square_rank(brsq) == RANK_6 || (r <= RANK_3 &&
547 square_rank(wrsq) != RANK_6)))
548 return ScaleFactor(0);
550 // The defending side saves a draw by checking from behind in case the pawn
551 // has advanced to the 6th rank with the king behind.
552 if(r == RANK_6 && square_distance(bksq, queeningSq) <= 1 &&
553 square_rank(wksq) + tempo <= RANK_6 &&
554 (square_rank(brsq) == RANK_1 ||
555 (!tempo && abs(square_file(brsq) - f) >= 3)))
556 return ScaleFactor(0);
558 if(r >= RANK_6 && bksq == queeningSq && square_rank(brsq) == RANK_1 &&
559 (!tempo || square_distance(wksq, wpsq) >= 2))
560 return ScaleFactor(0);
562 // White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7
563 // and the black rook is behind the pawn.
564 if(wpsq == SQ_A7 && wrsq == SQ_A8 && (bksq == SQ_H7 || bksq == SQ_G7) &&
565 square_file(brsq) == FILE_A &&
566 (square_rank(brsq) <= RANK_3 || square_file(wksq) >= FILE_D ||
567 square_rank(wksq) <= RANK_5))
568 return ScaleFactor(0);
570 // If the defending king blocks the pawn and the attacking king is too far
571 // away, it's a draw.
572 if(r <= RANK_5 && bksq == wpsq + DELTA_N &&
573 square_distance(wksq, wpsq) - tempo >= 2 &&
574 square_distance(wksq, brsq) - tempo >= 2)
575 return ScaleFactor(0);
577 // Pawn on the 7th rank supported by the rook from behind usually wins if the
578 // attacking king is closer to the queening square than the defending king,
579 // and the defending king cannot gain tempi by threatening the attacking
580 // rook.
581 if(r == RANK_7 && f != FILE_A && square_file(wrsq) == f
582 && wrsq != queeningSq
583 && (square_distance(wksq, queeningSq) <
584 square_distance(bksq, queeningSq) - 2 + tempo)
585 && (square_distance(wksq, queeningSq) <
586 square_distance(bksq, wrsq) + tempo))
587 return ScaleFactor(SCALE_FACTOR_MAX
588 - 2 * square_distance(wksq, queeningSq));
590 // Similar to the above, but with the pawn further back:
591 if(f != FILE_A && square_file(wrsq) == f && wrsq < wpsq
592 && (square_distance(wksq, queeningSq) <
593 square_distance(bksq, queeningSq) - 2 + tempo)
594 && (square_distance(wksq, wpsq + DELTA_N) <
595 square_distance(bksq, wpsq + DELTA_N) - 2 + tempo)
596 && (square_distance(bksq, wrsq) + tempo >= 3
597 || (square_distance(wksq, queeningSq) <
598 square_distance(bksq, wrsq) + tempo
599 && (square_distance(wksq, wpsq + DELTA_N) <
600 square_distance(bksq, wrsq) + tempo))))
601 return
602 ScaleFactor(SCALE_FACTOR_MAX
603 - (8 * square_distance(wpsq, queeningSq) +
604 2 * square_distance(wksq, queeningSq)));
606 return SCALE_FACTOR_NONE;
610 /// KRPPKRPScalingFunction scales KRPP vs KRP endgames. There is only a
611 /// single pattern: If the stronger side has no pawns and the defending king
612 /// is actively placed, the position is drawish.
614 ScaleFactor KRPPKRPScalingFunction::apply(const Position &pos) {
615 assert(pos.non_pawn_material(strongerSide) == RookValueMidgame);
616 assert(pos.pawn_count(strongerSide) == 2);
617 assert(pos.non_pawn_material(weakerSide) == RookValueMidgame);
618 assert(pos.pawn_count(weakerSide) == 1);
620 Square wpsq1 = pos.pawn_list(strongerSide, 0);
621 Square wpsq2 = pos.pawn_list(strongerSide, 1);
622 Square bksq = pos.king_square(weakerSide);
624 // Does the stronger side have a passed pawn?
625 if(pos.pawn_is_passed(strongerSide, wpsq1) ||
626 pos.pawn_is_passed(strongerSide, wpsq2))
627 return SCALE_FACTOR_NONE;
629 Rank r = Max(pawn_rank(strongerSide, wpsq1), pawn_rank(strongerSide, wpsq2));
631 if(file_distance(bksq, wpsq1) <= 1 && file_distance(bksq, wpsq2) <= 1
632 && pawn_rank(strongerSide, bksq) > r) {
633 switch(r) {
635 case RANK_2: return ScaleFactor(10);
636 case RANK_3: return ScaleFactor(10);
637 case RANK_4: return ScaleFactor(15);
638 case RANK_5: return ScaleFactor(20);
639 case RANK_6: return ScaleFactor(40);
640 default: assert(false);
644 return SCALE_FACTOR_NONE;
648 /// KPsKScalingFunction scales endgames with king and two or more pawns
649 /// against king. There is just a single rule here: If all pawns are on
650 /// the same rook file and are blocked by the defending king, it's a draw.
652 ScaleFactor KPsKScalingFunction::apply(const Position &pos) {
653 assert(pos.non_pawn_material(strongerSide) == Value(0));
654 assert(pos.pawn_count(strongerSide) >= 2);
655 assert(pos.non_pawn_material(weakerSide) == Value(0));
656 assert(pos.pawn_count(weakerSide) == 0);
658 Bitboard pawns = pos.pawns(strongerSide);
660 // Are all pawns on the 'a' file?
661 if((pawns & ~FileABB) == EmptyBoardBB) {
662 // Does the defending king block the pawns?
663 Square ksq = pos.king_square(weakerSide);
664 if(square_distance(ksq, relative_square(strongerSide, SQ_A8)) <= 1)
665 return ScaleFactor(0);
666 else if(square_file(ksq) == FILE_A &&
667 (in_front_bb(strongerSide, ksq) & pawns) == EmptyBoardBB)
668 return ScaleFactor(0);
669 else
670 return SCALE_FACTOR_NONE;
672 // Are all pawns on the 'h' file?
673 else if((pawns & ~FileHBB) == EmptyBoardBB) {
674 // Does the defending king block the pawns?
675 Square ksq = pos.king_square(weakerSide);
676 if(square_distance(ksq, relative_square(strongerSide, SQ_H8)) <= 1)
677 return ScaleFactor(0);
678 else if(square_file(ksq) == FILE_H &&
679 (in_front_bb(strongerSide, ksq) & pawns) == EmptyBoardBB)
680 return ScaleFactor(0);
681 else
682 return SCALE_FACTOR_NONE;
684 else
685 return SCALE_FACTOR_NONE;
689 /// KBPKBScalingFunction scales KBP vs KB endgames. There are two rules:
690 /// If the defending king is somewhere along the path of the pawn, and the
691 /// square of the king is not of the same color as the stronger side's bishop,
692 /// it's a draw. If the two bishops have opposite color, it's almost always
693 /// a draw.
695 ScaleFactor KBPKBScalingFunction::apply(const Position &pos) {
696 assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
697 assert(pos.bishop_count(strongerSide) == 1);
698 assert(pos.pawn_count(strongerSide) == 1);
699 assert(pos.non_pawn_material(weakerSide) == BishopValueMidgame);
700 assert(pos.bishop_count(weakerSide) == 1);
701 assert(pos.pawn_count(weakerSide) == 0);
703 Square pawnSq = pos.pawn_list(strongerSide, 0);
704 Square strongerBishopSq = pos.bishop_list(strongerSide, 0);
705 Square weakerBishopSq = pos.bishop_list(weakerSide, 0);
706 Square weakerKingSq = pos.king_square(weakerSide);
708 // Case 1: Defending king blocks the pawn, and cannot be driven away.
709 if(square_file(weakerKingSq) == square_file(pawnSq)
710 && pawn_rank(strongerSide, pawnSq) < pawn_rank(strongerSide, weakerKingSq)
711 && (square_color(weakerKingSq) != square_color(strongerBishopSq)
712 || pawn_rank(strongerSide, weakerKingSq) <= RANK_6))
713 return ScaleFactor(0);
715 // Case 2: Opposite colored bishops.
716 if(square_color(strongerBishopSq) != square_color(weakerBishopSq)) {
718 // We assume that the position is drawn in the following three situations:
720 // a. The pawn is on rank 5 or further back.
721 // b. The defending king is somewhere in the pawn's path.
722 // c. The defending bishop attacks some square along the pawn's path,
723 // and is at least three squares away from the pawn.
725 // These rules are probably not perfect, but in practice they work
726 // reasonably well.
728 if(pawn_rank(strongerSide, pawnSq) <= RANK_5)
729 return ScaleFactor(0);
730 else {
731 Bitboard ray =
732 ray_bb(pawnSq, (strongerSide == WHITE)? SIGNED_DIR_N : SIGNED_DIR_S);
733 if(ray & pos.kings(weakerSide))
734 return ScaleFactor(0);
735 if((pos.bishop_attacks(weakerBishopSq) & ray)
736 && square_distance(weakerBishopSq, pawnSq) >= 3)
737 return ScaleFactor(0);
740 return SCALE_FACTOR_NONE;
744 /// KBPKNScalingFunction scales KBP vs KN endgames. There is a single rule:
745 /// If the defending king is somewhere along the path of the pawn, and the
746 /// square of the king is not of the same color as the stronger side's bishop,
747 /// it's a draw.
749 ScaleFactor KBPKNScalingFunction::apply(const Position &pos) {
750 assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame);
751 assert(pos.bishop_count(strongerSide) == 1);
752 assert(pos.pawn_count(strongerSide) == 1);
753 assert(pos.non_pawn_material(weakerSide) == KnightValueMidgame);
754 assert(pos.knight_count(weakerSide) == 1);
755 assert(pos.pawn_count(weakerSide) == 0);
757 Square pawnSq = pos.pawn_list(strongerSide, 0);
758 Square strongerBishopSq = pos.bishop_list(strongerSide, 0);
759 Square weakerKingSq = pos.king_square(weakerSide);
761 if(square_file(weakerKingSq) == square_file(pawnSq)
762 && pawn_rank(strongerSide, pawnSq) < pawn_rank(strongerSide, weakerKingSq)
763 && (square_color(weakerKingSq) != square_color(strongerBishopSq)
764 || pawn_rank(strongerSide, weakerKingSq) <= RANK_6))
765 return ScaleFactor(0);
767 return SCALE_FACTOR_NONE;
771 /// KNPKScalingFunction scales KNP vs K endgames. There is a single rule:
772 /// If the pawn is a rook pawn on the 7th rank and the defending king prevents
773 /// the pawn from advancing, the position is drawn.
775 ScaleFactor KNPKScalingFunction::apply(const Position &pos) {
776 assert(pos.non_pawn_material(strongerSide) == KnightValueMidgame);
777 assert(pos.knight_count(strongerSide) == 1);
778 assert(pos.pawn_count(strongerSide) == 1);
779 assert(pos.non_pawn_material(weakerSide) == Value(0));
780 assert(pos.pawn_count(weakerSide) == 0);
782 Square pawnSq = pos.pawn_list(strongerSide, 0);
783 Square weakerKingSq = pos.king_square(weakerSide);
785 if(pawnSq == relative_square(strongerSide, SQ_A7) &&
786 square_distance(weakerKingSq, relative_square(strongerSide, SQ_A8)) <= 1)
787 return ScaleFactor(0);
789 if(pawnSq == relative_square(strongerSide, SQ_H7) &&
790 square_distance(weakerKingSq, relative_square(strongerSide, SQ_H8)) <= 1)
791 return ScaleFactor(0);
793 return SCALE_FACTOR_NONE;
797 /// KPKPScalingFunction scales KP vs KP endgames. This is done by removing
798 /// the weakest side's pawn and probing the KP vs K bitbase: If the weakest
799 /// side has a draw without the pawn, she probably has at least a draw with
800 /// the pawn as well. The exception is when the stronger side's pawn is far
801 /// advanced and not on a rook file; in this case it is often possible to win
802 /// (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1).
804 ScaleFactor KPKPScalingFunction::apply(const Position &pos) {
805 assert(pos.non_pawn_material(strongerSide) == Value(0));
806 assert(pos.non_pawn_material(weakerSide) == Value(0));
807 assert(pos.pawn_count(WHITE) == 1);
808 assert(pos.pawn_count(BLACK) == 1);
810 Square wksq, bksq, wpsq;
811 Color stm;
813 if(strongerSide == WHITE) {
814 wksq = pos.king_square(WHITE);
815 bksq = pos.king_square(BLACK);
816 wpsq = pos.pawn_list(WHITE, 0);
817 stm = pos.side_to_move();
819 else {
820 wksq = flip_square(pos.king_square(BLACK));
821 bksq = flip_square(pos.king_square(WHITE));
822 wpsq = flip_square(pos.pawn_list(BLACK, 0));
823 stm = opposite_color(pos.side_to_move());
826 if(square_file(wpsq) >= FILE_E) {
827 wksq = flop_square(wksq);
828 bksq = flop_square(bksq);
829 wpsq = flop_square(wpsq);
832 // If the pawn has advanced to the fifth rank or further, and is not a
833 // rook pawn, it's too dangerous to assume that it's at least a draw.
834 if(square_rank(wpsq) >= RANK_5 && square_file(wpsq) != FILE_A)
835 return SCALE_FACTOR_NONE;
837 // Probe the KPK bitbase with the weakest side's pawn removed. If it's a
838 // draw, it's probably at least a draw even with the pawn.
839 if(probe_kpk(wksq, wpsq, bksq, stm))
840 return SCALE_FACTOR_NONE;
841 else
842 return ScaleFactor(0);
846 /// init_bitbases() is called during program initialization, and simply loads
847 /// bitbases from disk into memory. At the moment, there is only the bitbase
848 /// for KP vs K, but we may decide to add other bitbases later.
850 void init_bitbases() {
851 generate_kpk_bitbase(KPKBitbase);
855 namespace {
857 // Probe the KP vs K bitbase:
859 int probe_kpk(Square wksq, Square wpsq, Square bksq, Color stm) {
860 int wp = int(square_file(wpsq)) + (int(square_rank(wpsq)) - 1) * 4;
861 int index = int(stm) + 2*int(bksq) + 128*int(wksq) + 8192*wp;
863 assert(index >= 0 && index < 24576*8);
864 return KPKBitbase[index/8] & (1 << (index&7));