diff options
| author | Adam <adammegarules1@gmail.com> | 2026-08-17 15:22:37 +0200 |
|---|---|---|
| committer | Adam <adammegarules1@gmail.com> | 2026-08-17 15:22:37 +0200 |
| commit | ad04f16e478357633c08174e844c8756f7892a32 (patch) | |
| tree | 6e1ca98dfa67584e86346bfe36c5d98ff6d59b3c | |
| parent | 26c0c08b1c4fb302db55355bd49181c8740b7ee6 (diff) | |
refactor(board): refactoring move generation code into better and nice way + adding debug command moves
| -rw-r--r-- | src/board/board.cpp | 4 | ||||
| -rw-r--r-- | src/board/board.hpp | 2 | ||||
| -rw-r--r-- | src/bot.cpp | 18 | ||||
| -rw-r--r-- | src/evaluate.cpp | 4 | ||||
| -rw-r--r-- | src/misc.cpp | 2 | ||||
| -rw-r--r-- | src/moves.cpp | 352 | ||||
| -rw-r--r-- | src/moves.hpp | 23 | ||||
| -rw-r--r-- | src/uci.cpp | 21 |
8 files changed, 244 insertions, 182 deletions
diff --git a/src/board/board.cpp b/src/board/board.cpp index 09c7a25..9ac60a8 100644 --- a/src/board/board.cpp +++ b/src/board/board.cpp @@ -87,8 +87,8 @@ PieceType getPromotionTypeFromMove(uint16_t move) { uint8_t getFromValueFromMove(uint16_t move) { return (move >> 2) & 63; }; uint8_t getToValueFromMove(uint16_t move) { return (move >> 8) & 63; }; -Position FindKing(Game *g, bool color) { - return IndexToPosition(__builtin_ctzll(g->PieceBitboards[color][KING])); +Position FindKing(const Game &g, bool color) { + return IndexToPosition(__builtin_ctzll(g.PieceBitboards[color][KING])); } bool isRepetionDraw(uint64_t key, Game *g) { diff --git a/src/board/board.hpp b/src/board/board.hpp index e3692f6..a2c4e1f 100644 --- a/src/board/board.hpp +++ b/src/board/board.hpp @@ -108,6 +108,6 @@ int PositionToIndex(Position i); Undo MakeMove(uint16_t move, Game *g); void UndoMove(Undo undo, Game *g); -Position FindKing(Game *g, bool color); +Position FindKing(const Game &g, bool color); void UpdateHelpers(Game *g); #endif /* SRC_BOARD_H_ */ diff --git a/src/bot.cpp b/src/bot.cpp index b09a704..7b937bd 100644 --- a/src/bot.cpp +++ b/src/bot.cpp @@ -84,10 +84,10 @@ static int ScoreMove(const Game *board, const uint16_t &move, return score; } -static std::vector<uint16_t> GetSortedLegalMoves(Game *g, - bool generateQuietMoves, - const uint16_t *bestMove) { - auto moves = GetLegalMoves(g, generateQuietMoves); +static std::vector<uint16_t> +GetSortedLegalMoves(Game *g, const move_generate_options &options, + const uint16_t *bestMove) { + auto moves = GetLegalMoves(g, options); std::ranges::sort(moves, [&](const uint16_t &a, const uint16_t &c) { return ScoreMove(g, a, bestMove) > ScoreMove(g, c, bestMove); }); @@ -134,7 +134,7 @@ static int quiescenceSearch(Game *b, int qdepth, int alpha, int beta, int ply) { } alpha = std::max(alpha, standPat); - auto moves = GetSortedLegalMoves(b, false, nullptr); + auto moves = GetSortedLegalMoves(b, CAPTUARES_ONLY, nullptr); for (uint16_t move : moves) { Undo undo = MakeMove(move, b); @@ -200,10 +200,10 @@ static int search(int depth, Game *b, int alpha, int beta, int ply) { } uint16_t ttBestMove = entry != nullptr ? entry->bestMove : uint16_t{}; - std::vector<uint16_t> moves = GetSortedLegalMoves(b, true, &ttBestMove); + std::vector<uint16_t> moves = GetSortedLegalMoves(b, ALL, &ttBestMove); if (moves.empty()) { - if (IsSquareAttacked(b, FindKing(b, b->turn), !b->turn)) { + if (IsSquareAttacked(*b, FindKing(*b, b->turn), !b->turn)) { return -(MATE - ply); // mated } return 0; // stalemate @@ -256,7 +256,7 @@ struct SearchResult { */ static SearchResult SearchDepth(Game *b, int depth, const uint16_t *previousBest) { - auto moves = GetSortedLegalMoves(b, true, previousBest); + auto moves = GetSortedLegalMoves(b, ALL, previousBest); if (moves.empty()) { return { @@ -325,7 +325,7 @@ uint16_t GetBestMove(Game *b, int maxDepth, move_options options) { bool hasSetSpecialTimeLimit = false; - auto legalMoves = GetSortedLegalMoves(b, true, nullptr); + auto legalMoves = GetSortedLegalMoves(b, ALL, nullptr); if (legalMoves.empty()) { assert(false && "GetBestMove called with no legal moves"); return {}; diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 3958999..c14fb9a 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -223,8 +223,8 @@ int EvaluateBoardForWhite(Game *g) { score += CountBoardMaterial(g, isEndGame); if (isEndGame) { - Position whiteKing = FindKing(g, true); - Position blackKing = FindKing(g, false); + Position whiteKing = FindKing(*g, true); + Position blackKing = FindKing(*g, false); score += ForceKingToEdgeBonus(blackKing, whiteKing); score -= ForceKingToEdgeBonus(whiteKing, blackKing); diff --git a/src/misc.cpp b/src/misc.cpp index 6737777..e9073d4 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -19,7 +19,7 @@ uint64_t MoveGenTest(uint32_t depth, Game *g) { uint64_t positionCount = 0; - std::vector<uint16_t> moves = GetLegalMoves(g); + std::vector<uint16_t> moves = GetLegalMoves(g, ALL); // for each possible move create new branch for (uint16_t move : moves) { diff --git a/src/moves.cpp b/src/moves.cpp index 8120f18..ac6e5cb 100644 --- a/src/moves.cpp +++ b/src/moves.cpp @@ -10,6 +10,10 @@ #include "board/board.hpp" #include "moves.hpp" +static void Assert_message() { + std::cout << "Internal error: run in debug to see assert\n"; +} + constexpr std::array<std::uint64_t, 64> computeKnightAttacks() { std::array<std::uint64_t, 64> attacks{}; @@ -64,62 +68,71 @@ 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(const Game &g, std::vector<uint16_t> &moves, - bool GenerateQuietMoves) { - uint64_t knights = g.PieceBitboards[g.turn][KNIGHT]; - while (knights != 0) { - auto from = static_cast<uint8_t>(__builtin_ctzll(knights)); - knights &= knights - 1; - uint64_t knight_attacks = KNIGHT_ATTACKS[static_cast<size_t>(from)]; - while (knight_attacks != 0) { - auto next = static_cast<uint8_t>(__builtin_ctzll(knight_attacks)); - knight_attacks &= knight_attacks - 1; - - bool hasFriendlyPiece = g.turn - ? (g.WhitePieceBitboard & (1ULL << next)) > 0 - : (g.BlackPieceBitboard & (1ULL << next)) > 0; - - bool isCaptuare = (g.PieceBitboard & (1ULL << next)) > 0; - if (hasFriendlyPiece) { - continue; - } - if (!GenerateQuietMoves && !isCaptuare) { - continue; - } - moves.push_back(CreateMove(from, next)); +static void GenerateKnightMoves(const uint8_t &from, const Game &g, + std::vector<uint16_t> &moves, + const move_generate_options &options) { + uint64_t knight_attacks = KNIGHT_ATTACKS[static_cast<size_t>(from)]; + while (knight_attacks != 0) { + auto next = static_cast<uint8_t>(__builtin_ctzll(knight_attacks)); + knight_attacks &= knight_attacks - 1; + + bool hasFriendlyPiece = g.turn + ? (g.WhitePieceBitboard & (1ULL << next)) > 0 + : (g.BlackPieceBitboard & (1ULL << next)) > 0; + + bool isCaptuare = (g.PieceBitboard & (1ULL << next)) > 0; + if (hasFriendlyPiece) { + continue; + } + if (options == NON_CAPTUARES_ONLY && isCaptuare) { + continue; + } + if (options == CAPTUARES_ONLY && !isCaptuare) { + continue; } + moves.push_back(CreateMove(from, next)); } }; -void GeneratePawnMoves(const Game &g, uint8_t from, - std::vector<uint16_t> &moves, bool quietMoves) { +static void GeneratePawnMoves(const uint8_t &from, const Game &g, + std::vector<uint16_t> &moves, + const move_generate_options &options) { + constexpr std::array<int, 2> startingRank = {6, 1}; + Piece pawn = g.pieces[from]; if (pawn.type != PAWN) { assert(false && "Calling generate pawn moves on non pawn"); + Assert_message(); + exit(1); + return; + } + if (from >= 64) { + assert(false && "from should be valid square index"); + Assert_message(); + exit(1); return; } 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}; + auto next = static_cast<uint8_t>(from + step); - // wrap check - if (position.rank + (pawn.color ? 1 : -1) < 0 || - position.rank + (pawn.color ? 1 : -1) >= 8) { + // because fen allow arbitrary position we need to check that pawn is not + // gonna go out of board + if (next >= 64) { return; } - const bool oneStepOccupied = (g.PieceBitboard & (1ULL << (from + step))) != 0; + const bool oneStepOccupied = (g.PieceBitboard & (1ULL << next)) != 0; // if piece it want to move to is none and it as legal move - if (!oneStepOccupied && quietMoves) { + if (!oneStepOccupied && options != CAPTUARES_ONLY) { 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)); + moves.push_back(CreateMove(from, next, QUEEN)); + moves.push_back(CreateMove(from, next, ROOK)); + moves.push_back(CreateMove(from, next, BISHOP)); + moves.push_back(CreateMove(from, next, KNIGHT)); } else { - moves.push_back(CreateMove(from, static_cast<uint8_t>(next))); + moves.push_back(CreateMove(from, next)); } const bool twoStepOccupied = @@ -133,6 +146,10 @@ void GeneratePawnMoves(const Game &g, uint8_t from, } }; + if (options == NON_CAPTUARES_ONLY) { + return; + } + uint64_t enpassant = 0; if (g.canEnpassant) { enpassant |= (1ULL << PositionToIndex(g.enPassant)); @@ -157,31 +174,42 @@ void GeneratePawnMoves(const Game &g, uint8_t from, } } }; -void GenerateKingMoves(Game *g, int from, std::vector<uint16_t> &moves, - bool GenerateQuietMoves) { - if (g->pieces[from].type != KING) { +static void GenerateKingMoves(const Game &g, const uint8_t &from, + std::vector<uint16_t> &moves, + const move_generate_options &options) { + if (g.pieces[from].type != KING) { assert(false && "calling generate king moves on non king"); - return; + Assert_message(); + exit(1); } - if (g->pieces[from].color != g->turn) { + if (g.pieces[from].color != g.turn) { assert(false && "calling generate king moves on king of opposite color"); - return; + Assert_message(); + exit(1); + } + if (from >= 64) { + assert(false && "Expected valid chess square"); + Assert_message(); + exit(1); } - constexpr std::array<int, 8> king_moves{-1, 1, 8, -8, -9, 9, -7, 7}; - for (int offset : king_moves) { - uint8_t next = static_cast<uint8_t>(from + offset); + constexpr std::array<int, 8> king_offsets{-1, 1, 8, -8, -9, 9, -7, 7}; + for (int offset : king_offsets) { + auto next = static_cast<uint8_t>(from + offset); if (next >= 64) { continue; } if (std::abs((next % 8) - (from % 8)) > 1) { continue; }; - if (g->pieces[next].type != NONEPIECE) { - if (g->pieces[next].color == g->turn) { + if (g.pieces[next].type != NONEPIECE) { + if (g.pieces[next].color == g.turn) { continue; }; } - if (!GenerateQuietMoves && g->pieces[next].type == NONEPIECE) { + if (options == CAPTUARES_ONLY && g.pieces[next].type == NONEPIECE) { + continue; + } + if (options == NON_CAPTUARES_ONLY && g.pieces[next].type != NONEPIECE) { continue; } @@ -189,51 +217,7 @@ void GenerateKingMoves(Game *g, int from, std::vector<uint16_t> &moves, } }; -std::vector<uint16_t> GetPseudoLegalMoves(Game *g, bool GenerateQuietMoves) { - std::vector<uint16_t> moves; - moves.reserve(40); - - GenerateKnightMoves(*g, moves, GenerateQuietMoves); - - constexpr std::array<int, 4> rook_Moves{-1, 1, 8, -8}; - constexpr std::array<int, 4> bishop_Moves{-9, 9, -7, 7}; - - uint64_t piece_bitboard = g->PieceBitboard; - while (piece_bitboard != 0) { - uint8_t i = static_cast<uint8_t>(__builtin_ctzll(piece_bitboard)); - piece_bitboard &= piece_bitboard - 1; - Piece piece = g->pieces[i]; - if (piece.type == NONEPIECE) { - assert(false && "got none piece in piece bitboard"); - } - if (piece.color != g->turn) { - continue; - } - - if (piece.type == PAWN) { - GeneratePawnMoves(*g, i, moves, GenerateQuietMoves); - } - if (piece.type == BISHOP) { - GenerateSlidingMoves(g, i, bishop_Moves, moves, GenerateQuietMoves); - } - if (piece.type == ROOK) { - GenerateSlidingMoves(g, i, rook_Moves, moves, GenerateQuietMoves); - } - if (piece.type == QUEEN) { - GenerateSlidingMoves(g, i, rook_Moves, moves, GenerateQuietMoves); - GenerateSlidingMoves(g, i, bishop_Moves, moves, GenerateQuietMoves); - } - if (piece.type == KING) { - GenerateKingMoves(g, i, moves, GenerateQuietMoves); - if (GenerateQuietMoves) { - GenerateCastlingMoves(i, g, moves); - } - }; - }; - - return moves; -} -bool IsSquareAttacked(Game *g, Position square, bool byColor) { +bool IsSquareAttacked(const Game &g, Position square, bool byColor) { int target = PositionToIndex(square); // Pawn attacks: a pawn of byColor attacks diagonally "forward" from its @@ -247,7 +231,7 @@ bool IsSquareAttacked(Game *g, Position square, bool byColor) { if (file < 0 || file >= 8) continue; - Piece p = g->pieces[pawnRank * 8 + file]; + Piece p = g.pieces[pawnRank * 8 + file]; if (p.type == PAWN && p.color == byColor) { return true; } @@ -265,7 +249,7 @@ bool IsSquareAttacked(Game *g, Position square, bool byColor) { if (fileDiff != 1 && fileDiff != 2) continue; - Piece p = g->pieces[from]; + Piece p = g.pieces[from]; if (p.type == KNIGHT && p.color == byColor) return true; } @@ -279,7 +263,7 @@ bool IsSquareAttacked(Game *g, Position square, bool byColor) { if (std::abs((from % 8) - (target % 8)) > 1) continue; - Piece p = g->pieces[from]; + Piece p = g.pieces[from]; if (p.type == KING && p.color == byColor) return true; } @@ -295,7 +279,7 @@ bool IsSquareAttacked(Game *g, Position square, bool byColor) { if ((dir == 1 || dir == -1) && next / 8 != pos / 8) break; // horizontal wrap - Piece p = g->pieces[next]; + Piece p = g.pieces[next]; if (p.type != NONEPIECE) { if (p.color == byColor && (p.type == ROOK || p.type == QUEEN)) return true; @@ -316,7 +300,7 @@ bool IsSquareAttacked(Game *g, Position square, bool byColor) { if (std::abs((next % 8) - (pos % 8)) != 1) break; // diagonal wrap - Piece p = g->pieces[next]; + Piece p = g.pieces[next]; if (p.type != NONEPIECE) { if (p.color == byColor && (p.type == BISHOP || p.type == QUEEN)) return true; @@ -328,44 +312,18 @@ bool IsSquareAttacked(Game *g, Position square, bool byColor) { return false; } -std::vector<uint16_t> GetLegalMoves(Game *g, bool quietMove) { - std::vector<uint16_t> moves = GetPseudoLegalMoves(g, quietMove); - std::vector<uint16_t> legalMoves; - legalMoves.reserve(moves.size()); - - for (const uint16_t &move : moves) { - Undo undo = MakeMove(move, g); - - bool legal = true; - - Position kingPosition = FindKing(g, !g->turn); - - // opponent attacks our king? - if (IsSquareAttacked(g, kingPosition, g->turn)) { - legal = false; - } - - UndoMove(undo, g); - - if (legal) { - legalMoves.push_back(move); - } - } - - return legalMoves; -} GameState GetNewGameState(Game *g) { // make sure we dont override game ending states if (g->state == DRAW || g->state == WHITE_WON || g->state == BLACK_WON) { return g->state; } - auto legalMoves = GetLegalMoves(g); + auto legalMoves = GetLegalMoves(g, ALL); if (legalMoves.empty()) { - Position kingPosition = FindKing(g, g->turn); + Position kingPosition = FindKing(*g, g->turn); - bool check = IsSquareAttacked(g, kingPosition, !g->turn); + bool check = IsSquareAttacked(*g, kingPosition, !g->turn); if (check) { g->state = g->turn ? BLACK_WON : WHITE_WON; @@ -382,10 +340,10 @@ Position IndexToPosition(int i) { return {.rank = rank, .file = file}; } -void GenerateSlidingMoves(Game *b, int from, - const std::array<int, 4> &directions, - std::vector<uint16_t> &moves, - bool GenerateQuietMoves) { +static void GenerateSlidingMoves(const uint8_t &from, const Game &g, + const std::array<int, 4> &directions, + std::vector<uint16_t> &moves, + const move_generate_options options) { for (uint i = 0; i < directions.size(); i++) { int direction = directions[i]; @@ -409,71 +367,155 @@ void GenerateSlidingMoves(Game *b, int from, (i2 / 8 != (i2 - direction) / 8)) { break; } - if (b->pieces[i2].color == b->turn && b->pieces[i2].type != NONEPIECE) { + if (g.pieces[i2].color == g.turn && g.pieces[i2].type != NONEPIECE) { break; } - if (!GenerateQuietMoves && b->pieces[i2].type == NONEPIECE) { + if (options == CAPTUARES_ONLY && g.pieces[i2].type == NONEPIECE) { continue; } + if (options == NON_CAPTUARES_ONLY && g.pieces[i2].type != NONEPIECE) { + break; + } moves.push_back( CreateMove(static_cast<uint8_t>(from), static_cast<uint8_t>(i2))); - if (b->pieces[i2].color != b->turn && b->pieces[i2].type != NONEPIECE) { + if (g.pieces[i2].color != g.turn && g.pieces[i2].type != NONEPIECE) { break; } } }; }; -void GenerateCastlingMoves(int from, Game *g, std::vector<uint16_t> &moves) { - Piece piece = g->pieces[from]; +static void GenerateCastlingMoves(const uint8_t &from, const Game &g, + std::vector<uint16_t> &moves) { + Piece piece = g.pieces[from]; if (piece.type != KING) { assert(false && "Calling generate castling moves on non king piece"); - std::cout << "Internal error\n"; + Assert_message(); + exit(1); + } + if (from >= 64) { + assert(false && "expected a valid square index"); + Assert_message(); exit(1); } - if (from != 60 && !g->turn) { + if (from != 60 && !g.turn) { return; } - if (from != 4 && g->turn) { + if (from != 4 && g.turn) { return; } - bool oneToRight = (g->PieceBitboard & (1ULL << (from + 1))) > 0; - bool twoToRight = (g->PieceBitboard & (1ULL << (from + 2))) > 0; - bool oneToLeft = (g->PieceBitboard & (1ULL << (from - 1))) > 0; - bool twoToLeft = (g->PieceBitboard & (1ULL << (from - 2))) > 0; - bool threeToLeft = (g->PieceBitboard & (1ULL << (from - 3))) > 0; + bool oneToRight = (g.PieceBitboard & (1ULL << (from + 1))) > 0; + bool twoToRight = (g.PieceBitboard & (1ULL << (from + 2))) > 0; + bool oneToLeft = (g.PieceBitboard & (1ULL << (from - 1))) > 0; + bool twoToLeft = (g.PieceBitboard & (1ULL << (from - 2))) > 0; + bool threeToLeft = (g.PieceBitboard & (1ULL << (from - 3))) > 0; - Position kingPosition = FindKing(g, g->turn); + Position kingPosition = FindKing(g, g.turn); - bool check = IsSquareAttacked(g, kingPosition, !g->turn); + bool check = IsSquareAttacked(g, kingPosition, !g.turn); if (check) { return; } auto pathIsSafe = [&](int step) { - return !IsSquareAttacked(g, IndexToPosition(from + step), !g->turn) && - !IsSquareAttacked(g, IndexToPosition(from + (2 * step)), !g->turn); + return !IsSquareAttacked(g, IndexToPosition(from + step), !g.turn) && + !IsSquareAttacked(g, IndexToPosition(from + (2 * step)), !g.turn); }; - if (g->turn) { + if (g.turn) { // white - if (!oneToRight && !twoToRight && g->whiteCastleKing && pathIsSafe(1)) { + if (!oneToRight && !twoToRight && g.whiteCastleKing && pathIsSafe(1)) { moves.push_back(CreateMove(static_cast<uint8_t>(from), static_cast<uint8_t>(from + 2))); } - if (!oneToLeft && !twoToLeft && !threeToLeft && g->whiteCastleQueen && + if (!oneToLeft && !twoToLeft && !threeToLeft && g.whiteCastleQueen && pathIsSafe(-1)) { moves.push_back(CreateMove(static_cast<uint8_t>(from), static_cast<uint8_t>(from - 2))); } } - if (!g->turn) { + if (!g.turn) { // black - if (!oneToRight && !twoToRight && g->blackCastleKing && pathIsSafe(1)) { + if (!oneToRight && !twoToRight && g.blackCastleKing && pathIsSafe(1)) { moves.push_back(CreateMove(static_cast<uint8_t>(from), static_cast<uint8_t>(from + 2))); } - if (!oneToLeft && !twoToLeft && !threeToLeft && g->blackCastleQueen && + if (!oneToLeft && !twoToLeft && !threeToLeft && g.blackCastleQueen && pathIsSafe(-1)) { moves.push_back(CreateMove(static_cast<uint8_t>(from), static_cast<uint8_t>(from - 2))); } } } + +std::vector<uint16_t> +GetPseudoLegalMoves(const Game &g, const move_generate_options &options) { + std::vector<uint16_t> moves; + moves.reserve(40); + + constexpr std::array<int, 4> ROOK_MOVES{-1, 1, 8, -8}; + constexpr std::array<int, 4> BISHOP_MOVES{-9, 9, -7, 7}; + + uint64_t piece_bitboard = g.PieceBitboard; + while (piece_bitboard != 0) { + const auto i = static_cast<uint8_t>(__builtin_ctzll(piece_bitboard)); + piece_bitboard &= piece_bitboard - 1; + Piece piece = g.pieces[i]; + if (piece.type == NONEPIECE) { + assert(false && "got none piece in piece bitboard"); + } + if (piece.color != g.turn) { + continue; + } + + if (piece.type == PAWN) { + GeneratePawnMoves(i, g, moves, options); + } + if (piece.type == KNIGHT) { + GenerateKnightMoves(i, g, moves, options); + } + if (piece.type == BISHOP) { + GenerateSlidingMoves(i, g, BISHOP_MOVES, moves, options); + } + if (piece.type == ROOK) { + GenerateSlidingMoves(i, g, ROOK_MOVES, moves, options); + } + if (piece.type == QUEEN) { + GenerateSlidingMoves(i, g, ROOK_MOVES, moves, options); + GenerateSlidingMoves(i, g, BISHOP_MOVES, moves, options); + } + if (piece.type == KING) { + GenerateKingMoves(g, i, moves, options); + if (options != CAPTUARES_ONLY) { + GenerateCastlingMoves(i, g, moves); + } + }; + }; + + return moves; +} + +std::vector<uint16_t> GetLegalMoves(Game *g, + const move_generate_options &options) { + std::vector<uint16_t> moves = GetPseudoLegalMoves(*g, options); + std::vector<uint16_t> legalMoves; + legalMoves.reserve(moves.size()); + + // this is a terrible way to checking it + for (const uint16_t &move : moves) { + Undo undo = MakeMove(move, g); + + bool legal = true; + + Position kingPosition = FindKing(*g, !g->turn); + + if (IsSquareAttacked(*g, kingPosition, g->turn)) { + legal = false; + } + + UndoMove(undo, g); + + if (legal) { + legalMoves.push_back(move); + } + } + + return legalMoves; +} diff --git a/src/moves.hpp b/src/moves.hpp index c7ce5e3..e0ed427 100644 --- a/src/moves.hpp +++ b/src/moves.hpp @@ -5,19 +5,18 @@ #include <cstdint> #include <vector> -std::vector<uint16_t> GetLegalMoves(Game *g, bool GenerateQuietMoves = true); -std::vector<uint16_t> GetPseudoLegalMoves(Game *g, bool GenerateQuietMoves); +enum move_generate_options : std::uint8_t { + ALL, + CAPTUARES_ONLY, + NON_CAPTUARES_ONLY, +}; + +std::vector<uint16_t> GetLegalMoves(Game *g, + const move_generate_options &options); +std::vector<uint16_t> GetPseudoLegalMoves(const Game &g, + const move_generate_options &options); Position IndexToPosition(int i); -void GenerateSlidingMoves(Game *g, int from, - const std::array<int, 4> &directions, - std::vector<uint16_t> &moves, - bool GenerateQuietMoves); -void GenerateKingMoves(Game *g, int 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); +bool IsSquareAttacked(const Game &g, Position square, bool byColor); GameState GetNewGameState(Game *g); #endif /* SRC_MOVES_H_ */ diff --git a/src/uci.cpp b/src/uci.cpp index b98e6ce..6c035d5 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -286,6 +286,24 @@ static void positionCommnad(Game *game, std::string &cmd) { MakeMove(move, game); } } +static void movesCommnad(Game *g) { + auto moves = GetLegalMoves(g, ALL); + for (auto move : moves) { + Piece piece = g->pieces[getFromValueFromMove(move)]; + + Position from = IndexToPosition(getFromValueFromMove(move)); + Position to = IndexToPosition(getToValueFromMove(move)); + PieceType promotion = getPromotionTypeFromMove(move); + + std::cout << static_cast<char>(from.file + 'a') << 1 + from.rank + << static_cast<char>(to.file + 'a') << 1 + to.rank; + std::cout << "\n"; + + if ((to.rank == 0 || to.rank == 7) && piece.type == PAWN) { + printPromotionLetter(promotion); + } + } +}; void Uci() { std::unordered_map<uint64_t, TranspositionsEntry> transpositions = {}; Game game = initBoard(starting_fen, &transpositions); @@ -321,5 +339,8 @@ void Uci() { if (cmd.starts_with("position")) { positionCommnad(&game, cmd); } + if (cmd == "moves") { + movesCommnad(&game); + } } } |
