1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-07-11 19:49:14 +00:00

Assorted renaming in evaluation

And some reshuffle too.

No functional change.
This commit is contained in:
Marco Costalba 2013-06-01 11:48:38 +02:00
parent d8b266af8b
commit 46409a7852
4 changed files with 188 additions and 191 deletions

View file

@ -31,6 +31,20 @@
namespace { 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 // Struct EvalInfo contains various information computed and collected
// by the evaluation functions. // by the evaluation functions.
struct EvalInfo { 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) 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 // MobilityBonus[PieceType][attacked] contains bonuses for middle and end
// end game, indexed by piece type and number of attacked squares not occupied // game, indexed by piece type and number of attacked squares not occupied by
// by friendly pieces. // friendly pieces.
const Score MobilityBonus[][32] = { const Score MobilityBonus[][32] = {
{}, {}, {}, {},
{ S(-35,-30), S(-22,-20), S(-9,-10), S( 3, 0), S(15, 10), S(27, 20), // Knights { 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) } S( 25, 41), S( 25, 41) }
}; };
// OutpostBonus[PieceType][Square] contains outpost bonuses of knights and // Outpost[PieceType][Square] contains bonuses of knights and bishops, indexed
// bishops, indexed by piece type and square (from white's point of view). // by piece type and square (from white's point of view).
const Value OutpostBonus[][SQUARE_NB] = { const Value Outpost[][SQUARE_NB] = {
{ {
// A B C D E F G H // 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 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) } V(0), V(5), V(8), V(8), V(8), V(8), V(5), V(0) }
}; };
// ThreatBonus[attacking][attacked] contains threat bonuses according to // Threat[attacking][attacked] contains bonuses according to which piece
// which piece type attacks which one. // type attacks which one.
const Score ThreatBonus[][PIECE_TYPE_NB] = { 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( 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 { 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 { 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 // ThreatenedByPawn[PieceType] contains a penalty according to which piece
// piece type is attacked by an enemy pawn. // type is attacked by an enemy pawn.
const Score ThreatenedByPawnPenalty[] = { const Score ThreatenedByPawn[] = {
S(0, 0), S(0, 0), S(56, 70), S(56, 70), S(76, 99), S(86, 118) S(0, 0), S(0, 0), S(56, 70), S(56, 70), S(76, 99), S(86, 118)
}; };
#undef S #undef S
const Score Tempo = make_score(24, 11); const Score Tempo = make_score(24, 11);
const Score BishopPin = make_score(66, 11);
const Score BishopPinBonus = make_score(66, 11); const Score RookOn7th = make_score(11, 20);
const Score RookOn7thBonus = make_score(11, 20); const Score QueenOn7th = make_score( 3, 8);
const Score QueenOn7thBonus = make_score( 3, 8); const Score RookOnPawn = make_score(10, 28);
const Score RookOnPawnBonus = make_score(10, 28); const Score QueenOnPawn = make_score( 4, 20);
const Score QueenOnPawnBonus = make_score( 4, 20); const Score RookOpenFile = make_score(43, 21);
const Score RookOpenFileBonus = make_score(43, 21); const Score RookSemiopenFile = make_score(19, 10);
const Score RookHalfOpenFileBonus = make_score(19, 10); const Score BishopPawns = make_score( 8, 12);
const Score BishopPawnsPenalty = make_score( 8, 12); const Score UndefendedMinor = make_score(25, 10);
const Score UndefendedMinorPenalty = make_score(25, 10); const Score TrappedRook = make_score(90, 0);
const Score TrappedRookPenalty = make_score(90, 0);
// Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by // 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 // a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
// happen in Chess960 games. // 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 // 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 // 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 // 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 // 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 // KingAttackWeights[PieceType] contains king attack weights by piece type
const int KingAttackWeights[] = { 0, 0, 2, 2, 3, 5 }; const int KingAttackWeights[] = { 0, 0, 2, 2, 3, 5 };
// Bonuses for enemy's safe checks // Bonuses for enemy's safe checks
const int QueenContactCheckBonus = 6; const int QueenContactCheck = 6;
const int RookContactCheckBonus = 4; const int RookContactCheck = 4;
const int QueenCheckBonus = 3; const int QueenCheck = 3;
const int RookCheckBonus = 2; const int RookCheck = 2;
const int BishopCheckBonus = 1; const int BishopCheck = 1;
const int KnightCheckBonus = 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). // 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, 0, 2, 5, 5, 2, 0, 2,
2, 2, 4, 8, 8, 4, 2, 2, 2, 2, 4, 8, 8, 4, 2, 2,
7, 10, 12, 12, 12, 12, 10, 7, 7, 10, 12, 12, 12, 12, 10, 7,
@ -210,19 +223,9 @@ namespace {
15, 15, 15, 15, 15, 15, 15, 15 15, 15, 15, 15, 15, 15, 15, 15
}; };
// KingDangerTable[Color][attackUnits] contains the actual king danger // KingDanger[Color][attackUnits] contains the actual king danger weighted
// weighted scores, indexed by color and by a calculated integer number. // scores, indexed by color and by a calculated integer number.
Score KingDangerTable[COLOR_NB][128]; Score KingDanger[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
};
// Function prototypes // Function prototypes
template<bool Trace> template<bool Trace>
@ -252,8 +255,6 @@ namespace {
Score apply_weight(Score v, Score w); Score apply_weight(Score v, Score w);
Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight); Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight);
double to_cp(Value v); 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 /// init() computes evaluation weights from the corresponding UCI parameters
/// and setup king tables. /// and setup king tables.
@ -287,57 +296,11 @@ namespace Eval {
{ {
t = std::min(Peak, std::min(int(0.4 * i * i), t + MaxSlope)); t = std::min(Peak, std::min(int(0.4 * i * i), t + MaxSlope));
KingDangerTable[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]); KingDanger[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]);
KingDangerTable[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]); 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 } // 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 // In case of tracing add all single evaluation contributions for both white and black
if (Trace) if (Trace)
{ {
trace_add(PST, pos.psq_score()); Tracing::add(PST, pos.psq_score());
trace_add(IMBALANCE, ei.mi->material_value()); Tracing::add(IMBALANCE, ei.mi->material_value());
trace_add(PAWN, ei.pi->pawns_value()); Tracing::add(PAWN, ei.pi->pawns_value());
trace_add(UNSTOPPABLE, evaluate_unstoppable_pawns(pos, ei)); Tracing::add(UNSTOPPABLE, evaluate_unstoppable_pawns(pos, ei));
Score w = make_score(ei.mi->space_weight() * evaluate_space<WHITE>(pos, ei), 0); 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); 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])); Tracing::add(SPACE, apply_weight(w, Weights[Space]), apply_weight(b, Weights[Space]));
trace_add(TOTAL, score); Tracing::add(TOTAL, score);
TraceStream << "\nUncertainty margin: White: " << to_cp(margins[WHITE]) Tracing::stream << "\nUncertainty margin: White: " << to_cp(margins[WHITE])
<< ", Black: " << to_cp(margins[BLACK]) << ", Black: " << to_cp(margins[BLACK])
<< "\nScaling: " << std::noshowpos << "\nScaling: " << std::noshowpos
<< std::setw(6) << 100.0 * ei.mi->game_phase() / 128.0 << "% MG, " << 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 * (1.0 - ei.mi->game_phase() / 128.0) << "% * "
<< std::setw(6) << (100.0 * sf) / SCALE_FACTOR_NORMAL << "% EG.\n" << std::setw(6) << (100.0 * sf) / SCALE_FACTOR_NORMAL << "% EG.\n"
<< "Total evaluation: " << to_cp(v); << "Total evaluation: " << to_cp(v);
} }
return pos.side_to_move() == WHITE ? v : -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); assert (Piece == BISHOP || Piece == KNIGHT);
// Initial bonus based on square // 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 // Increase bonus if supported by pawn, especially if the opponent has
// no minor piece which can exchange the outpost piece. // 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 // 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. // of threat evaluation must be done later when we have full attack info.
if (ei.attackedBy[Them][PAWN] & s) 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 // 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. // give a discovered check through an x-ray attack.
else if ( Piece == BISHOP else if ( Piece == BISHOP
&& (PseudoAttacks[Piece][pos.king_square(Them)] & s) && (PseudoAttacks[Piece][pos.king_square(Them)] & s)
&& !more_than_one(BetweenBB[s][pos.king_square(Them)] & pos.pieces())) && !more_than_one(BetweenBB[s][pos.king_square(Them)] & pos.pieces()))
score += BishopPinBonus; score += BishopPin;
// Penalty for bishop with same coloured pawns // Penalty for bishop with same coloured pawns
if (Piece == BISHOP) 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 // Bishop and knight outposts squares
if ( (Piece == BISHOP || Piece == KNIGHT) 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 // Major piece on 7th rank and enemy king trapped on 8th
if ( relative_rank(Us, s) == RANK_7 if ( relative_rank(Us, s) == RANK_7
&& relative_rank(Us, pos.king_square(Them)) == RANK_8) && 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 // Major piece attacking enemy pawns on the same rank
Bitboard pawns = pos.pieces(Them, PAWN) & rank_bb(s); Bitboard pawns = pos.pieces(Them, PAWN) & rank_bb(s);
if (pawns) if (pawns)
score += popcount<Max15>(pawns) * (Piece == ROOK ? RookOnPawnBonus : QueenOnPawnBonus); score += popcount<Max15>(pawns) * (Piece == ROOK ? RookOnPawn : QueenOnPawn);
} }
// Special extra evaluation for rooks // Special extra evaluation for rooks
if (Piece == ROOK) if (Piece == ROOK)
{ {
// Give a bonus for a rook on a open or half-open file // Give a bonus for a rook on a open or semi-open file
if (ei.pi->half_open(Us, file_of(s))) if (ei.pi->semiopen(Us, file_of(s)))
score += ei.pi->half_open(Them, file_of(s)) ? RookOpenFileBonus score += ei.pi->semiopen(Them, file_of(s)) ? RookOpenFile : RookSemiopenFile;
: RookHalfOpenFileBonus;
if (mob > 6 || ei.pi->half_open(Us, file_of(s))) if (mob > 6 || ei.pi->semiopen(Us, file_of(s)))
continue; continue;
Square ksq = pos.king_square(Us); Square ksq = pos.king_square(Us);
@ -600,8 +563,8 @@ Value do_evaluate(const Position& pos, Value& margin) {
// king has lost right to castle. // king has lost right to castle.
if ( ((file_of(ksq) < FILE_E) == (file_of(s) < file_of(ksq))) if ( ((file_of(ksq) < FILE_E) == (file_of(s) < file_of(ksq)))
&& (rank_of(ksq) == rank_of(s) || relative_rank(Us, ksq) == RANK_1) && (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)) && !ei.pi->semiopen_on_side(Us, file_of(ksq), file_of(ksq) < FILE_E))
score -= (TrappedRookPenalty - make_score(mob * 8, 0)) * (pos.can_castle(Us) ? 1 : 2); score -= (TrappedRook - make_score(mob * 8, 0)) * (pos.can_castle(Us) ? 1 : 2);
} }
// An important Chess960 pattern: A cornered bishop blocked by a friendly // 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); const enum Piece P = make_piece(Us, PAWN);
Square d = pawn_push(Us) + (file_of(s) == FILE_A ? DELTA_E : DELTA_W); Square d = pawn_push(Us) + (file_of(s) == FILE_A ? DELTA_E : DELTA_W);
if (pos.piece_on(s + d) == P) if (pos.piece_on(s + d) == P)
score -= !pos.is_empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1Penalty * 4 score -= !pos.is_empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4
: pos.piece_on(s + d + d) == P ? TrappedBishopA1H1Penalty * 2 : pos.piece_on(s + d + d) == P ? TrappedBishopA1H1 * 2
: TrappedBishopA1H1Penalty; : TrappedBishopA1H1;
} }
} }
if (Trace) if (Trace)
TracedScores[Us][Piece] = score; Tracing::scores[Us][Piece] = score;
return score; return score;
} }
@ -643,7 +606,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
& ~ei.attackedBy[Them][ALL_PIECES]; & ~ei.attackedBy[Them][ALL_PIECES];
if (undefendedMinors) if (undefendedMinors)
score += UndefendedMinorPenalty; score += UndefendedMinor;
// Enemy pieces not defended by a pawn and under our attack // Enemy pieces not defended by a pawn and under our attack
weakEnemies = pos.pieces(Them) weakEnemies = pos.pieces(Them)
@ -660,11 +623,11 @@ Value do_evaluate(const Position& pos, Value& margin) {
if (b) if (b)
for (PieceType pt2 = PAWN; pt2 < KING; pt2++) for (PieceType pt2 = PAWN; pt2 < KING; pt2++)
if (b & pos.pieces(pt2)) if (b & pos.pieces(pt2))
score += ThreatBonus[pt1][pt2]; score += Threat[pt1][pt2];
} }
if (Trace) if (Trace)
TracedScores[Us][THREAT] = score; Tracing::scores[Us][THREAT] = score;
return 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][BISHOP] | ei.attackedBy[Us][ROOK]
| ei.attackedBy[Us][QUEEN] | ei.attackedBy[Us][KING]; | ei.attackedBy[Us][QUEEN] | ei.attackedBy[Us][KING];
if (Trace) if (Trace)
TracedScores[Us][MOBILITY] = apply_weight(mobility, Weights[Mobility]); Tracing::scores[Us][MOBILITY] = apply_weight(mobility, Weights[Mobility]);
return score; return score;
} }
@ -726,13 +689,13 @@ Value do_evaluate(const Position& pos, Value& margin) {
| ei.attackedBy[Us][QUEEN]); | ei.attackedBy[Us][QUEEN]);
// Initialize the 'attackUnits' variable, which is used later on as an // Initialize the 'attackUnits' variable, which is used later on as an
// index to the KingDangerTable[] array. The initial value is based on // index to the KingDanger[] array. The initial value is based on the
// the number and types of the enemy's attacking pieces, the number of // number and types of the enemy's attacking pieces, the number of
// attacked and undefended squares around our king, the square of the // attacked and undefended squares around our king, the square of the
// king, and the quality of the pawn shelter. // king, and the quality of the pawn shelter.
attackUnits = std::min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2) attackUnits = std::min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
+ 3 * (ei.kingAdjacentZoneAttacksCount[Them] + popcount<Max15>(undefended)) + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + popcount<Max15>(undefended))
+ InitKingDanger[relative_square(Us, ksq)] + KingExposed[relative_square(Us, ksq)]
- mg_value(score) / 32; - mg_value(score) / 32;
// Analyse enemy's safe queen contact checks. First find undefended // 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] b &= ( ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT]
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]); | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]);
if (b) if (b)
attackUnits += QueenContactCheckBonus attackUnits += QueenContactCheck
* popcount<Max15>(b) * popcount<Max15>(b)
* (Them == pos.side_to_move() ? 2 : 1); * (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] b &= ( ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT]
| ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][QUEEN]); | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][QUEEN]);
if (b) if (b)
attackUnits += RookContactCheckBonus attackUnits += RookContactCheck
* popcount<Max15>(b) * popcount<Max15>(b)
* (Them == pos.side_to_move() ? 2 : 1); * (Them == pos.side_to_move() ? 2 : 1);
} }
@ -776,37 +739,37 @@ Value do_evaluate(const Position& pos, Value& margin) {
// Enemy queen safe checks // Enemy queen safe checks
b = (b1 | b2) & ei.attackedBy[Them][QUEEN]; b = (b1 | b2) & ei.attackedBy[Them][QUEEN];
if (b) if (b)
attackUnits += QueenCheckBonus * popcount<Max15>(b); attackUnits += QueenCheck * popcount<Max15>(b);
// Enemy rooks safe checks // Enemy rooks safe checks
b = b1 & ei.attackedBy[Them][ROOK]; b = b1 & ei.attackedBy[Them][ROOK];
if (b) if (b)
attackUnits += RookCheckBonus * popcount<Max15>(b); attackUnits += RookCheck * popcount<Max15>(b);
// Enemy bishops safe checks // Enemy bishops safe checks
b = b2 & ei.attackedBy[Them][BISHOP]; b = b2 & ei.attackedBy[Them][BISHOP];
if (b) if (b)
attackUnits += BishopCheckBonus * popcount<Max15>(b); attackUnits += BishopCheck * popcount<Max15>(b);
// Enemy knights safe checks // Enemy knights safe checks
b = pos.attacks_from<KNIGHT>(ksq) & ei.attackedBy[Them][KNIGHT] & safe; b = pos.attacks_from<KNIGHT>(ksq) & ei.attackedBy[Them][KNIGHT] & safe;
if (b) 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)); 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[] // array and subtract the score from evaluation. Set also margins[]
// value that will be used for pruning because this value can sometimes // value that will be used for pruning because this value can sometimes
// be very big, and so capturing a single attacking piece can therefore // 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. // result in a score change far bigger than the value of the captured piece.
score -= KingDangerTable[Us == Search::RootColor][attackUnits]; score -= KingDanger[Us == Search::RootColor][attackUnits];
margins[Us] += mg_value(KingDangerTable[Us == Search::RootColor][attackUnits]); margins[Us] += mg_value(KingDanger[Us == Search::RootColor][attackUnits]);
} }
if (Trace) if (Trace)
TracedScores[Us][KING] = score; Tracing::scores[Us][KING] = score;
return score; return score;
} }
@ -907,7 +870,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
} }
if (Trace) 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 // Add the scores to the middle game and endgame eval
return apply_weight(score, Weights[PassedPawns]); 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 // Tracing functions definitions
// a double in centipawns scale, trace_add() stores white and black scores.
double to_cp(Value v) { return double(v) / double(PawnValueMg); } 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; scores[WHITE][idx] = wScore;
TracedScores[BLACK][idx] = bScore; 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 Score wScore = scores[WHITE][idx];
// values of a single evaluation term. Score bScore = scores[BLACK][idx];
void trace_row(const char* name, int idx) {
Score wScore = TracedScores[WHITE][idx];
Score bScore = TracedScores[BLACK][idx];
switch (idx) { switch (idx) {
case PST: case IMBALANCE: case PAWN: case UNSTOPPABLE: case TOTAL: case PST: case IMBALANCE: case PAWN: case UNSTOPPABLE: case TOTAL:
TraceStream << std::setw(20) << name << " | --- --- | --- --- | " stream << std::setw(20) << name << " | --- --- | --- --- | "
<< std::setw(6) << to_cp(mg_value(wScore)) << " " << std::setw(6) << to_cp(mg_value(wScore)) << " "
<< std::setw(6) << to_cp(eg_value(wScore)) << " \n"; << std::setw(6) << to_cp(eg_value(wScore)) << " \n";
break; break;
default: default:
TraceStream << std::setw(20) << name << " | " << std::noshowpos stream << std::setw(20) << name << " | " << std::noshowpos
<< std::setw(5) << to_cp(mg_value(wScore)) << " " << std::setw(5) << to_cp(mg_value(wScore)) << " "
<< std::setw(5) << to_cp(eg_value(wScore)) << " | " << std::setw(5) << to_cp(eg_value(wScore)) << " | "
<< std::setw(5) << to_cp(mg_value(bScore)) << " " << std::setw(5) << to_cp(mg_value(bScore)) << " "
<< std::setw(5) << to_cp(eg_value(bScore)) << " | " << std::setw(5) << to_cp(eg_value(bScore)) << " | "
<< std::showpos << std::showpos
<< std::setw(6) << to_cp(mg_value(wScore - bScore)) << " " << std::setw(6) << to_cp(mg_value(wScore - bScore)) << " "
<< std::setw(6) << to_cp(eg_value(wScore - bScore)) << " \n"; << 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();
}
} }

