// ThreatBySafePawn[PieceType] contains bonuses according to which piece
// type is attacked by a pawn which is protected or is not attacked.
const Score ThreatBySafePawn[PIECE_TYPE_NB] = {
- S(0, 0), S(0, 0), S(176, 139), S(131, 127), S(217, 218), S(203, 215) };
+ S(0, 0), S(0, 0), S(176, 139), S(131, 127), S(217, 218), S(203, 215)
+ };
// Threat[by minor/by rook][attacked PieceType] contains
// bonuses according to which piece type attacks which one.
const Score RookOnPawn = S( 8, 24);
const Score TrappedRook = S(92, 0);
const Score CloseEnemies = S( 7, 0);
- const Score SafeCheck = S(20, 20);
const Score OtherCheck = S(10, 10);
const Score ThreatByHangingPawn = S(71, 61);
const Score LooseEnemies = S( 0, 25);
- const Score WeakQueen = S(35, 0);
+ const Score WeakQueen = S(50, 10);
const Score Hanging = S(48, 27);
const Score ThreatByPawnPush = S(38, 22);
- const Score Unstoppable = S( 0, 20);
+ const Score PawnlessFlank = S(20, 80);
+ const Score HinderPassedPawn = S( 7, 0);
+ const Score ThreatByRank = S(16, 3);
// Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by
// a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
// Penalties for enemy's safe checks
const int QueenContactCheck = 997;
- const int QueenCheck = 695;
- const int RookCheck = 638;
- const int BishopCheck = 538;
- const int KnightCheck = 874;
+ const int QueenCheck = 745;
+ const int RookCheck = 688;
+ const int BishopCheck = 588;
+ const int KnightCheck = 924;
// eval_init() initializes king and attack bitboards for a given color
template<Color Us>
void eval_init(const Position& pos, EvalInfo& ei) {
- const Color Them = (Us == WHITE ? BLACK : WHITE);
- const Square Down = (Us == WHITE ? DELTA_S : DELTA_N);
+ const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Square Down = (Us == WHITE ? SOUTH : NORTH);
ei.pinnedPieces[Us] = pos.pinned_pieces(Us);
Bitboard b = ei.attackedBy[Them][KING];
// Init king safety tables only if we are going to use them
if (pos.non_pawn_material(Us) >= QueenValueMg)
{
- ei.kingRing[Them] = b | shift_bb<Down>(b);
+ ei.kingRing[Them] = b | shift<Down>(b);
b &= ei.attackedBy[Us][PAWN];
ei.kingAttackersCount[Us] = popcount(b);
ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0;
&& pos.is_chess960()
&& (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1)))
{
- Square d = pawn_push(Us) + (file_of(s) == FILE_A ? DELTA_E : DELTA_W);
+ Square 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)) ? TrappedBishopA1H1 * 4
: pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? TrappedBishopA1H1 * 2
Square ksq = pos.square<KING>(Us);
if ( ((file_of(ksq) < FILE_E) == (file_of(s) < file_of(ksq)))
- && (rank_of(ksq) == rank_of(s) || relative_rank(Us, ksq) == RANK_1)
&& !ei.pi->semiopen_side(Us, file_of(ksq), file_of(s) < file_of(ksq)))
score -= (TrappedRook - make_score(mob * 22, 0)) * (1 + !pos.can_castle(Us));
}
template<Color Us, bool DoTrace>
Score evaluate_king(const Position& pos, const EvalInfo& ei) {
- const Color Them = (Us == WHITE ? BLACK : WHITE);
- const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
+ const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Square Up = (Us == WHITE ? NORTH : SOUTH);
Bitboard undefended, b, b1, b2, safe, other;
int kingDanger;
// attacked and undefended squares around our king and the quality of
// the pawn shelter (current 'score' value).
kingDanger = std::min(807, ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them])
- + 101 * ei.kingAdjacentZoneAttacksCount[Them]
- + 235 * popcount(undefended)
- + 134 * (popcount(b) + !!ei.pinnedPieces[Us])
- - 717 * !pos.count<QUEEN>(Them)
- - 7 * mg_value(score) / 5 - 5;
+ + 101 * ei.kingAdjacentZoneAttacksCount[Them]
+ + 235 * popcount(undefended)
+ + 134 * (popcount(b) + !!ei.pinnedPieces[Us])
+ - 717 * !pos.count<QUEEN>(Them)
+ - 7 * mg_value(score) / 5 - 5;
// Analyse the enemy's safe queen contact checks. Firstly, find the
// undefended squares around the king reachable by the enemy queen...
// ... and some other potential checks, only requiring the square to be
// safe from pawn-attacks, and not being occupied by a blocked pawn.
other = ~( ei.attackedBy[Us][PAWN]
- | (pos.pieces(Them, PAWN) & shift_bb<Up>(pos.pieces(PAWN))));
+ | (pos.pieces(Them, PAWN) & shift<Up>(pos.pieces(PAWN))));
b1 = pos.attacks_from<ROOK >(ksq);
b2 = pos.attacks_from<BISHOP>(ksq);
// Enemy queen safe checks
if ((b1 | b2) & ei.attackedBy[Them][QUEEN] & safe)
- kingDanger += QueenCheck, score -= SafeCheck;
+ kingDanger += QueenCheck;
// For other pieces, also consider the square safe if attacked twice,
// and only defended by a queen.
// Enemy rooks safe and other checks
if (b1 & ei.attackedBy[Them][ROOK] & safe)
- kingDanger += RookCheck, score -= SafeCheck;
+ kingDanger += RookCheck;
else if (b1 & ei.attackedBy[Them][ROOK] & other)
score -= OtherCheck;
// Enemy bishops safe and other checks
if (b2 & ei.attackedBy[Them][BISHOP] & safe)
- kingDanger += BishopCheck, score -= SafeCheck;
+ kingDanger += BishopCheck;
else if (b2 & ei.attackedBy[Them][BISHOP] & other)
score -= OtherCheck;
// Enemy knights safe and other checks
b = pos.attacks_from<KNIGHT>(ksq) & ei.attackedBy[Them][KNIGHT];
if (b & safe)
- kingDanger += KnightCheck, score -= SafeCheck;
+ kingDanger += KnightCheck;
else if (b & other)
score -= OtherCheck;
}
// King tropism: firstly, find squares that opponent attacks in our king flank
- b = ei.attackedBy[Them][ALL_PIECES] & KingFlank[Us][file_of(ksq)];
+ File kf = file_of(ksq);
+ b = ei.attackedBy[Them][ALL_PIECES] & KingFlank[Us][kf];
assert(((Us == WHITE ? b << 4 : b >> 4) & b) == 0);
assert(popcount(Us == WHITE ? b << 4 : b >> 4) == popcount(b));
score -= CloseEnemies * popcount(b);
+ // Penalty when our king is on a pawnless flank
+ if (!(pos.pieces(PAWN) & (KingFlank[WHITE][kf] | KingFlank[BLACK][kf])))
+ score -= PawnlessFlank;
+
if (DoTrace)
Trace::add(KING, Us, score);
template<Color Us, bool DoTrace>
Score evaluate_threats(const Position& pos, const EvalInfo& ei) {
- const Color Them = (Us == WHITE ? BLACK : WHITE);
- const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
- const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE);
- const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW);
- const Bitboard TRank2BB = (Us == WHITE ? Rank2BB : Rank7BB);
- const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
+ const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Square Up = (Us == WHITE ? NORTH : SOUTH);
+ const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
+ const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
+ const Bitboard TRank2BB = (Us == WHITE ? Rank2BB : Rank7BB);
+ const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
enum { Minor, Rook };
b = pos.pieces(Us, PAWN) & ( ~ei.attackedBy[Them][ALL_PIECES]
| ei.attackedBy[Us][ALL_PIECES]);
- safeThreats = (shift_bb<Right>(b) | shift_bb<Left>(b)) & weak;
+ safeThreats = (shift<Right>(b) | shift<Left>(b)) & weak;
if (weak ^ safeThreats)
score += ThreatByHangingPawn;
{
b = (defended | weak) & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
while (b)
- score += Threat[Minor][type_of(pos.piece_on(pop_lsb(&b)))];
+ {
+ Square s = pop_lsb(&b);
+ score += Threat[Minor][type_of(pos.piece_on(s))];
+ if (type_of(pos.piece_on(s)) != PAWN)
+ score += ThreatByRank * (int)relative_rank(Them, s);
+ }
b = (pos.pieces(Them, QUEEN) | weak) & ei.attackedBy[Us][ROOK];
while (b)
- score += Threat[Rook ][type_of(pos.piece_on(pop_lsb(&b)))];
+ {
+ Square s = pop_lsb(&b);
+ score += Threat[Rook][type_of(pos.piece_on(s))];
+ if (type_of(pos.piece_on(s)) != PAWN)
+ score += ThreatByRank * (int)relative_rank(Them, s);
+ }
score += Hanging * popcount(weak & ~ei.attackedBy[Them][ALL_PIECES]);
// Bonus if some pawns can safely push and attack an enemy piece
b = pos.pieces(Us, PAWN) & ~TRank7BB;
- b = shift_bb<Up>(b | (shift_bb<Up>(b & TRank2BB) & ~pos.pieces()));
+ b = shift<Up>(b | (shift<Up>(b & TRank2BB) & ~pos.pieces()));
b &= ~pos.pieces()
& ~ei.attackedBy[Them][PAWN]
& (ei.attackedBy[Us][ALL_PIECES] | ~ei.attackedBy[Them][ALL_PIECES]);
- b = (shift_bb<Left>(b) | shift_bb<Right>(b))
+ b = (shift<Left>(b) | shift<Right>(b))
& pos.pieces(Them)
& ~ei.attackedBy[Us][PAWN];
const Color Them = (Us == WHITE ? BLACK : WHITE);
- Bitboard b, squaresToQueen, defendedSquares, unsafeSquares;
+ Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares;
Score score = SCORE_ZERO;
b = ei.pi->passed_pawns(Us);
assert(pos.pawn_passed(Us, s));
assert(!(pos.pieces(PAWN) & forward_bb(Us, s)));
+ bb = forward_bb(Us, s) & (ei.attackedBy[Them][ALL_PIECES] | pos.pieces(Them));
+ score -= HinderPassedPawn * popcount(bb);
+
int r = relative_rank(Us, s) - RANK_2;
int rr = r * (r - 1);
// in the pawn's path attacked or occupied by the enemy.
defendedSquares = unsafeSquares = squaresToQueen = forward_bb(Us, s);
- Bitboard bb = forward_bb(Them, s) & pos.pieces(ROOK, QUEEN) & pos.attacks_from<ROOK>(s);
+ bb = forward_bb(Them, s) & pos.pieces(ROOK, QUEEN) & pos.attacks_from<ROOK>(s);
if (!(pos.pieces(Us) & bb))
defendedSquares &= ei.attackedBy[Us][ALL_PIECES];
mbonus += rr + r * 2, ebonus += rr + r * 2;
} // rr != 0
+ // Assign a small bonus when no pieces left (unstoppable)
+ if (!pos.non_pawn_material(Us) && !pos.non_pawn_material(Them))
+ ebonus += 20;
+
score += make_score(mbonus, ebonus) + PassedFile[file_of(s)];
}
// Pawns blocked or on ranks 2 and 3 will be excluded from the mobility area
Bitboard blockedPawns[] = {
- pos.pieces(WHITE, PAWN) & (shift_bb<DELTA_S>(pos.pieces()) | Rank2BB | Rank3BB),
- pos.pieces(BLACK, PAWN) & (shift_bb<DELTA_N>(pos.pieces()) | Rank7BB | Rank6BB)
+ pos.pieces(WHITE, PAWN) & (shift<SOUTH>(pos.pieces()) | Rank2BB | Rank3BB),
+ pos.pieces(BLACK, PAWN) & (shift<NORTH>(pos.pieces()) | Rank7BB | Rank6BB)
};
// Do not include in mobility area squares protected by enemy pawns, or occupied
score += evaluate_passed_pawns<WHITE, DoTrace>(pos, ei)
- evaluate_passed_pawns<BLACK, DoTrace>(pos, ei);
- // If both sides have only pawns, score for potential unstoppable pawns
- if (!pos.non_pawn_material(WHITE) && !pos.non_pawn_material(BLACK))
- {
- Bitboard b;
- if ((b = ei.pi->passed_pawns(WHITE)) != 0)
- score += Unstoppable * int(relative_rank(WHITE, frontmost_sq(WHITE, b)));
-
- if ((b = ei.pi->passed_pawns(BLACK)) != 0)
- score -= Unstoppable * int(relative_rank(BLACK, frontmost_sq(BLACK, b)));
- }
-
// Evaluate space for both sides, only during opening
if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >= 12222)
score += evaluate_space<WHITE>(pos, ei)
Trace::add(IMBALANCE, ei.me->imbalance());
Trace::add(PAWN, ei.pi->pawns_score());
Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]);
- Trace::add(SPACE, evaluate_space<WHITE>(pos, ei)
- , evaluate_space<BLACK>(pos, ei));
+ if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >= 12222)
+ Trace::add(SPACE, evaluate_space<WHITE>(pos, ei)
+ , evaluate_space<BLACK>(pos, ei));
Trace::add(TOTAL, score);
}