X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fmaterial.cpp;h=63901d148e3e6c0a1d4b3cd1bbd1572b52c3cb5c;hp=c9dcaba1d42c8441a02bb03638ac80b75d3c3520;hb=1b0303b6e930babbaf41385f2a775bc57c8c8a22;hpb=297c12e595ebc33e11be73ee4b188326418acb4f diff --git a/src/material.cpp b/src/material.cpp index c9dcaba1..63901d14 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -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,37 +70,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); std::map EEFmap; - std::map ESFmap; + std::map ESFmap; + + // Maps accessing functions for const and non-const references + template const std::map& map() const { return EEFmap; } + template std::map& map() { return EEFmap; } }; +// Explicit specializations of a member function shall be declared in +// the namespace of which the class template is a member. +template<> const std::map& +EndgameFunctions::map() const { return ESFmap; } + +template<> std::map& +EndgameFunctions::map() { return ESFmap; } + //// //// Functions @@ -152,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->getEEF(key)) != NULL) + if ((mi->evaluationFunction = funcs->get(key)) != NULL) return mi; else if ( pos.non_pawn_material(BLACK) == Value(0) @@ -193,12 +209,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; } @@ -259,9 +274,10 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) { // Evaluate the material balance + 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) { @@ -288,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; } @@ -328,21 +351,21 @@ 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 >("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() { @@ -350,8 +373,8 @@ 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; + for (std::map::iterator it = ESFmap.begin(); it != ESFmap.end(); ++it) + delete (*it).second; } Key EndgameFunctions::buildKey(const string& keyCode) { @@ -382,35 +405,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)); + map().insert(std::pair(buildKey(keyCode), new T(WHITE))); + map().insert(std::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 std::map::const_iterator it(map().find(key)); + return (it != map().end() ? it->second : NULL); }