Simplify endgame functions handling
authorMarco Costalba <mcostalba@gmail.com>
Thu, 16 Jul 2009 12:31:32 +0000 (14:31 +0200)
committerMarco Costalba <mcostalba@gmail.com>
Fri, 17 Jul 2009 06:55:51 +0000 (07:55 +0100)
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<xxx>::apply() specialization in endgame.cpp

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
src/endgame.cpp
src/endgame.h
src/material.cpp

index 3258c6f..a8c1e1d 100644 (file)
 #include "endgame.h"
 
 
 #include "endgame.h"
 
 
-////
-//// Constants and variables
-////
-
-/// Evaluation functions
-
-// Generic "mate lone king" eval
-EvaluationFunction<KXK> EvaluateKXK(WHITE), EvaluateKKX(BLACK);
-
-// K and two minors vs K and one or two minors
-EvaluationFunction<KmmKm> EvaluateKmmKm(WHITE);
-
-EvaluationFunction<KBNK> EvaluateKBNK(WHITE), EvaluateKKBN(BLACK); // KBN vs K
-EvaluationFunction<KPK> EvaluateKPK(WHITE), EvaluateKKP(BLACK);    // KP vs K
-EvaluationFunction<KRKP> EvaluateKRKP(WHITE), EvaluateKPKR(BLACK); // KR vs KP
-EvaluationFunction<KRKB> EvaluateKRKB(WHITE), EvaluateKBKR(BLACK); // KR vs KB
-EvaluationFunction<KRKN> EvaluateKRKN(WHITE), EvaluateKNKR(BLACK); // KR vs KN
-EvaluationFunction<KQKR> EvaluateKQKR(WHITE), EvaluateKRKQ(BLACK); // KQ vs KR
-EvaluationFunction<KBBKN> EvaluateKBBKN(WHITE), EvaluateKNKBB(BLACK); // KBB vs KN
-
-
-/// Scaling functions
-
-ScalingFunction<KBPK> ScaleKBPK(WHITE), ScaleKKBP(BLACK);    // KBP vs K
-ScalingFunction<KQKRP> ScaleKQKRP(WHITE), ScaleKRPKQ(BLACK); // KQ vs KRP
-ScalingFunction<KRPKR> ScaleKRPKR(WHITE), ScaleKRKRP(BLACK); // KRP vs KR
-ScalingFunction<KRPPKRP> ScaleKRPPKRP(WHITE), ScaleKRPKRPP(BLACK); // KRPP vs KRP
-ScalingFunction<KPsK> ScaleKPsK(WHITE), ScaleKKPs(BLACK);    // King and pawns vs king
-ScalingFunction<KBPKB> ScaleKBPKB(WHITE), ScaleKBKBP(BLACK); // KBP vs KB
-ScalingFunction<KBPPKB> ScaleKBPPKB(WHITE), ScaleKBKBPP(BLACK); // KBPP vs KB
-ScalingFunction<KBPKN> ScaleKBPKN(WHITE), ScaleKNKBP(BLACK); // KBP vs KN
-ScalingFunction<KNPK> ScaleKNPK(WHITE), ScaleKKNP(BLACK);    // KNP vs K
-ScalingFunction<KPKP> ScaleKPKPw(WHITE), ScaleKPKPb(BLACK);  // KPKP
-
-
 ////
 //// Local definitions
 ////
 ////
 //// Local definitions
 ////
index 011299a..271490b 100644 (file)
@@ -92,31 +92,6 @@ struct ScalingFunction : public EndgameScalingFunctionBase {
 };
 
 
 };
 
 
-////
-//// Constants and variables
-////
-
-extern EvaluationFunction<KXK> EvaluateKXK, EvaluateKKX;       // Generic "mate lone king" eval
-extern EvaluationFunction<KBNK> EvaluateKBNK, EvaluateKKBN;    // KBN vs K
-extern EvaluationFunction<KPK> EvaluateKPK, EvaluateKKP;       // KP vs K
-extern EvaluationFunction<KRKP> EvaluateKRKP, EvaluateKPKR;    // KR vs KP
-extern EvaluationFunction<KRKB> EvaluateKRKB, EvaluateKBKR;    // KR vs KB
-extern EvaluationFunction<KRKN> EvaluateKRKN, EvaluateKNKR;    // KR vs KN
-extern EvaluationFunction<KQKR> EvaluateKQKR, EvaluateKRKQ;    // KQ vs KR
-extern EvaluationFunction<KBBKN> EvaluateKBBKN, EvaluateKNKBB; // KBB vs KN
-extern EvaluationFunction<KmmKm> EvaluateKmmKm; // K and two minors vs K and one or two minors:
-
-extern ScalingFunction<KBPK> ScaleKBPK, ScaleKKBP;    // KBP vs K
-extern ScalingFunction<KQKRP> ScaleKQKRP, ScaleKRPKQ; // KQ vs KRP
-extern ScalingFunction<KRPKR> ScaleKRPKR, ScaleKRKRP; // KRP vs KR
-extern ScalingFunction<KRPPKRP> ScaleKRPPKRP, ScaleKRPKRPP; // KRPP vs KRP
-extern ScalingFunction<KPsK> ScaleKPsK, ScaleKKPs;    // King and pawns vs king
-extern ScalingFunction<KBPKB> ScaleKBPKB, ScaleKBKBP; // KBP vs KB
-extern ScalingFunction<KBPPKB> ScaleKBPPKB, ScaleKBKBPP; // KBPP vs KB
-extern ScalingFunction<KBPKN> ScaleKBPKN, ScaleKNKBP; // KBP vs KN
-extern ScalingFunction<KNPK> ScaleKNPK, ScaleKKNP;    // KNP vs K
-extern ScalingFunction<KPKP> ScaleKPKPw, ScaleKPKPb;  // KP vs KP
-
 ////
 //// Prototypes
 ////
 ////
 //// Prototypes
 ////
