X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fevaluate.cpp;h=bea0e306388ffed3864091372247f003b55af9b9;hb=7f56d2949d4244c9d2e6796adc721582e9d85804;hp=6ec42e24e9a0c602e50b2838857bc49449106060;hpb=619d66b7ab1b8491363f9fd5ce98372e51e55cde;p=stockfish
diff --git a/src/evaluate.cpp b/src/evaluate.cpp
index 6ec42e24..bea0e306 100644
--- a/src/evaluate.cpp
+++ b/src/evaluate.cpp
@@ -17,10 +17,10 @@
along with this program. If not, see .
*/
+#include
#include
#include
#include
-#include
#include "bitcount.h"
#include "evaluate.h"
@@ -89,23 +89,15 @@ namespace {
std::string do_trace(const Position& pos);
}
- // Evaluation weights, initialized from UCI options
- enum { Mobility, PawnStructure, PassedPawns, Space, KingDangerUs, KingDangerThem };
- struct Weight { int mg, eg; } Weights[6];
+ // Evaluation weights, indexed by evaluation term
+ enum { Mobility, PawnStructure, PassedPawns, Space, KingSafety };
+ const struct Weight { int mg, eg; } Weights[] = {
+ {289, 344}, {233, 201}, {221, 273}, {46, 0}, {318, 0}
+ };
typedef Value V;
#define S(mg, eg) make_score(mg, eg)
- // Internal evaluation weights. These are applied on top of the evaluation
- // weights read from UCI parameters. The purpose is to be able to change
- // the evaluation weights while keeping the default values of the UCI
- // parameters at 100, which looks prettier.
- //
- // Values modified by Joona Kiiski
- const Score WeightsInternal[] = {
- S(289, 344), S(233, 201), S(221, 273), S(46, 0), S(271, 0), S(307, 0)
- };
-
// MobilityBonus[PieceType][attacked] contains bonuses for middle and end
// game, indexed by piece type and number of attacked squares not occupied by
// friendly pieces.
@@ -158,17 +150,16 @@ namespace {
S(0, 0), S(0, 0), S(56, 70), S(56, 70), S(76, 99), S(86, 118)
};
+ // Hanging contains a bonus for each enemy hanging piece
+ const Score Hanging = S(23, 20);
+
#undef S
- const Score Tempo = make_score(24, 11);
- const Score RookOn7th = make_score(11, 20);
const Score RookOnPawn = make_score(10, 28);
const Score RookOpenFile = make_score(43, 21);
const Score RookSemiopenFile = make_score(19, 10);
const Score BishopPawns = make_score( 8, 12);
- const Score KnightPawns = make_score( 8, 4);
const Score MinorBehindPawn = make_score(16, 0);
- const Score UndefendedMinor = make_score(25, 10);
const Score TrappedRook = make_score(90, 0);
const Score Unstoppable = make_score( 0, 20);
@@ -202,9 +193,9 @@ namespace {
const int BishopCheck = 2;
const int KnightCheck = 3;
- // KingDanger[Color][attackUnits] contains the actual king danger weighted
- // scores, indexed by color and by a calculated integer number.
- Score KingDanger[COLOR_NB][128];
+ // KingDanger[attackUnits] contains the actual king danger weighted
+ // scores, indexed by a calculated integer number.
+ Score KingDanger[128];
// apply_weight() weighs score 'v' by weight 'w' trying to prevent overflow
@@ -213,31 +204,6 @@ namespace {
}
- // weight_option() computes the value of an evaluation weight, by combining
- // two UCI-configurable weights (midgame and endgame) with an internal weight.
-
- Weight weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight) {
-
- Weight w = { Options[mgOpt] * mg_value(internalWeight) / 100,
- Options[egOpt] * eg_value(internalWeight) / 100 };
- return w;
- }
-
-
- // interpolate() interpolates between a middlegame and an endgame score,
- // based on game phase. It also scales the return value by a ScaleFactor array.
-
- Value interpolate(const Score& v, Phase ph, ScaleFactor sf) {
-
- assert(-VALUE_INFINITE < mg_value(v) && mg_value(v) < VALUE_INFINITE);
- assert(-VALUE_INFINITE < eg_value(v) && eg_value(v) < VALUE_INFINITE);
- assert(PHASE_ENDGAME <= ph && ph <= PHASE_MIDGAME);
-
- int eg = (eg_value(v) * int(sf)) / SCALE_FACTOR_NORMAL;
- return Value((mg_value(v) * int(ph) + eg * int(PHASE_MIDGAME - ph)) / PHASE_MIDGAME);
- }
-
-
// init_eval_info() initializes king bitboards for given color adding
// pawn attacks. To be done at the beginning of the evaluation.
@@ -349,10 +315,6 @@ namespace {
if (Pt == BISHOP)
score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s);
- // Penalty for knight when there are few enemy pawns
- if (Pt == KNIGHT)
- score -= KnightPawns * std::max(5 - pos.count(Them), 0);
-
// Bishop and knight outposts squares
if (!(pos.pieces(Them, PAWN) & pawn_attack_span(Us, s)))
score += evaluate_outposts(pos, ei, s);
@@ -365,11 +327,6 @@ namespace {
if (Pt == ROOK)
{
- // Rook on 7th rank and enemy king trapped on 8th
- if ( relative_rank(Us, s) == RANK_7
- && relative_rank(Us, pos.king_square(Them)) == RANK_8)
- score += RookOn7th;
-
// Rook piece attacking enemy pawns on the same rank/file
if (relative_rank(Us, s) >= RANK_5)
{
@@ -468,9 +425,7 @@ namespace {
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]);
if (b)
- attackUnits += QueenContactCheck
- * popcount(b)
- * (Them == pos.side_to_move() ? 2 : 1);
+ attackUnits += QueenContactCheck * popcount(b);
}
// Analyse the enemy's safe rook contact checks. Firstly, find the
@@ -488,9 +443,7 @@ namespace {
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][QUEEN]);
if (b)
- attackUnits += RookContactCheck
- * popcount(b)
- * (Them == pos.side_to_move() ? 2 : 1);
+ attackUnits += RookContactCheck * popcount(b);
}
// Analyse the enemy's safe distance checks for sliders and knights
@@ -524,7 +477,7 @@ namespace {
// Finally, extract the king danger score from the KingDanger[]
// array and subtract the score from evaluation.
- score -= KingDanger[Us == Search::RootColor][attackUnits];
+ score -= KingDanger[attackUnits];
}
if (Trace)
@@ -542,17 +495,10 @@ namespace {
const Color Them = (Us == WHITE ? BLACK : WHITE);
- Bitboard b, undefendedMinors, weakEnemies;
+ Bitboard b, weakEnemies;
Score score = SCORE_ZERO;
- // Undefended minors get penalized even if they are not under attack
- undefendedMinors = pos.pieces(Them, BISHOP, KNIGHT)
- & ~ei.attackedBy[Them][ALL_PIECES];
-
- if (undefendedMinors)
- score += UndefendedMinor;
-
- // Enemy pieces not defended by a pawn and under our attack
+ // Enemies not defended by a pawn and under our attack
weakEnemies = pos.pieces(Them)
& ~ei.attackedBy[Them][PAWN]
& ei.attackedBy[Us][ALL_PIECES];
@@ -560,13 +506,17 @@ namespace {
// Add a bonus according if the attacking pieces are minor or major
if (weakEnemies)
{
- b = weakEnemies & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
+ b = weakEnemies & (ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
if (b)
score += Threat[0][type_of(pos.piece_on(lsb(b)))];
b = weakEnemies & (ei.attackedBy[Us][ROOK] | ei.attackedBy[Us][QUEEN]);
if (b)
score += Threat[1][type_of(pos.piece_on(lsb(b)))];
+
+ b = weakEnemies & ~ei.attackedBy[Them][ALL_PIECES];
+ if (b)
+ score += more_than_one(b) ? Hanging * popcount(b) : Hanging;
}
if (Trace)
@@ -594,24 +544,23 @@ namespace {
assert(pos.pawn_passed(Us, s));
- int r = int(relative_rank(Us, s) - RANK_2);
+ int r = relative_rank(Us, s) - RANK_2;
int rr = r * (r - 1);
// Base bonus based on rank
- Value mbonus = Value(17 * rr);
- Value ebonus = Value(7 * (rr + r + 1));
+ Value mbonus = Value(17 * rr), ebonus = Value(7 * (rr + r + 1));
if (rr)
{
Square blockSq = s + pawn_push(Us);
// Adjust bonus based on the king's proximity
- ebonus += Value(square_distance(pos.king_square(Them), blockSq) * 5 * rr)
- - Value(square_distance(pos.king_square(Us ), blockSq) * 2 * rr);
+ ebonus += square_distance(pos.king_square(Them), blockSq) * 5 * rr
+ - square_distance(pos.king_square(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 -= Value(rr * square_distance(pos.king_square(Us), blockSq + pawn_push(Us)));
+ ebonus -= square_distance(pos.king_square(Us), blockSq + pawn_push(Us)) * rr;
// If the pawn is free to advance, then increase the bonus
if (pos.empty(blockSq))
@@ -633,39 +582,22 @@ namespace {
else
defendedSquares = squaresToQueen & ei.attackedBy[Us][ALL_PIECES];
- // If there aren't any enemy attacks, then assign a huge bonus.
- // The bonus will be a bit smaller if at least the block square
- // isn't attacked, otherwise assign the smallest possible bonus.
- int k = !unsafeSquares ? 15 : !(unsafeSquares & blockSq) ? 9 : 3;
+ // If there aren't any enemy attacks, assign a big bonus. Otherwise
+ // assign a smaller bonus if the block square isn't attacked.
+ int k = !unsafeSquares ? 15 : !(unsafeSquares & blockSq) ? 9 : 0;
- // Assign a big bonus if the path to the queen is fully defended,
- // otherwise assign a bit less of a bonus if at least the block
- // square is defended.
+ // If the path to queen is fully defended, assign a big bonus.
+ // Otherwise assign a smaller bonus if the block square is defended.
if (defendedSquares == squaresToQueen)
k += 6;
else if (defendedSquares & blockSq)
- k += (unsafeSquares & defendedSquares) == unsafeSquares ? 4 : 2;
+ k += 4;
- mbonus += Value(k * rr), ebonus += Value(k * rr);
+ mbonus += k * rr, ebonus += k * rr;
}
} // rr != 0
- // Rook pawns are a special case: They are sometimes worse, and
- // sometimes better than other passed pawns. It is difficult to find
- // good rules for determining whether they are good or bad. For now,
- // we try the following: Increase the value for rook pawns if the
- // other side has no pieces apart from a knight, and decrease the
- // value if the other side has a rook or queen.
- if (file_of(s) == FILE_A || file_of(s) == FILE_H)
- {
- if (pos.non_pawn_material(Them) <= KnightValueMg)
- ebonus += ebonus / 4;
-
- else if (pos.pieces(Them, ROOK, QUEEN))
- ebonus -= ebonus / 4;
- }
-
if (pos.count(Us) < pos.count(Them))
ebonus += ebonus / 4;
@@ -739,9 +671,9 @@ namespace {
Thread* thisThread = pos.this_thread();
// Initialize score by reading the incrementally updated scores included
- // in the position object (material + piece square tables) and adding a
- // Tempo bonus. Score is computed from the point of view of white.
- score = pos.psq_score() + (pos.side_to_move() == WHITE ? Tempo : -Tempo);
+ // in the position object (material + piece square tables).
+ // Score is computed from the point of view of white.
+ score = pos.psq_score();
// Probe the material hash table
ei.mi = Material::probe(pos, thisThread->materialTable, thisThread->endgames);
@@ -763,7 +695,7 @@ namespace {
ei.attackedBy[WHITE][ALL_PIECES] |= ei.attackedBy[WHITE][KING];
ei.attackedBy[BLACK][ALL_PIECES] |= ei.attackedBy[BLACK][KING];
- // Do not include in mobility squares protected by enemy pawns or occupied by our pieces
+ // Do not include in mobility squares protected by enemy pawns or occupied by our pawns or king
Bitboard mobilityArea[] = { ~(ei.attackedBy[BLACK][PAWN] | pos.pieces(WHITE, PAWN, KING)),
~(ei.attackedBy[WHITE][PAWN] | pos.pieces(BLACK, PAWN, KING)) };
@@ -822,7 +754,11 @@ namespace {
sf = ScaleFactor(50 * sf / SCALE_FACTOR_NORMAL);
}
- Value v = interpolate(score, ei.mi->game_phase(), sf);
+ // Interpolate between a middlegame and a (scaled by 'sf') endgame score
+ Value v = mg_value(score) * int(ei.mi->game_phase())
+ + eg_value(score) * int(PHASE_MIDGAME - ei.mi->game_phase()) * sf / SCALE_FACTOR_NORMAL;
+
+ v /= int(PHASE_MIDGAME);
// In case of tracing add all single evaluation contributions for both white and black
if (Trace)
@@ -889,7 +825,7 @@ namespace {
<< " | MG EG | MG EG | MG EG \n"
<< "---------------------+-------------+-------------+-------------\n";
- format_row(ss, "Material, PST, Tempo", PST);
+ format_row(ss, "Material, PST", PST);
format_row(ss, "Material imbalance", IMBALANCE);
format_row(ss, "Pawns", PAWN);
format_row(ss, "Knights", KNIGHT);
@@ -919,7 +855,7 @@ namespace Eval {
/// of the position always from the point of view of the side to move.
Value evaluate(const Position& pos) {
- return do_evaluate(pos);
+ return do_evaluate(pos) + Tempo;
}
@@ -937,22 +873,13 @@ namespace Eval {
void init() {
- Weights[Mobility] = weight_option("Mobility (Midgame)", "Mobility (Endgame)", WeightsInternal[Mobility]);
- Weights[PawnStructure] = weight_option("Pawn Structure (Midgame)", "Pawn Structure (Endgame)", WeightsInternal[PawnStructure]);
- Weights[PassedPawns] = weight_option("Passed Pawns (Midgame)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]);
- Weights[Space] = weight_option("Space", "Space", WeightsInternal[Space]);
- Weights[KingDangerUs] = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]);
- Weights[KingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]);
-
- const int MaxSlope = 30;
- const int Peak = 1280;
+ const double MaxSlope = 30;
+ const double Peak = 1280;
for (int t = 0, i = 1; i < 100; ++i)
{
- t = std::min(Peak, std::min(int(0.4 * i * i), t + MaxSlope));
-
- KingDanger[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]);
- KingDanger[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]);
+ t = int(std::min(Peak, std::min(0.4 * i * i, t + MaxSlope)));
+ KingDanger[i] = apply_weight(make_score(t, 0), Weights[KingSafety]);
}
}