Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
+ Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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
#include <cassert>
#include "bitboard.h"
-#include "bitcount.h"
#include "endgame.h"
#include "movegen.h"
// Table used to drive the king towards the edge of the board
// in KX vs K and KQ vs KR endgames.
- const int PushToEdges[SQUARE_NB] = {
+ constexpr int PushToEdges[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,
70, 50, 30, 20, 20, 30, 50, 70,
80, 60, 40, 30, 30, 40, 60, 80,
90, 70, 60, 50, 50, 60, 70, 90,
- 100, 90, 80, 70, 70, 80, 90, 100,
+ 100, 90, 80, 70, 70, 80, 90, 100
};
// Table used to drive the king towards a corner square of the
// right color in KBN vs K endgames.
- const int PushToCorners[SQUARE_NB] = {
+ constexpr int PushToCorners[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,
};
// Tables used to drive a piece towards or away from another piece
- const int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 };
- const int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 };
+ constexpr int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 };
+ constexpr int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 };
// Pawn Rank based scaling factors used in KRPPKRP endgame
- const int KRPPKRPScaleFactors[RANK_NB] = {0, 9, 10, 14, 21, 44, 0, 0};
+ constexpr int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 };
#ifndef NDEBUG
bool verify_material(const Position& pos, Color c, Value npm, int pawnsCnt) {
return sq;
}
- // Get the material key of Position out of the given endgame key code
- // like "KBPKN". The trick here is to first forge an ad-hoc FEN string
- // and then let a Position object do the work for us.
- Key key(const string& code, Color c) {
-
- assert(code.length() > 0 && code.length() < 8);
- assert(code[0] == 'K');
-
- string sides[] = { code.substr(code.find('K', 1)), // Weak
- code.substr(0, code.find('K', 1)) }; // Strong
-
- std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower);
-
- string fen = sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/8/8/"
- + sides[1] + char(8 - sides[1].length() + '0') + " w - - 0 10";
-
- return Position(fen, false, nullptr).material_key();
- }
-
} // namespace
-/// Endgames members definitions
-
-Endgames::Endgames() {
-
- add<KPK>("KPK");
- add<KNNK>("KNNK");
- add<KBNK>("KBNK");
- add<KRKP>("KRKP");
- add<KRKB>("KRKB");
- add<KRKN>("KRKN");
- add<KQKP>("KQKP");
- add<KQKR>("KQKR");
-
- add<KNPK>("KNPK");
- add<KNPKB>("KNPKB");
- add<KRPKR>("KRPKR");
- add<KRPKB>("KRPKB");
- add<KBPKB>("KBPKB");
- add<KBPKN>("KBPKN");
- add<KBPPKB>("KBPPKB");
- add<KRPPKRP>("KRPPKRP");
-}
-
-
-template<EndgameType E, typename T>
-void Endgames::add(const string& code) {
- map<T>()[key(code, WHITE)] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(WHITE));
- map<T>()[key(code, BLACK)] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(BLACK));
-}
-
-
/// Mate with KX vs K. This function is used to evaluate positions with
/// king and plenty of material vs a lone king. It simply gives the
/// attacking side a bonus for driving the defending king towards the edge
if ( pos.count<QUEEN>(strongSide)
|| pos.count<ROOK>(strongSide)
||(pos.count<BISHOP>(strongSide) && pos.count<KNIGHT>(strongSide))
- ||(pos.count<BISHOP>(strongSide) > 1 && opposite_colors(pos.squares<BISHOP>(strongSide)[0],
- pos.squares<BISHOP>(strongSide)[1])))
- result += VALUE_KNOWN_WIN;
+ || ( (pos.pieces(strongSide, BISHOP) & ~DarkSquares)
+ && (pos.pieces(strongSide, BISHOP) & DarkSquares)))
+ result = std::min(result + VALUE_KNOWN_WIN, VALUE_MATE_IN_MAX_PLY - 1);
return strongSide == pos.side_to_move() ? result : -result;
}
Value result;
// If the stronger side's king is in front of the pawn, it's a win
- if (wksq < psq && file_of(wksq) == file_of(psq))
+ if (forward_file_bb(WHITE, wksq) & psq)
result = RookValueEg - distance(wksq, psq);
// If the weaker side's king is too far from the pawn and the rook,
result = Value(80) - 8 * distance(wksq, psq);
else
- result = Value(200) - 8 * ( distance(wksq, psq + DELTA_S)
- - distance(bksq, psq + DELTA_S)
+ result = Value(200) - 8 * ( distance(wksq, psq + SOUTH)
+ - distance(bksq, psq + SOUTH)
- distance(psq, queeningSq));
return strongSide == pos.side_to_move() ? result : -result;
}
-/// KR vs KB. This is very simple, and always returns drawish scores. The
+/// KR vs KB. This is very simple, and always returns drawish scores. The
/// score is slightly bigger when the defending king is close to the edge.
template<>
Value Endgame<KRKB>::operator()(const Position& pos) const {
// If the defending king blocks the pawn and the attacking king is too far
// away, it's a draw.
if ( r <= RANK_5
- && bksq == wpsq + DELTA_N
+ && bksq == wpsq + NORTH
&& distance(wksq, wpsq) - tempo >= 2
&& distance(wksq, brsq) - tempo >= 2)
return SCALE_FACTOR_DRAW;
&& file_of(wrsq) == f
&& wrsq < wpsq
&& (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo)
- && (distance(wksq, wpsq + DELTA_N) < distance(bksq, wpsq + DELTA_N) - 2 + tempo)
+ && (distance(wksq, wpsq + NORTH) < distance(bksq, wpsq + NORTH) - 2 + tempo)
&& ( distance(bksq, wrsq) + tempo >= 3
|| ( distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo
- && (distance(wksq, wpsq + DELTA_N) < distance(bksq, wrsq) + tempo))))
+ && (distance(wksq, wpsq + NORTH) < distance(bksq, wrsq) + tempo))))
return ScaleFactor( SCALE_FACTOR_MAX
- 8 * distance(wpsq, queeningSq)
- 2 * distance(wksq, queeningSq));
Square bsq = pos.square<BISHOP>(weakSide);
Square psq = pos.square<PAWN>(strongSide);
Rank rk = relative_rank(strongSide, psq);
- Square push = pawn_push(strongSide);
+ Direction push = pawn_push(strongSide);
// If the pawn is on the 5th rank and the pawn (currently) is on
// the same color square as the bishop then there is a chance of
// If all pawns are ahead of the king, on a single rook file and
// the king is within one file of the pawns, it's a draw.
- if ( !(pawns & ~in_front_bb(weakSide, rank_of(ksq)))
+ if ( !(pawns & ~forward_ranks_bb(weakSide, ksq))
&& !((pawns & ~FileABB) && (pawns & ~FileHBB))
&& distance<File>(ksq, lsb(pawns)) <= 1)
return SCALE_FACTOR_DRAW;
// Case 2: Opposite colored bishops
if (opposite_colors(strongBishopSq, weakBishopSq))
- {
- // We assume that the position is drawn in the following three situations:
- //
- // a. The pawn is on rank 5 or further back.
- // b. The defending king is somewhere in the pawn's path.
- // c. The defending bishop attacks some square along the pawn's path,
- // and is at least three squares away from the pawn.
- //
- // These rules are probably not perfect, but in practice they work
- // reasonably well.
-
- if (relative_rank(strongSide, pawnSq) <= RANK_5)
- return SCALE_FACTOR_DRAW;
- else
- {
- Bitboard path = forward_bb(strongSide, pawnSq);
-
- if (path & pos.pieces(weakSide, KING))
- return SCALE_FACTOR_DRAW;
+ return SCALE_FACTOR_DRAW;
- if ( (pos.attacks_from<BISHOP>(weakBishopSq) & path)
- && distance(weakBishopSq, pawnSq) >= 3)
- return SCALE_FACTOR_DRAW;
- }
- }
return SCALE_FACTOR_NONE;
}
// 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(strongSide, pawnSq) & pos.attacks_from<BISHOP>(bishopSq))
+ if (forward_file_bb(strongSide, pawnSq) & pos.attacks_from<BISHOP>(bishopSq))
return ScaleFactor(distance(weakKingSq, pawnSq));
return SCALE_FACTOR_NONE;