mirror of
https://github.com/HChaZZY/Stockfish.git
synced 2025-12-24 19:16:49 +08:00
This is a somewhat different patch. It fixes blindspots for two knights vs pawn endgame. With local testing starting from random KNNvKP positions where the pawn has not advanced beyond the 4th rank (thanks @protonspring !) at 15+0.15 (4 cores), this went +105=868-27 against master. All except two losses were won in reverse. The heuristic is simple but effective - the strategy in these endgames is to push the opposing king to the corner, then move the knight that's blocking the pawn in for the checkmate while the pawn is free to move and prevents stalemate. This patch gives SF the little boost it needs to search the relevant king-cornering mating lines. See the discussion in pull request 1939 for some more good results for this test in independant tests: https://github.com/official-stockfish/Stockfish/pull/1939 Bench: 3310239
148 lines
3.9 KiB
C++
148 lines
3.9 KiB
C++
/*
|
|
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
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Stockfish is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef ENDGAME_H_INCLUDED
|
|
#define ENDGAME_H_INCLUDED
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#include "position.h"
|
|
#include "types.h"
|
|
|
|
|
|
/// EndgameCode lists all supported endgame functions by corresponding codes
|
|
|
|
enum EndgameCode {
|
|
|
|
EVALUATION_FUNCTIONS,
|
|
KNNK, // KNN vs K
|
|
KNNKP, // KNN vs KP
|
|
KXK, // Generic "mate lone king" eval
|
|
KBNK, // KBN vs K
|
|
KPK, // KP vs K
|
|
KRKP, // KR vs KP
|
|
KRKB, // KR vs KB
|
|
KRKN, // KR vs KN
|
|
KQKP, // KQ vs KP
|
|
KQKR, // KQ vs KR
|
|
|
|
SCALING_FUNCTIONS,
|
|
KBPsK, // KB and pawns vs K
|
|
KQKRPs, // KQ vs KR and pawns
|
|
KRPKR, // KRP vs KR
|
|
KRPKB, // KRP vs KB
|
|
KRPPKRP, // KRPP vs KRP
|
|
KPsK, // K and pawns vs K
|
|
KBPKB, // KBP vs KB
|
|
KBPPKB, // KBPP vs KB
|
|
KBPKN, // KBP vs KN
|
|
KNPK, // KNP vs K
|
|
KNPKB, // KNP vs KB
|
|
KPKP // KP vs KP
|
|
};
|
|
|
|
|
|
/// Endgame functions can be of two types depending on whether they return a
|
|
/// Value or a ScaleFactor.
|
|
|
|
template<EndgameCode E> using
|
|
eg_type = typename std::conditional<(E < SCALING_FUNCTIONS), Value, ScaleFactor>::type;
|
|
|
|
|
|
/// Base and derived functors for endgame evaluation and scaling functions
|
|
|
|
template<typename T>
|
|
struct EndgameBase {
|
|
|
|
explicit EndgameBase(Color c) : strongSide(c), weakSide(~c) {}
|
|
virtual ~EndgameBase() = default;
|
|
virtual T operator()(const Position&) const = 0;
|
|
|
|
const Color strongSide, weakSide;
|
|
};
|
|
|
|
|
|
template<EndgameCode E, typename T = eg_type<E>>
|
|
struct Endgame : public EndgameBase<T> {
|
|
|
|
explicit Endgame(Color c) : EndgameBase<T>(c) {}
|
|
T operator()(const Position&) const override;
|
|
};
|
|
|
|
|
|
/// The Endgames class stores the pointers to endgame evaluation and scaling
|
|
/// base objects in two std::map. We use polymorphism to invoke the actual
|
|
/// endgame function by calling its virtual operator().
|
|
|
|
class Endgames {
|
|
|
|
template<typename T> using Ptr = std::unique_ptr<EndgameBase<T>>;
|
|
template<typename T> using Map = std::map<Key, Ptr<T>>;
|
|
|
|
template<typename T>
|
|
Map<T>& map() {
|
|
return std::get<std::is_same<T, ScaleFactor>::value>(maps);
|
|
}
|
|
|
|
template<EndgameCode E, typename T = eg_type<E>>
|
|
void add(const std::string& code) {
|
|
|
|
StateInfo st;
|
|
map<T>()[Position().set(code, WHITE, &st).material_key()] = Ptr<T>(new Endgame<E>(WHITE));
|
|
map<T>()[Position().set(code, BLACK, &st).material_key()] = Ptr<T>(new Endgame<E>(BLACK));
|
|
}
|
|
|
|
std::pair<Map<Value>, Map<ScaleFactor>> maps;
|
|
|
|
public:
|
|
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<KNNKP>("KNNKP");
|
|
|
|
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<typename T>
|
|
const EndgameBase<T>* probe(Key key) {
|
|
return map<T>().count(key) ? map<T>()[key].get() : nullptr;
|
|
}
|
|
};
|
|
|
|
#endif // #ifndef ENDGAME_H_INCLUDED
|