X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fmaterial.cpp;h=27ea5923b492fc9caeb548a29e8dab6c1369da91;hp=c9dcaba1d42c8441a02bb03638ac80b75d3c3520;hb=339bb8a524a0a6af093b383da9f61b31504be9fe;hpb=297c12e595ebc33e11be73ee4b188326418acb4f diff --git a/src/material.cpp b/src/material.cpp index c9dcaba1..27ea5923 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -28,7 +28,7 @@ #include "material.h" -using std::string; +using namespace std; //// //// Local definitions @@ -40,7 +40,18 @@ namespace { const Value BishopPairMidgameBonus = Value(109); const Value BishopPairEndgameBonus = Value(97); - Key KNNKMaterialKey, KKNNMaterialKey; + // Polynomial material balance parameters + const Value RedundantQueenPenalty = Value(320); + const Value RedundantRookPenalty = Value(554); + const int LinearCoefficients[6] = { 1709, -137, -1185, -166, 141, 59 }; + + const int QuadraticCoefficientsSameColor[][6] = { + { 0, 0, 0, 0, 0, 0 }, { 33, -6, 0, 0, 0, 0 }, { 29, 269, -12, 0, 0, 0 }, + { 0, 19, -4, 0, 0, 0 }, { -35, -10, 40, 95, 50, 0 }, { 52, 23, 78, 144, -11, -33 } }; + + const int QuadraticCoefficientsOppositeColor[][6] = { + { 0, 0, 0, 0, 0, 0 }, { -5, 0, 0, 0, 0, 0 }, { -33, 23, 0, 0, 0, 0 }, + { 17, 25, -3, 0, 0, 0 }, { 10, -2, -19, -67, 0, 0 }, { 69, 64, -41, 116, 137, 0 } }; // Unmapped endgame evaluation and scaling functions, these // are accessed direcly and not through the function maps. @@ -57,37 +68,40 @@ namespace { //// Classes //// +typedef EndgameEvaluationFunctionBase EF; +typedef EndgameScalingFunctionBase SF; /// See header for a class description. It is declared here to avoid /// to include in the header file. class EndgameFunctions { - - typedef EndgameEvaluationFunctionBase EF; - typedef EndgameScalingFunctionBase SF; - public: EndgameFunctions(); ~EndgameFunctions(); - EF* getEEF(Key key) const; - SF* getESF(Key key, Color* c) const; + template T* get(Key key) const; private: - 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); + template void add(const string& keyCode); - struct ScalingInfo - { - Color col; - SF* fun; - }; + static Key buildKey(const string& keyCode); + static const string swapColors(const string& keyCode); + + // Here we store two maps, one for evaluate and one for scaling + pair, map > maps; - std::map EEFmap; - std::map ESFmap; + // Maps accessing functions for const and non-const references + template const map& get() const { return maps.first; } + template map& get() { return maps.first; } }; +// Explicit specializations of a member function shall be declared in +// the namespace of which the class template is a member. +template<> const map& +EndgameFunctions::get() const { return maps.second; } + +template<> map& +EndgameFunctions::get() { return maps.second; } + //// //// Functions @@ -103,8 +117,8 @@ MaterialInfoTable::MaterialInfoTable(unsigned int numOfEntries) { funcs = new EndgameFunctions(); if (!entries || !funcs) { - std::cerr << "Failed to allocate " << (numOfEntries * sizeof(MaterialInfo)) - << " bytes for material hash table." << std::endl; + cerr << "Failed to allocate " << (numOfEntries * sizeof(MaterialInfo)) + << " bytes for material hash table." << endl; Application::exit_with_failure(); } } @@ -141,18 +155,10 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) { mi->clear(); mi->key = key; - // A special case before looking for a specialized evaluation function - // KNN vs K is a draw. - if (key == KNNKMaterialKey || key == KKNNMaterialKey) - { - mi->factor[WHITE] = mi->factor[BLACK] = 0; - return mi; - } - // Let's look if we have a specialized evaluation function for this // particular material configuration. First we look for a fixed // configuration one, then a generic one if previous search failed. - if ((mi->evaluationFunction = funcs->getEEF(key)) != NULL) + if ((mi->evaluationFunction = funcs->get(key)) != NULL) return mi; else if ( pos.non_pawn_material(BLACK) == Value(0) @@ -193,12 +199,11 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) { // 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; - EndgameScalingFunctionBase* sf; + SF* sf; - if ((sf = funcs->getESF(key, &c)) != NULL) + if ((sf = funcs->get(key)) != NULL) { - mi->scalingFunction[c] = sf; + mi->scalingFunction[sf->color()] = sf; return mi; } @@ -258,10 +263,13 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) { } // Evaluate the material balance - + const int pieceCount[2][6] = { { pos.piece_count(WHITE, BISHOP) > 1, pos.piece_count(WHITE, PAWN), pos.piece_count(WHITE, KNIGHT), + pos.piece_count(WHITE, BISHOP), pos.piece_count(WHITE, ROOK), pos.piece_count(WHITE, QUEEN) }, + { pos.piece_count(BLACK, BISHOP) > 1, pos.piece_count(BLACK, PAWN), pos.piece_count(BLACK, KNIGHT), + pos.piece_count(BLACK, BISHOP), pos.piece_count(BLACK, ROOK), pos.piece_count(BLACK, QUEEN) } }; + Color c, them; int sign; - Value egValue = Value(0); - Value mgValue = Value(0); + int matValue = 0; for (c = WHITE, sign = 1; c <= BLACK; c++, sign = -sign) { @@ -288,30 +296,34 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) { } } - // Bishop pair - if (pos.piece_count(c, BISHOP) >= 2) + // Redundancy of major pieces, formula based on Kaufman's paper + // "The Evaluation of Material Imbalances in Chess" + // http://mywebpages.comcast.net/danheisman/Articles/evaluation_of_material_imbalance.htm + if (pieceCount[c][ROOK] >= 1) + matValue -= sign * ((pieceCount[c][ROOK] - 1) * RedundantRookPenalty + pieceCount[c][QUEEN] * RedundantQueenPenalty); + + // Second-degree polynomial material imbalance by Tord Romstad + // + // We use NO_PIECE_TYPE as a place holder for the bishop pair "extended piece", + // this allow us to be more flexible in defining bishop pair bonuses. + them = opposite_color(c); + for (int pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++) { - mgValue += sign * BishopPairMidgameBonus; - egValue += sign * BishopPairEndgameBonus; - } + int c1 = sign * pieceCount[c][pt1]; + if (!c1) + continue; - // Knights are stronger when there are many pawns on the board. The - // formula is taken from Larry Kaufman's paper "The Evaluation of Material - // Imbalances in Chess": - // http://mywebpages.comcast.net/danheisman/Articles/evaluation_of_material_imbalance.htm - mgValue += sign * Value(pos.piece_count(c, KNIGHT)*(pos.piece_count(c, PAWN)-5)*16); - egValue += sign * Value(pos.piece_count(c, KNIGHT)*(pos.piece_count(c, PAWN)-5)*16); + matValue += c1 * LinearCoefficients[pt1]; - // Redundancy of major pieces, again based on Kaufman's paper: - if (pos.piece_count(c, ROOK) >= 1) - { - Value v = Value((pos.piece_count(c, ROOK) - 1) * 32 + pos.piece_count(c, QUEEN) * 16); - mgValue -= sign * v; - egValue -= sign * v; + for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; pt2++) + { + matValue += c1 * pieceCount[c][pt2] * QuadraticCoefficientsSameColor[pt1][pt2]; + matValue += c1 * pieceCount[them][pt2] * QuadraticCoefficientsOppositeColor[pt1][pt2]; + } } } - mi->mgValue = int16_t(mgValue); - mi->egValue = int16_t(egValue); + + mi->value = int16_t(matValue / 16); return mi; } @@ -325,33 +337,31 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) { EndgameFunctions::EndgameFunctions() { - KNNKMaterialKey = buildKey("KNNK"); - KKNNMaterialKey = buildKey("KKNN"); - - 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"); + add >("KNNK"); + add >("KPK"); + add >("KBNK"); + add >("KRKP"); + add >("KRKB"); + add >("KRKN"); + add >("KQKR"); + add >("KBBKN"); + + add >("KNPK"); + add >("KRPKR"); + add >("KBPKB"); + add >("KBPPKB"); + add >("KBPKN"); + add >("KRPPKRP"); + add >("KRPPKRP"); } EndgameFunctions::~EndgameFunctions() { - for (std::map::iterator it = EEFmap.begin(); it != EEFmap.end(); ++it) + for (map::iterator it = maps.first.begin(); it != maps.first.end(); ++it) delete (*it).second; - for (std::map::iterator it = ESFmap.begin(); it != ESFmap.end(); ++it) - delete (*it).second.fun; + for (map::iterator it = maps.second.begin(); it != maps.second.end(); ++it) + delete (*it).second; } Key EndgameFunctions::buildKey(const string& keyCode) { @@ -359,7 +369,7 @@ Key EndgameFunctions::buildKey(const string& keyCode) { assert(keyCode.length() > 0 && keyCode[0] == 'K'); assert(keyCode.length() < 8); - std::stringstream s; + stringstream s; bool upcase = false; // Build up a fen substring with the given pieces, note @@ -382,35 +392,18 @@ const string EndgameFunctions::swapColors(const string& keyCode) { return keyCode.substr(idx) + keyCode.substr(0, idx); } -template -void EndgameFunctions::add_ef(const string& keyCode) { +template +void EndgameFunctions::add(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) { + typedef typename T::Base F; - ScalingInfo s1 = {WHITE, new ScalingFunction(WHITE)}; - ScalingInfo s2 = {BLACK, new ScalingFunction(BLACK)}; - - ESFmap.insert(std::pair(buildKey(keyCode), s1)); - ESFmap.insert(std::pair(buildKey(swapColors(keyCode)), s2)); + get().insert(pair(buildKey(keyCode), new T(WHITE))); + get().insert(pair(buildKey(swapColors(keyCode)), new T(BLACK))); } -EndgameEvaluationFunctionBase* EndgameFunctions::getEEF(Key key) const { - - std::map::const_iterator it(EEFmap.find(key)); - return (it != EEFmap.end() ? it->second : NULL); -} - -EndgameScalingFunctionBase* EndgameFunctions::getESF(Key key, Color* c) const { - - std::map::const_iterator it(ESFmap.find(key)); - if (it == ESFmap.end()) - return NULL; +template +T* EndgameFunctions::get(Key key) const { - *c = it->second.col; - return it->second.fun; + typename map::const_iterator it(get().find(key)); + return (it != get().end() ? it->second : NULL); }