/// Bitboards::pretty() returns an ASCII representation of a bitboard suitable
/// to be printed to standard output. Useful for debugging.
- const std::string Bitboards::pretty(Bitboard b) {
+ std::string Bitboards::pretty(Bitboard b) {
- std::string s = "+---+---+---+---+---+---+---+---+\n";
+ std::string s = "+---+---+---+---+---+---+---+---+---+---+---+---+\n";
- for (Rank r = RANK_8; r >= RANK_1; --r)
+ for (Rank r = RANK_MAX; r >= RANK_1; --r)
{
- for (File f = FILE_A; f <= FILE_H; ++f)
+ for (File f = FILE_A; f <= FILE_MAX; ++f)
s += b & make_square(f, r) ? "| X " : "| ";
- s += "| " + std::to_string(1 + r) + "\n+---+---+---+---+---+---+---+---+\n";
+ s += "| " + std::to_string(1 + r) + "\n+---+---+---+---+---+---+---+---+---+---+---+---+\n";
}
- s += " a b c d e f g h\n";
+ s += " a b c d e f g h i j k\n";
return s;
}
namespace Bitboards {
+void init_pieces();
void init();
- const std::string pretty(Bitboard b);
+ std::string pretty(Bitboard b);
}
/// the program was compiled) or "Stockfish <Version>", depending on whether
/// Version is empty.
- const string engine_info(bool to_uci, bool to_xboard) {
-string engine_info(bool to_uci) {
++string engine_info(bool to_uci, bool to_xboard) {
const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
string month, day, year;
#include "types.h"
- const std::string engine_info(bool to_uci = false, bool to_xboard = false);
- const std::string compiler_info();
-std::string engine_info(bool to_uci = false);
++std::string engine_info(bool to_uci = false, bool to_xboard = false);
+ std::string compiler_info();
void prefetch(void* addr);
void start_logger(const std::string& fname);
void* std_aligned_alloc(size_t alignment, size_t size);
/// Position::fen() returns a FEN representation of the position. In case of
/// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function.
- const string Position::fen(bool sfen, bool showPromoted, int countStarted, std::string holdings) const {
-string Position::fen() const {
++string Position::fen(bool sfen, bool showPromoted, int countStarted, std::string holdings) const {
int emptyCnt;
std::ostringstream ss;
Position& operator=(const Position&) = delete;
// FEN string input/output
- Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th);
+ Position& set(const Variant* v, const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th, bool sfen = false);
Position& set(const std::string& code, Color c, StateInfo* si);
- const std::string fen(bool sfen = false, bool showPromoted = false, int countStarted = 0, std::string holdings = "-") const;
- std::string fen() const;
++ std::string fen(bool sfen = false, bool showPromoted = false, int countStarted = 0, std::string holdings = "-") const;
+
+ // Variant rule properties
+ const Variant* variant() const;
+ Rank max_rank() const;
+ File max_file() const;
+ bool two_boards() const;
+ Bitboard board_bb() const;
+ Bitboard board_bb(Color c, PieceType pt) const;
+ const std::set<PieceType>& piece_types() const;
+ const std::string& piece_to_char() const;
+ const std::string& piece_to_char_synonyms() const;
+ Rank promotion_rank() const;
+ const std::set<PieceType, std::greater<PieceType> >& promotion_piece_types() const;
+ bool sittuyin_promotion() const;
+ int promotion_limit(PieceType pt) const;
+ PieceType promoted_piece_type(PieceType pt) const;
+ bool piece_promotion_on_capture() const;
+ bool mandatory_pawn_promotion() const;
+ bool mandatory_piece_promotion() const;
+ bool piece_demotion() const;
+ bool blast_on_capture() const;
+ bool endgame_eval() const;
+ bool double_step_enabled() const;
+ Rank double_step_rank_max() const;
+ Rank double_step_rank_min() const;
+ bool castling_enabled() const;
+ bool castling_dropped_piece() const;
+ File castling_kingside_file() const;
+ File castling_queenside_file() const;
+ Rank castling_rank(Color c) const;
+ File castling_king_file() const;
+ PieceType castling_king_piece() const;
+ PieceType castling_rook_piece() const;
+ PieceType king_type() const;
+ PieceType nnue_king() const;
+ bool checking_permitted() const;
+ bool drop_checks() const;
+ bool must_capture() const;
+ bool has_capture() const;
+ bool must_drop() const;
+ bool piece_drops() const;
+ bool drop_loop() const;
+ bool captures_to_hand() const;
+ bool first_rank_pawn_drops() const;
+ bool drop_on_top() const;
+ EnclosingRule enclosing_drop() const;
+ Bitboard drop_region(Color c) const;
+ Bitboard drop_region(Color c, PieceType pt) const;
+ bool sittuyin_rook_drop() const;
+ bool drop_opposite_colored_bishop() const;
+ bool drop_promoted() const;
+ PieceType drop_no_doubled() const;
+ bool immobility_illegal() const;
+ bool gating() const;
+ bool arrow_gating() const;
+ bool seirawan_gating() const;
+ bool cambodian_moves() const;
+ Bitboard diagonal_lines() const;
+ bool pass() const;
+ bool pass_on_stalemate() const;
+ Bitboard promoted_soldiers(Color c) const;
+ bool makpong() const;
+ EnclosingRule flip_enclosed_pieces() const;
+ // winning conditions
+ int n_move_rule() const;
+ int n_fold_rule() const;
+ Value stalemate_value(int ply = 0) const;
+ Value checkmate_value(int ply = 0) const;
+ Value extinction_value(int ply = 0) const;
+ bool extinction_claim() const;
+ const std::set<PieceType>& extinction_piece_types() const;
+ bool extinction_single_piece() const;
+ int extinction_piece_count() const;
+ int extinction_opponent_piece_count() const;
+ PieceType capture_the_flag_piece() const;
+ Bitboard capture_the_flag(Color c) const;
+ bool flag_move() const;
+ bool check_counting() const;
+ int connect_n() const;
+ CheckCount checks_remaining(Color c) const;
+ MaterialCounting material_counting() const;
+ CountingRule counting_rule() const;
+
+ // Variant-specific properties
+ int count_in_hand(PieceType pt) const;
+ int count_in_hand(Color c, PieceType pt) const;
+ int count_with_hand(Color c, PieceType pt) const;
+ bool bikjang() const;
+ bool allow_virtual_drop(Color c, PieceType pt) const;
// Position representation
- Bitboard pieces(PieceType pt) const;
+ Bitboard pieces(PieceType pt = ALL_PIECES) const;
Bitboard pieces(PieceType pt1, PieceType pt2) const;
Bitboard pieces(Color c) const;
Bitboard pieces(Color c, PieceType pt) const;
// Step 8. Null move search with verification search (~40 Elo)
if ( !PvNode
&& (ss-1)->currentMove != MOVE_NULL
- && (ss-1)->statScore < 22661
+ && (ss-1)->statScore < 24185
&& eval >= beta
&& eval >= ss->staticEval
- && ss->staticEval >= beta - 24 * depth - 34 * improving + 162 * ss->ttPv + 159
+ && ss->staticEval >= beta - 24 * depth - 34 * improving + 162 * ss->ttPv + 159 + 200 * (!pos.double_step_enabled() && pos.piece_to_char()[PAWN] != ' ')
&& !excludedMove
&& pos.non_pawn_material(us)
+ && pos.count<ALL_PIECES>(~us) != pos.count<PAWN>(~us)
+ && !pos.flip_enclosed_pieces()
&& (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor))
{
assert(eval - beta >= 0);
// Calculate new depth for this move
newDepth = depth - 1;
- // Step 12. Pruning at shallow depth (~200 Elo)
+ // Step 13. Pruning at shallow depth (~200 Elo)
if ( !rootNode
- && pos.non_pawn_material(us)
+ && (pos.non_pawn_material(us) || pos.count<ALL_PIECES>(us) == pos.count<PAWN>(us))
&& bestValue > VALUE_TB_LOSS_IN_MAX_PLY)
{
// Skip quiet moves if movecount exceeds our FutilityMoveCount threshold
// Futility pruning: parent node (~5 Elo)
if ( lmrDepth < 7
&& !ss->inCheck
- && ss->staticEval + 174 + 157 * lmrDepth <= alpha
- && (*contHist[0])[movedPiece][to_sq(move)]
- + (*contHist[1])[movedPiece][to_sq(move)]
- + (*contHist[3])[movedPiece][to_sq(move)]
- + (*contHist[5])[movedPiece][to_sq(move)] / 3 < 28255)
+ && !pos.extinction_single_piece()
+ && ss->staticEval + (174 + 157 * lmrDepth) * (1 + pos.check_counting()) <= alpha
+ && (*contHist[0])[history_slot(movedPiece)][to_sq(move)]
+ + (*contHist[1])[history_slot(movedPiece)][to_sq(move)]
+ + (*contHist[3])[history_slot(movedPiece)][to_sq(move)]
- + (*contHist[5])[history_slot(movedPiece)][to_sq(move)] / 3 < 26237)
++ + (*contHist[5])[history_slot(movedPiece)][to_sq(move)] / 3 < 28255)
continue;
// Prune moves with negative SEE (~20 Elo)
ss->currentMove = move;
ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck]
[captureOrPromotion]
- [movedPiece]
+ [history_slot(movedPiece)]
[to_sq(move)];
- // Step 14. Make the move
+ // Step 15. Make the move
pos.do_move(move, st, givesCheck);
- // Step 15. Reduced depth search (LMR, ~200 Elo). If the move fails high it will be
- // re-searched at full depth.
+ (ss+1)->distanceFromPv = ss->distanceFromPv + moveCount - 1;
+
+ // Step 16. Late moves reduction / extension (LMR, ~200 Elo)
+ // We use various heuristics for the sons of a node after the first son has
+ // been searched. In general we would like to reduce them, but there are many
+ // cases where we extend a son if it has good chances to be "interesting".
if ( depth >= 3
&& moveCount > 1 + 2 * rootNode
+ && !(pos.must_capture() && pos.has_capture())
&& ( !captureOrPromotion
|| moveCountPruning
|| ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha
r -= 2 + ss->ttPv - (type_of(movedPiece) == PAWN);
ss->statScore = thisThread->mainHistory[us][from_to(move)]
- + (*contHist[0])[movedPiece][to_sq(move)]
- + (*contHist[1])[movedPiece][to_sq(move)]
- + (*contHist[3])[movedPiece][to_sq(move)]
+ + (*contHist[0])[history_slot(movedPiece)][to_sq(move)]
+ + (*contHist[1])[history_slot(movedPiece)][to_sq(move)]
+ + (*contHist[3])[history_slot(movedPiece)][to_sq(move)]
- - 5337;
+ - 4741;
// Decrease/increase reduction by comparing opponent's stat score (~10 Elo)
if (ss->statScore >= -89 && (ss-1)->statScore < -116)
r++;
// Decrease/increase reduction for moves with a good/bad history (~30 Elo)
- // If we are not in check use statScore, if we are in check
- // use sum of main history and first continuation history with an offset
+ // If we are not in check use statScore, but if we are in check we use
+ // the sum of main history and first continuation history with an offset.
if (ss->inCheck)
r -= (thisThread->mainHistory[us][from_to(move)]
- + (*contHist[0])[history_slot(movedPiece)][to_sq(move)] - 4341) / 16384;
- + (*contHist[0])[movedPiece][to_sq(move)] - 3833) / 16384;
++ + (*contHist[0])[history_slot(movedPiece)][to_sq(move)] - 3833) / 16384;
else
- r -= ss->statScore / (14382 - 4434 * pos.captures_to_hand());
- r -= ss->statScore / 14790;
++ r -= ss->statScore / (14790 - 4434 * pos.captures_to_hand());
}
- Depth d = std::clamp(newDepth - r, 1, newDepth);
+ // In general we want to cap the LMR depth search at newDepth. But for nodes
+ // close to the principal variation the cap is at (newDepth + 1), which will
+ // allow these nodes to be searched deeper than the pv (up to 4 plies deeper).
+ Depth d = std::clamp(newDepth - r, 1, newDepth + ((ss+1)->distanceFromPv <= 4));
value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true);