From 8e350d3362804a8c2e327eb222447c490effbcda Mon Sep 17 00:00:00 2001 From: ianfab Date: Sun, 15 Jul 2018 12:20:42 +0200 Subject: [PATCH] Use endgame evaluation only for moderate variants Endgame evaluation functions and scaling factors are no longer applied to games where they are not applicable, e.g., crazyhouse, giveaway, etc. No functional change for standard chess. --- src/material.cpp | 113 +++++++++++++++++++++++++++-------------------------- src/position.h | 6 +++ src/variant.cpp | 10 +++++ src/variant.h | 1 + 4 files changed, 75 insertions(+), 55 deletions(-) diff --git a/src/material.cpp b/src/material.cpp index b18d29d..2585d47 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -137,74 +137,77 @@ Entry* probe(const Position& pos) { // Map total non-pawn material into [PHASE_ENDGAME, PHASE_MIDGAME] e->gamePhase = Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit)); - // Let's look if we have a specialized evaluation function for this particular - // material configuration. Firstly we look for a fixed configuration one, then - // for a generic one if the previous search failed. - if ((e->evaluationFunction = pos.this_thread()->endgames.probe(key)) != nullptr) - return e; - - for (Color c = WHITE; c <= BLACK; ++c) - if (is_KXK(pos, c)) - { - e->evaluationFunction = &EvaluateKXK[c]; + if (pos.endgame_eval()) + { + // Let's look if we have a specialized evaluation function for this particular + // material configuration. Firstly we look for a fixed configuration one, then + // for a generic one if the previous search failed. + if ((e->evaluationFunction = pos.this_thread()->endgames.probe(key)) != nullptr) return e; - } - // OK, we didn't find any special evaluation function for the current material - // configuration. Is there a suitable specialized scaling function? - EndgameBase* sf; + for (Color c = WHITE; c <= BLACK; ++c) + if (is_KXK(pos, c)) + { + e->evaluationFunction = &EvaluateKXK[c]; + return e; + } - if ((sf = pos.this_thread()->endgames.probe(key)) != nullptr) - { - e->scalingFunction[sf->strongSide] = sf; // Only strong color assigned - return e; - } - - // We didn't find any specialized scaling function, so fall back on generic - // ones that refer to more than one material distribution. Note that in this - // case we don't return after setting the function. - for (Color c = WHITE; c <= BLACK; ++c) - { - if (is_KBPsK(pos, c)) - e->scalingFunction[c] = &ScaleKBPsK[c]; + // OK, we didn't find any special evaluation function for the current material + // configuration. Is there a suitable specialized scaling function? + EndgameBase* sf; - else if (is_KQKRPs(pos, c)) - e->scalingFunction[c] = &ScaleKQKRPs[c]; - } - - if (npm_w + npm_b == VALUE_ZERO && pos.pieces(PAWN)) // Only pawns on the board - { - if (!pos.count(BLACK)) + if ((sf = pos.this_thread()->endgames.probe(key)) != nullptr) { - assert(pos.count(WHITE) >= 2); - - e->scalingFunction[WHITE] = &ScaleKPsK[WHITE]; + e->scalingFunction[sf->strongSide] = sf; // Only strong color assigned + return e; } - else if (!pos.count(WHITE)) + + // We didn't find any specialized scaling function, so fall back on generic + // ones that refer to more than one material distribution. Note that in this + // case we don't return after setting the function. + for (Color c = WHITE; c <= BLACK; ++c) { - assert(pos.count(BLACK) >= 2); + if (is_KBPsK(pos, c)) + e->scalingFunction[c] = &ScaleKBPsK[c]; - e->scalingFunction[BLACK] = &ScaleKPsK[BLACK]; + else if (is_KQKRPs(pos, c)) + e->scalingFunction[c] = &ScaleKQKRPs[c]; } - else if (pos.count(WHITE) == 1 && pos.count(BLACK) == 1) + + if (npm_w + npm_b == VALUE_ZERO && pos.pieces(PAWN)) // Only pawns on the board { - // This is a special case because we set scaling functions - // for both colors instead of only one. - e->scalingFunction[WHITE] = &ScaleKPKP[WHITE]; - e->scalingFunction[BLACK] = &ScaleKPKP[BLACK]; + if (!pos.count(BLACK)) + { + assert(pos.count(WHITE) >= 2); + + e->scalingFunction[WHITE] = &ScaleKPsK[WHITE]; + } + else if (!pos.count(WHITE)) + { + assert(pos.count(BLACK) >= 2); + + e->scalingFunction[BLACK] = &ScaleKPsK[BLACK]; + } + else if (pos.count(WHITE) == 1 && pos.count(BLACK) == 1) + { + // This is a special case because we set scaling functions + // for both colors instead of only one. + e->scalingFunction[WHITE] = &ScaleKPKP[WHITE]; + e->scalingFunction[BLACK] = &ScaleKPKP[BLACK]; + } } - } - // Zero or just one pawn makes it difficult to win, even with a small material - // advantage. This catches some trivial draws like KK, KBK and KNK and gives a - // drawish scale factor for cases such as KRKBP and KmmKm (except for KBBKN). - if (!pos.count(WHITE) && npm_w - npm_b <= BishopValueMg) - e->factor[WHITE] = uint8_t(npm_w < RookValueMg ? SCALE_FACTOR_DRAW : - npm_b <= BishopValueMg ? 4 : 14); + // Zero or just one pawn makes it difficult to win, even with a small material + // advantage. This catches some trivial draws like KK, KBK and KNK and gives a + // drawish scale factor for cases such as KRKBP and KmmKm (except for KBBKN). + if (!pos.count(WHITE) && npm_w - npm_b <= BishopValueMg) + e->factor[WHITE] = uint8_t(npm_w < RookValueMg ? SCALE_FACTOR_DRAW : + npm_b <= BishopValueMg ? 4 : 14); - if (!pos.count(BLACK) && npm_b - npm_w <= BishopValueMg) - e->factor[BLACK] = uint8_t(npm_b < RookValueMg ? SCALE_FACTOR_DRAW : - npm_w <= BishopValueMg ? 4 : 14); + if (!pos.count(BLACK) && npm_b - npm_w <= BishopValueMg) + e->factor[BLACK] = uint8_t(npm_b < RookValueMg ? SCALE_FACTOR_DRAW : + npm_w <= BishopValueMg ? 4 : 14); + } // Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder // for the bishop pair "extended piece", which allows us to be more flexible diff --git a/src/position.h b/src/position.h index 926c871..9adf7cd 100644 --- a/src/position.h +++ b/src/position.h @@ -94,6 +94,7 @@ public: const std::string piece_to_char() const; Rank promotion_rank() const; const std::set >& promotion_piece_types() const; + bool endgame_eval() const; bool double_step_enabled() const; bool castling_enabled() const; bool checking_permitted() const; @@ -279,6 +280,11 @@ inline const std::set >& Position::promotion_ return var->promotionPieceTypes; } +inline bool Position::endgame_eval() const { + assert(var != nullptr); + return var->endgameEval; +} + inline bool Position::double_step_enabled() const { assert(var != nullptr); return var->doubleStep; diff --git a/src/variant.cpp b/src/variant.cpp index fb9e908..f1ade24 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -30,6 +30,7 @@ void VariantMap::init() { // Define variant rules const Variant* chess = [&]{ Variant* v = new Variant(); + v->endgameEval = true; return v; } (); const Variant* makruk = [&]{ @@ -41,6 +42,7 @@ void VariantMap::init() { v->startFen = "rnsmksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKMSNR w - - 0 1"; v->promotionRank = RANK_6; v->promotionPieceTypes = {MET}; + v->endgameEval = true; v->doubleStep = false; v->castling = false; return v; @@ -53,6 +55,7 @@ void VariantMap::init() { v->add_piece(MET, 'q'); v->startFen = "rnbqkbnr/8/pppppppp/8/8/PPPPPPPP/8/RNBQKBNR w - - 0 1"; v->promotionPieceTypes = {ROOK, KNIGHT, KHON, MET}; + v->endgameEval = true; v->doubleStep = false; v->castling = false; return v; @@ -66,6 +69,7 @@ void VariantMap::init() { v->startFen = "rnsaksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKASNR w - - 0 1"; v->promotionRank = RANK_6; v->promotionPieceTypes = {AIWOK}; + v->endgameEval = true; v->doubleStep = false; v->castling = false; return v; @@ -78,6 +82,7 @@ void VariantMap::init() { v->add_piece(FERS, 'q'); v->startFen = "rnbkqbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBKQBNR w - - 0 1"; v->promotionPieceTypes = {FERS}; + v->endgameEval = true; v->doubleStep = false; v->castling = false; v->bareKingValue = -VALUE_MATE; @@ -91,6 +96,7 @@ void VariantMap::init() { v->add_piece(AMAZON, 'a'); v->startFen = "rnbakbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBAKBNR w KQkq - 0 1"; v->promotionPieceTypes = {AMAZON, ROOK, BISHOP, KNIGHT}; + v->endgameEval = true; return v; } (); const Variant* hoppelpoppel = [&]{ @@ -100,6 +106,7 @@ void VariantMap::init() { v->add_piece(KNIBIS, 'n'); v->add_piece(BISKNI, 'b'); v->promotionPieceTypes = {QUEEN, ROOK, BISKNI, KNIBIS}; + v->endgameEval = true; return v; } (); const Variant* kingofthehill = [&]{ @@ -274,6 +281,7 @@ void VariantMap::init() { v->add_piece(CHANCELLOR, 'c'); v->startFen = "rnbckbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBCKBNR w KQkq - 0 1"; v->promotionPieceTypes = {CHANCELLOR, ROOK, BISHOP, KNIGHT}; + v->endgameEval = true; return v; } (); const Variant* chigorin = [&]{ @@ -281,6 +289,7 @@ void VariantMap::init() { v->add_piece(CHANCELLOR, 'c'); v->startFen = "rbbqkbbr/pppppppp/8/8/8/8/PPPPPPPP/RNNCKNNR w KQkq - 0 1"; v->promotionPieceTypes = {QUEEN, CHANCELLOR, ROOK, BISHOP, KNIGHT}; + v->endgameEval = true; return v; } (); const Variant* shatar = [&]{ @@ -289,6 +298,7 @@ void VariantMap::init() { v->add_piece(BERS, 'j'); v->startFen = "rnbjkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBJKBNR w - - 0 1"; v->promotionPieceTypes = {BERS}; + v->endgameEval = true; v->doubleStep = false; v->castling = false; v->bareKingValue = VALUE_DRAW; diff --git a/src/variant.h b/src/variant.h index a79ffa7..8af0c54 100644 --- a/src/variant.h +++ b/src/variant.h @@ -42,6 +42,7 @@ struct Variant { std::string startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; Rank promotionRank = RANK_8; std::set > promotionPieceTypes = { QUEEN, ROOK, BISHOP, KNIGHT }; + bool endgameEval = false; bool doubleStep = true; bool castling = true; bool checking = true; -- 1.7.0.4