- // Compute the space weight
- if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >=
- 2*QueenValueMidgame + 4*RookValueMidgame + 2*KnightValueMidgame)
- {
- int minorPieceCount = pos.piece_count(WHITE, KNIGHT)
- + pos.piece_count(BLACK, KNIGHT)
- + pos.piece_count(WHITE, BISHOP)
- + pos.piece_count(BLACK, BISHOP);
-
- mi->spaceWeight = minorPieceCount * minorPieceCount;
- }
-
- // Evaluate the material balance
- const int pieceCount[2][6] = { { pos.piece_count(WHITE, BISHOP) > 1, pos.piece_count(WHITE, PAWN), pos.piece_count(WHITE, KNIGHT),
- pos.piece_count(WHITE, BISHOP), pos.piece_count(WHITE, ROOK), pos.piece_count(WHITE, QUEEN) },
- { pos.piece_count(BLACK, BISHOP) > 1, pos.piece_count(BLACK, PAWN), pos.piece_count(BLACK, KNIGHT),
- pos.piece_count(BLACK, BISHOP), pos.piece_count(BLACK, ROOK), pos.piece_count(BLACK, QUEEN) } };
- Color c, them;
- int sign, pt1, pt2, pc;
- int v, vv, matValue = 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.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))
- || pos.non_pawn_material(c) < RookValueMidgame)
- mi->factor[c] = 0;
- else
- {
- switch (pos.piece_count(c, BISHOP)) {
- case 2:
- mi->factor[c] = 32;
- break;
- case 1:
- mi->factor[c] = 12;
- break;
- case 0:
- mi->factor[c] = 6;
- break;
- }
- }
- }
-
- // 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
- if (pieceCount[c][ROOK] >= 1)
- matValue -= sign * ((pieceCount[c][ROOK] - 1) * RedundantRookPenalty + pieceCount[c][QUEEN] * RedundantQueenPenalty);
-
- them = opposite_color(c);
- v = 0;
-
- // 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.
- for (pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++)
- {
- pc = pieceCount[c][pt1];
- if (!pc)
- continue;
-
- vv = LinearCoefficients[pt1];
-
- for (pt2 = NO_PIECE_TYPE; pt2 <= pt1; pt2++)
- vv += pieceCount[c][pt2] * QuadraticCoefficientsSameColor[pt1][pt2]
- + pieceCount[them][pt2] * QuadraticCoefficientsOppositeColor[pt1][pt2];
-
- v += pc * vv;
- }
- matValue += sign * v;
- }
- mi->value = int16_t(matValue / 16);
- return mi;
-}
-
-
-/// EndgameFunctions member definitions.
-
-EndgameFunctions::EndgameFunctions() {
-
- add<EvaluationFunction<KNNK> >("KNNK");
- add<EvaluationFunction<KPK> >("KPK");
- add<EvaluationFunction<KBNK> >("KBNK");
- add<EvaluationFunction<KRKP> >("KRKP");
- add<EvaluationFunction<KRKB> >("KRKB");
- add<EvaluationFunction<KRKN> >("KRKN");
- add<EvaluationFunction<KQKR> >("KQKR");
- add<EvaluationFunction<KBBKN> >("KBBKN");
-
- add<ScalingFunction<KNPK> >("KNPK");
- add<ScalingFunction<KRPKR> >("KRPKR");
- add<ScalingFunction<KBPKB> >("KBPKB");
- add<ScalingFunction<KBPPKB> >("KBPPKB");
- add<ScalingFunction<KBPKN> >("KBPKN");
- add<ScalingFunction<KRPPKRP> >("KRPPKRP");
-}
-
-EndgameFunctions::~EndgameFunctions() {
-
- for (map<Key, EF*>::iterator it = maps.first.begin(); it != maps.first.end(); ++it)
- delete (*it).second;
-
- for (map<Key, SF*>::iterator it = maps.second.begin(); it != maps.second.end(); ++it)
- delete (*it).second;
-}
-
-Key EndgameFunctions::buildKey(const string& keyCode) {
-
- assert(keyCode.length() > 0 && keyCode[0] == 'K');
- assert(keyCode.length() < 8);
-
- stringstream s;
- bool upcase = false;
-
- // Build up a fen string with the given pieces, note that
- // the fen string could be of an illegal position.
- for (size_t i = 0; i < keyCode.length(); i++)
- {
- if (keyCode[i] == 'K')
- upcase = !upcase;
-
- s << char(upcase ? toupper(keyCode[i]) : tolower(keyCode[i]));
- }
- s << 8 - keyCode.length() << "/8/8/8/8/8/8/8 w -";
- return Position(s.str(), 0).get_material_key();
-}
-
-const string EndgameFunctions::swapColors(const string& keyCode) {
-
- // Build corresponding key for the opposite color: "KBPKN" -> "KNKBP"
- size_t idx = keyCode.find("K", 1);
- return keyCode.substr(idx) + keyCode.substr(0, idx);
-}
-
-template<class T>
-void EndgameFunctions::add(const string& keyCode) {
-
- typedef typename T::Base F;
-
- get<F>().insert(pair<Key, F*>(buildKey(keyCode), new T(WHITE)));
- get<F>().insert(pair<Key, F*>(buildKey(swapColors(keyCode)), new T(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);
+
+ 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
+ // in defining bishop pair bonuses.
+ const int pieceCount[COLOR_NB][PIECE_TYPE_NB] = {
+ { pos.count<BISHOP>(WHITE) > 1, pos.count<PAWN>(WHITE), pos.count<KNIGHT>(WHITE),
+ pos.count<BISHOP>(WHITE) , pos.count<ROOK>(WHITE), pos.count<QUEEN >(WHITE) },
+ { pos.count<BISHOP>(BLACK) > 1, pos.count<PAWN>(BLACK), pos.count<KNIGHT>(BLACK),
+ pos.count<BISHOP>(BLACK) , pos.count<ROOK>(BLACK), pos.count<QUEEN >(BLACK) } };
+
+ e->value = int16_t((imbalance<WHITE>(pieceCount) - imbalance<BLACK>(pieceCount)) / 16);
+ return e;