X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fmaterial.cpp;h=eb271e8c94b6701c7eab1a308a451454f242cd76;hp=57cf05cadac8b36e1f056a47d62635c93110aae8;hb=152f3b13b78d014dbc85204d6757e2cdf65e5ecf;hpb=0d69ac33ff1b0258c9b18dca48f7b8b40fab5713 diff --git a/src/material.cpp b/src/material.cpp index 57cf05ca..eb271e8c 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(358); + const Value RedundantRookPenalty = Value(536); + const int LinearCoefficients[6] = { 1740, -146, -1246, -197, 206, -7 }; + + const int QuadraticCoefficientsSameColor[][6] = { + { 0, 0, 0, 0, 0, 0 }, { 31, -4, 0, 0, 0, 0 }, { 14, 267, -21, 0, 0, 0 }, + { 0, 7, -26, 0, 0, 0 }, { -3, -1, 69, 162, 80, 0 }, { 40, 27, 119, 174, -64, -49 } }; + + const int QuadraticCoefficientsOppositeColor[][6] = { + { 0, 0, 0, 0, 0, 0 }, { -9, 0, 0, 0, 0, 0 }, { 49, 32, 0, 0, 0, 0 }, + { -25, 19, -5, 0, 0, 0 }, { 97, -6, 39, -88, 0, 0 }, { 77, 69, -42, 104, 116, 0 } }; // Unmapped endgame evaluation and scaling functions, these // are accessed direcly and not through the function maps. @@ -50,6 +61,8 @@ namespace { ScalingFunction ScaleKQKRP(WHITE), ScaleKRPKQ(BLACK); ScalingFunction ScaleKPsK(WHITE), ScaleKKPs(BLACK); ScalingFunction ScaleKPKPw(WHITE), ScaleKPKPb(BLACK); + + Key KNNKMaterialKey, KKNNMaterialKey; } @@ -57,15 +70,13 @@ 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(); @@ -77,16 +88,22 @@ private: static Key buildKey(const string& keyCode); static const string swapColors(const string& keyCode); - std::map EEFmap; - std::map ESFmap; + // Here we store two maps, one for evaluate and one for scaling + pair, map > maps; // Maps accessing functions for const and non-const references - template const std::map& map() const { return EEFmap; } - template<> const std::map& map() const { return ESFmap; } - template std::map& map() { return EEFmap; } - template<> std::map& map() { return ESFmap; } + 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 @@ -102,8 +119,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(); } } @@ -151,7 +168,7 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) { // 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->get(key)) != NULL) + if ((mi->evaluationFunction = funcs->get(key)) != NULL) return mi; else if ( pos.non_pawn_material(BLACK) == Value(0) @@ -192,9 +209,9 @@ 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. - EndgameScalingFunctionBase* sf; + SF* sf; - if ((sf = funcs->get(key)) != NULL) + if ((sf = funcs->get(key)) != NULL) { mi->scalingFunction[sf->color()] = sf; return mi; @@ -257,10 +274,10 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) { // Evaluate the material balance - Color c; + const int bishopsPair_count[2] = { pos.piece_count(WHITE, BISHOP) > 1, pos.piece_count(BLACK, BISHOP) > 1 }; + 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) { @@ -287,30 +304,37 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) { } } - // Bishop pair - if (pos.piece_count(c, BISHOP) >= 2) - { - mgValue += sign * BishopPairMidgameBonus; - egValue += sign * BishopPairEndgameBonus; - } - - // 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": + // 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 - 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); - - // Redundancy of major pieces, again based on Kaufman's paper: if (pos.piece_count(c, ROOK) >= 1) + matValue -= sign * ((pos.piece_count(c, ROOK) - 1) * RedundantRookPenalty + pos.piece_count(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 (PieceType pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++) { - Value v = Value((pos.piece_count(c, ROOK) - 1) * 32 + pos.piece_count(c, QUEEN) * 16); - mgValue -= sign * v; - egValue -= sign * v; + int c1, c2, c3; + c1 = sign * (pt1 != NO_PIECE_TYPE ? pos.piece_count(c, pt1) : bishopsPair_count[c]); + if (!c1) + continue; + + matValue += c1 * LinearCoefficients[pt1]; + + for (PieceType pt2 = NO_PIECE_TYPE; pt2 <= pt1; pt2++) + { + c2 = (pt2 != NO_PIECE_TYPE ? pos.piece_count(c, pt2) : bishopsPair_count[c]); + c3 = (pt2 != NO_PIECE_TYPE ? pos.piece_count(them, pt2) : bishopsPair_count[them]); + matValue += c1 * c2 * QuadraticCoefficientsSameColor[pt1][pt2]; + matValue += c1 * c3 * QuadraticCoefficientsOppositeColor[pt1][pt2]; + } } } - mi->mgValue = int16_t(mgValue); - mi->egValue = int16_t(egValue); + + mi->value = int16_t(matValue / 16); return mi; } @@ -346,10 +370,10 @@ EndgameFunctions::EndgameFunctions() { 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) + for (map::iterator it = maps.second.begin(); it != maps.second.end(); ++it) delete (*it).second; } @@ -358,7 +382,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 @@ -386,13 +410,13 @@ void EndgameFunctions::add(const string& keyCode) { typedef typename T::Base F; - map().insert(std::pair(buildKey(keyCode), new T(WHITE))); - map().insert(std::pair(buildKey(swapColors(keyCode)), new T(BLACK))); + get().insert(pair(buildKey(keyCode), new T(WHITE))); + get().insert(pair(buildKey(swapColors(keyCode)), new T(BLACK))); } template T* EndgameFunctions::get(Key key) const { - std::map::const_iterator it(map().find(key)); - return (it != map().end() ? it->second : NULL); + typename map::const_iterator it(get().find(key)); + return (it != get().end() ? it->second : NULL); }