4160, 4480, 4800, 5120, 5440, 5760, 6080, 6400
};
- // Tables used to drive a piece towards or away from another piece
- constexpr int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 };
- constexpr int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 };
+ // Drive a piece close to or away from another piece
+ inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); }
+ inline int push_away(Square s1, Square s2) { return 120 - push_close(s1, s2); }
// Pawn Rank based scaling factors used in KRPPKRP endgame
constexpr int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 };
assert(pos.count<PAWN>(strongSide) == 1);
if (file_of(pos.square<PAWN>(strongSide)) >= FILE_E)
- sq = Square(int(sq) ^ 7); // Mirror SQ_H1 -> SQ_A1
+ sq = flip_file(sq);
- return strongSide == WHITE ? sq : ~sq;
+ return strongSide == WHITE ? sq : flip_rank(sq);
}
} // namespace
Value result = pos.non_pawn_material(strongSide)
+ pos.count<PAWN>(strongSide) * PawnValueEg
+ PushToEdges[loserKSq]
- + PushClose[distance(winnerKSq, loserKSq)];
+ + push_close(winnerKSq, loserKSq);
if ( pos.count<QUEEN>(strongSide)
|| pos.count<ROOK>(strongSide)
// to drive to opposite corners (A8/H1).
Value result = VALUE_KNOWN_WIN
- + PushClose[distance(winnerKSq, loserKSq)]
+ + push_close(winnerKSq, loserKSq)
+ PushToCorners[opposite_colors(bishopSq, SQ_A1) ? ~loserKSq : loserKSq];
assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY);
Square bksq = pos.square<KING>(weakSide);
Square bnsq = pos.square<KNIGHT>(weakSide);
- Value result = Value(PushToEdges[bksq] + PushAway[distance(bksq, bnsq)]);
+ Value result = Value(PushToEdges[bksq] + push_away(bksq, bnsq));
return strongSide == pos.side_to_move() ? result : -result;
}
Square loserKSq = pos.square<KING>(weakSide);
Square pawnSq = pos.square<PAWN>(weakSide);
- Value result = Value(PushClose[distance(winnerKSq, loserKSq)]);
+ Value result = Value(push_close(winnerKSq, loserKSq));
if ( relative_rank(weakSide, pawnSq) != RANK_7
|| distance(loserKSq, pawnSq) != 1
- || !((FileABB | FileCBB | FileFBB | FileHBB) & pawnSq))
+ || ((FileBBB | FileDBB | FileEBB | FileGBB) & pawnSq))
result += QueenValueEg - PawnValueEg;
return strongSide == pos.side_to_move() ? result : -result;
Value result = QueenValueEg
- RookValueEg
+ PushToEdges[loserKSq]
- + PushClose[distance(winnerKSq, loserKSq)];
+ + push_close(winnerKSq, loserKSq);
return strongSide == pos.side_to_move() ? result : -result;
}
-/// KNN vs KP. Simply push the opposing king to the corner
+/// KNN vs KP. Very drawish, but there are some mate opportunities if we can
+// press the weakSide King to a corner before the pawn advances too much.
template<>
Value Endgame<KNNKP>::operator()(const Position& pos) const {
assert(verify_material(pos, strongSide, 2 * KnightValueMg, 0));
assert(verify_material(pos, weakSide, VALUE_ZERO, 1));
- Value result = 2 * KnightValueEg
- - PawnValueEg
- + PushToEdges[pos.square<KING>(weakSide)];
+ Value result = PawnValueEg
+ + 2 * PushToEdges[pos.square<KING>(weakSide)]
+ - 10 * relative_rank(weakSide, pos.square<PAWN>(weakSide));
return strongSide == pos.side_to_move() ? result : -result;
}