diff options
| author | Adam <adammegarules1@gmail.com> | 2026-08-16 18:05:27 +0200 |
|---|---|---|
| committer | Adam <adammegarules1@gmail.com> | 2026-08-16 18:05:27 +0200 |
| commit | 2f401ec6422a5d44fa1eb64b5b7d1d05c8075b19 (patch) | |
| tree | 6204da14914b7bcfade0061b7e4bdd68eeff3535 | |
| parent | 55ccaf0c531e1bea330f65c8d2f1c739819c2459 (diff) | |
refactor(board): refactoring pawn move generation code for better perfomance and quality
| -rw-r--r-- | src/moves.cpp | 129 | ||||
| -rw-r--r-- | src/moves.hpp | 4 |
2 files changed, 70 insertions, 63 deletions
diff --git a/src/moves.cpp b/src/moves.cpp index 6299e55..1a23b26 100644 --- a/src/moves.cpp +++ b/src/moves.cpp @@ -34,7 +34,35 @@ constexpr std::array<std::uint64_t, 64> computeKnightAttacks() { return attacks; } +constexpr std::array<std::array<std::uint64_t, 64>, 2> computePawnAttacks() { + std::array<std::array<std::uint64_t, 64>, 2> attacks{}; + + for (bool color : {false, true}) { + int step = 8 * (color ? 1 : -1); + for (int i = 0; i < 64; i++) { + uint64_t bb = 0; + for (int fileOffset : {-1, 1}) { + int next = i + fileOffset; + next += step; + if (next >= 64 || next < 0) { + continue; + } + const int fileDelta = (next % 8) - (i % 8); + if (fileDelta != 1 && fileDelta != 2 && fileDelta != -1 && + fileDelta != -2) { + continue; + }; + bb |= 1ULL << next; + } + attacks[static_cast<size_t>(color)][static_cast<size_t>(i)] = bb; + } + } + return attacks; +} + constexpr std::array<std::uint64_t, 64> KNIGHT_ATTACKS = computeKnightAttacks(); +constexpr std::array<std::array<std::uint64_t, 64>, 2> PAWN_ATTACKS = + computePawnAttacks(); static void GenerateKnightMoves(Game *b, std::vector<uint16_t> &moves, bool GenerateQuietMoves) { @@ -64,16 +92,17 @@ static void GenerateKnightMoves(Game *b, std::vector<uint16_t> &moves, } }; -void GeneratePawnMoves(Game *b, uint8_t from, std::vector<uint16_t> &moves, - bool quietMoves) { - Piece pawn = b->pieces[from]; +void GeneratePawnMoves(const Game &g, uint8_t from, + std::vector<uint16_t> &moves, bool quietMoves) { + Piece pawn = g.pieces[from]; if (pawn.type != PAWN) { assert(false && "Calling generate pawn moves on non pawn"); return; } - Position position = IndexToPosition(from); - int step = (pawn.color ? 1 : -1) * 8; + const Position position = IndexToPosition(from); + const int step = (pawn.color ? 1 : -1) * 8; int next = from + step; + constexpr std::array<int, 2> startingRank = {6, 1}; // wrap check if (position.rank + (pawn.color ? 1 : -1) < 0 || @@ -81,73 +110,51 @@ void GeneratePawnMoves(Game *b, uint8_t from, std::vector<uint16_t> &moves, return; } + const bool oneStepOccupied = (g.PieceBitboard & (1ULL << (from + step))) != 0; + // if piece it want to move to is none and it as legal move - if (b->pieces[next].type == NONEPIECE && quietMoves) { - if (position.rank + (pawn.color ? 1 : -1) == 0 || - position.rank + (pawn.color ? 1 : -1) == 7) { - moves.push_back( - CreateMove(static_cast<uint8_t>(PositionToIndex(position)), - static_cast<uint8_t>(next), QUEEN)); + if (!oneStepOccupied && quietMoves) { + if (IndexToPosition(next).rank == (pawn.color ? 7 : 0)) { + moves.push_back(CreateMove(from, static_cast<uint8_t>(next), QUEEN)); + moves.push_back(CreateMove(from, static_cast<uint8_t>(next), ROOK)); + moves.push_back(CreateMove(from, static_cast<uint8_t>(next), BISHOP)); + moves.push_back(CreateMove(from, static_cast<uint8_t>(next), KNIGHT)); + } else { + moves.push_back(CreateMove(from, static_cast<uint8_t>(next))); + } - moves.push_back( - CreateMove(static_cast<uint8_t>(PositionToIndex(position)), - static_cast<uint8_t>(next), ROOK)); + const bool twoStepOccupied = + (g.PieceBitboard & (1ULL << (from + (step * 2)))) != 0; + if (position.rank == startingRank[static_cast<size_t>(pawn.color)] && + !twoStepOccupied) { moves.push_back( CreateMove(static_cast<uint8_t>(PositionToIndex(position)), - static_cast<uint8_t>(next), BISHOP)); - moves.push_back( - CreateMove(static_cast<uint8_t>(PositionToIndex(position)), - static_cast<uint8_t>(next), KNIGHT)); - } else { - moves.push_back( - CreateMove(static_cast<uint8_t>(PositionToIndex(position)), - static_cast<uint8_t>(next))); - } - - int startingRank = pawn.color ? 1 : 6; - uint8_t twoSteps = static_cast<uint8_t>(from + (step * 2)); - if (position.rank == startingRank && - b->pieces[twoSteps].type == NONEPIECE) { - moves.push_back(CreateMove( - static_cast<uint8_t>(PositionToIndex(position)), twoSteps)); + static_cast<uint8_t>(from + (step * 2)))); } }; - for (int fileOffset : {-1, 1}) { - uint8_t targetFile = static_cast<uint8_t>(position.file + fileOffset); - uint8_t targetRank = - static_cast<uint8_t>(position.rank + (pawn.color ? 1 : -1)); + uint64_t enpassant = 0; + if (g.canEnpassant) { + enpassant |= (1ULL << PositionToIndex(g.enPassant)); + } - if (targetFile >= 8) { - continue; - } - if (targetRank >= 8) { - continue; - } + uint64_t pawn_attacks = PAWN_ATTACKS[static_cast<size_t>(pawn.color)][from]; - uint8_t target = static_cast<uint8_t>((targetRank * 8)) + targetFile; + pawn_attacks &= + (pawn.color ? g.BlackPieceBitboard : g.WhitePieceBitboard) | enpassant; - if (IndexToPosition(target) == b->enPassant && b->canEnpassant) { - moves.push_back( - CreateMove(static_cast<uint8_t>(PositionToIndex(position)), target)); - } + while (pawn_attacks != 0) { + auto i = static_cast<uint8_t>(__builtin_ctzll(pawn_attacks)); + pawn_attacks &= pawn_attacks - 1; - if (b->pieces[target].type != NONEPIECE && - b->pieces[target].color != pawn.color) { - if (targetRank == 0 || targetRank == 7) { - moves.push_back(CreateMove( - static_cast<uint8_t>(PositionToIndex(position)), target, QUEEN)); - moves.push_back(CreateMove( - static_cast<uint8_t>(PositionToIndex(position)), target, ROOK)); - moves.push_back(CreateMove( - static_cast<uint8_t>(PositionToIndex(position)), target, BISHOP)); - moves.push_back(CreateMove( - static_cast<uint8_t>(PositionToIndex(position)), target, KNIGHT)); - } else { - moves.push_back(CreateMove( - static_cast<uint8_t>(PositionToIndex(position)), target)); - } + if (IndexToPosition(i).rank == (pawn.color ? 7 : 0)) { + moves.push_back(CreateMove(from, i, QUEEN)); + moves.push_back(CreateMove(from, i, KNIGHT)); + moves.push_back(CreateMove(from, i, ROOK)); + moves.push_back(CreateMove(from, i, BISHOP)); + } else { + moves.push_back(CreateMove(from, i)); } } }; @@ -205,7 +212,7 @@ std::vector<uint16_t> GetPseudoLegalMoves(Game *g, bool GenerateQuietMoves) { } if (piece.type == PAWN) { - GeneratePawnMoves(g, i, moves, GenerateQuietMoves); + GeneratePawnMoves(*g, i, moves, GenerateQuietMoves); } if (piece.type == BISHOP) { GenerateSlidingMoves(g, i, bishop_Moves, moves, GenerateQuietMoves); diff --git a/src/moves.hpp b/src/moves.hpp index 54ab730..c7ce5e3 100644 --- a/src/moves.hpp +++ b/src/moves.hpp @@ -14,8 +14,8 @@ void GenerateSlidingMoves(Game *g, int from, bool GenerateQuietMoves); void GenerateKingMoves(Game *g, int from, std::vector<uint16_t> &moves, bool GenerateQuietMoves); -void GeneratePawnMoves(Game *b, uint8_t from, std::vector<uint16_t> &moves, - bool GenerateQuietMoves); +void GeneratePawnMoves(const Game &g, uint8_t from, + std::vector<uint16_t> &moves, bool GenerateQuietMoves); bool IsSquareAttacked(Game *g, Position square, bool byColor); void GenerateCastlingMoves(int from, Game *g, std::vector<uint16_t> &moves); GameState GetNewGameState(Game *g); |
