X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fmaterial.cpp;h=ce7d7ab591881c2a030ac57efd954822c6ad9425;hp=c7bb810d2869f6670e65c8099d11ca24eb666243;hb=73cce873de9ae241d30d405893dcc25e85293b98;hpb=bb751d6c890f5c50c642366d601740366cfae8d0 diff --git a/src/material.cpp b/src/material.cpp index c7bb810d..ce7d7ab5 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -1,17 +1,18 @@ /* - Glaurung, a UCI chess playing engine. - Copyright (C) 2004-2008 Tord Romstad + Stockfish, a UCI chess playing engine derived from Glaurung 2.1 + Copyright (C) 2004-2008 Tord Romstad (Glaurung author) + Copyright (C) 2008 Marco Costalba - Glaurung is free software: you can redistribute it and/or modify + Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - - Glaurung is distributed in the hope that it will be useful, + + Stockfish is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -22,6 +23,7 @@ //// #include +#include #include "material.h" @@ -35,135 +37,129 @@ namespace { const Value BishopPairMidgameBonus = Value(100); const Value BishopPairEndgameBonus = Value(100); - Key KPKMaterialKey, KKPMaterialKey; - Key KBNKMaterialKey, KKBNMaterialKey; - Key KRKPMaterialKey, KPKRMaterialKey; - Key KRKBMaterialKey, KBKRMaterialKey; - Key KRKNMaterialKey, KNKRMaterialKey; - Key KQKRMaterialKey, KRKQMaterialKey; Key KRPKRMaterialKey, KRKRPMaterialKey; - Key KRPPKRPMaterialKey, KRPKRPPMaterialKey; - Key KNNKMaterialKey, KKNNMaterialKey; + Key KNNKMaterialKey, KKNNMaterialKey; Key KBPKBMaterialKey, KBKBPMaterialKey; Key KBPKNMaterialKey, KNKBPMaterialKey; - Key KNPKMaterialKey, KKNPMaterialKey; + Key KNPKMaterialKey, KKNPMaterialKey; Key KPKPMaterialKey; + Key KRPPKRPMaterialKey, KRPKRPPMaterialKey; -}; + std::map EEFmap; + + void EEFAdd(Key k, EndgameEvaluationFunction* f) { + + EEFmap.insert(std::pair(k, f)); + } +} //// //// Functions //// -/// MaterialInfo::init() is called during program initialization. It +/// MaterialInfo::init() is called during program initialization. It /// precomputes material hash keys for a few basic endgames, in order /// to make it easy to recognize such endgames when they occur. void MaterialInfo::init() { - KPKMaterialKey = Position::zobMaterial[WHITE][PAWN][1]; - KKPMaterialKey = Position::zobMaterial[BLACK][PAWN][1]; - KBNKMaterialKey = - Position::zobMaterial[WHITE][BISHOP][1] ^ - Position::zobMaterial[WHITE][KNIGHT][1]; - KKBNMaterialKey = - Position::zobMaterial[BLACK][BISHOP][1] ^ - Position::zobMaterial[BLACK][KNIGHT][1]; - KRKPMaterialKey = - Position::zobMaterial[WHITE][ROOK][1] ^ - Position::zobMaterial[BLACK][PAWN][1]; - KPKRMaterialKey = - Position::zobMaterial[WHITE][PAWN][1] ^ - Position::zobMaterial[BLACK][ROOK][1]; - KRKBMaterialKey = - Position::zobMaterial[WHITE][ROOK][1] ^ - Position::zobMaterial[BLACK][BISHOP][1]; - KBKRMaterialKey = - Position::zobMaterial[WHITE][BISHOP][1] ^ - Position::zobMaterial[BLACK][ROOK][1]; - KRKNMaterialKey = - Position::zobMaterial[WHITE][ROOK][1] ^ - Position::zobMaterial[BLACK][KNIGHT][1]; - KNKRMaterialKey = - Position::zobMaterial[WHITE][KNIGHT][1] ^ - Position::zobMaterial[BLACK][ROOK][1]; - KQKRMaterialKey = - Position::zobMaterial[WHITE][QUEEN][1] ^ - Position::zobMaterial[BLACK][ROOK][1]; - KRKQMaterialKey = - Position::zobMaterial[WHITE][ROOK][1] ^ - Position::zobMaterial[BLACK][QUEEN][1]; - KRPKRMaterialKey = - Position::zobMaterial[WHITE][ROOK][1] ^ - Position::zobMaterial[WHITE][PAWN][1] ^ - Position::zobMaterial[BLACK][ROOK][1]; - KRKRPMaterialKey = - Position::zobMaterial[WHITE][ROOK][1] ^ - Position::zobMaterial[BLACK][ROOK][1] ^ - Position::zobMaterial[BLACK][PAWN][1]; + + typedef Key ZM[2][8][16]; + const ZM& z = Position::zobMaterial; + + static const Color W = WHITE; + static const Color B = BLACK; + + EEFAdd(z[W][PAWN][1], &EvaluateKPK); + EEFAdd(z[B][PAWN][1], &EvaluateKKP); + + EEFAdd(z[W][BISHOP][1] ^ z[W][KNIGHT][1], &EvaluateKBNK); + EEFAdd(z[B][BISHOP][1] ^ z[B][KNIGHT][1], &EvaluateKKBN); + EEFAdd(z[W][ROOK][1] ^ z[B][PAWN][1], &EvaluateKRKP); + EEFAdd(z[W][PAWN][1] ^ z[B][ROOK][1], &EvaluateKPKR); + EEFAdd(z[W][ROOK][1] ^ z[B][BISHOP][1], &EvaluateKRKB); + EEFAdd(z[W][BISHOP][1] ^ z[B][ROOK][1], &EvaluateKBKR); + EEFAdd(z[W][ROOK][1] ^ z[B][KNIGHT][1], &EvaluateKRKN); + EEFAdd(z[W][KNIGHT][1] ^ z[B][ROOK][1], &EvaluateKNKR); + EEFAdd(z[W][QUEEN][1] ^ z[B][ROOK][1], &EvaluateKQKR); + EEFAdd(z[W][ROOK][1] ^ z[B][QUEEN][1], &EvaluateKRKQ); + + KRPKRMaterialKey = z[W][ROOK][1] + ^ z[W][PAWN][1] + ^ z[B][ROOK][1]; + + KRKRPMaterialKey = z[W][ROOK][1] + ^ z[B][ROOK][1] + ^ z[B][PAWN][1]; + KRPPKRPMaterialKey = - Position::zobMaterial[WHITE][ROOK][1] ^ - Position::zobMaterial[WHITE][PAWN][1] ^ - Position::zobMaterial[WHITE][PAWN][2] ^ - Position::zobMaterial[BLACK][ROOK][1] ^ - Position::zobMaterial[BLACK][PAWN][1]; + z[W][ROOK][1] ^ + z[W][PAWN][1] ^ + z[W][PAWN][2] ^ + z[B][ROOK][1] ^ + z[B][PAWN][1]; KRPKRPPMaterialKey = - Position::zobMaterial[WHITE][ROOK][1] ^ - Position::zobMaterial[WHITE][PAWN][1] ^ - Position::zobMaterial[BLACK][ROOK][1] ^ - Position::zobMaterial[BLACK][PAWN][1] ^ - Position::zobMaterial[BLACK][PAWN][2]; + z[W][ROOK][1] ^ + z[W][PAWN][1] ^ + z[B][ROOK][1] ^ + z[B][PAWN][1] ^ + z[B][PAWN][2]; KNNKMaterialKey = - Position::zobMaterial[WHITE][KNIGHT][1] ^ - Position::zobMaterial[WHITE][KNIGHT][2]; + z[W][KNIGHT][1] ^ + z[W][KNIGHT][2]; KKNNMaterialKey = - Position::zobMaterial[BLACK][KNIGHT][1] ^ - Position::zobMaterial[BLACK][KNIGHT][2]; + z[B][KNIGHT][1] ^ + z[B][KNIGHT][2]; KBPKBMaterialKey = - Position::zobMaterial[WHITE][BISHOP][1] ^ - Position::zobMaterial[WHITE][PAWN][1] ^ - Position::zobMaterial[BLACK][BISHOP][1]; + z[W][BISHOP][1] ^ + z[W][PAWN][1] ^ + z[B][BISHOP][1]; KBKBPMaterialKey = - Position::zobMaterial[WHITE][BISHOP][1] ^ - Position::zobMaterial[BLACK][BISHOP][1] ^ - Position::zobMaterial[BLACK][PAWN][1]; + z[W][BISHOP][1] ^ + z[B][BISHOP][1] ^ + z[B][PAWN][1]; KBPKNMaterialKey = - Position::zobMaterial[WHITE][BISHOP][1] ^ - Position::zobMaterial[WHITE][PAWN][1] ^ - Position::zobMaterial[BLACK][KNIGHT][1]; + z[W][BISHOP][1] ^ + z[W][PAWN][1] ^ + z[B][KNIGHT][1]; KNKBPMaterialKey = - Position::zobMaterial[WHITE][KNIGHT][1] ^ - Position::zobMaterial[BLACK][BISHOP][1] ^ - Position::zobMaterial[BLACK][PAWN][1]; + z[W][KNIGHT][1] ^ + z[B][BISHOP][1] ^ + z[B][PAWN][1]; KNPKMaterialKey = - Position::zobMaterial[WHITE][KNIGHT][1] ^ - Position::zobMaterial[WHITE][PAWN][1]; + z[W][KNIGHT][1] ^ + z[W][PAWN][1]; KKNPMaterialKey = - Position::zobMaterial[BLACK][KNIGHT][1] ^ - Position::zobMaterial[BLACK][PAWN][1]; + z[B][KNIGHT][1] ^ + z[B][PAWN][1]; KPKPMaterialKey = - Position::zobMaterial[WHITE][PAWN][1] ^ - Position::zobMaterial[BLACK][PAWN][1]; + z[W][PAWN][1] ^ + z[B][PAWN][1]; + + } /// Constructor for the MaterialInfoTable class. MaterialInfoTable::MaterialInfoTable(unsigned numOfEntries) { + size = numOfEntries; entries = new MaterialInfo[size]; - if(entries == NULL) { - std::cerr << "Failed to allocate " << (numOfEntries * sizeof(MaterialInfo)) - << " bytes for material hash table." << std::endl; - exit(EXIT_FAILURE); + if (!entries) + { + std::cerr << "Failed to allocate " << (numOfEntries * sizeof(MaterialInfo)) + << " bytes for material hash table." << std::endl; + exit(EXIT_FAILURE); } - this->clear(); + clear(); } /// Destructor for the MaterialInfoTable class. MaterialInfoTable::~MaterialInfoTable() { + delete [] entries; } @@ -172,6 +168,7 @@ MaterialInfoTable::~MaterialInfoTable() { /// all entries to 0. void MaterialInfoTable::clear() { + memset(entries, 0, size * sizeof(MaterialInfo)); } @@ -179,15 +176,16 @@ void MaterialInfoTable::clear() { /// MaterialInfoTable::get_material_info() takes a position object as input, /// computes or looks up a MaterialInfo object, and returns a pointer to it. /// If the material configuration is not already present in the table, it -/// is stored there, so we don't have to recompute everything when the +/// is stored there, so we don't have to recompute everything when the /// same material configuration occurs again. MaterialInfo *MaterialInfoTable::get_material_info(const Position &pos) { + Key key = pos.get_material_key(); int index = key & (size - 1); MaterialInfo *mi = entries + index; - // If mi->key matches the position's material hash key, it means that we + // If mi->key matches the position's material hash key, it means that we // have analysed this material configuration before, and we can simply // return the information we found the last time instead of recomputing it: if(mi->key == key) @@ -199,76 +197,36 @@ MaterialInfo *MaterialInfoTable::get_material_info(const Position &pos) { // A special case before looking for a specialized evaluation function: // KNN vs K is a draw: - if(key == KNNKMaterialKey || key == KKNNMaterialKey) { + 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: - if(key == KPKMaterialKey) { - mi->evaluationFunction = &EvaluateKPK; - return mi; - } - else if(key == KKPMaterialKey) { - mi->evaluationFunction = &EvaluateKKP; - return mi; + // particular material configuration + if (EEFmap.find(key) != EEFmap.end()) + { + mi->evaluationFunction = EEFmap[key]; + return mi; } - else if(key == KBNKMaterialKey) { - mi->evaluationFunction = &EvaluateKBNK; - return mi; + else if ( pos.non_pawn_material(BLACK) == Value(0) + && pos.piece_count(BLACK, PAWN) == 0 + && pos.non_pawn_material(WHITE) >= RookValueEndgame) + { + mi->evaluationFunction = &EvaluateKXK; + return mi; } - else if(key == KKBNMaterialKey) { - mi->evaluationFunction = &EvaluateKKBN; - return mi; - } - else if(key == KRKPMaterialKey) { - mi->evaluationFunction = &EvaluateKRKP; - return mi; - } - else if(key == KPKRMaterialKey) { - mi->evaluationFunction = &EvaluateKPKR; - return mi; - } - else if(key == KRKBMaterialKey) { - mi->evaluationFunction = &EvaluateKRKB; - return mi; - } - else if(key == KBKRMaterialKey) { - mi->evaluationFunction = &EvaluateKBKR; - return mi; - } - else if(key == KRKNMaterialKey) { - mi->evaluationFunction = &EvaluateKRKN; - return mi; - } - else if(key == KNKRMaterialKey) { - mi->evaluationFunction = &EvaluateKNKR; - return mi; - } - else if(key == KQKRMaterialKey) { - mi->evaluationFunction = &EvaluateKQKR; - return mi; - } - else if(key == KRKQMaterialKey) { - mi->evaluationFunction = &EvaluateKRKQ; - return mi; - } - else if(pos.non_pawn_material(BLACK) == Value(0) && - pos.pawn_count(BLACK) == 0 && - pos.non_pawn_material(WHITE) >= RookValueEndgame) { - mi->evaluationFunction = &EvaluateKXK; - return mi; - } - else if(pos.non_pawn_material(WHITE) == Value(0) && - pos.pawn_count(WHITE) == 0 && - pos.non_pawn_material(BLACK) >= RookValueEndgame) { - mi->evaluationFunction = &EvaluateKKX; - return mi; + else if ( pos.non_pawn_material(WHITE) == Value(0) + && pos.piece_count(WHITE, PAWN) == 0 + && pos.non_pawn_material(BLACK) >= RookValueEndgame) + { + mi->evaluationFunction = &EvaluateKKX; + return mi; } // OK, we didn't find any special evaluation function for the current - // material configuration. Is there a suitable scaling function? + // 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 @@ -317,48 +275,48 @@ MaterialInfo *MaterialInfoTable::get_material_info(const Position &pos) { } if(pos.non_pawn_material(WHITE) == BishopValueMidgame && - pos.bishop_count(WHITE) == 1 && pos.pawn_count(WHITE) >= 1) + pos.piece_count(WHITE, BISHOP) == 1 && pos.piece_count(WHITE, PAWN) >= 1) mi->scalingFunction[WHITE] = &ScaleKBPK; if(pos.non_pawn_material(BLACK) == BishopValueMidgame && - pos.bishop_count(BLACK) == 1 && pos.pawn_count(BLACK) >= 1) + pos.piece_count(BLACK, BISHOP) == 1 && pos.piece_count(BLACK, PAWN) >= 1) mi->scalingFunction[BLACK] = &ScaleKKBP; - if(pos.pawn_count(WHITE) == 0 && + if(pos.piece_count(WHITE, PAWN) == 0 && pos.non_pawn_material(WHITE) == QueenValueMidgame && - pos.queen_count(WHITE) == 1 && - pos.rook_count(BLACK) == 1 && pos.pawn_count(BLACK) >= 1) + pos.piece_count(WHITE, QUEEN) == 1 && + pos.piece_count(BLACK, ROOK) == 1 && pos.piece_count(BLACK, PAWN) >= 1) mi->scalingFunction[WHITE] = &ScaleKQKRP; - else if(pos.pawn_count(BLACK) == 0 && + else if(pos.piece_count(BLACK, PAWN) == 0 && pos.non_pawn_material(BLACK) == QueenValueMidgame && - pos.queen_count(BLACK) == 1 && - pos.rook_count(WHITE) == 1 && pos.pawn_count(WHITE) >= 1) + pos.piece_count(BLACK, QUEEN) == 1 && + pos.piece_count(WHITE, ROOK) == 1 && pos.piece_count(WHITE, PAWN) >= 1) mi->scalingFunction[BLACK] = &ScaleKRPKQ; if(pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) == Value(0)) { - if(pos.pawn_count(BLACK) == 0) { - assert(pos.pawn_count(WHITE) >= 2); + if(pos.piece_count(BLACK, PAWN) == 0) { + assert(pos.piece_count(WHITE, PAWN) >= 2); mi->scalingFunction[WHITE] = &ScaleKPsK; } - else if(pos.pawn_count(WHITE) == 0) { - assert(pos.pawn_count(BLACK) >= 2); + else if(pos.piece_count(WHITE, PAWN) == 0) { + assert(pos.piece_count(BLACK, PAWN) >= 2); mi->scalingFunction[BLACK] = &ScaleKKPs; } - else if(pos.pawn_count(WHITE) == 1 && pos.pawn_count(BLACK) == 1) { + else if(pos.piece_count(WHITE, PAWN) == 1 && pos.piece_count(BLACK, PAWN) == 1) { mi->scalingFunction[WHITE] = &ScaleKPKPw; mi->scalingFunction[BLACK] = &ScaleKPKPb; } } // Evaluate the material balance. - + Color c; int sign; Value egValue = Value(0), mgValue = Value(0); - + for(c = WHITE, sign = 1; c <= BLACK; c++, sign = -sign) { // No pawns makes it difficult to win, even with a material advantage: - if(pos.pawn_count(c) == 0 && + if(pos.piece_count(c, PAWN) == 0 && pos.non_pawn_material(c) - pos.non_pawn_material(opposite_color(c)) <= BishopValueMidgame) { if(pos.non_pawn_material(c) == pos.non_pawn_material(opposite_color(c))) @@ -366,7 +324,7 @@ MaterialInfo *MaterialInfoTable::get_material_info(const Position &pos) { else if(pos.non_pawn_material(c) < RookValueMidgame) mi->factor[c] = 0; else { - switch(pos.bishop_count(c)) { + switch(pos.piece_count(c, BISHOP)) { case 2: mi->factor[c] = 32; break; case 1: @@ -376,27 +334,27 @@ MaterialInfo *MaterialInfoTable::get_material_info(const Position &pos) { } } } - + // Bishop pair: - if(pos.bishop_count(c) >= 2) { + 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 + // 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": + // Imbalances in Chess": // http://mywebpages.comcast.net/danheisman/Articles/evaluation_of_material_imbalance.htm - mgValue += sign * Value(pos.knight_count(c)*(pos.pawn_count(c)-5)*16); - egValue += sign * Value(pos.knight_count(c)*(pos.pawn_count(c)-5)*16); + 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.rook_count(c) >= 1) { - Value v = Value((pos.rook_count(c) - 1) * 32 + pos.queen_count(c) * 16); + 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; } - + } mi->mgValue = int16_t(mgValue);