|| pos.count<ROOK>(strongSide)
||(pos.count<BISHOP>(strongSide) && pos.count<KNIGHT>(strongSide))
|| ( (pos.pieces(strongSide, BISHOP) & ~DarkSquares)
- && (pos.pieces(strongSide, BISHOP) & DarkSquares)))
+ && (pos.pieces(strongSide, BISHOP) & DarkSquares))
+ || pos.count<SILVER>(strongSide) >= 2
+ ||(pos.count<SILVER>(strongSide) && pos.count<KNIGHT>(strongSide))
+ ||(pos.count<SILVER>(strongSide) && pos.count<FERS>(strongSide))
+ ||(pos.count<KNIGHT>(strongSide) && pos.count<FERS>(strongSide) >= 2)
+ ||(pos.count<FERS>(strongSide) >= 3
+ && ( DarkSquares & pos.pieces(strongSide, FERS))
+ && (~DarkSquares & pos.pieces(strongSide, FERS))))
- result = std::min(result + VALUE_KNOWN_WIN, VALUE_MATE_IN_MAX_PLY - 1);
+ result = std::min(result + VALUE_KNOWN_WIN, VALUE_TB_WIN_IN_MAX_PLY - 1);
return strongSide == pos.side_to_move() ? result : -result;
}
Value result = VALUE_KNOWN_WIN
+ PushClose[distance(winnerKSq, loserKSq)]
- + PushToCorners[opposite_colors(bishopSq, SQ_A1) ? ~loserKSq : loserKSq];
+ + PushToCorners[map_to_standard_board(pos, relative_square(opposite_colors(bishopSq, SQ_A1) ? BLACK : WHITE, loserKSq, pos.max_rank()))];
- assert(abs(result) < VALUE_MATE_IN_MAX_PLY);
+ assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY);
return strongSide == pos.side_to_move() ? result : -result;
}
assert(verify_material(pos, strongSide, 2 * KnightValueMg, 0));
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
- Value result = 2 * KnightValueEg
- - PawnValueEg
- + PushToEdges[map_to_standard_board(pos, pos.square<KING>(weakSide))];
+ Value result = PawnValueEg
- + 2 * PushToEdges[pos.square<KING>(weakSide)]
++ + 2 * PushToEdges[map_to_standard_board(pos, pos.square<KING>(weakSide))]
+ - 10 * relative_rank(weakSide, pos.square<PAWN>(weakSide));
return strongSide == pos.side_to_move() ? result : -result;
}
template<> Value Endgame<KNNK>::operator()(const Position&) const { return VALUE_DRAW; }
+/// KFsPs vs K.
+template<>
+Value Endgame<KFsPsK>::operator()(const Position& pos) const {
+
+ assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
+
+ Square winnerKSq = pos.square<KING>(strongSide);
+ Square loserKSq = pos.square<KING>(weakSide);
+
+ Value result = pos.non_pawn_material(strongSide)
+ + pos.count<PAWN>(strongSide) * PawnValueEg
+ + PushToEdges[map_to_standard_board(pos, loserKSq)]
+ + PushClose[distance(winnerKSq, loserKSq)];
+
+ if ( pos.count<FERS>(strongSide) >= 3
+ && ( DarkSquares & pos.pieces(strongSide, FERS))
+ && (~DarkSquares & pos.pieces(strongSide, FERS)))
- result = std::min(result + VALUE_KNOWN_WIN, VALUE_MATE_IN_MAX_PLY - 1);
++ result = std::min(result + VALUE_KNOWN_WIN, VALUE_TB_WIN_IN_MAX_PLY - 1);
+ else if (pos.count<FERS>(strongSide) + pos.count<PAWN>(strongSide) < 3)
+ return VALUE_DRAW;
+ else
+ {
+ bool dark = DarkSquares & pos.pieces(strongSide, FERS);
+ bool light = ~DarkSquares & pos.pieces(strongSide, FERS);
+
+ // Determine the color of ferzes from promoting pawns
+ Bitboard b = pos.pieces(strongSide, PAWN);
+ while (b && (!dark || !light))
+ {
+ if (file_of(pop_lsb(&b)) % 2 != relative_rank(strongSide, pos.promotion_rank(), pos.max_rank()) % 2)
+ light = true;
+ else
+ dark = true;
+ }
+ if (!dark || !light)
+ return VALUE_DRAW; // we can not checkmate with same colored ferzes
+ }
+
+ return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// Mate with KNS vs K.
+template<>
+Value Endgame<KNSK>::operator()(const Position& pos) const {
+
+ assert(verify_material(pos, strongSide, KnightValueMg + SilverValueMg, 0));
+ assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
+
+ Square winnerKSq = pos.square<KING>(strongSide);
+ Square loserKSq = pos.square<KING>(weakSide);
+
+ Value result = VALUE_KNOWN_WIN
+ + PushClose[distance(winnerKSq, loserKSq)]
+ + PushToOpposingSideEdges[map_to_standard_board(pos, relative_square(strongSide, loserKSq, pos.max_rank()))];
+
+ return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// KNF vs K. Can only be won if the weaker side's king
+/// is close to a corner of the same color as the fers.
+template<>
+Value Endgame<KNFK>::operator()(const Position& pos) const {
+
+ assert(verify_material(pos, strongSide, KnightValueMg + FersValueMg, 0));
+ assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
+
+ Square winnerKSq = pos.square<KING>(strongSide);
+ Square loserKSq = pos.square<KING>(weakSide);
+ Square fersSq = pos.square<FERS>(strongSide);
+
+ // tries to drive toward corners A1 or H8. If we have a
+ // fers that cannot reach the above squares, we flip the kings in order
+ // to drive the enemy toward corners A8 or H1.
+ if (opposite_colors(fersSq, SQ_A1))
+ {
+ winnerKSq = relative_square(BLACK, winnerKSq, pos.max_rank());
+ loserKSq = relative_square(BLACK, loserKSq, pos.max_rank());
+ }
+
+ Value result = Value(PushClose[distance(winnerKSq, loserKSq)])
+ + (PushToCorners[map_to_standard_board(pos, loserKSq)] - 3000) / 10;
+
+ return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// KNSFKR vs K.
+template<>
+Value Endgame<KNSFKR>::operator()(const Position& pos) const {
+
+ assert(verify_material(pos, strongSide, KnightValueMg + SilverValueMg + FersValueMg, 0));
+ assert(verify_material(pos, weakSide, RookValueMg, 0));
+
+ Square winnerKSq = pos.square<KING>(strongSide);
+ Square loserKSq = pos.square<KING>(weakSide);
+
+ Value result = KnightValueEg + SilverValueEg + FersValueEg - RookValueEg
+ + PushClose[distance(winnerKSq, loserKSq)]
+ + PushToOpposingSideEdges[map_to_standard_board(pos, relative_square(strongSide, loserKSq, pos.max_rank()))];
+
+ return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// Mate with KSF vs K.
+template<>
+Value Endgame<KSFK>::operator()(const Position& pos) const {
+
+ assert(verify_material(pos, strongSide, SilverValueMg + FersValueMg, 0));
+ assert(verify_material(pos, weakSide, VALUE_ZERO, 0));
+
+ Square winnerKSq = pos.square<KING>(strongSide);
+ Square loserKSq = pos.square<KING>(weakSide);
+
+ Value result = VALUE_KNOWN_WIN
+ + PushClose[distance(winnerKSq, loserKSq)]
+ + PushToOpposingSideEdges[map_to_standard_board(pos, relative_square(strongSide, loserKSq, pos.max_rank()))];
+
+ return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
+/// Mate with KSF vs KF.
+template<>
+Value Endgame<KSFKF>::operator()(const Position& pos) const {
+
+ assert(verify_material(pos, strongSide, SilverValueMg + FersValueMg, 0));
+ assert(verify_material(pos, weakSide, FersValueMg, 0));
+
+ Square winnerKSq = pos.square<KING>(strongSide);
+ Square loserKSq = pos.square<KING>(weakSide);
+ Square fersSq = pos.square<FERS>(weakSide);
+
+ Value result = SilverValueEg
+ + PushClose[distance(winnerKSq, loserKSq)]
+ + PushAway[distance(fersSq, loserKSq)]
+ + PushToOpposingSideEdges[map_to_standard_board(pos, relative_square(strongSide, loserKSq, pos.max_rank()))];
+
+ return strongSide == pos.side_to_move() ? result : -result;
+}
+
+
/// KB and one or more pawns vs K. It checks for draws with rook pawns and
/// a bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_DRAW
/// is returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling