From 297c12e595ebc33e11be73ee4b188326418acb4f Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Thu, 16 Jul 2009 14:31:32 +0200 Subject: [PATCH] Simplify endgame functions handling We really don't need to have global endgame functions. We can allocate them on the heap at initialization time and store the corresponding pointer directly in the functions maps. To avoid leaks we just need to remember to deallocate them in map d'tor. These functions are always created in couple, one for each color, so remove a lot of redundant hard coded info and just use the minimum required: the type and the corresponding named string. This greatly simplifies the code and also it is less error prone, now is much simpler to add a new endgame specialized function: just add the corresponding enum in endgame.h and the obvious add_xx() call in EndgameFunctions c'tor, and of course, the most important part, the EvaluationFunction::apply() specialization in endgame.cpp No functional change. Signed-off-by: Marco Costalba --- src/endgame.cpp | 35 --------------- src/endgame.h | 25 ----------- src/material.cpp | 110 +++++++++++++++++++++++++++++------------------ 3 files changed, 67 insertions(+), 103 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 3258c6fc..a8c1e1d0 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -29,41 +29,6 @@ #include "endgame.h" -//// -//// Constants and variables -//// - -/// Evaluation functions - -// Generic "mate lone king" eval -EvaluationFunction EvaluateKXK(WHITE), EvaluateKKX(BLACK); - -// K and two minors vs K and one or two minors -EvaluationFunction EvaluateKmmKm(WHITE); - -EvaluationFunction EvaluateKBNK(WHITE), EvaluateKKBN(BLACK); // KBN vs K -EvaluationFunction EvaluateKPK(WHITE), EvaluateKKP(BLACK); // KP vs K -EvaluationFunction EvaluateKRKP(WHITE), EvaluateKPKR(BLACK); // KR vs KP -EvaluationFunction EvaluateKRKB(WHITE), EvaluateKBKR(BLACK); // KR vs KB -EvaluationFunction EvaluateKRKN(WHITE), EvaluateKNKR(BLACK); // KR vs KN -EvaluationFunction EvaluateKQKR(WHITE), EvaluateKRKQ(BLACK); // KQ vs KR -EvaluationFunction EvaluateKBBKN(WHITE), EvaluateKNKBB(BLACK); // KBB vs KN - - -/// Scaling functions - -ScalingFunction ScaleKBPK(WHITE), ScaleKKBP(BLACK); // KBP vs K -ScalingFunction ScaleKQKRP(WHITE), ScaleKRPKQ(BLACK); // KQ vs KRP -ScalingFunction ScaleKRPKR(WHITE), ScaleKRKRP(BLACK); // KRP vs KR -ScalingFunction ScaleKRPPKRP(WHITE), ScaleKRPKRPP(BLACK); // KRPP vs KRP -ScalingFunction ScaleKPsK(WHITE), ScaleKKPs(BLACK); // King and pawns vs king -ScalingFunction ScaleKBPKB(WHITE), ScaleKBKBP(BLACK); // KBP vs KB -ScalingFunction ScaleKBPPKB(WHITE), ScaleKBKBPP(BLACK); // KBPP vs KB -ScalingFunction ScaleKBPKN(WHITE), ScaleKNKBP(BLACK); // KBP vs KN -ScalingFunction ScaleKNPK(WHITE), ScaleKKNP(BLACK); // KNP vs K -ScalingFunction ScaleKPKPw(WHITE), ScaleKPKPb(BLACK); // KPKP - - //// //// Local definitions //// diff --git a/src/endgame.h b/src/endgame.h index 011299ac..271490b1 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -92,31 +92,6 @@ struct ScalingFunction : public EndgameScalingFunctionBase { }; -//// -//// Constants and variables -//// - -extern EvaluationFunction EvaluateKXK, EvaluateKKX; // Generic "mate lone king" eval -extern EvaluationFunction EvaluateKBNK, EvaluateKKBN; // KBN vs K -extern EvaluationFunction EvaluateKPK, EvaluateKKP; // KP vs K -extern EvaluationFunction EvaluateKRKP, EvaluateKPKR; // KR vs KP -extern EvaluationFunction EvaluateKRKB, EvaluateKBKR; // KR vs KB -extern EvaluationFunction EvaluateKRKN, EvaluateKNKR; // KR vs KN -extern EvaluationFunction EvaluateKQKR, EvaluateKRKQ; // KQ vs KR -extern EvaluationFunction EvaluateKBBKN, EvaluateKNKBB; // KBB vs KN -extern EvaluationFunction EvaluateKmmKm; // K and two minors vs K and one or two minors: - -extern ScalingFunction ScaleKBPK, ScaleKKBP; // KBP vs K -extern ScalingFunction ScaleKQKRP, ScaleKRPKQ; // KQ vs KRP -extern ScalingFunction ScaleKRPKR, ScaleKRKRP; // KRP vs KR -extern ScalingFunction ScaleKRPPKRP, ScaleKRPKRPP; // KRPP vs KRP -extern ScalingFunction ScaleKPsK, ScaleKKPs; // King and pawns vs king -extern ScalingFunction ScaleKBPKB, ScaleKBKBP; // KBP vs KB -extern ScalingFunction ScaleKBPPKB, ScaleKBKBPP; // KBPP vs KB -extern ScalingFunction ScaleKBPKN, ScaleKNKBP; // KBP vs KN -extern ScalingFunction ScaleKNPK, ScaleKKNP; // KNP vs K -extern ScalingFunction ScaleKPKPw, ScaleKPKPb; // KP vs KP - //// //// Prototypes //// diff --git a/src/material.cpp b/src/material.cpp index 845519bc..c9dcaba1 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -42,8 +42,17 @@ namespace { Key KNNKMaterialKey, KKNNMaterialKey; + // Unmapped endgame evaluation and scaling functions, these + // are accessed direcly and not through the function maps. + EvaluationFunction EvaluateKmmKm(WHITE); + EvaluationFunction EvaluateKXK(WHITE), EvaluateKKX(BLACK); + ScalingFunction ScaleKBPK(WHITE), ScaleKKBP(BLACK); + ScalingFunction ScaleKQKRP(WHITE), ScaleKRPKQ(BLACK); + ScalingFunction ScaleKPsK(WHITE), ScaleKKPs(BLACK); + ScalingFunction ScaleKPKPw(WHITE), ScaleKPKPb(BLACK); } + //// //// Classes //// @@ -54,23 +63,28 @@ namespace { class EndgameFunctions { + typedef EndgameEvaluationFunctionBase EF; + typedef EndgameScalingFunctionBase SF; + public: EndgameFunctions(); - EndgameEvaluationFunctionBase* getEEF(Key key) const; - EndgameScalingFunctionBase* getESF(Key key, Color* c) const; + ~EndgameFunctions(); + EF* getEEF(Key key) const; + SF* getESF(Key key, Color* c) const; private: - void add(const string& keyCode, EndgameEvaluationFunctionBase* f); - void add(const string& keyCode, Color c, EndgameScalingFunctionBase* f); Key buildKey(const string& keyCode); + const string swapColors(const string& keyCode); + template void add_ef(const string& keyCode); + template void add_sf(const string& keyCode); struct ScalingInfo { Color col; - EndgameScalingFunctionBase* fun; + SF* fun; }; - std::map EEFmap; + std::map EEFmap; std::map ESFmap; }; @@ -176,7 +190,7 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) { // material configuration. Is there a suitable scaling function? // // The code below is rather messy, and it could easily get worse later, - // if we decide to add more special cases. We face problems when there + // if we decide to add more special cases. We face problems when there // are several conflicting applicable scaling functions and we need to // decide which one to use. Color c; @@ -305,42 +319,39 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) { /// EndgameFunctions member definitions. This class is used to store the maps /// of end game and scaling functions that MaterialInfoTable will query for /// each key. The maps are constant and are populated only at construction, -/// but are per-thread instead of globals to avoid expensive locks. +/// but are per-thread instead of globals to avoid expensive locks needed +/// because std::map is not guaranteed to be thread-safe even if accessed +/// only for a lookup. EndgameFunctions::EndgameFunctions() { KNNKMaterialKey = buildKey("KNNK"); KKNNMaterialKey = buildKey("KKNN"); - add("KPK", &EvaluateKPK); - add("KKP", &EvaluateKKP); - add("KBNK", &EvaluateKBNK); - add("KKBN", &EvaluateKKBN); - add("KRKP", &EvaluateKRKP); - add("KPKR", &EvaluateKPKR); - add("KRKB", &EvaluateKRKB); - add("KBKR", &EvaluateKBKR); - add("KRKN", &EvaluateKRKN); - add("KNKR", &EvaluateKNKR); - add("KQKR", &EvaluateKQKR); - add("KRKQ", &EvaluateKRKQ); - add("KBBKN", &EvaluateKBBKN); - add("KNKBB", &EvaluateKNKBB); - - add("KNPK", WHITE, &ScaleKNPK); - add("KKNP", BLACK, &ScaleKKNP); - add("KRPKR", WHITE, &ScaleKRPKR); - add("KRKRP", BLACK, &ScaleKRKRP); - add("KBPKB", WHITE, &ScaleKBPKB); - add("KBKBP", BLACK, &ScaleKBKBP); - add("KBPPKB", WHITE, &ScaleKBPPKB); - add("KBKBPP", BLACK, &ScaleKBKBPP); - add("KBPKN", WHITE, &ScaleKBPKN); - add("KNKBP", BLACK, &ScaleKNKBP); - add("KRPPKRP", WHITE, &ScaleKRPPKRP); - add("KRPKRPP", BLACK, &ScaleKRPKRPP); - add("KRPPKRP", WHITE, &ScaleKRPPKRP); - add("KRPKRPP", BLACK, &ScaleKRPKRPP); + add_ef("KPK"); + add_ef("KBNK"); + add_ef("KRKP"); + add_ef("KRKB"); + add_ef("KRKN"); + add_ef("KQKR"); + add_ef("KBBKN"); + + add_sf("KNPK"); + add_sf("KRPKR"); + add_sf("KBPKB"); + add_sf("KBPPKB"); + add_sf("KBPKN"); + add_sf("KRPPKRP"); + add_sf("KRPPKRP"); +} + +EndgameFunctions::~EndgameFunctions() { + + for (std::map::iterator it = EEFmap.begin(); it != EEFmap.end(); ++it) + delete (*it).second; + + for (std::map::iterator it = ESFmap.begin(); it != ESFmap.end(); ++it) + delete (*it).second.fun; } Key EndgameFunctions::buildKey(const string& keyCode) { @@ -364,20 +375,33 @@ Key EndgameFunctions::buildKey(const string& keyCode) { return Position(s.str()).get_material_key(); } -void EndgameFunctions::add(const string& keyCode, EndgameEvaluationFunctionBase* f) { +const string EndgameFunctions::swapColors(const string& keyCode) { - EEFmap.insert(std::pair(buildKey(keyCode), f)); + // Build corresponding key for the opposite color: "KBPKN" -> "KNKBP" + size_t idx = keyCode.find("K", 1); + return keyCode.substr(idx) + keyCode.substr(0, idx); } -void EndgameFunctions::add(const string& keyCode, Color c, EndgameScalingFunctionBase* f) { +template +void EndgameFunctions::add_ef(const string& keyCode) { + + EEFmap.insert(std::pair(buildKey(keyCode), new EvaluationFunction(WHITE))); + EEFmap.insert(std::pair(buildKey(swapColors(keyCode)), new EvaluationFunction(BLACK))); +} + +template +void EndgameFunctions::add_sf(const string& keyCode) { + + ScalingInfo s1 = {WHITE, new ScalingFunction(WHITE)}; + ScalingInfo s2 = {BLACK, new ScalingFunction(BLACK)}; - ScalingInfo s = {c, f}; - ESFmap.insert(std::pair(buildKey(keyCode), s)); + ESFmap.insert(std::pair(buildKey(keyCode), s1)); + ESFmap.insert(std::pair(buildKey(swapColors(keyCode)), s2)); } EndgameEvaluationFunctionBase* EndgameFunctions::getEEF(Key key) const { - std::map::const_iterator it(EEFmap.find(key)); + std::map::const_iterator it(EEFmap.find(key)); return (it != EEFmap.end() ? it->second : NULL); } -- 2.39.2