// 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<Value>(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<Value>(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<ScaleFactor>* 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<ScaleFactor>(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<ScaleFactor>* 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<PAWN>(BLACK))
+ if ((sf = pos.this_thread()->endgames.probe<ScaleFactor>(key)) != nullptr)
{
- assert(pos.count<PAWN>(WHITE) >= 2);
-
- e->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
+ e->scalingFunction[sf->strongSide] = sf; // Only strong color assigned
+ return e;
}
- else if (!pos.count<PAWN>(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<PAWN>(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<PAWN>(WHITE) == 1 && pos.count<PAWN>(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<PAWN>(BLACK))
+ {
+ assert(pos.count<PAWN>(WHITE) >= 2);
+
+ e->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
+ }
+ else if (!pos.count<PAWN>(WHITE))
+ {
+ assert(pos.count<PAWN>(BLACK) >= 2);
+
+ e->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
+ }
+ else if (pos.count<PAWN>(WHITE) == 1 && pos.count<PAWN>(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<PAWN>(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<PAWN>(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<PAWN>(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<PAWN>(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
// Define variant rules
const Variant* chess = [&]{
Variant* v = new Variant();
+ v->endgameEval = true;
return v;
} ();
const Variant* makruk = [&]{
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;
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;
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;
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;
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 = [&]{
v->add_piece(KNIBIS, 'n');
v->add_piece(BISKNI, 'b');
v->promotionPieceTypes = {QUEEN, ROOK, BISKNI, KNIBIS};
+ v->endgameEval = true;
return v;
} ();
const Variant* kingofthehill = [&]{
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 = [&]{
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 = [&]{
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;