X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fendgame.cpp;h=65b858613dd8f74ae6ad73674187473e059afe25;hp=ae29a71aba07d0faa77847e7045a31f1ef92b58c;hb=aecdbfc4a000c72fcc2642f54ce83967913a16ba;hpb=a7cdf7299a771949332f8c7ef77ae8fd125d0f08 diff --git a/src/endgame.cpp b/src/endgame.cpp index ae29a71a..65b85861 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -1,7 +1,7 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2012 Marco Costalba, Joona Kiiski, Tord Romstad + Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -100,6 +100,7 @@ Endgames::Endgames() { add("KBBKN"); add("KNPK"); + add("KNPKB"); add("KRPKR"); add("KBPKB"); add("KBPKN"); @@ -129,28 +130,25 @@ template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); - assert(pos.piece_count(weakerSide, PAWN) == VALUE_ZERO); + assert(!pos.count(weakerSide)); + assert(!pos.checkers()); // Eval is never called when in check // Stalemate detection with lone king - if ( pos.side_to_move() == weakerSide - && !pos.checkers() - && !MoveList(pos).size()) { - return VALUE_DRAW; - } + if (pos.side_to_move() == weakerSide && !MoveList(pos).size()) + return VALUE_DRAW; Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); Value result = pos.non_pawn_material(strongerSide) - + pos.piece_count(strongerSide, PAWN) * PawnValueEg + + pos.count(strongerSide) * PawnValueEg + MateTable[loserKSq] + DistanceBonus[square_distance(winnerKSq, loserKSq)]; - if ( pos.piece_count(strongerSide, QUEEN) - || pos.piece_count(strongerSide, ROOK) - || pos.bishop_pair(strongerSide)) { - result += VALUE_KNOWN_WIN; - } + if ( pos.count(strongerSide) + || pos.count(strongerSide) + || pos.bishop_pair(strongerSide)) + result += VALUE_KNOWN_WIN; return strongerSide == pos.side_to_move() ? result : -result; } @@ -161,16 +159,16 @@ Value Endgame::operator()(const Position& pos) const { template<> Value Endgame::operator()(const Position& pos) const { - assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); - assert(pos.piece_count(weakerSide, PAWN) == VALUE_ZERO); assert(pos.non_pawn_material(strongerSide) == KnightValueMg + BishopValueMg); - assert(pos.piece_count(strongerSide, BISHOP) == 1); - assert(pos.piece_count(strongerSide, KNIGHT) == 1); - assert(pos.piece_count(strongerSide, PAWN) == 0); + assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); + assert(pos.count(strongerSide) == 1); + assert(pos.count(strongerSide) == 1); + assert(pos.count< PAWN>(strongerSide) == 0); + assert(pos.count< PAWN>(weakerSide ) == 0); Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); - Square bishopSq = pos.piece_list(strongerSide, BISHOP)[0]; + Square bishopSq = pos.list(strongerSide)[0]; // kbnk_mate_table() tries to drive toward corners A1 or H8, // if we have a bishop that cannot reach the above squares we @@ -195,25 +193,25 @@ Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO); assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); - assert(pos.piece_count(strongerSide, PAWN) == 1); - assert(pos.piece_count(weakerSide, PAWN) == 0); + assert(pos.count(strongerSide) == 1); + assert(pos.count(weakerSide ) == 0); Square wksq, bksq, wpsq; - Color stm; + Color us; if (strongerSide == WHITE) { wksq = pos.king_square(WHITE); bksq = pos.king_square(BLACK); - wpsq = pos.piece_list(WHITE, PAWN)[0]; - stm = pos.side_to_move(); + wpsq = pos.list(WHITE)[0]; + us = pos.side_to_move(); } else { wksq = ~pos.king_square(BLACK); bksq = ~pos.king_square(WHITE); - wpsq = ~pos.piece_list(BLACK, PAWN)[0]; - stm = ~pos.side_to_move(); + wpsq = ~pos.list(BLACK)[0]; + us = ~pos.side_to_move(); } if (file_of(wpsq) >= FILE_E) @@ -223,7 +221,7 @@ Value Endgame::operator()(const Position& pos) const { wpsq = mirror(wpsq); } - if (!Bitbases::probe_kpk(wksq, wpsq, bksq, stm)) + if (!Bitbases::probe_kpk(wksq, wpsq, bksq, us)) return VALUE_DRAW; Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(wpsq)); @@ -240,17 +238,17 @@ template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.non_pawn_material(weakerSide) == 0); - assert(pos.piece_count(weakerSide, PAWN) == 1); + assert(pos.count(strongerSide) == 0); + assert(pos.count(weakerSide ) == 1); Square wksq, wrsq, bksq, bpsq; int tempo = (pos.side_to_move() == strongerSide); wksq = pos.king_square(strongerSide); - wrsq = pos.piece_list(strongerSide, ROOK)[0]; bksq = pos.king_square(weakerSide); - bpsq = pos.piece_list(weakerSide, PAWN)[0]; + wrsq = pos.list(strongerSide)[0]; + bpsq = pos.list(weakerSide)[0]; if (strongerSide == BLACK) { @@ -297,10 +295,10 @@ template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 0); - assert(pos.non_pawn_material(weakerSide) == BishopValueMg); - assert(pos.piece_count(weakerSide, PAWN) == 0); - assert(pos.piece_count(weakerSide, BISHOP) == 1); + assert(pos.non_pawn_material(weakerSide ) == BishopValueMg); + assert(pos.count(weakerSide ) == 1); + assert(pos.count< PAWN>(weakerSide ) == 0); + assert(pos.count< PAWN>(strongerSide) == 0); Value result = Value(MateTable[pos.king_square(weakerSide)]); return strongerSide == pos.side_to_move() ? result : -result; @@ -313,15 +311,15 @@ template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 0); - assert(pos.non_pawn_material(weakerSide) == KnightValueMg); - assert(pos.piece_count(weakerSide, PAWN) == 0); - assert(pos.piece_count(weakerSide, KNIGHT) == 1); + assert(pos.non_pawn_material(weakerSide ) == KnightValueMg); + assert(pos.count(weakerSide ) == 1); + assert(pos.count< PAWN>(weakerSide ) == 0); + assert(pos.count< PAWN>(strongerSide) == 0); const int penalty[8] = { 0, 10, 14, 20, 30, 42, 58, 80 }; Square bksq = pos.king_square(weakerSide); - Square bnsq = pos.piece_list(weakerSide, KNIGHT)[0]; + Square bnsq = pos.list(weakerSide)[0]; Value result = Value(MateTable[bksq] + penalty[square_distance(bksq, bnsq)]); return strongerSide == pos.side_to_move() ? result : -result; } @@ -334,13 +332,13 @@ template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == QueenValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 0); - assert(pos.non_pawn_material(weakerSide) == 0); - assert(pos.piece_count(weakerSide, PAWN) == 1); + assert(pos.non_pawn_material(weakerSide ) == VALUE_ZERO); + assert(pos.count(strongerSide) == 0); + assert(pos.count(weakerSide ) == 1); Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); - Square pawnSq = pos.piece_list(weakerSide, PAWN)[0]; + Square pawnSq = pos.list(weakerSide)[0]; Value result = QueenValueEg - PawnValueEg @@ -367,9 +365,9 @@ template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == QueenValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 0); - assert(pos.non_pawn_material(weakerSide) == RookValueMg); - assert(pos.piece_count(weakerSide, PAWN) == 0); + assert(pos.non_pawn_material(weakerSide ) == RookValueMg); + assert(pos.count(strongerSide) == 0); + assert(pos.count(weakerSide ) == 0); Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); @@ -385,16 +383,16 @@ Value Endgame::operator()(const Position& pos) const { template<> Value Endgame::operator()(const Position& pos) const { - assert(pos.piece_count(strongerSide, BISHOP) == 2); - assert(pos.non_pawn_material(strongerSide) == 2*BishopValueMg); - assert(pos.piece_count(weakerSide, KNIGHT) == 1); - assert(pos.non_pawn_material(weakerSide) == KnightValueMg); + assert(pos.non_pawn_material(strongerSide) == 2 * BishopValueMg); + assert(pos.non_pawn_material(weakerSide ) == KnightValueMg); + assert(pos.count(strongerSide) == 2); + assert(pos.count(weakerSide ) == 1); assert(!pos.pieces(PAWN)); Value result = BishopValueEg; Square wksq = pos.king_square(strongerSide); Square bksq = pos.king_square(weakerSide); - Square nsq = pos.piece_list(weakerSide, KNIGHT)[0]; + Square nsq = pos.list(weakerSide)[0]; // Bonus for attacking king close to defending king result += Value(DistanceBonus[square_distance(wksq, bksq)]); @@ -409,17 +407,10 @@ Value Endgame::operator()(const Position& pos) const { } -/// K and two minors vs K and one or two minors or K and two knights against -/// king alone are always draw. -template<> -Value Endgame::operator()(const Position&) const { - return VALUE_DRAW; -} +/// Some cases of trivial draws +template<> Value Endgame::operator()(const Position&) const { return VALUE_DRAW; } +template<> Value Endgame::operator()(const Position&) const { return VALUE_DRAW; } -template<> -Value Endgame::operator()(const Position&) const { - return VALUE_DRAW; -} /// K, bishop and one or more pawns vs K. It checks for draws with rook pawns and /// a bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_DRAW @@ -429,20 +420,20 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMg); - assert(pos.piece_count(strongerSide, BISHOP) == 1); - assert(pos.piece_count(strongerSide, PAWN) >= 1); + assert(pos.count(strongerSide) == 1); + assert(pos.count< PAWN>(strongerSide) >= 1); // No assertions about the material of weakerSide, because we want draws to // be detected even when the weaker side has some pawns. Bitboard pawns = pos.pieces(strongerSide, PAWN); - File pawnFile = file_of(pos.piece_list(strongerSide, PAWN)[0]); + File pawnFile = file_of(pos.list(strongerSide)[0]); // All pawns are on a single rook file ? if ( (pawnFile == FILE_A || pawnFile == FILE_H) && !(pawns & ~file_bb(pawnFile))) { - Square bishopSq = pos.piece_list(strongerSide, BISHOP)[0]; + Square bishopSq = pos.list(strongerSide)[0]; Square queeningSq = relative_square(strongerSide, pawnFile | RANK_8); Square kingSq = pos.king_square(weakerSide); @@ -452,18 +443,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // The bishop has the wrong color, and the defending king is on the // file of the pawn(s) or the adjacent file. Find the rank of the // frontmost pawn. - Rank rank; - if (strongerSide == WHITE) - { - for (rank = RANK_7; !(rank_bb(rank) & pawns); rank--) {} - assert(rank >= RANK_2 && rank <= RANK_7); - } - else - { - for (rank = RANK_2; !(rank_bb(rank) & pawns); rank++) {} - rank = Rank(rank ^ 7); // HACK to get the relative rank - assert(rank >= RANK_2 && rank <= RANK_7); - } + Rank rank = relative_rank(strongerSide, lsb(weakerSide, pawns)); // If the defending king has distance 1 to the promotion square or // is placed somewhere in front of the pawn, it's a draw. if ( square_distance(kingSq, queeningSq) <= 1 @@ -476,15 +456,14 @@ ScaleFactor Endgame::operator()(const Position& pos) const { if ( (pawnFile == FILE_B || pawnFile == FILE_G) && !(pos.pieces(PAWN) & ~file_bb(pawnFile)) && pos.non_pawn_material(weakerSide) == 0 - && pos.piece_count(weakerSide, PAWN) >= 1) + && pos.count(weakerSide) >= 1) { - // Get weaker pawn closest to opponent's queening square - Bitboard wkPawns = pos.pieces(weakerSide, PAWN); - Square weakerPawnSq = strongerSide == WHITE ? msb(wkPawns) : lsb(wkPawns); + // Get weakerSide pawn that is closest to home rank + Square weakerPawnSq = lsb(weakerSide, pos.pieces(weakerSide, PAWN)); Square strongerKingSq = pos.king_square(strongerSide); Square weakerKingSq = pos.king_square(weakerSide); - Square bishopSq = pos.piece_list(strongerSide, BISHOP)[0]; + Square bishopSq = pos.list(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. @@ -504,19 +483,19 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == QueenValueMg); - assert(pos.piece_count(strongerSide, QUEEN) == 1); - assert(pos.piece_count(strongerSide, PAWN) == 0); - assert(pos.piece_count(weakerSide, ROOK) == 1); - assert(pos.piece_count(weakerSide, PAWN) >= 1); + assert(pos.count(strongerSide) == 1); + assert(pos.count< PAWN>(strongerSide) == 0); + assert(pos.count< ROOK>(weakerSide ) == 1); + assert(pos.count< PAWN>(weakerSide ) >= 1); Square kingSq = pos.king_square(weakerSide); - if ( relative_rank(weakerSide, kingSq) <= RANK_2 - && relative_rank(weakerSide, pos.king_square(strongerSide)) >= RANK_4 + if ( relative_rank(weakerSide, kingSq) <= RANK_2 + && relative_rank(weakerSide, pos.king_square(strongerSide)) >= RANK_4 && (pos.pieces(weakerSide, ROOK) & rank_bb(relative_rank(weakerSide, RANK_3))) && (pos.pieces(weakerSide, PAWN) & rank_bb(relative_rank(weakerSide, RANK_2))) && (pos.attacks_from(kingSq) & pos.pieces(weakerSide, PAWN))) { - Square rsq = pos.piece_list(weakerSide, ROOK)[0]; + Square rsq = pos.list(weakerSide)[0]; if (pos.attacks_from(rsq, strongerSide) & pos.pieces(weakerSide, PAWN)) return SCALE_FACTOR_DRAW; } @@ -534,15 +513,15 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 1); - assert(pos.non_pawn_material(weakerSide) == RookValueMg); - assert(pos.piece_count(weakerSide, PAWN) == 0); + assert(pos.non_pawn_material(weakerSide) == RookValueMg); + assert(pos.count(strongerSide) == 1); + assert(pos.count(weakerSide ) == 0); Square wksq = pos.king_square(strongerSide); - Square wrsq = pos.piece_list(strongerSide, ROOK)[0]; - Square wpsq = pos.piece_list(strongerSide, PAWN)[0]; Square bksq = pos.king_square(weakerSide); - Square brsq = pos.piece_list(weakerSide, ROOK)[0]; + Square wrsq = pos.list(strongerSide)[0]; + Square wpsq = pos.list(strongerSide)[0]; + Square brsq = pos.list(weakerSide)[0]; // Orient the board in such a way that the stronger side is white, and the // pawn is on the left half of the board. @@ -652,12 +631,12 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); - assert(pos.piece_count(strongerSide, PAWN) == 2); - assert(pos.non_pawn_material(weakerSide) == RookValueMg); - assert(pos.piece_count(weakerSide, PAWN) == 1); + assert(pos.non_pawn_material(weakerSide) == RookValueMg); + assert(pos.count(strongerSide) == 2); + assert(pos.count(weakerSide ) == 1); - Square wpsq1 = pos.piece_list(strongerSide, PAWN)[0]; - Square wpsq2 = pos.piece_list(strongerSide, PAWN)[1]; + Square wpsq1 = pos.list(strongerSide)[0]; + Square wpsq2 = pos.list(strongerSide)[1]; Square bksq = pos.king_square(weakerSide); // Does the stronger side have a passed pawn? @@ -690,9 +669,9 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO); - assert(pos.piece_count(strongerSide, PAWN) >= 2); - assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); - assert(pos.piece_count(weakerSide, PAWN) == 0); + assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); + assert(pos.count(strongerSide) >= 2); + assert(pos.count(weakerSide ) == 0); Square ksq = pos.king_square(weakerSide); Bitboard pawns = pos.pieces(strongerSide, PAWN); @@ -703,7 +682,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // Does the defending king block the pawns? if ( square_distance(ksq, relative_square(strongerSide, SQ_A8)) <= 1 || ( file_of(ksq) == FILE_A - && !(in_front_bb(strongerSide, ksq) & pawns))) + && !(in_front_bb(strongerSide, rank_of(ksq)) & pawns))) return SCALE_FACTOR_DRAW; } // Are all pawns on the 'h' file? @@ -712,7 +691,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // Does the defending king block the pawns? if ( square_distance(ksq, relative_square(strongerSide, SQ_H8)) <= 1 || ( file_of(ksq) == FILE_H - && !(in_front_bb(strongerSide, ksq) & pawns))) + && !(in_front_bb(strongerSide, rank_of(ksq)) & pawns))) return SCALE_FACTOR_DRAW; } return SCALE_FACTOR_NONE; @@ -727,15 +706,15 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMg); - assert(pos.piece_count(strongerSide, BISHOP) == 1); - assert(pos.piece_count(strongerSide, PAWN) == 1); - assert(pos.non_pawn_material(weakerSide) == BishopValueMg); - assert(pos.piece_count(weakerSide, BISHOP) == 1); - assert(pos.piece_count(weakerSide, PAWN) == 0); - - Square pawnSq = pos.piece_list(strongerSide, PAWN)[0]; - Square strongerBishopSq = pos.piece_list(strongerSide, BISHOP)[0]; - Square weakerBishopSq = pos.piece_list(weakerSide, BISHOP)[0]; + assert(pos.non_pawn_material(weakerSide ) == BishopValueMg); + assert(pos.count(strongerSide) == 1); + assert(pos.count(weakerSide ) == 1); + assert(pos.count< PAWN>(strongerSide) == 1); + assert(pos.count< PAWN>(weakerSide ) == 0); + + Square pawnSq = pos.list(strongerSide)[0]; + Square strongerBishopSq = pos.list(strongerSide)[0]; + Square weakerBishopSq = pos.list(weakerSide)[0]; Square weakerKingSq = pos.king_square(weakerSide); // Case 1: Defending king blocks the pawn, and cannot be driven away @@ -782,21 +761,21 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMg); - assert(pos.piece_count(strongerSide, BISHOP) == 1); - assert(pos.piece_count(strongerSide, PAWN) == 2); - assert(pos.non_pawn_material(weakerSide) == BishopValueMg); - assert(pos.piece_count(weakerSide, BISHOP) == 1); - assert(pos.piece_count(weakerSide, PAWN) == 0); + assert(pos.non_pawn_material(weakerSide ) == BishopValueMg); + assert(pos.count(strongerSide) == 1); + assert(pos.count(weakerSide ) == 1); + assert(pos.count< PAWN>(strongerSide) == 2); + assert(pos.count< PAWN>(weakerSide ) == 0); - Square wbsq = pos.piece_list(strongerSide, BISHOP)[0]; - Square bbsq = pos.piece_list(weakerSide, BISHOP)[0]; + Square wbsq = pos.list(strongerSide)[0]; + Square bbsq = pos.list(weakerSide)[0]; if (!opposite_colors(wbsq, bbsq)) 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]; + Square psq1 = pos.list(strongerSide)[0]; + Square psq2 = pos.list(strongerSide)[1]; Rank r1 = rank_of(psq1); Rank r2 = rank_of(psq2); Square blockSq1, blockSq2; @@ -857,14 +836,14 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMg); - assert(pos.piece_count(strongerSide, BISHOP) == 1); - assert(pos.piece_count(strongerSide, PAWN) == 1); - assert(pos.non_pawn_material(weakerSide) == KnightValueMg); - assert(pos.piece_count(weakerSide, KNIGHT) == 1); - assert(pos.piece_count(weakerSide, PAWN) == 0); - - Square pawnSq = pos.piece_list(strongerSide, PAWN)[0]; - Square strongerBishopSq = pos.piece_list(strongerSide, BISHOP)[0]; + assert(pos.non_pawn_material(weakerSide ) == KnightValueMg); + assert(pos.count(strongerSide) == 1); + assert(pos.count(weakerSide ) == 1); + assert(pos.count< PAWN>(strongerSide) == 1); + assert(pos.count< PAWN>(weakerSide ) == 0); + + Square pawnSq = pos.list(strongerSide)[0]; + Square strongerBishopSq = pos.list(strongerSide)[0]; Square weakerKingSq = pos.king_square(weakerSide); if ( file_of(weakerKingSq) == file_of(pawnSq) @@ -884,12 +863,12 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == KnightValueMg); - assert(pos.piece_count(strongerSide, KNIGHT) == 1); - assert(pos.piece_count(strongerSide, PAWN) == 1); - assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); - assert(pos.piece_count(weakerSide, PAWN) == 0); + assert(pos.non_pawn_material(weakerSide ) == VALUE_ZERO); + assert(pos.count(strongerSide) == 1); + assert(pos.count< PAWN>(strongerSide) == 1); + assert(pos.count< PAWN>(weakerSide ) == 0); - Square pawnSq = pos.piece_list(strongerSide, PAWN)[0]; + Square pawnSq = pos.list(strongerSide)[0]; Square weakerKingSq = pos.king_square(weakerSide); if ( pawnSq == relative_square(strongerSide, SQ_A7) @@ -904,6 +883,24 @@ ScaleFactor Endgame::operator()(const Position& pos) const { } +/// K, knight and a pawn vs K and bishop. If knight can block bishop from taking +/// pawn, it's a win. Otherwise, drawn. +template<> +ScaleFactor Endgame::operator()(const Position& pos) const { + + Square pawnSq = pos.list(strongerSide)[0]; + Square bishopSq = pos.list(weakerSide)[0]; + Square weakerKingSq = pos.king_square(weakerSide); + + // King needs to get close to promoting pawn to prevent knight from blocking. + // Rules for this are very tricky, so just approximate. + if (forward_bb(strongerSide, pawnSq) & pos.attacks_from(bishopSq)) + return ScaleFactor(square_distance(weakerKingSq, pawnSq)); + + return SCALE_FACTOR_NONE; +} + + /// K and a pawn vs K and a pawn. This is done by removing the weakest side's /// pawn and probing the KP vs K bitbase: If the weakest side has a draw without /// the pawn, she probably has at least a draw with the pawn as well. The exception @@ -913,21 +910,21 @@ template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO); - assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); - assert(pos.piece_count(WHITE, PAWN) == 1); - assert(pos.piece_count(BLACK, PAWN) == 1); + assert(pos.non_pawn_material(weakerSide ) == VALUE_ZERO); + assert(pos.count(WHITE) == 1); + assert(pos.count(BLACK) == 1); Square wksq = pos.king_square(strongerSide); Square bksq = pos.king_square(weakerSide); - Square wpsq = pos.piece_list(strongerSide, PAWN)[0]; - Color stm = pos.side_to_move(); + Square wpsq = pos.list(strongerSide)[0]; + Color us = pos.side_to_move(); if (strongerSide == BLACK) { wksq = ~wksq; bksq = ~bksq; wpsq = ~wpsq; - stm = ~stm; + us = ~us; } if (file_of(wpsq) >= FILE_E) @@ -945,5 +942,5 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw, // it's probably at least a draw even with the pawn. - return Bitbases::probe_kpk(wksq, wpsq, bksq, stm) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW; + return Bitbases::probe_kpk(wksq, wpsq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW; }