aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam <adammegarules1@gmail.com>2026-08-17 15:22:37 +0200
committerAdam <adammegarules1@gmail.com>2026-08-17 15:22:37 +0200
commitad04f16e478357633c08174e844c8756f7892a32 (patch)
tree6e1ca98dfa67584e86346bfe36c5d98ff6d59b3c
parent26c0c08b1c4fb302db55355bd49181c8740b7ee6 (diff)
refactor(board): refactoring move generation code into better and nice way + adding debug command moves
-rw-r--r--src/board/board.cpp4
-rw-r--r--src/board/board.hpp2
-rw-r--r--src/bot.cpp18
-rw-r--r--src/evaluate.cpp4
-rw-r--r--src/misc.cpp2
-rw-r--r--src/moves.cpp352
-rw-r--r--src/moves.hpp23
-rw-r--r--src/uci.cpp21
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);
+ }
}
}