Anonymous
Как я могу дополнительно оптимизировать генерацию перемещения в моем шахматном двигателе C ++? [закрыто]
Сообщение
Anonymous » 10 сен 2025, 10:21
Я строю шахматный двигатель в C ++ и в настоящее время работаю над генерацией движения. Чтобы измерить производительность, я использую Perft, но моя главная цель состоит в том, чтобы сделать сам генератор движения быстрее.
, std :: counst_zero , std :: popcount )
[*] Эффективная компоновка и повторное использование данных (плоские массивы, предварительные маски)
[*] Нет динамических ассигнований
с ними. Реализация: < /p>
Код: Выделить всё
size_t perft(int depth, bool printCountAfterMoves) {
size_t nodes = 0;
MoveList legalMoves = moveGenerator.generateLegalMoves();
if (depth == 1) {
return static_cast(legalMoves.getMovesCount());
}
for (Move move : legalMoves) {
position.makeMove(move);
size_t count = perft(depth - 1, false);
if (printCountAfterMoves) [[unlikely]] {
std::cout pieces[position->usColor * 6 + PT_KING]);
assert(kingSq < 64);
Bitboard occ = position->occForColor[WHITE] | position->occForColor[BLACK];
Bitboard attackMask = computeAttackMask(occ);
Bitboard checkerMask = computeCheckerMask(kingSq, occ);
bool isInCheck = std::popcount(checkerMask) >= 1;
bool isInDoubleCheck = std::popcount(checkerMask) == 2;
// if in normal check and the checking piece is a slider piece, generate the block mask
Bitboard checkBlockMask =
isInCheck && !isInDoubleCheck &&
(checkerMask & ~position->pieces[position->oppColor * 6 + PT_PAWN] &
~position->pieces[position->oppColor * 6 + PT_KNIGHT])
? BETWEEN_MASK[kingSq][std::countr_zero(checkerMask)]
: 0ULL;
Bitboard checkEvasionMask = checkerMask | checkBlockMask;
Bitboard pinMask = computePinMask(kingSq, occ);
Bitboard capturableSquares = ~position->occForColor[position->usColor];
if (!isInDoubleCheck) [[likely]] {
// pawns
Bitboard freeSquares = ~occ;
Bitboard pawns = position->pieces[position->usColor * 6 + PT_PAWN];
while (pawns) {
Bitboard currPawn = pawns & -pawns;
int currPawnSq = std::countr_zero(currPawn);
if (position->usColor == WHITE) {
// we are white
// pushes
Bitboard singlePush = WHITE_PAWN_SINGLE_PUSH_MASK[currPawnSq] & freeSquares;
Bitboard doublePush = ((singlePush & RANK_3) occForColor[position->oppColor];
Bitboard rightCapture = WHITE_PAWN_CAPTURE_RIGHT_MASK[currPawnSq] &
position->occForColor[position->oppColor];
Bitboard normalMoves = singlePush | doublePush | leftCapture | rightCapture;
// en-passant
Bitboard ep =
isEpLegal(kingSq, occ, currPawn)
? (WHITE_PAWN_CAPTURE_LEFT_MASK[currPawnSq] & position->epSquare) |
(WHITE_PAWN_CAPTURE_RIGHT_MASK[currPawnSq] & position->epSquare)
: 0ULL;
if (isInCheck) {
normalMoves &= checkEvasionMask;
// if en-passant does not resolve the check, disallow it
if ((ep >> 8) != checkEvasionMask) {
ep = 0ULL;
}
}
if (currPawn & pinMask) {
normalMoves &= LINE_MASK[currPawnSq][kingSq];
ep &= LINE_MASK[currPawnSq][kingSq];
}
// add en-passant move
if (ep) {
moveList.add(Move(currPawn, ep, PT_PAWN, PT_NULL, false, true));
}
// add each normal move
while (normalMoves) {
Bitboard to = normalMoves & -normalMoves;
// promotion
if (to & RANK_8) {
moveList.add(Move(currPawn, to, PT_PAWN, PT_KNIGHT, false, false));
moveList.add(Move(currPawn, to, PT_PAWN, PT_BISHOP, false, false));
moveList.add(Move(currPawn, to, PT_PAWN, PT_ROOK, false, false));
moveList.add(Move(currPawn, to, PT_PAWN, PT_QUEEN, false, false));
}
else {
moveList.add(Move(currPawn, to, PT_PAWN, PT_NULL, false, false));
}
normalMoves &= normalMoves - 1;
}
}
else {
// we are black
// pushes
Bitboard singlePush = BLACK_PAWN_SINGLE_PUSH_MASK[currPawnSq] & freeSquares;
Bitboard doublePush = ((singlePush & RANK_6) >> 8) & freeSquares;
// captures
Bitboard leftCapture = BLACK_PAWN_CAPTURE_LEFT_MASK[currPawnSq] &
position->occForColor[position->oppColor];
Bitboard rightCapture = BLACK_PAWN_CAPTURE_RIGHT_MASK[currPawnSq] &
position->occForColor[position->oppColor];
Bitboard normalMoves = singlePush | doublePush | leftCapture | rightCapture;
// en-passant
Bitboard ep =
isEpLegal(kingSq, occ, currPawn)
? (BLACK_PAWN_CAPTURE_LEFT_MASK[currPawnSq] & position->epSquare) |
(BLACK_PAWN_CAPTURE_RIGHT_MASK[currPawnSq] & position->epSquare)
: 0ULL;
if (isInCheck) {
normalMoves &= checkEvasionMask;
// if en-passant does not resolve the check, disallow it
if ((ep pieces[position->usColor * 6 + PT_KNIGHT];
while (knights) {
Bitboard currKnight = knights & -knights;
Bitboard moves = KNIGHT_MOVE_MASK[std::countr_zero(currKnight)] & capturableSquares;
// checks & pins
if (isInCheck) {
moves &= checkEvasionMask;
}
if (currKnight & pinMask) {
moves &= LINE_MASK[std::countr_zero(currKnight)][kingSq];
}
addMovesToList(moveList, currKnight, moves, PT_KNIGHT);
knights &= knights - 1;
}
// bishops
Bitboard bishops = position->pieces[position->usColor * 6 + PT_BISHOP];
while (bishops) {
Bitboard currBishop = bishops & -bishops;
Bitboard moves =
getBishopAttacks(std::countr_zero(currBishop), occ) & capturableSquares;
// checks & pins
if (isInCheck) {
moves &= checkEvasionMask;
}
if (currBishop & pinMask) {
moves &= LINE_MASK[std::countr_zero(currBishop)][kingSq];
}
addMovesToList(moveList, currBishop, moves, PT_BISHOP);
bishops &= bishops - 1;
}
// rooks
Bitboard rooks = position->pieces[position->usColor * 6 + PT_ROOK];
while (rooks) {
Bitboard currRook = rooks & -rooks;
Bitboard moves = getRookAttacks(std::countr_zero(currRook), occ) & capturableSquares;
// checks & pins
if (isInCheck) {
moves &= checkEvasionMask;
}
if (currRook & pinMask) {
moves &= LINE_MASK[std::countr_zero(currRook)][kingSq];
}
addMovesToList(moveList, currRook, moves, PT_ROOK);
rooks &= rooks - 1;
}
// queens
Bitboard queens = position->pieces[position->usColor * 6 + PT_QUEEN];
while (queens) {
Bitboard currQueen = queens & -queens;
Bitboard moves = (getRookAttacks(std::countr_zero(currQueen), occ) |
getBishopAttacks(std::countr_zero(currQueen), occ)) &
capturableSquares;
// checks & pins
if (isInCheck) {
moves &= checkEvasionMask;
}
if (currQueen & pinMask) {
moves &= LINE_MASK[std::countr_zero(currQueen)][kingSq];
}
addMovesToList(moveList, currQueen, moves, PT_QUEEN);
queens &= queens - 1;
}
}
// king
Bitboard kingMoves = KING_MOVE_MASK[kingSq] & capturableSquares & ~attackMask;
addMovesToList(moveList, position->pieces[position->usColor * 6 + PT_KING], kingMoves, PT_KING);
if (!isInCheck) {
if (position->usColor == WHITE) {
constexpr Bitboard E1 = 1ULL
Подробнее здесь: [url]https://stackoverflow.com/questions/79760571/how-can-i-further-optimize-move-generation-in-my-c-chess-engine[/url]
1757488887
Anonymous
Я строю шахматный двигатель в C ++ и в настоящее время работаю над генерацией движения. Чтобы измерить производительность, я использую Perft, но моя главная цель состоит в том, чтобы сделать сам генератор движения быстрее.[code]x & -x[/code], std :: counst_zero , std :: popcount ) [*] Эффективная компоновка и повторное использование данных (плоские массивы, предварительные маски) [*] Нет динамических ассигнований с ними. Реализация: < /p> [code]size_t perft(int depth, bool printCountAfterMoves) { size_t nodes = 0; MoveList legalMoves = moveGenerator.generateLegalMoves(); if (depth == 1) { return static_cast(legalMoves.getMovesCount()); } for (Move move : legalMoves) { position.makeMove(move); size_t count = perft(depth - 1, false); if (printCountAfterMoves) [[unlikely]] { std::cout pieces[position->usColor * 6 + PT_KING]); assert(kingSq < 64); Bitboard occ = position->occForColor[WHITE] | position->occForColor[BLACK]; Bitboard attackMask = computeAttackMask(occ); Bitboard checkerMask = computeCheckerMask(kingSq, occ); bool isInCheck = std::popcount(checkerMask) >= 1; bool isInDoubleCheck = std::popcount(checkerMask) == 2; // if in normal check and the checking piece is a slider piece, generate the block mask Bitboard checkBlockMask = isInCheck && !isInDoubleCheck && (checkerMask & ~position->pieces[position->oppColor * 6 + PT_PAWN] & ~position->pieces[position->oppColor * 6 + PT_KNIGHT]) ? BETWEEN_MASK[kingSq][std::countr_zero(checkerMask)] : 0ULL; Bitboard checkEvasionMask = checkerMask | checkBlockMask; Bitboard pinMask = computePinMask(kingSq, occ); Bitboard capturableSquares = ~position->occForColor[position->usColor]; if (!isInDoubleCheck) [[likely]] { // pawns Bitboard freeSquares = ~occ; Bitboard pawns = position->pieces[position->usColor * 6 + PT_PAWN]; while (pawns) { Bitboard currPawn = pawns & -pawns; int currPawnSq = std::countr_zero(currPawn); if (position->usColor == WHITE) { // we are white // pushes Bitboard singlePush = WHITE_PAWN_SINGLE_PUSH_MASK[currPawnSq] & freeSquares; Bitboard doublePush = ((singlePush & RANK_3) occForColor[position->oppColor]; Bitboard rightCapture = WHITE_PAWN_CAPTURE_RIGHT_MASK[currPawnSq] & position->occForColor[position->oppColor]; Bitboard normalMoves = singlePush | doublePush | leftCapture | rightCapture; // en-passant Bitboard ep = isEpLegal(kingSq, occ, currPawn) ? (WHITE_PAWN_CAPTURE_LEFT_MASK[currPawnSq] & position->epSquare) | (WHITE_PAWN_CAPTURE_RIGHT_MASK[currPawnSq] & position->epSquare) : 0ULL; if (isInCheck) { normalMoves &= checkEvasionMask; // if en-passant does not resolve the check, disallow it if ((ep >> 8) != checkEvasionMask) { ep = 0ULL; } } if (currPawn & pinMask) { normalMoves &= LINE_MASK[currPawnSq][kingSq]; ep &= LINE_MASK[currPawnSq][kingSq]; } // add en-passant move if (ep) { moveList.add(Move(currPawn, ep, PT_PAWN, PT_NULL, false, true)); } // add each normal move while (normalMoves) { Bitboard to = normalMoves & -normalMoves; // promotion if (to & RANK_8) { moveList.add(Move(currPawn, to, PT_PAWN, PT_KNIGHT, false, false)); moveList.add(Move(currPawn, to, PT_PAWN, PT_BISHOP, false, false)); moveList.add(Move(currPawn, to, PT_PAWN, PT_ROOK, false, false)); moveList.add(Move(currPawn, to, PT_PAWN, PT_QUEEN, false, false)); } else { moveList.add(Move(currPawn, to, PT_PAWN, PT_NULL, false, false)); } normalMoves &= normalMoves - 1; } } else { // we are black // pushes Bitboard singlePush = BLACK_PAWN_SINGLE_PUSH_MASK[currPawnSq] & freeSquares; Bitboard doublePush = ((singlePush & RANK_6) >> 8) & freeSquares; // captures Bitboard leftCapture = BLACK_PAWN_CAPTURE_LEFT_MASK[currPawnSq] & position->occForColor[position->oppColor]; Bitboard rightCapture = BLACK_PAWN_CAPTURE_RIGHT_MASK[currPawnSq] & position->occForColor[position->oppColor]; Bitboard normalMoves = singlePush | doublePush | leftCapture | rightCapture; // en-passant Bitboard ep = isEpLegal(kingSq, occ, currPawn) ? (BLACK_PAWN_CAPTURE_LEFT_MASK[currPawnSq] & position->epSquare) | (BLACK_PAWN_CAPTURE_RIGHT_MASK[currPawnSq] & position->epSquare) : 0ULL; if (isInCheck) { normalMoves &= checkEvasionMask; // if en-passant does not resolve the check, disallow it if ((ep pieces[position->usColor * 6 + PT_KNIGHT]; while (knights) { Bitboard currKnight = knights & -knights; Bitboard moves = KNIGHT_MOVE_MASK[std::countr_zero(currKnight)] & capturableSquares; // checks & pins if (isInCheck) { moves &= checkEvasionMask; } if (currKnight & pinMask) { moves &= LINE_MASK[std::countr_zero(currKnight)][kingSq]; } addMovesToList(moveList, currKnight, moves, PT_KNIGHT); knights &= knights - 1; } // bishops Bitboard bishops = position->pieces[position->usColor * 6 + PT_BISHOP]; while (bishops) { Bitboard currBishop = bishops & -bishops; Bitboard moves = getBishopAttacks(std::countr_zero(currBishop), occ) & capturableSquares; // checks & pins if (isInCheck) { moves &= checkEvasionMask; } if (currBishop & pinMask) { moves &= LINE_MASK[std::countr_zero(currBishop)][kingSq]; } addMovesToList(moveList, currBishop, moves, PT_BISHOP); bishops &= bishops - 1; } // rooks Bitboard rooks = position->pieces[position->usColor * 6 + PT_ROOK]; while (rooks) { Bitboard currRook = rooks & -rooks; Bitboard moves = getRookAttacks(std::countr_zero(currRook), occ) & capturableSquares; // checks & pins if (isInCheck) { moves &= checkEvasionMask; } if (currRook & pinMask) { moves &= LINE_MASK[std::countr_zero(currRook)][kingSq]; } addMovesToList(moveList, currRook, moves, PT_ROOK); rooks &= rooks - 1; } // queens Bitboard queens = position->pieces[position->usColor * 6 + PT_QUEEN]; while (queens) { Bitboard currQueen = queens & -queens; Bitboard moves = (getRookAttacks(std::countr_zero(currQueen), occ) | getBishopAttacks(std::countr_zero(currQueen), occ)) & capturableSquares; // checks & pins if (isInCheck) { moves &= checkEvasionMask; } if (currQueen & pinMask) { moves &= LINE_MASK[std::countr_zero(currQueen)][kingSq]; } addMovesToList(moveList, currQueen, moves, PT_QUEEN); queens &= queens - 1; } } // king Bitboard kingMoves = KING_MOVE_MASK[kingSq] & capturableSquares & ~attackMask; addMovesToList(moveList, position->pieces[position->usColor * 6 + PT_KING], kingMoves, PT_KING); if (!isInCheck) { if (position->usColor == WHITE) { constexpr Bitboard E1 = 1ULL Подробнее здесь: [url]https://stackoverflow.com/questions/79760571/how-can-i-further-optimize-move-generation-in-my-c-chess-engine[/url]