X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fposition.h;h=393c1ac9226ade4e18c40d54dcce040298fed3b7;hb=0ad9b51deaaa1f2a8273ed064fbf6425cfbbe4f2;hp=343751ede6201175c894c99c68c002b6495625ff;hpb=c645587270c2b08d327d290d0ae3c3f5e0a30eee;p=stockfish diff --git a/src/position.h b/src/position.h index 343751ed..393c1ac9 100644 --- a/src/position.h +++ b/src/position.h @@ -1,8 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad - Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad + Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,8 +25,12 @@ #include #include "bitboard.h" +#include "evaluate.h" #include "types.h" +#include "nnue/nnue_accumulator.h" + +namespace Stockfish { /// StateInfo struct stores information needed to restore a Position object to /// its previous state when we retract a move. Whenever a move is made on the @@ -37,7 +39,6 @@ struct StateInfo { // Copied when making a move - Key pawnKey; Key materialKey; Value nonPawnMaterial[COLOR_NB]; int castlingRights; @@ -46,21 +47,26 @@ struct StateInfo { Square epSquare; // Not copied when making a move (will be recomputed anyhow) - int repetition; Key key; Bitboard checkersBB; - Piece capturedPiece; StateInfo* previous; Bitboard blockersForKing[COLOR_NB]; Bitboard pinners[COLOR_NB]; Bitboard checkSquares[PIECE_TYPE_NB]; + Piece capturedPiece; + int repetition; + + // Used by NNUE + Eval::NNUE::Accumulator accumulator; + DirtyPiece dirtyPiece; }; + /// A list to keep track of the position states along the setup moves (from the /// start position to the position just before the search starts). Needed by /// 'draw by repetition' detection. Use a std::deque because pointers to /// elements are not invalidated upon list resizing. -typedef std::unique_ptr> StateListPtr; +using StateListPtr = std::unique_ptr>; /// Position class stores information regarding the board representation as @@ -80,58 +86,47 @@ public: // FEN string input/output Position& set(const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th); Position& set(const std::string& code, Color c, StateInfo* si); - const std::string fen() const; + std::string fen() const; // Position representation - Bitboard pieces() const; - Bitboard pieces(PieceType pt) const; - Bitboard pieces(PieceType pt1, PieceType pt2) const; + Bitboard pieces(PieceType pt = ALL_PIECES) const; + template Bitboard pieces(PieceType pt, PieceTypes... pts) const; Bitboard pieces(Color c) const; - Bitboard pieces(Color c, PieceType pt) const; - Bitboard pieces(Color c, PieceType pt1, PieceType pt2) const; + template Bitboard pieces(Color c, PieceTypes... pts) const; Piece piece_on(Square s) const; Square ep_square() const; bool empty(Square s) const; template int count(Color c) const; template int count() const; - template const Square* squares(Color c) const; template Square square(Color c) const; - bool is_on_semiopen_file(Color c, Square s) const; // Castling - int castling_rights(Color c) const; - bool can_castle(CastlingRight cr) const; - bool castling_impeded(CastlingRight cr) const; - Square castling_rook_square(CastlingRight cr) const; + CastlingRights castling_rights(Color c) const; + bool can_castle(CastlingRights cr) const; + bool castling_impeded(CastlingRights cr) const; + Square castling_rook_square(CastlingRights cr) const; // Checking Bitboard checkers() const; Bitboard blockers_for_king(Color c) const; Bitboard check_squares(PieceType pt) const; + Bitboard pinners(Color c) const; // Attacks to/from a given square Bitboard attackers_to(Square s) const; Bitboard attackers_to(Square s, Bitboard occupied) const; - Bitboard attacks_from(PieceType pt, Square s) const; - template Bitboard attacks_from(Square s) const; - template Bitboard attacks_from(Square s, Color c) const; Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const; + template Bitboard attacks_by(Color c) const; // Properties of moves bool legal(Move m) const; bool pseudo_legal(const Move m) const; bool capture(Move m) const; - bool capture_or_promotion(Move m) const; + bool capture_stage(Move m) const; bool gives_check(Move m) const; - bool advanced_pawn_push(Move m) const; Piece moved_piece(Move m) const; Piece captured_piece() const; - // Piece specific - bool pawn_passed(Color c, Square s) const; - bool opposite_bishops() const; - int pawns_on_same_color_squares(Color c, Square s) const; - // Doing and undoing moves void do_move(Move m, StateInfo& newSt); void do_move(Move m, StateInfo& newSt, bool givesCheck); @@ -141,12 +136,12 @@ public: // Static Exchange Evaluation bool see_ge(Move m, Value threshold = VALUE_ZERO) const; + bool see_ge(Move m, Bitboard& occupied, Value threshold = VALUE_ZERO) const; // Accessing hash keys Key key() const; Key key_after(Move m) const; Key material_key() const; - Key pawn_key() const; // Other properties of the position Color side_to_move() const; @@ -157,7 +152,6 @@ public: bool has_game_cycle(int ply) const; bool has_repeated() const; int rule50_count() const; - Score psq_score() const; Value non_pawn_material(Color c) const; Value non_pawn_material() const; @@ -165,81 +159,75 @@ public: bool pos_is_ok() const; void flip(); + // Used by NNUE + StateInfo* state() const; + + void put_piece(Piece pc, Square s); + void remove_piece(Square s); + private: // Initialization helpers (used while setting up a position) void set_castling_right(Color c, Square rfrom); - void set_state(StateInfo* si) const; - void set_check_info(StateInfo* si) const; + void set_state() const; + void set_check_info() const; // Other helpers - void put_piece(Piece pc, Square s); - void remove_piece(Piece pc, Square s); - void move_piece(Piece pc, Square from, Square to); + void move_piece(Square from, Square to); template void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto); + template + Key adjust_key50(Key k) const; // Data members Piece board[SQUARE_NB]; Bitboard byTypeBB[PIECE_TYPE_NB]; Bitboard byColorBB[COLOR_NB]; int pieceCount[PIECE_NB]; - Square pieceList[PIECE_NB][16]; - int index[SQUARE_NB]; int castlingRightsMask[SQUARE_NB]; Square castlingRookSquare[CASTLING_RIGHT_NB]; Bitboard castlingPath[CASTLING_RIGHT_NB]; - int gamePly; - Color sideToMove; - Score psq; Thread* thisThread; StateInfo* st; + int gamePly; + Color sideToMove; bool chess960; }; -namespace PSQT { - extern Score psq[PIECE_NB][SQUARE_NB]; -} - -extern std::ostream& operator<<(std::ostream& os, const Position& pos); +std::ostream& operator<<(std::ostream& os, const Position& pos); inline Color Position::side_to_move() const { return sideToMove; } -inline bool Position::empty(Square s) const { - return board[s] == NO_PIECE; -} - inline Piece Position::piece_on(Square s) const { + assert(is_ok(s)); return board[s]; } -inline Piece Position::moved_piece(Move m) const { - return board[from_sq(m)]; +inline bool Position::empty(Square s) const { + return piece_on(s) == NO_PIECE; } -inline Bitboard Position::pieces() const { - return byTypeBB[ALL_PIECES]; +inline Piece Position::moved_piece(Move m) const { + return piece_on(from_sq(m)); } inline Bitboard Position::pieces(PieceType pt) const { return byTypeBB[pt]; } -inline Bitboard Position::pieces(PieceType pt1, PieceType pt2) const { - return byTypeBB[pt1] | byTypeBB[pt2]; +template +inline Bitboard Position::pieces(PieceType pt, PieceTypes... pts) const { + return pieces(pt) | pieces(pts...); } inline Bitboard Position::pieces(Color c) const { return byColorBB[c]; } -inline Bitboard Position::pieces(Color c, PieceType pt) const { - return byColorBB[c] & byTypeBB[pt]; -} - -inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const { - return byColorBB[c] & (byTypeBB[pt1] | byTypeBB[pt2]); +template +inline Bitboard Position::pieces(Color c, PieceTypes... pts) const { + return pieces(c) & pieces(pts...); } template inline int Position::count(Color c) const { @@ -247,61 +235,56 @@ template inline int Position::count(Color c) const { } template inline int Position::count() const { - return pieceCount[make_piece(WHITE, Pt)] + pieceCount[make_piece(BLACK, Pt)]; -} - -template inline const Square* Position::squares(Color c) const { - return pieceList[make_piece(c, Pt)]; + return count(WHITE) + count(BLACK); } template inline Square Position::square(Color c) const { - assert(pieceCount[make_piece(c, Pt)] == 1); - return pieceList[make_piece(c, Pt)][0]; + assert(count(c) == 1); + return lsb(pieces(c, Pt)); } inline Square Position::ep_square() const { return st->epSquare; } -inline bool Position::is_on_semiopen_file(Color c, Square s) const { - return !(pieces(c, PAWN) & file_bb(s)); -} - -inline bool Position::can_castle(CastlingRight cr) const { +inline bool Position::can_castle(CastlingRights cr) const { return st->castlingRights & cr; } -inline int Position::castling_rights(Color c) const { - return st->castlingRights & (c == WHITE ? WHITE_CASTLING : BLACK_CASTLING); +inline CastlingRights Position::castling_rights(Color c) const { + return c & CastlingRights(st->castlingRights); } -inline bool Position::castling_impeded(CastlingRight cr) const { - return byTypeBB[ALL_PIECES] & castlingPath[cr]; -} +inline bool Position::castling_impeded(CastlingRights cr) const { + assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO); -inline Square Position::castling_rook_square(CastlingRight cr) const { - return castlingRookSquare[cr]; + return pieces() & castlingPath[cr]; } -template -inline Bitboard Position::attacks_from(Square s) const { - assert(Pt != PAWN); - return Pt == BISHOP || Pt == ROOK ? attacks_bb(s, byTypeBB[ALL_PIECES]) - : Pt == QUEEN ? attacks_from(s) | attacks_from(s) - : PseudoAttacks[Pt][s]; -} +inline Square Position::castling_rook_square(CastlingRights cr) const { + assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO); -template<> -inline Bitboard Position::attacks_from(Square s, Color c) const { - return PawnAttacks[c][s]; + return castlingRookSquare[cr]; } -inline Bitboard Position::attacks_from(PieceType pt, Square s) const { - return attacks_bb(pt, s, byTypeBB[ALL_PIECES]); +inline Bitboard Position::attackers_to(Square s) const { + return attackers_to(s, pieces()); } -inline Bitboard Position::attackers_to(Square s) const { - return attackers_to(s, byTypeBB[ALL_PIECES]); +template +inline Bitboard Position::attacks_by(Color c) const { + + if constexpr (Pt == PAWN) + return c == WHITE ? pawn_attacks_bb(pieces(WHITE, PAWN)) + : pawn_attacks_bb(pieces(BLACK, PAWN)); + else + { + Bitboard threats = 0; + Bitboard attackers = pieces(c, Pt); + while (attackers) + threats |= attacks_bb(pop_lsb(attackers), pieces()); + return threats; + } } inline Bitboard Position::checkers() const { @@ -312,45 +295,35 @@ inline Bitboard Position::blockers_for_king(Color c) const { return st->blockersForKing[c]; } -inline Bitboard Position::check_squares(PieceType pt) const { - return st->checkSquares[pt]; +inline Bitboard Position::pinners(Color c) const { + return st->pinners[c]; } -inline bool Position::pawn_passed(Color c, Square s) const { - return !(pieces(~c, PAWN) & passed_pawn_span(c, s)); -} - -inline bool Position::advanced_pawn_push(Move m) const { - return type_of(moved_piece(m)) == PAWN - && relative_rank(sideToMove, to_sq(m)) > RANK_5; -} - -inline int Position::pawns_on_same_color_squares(Color c, Square s) const { - return popcount(pieces(c, PAWN) & ((DarkSquares & s) ? DarkSquares : ~DarkSquares)); +inline Bitboard Position::check_squares(PieceType pt) const { + return st->checkSquares[pt]; } inline Key Position::key() const { - return st->key; + return adjust_key50(st->key); } -inline Key Position::pawn_key() const { - return st->pawnKey; +template +inline Key Position::adjust_key50(Key k) const +{ + return st->rule50 < 14 - AfterMove + ? k : k ^ make_key((st->rule50 - (14 - AfterMove)) / 8); } inline Key Position::material_key() const { return st->materialKey; } -inline Score Position::psq_score() const { - return psq; -} - inline Value Position::non_pawn_material(Color c) const { return st->nonPawnMaterial[c]; } inline Value Position::non_pawn_material() const { - return st->nonPawnMaterial[WHITE] + st->nonPawnMaterial[BLACK]; + return non_pawn_material(WHITE) + non_pawn_material(BLACK); } inline int Position::game_ply() const { @@ -361,25 +334,22 @@ inline int Position::rule50_count() const { return st->rule50; } -inline bool Position::opposite_bishops() const { - return pieceCount[W_BISHOP] == 1 - && pieceCount[B_BISHOP] == 1 - && opposite_colors(square(WHITE), square(BLACK)); -} - inline bool Position::is_chess960() const { return chess960; } -inline bool Position::capture_or_promotion(Move m) const { +inline bool Position::capture(Move m) const { assert(is_ok(m)); - return type_of(m) != NORMAL ? type_of(m) != CASTLING : !empty(to_sq(m)); + return (!empty(to_sq(m)) && type_of(m) != CASTLING) + || type_of(m) == EN_PASSANT; } -inline bool Position::capture(Move m) const { +// returns true if a move is generated from the capture stage +// having also queen promotions covered, i.e. consistency with the capture stage move generation +// is needed to avoid the generation of duplicate moves. +inline bool Position::capture_stage(Move m) const { assert(is_ok(m)); - // Castling is encoded as "king captures rook" - return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == ENPASSANT; + return capture(m) || promotion_type(m) == QUEEN; } inline Piece Position::captured_piece() const { @@ -393,50 +363,43 @@ inline Thread* Position::this_thread() const { inline void Position::put_piece(Piece pc, Square s) { board[s] = pc; - byTypeBB[ALL_PIECES] |= s; - byTypeBB[type_of(pc)] |= s; + byTypeBB[ALL_PIECES] |= byTypeBB[type_of(pc)] |= s; byColorBB[color_of(pc)] |= s; - index[s] = pieceCount[pc]++; - pieceList[pc][index[s]] = s; + pieceCount[pc]++; pieceCount[make_piece(color_of(pc), ALL_PIECES)]++; - psq += PSQT::psq[pc][s]; } -inline void Position::remove_piece(Piece pc, Square s) { +inline void Position::remove_piece(Square s) { - // WARNING: This is not a reversible operation. If we remove a piece in - // do_move() and then replace it in undo_move() we will put it at the end of - // the list and not in its original place, it means index[] and pieceList[] - // are not invariant to a do_move() + undo_move() sequence. + Piece pc = board[s]; byTypeBB[ALL_PIECES] ^= s; byTypeBB[type_of(pc)] ^= s; byColorBB[color_of(pc)] ^= s; - /* board[s] = NO_PIECE; Not needed, overwritten by the capturing one */ - Square lastSquare = pieceList[pc][--pieceCount[pc]]; - index[lastSquare] = index[s]; - pieceList[pc][index[lastSquare]] = lastSquare; - pieceList[pc][pieceCount[pc]] = SQ_NONE; + board[s] = NO_PIECE; + pieceCount[pc]--; pieceCount[make_piece(color_of(pc), ALL_PIECES)]--; - psq -= PSQT::psq[pc][s]; } -inline void Position::move_piece(Piece pc, Square from, Square to) { +inline void Position::move_piece(Square from, Square to) { - // index[from] is not updated and becomes stale. This works as long as index[] - // is accessed just by known occupied squares. - Bitboard fromTo = square_bb(from) | square_bb(to); + Piece pc = board[from]; + Bitboard fromTo = from | to; byTypeBB[ALL_PIECES] ^= fromTo; byTypeBB[type_of(pc)] ^= fromTo; byColorBB[color_of(pc)] ^= fromTo; board[from] = NO_PIECE; board[to] = pc; - index[to] = index[from]; - pieceList[pc][index[to]] = to; - psq += PSQT::psq[pc][to] - PSQT::psq[pc][from]; } inline void Position::do_move(Move m, StateInfo& newSt) { do_move(m, newSt, gives_check(m)); } +inline StateInfo* Position::state() const { + + return st; +} + +} // namespace Stockfish + #endif // #ifndef POSITION_H_INCLUDED