S( 37, 28), S( 42, 31), S(44, 33) },
{ S(-22,-27), S( -8,-13), S( 6, 1), S(20, 15), S(34, 29), S(48, 43), // Bishops
S( 60, 55), S( 68, 63), S(74, 68), S(77, 72), S(80, 75), S(82, 77),
- S( 84, 79), S( 86, 81), S(87, 82), S(87, 82) },
+ S( 84, 79), S( 86, 81) },
{ S(-17,-33), S(-11,-16), S(-5, 0), S( 1, 16), S( 7, 32), S(13, 48), // Rooks
S( 18, 64), S( 22, 80), S(26, 96), S(29,109), S(31,115), S(33,119),
- S( 35,122), S( 36,123), S(37,124), S(38,124) },
+ S( 35,122), S( 36,123), S(37,124) },
{ S(-12,-20), S( -8,-13), S(-5, -7), S(-2, -1), S( 1, 5), S( 4, 11), // Queens
S( 7, 17), S( 10, 23), S(13, 29), S(16, 34), S(18, 38), S(20, 40),
S( 22, 41), S( 23, 41), S(24, 41), S(25, 41), S(25, 41), S(25, 41),
S( 25, 41), S( 25, 41), S(25, 41), S(25, 41), S(25, 41), S(25, 41),
- S( 25, 41), S( 25, 41), S(25, 41), S(25, 41), S(25, 41), S(25, 41),
- S( 25, 41), S( 25, 41) }
+ S( 25, 41), S( 25, 41), S(25, 41), S(25, 41) }
};
// Outpost[PieceType][Square] contains bonuses of knights and bishops, indexed
const Score RookOpenFile = make_score(43, 21);
const Score RookSemiopenFile = make_score(19, 10);
const Score BishopPawns = make_score( 8, 12);
+ const Score MinorBehindPawn = make_score(16, 0);
const Score UndefendedMinor = make_score(25, 10);
const Score TrappedRook = make_score(90, 0);
// based on how many squares inside this area are safe and available for
// friendly minor pieces.
const Bitboard SpaceMask[] = {
- (1ULL << SQ_C2) | (1ULL << SQ_D2) | (1ULL << SQ_E2) | (1ULL << SQ_F2) |
- (1ULL << SQ_C3) | (1ULL << SQ_D3) | (1ULL << SQ_E3) | (1ULL << SQ_F3) |
- (1ULL << SQ_C4) | (1ULL << SQ_D4) | (1ULL << SQ_E4) | (1ULL << SQ_F4),
- (1ULL << SQ_C7) | (1ULL << SQ_D7) | (1ULL << SQ_E7) | (1ULL << SQ_F7) |
- (1ULL << SQ_C6) | (1ULL << SQ_D6) | (1ULL << SQ_E6) | (1ULL << SQ_F6) |
- (1ULL << SQ_C5) | (1ULL << SQ_D5) | (1ULL << SQ_E5) | (1ULL << SQ_F5)
+ (FileCBB | FileDBB | FileEBB | FileFBB) & (Rank2BB | Rank3BB | Rank4BB),
+ (FileCBB | FileDBB | FileEBB | FileFBB) & (Rank7BB | Rank6BB | Rank5BB)
};
// King danger constants and variables. The king danger scores are taken
Score evaluate_pieces_of_color(const Position& pos, EvalInfo& ei, Score& mobility);
template<Color Us, bool Trace>
- Score evaluate_king(const Position& pos, EvalInfo& ei, Value margins[]);
+ Score evaluate_king(const Position& pos, const EvalInfo& ei, Value margins[]);
template<Color Us, bool Trace>
- Score evaluate_threats(const Position& pos, EvalInfo& ei);
+ Score evaluate_threats(const Position& pos, const EvalInfo& ei);
template<Color Us, bool Trace>
- Score evaluate_passed_pawns(const Position& pos, EvalInfo& ei);
+ Score evaluate_passed_pawns(const Position& pos, const EvalInfo& ei);
template<Color Us>
- int evaluate_space(const Position& pos, EvalInfo& ei);
+ int evaluate_space(const Position& pos, const EvalInfo& ei);
- Score evaluate_unstoppable_pawns(const Position& pos, EvalInfo& ei);
+ Score evaluate_unstoppable_pawns(const Position& pos, const EvalInfo& ei);
Value interpolate(const Score& v, Phase ph, ScaleFactor sf);
Score apply_weight(Score v, Score w);
if (ei.mi->space_weight())
{
int s = evaluate_space<WHITE>(pos, ei) - evaluate_space<BLACK>(pos, ei);
- score += apply_weight(make_score(s * ei.mi->space_weight(), 0), Weights[Space]);
+ score += apply_weight(s * ei.mi->space_weight(), Weights[Space]);
}
// Scale winning side if position is more drawish that what it appears
{
// 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.piece_count(WHITE, PAWN) + pos.piece_count(BLACK, PAWN) == 1);
+ bool one_pawn = (pos.count<PAWN>(WHITE) + pos.count<PAWN>(BLACK) == 1);
sf = one_pawn ? ScaleFactor(8) : ScaleFactor(32);
}
else
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);
+ Score w = ei.mi->space_weight() * evaluate_space<WHITE>(pos, ei);
+ Score b = ei.mi->space_weight() * evaluate_space<BLACK>(pos, ei);
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])
template<Color Us>
void init_eval_info(const Position& pos, EvalInfo& ei) {
- const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Square Down = (Us == WHITE ? DELTA_S : DELTA_N);
Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from<KING>(pos.king_square(Them));
ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us);
// Init king safety tables only if we are going to use them
- if ( pos.piece_count(Us, QUEEN)
- && pos.non_pawn_material(Us) > QueenValueMg + PawnValueMg)
+ if (pos.count<QUEEN>(Us) && pos.non_pawn_material(Us) > QueenValueMg + PawnValueMg)
{
- ei.kingRing[Them] = (b | (Us == WHITE ? b >> 8 : b << 8));
+ ei.kingRing[Them] = b | shift_bb<Down>(b);
b &= ei.attackedBy[Us][PAWN];
ei.kingAttackersCount[Us] = b ? popcount<Max15>(b) / 2 : 0;
ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0;
if (bonus && (ei.attackedBy[Us][PAWN] & s))
{
if ( !pos.pieces(Them, KNIGHT)
- && !(same_color_squares(s) & pos.pieces(Them, BISHOP)))
+ && !(squares_of_color(s) & pos.pieces(Them, BISHOP)))
bonus += bonus + bonus / 2;
else
bonus += bonus / 2;
Score score = SCORE_ZERO;
const Color Them = (Us == WHITE ? BLACK : WHITE);
- const Square* pl = pos.piece_list(Us, Piece);
+ const Square* pl = pos.list<Piece>(Us);
ei.attackedBy[Us][Piece] = 0;
ei.kingAdjacentZoneAttacksCount[Us] += popcount<Max15>(bb);
}
- int mob = popcount<Piece == QUEEN ? Full : Max15>(b & mobilityArea);
+ int mob = Piece != QUEEN ? popcount<Max15>(b & mobilityArea)
+ : popcount<Full >(b & mobilityArea);
+
mobility += MobilityBonus[Piece][mob];
// Decrease score if we are attacked by an enemy pawn. Remaining part
if (Piece == BISHOP)
score -= BishopPawns * ei.pi->pawns_on_same_color_squares(Us, s);
- // Bishop and knight outposts squares
- if ( (Piece == BISHOP || Piece == KNIGHT)
- && !(pos.pieces(Them, PAWN) & attack_span_mask(Us, s)))
- score += evaluate_outposts<Piece, Us>(pos, ei, s);
+ if (Piece == BISHOP || Piece == KNIGHT)
+ {
+ // Bishop and knight outposts squares
+ if (!(pos.pieces(Them, PAWN) & pawn_attack_span(Us, s)))
+ score += evaluate_outposts<Piece, Us>(pos, ei, s);
+
+ // Bishop or knight behind a pawn
+ if ( relative_rank(Us, s) < RANK_5
+ && (pos.pieces(PAWN) & (s + pawn_push(Us))))
+ score += MinorBehindPawn;
+ }
if ( (Piece == ROOK || Piece == QUEEN)
&& relative_rank(Us, s) >= RANK_5)
&& relative_rank(Us, pos.king_square(Them)) == RANK_8)
score += Piece == ROOK ? RookOn7th : QueenOn7th;
- // Major piece attacking enemy pawns on the same rank
- Bitboard pawns = pos.pieces(Them, PAWN) & rank_bb(s);
+ // Major piece attacking enemy pawns on the same rank/file
+ Bitboard pawns = pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s];
if (pawns)
score += popcount<Max15>(pawns) * (Piece == ROOK ? RookOnPawn : QueenOnPawn);
}
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)))
+ if (mob > 3 || ei.pi->semiopen(Us, file_of(s)))
continue;
Square ksq = pos.king_square(Us);
// and the type of attacked one.
template<Color Us, bool Trace>
- Score evaluate_threats(const Position& pos, EvalInfo& ei) {
+ Score evaluate_threats(const Position& pos, const EvalInfo& ei) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
// evaluate_king<>() assigns bonuses and penalties to a king of a given color
template<Color Us, bool Trace>
- Score evaluate_king(const Position& pos, EvalInfo& ei, Value margins[]) {
+ Score evaluate_king(const Position& pos, const EvalInfo& ei, Value margins[]) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
// evaluate_passed_pawns<>() evaluates the passed pawns of the given color
template<Color Us, bool Trace>
- Score evaluate_passed_pawns(const Position& pos, EvalInfo& ei) {
+ Score evaluate_passed_pawns(const Position& pos, const EvalInfo& ei) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
ebonus -= Value(square_distance(pos.king_square(Us), blockSq) * 2 * rr);
// If blockSq is not the queening square then consider also a second push
- if (rank_of(blockSq) != (Us == WHITE ? RANK_8 : RANK_1))
+ if (relative_rank(Us, blockSq) != RANK_8)
ebonus -= Value(square_distance(pos.king_square(Us), blockSq + pawn_push(Us)) * rr);
// If the pawn is free to advance, increase bonus
if (pos.is_empty(blockSq))
{
squaresToQueen = forward_bb(Us, s);
- defendedSquares = squaresToQueen & ei.attackedBy[Us][ALL_PIECES];
// If there is an enemy rook or queen attacking the pawn from behind,
// add all X-ray attacks by the rook or queen. Otherwise consider only
// the squares in the pawn's path attacked or occupied by the enemy.
- if ( (forward_bb(Them, s) & pos.pieces(Them, ROOK, QUEEN))
+ if ( unlikely(forward_bb(Them, s) & pos.pieces(Them, ROOK, QUEEN))
&& (forward_bb(Them, s) & pos.pieces(Them, ROOK, QUEEN) & pos.attacks_from<ROOK>(s)))
unsafeSquares = squaresToQueen;
else
unsafeSquares = squaresToQueen & (ei.attackedBy[Them][ALL_PIECES] | pos.pieces(Them));
+ if ( unlikely(forward_bb(Them, s) & pos.pieces(Us, ROOK, QUEEN))
+ && (forward_bb(Them, s) & pos.pieces(Us, ROOK, QUEEN) & pos.attacks_from<ROOK>(s)))
+ defendedSquares = squaresToQueen;
+ else
+ defendedSquares = squaresToQueen & ei.attackedBy[Us][ALL_PIECES];
+
// If there aren't enemy attacks huge bonus, a bit smaller if at
// least block square is not attacked, otherwise smallest bonus.
int k = !unsafeSquares ? 15 : !(unsafeSquares & blockSq) ? 9 : 3;
// evaluate_unstoppable_pawns() evaluates the unstoppable passed pawns for both sides, this is quite
// conservative and returns a winning score only when we are very sure that the pawn is winning.
- Score evaluate_unstoppable_pawns(const Position& pos, EvalInfo& ei) {
+ Score evaluate_unstoppable_pawns(const Position& pos, const EvalInfo& ei) {
Bitboard b, b2, blockers, supporters, queeningPath, candidates;
Square s, blockSq, queeningSquare;
// black pawns: a4, b4 white: b2 then pawn in b4 is giving support.
if (!opposed)
{
- b2 = supporters & in_front_bb(winnerSide, blockSq + pawn_push(winnerSide));
+ b2 = supporters & in_front_bb(winnerSide, rank_of(blockSq + pawn_push(winnerSide)));
while (b2) // This while-loop could be replaced with LSB/MSB (depending on color)
{
}
// Check pawns that can be sacrificed against the blocking pawn
- b2 = attack_span_mask(winnerSide, blockSq) & candidates & ~(1ULL << s);
+ b2 = pawn_attack_span(winnerSide, blockSq) & candidates & ~(1ULL << s);
while (b2) // This while-loop could be replaced with LSB/MSB (depending on color)
{
// twice. Finally, the space bonus is scaled by a weight taken from the
// material hash table. The aim is to improve play on game opening.
template<Color Us>
- int evaluate_space(const Position& pos, EvalInfo& ei) {
+ int evaluate_space(const Position& pos, const EvalInfo& ei) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
assert(eg_value(v) > -VALUE_INFINITE && eg_value(v) < VALUE_INFINITE);
assert(ph >= PHASE_ENDGAME && ph <= PHASE_MIDGAME);
- int ev = (eg_value(v) * int(sf)) / SCALE_FACTOR_NORMAL;
- int result = (mg_value(v) * int(ph) + ev * int(128 - ph)) / 128;
- return Value((result + GrainSize / 2) & ~(GrainSize - 1));
+ int e = (eg_value(v) * int(sf)) / SCALE_FACTOR_NORMAL;
+ int r = (mg_value(v) * int(ph) + e * int(PHASE_MIDGAME - ph)) / PHASE_MIDGAME;
+ return Value((r / GrainSize) * GrainSize); // Sign independent
}
// apply_weight() weights score v by score w trying to prevent overflow
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));
+ std::memset(scores, 0, 2 * (TOTAL + 1) * sizeof(Score));
Value margin;
do_evaluate<true>(pos, margin);