Assorted renaming in evaluation
And some reshuffle too. No functional change.sf_4_base
parent
d8b266af8b
commit
46409a7852
337
src/evaluate.cpp
337
src/evaluate.cpp
|
@ -31,6 +31,20 @@
|
|||
|
||||
namespace {
|
||||
|
||||
enum ExtendedPieceType { // Used for tracing
|
||||
PST = 8, IMBALANCE, MOBILITY, THREAT, PASSED, UNSTOPPABLE, SPACE, TOTAL
|
||||
};
|
||||
|
||||
namespace Tracing {
|
||||
|
||||
Score scores[COLOR_NB][TOTAL + 1];
|
||||
std::stringstream stream;
|
||||
|
||||
void add(int idx, Score term_w, Score term_b = SCORE_ZERO);
|
||||
void row(const char* name, int idx);
|
||||
std::string do_trace(const Position& pos);
|
||||
}
|
||||
|
||||
// Struct EvalInfo contains various information computed and collected
|
||||
// by the evaluation functions.
|
||||
struct EvalInfo {
|
||||
|
@ -91,9 +105,9 @@ namespace {
|
|||
S(289, 344), S(233, 201), S(221, 273), S(46, 0), S(271, 0), S(307, 0)
|
||||
};
|
||||
|
||||
// MobilityBonus[PieceType][attacked] contains mobility bonuses for middle and
|
||||
// end game, indexed by piece type and number of attacked squares not occupied
|
||||
// by friendly pieces.
|
||||
// MobilityBonus[PieceType][attacked] contains bonuses for middle and end
|
||||
// game, indexed by piece type and number of attacked squares not occupied by
|
||||
// friendly pieces.
|
||||
const Score MobilityBonus[][32] = {
|
||||
{}, {},
|
||||
{ S(-35,-30), S(-22,-20), S(-9,-10), S( 3, 0), S(15, 10), S(27, 20), // Knights
|
||||
|
@ -112,9 +126,9 @@ namespace {
|
|||
S( 25, 41), S( 25, 41) }
|
||||
};
|
||||
|
||||
// OutpostBonus[PieceType][Square] contains outpost bonuses of knights and
|
||||
// bishops, indexed by piece type and square (from white's point of view).
|
||||
const Value OutpostBonus[][SQUARE_NB] = {
|
||||
// Outpost[PieceType][Square] contains bonuses of knights and bishops, indexed
|
||||
// by piece type and square (from white's point of view).
|
||||
const Value Outpost[][SQUARE_NB] = {
|
||||
{
|
||||
// A B C D E F G H
|
||||
V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // Knights
|
||||
|
@ -132,9 +146,9 @@ namespace {
|
|||
V(0), V(5), V(8), V(8), V(8), V(8), V(5), V(0) }
|
||||
};
|
||||
|
||||
// ThreatBonus[attacking][attacked] contains threat bonuses according to
|
||||
// which piece type attacks which one.
|
||||
const Score ThreatBonus[][PIECE_TYPE_NB] = {
|
||||
// Threat[attacking][attacked] contains bonuses according to which piece
|
||||
// type attacks which one.
|
||||
const Score Threat[][PIECE_TYPE_NB] = {
|
||||
{}, {},
|
||||
{ S(0, 0), S( 7, 39), S( 0, 0), S(24, 49), S(41,100), S(41,100) }, // KNIGHT
|
||||
{ S(0, 0), S( 7, 39), S(24, 49), S( 0, 0), S(41,100), S(41,100) }, // BISHOP
|
||||
|
@ -142,31 +156,30 @@ namespace {
|
|||
{ S(0, 0), S(15, 39), S(15, 39), S(15, 39), S(15, 39), S( 0, 0) } // QUEEN
|
||||
};
|
||||
|
||||
// ThreatenedByPawnPenalty[PieceType] contains a penalty according to which
|
||||
// piece type is attacked by an enemy pawn.
|
||||
const Score ThreatenedByPawnPenalty[] = {
|
||||
// ThreatenedByPawn[PieceType] contains a penalty according to which piece
|
||||
// type is attacked by an enemy pawn.
|
||||
const Score ThreatenedByPawn[] = {
|
||||
S(0, 0), S(0, 0), S(56, 70), S(56, 70), S(76, 99), S(86, 118)
|
||||
};
|
||||
|
||||
#undef S
|
||||
|
||||
const Score Tempo = make_score(24, 11);
|
||||
|
||||
const Score BishopPinBonus = make_score(66, 11);
|
||||
const Score RookOn7thBonus = make_score(11, 20);
|
||||
const Score QueenOn7thBonus = make_score( 3, 8);
|
||||
const Score RookOnPawnBonus = make_score(10, 28);
|
||||
const Score QueenOnPawnBonus = make_score( 4, 20);
|
||||
const Score RookOpenFileBonus = make_score(43, 21);
|
||||
const Score RookHalfOpenFileBonus = make_score(19, 10);
|
||||
const Score BishopPawnsPenalty = make_score( 8, 12);
|
||||
const Score UndefendedMinorPenalty = make_score(25, 10);
|
||||
const Score TrappedRookPenalty = make_score(90, 0);
|
||||
const Score Tempo = make_score(24, 11);
|
||||
const Score BishopPin = make_score(66, 11);
|
||||
const Score RookOn7th = make_score(11, 20);
|
||||
const Score QueenOn7th = make_score( 3, 8);
|
||||
const Score RookOnPawn = make_score(10, 28);
|
||||
const Score QueenOnPawn = make_score( 4, 20);
|
||||
const Score RookOpenFile = make_score(43, 21);
|
||||
const Score RookSemiopenFile = make_score(19, 10);
|
||||
const Score BishopPawns = make_score( 8, 12);
|
||||
const Score UndefendedMinor = make_score(25, 10);
|
||||
const Score TrappedRook = make_score(90, 0);
|
||||
|
||||
// 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
|
||||
// happen in Chess960 games.
|
||||
const Score TrappedBishopA1H1Penalty = make_score(50, 50);
|
||||
const Score TrappedBishopA1H1 = make_score(50, 50);
|
||||
|
||||
// The SpaceMask[Color] contains the area of the board which is considered
|
||||
// by the space evaluation. In the middle game, each side is given a bonus
|
||||
|
@ -182,24 +195,24 @@ namespace {
|
|||
};
|
||||
|
||||
// King danger constants and variables. The king danger scores are taken
|
||||
// from the KingDangerTable[]. Various little "meta-bonuses" measuring
|
||||
// from the KingDanger[]. Various little "meta-bonuses" measuring
|
||||
// the strength of the enemy attack are added up into an integer, which
|
||||
// is used as an index to KingDangerTable[].
|
||||
// is used as an index to KingDanger[].
|
||||
//
|
||||
// KingAttackWeights[PieceType] contains king attack weights by piece type
|
||||
const int KingAttackWeights[] = { 0, 0, 2, 2, 3, 5 };
|
||||
|
||||
// Bonuses for enemy's safe checks
|
||||
const int QueenContactCheckBonus = 6;
|
||||
const int RookContactCheckBonus = 4;
|
||||
const int QueenCheckBonus = 3;
|
||||
const int RookCheckBonus = 2;
|
||||
const int BishopCheckBonus = 1;
|
||||
const int KnightCheckBonus = 1;
|
||||
const int QueenContactCheck = 6;
|
||||
const int RookContactCheck = 4;
|
||||
const int QueenCheck = 3;
|
||||
const int RookCheck = 2;
|
||||
const int BishopCheck = 1;
|
||||
const int KnightCheck = 1;
|
||||
|
||||
// InitKingDanger[Square] contains penalties based on the position of the
|
||||
// KingExposed[Square] contains penalties based on the position of the
|
||||
// defending king, indexed by king's square (from white's point of view).
|
||||
const int InitKingDanger[] = {
|
||||
const int KingExposed[] = {
|
||||
2, 0, 2, 5, 5, 2, 0, 2,
|
||||
2, 2, 4, 8, 8, 4, 2, 2,
|
||||
7, 10, 12, 12, 12, 12, 10, 7,
|
||||
|
@ -210,19 +223,9 @@ namespace {
|
|||
15, 15, 15, 15, 15, 15, 15, 15
|
||||
};
|
||||
|
||||
// KingDangerTable[Color][attackUnits] contains the actual king danger
|
||||
// weighted scores, indexed by color and by a calculated integer number.
|
||||
Score KingDangerTable[COLOR_NB][128];
|
||||
|
||||
// TracedTerms[Color][PieceType || TracedType] contains a breakdown of the
|
||||
// evaluation terms, used when tracing.
|
||||
Score TracedScores[COLOR_NB][16];
|
||||
std::stringstream TraceStream;
|
||||
|
||||
enum TracedType {
|
||||
PST = 8, IMBALANCE = 9, MOBILITY = 10, THREAT = 11,
|
||||
PASSED = 12, UNSTOPPABLE = 13, SPACE = 14, TOTAL = 15
|
||||
};
|
||||
// KingDanger[Color][attackUnits] contains the actual king danger weighted
|
||||
// scores, indexed by color and by a calculated integer number.
|
||||
Score KingDanger[COLOR_NB][128];
|
||||
|
||||
// Function prototypes
|
||||
template<bool Trace>
|
||||
|
@ -252,8 +255,6 @@ namespace {
|
|||
Score apply_weight(Score v, Score w);
|
||||
Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight);
|
||||
double to_cp(Value v);
|
||||
void trace_add(int idx, Score term_w, Score term_b = SCORE_ZERO);
|
||||
void trace_row(const char* name, int idx);
|
||||
}
|
||||
|
||||
|
||||
|
@ -268,6 +269,14 @@ namespace Eval {
|
|||
}
|
||||
|
||||
|
||||
/// trace() is like evaluate() but instead of a value returns a string suitable
|
||||
/// to be print on stdout with the detailed descriptions and values of each
|
||||
/// evaluation term. Used mainly for debugging.
|
||||
std::string trace(const Position& pos) {
|
||||
return Tracing::do_trace(pos);
|
||||
}
|
||||
|
||||
|
||||
/// init() computes evaluation weights from the corresponding UCI parameters
|
||||
/// and setup king tables.
|
||||
|
||||
|
@ -287,57 +296,11 @@ namespace Eval {
|
|||
{
|
||||
t = std::min(Peak, std::min(int(0.4 * i * i), t + MaxSlope));
|
||||
|
||||
KingDangerTable[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]);
|
||||
KingDangerTable[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]);
|
||||
KingDanger[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]);
|
||||
KingDanger[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// trace() is like evaluate() but instead of a value returns a string suitable
|
||||
/// to be print on stdout with the detailed descriptions and values of each
|
||||
/// evaluation term. Used mainly for debugging.
|
||||
|
||||
std::string trace(const Position& pos) {
|
||||
|
||||
Value margin;
|
||||
std::string totals;
|
||||
|
||||
Search::RootColor = pos.side_to_move();
|
||||
|
||||
TraceStream.str("");
|
||||
TraceStream << std::showpoint << std::showpos << std::fixed << std::setprecision(2);
|
||||
memset(TracedScores, 0, 2 * 16 * sizeof(Score));
|
||||
|
||||
do_evaluate<true>(pos, margin);
|
||||
|
||||
totals = TraceStream.str();
|
||||
TraceStream.str("");
|
||||
|
||||
TraceStream << std::setw(21) << "Eval term " << "| White | Black | Total \n"
|
||||
<< " | MG EG | MG EG | MG EG \n"
|
||||
<< "---------------------+-------------+-------------+---------------\n";
|
||||
|
||||
trace_row("Material, PST, Tempo", PST);
|
||||
trace_row("Material imbalance", IMBALANCE);
|
||||
trace_row("Pawns", PAWN);
|
||||
trace_row("Knights", KNIGHT);
|
||||
trace_row("Bishops", BISHOP);
|
||||
trace_row("Rooks", ROOK);
|
||||
trace_row("Queens", QUEEN);
|
||||
trace_row("Mobility", MOBILITY);
|
||||
trace_row("King safety", KING);
|
||||
trace_row("Threats", THREAT);
|
||||
trace_row("Passed pawns", PASSED);
|
||||
trace_row("Unstoppable pawns", UNSTOPPABLE);
|
||||
trace_row("Space", SPACE);
|
||||
|
||||
TraceStream << "---------------------+-------------+-------------+---------------\n";
|
||||
trace_row("Total", TOTAL);
|
||||
TraceStream << totals;
|
||||
|
||||
return TraceStream.str();
|
||||
}
|
||||
|
||||
} // namespace Eval
|
||||
|
||||
|
||||
|
@ -443,21 +406,21 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
// In case of tracing add all single evaluation contributions for both white and black
|
||||
if (Trace)
|
||||
{
|
||||
trace_add(PST, pos.psq_score());
|
||||
trace_add(IMBALANCE, ei.mi->material_value());
|
||||
trace_add(PAWN, ei.pi->pawns_value());
|
||||
trace_add(UNSTOPPABLE, evaluate_unstoppable_pawns(pos, ei));
|
||||
Tracing::add(PST, pos.psq_score());
|
||||
Tracing::add(IMBALANCE, ei.mi->material_value());
|
||||
Tracing::add(PAWN, ei.pi->pawns_value());
|
||||
Tracing::add(UNSTOPPABLE, evaluate_unstoppable_pawns(pos, ei));
|
||||
Score w = make_score(ei.mi->space_weight() * evaluate_space<WHITE>(pos, ei), 0);
|
||||
Score b = make_score(ei.mi->space_weight() * evaluate_space<BLACK>(pos, ei), 0);
|
||||
trace_add(SPACE, apply_weight(w, Weights[Space]), apply_weight(b, Weights[Space]));
|
||||
trace_add(TOTAL, score);
|
||||
TraceStream << "\nUncertainty margin: White: " << to_cp(margins[WHITE])
|
||||
<< ", Black: " << to_cp(margins[BLACK])
|
||||
<< "\nScaling: " << std::noshowpos
|
||||
<< std::setw(6) << 100.0 * ei.mi->game_phase() / 128.0 << "% MG, "
|
||||
<< std::setw(6) << 100.0 * (1.0 - ei.mi->game_phase() / 128.0) << "% * "
|
||||
<< std::setw(6) << (100.0 * sf) / SCALE_FACTOR_NORMAL << "% EG.\n"
|
||||
<< "Total evaluation: " << to_cp(v);
|
||||
Tracing::add(SPACE, apply_weight(w, Weights[Space]), apply_weight(b, Weights[Space]));
|
||||
Tracing::add(TOTAL, score);
|
||||
Tracing::stream << "\nUncertainty margin: White: " << to_cp(margins[WHITE])
|
||||
<< ", Black: " << to_cp(margins[BLACK])
|
||||
<< "\nScaling: " << std::noshowpos
|
||||
<< std::setw(6) << 100.0 * ei.mi->game_phase() / 128.0 << "% MG, "
|
||||
<< std::setw(6) << 100.0 * (1.0 - ei.mi->game_phase() / 128.0) << "% * "
|
||||
<< std::setw(6) << (100.0 * sf) / SCALE_FACTOR_NORMAL << "% EG.\n"
|
||||
<< "Total evaluation: " << to_cp(v);
|
||||
}
|
||||
|
||||
return pos.side_to_move() == WHITE ? v : -v;
|
||||
|
@ -498,7 +461,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
assert (Piece == BISHOP || Piece == KNIGHT);
|
||||
|
||||
// Initial bonus based on square
|
||||
Value bonus = OutpostBonus[Piece == BISHOP][relative_square(Us, s)];
|
||||
Value bonus = Outpost[Piece == BISHOP][relative_square(Us, s)];
|
||||
|
||||
// Increase bonus if supported by pawn, especially if the opponent has
|
||||
// no minor piece which can exchange the outpost piece.
|
||||
|
@ -552,18 +515,18 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
// Decrease score if we are attacked by an enemy pawn. Remaining part
|
||||
// of threat evaluation must be done later when we have full attack info.
|
||||
if (ei.attackedBy[Them][PAWN] & s)
|
||||
score -= ThreatenedByPawnPenalty[Piece];
|
||||
score -= ThreatenedByPawn[Piece];
|
||||
|
||||
// Otherwise give a bonus if we are a bishop and can pin a piece or can
|
||||
// give a discovered check through an x-ray attack.
|
||||
else if ( Piece == BISHOP
|
||||
&& (PseudoAttacks[Piece][pos.king_square(Them)] & s)
|
||||
&& !more_than_one(BetweenBB[s][pos.king_square(Them)] & pos.pieces()))
|
||||
score += BishopPinBonus;
|
||||
score += BishopPin;
|
||||
|
||||
// Penalty for bishop with same coloured pawns
|
||||
if (Piece == BISHOP)
|
||||
score -= BishopPawnsPenalty * ei.pi->pawns_on_same_color_squares(Us, s);
|
||||
score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s);
|
||||
|
||||
// Bishop and knight outposts squares
|
||||
if ( (Piece == BISHOP || Piece == KNIGHT)
|
||||
|
@ -576,22 +539,22 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
// Major piece 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 += Piece == ROOK ? RookOn7thBonus : QueenOn7thBonus;
|
||||
score += Piece == ROOK ? RookOn7th : QueenOn7th;
|
||||
|
||||
// Major piece attacking enemy pawns on the same rank
|
||||
Bitboard pawns = pos.pieces(Them, PAWN) & rank_bb(s);
|
||||
if (pawns)
|
||||
score += popcount<Max15>(pawns) * (Piece == ROOK ? RookOnPawnBonus : QueenOnPawnBonus);
|
||||
score += popcount<Max15>(pawns) * (Piece == ROOK ? RookOnPawn : QueenOnPawn);
|
||||
}
|
||||
|
||||
// Special extra evaluation for rooks
|
||||
if (Piece == ROOK)
|
||||
{
|
||||
// Give a bonus for a rook on a open or half-open file
|
||||
if (ei.pi->half_open(Us, file_of(s)))
|
||||
score += ei.pi->half_open(Them, file_of(s)) ? RookOpenFileBonus
|
||||
: RookHalfOpenFileBonus;
|
||||
if (mob > 6 || ei.pi->half_open(Us, file_of(s)))
|
||||
// Give a bonus for a rook on a open or semi-open file
|
||||
if (ei.pi->semiopen(Us, file_of(s)))
|
||||
score += ei.pi->semiopen(Them, file_of(s)) ? RookOpenFile : RookSemiopenFile;
|
||||
|
||||
if (mob > 6 || ei.pi->semiopen(Us, file_of(s)))
|
||||
continue;
|
||||
|
||||
Square ksq = pos.king_square(Us);
|
||||
|
@ -600,8 +563,8 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
// king has lost right to castle.
|
||||
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->half_open_on_side(Us, file_of(ksq), file_of(ksq) < FILE_E))
|
||||
score -= (TrappedRookPenalty - make_score(mob * 8, 0)) * (pos.can_castle(Us) ? 1 : 2);
|
||||
&& !ei.pi->semiopen_on_side(Us, file_of(ksq), file_of(ksq) < FILE_E))
|
||||
score -= (TrappedRook - make_score(mob * 8, 0)) * (pos.can_castle(Us) ? 1 : 2);
|
||||
}
|
||||
|
||||
// An important Chess960 pattern: A cornered bishop blocked by a friendly
|
||||
|
@ -614,14 +577,14 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
const enum Piece P = make_piece(Us, PAWN);
|
||||
Square d = pawn_push(Us) + (file_of(s) == FILE_A ? DELTA_E : DELTA_W);
|
||||
if (pos.piece_on(s + d) == P)
|
||||
score -= !pos.is_empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1Penalty * 4
|
||||
: pos.piece_on(s + d + d) == P ? TrappedBishopA1H1Penalty * 2
|
||||
: TrappedBishopA1H1Penalty;
|
||||
score -= !pos.is_empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4
|
||||
: pos.piece_on(s + d + d) == P ? TrappedBishopA1H1 * 2
|
||||
: TrappedBishopA1H1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Trace)
|
||||
TracedScores[Us][Piece] = score;
|
||||
Tracing::scores[Us][Piece] = score;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
@ -643,7 +606,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
& ~ei.attackedBy[Them][ALL_PIECES];
|
||||
|
||||
if (undefendedMinors)
|
||||
score += UndefendedMinorPenalty;
|
||||
score += UndefendedMinor;
|
||||
|
||||
// Enemy pieces not defended by a pawn and under our attack
|
||||
weakEnemies = pos.pieces(Them)
|
||||
|
@ -660,11 +623,11 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
if (b)
|
||||
for (PieceType pt2 = PAWN; pt2 < KING; pt2++)
|
||||
if (b & pos.pieces(pt2))
|
||||
score += ThreatBonus[pt1][pt2];
|
||||
score += Threat[pt1][pt2];
|
||||
}
|
||||
|
||||
if (Trace)
|
||||
TracedScores[Us][THREAT] = score;
|
||||
Tracing::scores[Us][THREAT] = score;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
@ -693,7 +656,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
| ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK]
|
||||
| ei.attackedBy[Us][QUEEN] | ei.attackedBy[Us][KING];
|
||||
if (Trace)
|
||||
TracedScores[Us][MOBILITY] = apply_weight(mobility, Weights[Mobility]);
|
||||
Tracing::scores[Us][MOBILITY] = apply_weight(mobility, Weights[Mobility]);
|
||||
|
||||
return score;
|
||||
}
|
||||
|
@ -726,13 +689,13 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
| ei.attackedBy[Us][QUEEN]);
|
||||
|
||||
// Initialize the 'attackUnits' variable, which is used later on as an
|
||||
// index to the KingDangerTable[] array. The initial value is based on
|
||||
// the number and types of the enemy's attacking pieces, the number of
|
||||
// index to the KingDanger[] array. The initial value is based on the
|
||||
// number and types of the enemy's attacking pieces, the number of
|
||||
// attacked and undefended squares around our king, the square of the
|
||||
// king, and the quality of the pawn shelter.
|
||||
attackUnits = std::min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
|
||||
+ 3 * (ei.kingAdjacentZoneAttacksCount[Them] + popcount<Max15>(undefended))
|
||||
+ InitKingDanger[relative_square(Us, ksq)]
|
||||
+ KingExposed[relative_square(Us, ksq)]
|
||||
- mg_value(score) / 32;
|
||||
|
||||
// Analyse enemy's safe queen contact checks. First find undefended
|
||||
|
@ -744,7 +707,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
b &= ( ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT]
|
||||
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]);
|
||||
if (b)
|
||||
attackUnits += QueenContactCheckBonus
|
||||
attackUnits += QueenContactCheck
|
||||
* popcount<Max15>(b)
|
||||
* (Them == pos.side_to_move() ? 2 : 1);
|
||||
}
|
||||
|
@ -762,7 +725,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
b &= ( ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT]
|
||||
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][QUEEN]);
|
||||
if (b)
|
||||
attackUnits += RookContactCheckBonus
|
||||
attackUnits += RookContactCheck
|
||||
* popcount<Max15>(b)
|
||||
* (Them == pos.side_to_move() ? 2 : 1);
|
||||
}
|
||||
|
@ -776,37 +739,37 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
// Enemy queen safe checks
|
||||
b = (b1 | b2) & ei.attackedBy[Them][QUEEN];
|
||||
if (b)
|
||||
attackUnits += QueenCheckBonus * popcount<Max15>(b);
|
||||
attackUnits += QueenCheck * popcount<Max15>(b);
|
||||
|
||||
// Enemy rooks safe checks
|
||||
b = b1 & ei.attackedBy[Them][ROOK];
|
||||
if (b)
|
||||
attackUnits += RookCheckBonus * popcount<Max15>(b);
|
||||
attackUnits += RookCheck * popcount<Max15>(b);
|
||||
|
||||
// Enemy bishops safe checks
|
||||
b = b2 & ei.attackedBy[Them][BISHOP];
|
||||
if (b)
|
||||
attackUnits += BishopCheckBonus * popcount<Max15>(b);
|
||||
attackUnits += BishopCheck * popcount<Max15>(b);
|
||||
|
||||
// Enemy knights safe checks
|
||||
b = pos.attacks_from<KNIGHT>(ksq) & ei.attackedBy[Them][KNIGHT] & safe;
|
||||
if (b)
|
||||
attackUnits += KnightCheckBonus * popcount<Max15>(b);
|
||||
attackUnits += KnightCheck * popcount<Max15>(b);
|
||||
|
||||
// To index KingDangerTable[] attackUnits must be in [0, 99] range
|
||||
// To index KingDanger[] attackUnits must be in [0, 99] range
|
||||
attackUnits = std::min(99, std::max(0, attackUnits));
|
||||
|
||||
// Finally, extract the king danger score from the KingDangerTable[]
|
||||
// Finally, extract the king danger score from the KingDanger[]
|
||||
// array and subtract the score from evaluation. Set also margins[]
|
||||
// value that will be used for pruning because this value can sometimes
|
||||
// be very big, and so capturing a single attacking piece can therefore
|
||||
// result in a score change far bigger than the value of the captured piece.
|
||||
score -= KingDangerTable[Us == Search::RootColor][attackUnits];
|
||||
margins[Us] += mg_value(KingDangerTable[Us == Search::RootColor][attackUnits]);
|
||||
score -= KingDanger[Us == Search::RootColor][attackUnits];
|
||||
margins[Us] += mg_value(KingDanger[Us == Search::RootColor][attackUnits]);
|
||||
}
|
||||
|
||||
if (Trace)
|
||||
TracedScores[Us][KING] = score;
|
||||
Tracing::scores[Us][KING] = score;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
@ -907,7 +870,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
}
|
||||
|
||||
if (Trace)
|
||||
TracedScores[Us][PASSED] = apply_weight(score, Weights[PassedPawns]);
|
||||
Tracing::scores[Us][PASSED] = apply_weight(score, Weights[PassedPawns]);
|
||||
|
||||
// Add the scores to the middle game and endgame eval
|
||||
return apply_weight(score, Weights[PassedPawns]);
|
||||
|
@ -1140,41 +1103,75 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
}
|
||||
|
||||
|
||||
// A couple of little helpers used by tracing code, to_cp() converts a value to
|
||||
// a double in centipawns scale, trace_add() stores white and black scores.
|
||||
// Tracing functions definitions
|
||||
|
||||
double to_cp(Value v) { return double(v) / double(PawnValueMg); }
|
||||
|
||||
void trace_add(int idx, Score wScore, Score bScore) {
|
||||
void Tracing::add(int idx, Score wScore, Score bScore) {
|
||||
|
||||
TracedScores[WHITE][idx] = wScore;
|
||||
TracedScores[BLACK][idx] = bScore;
|
||||
scores[WHITE][idx] = wScore;
|
||||
scores[BLACK][idx] = bScore;
|
||||
}
|
||||
|
||||
void Tracing::row(const char* name, int idx) {
|
||||
|
||||
// trace_row() is an helper function used by tracing code to register the
|
||||
// values of a single evaluation term.
|
||||
|
||||
void trace_row(const char* name, int idx) {
|
||||
|
||||
Score wScore = TracedScores[WHITE][idx];
|
||||
Score bScore = TracedScores[BLACK][idx];
|
||||
Score wScore = scores[WHITE][idx];
|
||||
Score bScore = scores[BLACK][idx];
|
||||
|
||||
switch (idx) {
|
||||
case PST: case IMBALANCE: case PAWN: case UNSTOPPABLE: case TOTAL:
|
||||
TraceStream << std::setw(20) << name << " | --- --- | --- --- | "
|
||||
<< std::setw(6) << to_cp(mg_value(wScore)) << " "
|
||||
<< std::setw(6) << to_cp(eg_value(wScore)) << " \n";
|
||||
stream << std::setw(20) << name << " | --- --- | --- --- | "
|
||||
<< std::setw(6) << to_cp(mg_value(wScore)) << " "
|
||||
<< std::setw(6) << to_cp(eg_value(wScore)) << " \n";
|
||||
break;
|
||||
default:
|
||||
TraceStream << std::setw(20) << name << " | " << std::noshowpos
|
||||
<< std::setw(5) << to_cp(mg_value(wScore)) << " "
|
||||
<< std::setw(5) << to_cp(eg_value(wScore)) << " | "
|
||||
<< std::setw(5) << to_cp(mg_value(bScore)) << " "
|
||||
<< std::setw(5) << to_cp(eg_value(bScore)) << " | "
|
||||
<< std::showpos
|
||||
<< std::setw(6) << to_cp(mg_value(wScore - bScore)) << " "
|
||||
<< std::setw(6) << to_cp(eg_value(wScore - bScore)) << " \n";
|
||||
stream << std::setw(20) << name << " | " << std::noshowpos
|
||||
<< std::setw(5) << to_cp(mg_value(wScore)) << " "
|
||||
<< std::setw(5) << to_cp(eg_value(wScore)) << " | "
|
||||
<< std::setw(5) << to_cp(mg_value(bScore)) << " "
|
||||
<< std::setw(5) << to_cp(eg_value(bScore)) << " | "
|
||||
<< std::showpos
|
||||
<< std::setw(6) << to_cp(mg_value(wScore - bScore)) << " "
|
||||
<< std::setw(6) << to_cp(eg_value(wScore - bScore)) << " \n";
|
||||
}
|
||||
}
|
||||
|
||||
std::string Tracing::do_trace(const Position& pos) {
|
||||
|
||||
Search::RootColor = pos.side_to_move();
|
||||
|
||||
stream.str("");
|
||||
stream << std::showpoint << std::showpos << std::fixed << std::setprecision(2);
|
||||
memset(scores, 0, 2 * (TOTAL + 1) * sizeof(Score));
|
||||
|
||||
Value margin;
|
||||
do_evaluate<true>(pos, margin);
|
||||
|
||||
std::string totals = stream.str();
|
||||
stream.str("");
|
||||
|
||||
stream << std::setw(21) << "Eval term " << "| White | Black | Total \n"
|
||||
<< " | MG EG | MG EG | MG EG \n"
|
||||
<< "---------------------+-------------+-------------+---------------\n";
|
||||
|
||||
row("Material, PST, Tempo", PST);
|
||||
row("Material imbalance", IMBALANCE);
|
||||
row("Pawns", PAWN);
|
||||
row("Knights", KNIGHT);
|
||||
row("Bishops", BISHOP);
|
||||
row("Rooks", ROOK);
|
||||
row("Queens", QUEEN);
|
||||
row("Mobility", MOBILITY);
|
||||
row("King safety", KING);
|
||||
row("Threats", THREAT);
|
||||
row("Passed pawns", PASSED);
|
||||
row("Unstoppable pawns", UNSTOPPABLE);
|
||||
row("Space", SPACE);
|
||||
|
||||
stream << "---------------------+-------------+-------------+---------------\n";
|
||||
row("Total", TOTAL);
|
||||
stream << totals;
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ namespace {
|
|||
const int NoPawnsSF[4] = { 6, 12, 32 };
|
||||
|
||||
// Polynomial material balance parameters
|
||||
const Value RedundantQueenPenalty = Value(320);
|
||||
const Value RedundantRookPenalty = Value(554);
|
||||
const Value RedundantQueen = Value(320);
|
||||
const Value RedundantRook = Value(554);
|
||||
|
||||
// pair pawn knight bishop rook queen
|
||||
const int LinearCoefficients[6] = { 1617, -162, -1172, -190, 105, 26 };
|
||||
|
@ -109,8 +109,8 @@ namespace {
|
|||
// Redundancy of major pieces, formula based on Kaufman's paper
|
||||
// "The Evaluation of Material Imbalances in Chess"
|
||||
if (pieceCount[Us][ROOK] > 0)
|
||||
value -= RedundantRookPenalty * (pieceCount[Us][ROOK] - 1)
|
||||
+ RedundantQueenPenalty * pieceCount[Us][QUEEN];
|
||||
value -= RedundantRook * (pieceCount[Us][ROOK] - 1)
|
||||
+ RedundantQueen * pieceCount[Us][QUEEN];
|
||||
|
||||
// Second-degree polynomial material imbalance by Tord Romstad
|
||||
for (pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++)
|
||||
|
|
|
@ -30,34 +30,34 @@ namespace {
|
|||
#define S(mg, eg) make_score(mg, eg)
|
||||
|
||||
// Doubled pawn penalty by opposed flag and file
|
||||
const Score DoubledPawnPenalty[2][FILE_NB] = {
|
||||
const Score Doubled[2][FILE_NB] = {
|
||||
{ S(13, 43), S(20, 48), S(23, 48), S(23, 48),
|
||||
S(23, 48), S(23, 48), S(20, 48), S(13, 43) },
|
||||
{ S(13, 43), S(20, 48), S(23, 48), S(23, 48),
|
||||
S(23, 48), S(23, 48), S(20, 48), S(13, 43) }};
|
||||
|
||||
// Isolated pawn penalty by opposed flag and file
|
||||
const Score IsolatedPawnPenalty[2][FILE_NB] = {
|
||||
const Score Isolated[2][FILE_NB] = {
|
||||
{ S(37, 45), S(54, 52), S(60, 52), S(60, 52),
|
||||
S(60, 52), S(60, 52), S(54, 52), S(37, 45) },
|
||||
{ S(25, 30), S(36, 35), S(40, 35), S(40, 35),
|
||||
S(40, 35), S(40, 35), S(36, 35), S(25, 30) }};
|
||||
|
||||
// Backward pawn penalty by opposed flag and file
|
||||
const Score BackwardPawnPenalty[2][FILE_NB] = {
|
||||
const Score Backward[2][FILE_NB] = {
|
||||
{ S(30, 42), S(43, 46), S(49, 46), S(49, 46),
|
||||
S(49, 46), S(49, 46), S(43, 46), S(30, 42) },
|
||||
{ S(20, 28), S(29, 31), S(33, 31), S(33, 31),
|
||||
S(33, 31), S(33, 31), S(29, 31), S(20, 28) }};
|
||||
|
||||
// Pawn chain membership bonus by file
|
||||
const Score ChainBonus[FILE_NB] = {
|
||||
const Score ChainMember[FILE_NB] = {
|
||||
S(11,-1), S(13,-1), S(13,-1), S(14,-1),
|
||||
S(14,-1), S(13,-1), S(13,-1), S(11,-1)
|
||||
};
|
||||
|
||||
// Candidate passed pawn bonus by rank
|
||||
const Score CandidateBonus[RANK_NB] = {
|
||||
const Score CandidatePassed[RANK_NB] = {
|
||||
S( 0, 0), S( 6, 13), S(6,13), S(14,29),
|
||||
S(34,68), S(83,166), S(0, 0), S( 0, 0)
|
||||
};
|
||||
|
@ -101,8 +101,8 @@ namespace {
|
|||
f = file_of(s);
|
||||
r = rank_of(s);
|
||||
|
||||
// This file cannot be half open
|
||||
e->halfOpenFiles[Us] &= ~(1 << f);
|
||||
// This file cannot be semi-open
|
||||
e->semiopenFiles[Us] &= ~(1 << f);
|
||||
|
||||
// Our rank plus previous one. Used for chain detection
|
||||
b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1));
|
||||
|
@ -159,19 +159,19 @@ namespace {
|
|||
|
||||
// Score this pawn
|
||||
if (isolated)
|
||||
value -= IsolatedPawnPenalty[opposed][f];
|
||||
value -= Isolated[opposed][f];
|
||||
|
||||
if (doubled)
|
||||
value -= DoubledPawnPenalty[opposed][f];
|
||||
value -= Doubled[opposed][f];
|
||||
|
||||
if (backward)
|
||||
value -= BackwardPawnPenalty[opposed][f];
|
||||
value -= Backward[opposed][f];
|
||||
|
||||
if (chain)
|
||||
value += ChainBonus[f];
|
||||
value += ChainMember[f];
|
||||
|
||||
if (candidate)
|
||||
value += CandidateBonus[relative_rank(Us, s)];
|
||||
value += CandidatePassed[relative_rank(Us, s)];
|
||||
}
|
||||
|
||||
e->pawnsOnSquares[Us][BLACK] = popcount<Max15>(ourPawns & BlackSquares);
|
||||
|
@ -204,7 +204,7 @@ Entry* probe(const Position& pos, Table& entries) {
|
|||
e->key = key;
|
||||
e->passedPawns[WHITE] = e->passedPawns[BLACK] = 0;
|
||||
e->kingSquares[WHITE] = e->kingSquares[BLACK] = SQ_NONE;
|
||||
e->halfOpenFiles[WHITE] = e->halfOpenFiles[BLACK] = 0xFF;
|
||||
e->semiopenFiles[WHITE] = e->semiopenFiles[BLACK] = 0xFF;
|
||||
|
||||
Bitboard wPawns = pos.pieces(WHITE, PAWN);
|
||||
Bitboard bPawns = pos.pieces(BLACK, PAWN);
|
||||
|
|
|
@ -38,10 +38,10 @@ struct Entry {
|
|||
Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; }
|
||||
Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
|
||||
int pawns_on_same_color_squares(Color c, Square s) const { return pawnsOnSquares[c][!!(BlackSquares & s)]; }
|
||||
int half_open(Color c, File f) const { return halfOpenFiles[c] & (1 << int(f)); }
|
||||
int half_open_on_side(Color c, File f, bool left) const {
|
||||
int semiopen(Color c, File f) const { return semiopenFiles[c] & (1 << int(f)); }
|
||||
int semiopen_on_side(Color c, File f, bool left) const {
|
||||
|
||||
return halfOpenFiles[c] & (left ? ((1 << int(f)) - 1) : ~((1 << int(f+1)) - 1));
|
||||
return semiopenFiles[c] & (left ? ((1 << int(f)) - 1) : ~((1 << int(f+1)) - 1));
|
||||
}
|
||||
|
||||
template<Color Us>
|
||||
|
@ -64,7 +64,7 @@ struct Entry {
|
|||
int minKPdistance[COLOR_NB];
|
||||
int castleRights[COLOR_NB];
|
||||
Score value;
|
||||
int halfOpenFiles[COLOR_NB];
|
||||
int semiopenFiles[COLOR_NB];
|
||||
Score kingSafety[COLOR_NB];
|
||||
int pawnsOnSquares[COLOR_NB][COLOR_NB];
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue