X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fendgame.cpp;h=52786cdbe3b58b6166192802f35ab2f3eef674a8;hp=dbf10582ac8964fdf3f047d6d93c54b202274c5d;hb=52f3e717fa93c8774f37c249b05aa857993ee8a2;hpb=b84af67f4c88f3e3f7b61bf2035475f79fb3e62e diff --git a/src/endgame.cpp b/src/endgame.cpp index dbf10582..52786cdb 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 @@ -31,7 +31,7 @@ namespace { // Table used to drive the defending king towards the edge of the board // in KX vs K and KQ vs KR endgames. - const int MateTable[64] = { + const int MateTable[SQUARE_NB] = { 100, 90, 80, 70, 70, 80, 90, 100, 90, 70, 60, 50, 50, 60, 70, 90, 80, 60, 40, 30, 30, 40, 60, 80, @@ -44,7 +44,7 @@ namespace { // Table used to drive the defending king towards a corner square of the // right color in KBN vs K endgames. - const int KBNKMateTable[64] = { + const int KBNKMateTable[SQUARE_NB] = { 200, 190, 180, 170, 160, 150, 140, 130, 190, 180, 170, 160, 150, 140, 130, 140, 180, 170, 155, 140, 140, 125, 140, 150, @@ -95,10 +95,12 @@ Endgames::Endgames() { add("KRKP"); add("KRKB"); add("KRKN"); + add("KQKP"); add("KQKR"); add("KBBKN"); add("KNPK"); + add("KNPKB"); add("KRPKR"); add("KBPKB"); add("KBPKN"); @@ -132,7 +134,7 @@ Value Endgame::operator()(const Position& pos) const { // Stalemate detection with lone king if ( pos.side_to_move() == weakerSide - && !pos.in_check() + && !pos.checkers() && !MoveList(pos).size()) { return VALUE_DRAW; } @@ -169,12 +171,12 @@ Value Endgame::operator()(const Position& pos) const { Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); - Square bishopSquare = pos.piece_list(strongerSide, BISHOP)[0]; + Square bishopSq = pos.piece_list(strongerSide, BISHOP)[0]; // kbnk_mate_table() tries to drive toward corners A1 or H8, // if we have a bishop that cannot reach the above squares we // mirror the kings so to drive enemy toward corners A8 or H1. - if (opposite_colors(bishopSquare, SQ_A1)) + if (opposite_colors(bishopSq, SQ_A1)) { winnerKSq = mirror(winnerKSq); loserKSq = mirror(loserKSq); @@ -198,21 +200,21 @@ Value Endgame::operator()(const Position& pos) const { assert(pos.piece_count(weakerSide, PAWN) == 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(); + 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(); + us = ~pos.side_to_move(); } if (file_of(wpsq) >= FILE_E) @@ -222,7 +224,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)); @@ -326,6 +328,37 @@ Value Endgame::operator()(const Position& pos) const { } +/// KQ vs KP. In general, a win for the stronger side, however, there are a few +/// important exceptions. Pawn on 7th rank, A,C,F or H file, with king next can +/// be a draw, so we scale down to distance between kings only. +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); + + Square winnerKSq = pos.king_square(strongerSide); + Square loserKSq = pos.king_square(weakerSide); + Square pawnSq = pos.piece_list(weakerSide, PAWN)[0]; + + Value result = QueenValueEg + - PawnValueEg + + DistanceBonus[square_distance(winnerKSq, loserKSq)]; + + if ( square_distance(loserKSq, pawnSq) == 1 + && relative_rank(weakerSide, pawnSq) == RANK_7) + { + File f = file_of(pawnSq); + + if (f == FILE_A || f == FILE_C || f == FILE_F || f == FILE_H) + result = Value(DistanceBonus[square_distance(winnerKSq, loserKSq)]); + } + return strongerSide == pos.side_to_move() ? result : -result; +} + + /// KQ vs KR. This is almost identical to KX vs K: We give the attacking /// king a bonus for having the kings close together, and for forcing the /// defending king towards the edge. If we also take care to avoid null move @@ -439,6 +472,29 @@ ScaleFactor Endgame::operator()(const Position& pos) const { return SCALE_FACTOR_DRAW; } } + + // All pawns on same B or G file? Then potential draw + 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) + { + // Get weaker pawn closest to opponent's queening square + Bitboard wkPawns = pos.pieces(weakerSide, PAWN); + Square weakerPawnSq = strongerSide == WHITE ? msb(wkPawns) : lsb(wkPawns); + + Square strongerKingSq = pos.king_square(strongerSide); + Square weakerKingSq = pos.king_square(weakerSide); + Square bishopSq = pos.piece_list(strongerSide, BISHOP)[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; + } + return SCALE_FACTOR_NONE; } @@ -648,7 +704,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, ksq) & pawns))) return SCALE_FACTOR_DRAW; } // Are all pawns on the 'h' file? @@ -657,7 +713,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, ksq) & pawns))) return SCALE_FACTOR_DRAW; } return SCALE_FACTOR_NONE; @@ -849,6 +905,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.piece_list(strongerSide, PAWN)[0]; + Square bishopSq = pos.piece_list(weakerSide, BISHOP)[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 @@ -865,14 +939,14 @@ ScaleFactor Endgame::operator()(const Position& pos) const { 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(); + 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) @@ -890,5 +964,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; }