using namespace std;
-using namespace Stockfish::Eval::NNUE;
namespace Stockfish {
constexpr Score UncontestedOutpost = S( 1, 10);
constexpr Score BishopOnKingRing = S( 24, 0);
constexpr Score BishopXRayPawns = S( 4, 5);
- constexpr Score CorneredBishop = S( 50, 50);
+ constexpr Value CorneredBishopV = Value(50);
+ constexpr Score CorneredBishop = S(CorneredBishopV, CorneredBishopV);
constexpr Score FlankAttacks = S( 8, 0);
constexpr Score Hanging = S( 69, 36);
constexpr Score KnightOnQueen = S( 16, 11);
attackedBy[Us][Pt] = 0;
- while (b1) {
- Square s = pop_lsb(&b1);
+ while (b1)
+ {
+ Square s = pop_lsb(b1);
// Find attacked squares, including x-ray attacks for bishops and rooks
b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(QUEEN))
{
Direction d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST);
if (pos.piece_on(s + d) == make_piece(Us, PAWN))
- score -= !pos.empty(s + d + pawn_push(Us)) ? CorneredBishop * 4
- : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? CorneredBishop * 2
- : CorneredBishop;
+ score -= !pos.empty(s + d + pawn_push(Us)) ? CorneredBishop * 4
+ : CorneredBishop * 3;
}
}
}
{
b = (defended | weak) & (attackedBy[Us][KNIGHT] | attackedBy[Us][BISHOP]);
while (b)
- score += ThreatByMinor[type_of(pos.piece_on(pop_lsb(&b)))];
+ score += ThreatByMinor[type_of(pos.piece_on(pop_lsb(b)))];
b = weak & attackedBy[Us][ROOK];
while (b)
- score += ThreatByRook[type_of(pos.piece_on(pop_lsb(&b)))];
+ score += ThreatByRook[type_of(pos.piece_on(pop_lsb(b)))];
if (weak & attackedBy[Us][KING])
score += ThreatByKing;
while (b)
{
- Square s = pop_lsb(&b);
+ Square s = pop_lsb(b);
assert(!(pos.pieces(Them, PAWN) & forward_file_bb(Us, s + Up)));
return v;
}
-} // namespace
+
+ /// Fisher Random Chess: correction for cornered bishops, to fix chess960 play with NNUE
+
+ Value fix_FRC(const Position& pos) {
+
+ constexpr Bitboard Corners = 1ULL << SQ_A1 | 1ULL << SQ_H1 | 1ULL << SQ_A8 | 1ULL << SQ_H8;
+
+ if (!(pos.pieces(BISHOP) & Corners))
+ return VALUE_ZERO;
+
+ int correction = 0;
+
+ if ( pos.piece_on(SQ_A1) == W_BISHOP
+ && pos.piece_on(SQ_B2) == W_PAWN)
+ correction += !pos.empty(SQ_B3) ? -CorneredBishopV * 4
+ : -CorneredBishopV * 3;
+
+ if ( pos.piece_on(SQ_H1) == W_BISHOP
+ && pos.piece_on(SQ_G2) == W_PAWN)
+ correction += !pos.empty(SQ_G3) ? -CorneredBishopV * 4
+ : -CorneredBishopV * 3;
+
+ if ( pos.piece_on(SQ_A8) == B_BISHOP
+ && pos.piece_on(SQ_B7) == B_PAWN)
+ correction += !pos.empty(SQ_B6) ? CorneredBishopV * 4
+ : CorneredBishopV * 3;
+
+ if ( pos.piece_on(SQ_H8) == B_BISHOP
+ && pos.piece_on(SQ_G7) == B_PAWN)
+ correction += !pos.empty(SQ_G6) ? CorneredBishopV * 4
+ : CorneredBishopV * 3;
+
+ return pos.side_to_move() == WHITE ? Value(correction)
+ : -Value(correction);
+ }
+
+} // namespace Eval
/// evaluate() is the evaluator for the outer world. It returns a static
else
{
// Scale and shift NNUE for compatibility with search and classical evaluation
- auto adjusted_NNUE = [&](){
- int mat = pos.non_pawn_material() + 2 * PawnValueMg * pos.count<PAWN>();
- return NNUE::evaluate(pos) * (641 + mat / 32 - 4 * pos.rule50_count()) / 1024 + Tempo;
+ auto adjusted_NNUE = [&]()
+ {
+ int material = pos.non_pawn_material() + 2 * PawnValueMg * pos.count<PAWN>();
+ int scale = 641
+ + material / 32
+ - 4 * pos.rule50_count();
+
+ Value nnue = NNUE::evaluate(pos) * scale / 1024 + Tempo;
+
+ if (pos.is_chess960())
+ nnue += fix_FRC(pos);
+
+ return nnue;
};
// If there is PSQ imbalance use classical eval, with small probability if it is small