int WeightPassedPawnsMidgame = 0x100;
int WeightPassedPawnsEndgame = 0x100;
int WeightKingSafety[2] = { 0x100, 0x100 };
+ int WeightSpace;
// Internal evaluation weights. These are applied on top of the evaluation
// weights read from UCI parameters. The purpose is to be able to change
const int WeightPawnStructureEndgameInternal = 0x100;
const int WeightPassedPawnsMidgameInternal = 0x100;
const int WeightPassedPawnsEndgameInternal = 0x100;
- const int WeightKingSafetyInternal = 0x100;
- const int WeightKingOppSafetyInternal = 0x100;
+ const int WeightKingSafetyInternal = 0x110;
+ const int WeightKingOppSafetyInternal = 0x110;
+ const int WeightSpaceInternal = 0x30;
// Visually better to define tables constants
typedef Value V;
((1ULL << SQ_A8) | (1ULL << SQ_H8))
};
+ // The SpaceMask[color] contains area of the board which is consdered by
+ // the space evaluation. In the middle game, each side is given a bonus
+ // based on how many squares inside this area are safe and available for
+ // friendly minor pieces.
+ const Bitboard SpaceMask[2] = {
+ (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)
+ };
+
/// King safety constants and variables. The king safety scores are taken
/// from the array SafetyTable[]. Various little "meta-bonuses" measuring
/// the strength of the attack are added up into an integer, which is used
const int KnightAttackWeight = 2;
// Bonuses for safe checks for each piece type.
- int QueenContactCheckBonus = 4;
- int RookContactCheckBonus = 2;
+ int QueenContactCheckBonus = 3;
int QueenCheckBonus = 2;
int RookCheckBonus = 1;
int BishopCheckBonus = 1;
// in init_safety().
Value SafetyTable[100];
- // Pawn and material hash tables, indexed by the current thread id:
+ // Pawn and material hash tables, indexed by the current thread id
PawnInfoTable *PawnTable[8] = {0, 0, 0, 0, 0, 0, 0, 0};
MaterialInfoTable *MaterialTable[8] = {0, 0, 0, 0, 0, 0, 0, 0};
- // Sizes of pawn and material hash tables:
+ // Sizes of pawn and material hash tables
const int PawnTableSize = 16384;
const int MaterialTableSize = 1024;
// Array which gives the number of nonzero bits in an 8-bit integer:
uint8_t BitCount8Bit[256];
- // Function prototypes:
+ // Function prototypes
void evaluate_knight(const Position &p, Square s, Color us, EvalInfo &ei);
void evaluate_bishop(const Position &p, Square s, Color us, EvalInfo &ei);
void evaluate_rook(const Position &p, Square s, Color us, EvalInfo &ei);
void evaluate_trapped_bishop_a1h1(const Position &pos, Square s, Color us,
EvalInfo &ei);
+ void evaluate_space(const Position &p, Color us, EvalInfo &ei);
inline Value apply_weight(Value v, int w);
Value scale_by_game_phase(Value mv, Value ev, Phase ph, const ScaleFactor sf[]);
ei.mgValue += ei.pi->kingside_storm_value(WHITE)
- ei.pi->queenside_storm_value(BLACK);
+
+ // Evaluate space for both sides
+ if (ei.mi->space_weight() > 0)
+ {
+ evaluate_space(pos, WHITE, ei);
+ evaluate_space(pos, BLACK, ei);
+ }
}
// Mobility
ei.egValue += apply_weight(ei.egMobility, WeightMobilityEndgame);
// If we don't already have an unusual scale factor, check for opposite
- // colored bishop endgames, and use a lower scale for those:
+ // colored bishop endgames, and use a lower scale for those
if ( phase < PHASE_MIDGAME
&& pos.opposite_colored_bishops()
&& ( (factor[WHITE] == SCALE_FACTOR_NORMAL && ei.egValue > Value(0))
assert(pos.is_ok());
static const
- ScaleFactor sf[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL};
+ ScaleFactor sf[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL};
Value mgv = pos.mg_value();
Value egv = pos.eg_value();
WeightKingSafety[us] = weight_option("Cowardice", WeightKingSafetyInternal);
WeightKingSafety[them] = weight_option("Aggressiveness", WeightKingOppSafetyInternal);
+ WeightSpace = weight_option("Space", WeightSpaceInternal);
init_safety();
}
// evaluate_common() computes terms common to all pieces attack
- int evaluate_common(const Position&p, const Bitboard& b, Color us, EvalInfo& ei,
- int AttackWeight, const Value* mgBonus, const Value* egBonus,
- Square s = SQ_NONE, const Value* OutpostBonus = NULL) {
+ template<PieceType Piece>
+ int evaluate_common(const Position& p, const Bitboard& b, Color us, EvalInfo& ei, Square s = SQ_NONE) {
+
+ static const int AttackWeight[] = { 0, 0, KnightAttackWeight, BishopAttackWeight, RookAttackWeight, QueenAttackWeight };
+ static const Value* MgBonus[] = { 0, 0, MidgameKnightMobilityBonus, MidgameBishopMobilityBonus, MidgameRookMobilityBonus, MidgameQueenMobilityBonus };
+ static const Value* EgBonus[] = { 0, 0, EndgameKnightMobilityBonus, EndgameBishopMobilityBonus, EndgameRookMobilityBonus, EndgameQueenMobilityBonus };
+ static const Value* OutpostBonus[] = { 0, 0, KnightOutpostBonus, BishopOutpostBonus, 0, 0 };
Color them = opposite_color(us);
+ // Update attack info
+ ei.attackedBy[us][Piece] |= b;
+
// King attack
if (b & ei.kingZone[us])
{
ei.kingAttackersCount[us]++;
- ei.kingAttackersWeight[us] += AttackWeight;
+ ei.kingAttackersWeight[us] += AttackWeight[Piece];
Bitboard bb = (b & ei.attackedBy[them][KING]);
if (bb)
ei.kingAdjacentZoneAttacksCount[us] += count_1s_max_15(bb);
}
+ // Remove squares protected by enemy pawns
+ Bitboard bb = (b & ~ei.attackedBy[them][PAWN]);
+
// Mobility
- int mob = count_1s_max_15(b & ~p.pieces_of_color(us));
- ei.mgMobility += Sign[us] * mgBonus[mob];
- ei.egMobility += Sign[us] * egBonus[mob];
+ int mob = (Piece != QUEEN ? count_1s_max_15(bb & ~p.pieces_of_color(us))
+ : count_1s(bb & ~p.pieces_of_color(us)));
+
+ ei.mgMobility += Sign[us] * MgBonus[Piece][mob];
+ ei.egMobility += Sign[us] * EgBonus[Piece][mob];
// Bishop and Knight outposts
- if (!OutpostBonus || !p.square_is_weak(s, them))
+ if ( (Piece != BISHOP && Piece != KNIGHT) // compile time condition
+ || !p.square_is_weak(s, them))
return mob;
// Initial bonus based on square
Value v, bonus;
- v = bonus = OutpostBonus[relative_square(us, s)];
+ v = bonus = OutpostBonus[Piece][relative_square(us, s)];
// Increase bonus if supported by pawn, especially if the opponent has
// no minor piece which can exchange the outpost piece
// evaluate_knight() assigns bonuses and penalties to a knight of a given
// color on a given square.
- void evaluate_knight(const Position &p, Square s, Color us, EvalInfo &ei) {
+ void evaluate_knight(const Position& p, Square s, Color us, EvalInfo& ei) {
- Bitboard b = p.piece_attacks<KNIGHT>(s);
- ei.attackedBy[us][KNIGHT] |= b;
-
- // King attack, mobility and outposts
- evaluate_common(p, b, us, ei, KnightAttackWeight, MidgameKnightMobilityBonus,
- EndgameKnightMobilityBonus, s, KnightOutpostBonus);
+ // Attacks, mobility and outposts
+ evaluate_common<KNIGHT>(p, p.piece_attacks<KNIGHT>(s), us, ei, s);
}
// evaluate_bishop() assigns bonuses and penalties to a bishop of a given
// color on a given square.
- void evaluate_bishop(const Position &p, Square s, Color us, EvalInfo &ei) {
+ void evaluate_bishop(const Position& p, Square s, Color us, EvalInfo& ei) {
Bitboard b = bishop_attacks_bb(s, p.occupied_squares() & ~p.queens(us));
- ei.attackedBy[us][BISHOP] |= b;
- // King attack, mobility and outposts
- evaluate_common(p, b, us, ei, BishopAttackWeight, MidgameBishopMobilityBonus,
- EndgameBishopMobilityBonus, s, BishopOutpostBonus);
+ // Attacks, mobility and outposts
+ evaluate_common<BISHOP>(p, b, us, ei, s);
}
// evaluate_rook() assigns bonuses and penalties to a rook of a given
// color on a given square.
- void evaluate_rook(const Position &p, Square s, Color us, EvalInfo &ei) {
+ void evaluate_rook(const Position& p, Square s, Color us, EvalInfo& ei) {
- //Bitboard b = p.rook_attacks(s);
Bitboard b = rook_attacks_bb(s, p.occupied_squares() & ~p.rooks_and_queens(us));
- ei.attackedBy[us][ROOK] |= b;
- // King attack and mobility
- int mob = evaluate_common(p, b, us, ei, RookAttackWeight, MidgameRookMobilityBonus,
- EndgameRookMobilityBonus);
+ // Attacks and mobility
+ int mob = evaluate_common<ROOK>(p, b, us, ei);
// Rook on 7th rank
Color them = opposite_color(us);
// evaluate_queen() assigns bonuses and penalties to a queen of a given
// color on a given square.
- void evaluate_queen(const Position &p, Square s, Color us, EvalInfo &ei) {
-
- Bitboard b = p.piece_attacks<QUEEN>(s);
- ei.attackedBy[us][QUEEN] |= b;
+ void evaluate_queen(const Position& p, Square s, Color us, EvalInfo& ei) {
- // King attack and mobility
- evaluate_common(p, b, us, ei, QueenAttackWeight, MidgameQueenMobilityBonus,
- EndgameQueenMobilityBonus);
+ // Attacks and mobility
+ evaluate_common<QUEEN>(p, p.piece_attacks<QUEEN>(s), us, ei);
// Queen on 7th rank
Color them = opposite_color(us);
// evaluate_king() assigns bonuses and penalties to a king of a given
// color on a given square.
- void evaluate_king(const Position &p, Square s, Color us, EvalInfo &ei) {
+ void evaluate_king(const Position& p, Square s, Color us, EvalInfo& ei) {
int shelter = 0, sign = Sign[us];
Bitboard occ = p.occupied_squares(), b, b2;
// Initialize the 'attackUnits' variable, which is used later on as an
- // index to the SafetyTable[] array. The initial is based on the number
- // and types of the attacking pieces, the number of attacked and
+ // index to the SafetyTable[] array. The initial value is based on the
+ // number and types of the attacking pieces, the number of attacked and
// 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.kingAdjacentZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3
- + InitKingDanger[relative_square(us, s)] - shelter / 32;
+ + InitKingDanger[relative_square(us, s)] - (shelter >> 5);
// Analyse safe queen contact checks
b = undefended & ei.attacked_by(them, QUEEN) & ~p.pieces_of_color(them);
while (b)
{
Square from, to = pop_1st_bit(&b);
- if (!(escapeSquares & ~queen_attacks_bb(to, occ & clear_mask_bb(s))))
+ 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.
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 & clear_mask_bb(from)) & p.rooks_and_queens(us))
- && !(rook_attacks_bb(to, occ & clear_mask_bb(from)) & p.rooks_and_queens(us)))
-
+ && !(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));
- }
- }
- }
- // Analyse safe distance checks:
+
+ // Analyse safe distance checks
if (QueenCheckBonus > 0 || RookCheckBonus > 0)
{
b = p.piece_attacks<ROOK>(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
// evaluate_passed_pawns() evaluates the passed pawns for both sides.
void evaluate_passed_pawns(const Position &pos, EvalInfo &ei) {
+
bool hasUnstoppable[2] = {false, false};
int movesToGo[2] = {100, 100};
- for(Color us = WHITE; us <= BLACK; us++) {
- Color them = opposite_color(us);
- Square ourKingSq = pos.king_square(us);
- Square theirKingSq = pos.king_square(them);
- Bitboard b = ei.pi->passed_pawns() & pos.pawns(us), b2, b3, b4;
+ for (Color us = WHITE; us <= BLACK; us++)
+ {
+ Color them = opposite_color(us);
+ Square ourKingSq = pos.king_square(us);
+ Square theirKingSq = pos.king_square(them);
+ Bitboard b = ei.pi->passed_pawns() & pos.pawns(us), b2, b3, b4;
- while(b) {
- Square s = pop_1st_bit(&b);
- assert(pos.piece_on(s) == pawn_of_color(us));
- assert(pos.pawn_is_passed(us, s));
-
- int r = int(relative_rank(us, s) - RANK_2);
- int tr = Max(0, r * (r-1));
- Square blockSq = s + pawn_push(us);
-
- // Base bonus based on rank:
- Value mbonus = Value(20 * tr);
- Value ebonus = Value(10 + r * r * 10);
-
- // Adjust bonus based on king proximity:
- ebonus -= Value(square_distance(ourKingSq, blockSq) * 3 * tr);
- ebonus -=
- Value(square_distance(ourKingSq, blockSq + pawn_push(us)) * 1 * tr);
- ebonus += Value(square_distance(theirKingSq, blockSq) * 6 * tr);
-
- // If the pawn is free to advance, increase bonus:
- if(pos.square_is_empty(blockSq)) {
-
- b2 = squares_in_front_of(us, s);
- b3 = b2 & ei.attacked_by(them);
- b4 = b2 & ei.attacked_by(us);
- if((b2 & pos.pieces_of_color(them)) == EmptyBoardBB) {
- // There are no enemy pieces in the pawn's path! Are any of the
- // squares in the pawn's path attacked by the enemy?
- if(b3 == EmptyBoardBB)
- // No enemy attacks, huge bonus!
- ebonus += Value(tr * ((b2 == b4)? 17 : 15));
- else
- // OK, there are enemy attacks. Are those squares which are
- // attacked by the enemy also attacked by us? If yes, big bonus
- // (but smaller than when there are no enemy attacks), if no,
- // somewhat smaller bonus.
- ebonus += Value(tr * (((b3 & b4) == b3)? 13 : 8));
- }
- else {
- // There are some enemy pieces in the pawn's path. While this is
- // sad, we still assign a moderate bonus if all squares in the path
- // which are either occupied by or attacked by enemy pieces are
- // also attacked by us.
- if(((b3 | (b2 & pos.pieces_of_color(them))) & ~b4) == EmptyBoardBB)
- ebonus += Value(tr * 6);
- }
- // At last, add a small bonus when there are no *friendly* pieces
- // in the pawn's path:
- if((b2 & pos.pieces_of_color(us)) == EmptyBoardBB)
- ebonus += Value(tr);
- }
+ while (b)
+ {
+ Square s = pop_1st_bit(&b);
+
+ assert(pos.piece_on(s) == pawn_of_color(us));
+ assert(pos.pawn_is_passed(us, s));
+
+ int r = int(relative_rank(us, s) - RANK_2);
+ int tr = Max(0, r * (r - 1));
+ Square blockSq = s + pawn_push(us);
+
+ // Base bonus based on rank
+ Value mbonus = Value(20 * tr);
+ Value ebonus = Value(10 + r * r * 10);
+
+ // Adjust bonus based on king proximity
+ if (tr != 0)
+ {
+ ebonus -= Value(square_distance(ourKingSq, blockSq) * 3 * tr);
+ ebonus -= Value(square_distance(ourKingSq, blockSq + pawn_push(us)) * 1 * tr);
+ ebonus += Value(square_distance(theirKingSq, blockSq) * 6 * tr);
- // If the pawn is supported by a friendly pawn, increase bonus.
- b2 = pos.pawns(us) & neighboring_files_bb(s);
- if(b2 & rank_bb(s))
- ebonus += Value(r * 20);
- else if(pos.pawn_attacks(them, s) & b2)
- ebonus += Value(r * 12);
-
- // If the other side has only a king, check whether the pawn is
- // unstoppable:
- if(pos.non_pawn_material(them) == Value(0)) {
- Square qsq;
- int d;
-
- qsq = relative_square(us, make_square(square_file(s), RANK_8));
- d = square_distance(s, qsq) - square_distance(theirKingSq, qsq)
- + ((us == pos.side_to_move())? 0 : 1);
-
- if(d < 0) {
- int mtg = RANK_8 - relative_rank(us, s);
- int blockerCount =
- count_1s_max_15(squares_in_front_of(us,s)&pos.occupied_squares());
- mtg += blockerCount;
- d += blockerCount;
- if(d < 0) {
- hasUnstoppable[us] = true;
- movesToGo[us] = Min(movesToGo[us], mtg);
+ // If the pawn is free to advance, increase bonus
+ if (pos.square_is_empty(blockSq))
+ {
+ b2 = squares_in_front_of(us, s);
+ b3 = b2 & ei.attacked_by(them);
+ b4 = b2 & ei.attacked_by(us);
+
+ // If there is an enemy rook or queen attacking the pawn from behind,
+ // add all X-ray attacks by the rook or queen.
+ if ( bit_is_set(ei.attacked_by(them,ROOK) | ei.attacked_by(them,QUEEN),s)
+ && (squares_behind(us, s) & pos.rooks_and_queens(them)))
+ b3 = b2;
+
+ if ((b2 & pos.pieces_of_color(them)) == EmptyBoardBB)
+ {
+ // There are no enemy pieces in the pawn's path! Are any of the
+ // squares in the pawn's path attacked by the enemy?
+ if (b3 == EmptyBoardBB)
+ // No enemy attacks, huge bonus!
+ ebonus += Value(tr * (b2 == b4 ? 17 : 15));
+ else
+ // OK, there are enemy attacks. Are those squares which are
+ // attacked by the enemy also attacked by us? If yes, big bonus
+ // (but smaller than when there are no enemy attacks), if no,
+ // somewhat smaller bonus.
+ ebonus += Value(tr * ((b3 & b4) == b3 ? 13 : 8));
+ }
+ else
+ {
+ // There are some enemy pieces in the pawn's path. While this is
+ // sad, we still assign a moderate bonus if all squares in the path
+ // which are either occupied by or attacked by enemy pieces are
+ // also attacked by us.
+ if (((b3 | (b2 & pos.pieces_of_color(them))) & ~b4) == EmptyBoardBB)
+ ebonus += Value(tr * 6);
+ }
+ // At last, add a small bonus when there are no *friendly* pieces
+ // in the pawn's path.
+ if ((b2 & pos.pieces_of_color(us)) == EmptyBoardBB)
+ ebonus += Value(tr);
+ }
}
- }
- }
- // Rook pawns are a special case: They are sometimes worse, and
- // sometimes better than other passed pawns. It is difficult to find
- // good rules for determining whether they are good or bad. For now,
- // we try the following: Increase the value for rook pawns if the
- // other side has no pieces apart from a knight, and decrease the
- // 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.piece_count(them, KNIGHT) == 1)
- ebonus += ebonus / 4;
- else if(pos.rooks_and_queens(them))
- ebonus -= ebonus / 4;
- }
- // Add the scores for this pawn to the middle game and endgame eval.
- ei.mgValue += apply_weight(Sign[us] * mbonus, WeightPassedPawnsMidgame);
- ei.egValue += apply_weight(Sign[us] * ebonus, WeightPassedPawnsEndgame);
- }
+ // If the pawn is supported by a friendly pawn, increase bonus
+ b2 = pos.pawns(us) & neighboring_files_bb(s);
+ if (b2 & rank_bb(s))
+ ebonus += Value(r * 20);
+ else if (pos.pawn_attacks(them, s) & b2)
+ ebonus += Value(r * 12);
+
+ // If the other side has only a king, check whether the pawn is
+ // unstoppable
+ if (pos.non_pawn_material(them) == Value(0))
+ {
+ Square qsq;
+ int d;
+
+ qsq = relative_square(us, make_square(square_file(s), RANK_8));
+ d = square_distance(s, qsq)
+ - square_distance(theirKingSq, qsq)
+ + (us != pos.side_to_move());
+
+ if (d < 0)
+ {
+ int mtg = RANK_8 - relative_rank(us, s);
+ int blockerCount = count_1s_max_15(squares_in_front_of(us,s) & pos.occupied_squares());
+ mtg += blockerCount;
+ d += blockerCount;
+ if (d < 0)
+ {
+ hasUnstoppable[us] = true;
+ movesToGo[us] = Min(movesToGo[us], mtg);
+ }
+ }
+ }
+ // Rook pawns are a special case: They are sometimes worse, and
+ // sometimes better than other passed pawns. It is difficult to find
+ // good rules for determining whether they are good or bad. For now,
+ // we try the following: Increase the value for rook pawns if the
+ // other side has no pieces apart from a knight, and decrease the
+ // 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.piece_count(them, KNIGHT) <= 1)
+ ebonus += ebonus / 4;
+ else if(pos.rooks_and_queens(them))
+ ebonus -= ebonus / 4;
+ }
+
+ // Add the scores for this pawn to the middle game and endgame eval.
+ ei.mgValue += apply_weight(Sign[us] * mbonus, WeightPassedPawnsMidgame);
+ ei.egValue += apply_weight(Sign[us] * ebonus, WeightPassedPawnsEndgame);
+ }
}
// Does either side have an unstoppable passed pawn?
- if(hasUnstoppable[WHITE] && !hasUnstoppable[BLACK])
- ei.egValue += UnstoppablePawnValue - Value(0x40 * movesToGo[WHITE]);
- else if(hasUnstoppable[BLACK] && !hasUnstoppable[WHITE])
- ei.egValue -= UnstoppablePawnValue - Value(0x40 * movesToGo[BLACK]);
- else if(hasUnstoppable[BLACK] && hasUnstoppable[WHITE]) {
- // Both sides have unstoppable pawns! Try to find out who queens
- // first. We begin by transforming 'movesToGo' to the number of
- // plies until the pawn queens for both sides:
- movesToGo[WHITE] *= 2;
- movesToGo[BLACK] *= 2;
- movesToGo[pos.side_to_move()]--;
-
- // If one side queens at least three plies before the other, that
- // side wins:
- if(movesToGo[WHITE] <= movesToGo[BLACK] - 3)
- ei.egValue += UnstoppablePawnValue - Value(0x40 * (movesToGo[WHITE]/2));
- else if(movesToGo[BLACK] <= movesToGo[WHITE] - 3)
- ei.egValue -= UnstoppablePawnValue - Value(0x40 * (movesToGo[BLACK]/2));
-
- // We could also add some rules about the situation when one side
- // queens exactly one ply before the other: Does the first queen
- // check the opponent's king, or attack the opponent's queening square?
- // This is slightly tricky to get right, because it is possible that
- // the opponent's king has moved somewhere before the first pawn queens.
+ if (hasUnstoppable[WHITE] && !hasUnstoppable[BLACK])
+ ei.egValue += UnstoppablePawnValue - Value(0x40 * movesToGo[WHITE]);
+ else if (hasUnstoppable[BLACK] && !hasUnstoppable[WHITE])
+ ei.egValue -= UnstoppablePawnValue - Value(0x40 * movesToGo[BLACK]);
+ else if (hasUnstoppable[BLACK] && hasUnstoppable[WHITE])
+ {
+ // Both sides have unstoppable pawns! Try to find out who queens
+ // first. We begin by transforming 'movesToGo' to the number of
+ // plies until the pawn queens for both sides.
+ movesToGo[WHITE] *= 2;
+ movesToGo[BLACK] *= 2;
+ movesToGo[pos.side_to_move()]--;
+
+ // If one side queens at least three plies before the other, that
+ // side wins.
+ if (movesToGo[WHITE] <= movesToGo[BLACK] - 3)
+ ei.egValue += UnstoppablePawnValue - Value(0x40 * (movesToGo[WHITE]/2));
+ else if(movesToGo[BLACK] <= movesToGo[WHITE] - 3)
+ ei.egValue -= UnstoppablePawnValue - Value(0x40 * (movesToGo[BLACK]/2));
+
+ // We could also add some rules about the situation when one side
+ // queens exactly one ply before the other: Does the first queen
+ // check the opponent's king, or attack the opponent's queening square?
+ // This is slightly tricky to get right, because it is possible that
+ // the opponent's king has moved somewhere before the first pawn queens.
}
}
void evaluate_trapped_bishop_a7h7(const Position &pos, Square s, Color us,
EvalInfo &ei) {
-
assert(square_is_ok(s));
assert(pos.piece_on(s) == bishop_of_color(us));
assert(square_is_ok(s));
assert(pos.piece_on(s) == bishop_of_color(us));
- if(square_file(s) == FILE_A) {
- b2 = relative_square(us, SQ_B2);
- b3 = relative_square(us, SQ_B3);
- c3 = relative_square(us, SQ_C3);
+ if (square_file(s) == FILE_A)
+ {
+ b2 = relative_square(us, SQ_B2);
+ b3 = relative_square(us, SQ_B3);
+ c3 = relative_square(us, SQ_C3);
+ }
+ else
+ {
+ b2 = relative_square(us, SQ_G2);
+ b3 = relative_square(us, SQ_G3);
+ c3 = relative_square(us, SQ_F3);
}
- else {
- b2 = relative_square(us, SQ_G2);
- b3 = relative_square(us, SQ_G3);
- c3 = relative_square(us, SQ_F3);
+
+ if (pos.piece_on(b2) == pawn)
+ {
+ Value penalty;
+
+ if (!pos.square_is_empty(b3))
+ penalty = 2*TrappedBishopA1H1Penalty;
+ else if (pos.piece_on(c3) == pawn)
+ penalty = TrappedBishopA1H1Penalty;
+ else
+ penalty = TrappedBishopA1H1Penalty / 2;
+
+ ei.mgValue -= Sign[us] * penalty;
+ ei.egValue -= Sign[us] * penalty;
}
+ }
- if(pos.piece_on(b2) == pawn) {
- Value penalty;
- if(!pos.square_is_empty(b3))
- penalty = 2*TrappedBishopA1H1Penalty;
- else if(pos.piece_on(c3) == pawn)
- penalty = TrappedBishopA1H1Penalty;
- else
- penalty = TrappedBishopA1H1Penalty / 2;
+ // evaluate_space() computes the space evaluation for a given side. The
+ // space evaluation is a simple bonus based on the number of safe squares
+ // available for minor pieces on the central four files on ranks 2--4. Safe
+ // squares one, two or three squares behind a friendly pawn are counted
+ // twice. Finally, the space bonus is scaled by a weight taken from the
+ // material hash table.
+
+ void evaluate_space(const Position &pos, Color us, EvalInfo &ei) {
+
+ Color them = opposite_color(us);
- ei.mgValue -= Sign[us] * penalty;
- ei.egValue -= Sign[us] * penalty;
+ // Find the safe squares for our pieces inside the area defined by
+ // SpaceMask[us]. A square is unsafe it is attacked by an enemy
+ // pawn, or if it is undefended and attacked by an enemy piece.
+
+ Bitboard safeSquares = SpaceMask[us]
+ & ~pos.pawns(us)
+ & ~ei.attacked_by(them, PAWN)
+ & ~(~ei.attacked_by(us) & ei.attacked_by(them));
+
+ // Find all squares which are at most three squares behind some friendly
+ // pawn.
+ Bitboard behindFriendlyPawns = pos.pawns(us);
+ if (us == WHITE)
+ {
+ behindFriendlyPawns |= (behindFriendlyPawns >> 8);
+ behindFriendlyPawns |= (behindFriendlyPawns >> 16);
+ }
+ else
+ {
+ behindFriendlyPawns |= (behindFriendlyPawns << 8);
+ behindFriendlyPawns |= (behindFriendlyPawns << 16);
}
+ int space = count_1s_max_15(safeSquares)
+ + count_1s_max_15(behindFriendlyPawns & safeSquares);
+
+ ei.mgValue += Sign[us] * apply_weight(Value(space * ei.mi->space_weight()), WeightSpace);
}
- // apply_weight applies an evaluation weight to a value.
+ // apply_weight() applies an evaluation weight to a value
inline Value apply_weight(Value v, int w) {
return (v*w) / 0x100;
}
- // scale_by_game_phase interpolates between a middle game and an endgame
+ // scale_by_game_phase() interpolates between a middle game and an endgame
// score, based on game phase. It also scales the return value by a
// ScaleFactor array.
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));
}
// an UCI-configurable weight with an internal weight.
int compute_weight(int uciWeight, int internalWeight) {
+
uciWeight = (uciWeight * 0x100) / 100;
return (uciWeight * internalWeight) / 0x100;
}
void init_safety() {
QueenContactCheckBonus = get_option_value_int("Queen Contact Check Bonus");
- RookContactCheckBonus = get_option_value_int("Rook Contact Check Bonus");
QueenCheckBonus = get_option_value_int("Queen Check Bonus");
RookCheckBonus = get_option_value_int("Rook Check Bonus");
BishopCheckBonus = get_option_value_int("Bishop Check Bonus");
SafetyTable[i] = Value(peak);
}
}
-
}