diff --git a/src/Hash.hpp b/src/Hash.hpp index 1c6542e..6b9352a 100644 --- a/src/Hash.hpp +++ b/src/Hash.hpp @@ -189,6 +189,11 @@ class HashTable { return m_full * 1000 / m_table.size(); } + + void prefetch(Hash hash) + { + __builtin_prefetch(&m_table[index(hash)]); + } }; diff --git a/src/Position.cpp b/src/Position.cpp index a3ae0cb..17e4467 100644 --- a/src/Position.cpp +++ b/src/Position.cpp @@ -404,6 +404,69 @@ Board Board::make_move(Move move) const } +Hash Board::hash_after(Move move) const +{ + Hash result = hash() ^ Zobrist::get_black_move(); + + // Moved piece (and handle promotions) + PieceType piece = get_piece_at(move.from()); + PieceType target_piece = move.is_promotion() ? move.promo_piece() : piece; + result ^= Zobrist::get_piece_turn_square(piece, turn(), move.from()); + result ^= Zobrist::get_piece_turn_square(target_piece, turn(), move.to()); + + // Handle special moves + if (move.is_capture()) + { + // Remove captured piece, if any + Square target = move.is_ep_capture() ? move.to() - (turn() == WHITE ? 8 : -8) : move.to(); + PieceType captured = get_piece_at(target); + result ^= Zobrist::get_piece_turn_square(captured, ~turn(), target); + + // Castling: check if any rook has been captured + if (captured == ROOK) + for (auto side : { KINGSIDE, QUEENSIDE }) + if (castling_rights(side, ~turn()) && move.to() == get_rook_square(m_castling_rights[side][~turn()], ~turn())) + result ^= Zobrist::get_castle_side_turn(side, ~turn()); + } + else if (move.is_double_pawn_push()) + { + // Update ep square + result ^= Zobrist::get_ep_file(file(move.to())); + } + else if (move.is_castle()) + { + // Castling: update the hash of the rook + CastleSide side = file(move.to()) >= 4 ? KINGSIDE : QUEENSIDE; + Square iS = get_rook_square(m_castling_rights[side][turn()], turn()); + Square iE = move.to() + (side == KINGSIDE ? -1 : +1); + result ^= Zobrist::get_piece_turn_square(ROOK, turn(), iS); + result ^= Zobrist::get_piece_turn_square(ROOK, turn(), iE); + } + + // Reset castling rights after a king or rook move + if (piece == KING) + { + // Unset all castling rights after a king move + for (auto side : { KINGSIDE, QUEENSIDE }) + if (castling_rights(side, turn())) + result ^= Zobrist::get_castle_side_turn(side, turn()); + } + else if (piece == ROOK) + { + // Unset castling rights for a certain side if a rook moves + for (auto side : { KINGSIDE, QUEENSIDE }) + if (castling_rights(side, turn()) && move.from() == get_rook_square(m_castling_rights[side][turn()], turn())) + result ^= Zobrist::get_castle_side_turn(side, turn()); + } + + // Reset previous en-passant hash + if (m_enpassant_square != SQUARE_NULL) + result ^= Zobrist::get_ep_file(file(m_enpassant_square)); + + return result; +} + + bool Board::is_valid() const { // Side not to move in check? @@ -915,6 +978,12 @@ Move Position::last_move(std::size_t offset) const } +const Board& Position::last_board() const +{ + return m_boards[m_boards.size() - 2]; +} + + std::ostream& operator<<(std::ostream& out, const Board& board) { out << " +------------------------+\n"; diff --git a/src/Position.hpp b/src/Position.hpp index 1e79eb0..17c6700 100644 --- a/src/Position.hpp +++ b/src/Position.hpp @@ -475,6 +475,9 @@ class Board void generate_moves(MoveList& list, MoveGenType type) const; + Hash hash_after(Move move) const; + + inline void set_piece(PieceType piece, Turn turn, Square square) { m_pieces[piece][turn].set(square); @@ -756,6 +759,9 @@ class Position Move last_move(std::size_t offset = 0) const; + + + const Board& last_board() const; }; diff --git a/src/Search.cpp b/src/Search.cpp index ca46fc9..92f2762 100644 --- a/src/Search.cpp +++ b/src/Search.cpp @@ -595,6 +595,8 @@ namespace Search } } + ttable.prefetch(position.board().hash_after(move)); + // Make the move Score score = -SCORE_INFINITE; bool captureOrPromotion = move.is_capture() || move.is_promotion(); @@ -825,6 +827,8 @@ namespace Search if (!InCheck && position.board().see(move) < 0) continue; + ttable.prefetch(position.board().hash_after(move)); + // PVS Score score; position.make_move(move); diff --git a/src/Search.hpp b/src/Search.hpp index 8e92d5b..7372827 100644 --- a/src/Search.hpp +++ b/src/Search.hpp @@ -197,6 +197,10 @@ namespace Search int64_t n_nodes = 0; auto move_list = position.generate_moves(MoveGenType::LEGAL); + // Hash update + if (VALIDITY && position.last_move() != MOVE_NULL && position.last_board().hash_after(position.last_move()) != position.hash()) + return 0; + // Move counting if (USE_ORDER) {