/*
- Glaurung, a UCI chess playing engine.
- Copyright (C) 2004-2008 Tord Romstad
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+ Copyright (C) 2008 Marco Costalba
- Glaurung is free software: you can redistribute it and/or modify
+ Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
- Glaurung is distributed in the hope that it will be useful,
+ Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
EvalInfo &ei);
inline Value apply_weight(Value v, int w);
- Value scale_by_game_phase(Value mv, Value ev, Phase ph, ScaleFactor sf[]);
+ Value scale_by_game_phase(Value mv, Value ev, Phase ph, const ScaleFactor sf[]);
int count_1s_8bit(Bitboard b);
ei.egValue += apply_weight(ei.pi->eg_value(), WeightPawnStructureEndgame);
// Initialize king attack bitboards and king attack zones for both sides
- ei.attackedBy[WHITE][KING] = pos.king_attacks(pos.king_square(WHITE));
- ei.attackedBy[BLACK][KING] = pos.king_attacks(pos.king_square(BLACK));
+ ei.attackedBy[WHITE][KING] = pos.piece_attacks<KING>(pos.king_square(WHITE));
+ ei.attackedBy[BLACK][KING] = pos.piece_attacks<KING>(pos.king_square(BLACK));
ei.kingZone[WHITE] = ei.attackedBy[BLACK][KING] | (ei.attackedBy[BLACK][KING] >> 8);
ei.kingZone[BLACK] = ei.attackedBy[WHITE][KING] | (ei.attackedBy[WHITE][KING] << 8);
for (Color c = WHITE; c <= BLACK; c++)
{
// Knights
- for (int i = 0; i < pos.knight_count(c); i++)
- evaluate_knight(pos, pos.knight_list(c, i), c, ei);
+ for (int i = 0; i < pos.piece_count(c, KNIGHT); i++)
+ evaluate_knight(pos, pos.piece_list(c, KNIGHT, i), c, ei);
// Bishops
- for (int i = 0; i < pos.bishop_count(c); i++)
- evaluate_bishop(pos, pos.bishop_list(c, i), c, ei);
+ for (int i = 0; i < pos.piece_count(c, BISHOP); i++)
+ evaluate_bishop(pos, pos.piece_list(c, BISHOP, i), c, ei);
// Rooks
- for (int i = 0; i < pos.rook_count(c); i++)
- evaluate_rook(pos, pos.rook_list(c, i), c, ei);
+ for (int i = 0; i < pos.piece_count(c, ROOK); i++)
+ evaluate_rook(pos, pos.piece_list(c, ROOK, i), c, ei);
// Queens
- for(int i = 0; i < pos.queen_count(c); i++)
- evaluate_queen(pos, pos.queen_list(c, i), c, ei);
+ for(int i = 0; i < pos.piece_count(c, QUEEN); i++)
+ evaluate_queen(pos, pos.piece_list(c, QUEEN, i), c, ei);
// Special pattern: trapped bishops on a7/h7/a2/h2
Bitboard b = pos.bishops(c) & MaskA7H7[c];
&& ( (factor[WHITE] == SCALE_FACTOR_NORMAL && ei.egValue > Value(0))
|| (factor[BLACK] == SCALE_FACTOR_NORMAL && ei.egValue < Value(0))))
{
- if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) == 2*BishopValueMidgame)
- {
- // Only the two bishops
- if (pos.pawn_count(WHITE) + pos.pawn_count(BLACK) == 1)
+ ScaleFactor sf;
+
+ // Only the two bishops ?
+ if ( pos.non_pawn_material(WHITE) == BishopValueMidgame
+ && pos.non_pawn_material(BLACK) == BishopValueMidgame)
{
- // KBP vs KB with only a single pawn; almost certainly a draw.
- if (factor[WHITE] == SCALE_FACTOR_NORMAL)
- factor[WHITE] = ScaleFactor(8);
- if (factor[BLACK] == SCALE_FACTOR_NORMAL)
- factor[BLACK] = ScaleFactor(8);
+ // 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);
+ sf = one_pawn ? ScaleFactor(8) : ScaleFactor(32);
}
else
- {
- // At least two pawns
- if (factor[WHITE] == SCALE_FACTOR_NORMAL)
- factor[WHITE] = ScaleFactor(32);
- if (factor[BLACK] == SCALE_FACTOR_NORMAL)
- factor[BLACK] = ScaleFactor(32);
- }
- }
- else
- {
- // Endgame with opposite-colored bishops, but also other pieces.
- // Still a bit drawish, but not as drawish as with only the two
- // bishops.
+ // 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);
+
if (factor[WHITE] == SCALE_FACTOR_NORMAL)
- factor[WHITE] = ScaleFactor(50);
+ factor[WHITE] = sf;
if (factor[BLACK] == SCALE_FACTOR_NORMAL)
- factor[BLACK] = ScaleFactor(50);
- }
+ factor[BLACK] = sf;
}
// Interpolate between the middle game and the endgame score, and
/// we should add scores from the pawn and material hash tables?
Value quick_evaluate(const Position &pos) {
- Color stm;
- Value mgValue, egValue;
- ScaleFactor factor[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL};
- Phase phase;
assert(pos.is_ok());
- stm = pos.side_to_move();
+ static const
+ ScaleFactor sf[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL};
- mgValue = pos.mg_value();
- egValue = pos.eg_value();
- phase = pos.game_phase();
-
- Value value = scale_by_game_phase(mgValue, egValue, phase, factor);
+ Value mgv = pos.mg_value();
+ Value egv = pos.eg_value();
+ Phase ph = pos.game_phase();
+ Color stm = pos.side_to_move();
- return Sign[stm] * value;
+ return Sign[stm] * scale_by_game_phase(mgv, egv, ph, sf);
}
/// quit_eval() releases heap-allocated memory at program termination.
void quit_eval() {
- for(int i = 0; i < THREAD_MAX; i++) {
- delete PawnTable[i];
- delete MaterialTable[i];
+
+ for (int i = 0; i < THREAD_MAX; i++)
+ {
+ delete PawnTable[i];
+ delete MaterialTable[i];
}
}
// King attack
if (b & ei.kingZone[us])
{
- ei.kingAttackersCount[us]++;
- ei.kingAttackersWeight[us] += AttackWeight;
- Bitboard bb = (b & ei.attackedBy[them][KING]);
- if (bb)
- ei.kingZoneAttacksCount[us] += count_1s_max_15(bb);
+ ei.kingAttackersCount[us]++;
+ ei.kingAttackersWeight[us] += AttackWeight;
+ Bitboard bb = (b & ei.attackedBy[them][KING]);
+ if (bb)
+ ei.kingAdjacentZoneAttacksCount[us] += count_1s_max_15(bb);
}
// Mobility
if (v && (p.pawn_attacks(them, s) & p.pawns(us)))
{
bonus += v / 2;
- if ( p.knight_count(them) == 0
+ if ( p.piece_count(them, KNIGHT) == 0
&& (SquaresByColorBB[square_color(s)] & p.bishops(them)) == EmptyBoardBB)
bonus += v;
}
void evaluate_knight(const Position &p, Square s, Color us, EvalInfo &ei) {
- Bitboard b = p.knight_attacks(s);
+ Bitboard b = p.piece_attacks<KNIGHT>(s);
ei.attackedBy[us][KNIGHT] |= b;
// King attack, mobility and outposts
void evaluate_queen(const Position &p, Square s, Color us, EvalInfo &ei) {
- Bitboard b = p.queen_attacks(s);
+ Bitboard b = p.piece_attacks<QUEEN>(s);
ei.attackedBy[us][QUEEN] |= b;
// King attack and mobility
}
}
+ inline Bitboard shiftRowsDown(const Bitboard& b, int num) {
+
+ return b >> (num << 3);
+ }
// evaluate_king() assigns bonuses and penalties to a king of a given
// color on a given square.
int shelter = 0, sign = Sign[us];
- // King shelter.
- if(relative_rank(us, s) <= RANK_4) {
- Bitboard pawns = p.pawns(us) & this_and_neighboring_files_bb(s);
- Rank r = square_rank(s);
- for(int i = 0; i < 3; i++)
- shelter += count_1s_8bit(pawns >> ((r+(i+1)*sign) * 8)) * (64>>i);
- ei.mgValue += sign * Value(shelter);
+ // King shelter
+ if (relative_rank(us, s) <= RANK_4)
+ {
+ Bitboard pawns = p.pawns(us) & this_and_neighboring_files_bb(s);
+ Rank r = square_rank(s);
+ for (int i = 1; i < 4; i++)
+ shelter += count_1s_8bit(shiftRowsDown(pawns, r+i*sign)) * (128>>i);
+
+ ei.mgValue += sign * Value(shelter);
}
// King safety. This is quite complicated, and is almost certainly far
// from optimally tuned.
Color them = opposite_color(us);
- if(p.queen_count(them) >= 1 && ei.kingAttackersCount[them] >= 2
- && p.non_pawn_material(them) >= QueenValueMidgame + RookValueMidgame
- && ei.kingZoneAttacksCount[them]) {
+ if ( p.piece_count(them, QUEEN) >= 1
+ && ei.kingAttackersCount[them] >= 2
+ && p.non_pawn_material(them) >= QueenValueMidgame + RookValueMidgame
+ && ei.kingAdjacentZoneAttacksCount[them])
+ {
// Is it the attackers turn to move?
bool sente = (them == p.side_to_move());
// Find the attacked squares around the king which has no defenders
- // apart from the king itself:
+ // apart from the king itself
Bitboard undefended =
- ei.attacked_by(them) & ~ei.attacked_by(us, PAWN)
- & ~ei.attacked_by(us, KNIGHT) & ~ei.attacked_by(us, BISHOP)
- & ~ei.attacked_by(us, ROOK) & ~ei.attacked_by(us, QUEEN)
- & ei.attacked_by(us, KING);
+ ei.attacked_by(them) & ~ei.attacked_by(us, PAWN)
+ & ~ei.attacked_by(us, KNIGHT) & ~ei.attacked_by(us, BISHOP)
+ & ~ei.attacked_by(us, ROOK) & ~ei.attacked_by(us, QUEEN)
+ & ei.attacked_by(us, KING);
+
Bitboard occ = p.occupied_squares(), b, b2;
// Initialize the 'attackUnits' variable, which is used later on as an
// undefended squares around the king, the square of the king, and the
// quality of the pawn shelter.
int attackUnits =
- Min((ei.kingAttackersCount[them] * ei.kingAttackersWeight[them]) / 2, 25)
- + (ei.kingZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3
- + InitKingDanger[relative_square(us, s)] - shelter / 32;
+ Min((ei.kingAttackersCount[them] * ei.kingAttackersWeight[them]) / 2, 25)
+ + (ei.kingAdjacentZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3
+ + InitKingDanger[relative_square(us, s)] - shelter / 32;
- // Analyse safe queen contact checks:
+ // Analyse safe queen contact checks
b = undefended & ei.attacked_by(them, QUEEN) & ~p.pieces_of_color(them);
- if(b) {
+ if (b)
+ {
Bitboard attackedByOthers =
- ei.attacked_by(them, PAWN) | ei.attacked_by(them, KNIGHT)
- | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, ROOK);
+ ei.attacked_by(them, PAWN) | ei.attacked_by(them, KNIGHT)
+ | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, ROOK);
+
b &= attackedByOthers;
- if(b) {
+ if (b)
+ {
// The bitboard b now contains the squares available for safe queen
// contact checks.
int count = count_1s_max_15(b);
- attackUnits += QueenContactCheckBonus * count * (sente? 2 : 1);
+ attackUnits += QueenContactCheckBonus * count * (sente ? 2 : 1);
// Is there a mate threat?
- if(QueenContactMates && !p.is_check()) {
+ if (QueenContactMates && !p.is_check())
+ {
Bitboard escapeSquares =
- p.king_attacks(s) & ~p.pieces_of_color(us) & ~attackedByOthers;
- while(b) {
- Square from, to = pop_1st_bit(&b);
- if(!(escapeSquares
- & ~queen_attacks_bb(to, occ & clear_mask_bb(s)))) {
- // We have a mate, unless the queen is pinned or there
- // is an X-ray attack through the queen.
- for(int i = 0; i < p.queen_count(them); i++) {
- from = p.queen_list(them, i);
- if(bit_is_set(p.queen_attacks(from), to)
- && !bit_is_set(p.pinned_pieces(them), from)
- && !(rook_attacks_bb(to, occ & clear_mask_bb(from))
- & p.rooks_and_queens(us))
- && !(rook_attacks_bb(to, occ & clear_mask_bb(from))
- & p.rooks_and_queens(us)))
- ei.mateThreat[them] = make_move(from, to);
+ p.piece_attacks<KING>(s) & ~p.pieces_of_color(us) & ~attackedByOthers;
+
+ while (b)
+ {
+ Square from, to = pop_1st_bit(&b);
+ if (!(escapeSquares & ~queen_attacks_bb(to, occ & ClearMaskBB[s])))
+ {
+ // We have a mate, unless the queen is pinned or there
+ // is an X-ray attack through the queen.
+ for (int i = 0; i < p.piece_count(them, QUEEN); i++)
+ {
+ from = p.piece_list(them, QUEEN, i);
+ if ( bit_is_set(p.piece_attacks<QUEEN>(from), to)
+ && !bit_is_set(p.pinned_pieces(them), from)
+ && !(rook_attacks_bb(to, occ & ClearMaskBB[from]) & p.rooks_and_queens(us))
+ && !(rook_attacks_bb(to, occ & ClearMaskBB[from]) & p.rooks_and_queens(us)))
+
+ ei.mateThreat[them] = make_move(from, to);
+ }
}
- }
}
}
}
}
-
// Analyse safe rook contact checks:
- if(RookContactCheckBonus) {
- b = undefended & ei.attacked_by(them, ROOK) & ~p.pieces_of_color(them);
- if(b) {
- Bitboard attackedByOthers =
- ei.attacked_by(them, PAWN) | ei.attacked_by(them, KNIGHT)
- | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, QUEEN);
- b &= attackedByOthers;
- if(b) {
- int count = count_1s_max_15(b);
- attackUnits += (RookContactCheckBonus * count * (sente? 2 : 1));
+ if (RookContactCheckBonus)
+ {
+ b = undefended & ei.attacked_by(them, ROOK) & ~p.pieces_of_color(them);
+ if (b)
+ {
+ Bitboard attackedByOthers =
+ ei.attacked_by(them, PAWN) | ei.attacked_by(them, KNIGHT)
+ | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, QUEEN);
+
+ b &= attackedByOthers;
+ if (b)
+ {
+ int count = count_1s_max_15(b);
+ attackUnits += (RookContactCheckBonus * count * (sente? 2 : 1));
+ }
}
- }
}
-
// Analyse safe distance checks:
- if(QueenCheckBonus > 0 || RookCheckBonus > 0) {
- b = p.rook_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
+ if (QueenCheckBonus > 0 || RookCheckBonus > 0)
+ {
+ b = p.piece_attacks<ROOK>(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
- // Queen checks
- b2 = b & ei.attacked_by(them, QUEEN);
- if(b2) attackUnits += QueenCheckBonus * count_1s_max_15(b2);
+ // Queen checks
+ b2 = b & ei.attacked_by(them, QUEEN);
+ if( b2)
+ attackUnits += QueenCheckBonus * count_1s_max_15(b2);
- // Rook checks
- b2 = b & ei.attacked_by(them, ROOK);
- if(b2) attackUnits += RookCheckBonus * count_1s_max_15(b2);
+ // Rook checks
+ b2 = b & ei.attacked_by(them, ROOK);
+ if (b2)
+ attackUnits += RookCheckBonus * count_1s_max_15(b2);
}
- if(QueenCheckBonus > 0 || BishopCheckBonus > 0) {
- b = p.bishop_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
- // Queen checks
- b2 = b & ei.attacked_by(them, QUEEN);
- if(b2) attackUnits += QueenCheckBonus * count_1s_max_15(b2);
-
- // Bishop checks
- b2 = b & ei.attacked_by(them, BISHOP);
- if(b2) attackUnits += BishopCheckBonus * count_1s_max_15(b2);
+ if (QueenCheckBonus > 0 || BishopCheckBonus > 0)
+ {
+ b = p.piece_attacks<BISHOP>(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
+
+ // Queen checks
+ b2 = b & ei.attacked_by(them, QUEEN);
+ if (b2)
+ attackUnits += QueenCheckBonus * count_1s_max_15(b2);
+
+ // Bishop checks
+ b2 = b & ei.attacked_by(them, BISHOP);
+ if (b2)
+ attackUnits += BishopCheckBonus * count_1s_max_15(b2);
}
- if(KnightCheckBonus > 0) {
- b = p.knight_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
- // Knight checks
- b2 = b & ei.attacked_by(them, KNIGHT);
- if(b2) attackUnits += KnightCheckBonus * count_1s_max_15(b2);
+ if (KnightCheckBonus > 0)
+ {
+ b = p.piece_attacks<KNIGHT>(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
+
+ // Knight checks
+ b2 = b & ei.attacked_by(them, KNIGHT);
+ if (b2)
+ attackUnits += KnightCheckBonus * count_1s_max_15(b2);
}
// Analyse discovered checks (only for non-pawns right now, consider
// adding pawns later).
- if(DiscoveredCheckBonus) {
+ if (DiscoveredCheckBonus)
+ {
b = p.discovered_check_candidates(them) & ~p.pawns();
- if(b)
- attackUnits +=
- DiscoveredCheckBonus * count_1s_max_15(b) * (sente? 2 : 1);
+ if (b)
+ attackUnits += DiscoveredCheckBonus * count_1s_max_15(b) * (sente? 2 : 1);
}
// Has a mate threat been found? We don't do anything here if the
// side with the mating move is the side to move, because in that
// case the mating side will get a huge bonus at the end of the main
// evaluation function instead.
- if(ei.mateThreat[them] != MOVE_NONE)
- attackUnits += MateThreatBonus;
+ if (ei.mateThreat[them] != MOVE_NONE)
+ attackUnits += MateThreatBonus;
// Ensure that attackUnits is between 0 and 99, in order to avoid array
// out of bounds errors:
- if(attackUnits < 0) attackUnits = 0;
- if(attackUnits >= 100) attackUnits = 99;
+ if (attackUnits < 0)
+ attackUnits = 0;
+
+ if (attackUnits >= 100)
+ attackUnits = 99;
// Finally, extract the king safety score from the SafetyTable[] array.
// Add the score to the evaluation, and also to ei.futilityMargin. The
// capturing a single attacking piece can therefore result in a score
// change far bigger than the value of the captured piece.
Value v = apply_weight(SafetyTable[attackUnits], WeightKingSafety[us]);
+
ei.mgValue -= sign * v;
- if(us == p.side_to_move())
- ei.futilityMargin += v;
+
+ if (us == p.side_to_move())
+ ei.futilityMargin += v;
}
}
// value if the other side has a rook or queen.
if(square_file(s) == FILE_A || square_file(s) == FILE_H) {
if(pos.non_pawn_material(them) == KnightValueMidgame
- && pos.knight_count(them) == 1)
+ && pos.piece_count(them, KNIGHT) == 1)
ebonus += ebonus / 4;
else if(pos.rooks_and_queens(them))
ebonus -= ebonus / 4;
// score, based on game phase. It also scales the return value by a
// ScaleFactor array.
- Value scale_by_game_phase(Value mv, Value ev, Phase ph, ScaleFactor sf[]) {
+ Value scale_by_game_phase(Value mv, Value ev, Phase ph, const ScaleFactor sf[]) {
assert(mv > -VALUE_INFINITE && mv < VALUE_INFINITE);
assert(ev > -VALUE_INFINITE && ev < VALUE_INFINITE);
ev = apply_scale_factor(ev, sf[(ev > Value(0) ? WHITE : BLACK)]);
- // Linearized sigmoid interpolator
- int sph = int(ph);
- sph -= (64 - sph) / 4;
- sph = Min(PHASE_MIDGAME, Max(PHASE_ENDGAME, sph));
-
- Value result = Value(int((mv * sph + ev * (128 - sph)) / 128));
-
+ Value result = Value(int((mv * ph + ev * (128 - ph)) / 128));
return Value(int(result) & ~(GrainSize - 1));
}