From 87697f10100fc15dde5eb4fde8e7834bf0cfc6cd Mon Sep 17 00:00:00 2001 From: winapiadmin <138602885+winapiadmin@users.noreply.github.com> Date: Wed, 12 Nov 2025 11:11:52 +0000 Subject: [PATCH] super-OPTIMIZED! --- examples/perft_with_tt.cpp | 4 +- position.cpp | 2 +- position.h | 165 +++++++++++++++---------------------- printers.cpp | 8 +- 4 files changed, 74 insertions(+), 105 deletions(-) diff --git a/examples/perft_with_tt.cpp b/examples/perft_with_tt.cpp index 51905cc..2b0d877 100644 --- a/examples/perft_with_tt.cpp +++ b/examples/perft_with_tt.cpp @@ -121,11 +121,11 @@ template void benchmark(Position &pos) { int main() { - Position pos("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); + Position pos; #ifdef TT_ENABLED tt.resize(1 << 28); #endif - benchmark<6>(pos); + benchmark<7>(pos); } diff --git a/position.cpp b/position.cpp index a2966a2..482eda3 100644 --- a/position.cpp +++ b/position.cpp @@ -654,7 +654,7 @@ template template void _Position)>(history.data() + history.size_++, ¤t_state); + history.push_back(current_state); current_state.mv = move; // Update the move in the current state #if defined(_DEBUG) || !defined(NDEBUG) assert(target_piecetype != KING && "No captures"); diff --git a/position.h b/position.h index 42db8eb..e92e913 100644 --- a/position.h +++ b/position.h @@ -8,6 +8,7 @@ #include #include #include +#include "printers.h" #if defined(_MSC_VER) #include #endif @@ -34,100 +35,14 @@ inline void aligned_free(void *ptr) { free(ptr); #endif } -template inline void memcpy_handimpl(void *dst, const void *src) { - static_assert(N > 0, "Size must be > 0"); - -#define MEMCPY_SCALAR(dst, src, N) \ - do { \ - uint8_t *d8 = (uint8_t *)(dst); \ - const uint8_t *s8 = (const uint8_t *)(src); \ - for (size_t t = 0; t < (N); ++t) \ - d8[t] = s8[t]; \ - } while (0) - -// SSE (128-bit) unaligned copy -#define MEMCPY_SSE(dst, src, N) \ - do { \ - size_t i = 0; \ - for (; i + 16 <= (N); i += 16) { \ - __m128i tmp = _mm_loadu_si128((__m128i *)((const uint8_t *)(src) + i)); \ - _mm_storeu_si128((__m128i *)((uint8_t *)(dst) + i), tmp); \ - } \ - MEMCPY_SCALAR((uint8_t *)(dst) + i, (const uint8_t *)(src) + i, (N) - i); \ - } while (0) - -// SSE2 (128-bit, more instructions) -#define MEMCPY_SSE2 MEMCPY_SSE - -// SSSE3 / SSE4.1: same copy pattern, can add shuffle/optimized if needed -#define MEMCPY_SSSE3 MEMCPY_SSE -#define MEMCPY_SSE41 MEMCPY_SSE - -// AVX (256-bit) -#define MEMCPY_AVX(dst, src, N) \ - do { \ - size_t i = 0; \ - for (; i + 32 <= (N); i += 32) { \ - __m256i tmp = _mm256_loadu_si256((__m256i *)((const uint8_t *)(src) + i)); \ - _mm256_storeu_si256((__m256i *)((uint8_t *)(dst) + i), tmp); \ - } \ - MEMCPY_SCALAR((uint8_t *)(dst) + i, (const uint8_t *)(src) + i, (N) - i); \ - } while (0) - -// AVX2 (256-bit, more instructions) -#define MEMCPY_AVX2 MEMCPY_AVX - -// AVX512 (512-bit) -#define MEMCPY_AVX512(dst, src, N) \ - do { \ - size_t i = 0; \ - for (; i + 64 <= (N); i += 64) { \ - __m512i tmp = _mm512_loadu_si512((__m512i *)((const uint8_t *)(src) + i)); \ - _mm512_storeu_si512((__m512i *)((uint8_t *)(dst) + i), tmp); \ - } \ - MEMCPY_SCALAR((uint8_t *)(dst) + i, (const uint8_t *)(src) + i, (N) - i); \ - } while (0) - -// Helper macro to select automatically based on compiler defines -#if defined(__AVX512F__) -#define MEMCPY_BEST(dst, src, N) MEMCPY_AVX512(dst, src, N) -#elif defined(__AVX2__) -#define MEMCPY_BEST(dst, src, N) MEMCPY_AVX2(dst, src, N) -#elif defined(__AVX__) -#define MEMCPY_BEST(dst, src, N) MEMCPY_AVX(dst, src, N) -#elif defined(__SSE4_1__) -#define MEMCPY_BEST(dst, src, N) MEMCPY_SSE41(dst, src, N) -#elif defined(__SSSE3__) -#define MEMCPY_BEST(dst, src, N) MEMCPY_SSSE3(dst, src, N) -#elif defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || (_M_IX86_FP == 2) -#define MEMCPY_BEST(dst, src, N) MEMCPY_SSE2(dst, src, N) -#elif defined(__SSE__) || (_M_IX86_FP == 1) -#define MEMCPY_BEST(dst, src, N) MEMCPY_SSE(dst, src, N) -#else -#define MEMCPY_BEST(dst, src, N) MEMCPY_SCALAR(dst, src, N) -#endif - MEMCPY_BEST(dst, src, N); -#undef MEMCPY_BEST -#undef MEMCPY_AVX512 -#undef MEMCPY_AVX2 -#undef MEMCPY_AVX -#undef MEMCPY_SSE41 -#undef MEMCPY_SSSE3 -#undef MEMCPY_SSE2 -#undef MEMCPY_SSE -#undef MEMCPY_SCALAR - //return dst; -} } // namespace _chess -template struct alignas(64) HistoryEntry { +template struct alignas(32) HistoryEntry { // Bitboards for each piece type (white and black) struct { Bitboard pieces[7]; Bitboard occ[COLOR_NB]; }; - Piece pieces_list[SQUARE_NB] = { Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, - Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE, Piece::NO_PIECE }; Color turn; // true if white to move Move mv; Key hash; @@ -246,6 +161,9 @@ template inline void legals(Movelist &out) const { @@ -296,9 +214,59 @@ template void doMove(const Move &move); - template inline auto undoMove() -> std::conditional_t &, void> { - // manual impl - _chess::memcpy_handimpl)>(¤t_state, history.data() + (--history.size_)); + template + inline auto undoMove() -> std::conditional_t &, void> { + // Save only the move (we'll restore the full state next) + const Move move = current_state.mv; + + // Make sure there's something to pop + assert(history.size_ > 0 && "undoMove called with empty history"); + + // Restore previous state from history + current_state = history.pop(); + + // After restore, sideToMove() is the mover + const Color mover = sideToMove(); + // Squares to update + Square sqs[4]; + int n_sqs = 0; + sqs[n_sqs++] = move.from_sq(); + sqs[n_sqs++] = move.to_sq(); + switch(auto type = move.type_of()){ + case CASTLING: { + bool is_king_side = file_of(move.to_sq()) > file_of(move.from_sq()); + sqs[n_sqs++] = relative_square(mover, is_king_side ? SQ_G1 : SQ_C1); // king to + sqs[n_sqs++] = relative_square(mover, is_king_side ? SQ_F1 : SQ_D1); // rook to + break; + } + case EN_PASSANT: { + sqs[n_sqs++] = static_cast(static_cast(move.to_sq()) - pawn_push(mover)); + break; + } + } + // Update all squares + for (int i = 0; i < n_sqs; ++i) { + + const Square sq = sqs[i]; + Bitboard sq_bb = 1ULL << sq; + + if ((occ()&sq_bb)==0) { + pieces_list[sq] = PieceC::NO_PIECE; + continue; + } + + // Determine color first + Color pc = (current_state.occ[WHITE] & sq_bb) ? WHITE : BLACK; + + // Find piece type (can be branchless via bit scan) + PieceType pt = PAWN; + for (; pt <= KING; ++pt) { + if (current_state.pieces[pt] & sq_bb) break; + } + + pieces_list[sq] = make_piece(pt, pc); + } + if constexpr (RetAll) { return current_state; } @@ -310,6 +278,7 @@ template (pt, c); - current_state.hash ^= zobrist::RandomPiece[enum_idx()][(int)current_state.pieces_list[sq]][sq]; + pieces_list[sq] = make_piece(pt, c); + current_state.hash ^= zobrist::RandomPiece[enum_idx()][(int)pieces_list[sq]][sq]; if constexpr (pt == KING) current_state.kings[c] = sq; } @@ -431,7 +400,7 @@ template ()][static_cast(make_piece(pt, c))][sq]; if constexpr (pt == KING) current_state.kings[c] = SQ_NONE; @@ -445,8 +414,8 @@ template (pt, c); - current_state.hash ^= zobrist::RandomPiece[enum_idx()][(int)current_state.pieces_list[sq]][sq]; + pieces_list[sq] = make_piece(pt, c); + current_state.hash ^= zobrist::RandomPiece[enum_idx()][(int)pieces_list[sq]][sq]; current_state.kings[c] = a ? sq : current_state.kings[c]; } @@ -457,7 +426,7 @@ template ()][static_cast(make_piece(pt, c))][sq]; current_state.kings[c] = a ? SQ_NONE : current_state.kings[c]; } @@ -469,9 +438,9 @@ template ? EnginePieceToChar : PolyglotPieceToChar; return os << PieceToChar[(int)p]; } std::ostream &operator<<(std::ostream &os, const EnginePiece &p) { - constexpr std::string_view EnginePieceToChar(" PNBRQK pnbrqk "); - constexpr std::string_view PolyglotPieceToChar("PNBRQKpnbrqk "); + constexpr std::string_view EnginePieceToChar(".PNBRQK'/pnbrqk,"); + constexpr std::string_view PolyglotPieceToChar("PNBRQKpnbrqk."); constexpr std::string_view PieceToChar = std::is_same_v ? EnginePieceToChar : PolyglotPieceToChar; return os << PieceToChar[(int)p]; }