View file

@ -35,8 +35,8 @@ namespace {
const int NoPawnsSF[4] = { 6, 12, 32 }; const int NoPawnsSF[4] = { 6, 12, 32 };
// Polynomial material balance parameters // Polynomial material balance parameters
const Value RedundantQueenPenalty = Value(320); const Value RedundantQueen = Value(320);
const Value RedundantRookPenalty = Value(554); const Value RedundantRook = Value(554);
// pair pawn knight bishop rook queen // pair pawn knight bishop rook queen
const int LinearCoefficients[6] = { 1617, -162, -1172, -190, 105, 26 }; 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 // Redundancy of major pieces, formula based on Kaufman's paper
// "The Evaluation of Material Imbalances in Chess" // "The Evaluation of Material Imbalances in Chess"
if (pieceCount[Us][ROOK] > 0) if (pieceCount[Us][ROOK] > 0)
value -= RedundantRookPenalty * (pieceCount[Us][ROOK] - 1) value -= RedundantRook * (pieceCount[Us][ROOK] - 1)
+ RedundantQueenPenalty * pieceCount[Us][QUEEN]; + RedundantQueen * pieceCount[Us][QUEEN];
// Second-degree polynomial material imbalance by Tord Romstad // Second-degree polynomial material imbalance by Tord Romstad
for (pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++) for (pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++)

View file

@ -30,34 +30,34 @@ namespace {
#define S(mg, eg) make_score(mg, eg) #define S(mg, eg) make_score(mg, eg)
// Doubled pawn penalty by opposed flag and file // 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(13, 43), S(20, 48), S(23, 48), S(23, 48),
S(23, 48), S(23, 48), S(20, 48), S(13, 43) }, 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(13, 43), S(20, 48), S(23, 48), S(23, 48),
S(23, 48), S(23, 48), S(20, 48), S(13, 43) }}; S(23, 48), S(23, 48), S(20, 48), S(13, 43) }};
// Isolated pawn penalty by opposed flag and file // 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(37, 45), S(54, 52), S(60, 52), S(60, 52),
S(60, 52), S(60, 52), S(54, 52), S(37, 45) }, 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(25, 30), S(36, 35), S(40, 35), S(40, 35),
S(40, 35), S(40, 35), S(36, 35), S(25, 30) }}; S(40, 35), S(40, 35), S(36, 35), S(25, 30) }};
// Backward pawn penalty by opposed flag and file // 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(30, 42), S(43, 46), S(49, 46), S(49, 46),
S(49, 46), S(49, 46), S(43, 46), S(30, 42) }, 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(20, 28), S(29, 31), S(33, 31), S(33, 31),
S(33, 31), S(33, 31), S(29, 31), S(20, 28) }}; S(33, 31), S(33, 31), S(29, 31), S(20, 28) }};
// Pawn chain membership bonus by file // 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(11,-1), S(13,-1), S(13,-1), S(14,-1),
S(14,-1), S(13,-1), S(13,-1), S(11,-1) S(14,-1), S(13,-1), S(13,-1), S(11,-1)
}; };
// Candidate passed pawn bonus by rank // 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( 0, 0), S( 6, 13), S(6,13), S(14,29),
S(34,68), S(83,166), S(0, 0), S( 0, 0) S(34,68), S(83,166), S(0, 0), S( 0, 0)
}; };
@ -101,8 +101,8 @@ namespace {
f = file_of(s); f = file_of(s);
r = rank_of(s); r = rank_of(s);
// This file cannot be half open // This file cannot be semi-open
e->halfOpenFiles[Us] &= ~(1 << f); e->semiopenFiles[Us] &= ~(1 << f);
// Our rank plus previous one. Used for chain detection // Our rank plus previous one. Used for chain detection
b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1)); b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1));
@ -159,19 +159,19 @@ namespace {
// Score this pawn // Score this pawn
if (isolated) if (isolated)
value -= IsolatedPawnPenalty[opposed][f]; value -= Isolated[opposed][f];
if (doubled) if (doubled)
value -= DoubledPawnPenalty[opposed][f]; value -= Doubled[opposed][f];
if (backward) if (backward)
value -= BackwardPawnPenalty[opposed][f]; value -= Backward[opposed][f];
if (chain) if (chain)
value += ChainBonus[f]; value += ChainMember[f];
if (candidate) if (candidate)
value += CandidateBonus[relative_rank(Us, s)]; value += CandidatePassed[relative_rank(Us, s)];
} }
e->pawnsOnSquares[Us][BLACK] = popcount<Max15>(ourPawns & BlackSquares); e->pawnsOnSquares[Us][BLACK] = popcount<Max15>(ourPawns & BlackSquares);
@ -204,7 +204,7 @@ Entry* probe(const Position& pos, Table& entries) {
e->key = key; e->key = key;
e->passedPawns[WHITE] = e->passedPawns[BLACK] = 0; e->passedPawns[WHITE] = e->passedPawns[BLACK] = 0;
e->kingSquares[WHITE] = e->kingSquares[BLACK] = SQ_NONE; 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 wPawns = pos.pieces(WHITE, PAWN);
Bitboard bPawns = pos.pieces(BLACK, PAWN); Bitboard bPawns = pos.pieces(BLACK, PAWN);

View file

@ -38,10 +38,10 @@ struct Entry {
Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; } Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; }
Bitboard passed_pawns(Color c) const { return passedPawns[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 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 semiopen(Color c, File f) const { return semiopenFiles[c] & (1 << int(f)); }
int half_open_on_side(Color c, File f, bool left) const { 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> template<Color Us>
@ -64,7 +64,7 @@ struct Entry {
int minKPdistance[COLOR_NB]; int minKPdistance[COLOR_NB];
int castleRights[COLOR_NB]; int castleRights[COLOR_NB];
Score value; Score value;
int halfOpenFiles[COLOR_NB]; int semiopenFiles[COLOR_NB];
Score kingSafety[COLOR_NB]; Score kingSafety[COLOR_NB];
int pawnsOnSquares[COLOR_NB][COLOR_NB]; int pawnsOnSquares[COLOR_NB][COLOR_NB];
}; };