index 845519b..c9dcaba 100644 (file)
@@ -42,8 +42,17 @@ namespace {
 
   Key KNNKMaterialKey, KKNNMaterialKey;
 
 
   Key KNNKMaterialKey, KKNNMaterialKey;
 
+  // Unmapped endgame evaluation and scaling functions, these
+  // are accessed direcly and not through the function maps.
+  EvaluationFunction<KmmKm> EvaluateKmmKm(WHITE);
+  EvaluationFunction<KXK>   EvaluateKXK(WHITE), EvaluateKKX(BLACK);
+  ScalingFunction<KBPK>     ScaleKBPK(WHITE),   ScaleKKBP(BLACK);
+  ScalingFunction<KQKRP>    ScaleKQKRP(WHITE),  ScaleKRPKQ(BLACK);
+  ScalingFunction<KPsK>     ScaleKPsK(WHITE),   ScaleKKPs(BLACK);
+  ScalingFunction<KPKP>     ScaleKPKPw(WHITE),  ScaleKPKPb(BLACK);
 }
 
 }
 
+
 ////
 //// Classes
 ////
 ////
 //// Classes
 ////
@@ -54,23 +63,28 @@ namespace {
 
 class EndgameFunctions {
 
 
 class EndgameFunctions {
 
+  typedef EndgameEvaluationFunctionBase EF;
+  typedef EndgameScalingFunctionBase SF;
+
 public:
   EndgameFunctions();
 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:
 
 private:
-  void add(const string& keyCode, EndgameEvaluationFunctionBase* f);
-  void add(const string& keyCode, Color c, EndgameScalingFunctionBase* f);
   Key buildKey(const string& keyCode);
   Key buildKey(const string& keyCode);
+  const string swapColors(const string& keyCode);
+  template<EndgameType> void add_ef(const string& keyCode);
+  template<EndgameType> void add_sf(const string& keyCode);
 
   struct ScalingInfo
   {
       Color col;
 
   struct ScalingInfo
   {
       Color col;
-      EndgameScalingFunctionBase* fun;
+      SF* fun;
   };
 
   };
 
-  std::map<Key, EndgameEvaluationFunctionBase*> EEFmap;
+  std::map<Key, EF*> EEFmap;
   std::map<Key, ScalingInfo> ESFmap;
 };
 
   std::map<Key, ScalingInfo> 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,
   // 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;
   // 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,
 /// 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");
 
 
 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>("KPK");
+  add_ef<KBNK>("KBNK");
+  add_ef<KRKP>("KRKP");
+  add_ef<KRKB>("KRKB");
+  add_ef<KRKN>("KRKN");
+  add_ef<KQKR>("KQKR");
+  add_ef<KBBKN>("KBBKN");
+
+  add_sf<KNPK>("KNPK");
+  add_sf<KRPKR>("KRPKR");
+  add_sf<KBPKB>("KBPKB");
+  add_sf<KBPPKB>("KBPPKB");
+  add_sf<KBPKN>("KBPKN");
+  add_sf<KRPPKRP>("KRPPKRP");
+  add_sf<KRPPKRP>("KRPPKRP");
+}
+
+EndgameFunctions::~EndgameFunctions() {
+
+    for (std::map<Key, EF*>::iterator it = EEFmap.begin(); it != EEFmap.end(); ++it)
+        delete (*it).second;
+
+    for (std::map<Key, ScalingInfo>::iterator it = ESFmap.begin(); it != ESFmap.end(); ++it)
+        delete (*it).second.fun;
 }
 
 Key EndgameFunctions::buildKey(const string& keyCode) {
 }
 
 Key EndgameFunctions::buildKey(const string& keyCode) {
@@ -364,20 +375,33 @@ Key EndgameFunctions::buildKey(const string& keyCode) {
     return Position(s.str()).get_material_key();
 }
 
     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<Key, EndgameEvaluationFunctionBase*>(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<EndgameType et>
+void EndgameFunctions::add_ef(const string& keyCode) {
+
+  EEFmap.insert(std::pair<Key, EF*>(buildKey(keyCode), new EvaluationFunction<et>(WHITE)));
+  EEFmap.insert(std::pair<Key, EF*>(buildKey(swapColors(keyCode)), new EvaluationFunction<et>(BLACK)));
+}
+
+template<EndgameType et>
+void EndgameFunctions::add_sf(const string& keyCode) {
+
+  ScalingInfo s1 = {WHITE, new ScalingFunction<et>(WHITE)};
+  ScalingInfo s2 = {BLACK, new ScalingFunction<et>(BLACK)};
 
 
-  ScalingInfo s = {c, f};
-  ESFmap.insert(std::pair<Key, ScalingInfo>(buildKey(keyCode), s));
+  ESFmap.insert(std::pair<Key, ScalingInfo>(buildKey(keyCode), s1));
+  ESFmap.insert(std::pair<Key, ScalingInfo>(buildKey(swapColors(keyCode)), s2));
 }
 
 EndgameEvaluationFunctionBase* EndgameFunctions::getEEF(Key key) const {
 
 }
 
 EndgameEvaluationFunctionBase* EndgameFunctions::getEEF(Key key) const {
 
-  std::map<Key, EndgameEvaluationFunctionBase*>::const_iterator it(EEFmap.find(key));
+  std::map<Key, EF*>::const_iterator it(EEFmap.find(key));
   return (it != EEFmap.end() ? it->second : NULL);
 }
 
   return (it != EEFmap.end() ? it->second : NULL);
 }