#include "material.h"
#include "pawns.h"
#include "thread.h"
-#include "ucioption.h"
namespace {
// kingAttackersWeight[color] is the sum of the "weight" of the pieces of the
// given color which attack a square in the kingRing of the enemy king. The
- // weights of the individual piece types are given by the variables
- // QueenAttackWeight, RookAttackWeight, BishopAttackWeight and
- // KnightAttackWeight in evaluate.cpp
+ // weights of the individual piece types are given by the elements in the
+ // KingAttackWeights array.
int kingAttackersWeight[COLOR_NB];
// kingAdjacentZoneAttacksCount[color] is the number of attacks to squares
V(0), V(5), V(8), V(8), V(8), V(8), V(5), V(0) }
};
- // Threat[attacking][attacked] contains bonuses according to which piece
- // type attacks which one.
- const Score Threat[][PIECE_TYPE_NB] = {
- { S(0, 0), S(0, 38), S(32, 45), S(32, 45), S(41,100), S(35,104) }, // Minor
- { S(0, 0), S(7, 28), S(20, 49), S(20, 49), S(8 , 42), S(23, 44) } // Major
+ // Threat[defended/weak][minor/major attacking][attacked PieceType] contains
+ // bonuses according to which piece type attacks which one.
+ const Score Threat[][2][PIECE_TYPE_NB] = {
+ { { S(0, 0), S( 0, 0), S(19, 37), S(24, 37), S(44, 97), S(35,106) }, // Defended Minor
+ { S(0, 0), S( 0, 0), S( 9, 14), S( 9, 14), S( 7, 14), S(24, 48) } }, // Defended Major
+ { { S(0, 0), S( 0,32), S(33, 41), S(31, 50), S(41,100), S(35,104) }, // Weak Minor
+ { S(0, 0), S( 0,27), S(26, 57), S(26, 57), S(0 , 43), S(23, 51) } } // Weak Major
};
// 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(80, 119), S(80, 119), S(117, 199), S(127, 218)
+ S(0, 0), S(0, 0), S(87, 118), S(84, 122), S(114, 203), S(121, 217)
};
// Assorted bonuses and penalties used by evaluation
- const Score KingOnOne = S(2 , 58);
- const Score KingOnMany = S(6 ,125);
- const Score RookOnPawn = S(10, 28);
+ const Score KingOnOne = S( 2, 58);
+ const Score KingOnMany = S( 6,125);
+ const Score RookOnPawn = S( 7, 27);
const Score RookOpenFile = S(43, 21);
const Score RookSemiOpenFile = S(19, 10);
const Score BishopPawns = S( 8, 12);
const Score MinorBehindPawn = S(16, 0);
const Score TrappedRook = S(92, 0);
const Score Unstoppable = S( 0, 20);
- const Score Hanging = S(23, 20);
+ const Score Hanging = S(31, 26);
// 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
// scores, indexed by a calculated integer number.
Score KingDanger[128];
- const int ScalePawnSpan[2] = { 38, 56 };
-
// apply_weight() weighs score 'v' by weight 'w' trying to prevent overflow
Score apply_weight(Score v, const Weight& w) {
return make_score(mg_value(v) * w.mg / 256, eg_value(v) * w.eg / 256);
ei.attackedBy[Us][ALL_PIECES] = ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us);
// Init king safety tables only if we are going to use them
- if (pos.non_pawn_material(Us) > QueenValueMg + PawnValueMg)
+ if (pos.non_pawn_material(Us) >= QueenValueMg)
{
ei.kingRing[Them] = b | shift_bb<Down>(b);
b &= ei.attackedBy[Us][PAWN];
return score;
}
- // max_threat() is a helper function to calculate the score of a set of threats.
- // The set of threatened pieces is in the "targets" parameter, and we return
- // the value of the threat on the biggest piece.
-
- template<Color Us> FORCE_INLINE
- Score max_threat(const Bitboard targets, const Position& pos, const Score threat_values[]) {
-
- const Color Them = (Us == WHITE ? BLACK : WHITE);
-
- PieceType threat = PAWN;
- if (targets & pos.pieces(Them, KNIGHT)) threat = KNIGHT;
- if (targets & pos.pieces(Them, BISHOP)) threat = BISHOP;
- if (targets & pos.pieces(Them, ROOK)) threat = ROOK;
- if (targets & pos.pieces(Them, QUEEN)) threat = QUEEN;
-
- return threat_values[threat];
- }
// evaluate_threats() assigns bonuses according to the type of attacking piece
// and the type of attacked one.
const Color Them = (Us == WHITE ? BLACK : WHITE);
- Bitboard b, weakEnemies, protectedEnemies;
- Score score = SCORE_ZERO;
+ enum { Defended, Weak };
enum { Minor, Major };
- // Protected enemies
- protectedEnemies = (pos.pieces(Them) ^ pos.pieces(Them,PAWN))
- & ei.attackedBy[Them][PAWN]
- & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
+ Bitboard b, weak, defended;
+ Score score = SCORE_ZERO;
- if (protectedEnemies)
- score += max_threat<Us>(protectedEnemies, pos, Threat[Minor]);
+ // Non-pawn enemies defended by a pawn
+ defended = (pos.pieces(Them) ^ pos.pieces(Them, PAWN))
+ & ei.attackedBy[Them][PAWN];
+ // Add a bonus according to the kind of attacking pieces
+ if (defended)
+ {
+ b = defended & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
+ while (b)
+ score += Threat[Defended][Minor][type_of(pos.piece_on(pop_lsb(&b)))];
+
+ b = defended & (ei.attackedBy[Us][ROOK]);
+ while (b)
+ score += Threat[Defended][Major][type_of(pos.piece_on(pop_lsb(&b)))];
+ }
// Enemies not defended by a pawn and under our attack
- weakEnemies = pos.pieces(Them)
- & ~ei.attackedBy[Them][PAWN]
- & ei.attackedBy[Us][ALL_PIECES];
+ weak = pos.pieces(Them)
+ & ~ei.attackedBy[Them][PAWN]
+ & ei.attackedBy[Us][ALL_PIECES];
- // Add a bonus according if the attacking pieces are minor or major
- if (weakEnemies)
+ // Add a bonus according to the kind of attacking pieces
+ if (weak)
{
- b = weakEnemies & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
- if (b)
- score += max_threat<Us>(b, pos, Threat[Minor]);
+ b = weak & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
+ while (b)
+ score += Threat[Weak][Minor][type_of(pos.piece_on(pop_lsb(&b)))];
- b = weakEnemies & (ei.attackedBy[Us][ROOK] | ei.attackedBy[Us][QUEEN]);
- if (b)
- score += max_threat<Us>(b, pos, Threat[Major]);
+ b = weak & (ei.attackedBy[Us][ROOK] | ei.attackedBy[Us][QUEEN]);
+ while (b)
+ score += Threat[Weak][Major][type_of(pos.piece_on(pop_lsb(&b)))];
- b = weakEnemies & ~ei.attackedBy[Them][ALL_PIECES];
+ b = weak & ~ei.attackedBy[Them][ALL_PIECES];
if (b)
score += more_than_one(b) ? Hanging * popcount<Max15>(b) : Hanging;
- b = weakEnemies & ei.attackedBy[Us][KING];
+ b = weak & ei.attackedBy[Us][KING];
if (b)
score += more_than_one(b) ? KingOnMany : KingOnOne;
}
Square blockSq = s + pawn_push(Us);
// Adjust bonus based on the king's proximity
- ebonus += square_distance(pos.king_square(Them), blockSq) * 5 * rr
- - square_distance(pos.king_square(Us ), blockSq) * 2 * rr;
+ ebonus += distance(pos.king_square(Them), blockSq) * 5 * rr
+ - 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 -= square_distance(pos.king_square(Us), blockSq + pawn_push(Us)) * rr;
+ ebonus -= 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))
if ( ei.mi->game_phase() < PHASE_MIDGAME
&& (sf == SCALE_FACTOR_NORMAL || sf == SCALE_FACTOR_ONEPAWN))
{
- if (pos.opposite_bishops()) {
- // Ignoring any pawns, do both sides only have a single bishop and no
- // other pieces?
+ if (pos.opposite_bishops())
+ {
+ // Endgame with opposite-colored bishops and no other pieces (ignoring pawns)
+ // is almost a draw, in case of KBP vs KB is even more a draw.
if ( pos.non_pawn_material(WHITE) == BishopValueMg
&& pos.non_pawn_material(BLACK) == BishopValueMg)
- {
- // Check for KBP vs KB with only a single pawn that is almost
- // certainly a draw or at least two pawns.
- bool one_pawn = (pos.count<PAWN>(WHITE) + pos.count<PAWN>(BLACK) == 1);
- sf = one_pawn ? ScaleFactor(8) : ScaleFactor(32);
- }
+ sf = more_than_one(pos.pieces(PAWN)) ? ScaleFactor(32) : ScaleFactor(8);
+
+ // Endgame with opposite-colored bishops, but also other pieces. Still
+ // a bit drawish, but not as drawish as with only the two bishops.
else
- // Endgame with opposite-colored bishops, but also other pieces. Still
- // a bit drawish, but not as drawish as with only the two bishops.
sf = ScaleFactor(50 * sf / SCALE_FACTOR_NORMAL);
- } else if ( abs(eg_value(score)) <= BishopValueEg
- && ei.pi->pawn_span(strongSide) <= 1
- && !pos.pawn_passed(~strongSide, pos.king_square(~strongSide))) {
- // Endings where weaker side can be place his king in front of the opponent's pawns are drawish.
- sf = ScaleFactor(ScalePawnSpan[ei.pi->pawn_span(strongSide)]);
}
+ // Endings where weaker side can place his king in front of the opponent's
+ // pawns are drawish.
+ else if ( abs(eg_value(score)) <= BishopValueEg
+ && ei.pi->pawn_span(strongSide) <= 1
+ && !pos.pawn_passed(~strongSide, pos.king_square(~strongSide)))
+ sf = ei.pi->pawn_span(strongSide) ? ScaleFactor(56) : ScaleFactor(38);
}
// Interpolate between a middlegame and a (scaled by 'sf') endgame score
}
- /// init() computes evaluation weights from the corresponding UCI parameters
- /// and setup king tables.
+ /// init() computes evaluation weights.
void init() {