Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
- Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
+ Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
template<Color Us> void initialize();
template<Color Us> Score evaluate_king();
template<Color Us> Score evaluate_threats();
+ int king_distance(Color c, Square s);
template<Color Us> Score evaluate_passed_pawns();
template<Color Us> Score evaluate_space();
template<Color Us, PieceType Pt> Score evaluate_pieces();
Score mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO };
// attackedBy[color][piece type] is a bitboard representing all squares
- // attacked by a given color and piece type (can be also ALL_PIECES).
+ // attacked by a given color and piece type. Special "piece types" which are
+ // also calculated are QUEEN_DIAGONAL and ALL_PIECES.
Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB];
// attackedBy2[color] are the squares attacked by 2 pieces of a given color,
// Passed[mg/eg][Rank] contains midgame and endgame bonuses for passed pawns.
// We don't use a Score because we process the two components independently.
const Value Passed[][RANK_NB] = {
- { V(5), V( 5), V(31), V(73), V(166), V(252) },
- { V(7), V(14), V(38), V(73), V(166), V(252) }
+ { V(0), V(5), V( 5), V(31), V(73), V(166), V(252) },
+ { V(0), V(7), V(14), V(38), V(73), V(166), V(252) }
};
// PassedFile[File] contains a bonus according to the file of a passed pawn
S(-20,-12), S( 1, -8), S( 2, 10), S( 9, 10)
};
+ // Rank factor applied on some bonus for passed pawn on rank 4 or beyond
+ const int RankFactor[RANK_NB] = {0, 0, 0, 2, 6, 11, 16};
+
// KingProtector[PieceType-2] contains a bonus according to distance from king
const Score KingProtector[] = { S(-3, -5), S(-4, -3), S(-3, 0), S(-1, 1) };
const Score RookOnPawn = S( 8, 24);
const Score TrappedRook = S( 92, 0);
const Score WeakQueen = S( 50, 10);
- const Score OtherCheck = S( 10, 10);
const Score CloseEnemies = S( 7, 0);
const Score PawnlessFlank = S( 20, 80);
- const Score ThreatByHangingPawn = S( 71, 61);
const Score ThreatBySafePawn = S(192,175);
const Score ThreatByRank = S( 16, 3);
const Score Hanging = S( 48, 27);
const int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 78, 56, 45, 11 };
// Penalties for enemy's safe checks
- const int QueenCheck = 780;
- const int RookCheck = 880;
- const int BishopCheck = 435;
- const int KnightCheck = 790;
+ const int QueenSafeCheck = 780;
+ const int RookSafeCheck = 880;
+ const int BishopSafeCheck = 435;
+ const int KnightSafeCheck = 790;
// Threshold for lazy and space evaluation
const Value LazyThreshold = Value(1500);
while ((s = *pl++) != SQ_NONE)
{
// Find attacked squares, including x-ray attacks for bishops and rooks
- b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(Us, QUEEN))
- : Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(Us, ROOK, QUEEN))
+ b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(QUEEN))
+ : Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK))
: pos.attacks_from<Pt>(s);
if (pos.pinned_pieces(Us) & s)
Score Evaluation<T>::evaluate_king() {
const Color Them = (Us == WHITE ? BLACK : WHITE);
- const Direction Up = (Us == WHITE ? NORTH : SOUTH);
const Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB
: AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
const Square ksq = pos.square<KING>(Us);
- Bitboard weak, b, b1, b2, safe, other;
- int kingDanger;
+ Bitboard weak, b, b1, b2, safe, unsafeChecks;
// King shelter and enemy pawns storm
Score score = pe->king_safety<Us>(pos, ksq);
& ~attackedBy2[Us]
& (attackedBy[Us][KING] | attackedBy[Us][QUEEN] | ~attackedBy[Us][ALL_PIECES]);
- // Initialize the 'kingDanger' variable, which will be transformed
- // later into a king danger score. The initial value is based on the
- // number and types of the enemy's attacking pieces, the number of
- // attacked and weak squares around our king, the absence of queen and
- // the quality of the pawn shelter (current 'score' value).
- kingDanger = kingAttackersCount[Them] * kingAttackersWeight[Them]
- + 102 * kingAdjacentZoneAttacksCount[Them]
- + 191 * popcount(kingRing[Us] & weak)
- + 143 * bool(pos.pinned_pieces(Us))
- - 848 * !pos.count<QUEEN>(Them)
- - 9 * mg_value(score) / 8
- + 40;
+ int kingDanger = unsafeChecks = 0;
// Analyse the safe enemy's checks which are possible on next move
safe = ~pos.pieces(Them);
// Enemy queen safe checks
if ((b1 | b2) & attackedBy[Them][QUEEN] & safe & ~attackedBy[Us][QUEEN])
- kingDanger += QueenCheck;
-
- // Some other potential checks are also analysed, even from squares
- // currently occupied by the opponent own pieces, as long as the square
- // is not attacked by our pawns, and is not occupied by a blocked pawn.
- other = ~( attackedBy[Us][PAWN]
- | (pos.pieces(Them, PAWN) & shift<Up>(pos.pieces(PAWN))));
+ kingDanger += QueenSafeCheck;
- // Enemy rooks safe and other checks
- if (b1 & attackedBy[Them][ROOK] & safe)
- kingDanger += RookCheck;
+ b1 &= attackedBy[Them][ROOK];
+ b2 &= attackedBy[Them][BISHOP];
- else if (b1 & attackedBy[Them][ROOK] & other)
- score -= OtherCheck;
+ // Enemy rooks checks
+ if (b1 & safe)
+ kingDanger += RookSafeCheck;
+ else
+ unsafeChecks |= b1;
- // Enemy bishops safe and other checks
- if (b2 & attackedBy[Them][BISHOP] & safe)
- kingDanger += BishopCheck;
+ // Enemy bishops checks
+ if (b2 & safe)
+ kingDanger += BishopSafeCheck;
+ else
+ unsafeChecks |= b2;
- else if (b2 & attackedBy[Them][BISHOP] & other)
- score -= OtherCheck;
-
- // Enemy knights safe and other checks
+ // Enemy knights checks
b = pos.attacks_from<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
if (b & safe)
- kingDanger += KnightCheck;
-
- else if (b & other)
- score -= OtherCheck;
-
- // Transform the kingDanger units into a Score, and substract it from the evaluation
+ kingDanger += KnightSafeCheck;
+ else
+ unsafeChecks |= b;
+
+ // Unsafe or occupied checking squares will also be considered, as long as
+ // the square is in the attacker's mobility area.
+ unsafeChecks &= mobilityArea[Them];
+
+ kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them]
+ + 102 * kingAdjacentZoneAttacksCount[Them]
+ + 191 * popcount(kingRing[Us] & weak)
+ + 143 * popcount(pos.pinned_pieces(Us) | unsafeChecks)
+ - 848 * !pos.count<QUEEN>(Them)
+ - 9 * mg_value(score) / 8
+ + 40;
+
+ // Transform the kingDanger units into a Score, and subtract it from the evaluation
if (kingDanger > 0)
+ {
+ int mobilityDanger = mg_value(mobility[Them] - mobility[Us]);
+ kingDanger = std::max(0, kingDanger + mobilityDanger);
score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16);
+ }
}
// King tropism: firstly, find squares that opponent attacks in our king flank
safeThreats = (shift<Right>(b) | shift<Left>(b)) & weak;
score += ThreatBySafePawn * popcount(safeThreats);
-
- if (weak ^ safeThreats)
- score += ThreatByHangingPawn;
}
// Squares strongly protected by the opponent, either because they attack the
return score;
}
+ // king_distance() returns an estimate of the distance that the king
+ // of the given color has to run to reach square s.
+ template<Tracing T>
+ int Evaluation<T>::king_distance(Color c, Square s) {
+ return std::min(distance(pos.square<KING>(c), s), 5);
+ }
// evaluate_passed_pawns() evaluates the passed pawns and candidate passed
// pawns of the given color.
bb = forward_file_bb(Us, s) & (attackedBy[Them][ALL_PIECES] | pos.pieces(Them));
score -= HinderPassedPawn * popcount(bb);
- int r = relative_rank(Us, s) - RANK_2;
- int rr = r * (r - 1);
+ int r = relative_rank(Us, s);
+ int rr = RankFactor[r];
Value mbonus = Passed[MG][r], ebonus = Passed[EG][r];
Square blockSq = s + Up;
// Adjust bonus based on the king's proximity
- ebonus += distance(pos.square<KING>(Them), blockSq) * 5 * rr
- - distance(pos.square<KING>( Us), blockSq) * 2 * rr;
+ ebonus += (king_distance(Them, blockSq) * 5 - king_distance(Us, blockSq) * 2) * rr;
// If blockSq is not the queening square then consider also a second push
- if (relative_rank(Us, blockSq) != RANK_8)
- ebonus -= distance(pos.square<KING>(Us), blockSq + Up) * rr;
+ if (r != RANK_7)
+ ebonus -= king_distance(Us, blockSq + Up) * rr;
// If the pawn is free to advance, then increase the bonus
if (pos.empty(blockSq))
Trace::add(TOTAL, score);
}
- return (pos.side_to_move() == WHITE ? v : -v) + Eval::Tempo; // Side to move point of view
+ return pos.side_to_move() == WHITE ? v : -v; // Side to move point of view
}
} // namespace
Value Eval::evaluate(const Position& pos)
{
- return Evaluation<>(pos).value();
+ return Evaluation<>(pos).value() + Eval::Tempo;
}
/// trace() is like evaluate(), but instead of returning a value, it returns
std::memset(scores, 0, sizeof(scores));
- Value v = Evaluation<TRACE>(pos).value();
+ Value v = Evaluation<TRACE>(pos).value() + Eval::Tempo;
v = pos.side_to_move() == WHITE ? v : -v; // White's point of view
std::stringstream ss;