diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 03d537d5..2e1465ff 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -141,6 +141,11 @@ namespace { S(112,125), S(113,127), S(117,137), S(122,143) } }; + // Mask of allowed outpost squares indexed by color + const Bitboard OutpostMask[COLOR_NB] = { + Rank4BB | Rank5BB | Rank6BB, Rank5BB | Rank4BB | Rank3BB + }; + // Outpost[knight/bishop][supported by pawn] contains bonuses for knights and // bishops outposts, bigger if outpost piece is supported by a pawn. const Score Outpost[][2] = { @@ -148,6 +153,13 @@ namespace { { S(18, 5), S(27, 8) } // Bishops }; + // ReachableOutpost[knight/bishop][supported by pawn] contains bonuses for knights and + // bishops which can reach a outpost square in one move, bigger if outpost square is supported by a pawn. + const Score ReachableOutpost[][2] = { + { S(21, 5), S(31, 8) }, // Knights + { S( 8, 2), S(13, 4) } // Bishops + }; + // Threat[minor/rook][attacked PieceType] contains // bonuses according to which piece type attacks which one. // Attacks on lesser pieces which are pawn defended are not considered. @@ -257,7 +269,7 @@ namespace { template Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, const Bitboard* mobilityArea) { - Bitboard b; + Bitboard b, bb; Square s; Score score = SCORE_ZERO; @@ -283,7 +295,7 @@ namespace { { ei.kingAttackersCount[Us]++; ei.kingAttackersWeight[Us] += KingAttackWeights[Pt]; - Bitboard bb = b & ei.attackedBy[Them][KING]; + bb = b & ei.attackedBy[Them][KING]; if (bb) ei.kingAdjacentZoneAttacksCount[Us] += popcount(bb); } @@ -299,11 +311,16 @@ namespace { if (Pt == BISHOP || Pt == KNIGHT) { - // Bonus for outpost square - if ( relative_rank(Us, s) >= RANK_4 - && relative_rank(Us, s) <= RANK_6 - && !(pos.pieces(Them, PAWN) & pawn_attack_span(Us, s))) + // Bonus for outpost squares + bb = OutpostMask[Us] & ~ei.pi->pawn_attacks_span(Them); + if (bb & s) score += Outpost[Pt == BISHOP][!!(ei.attackedBy[Us][PAWN] & s)]; + else + { + bb &= b & ~pos.pieces(Us); + if (bb) + score += ReachableOutpost[Pt == BISHOP][!!(ei.attackedBy[Us][PAWN] & bb)]; + } // Bonus when behind a pawn if ( relative_rank(Us, s) < RANK_5 diff --git a/src/pawns.cpp b/src/pawns.cpp index 40037bba..8b44587f 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -116,7 +116,7 @@ namespace { Bitboard ourPawns = pos.pieces(Us , PAWN); Bitboard theirPawns = pos.pieces(Them, PAWN); - e->passedPawns[Us] = 0; + e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0; e->kingSquares[Us] = SQ_NONE; e->semiopenFiles[Us] = 0xFF; e->pawnAttacks[Us] = shift_bb(ourPawns) | shift_bb(ourPawns); @@ -133,6 +133,8 @@ namespace { // This file cannot be semi-open e->semiopenFiles[Us] &= ~(1 << f); + e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); + // Flag the pawn neighbours = ourPawns & adjacent_files_bb(f); doubled = ourPawns & forward_bb(Us, s); diff --git a/src/pawns.h b/src/pawns.h index 2b978ba0..353cb6a5 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -35,6 +35,7 @@ struct Entry { Score pawns_score() const { return score; } Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; } Bitboard passed_pawns(Color c) const { return passedPawns[c]; } + Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; } int pawn_span(Color c) const { return pawnSpan[c]; } int pawn_asymmetry() const { return asymmetry; } @@ -66,6 +67,7 @@ struct Entry { Score score; Bitboard passedPawns[COLOR_NB]; Bitboard pawnAttacks[COLOR_NB]; + Bitboard pawnAttacksSpan[COLOR_NB]; Square kingSquares[COLOR_NB]; Score kingSafety[COLOR_NB]; int castlingRights[COLOR_NB];