/// rank_bb() and file_bb() return a bitboard representing all the squares on
/// the given file or rank.
- inline Bitboard rank_bb(Rank r) {
+ constexpr Bitboard rank_bb(Rank r) {
- return Rank1BB << (8 * r);
+ return Rank1BB << (FILE_NB * r);
}
- inline Bitboard rank_bb(Square s) {
+ constexpr Bitboard rank_bb(Square s) {
return rank_bb(rank_of(s));
}
/// in front of the given one, from the point of view of the given color. For instance,
/// forward_ranks_bb(BLACK, SQ_D3) will return the 16 squares on ranks 1 and 2.
- inline Bitboard forward_ranks_bb(Color c, Square s) {
+ constexpr Bitboard forward_ranks_bb(Color c, Square s) {
- return c == WHITE ? ~Rank1BB << 8 * relative_rank(WHITE, s)
- : ~Rank8BB >> 8 * relative_rank(BLACK, s);
+ return c == WHITE ? (AllSquares ^ Rank1BB) << FILE_NB * relative_rank(WHITE, s, RANK_MAX)
+ : (AllSquares ^ rank_bb(RANK_MAX)) >> FILE_NB * relative_rank(BLACK, s, RANK_MAX);
+}
+
- inline Bitboard forward_ranks_bb(Color c, Rank r) {
++constexpr Bitboard forward_ranks_bb(Color c, Rank r) {
+ return c == WHITE ? (AllSquares ^ Rank1BB) << FILE_NB * (r - RANK_1)
+ : (AllSquares ^ rank_bb(RANK_MAX)) >> FILE_NB * (RANK_MAX - r);
+}
+
+
+/// promotion_zone_bb() returns a bitboard representing the squares on all the ranks
+/// in front of and on the given relative rank, from the point of view of the given color.
+/// For instance, promotion_zone_bb(BLACK, RANK_7) will return the 16 squares on ranks 1 and 2.
+
+inline Bitboard promotion_zone_bb(Color c, Rank r, Rank maxRank) {
+ return forward_ranks_bb(c, relative_rank(c, r, maxRank)) | rank_bb(relative_rank(c, r, maxRank));
}
}
+ // Evaluation::variant() computes variant-specific evaluation bonuses for a given side.
+
+ template<Tracing T> template<Color Us>
+ Score Evaluation<T>::variant() const {
+
+ constexpr Color Them = ~Us;
+ constexpr Direction Down = pawn_push(Them);
+
+ Score score = SCORE_ZERO;
+
+ // Capture the flag
+ if (pos.capture_the_flag(Us))
+ {
+ PieceType ptCtf = pos.capture_the_flag_piece();
+ Bitboard ctfPieces = pos.pieces(Us, ptCtf);
+ Bitboard ctfTargets = pos.capture_the_flag(Us) & pos.board_bb();
+ Bitboard onHold = 0;
+ Bitboard onHold2 = 0;
+ Bitboard processed = 0;
+ Bitboard blocked = pos.pieces(Us, PAWN) | attackedBy[Them][ALL_PIECES];
+ Bitboard doubleBlocked = attackedBy2[Them]
+ | (pos.pieces(Us, PAWN) & (shift<Down>(pos.pieces()) | attackedBy[Them][ALL_PIECES]))
+ | (pos.pieces(Them) & pe->pawn_attacks(Them))
+ | (pawn_attacks_bb<Them>(pos.pieces(Them, PAWN) & pe->pawn_attacks(Them)));
+ Bitboard inaccessible = pos.pieces(Us, PAWN) & shift<Down>(pos.pieces(Them, PAWN));
+ // Traverse all paths of the CTF pieces to the CTF targets.
+ // Put squares that are attacked or occupied on hold for one iteration.
+ for (int dist = 0; (ctfPieces || onHold || onHold2) && (ctfTargets & ~processed); dist++)
+ {
+ int wins = popcount(ctfTargets & ctfPieces);
+ if (wins)
+ score += make_score(4000, 4000) * wins / (wins + dist * dist);
+ Bitboard current = ctfPieces & ~ctfTargets;
+ processed |= ctfPieces;
+ ctfPieces = onHold & ~processed;
+ onHold = onHold2 & ~processed;
+ onHold2 = 0;
+ while (current)
+ {
+ Square s = pop_lsb(¤t);
+ Bitboard attacks = ( (PseudoAttacks[Us][ptCtf][s] & pos.pieces())
+ | (PseudoMoves[Us][ptCtf][s] & ~pos.pieces())) & ~processed & pos.board_bb();
+ ctfPieces |= attacks & ~blocked;
+ onHold |= attacks & ~doubleBlocked;
+ onHold2 |= attacks & ~inaccessible;
+ }
+ }
+ }
+
+ // nCheck
+ if (pos.check_counting())
+ {
+ int remainingChecks = pos.checks_remaining(Us);
+ assert(remainingChecks > 0);
+ score += make_score(3600, 1000) / (remainingChecks * remainingChecks);
+ }
+
+ // Extinction
+ if (pos.extinction_value() != VALUE_NONE)
+ {
+ for (PieceType pt : pos.extinction_piece_types())
+ if (pt != ALL_PIECES)
+ {
+ int denom = std::max(pos.count(Us, pt) - pos.extinction_piece_count(), 1);
+ if (pos.count(Them, pt) >= pos.extinction_opponent_piece_count() || pos.two_boards())
+ score += make_score(1000000 / (500 + PieceValue[MG][pt]),
+ 1000000 / (500 + PieceValue[EG][pt])) / (denom * denom)
+ * (pos.extinction_value() / VALUE_MATE);
+ }
+ else if (pos.extinction_value() == VALUE_MATE)
+ score += make_score(pos.non_pawn_material(Us), pos.non_pawn_material(Us)) / pos.count<ALL_PIECES>(Us);
+ }
+
+ // Connect-n
+ if (pos.connect_n() > 0)
+ {
+ for (Direction d : {NORTH, NORTH_EAST, EAST, SOUTH_EAST})
+ {
+ // Find sufficiently large gaps
+ Bitboard b = pos.board_bb() & ~pos.pieces(Them);
+ for (int i = 1; i < pos.connect_n(); i++)
+ b &= shift(d, b);
+ // Count number of pieces per gap
+ while (b)
+ {
+ Square s = pop_lsb(&b);
+ int c = 0;
+ for (int j = 0; j < pos.connect_n(); j++)
+ if (pos.pieces(Us) & (s - j * d))
+ c++;
+ score += make_score(200, 200) * c / (pos.connect_n() - c) / (pos.connect_n() - c);
+ }
+ }
+ }
+
+ // Potential piece flips
+ if (pos.flip_enclosed_pieces())
+ {
+ // Stable pieces
+ if (pos.flip_enclosed_pieces() == REVERSI)
+ {
+ Bitboard edges = (FileABB | file_bb(pos.max_file()) | Rank1BB | rank_bb(pos.max_rank())) & pos.board_bb();
+ Bitboard edgePieces = pos.pieces(Us) & edges;
+ while (edgePieces)
+ {
+ Bitboard connectedEdge = attacks_bb(Us, ROOK, pop_lsb(&edgePieces), ~(pos.pieces(Us) & edges)) & edges;
+ if (!more_than_one(connectedEdge & ~pos.pieces(Us)))
+ score += make_score(300, 300);
+ else if (!(connectedEdge & ~pos.pieces()))
+ score += make_score(200, 200);
+ }
+ }
+
+ // Unstable
+ Bitboard unstable = 0;
+ Bitboard drops = pos.drop_region(Them, IMMOBILE_PIECE);
+ while (drops)
+ {
+ Square s = pop_lsb(&drops);
+ if (pos.flip_enclosed_pieces() == REVERSI)
+ {
+ Bitboard b = attacks_bb(Them, QUEEN, s, ~pos.pieces(Us)) & ~PseudoAttacks[Them][KING][s] & pos.pieces(Them);
+ while(b)
+ unstable |= between_bb(s, pop_lsb(&b));
+ }
+ else
+ unstable |= PseudoAttacks[Them][KING][s] & pos.pieces(Us);
+ }
+ score -= make_score(200, 200) * popcount(unstable);
+ }
+
+ if (T)
+ Trace::add(VARIANT, Us, score);
+
+ return score;
+ }
+
+
- // Evaluation::winnable() adjusts the mg and eg score components based on the
- // known attacking/defending status of the players. A single value is derived
- // by interpolation from the mg and eg values and returned.
+ // Evaluation::winnable() adjusts the midgame and endgame score components, based on
+ // the known attacking/defending status of the players. The final value is derived
+ // by interpolation from the midgame and endgame values.
template<Tracing T>
Value Evaluation<T>::winnable(Score score) const {
Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK;
int sf = me->scale_factor(pos, strongSide);
- // If scale is not already specific, scale down the endgame via general heuristics
+ // If scale factor is not already specific, scale down via general heuristics
- if (sf == SCALE_FACTOR_NORMAL)
+ if (sf == SCALE_FACTOR_NORMAL && !pos.captures_to_hand())
{
if (pos.opposite_bishops())
{