diff options
| -rw-r--r-- | src/moves.cpp | 95 | ||||
| -rw-r--r-- | tests/pawn_moves_test.cpp | 54 |
2 files changed, 136 insertions, 13 deletions
diff --git a/src/moves.cpp b/src/moves.cpp index f02dfbe..0a997db 100644 --- a/src/moves.cpp +++ b/src/moves.cpp @@ -5,7 +5,58 @@ #include "board.hpp" #include "moves.hpp" -std::vector<Move> GetLegalMoves(board *b) { +static void GeneratePawnMoves(board *b, int from, std::vector<Move> &moves) +{ + Piece pawn = b->pieces[from]; + if (pawn.type != PAWN) + { + return; + } + Position position = IndexToPosition(from); + int step = (pawn.color ? -1 : 1) * 8; + int next = from + step; + + // wrap check + if (position.rank + (pawn.color ? -1 : 1) < 0 || position.rank + (pawn.color ? -1 : 1) >= 8) + { + return; + } + + // if piece it want to move to is none and it as legal move + if (b->pieces[next].type == NONE) + { + moves.push_back({position, IndexToPosition(next)}); // adding legal move + + // todo find why this code is here and what it does + int startingRank = pawn.color ? 6 : 1; + int twoSteps = from + step * 2; + if (position.rank == startingRank && b->pieces[twoSteps].type == NONE) + { + moves.push_back({position, IndexToPosition(twoSteps)}); + } + } + + // check + for (int fileOffset : {-1, 1}) + { + int targetFile = position.file + fileOffset; + if (targetFile < 0 || targetFile >= 8) + { + continue; + } + + int target = (position.rank + (pawn.color ? -1 : 1)) * 8 + targetFile; + if (b->pieces[target].type != NONE && + b->pieces[target].color != pawn.color) + { + moves.push_back({position, IndexToPosition(target)}); + } + } + // the end +} + +std::vector<Move> GetLegalMoves(board *b) +{ std::vector<Move> moves; moves.reserve(50); // almost all position dont have that many moves @@ -14,20 +65,29 @@ std::vector<Move> GetLegalMoves(board *b) { for (uint i = 0; i < sizeof(b->pieces) / sizeof(b->pieces[0]); i++) { Piece piece = b->pieces[i]; - if (piece.type == NONE) { + if (piece.type == NONE) + { continue; } if (piece.color != b->turn) continue; - // Add support for other pieces - if (piece.type == BISHOP) { + // add support for knight and king later + + if (piece.type == PAWN) + { + GeneratePawnMoves(b, i, moves); + } + if (piece.type == BISHOP) + { GenerateSlidingMoves(b, i, bishop_Moves, moves); } - if (piece.type == ROOK) { + if (piece.type == ROOK) + { GenerateSlidingMoves(b, i, rook_Moves, moves); } - if (piece.type == QUEEN) { + if (piece.type == QUEEN) + { GenerateSlidingMoves(b, i, rook_Moves, moves); GenerateSlidingMoves(b, i, bishop_Moves, moves); } @@ -35,11 +95,14 @@ std::vector<Move> GetLegalMoves(board *b) { return moves; } -Position IndexToPosition(int i) { + +Position IndexToPosition(int i) +{ uint8_t rank = i / 8; // 0-7 uint8_t file = i % 8; // 0-7 return {rank, file}; } + void GenerateSlidingMoves(board *b, int from, const std::array<int, 4> &directions, std::vector<Move> &moves) { @@ -47,28 +110,34 @@ void GenerateSlidingMoves(board *b, int from, int direction = directions[i]; int i2 = from; - while (true) { + while (true) + { i2 += direction; int oldFile = (i2 - direction) % 8; int newFile = i2 % 8; if (direction == 7 || direction == -7 || direction == 9 || - direction == -9) { + direction == -9) + { if (std::abs(newFile - oldFile) != 1) break; } - if (i2 >= 64 || i2 < 0) { + if (i2 >= 64 || i2 < 0) + { break; } - if (b->pieces[i2].color == b->turn && b->pieces[i2].type != NONE) { + if (b->pieces[i2].color == b->turn && b->pieces[i2].type != NONE) + { break; } if ((direction == 1 || direction == -1) && - (i2 / 8 != (i2 - direction) / 8)) { + (i2 / 8 != (i2 - direction) / 8)) + { break; } moves.push_back({IndexToPosition(from), IndexToPosition(i2)}); - if (b->pieces[i2].color != b->turn && b->pieces[i2].type != NONE) { + if (b->pieces[i2].color != b->turn && b->pieces[i2].type != NONE) + { break; } } diff --git a/tests/pawn_moves_test.cpp b/tests/pawn_moves_test.cpp new file mode 100644 index 0000000..47b8ceb --- /dev/null +++ b/tests/pawn_moves_test.cpp @@ -0,0 +1,54 @@ +#include "moves.hpp" +#include <cassert> + +bool HasMove(const std::vector<Move> &moves, int from, int to) { + Position expectedFrom = IndexToPosition(from); + Position expectedTo = IndexToPosition(to); + for (const Move &move : moves) { + if (move.From.rank == expectedFrom.rank && + move.From.file == expectedFrom.file && move.To.rank == expectedTo.rank && + move.To.file == expectedTo.file) { + return true; + } + } + return false; +} + +int CountMovesFrom(const std::vector<Move> &moves, int from) { + Position expected = IndexToPosition(from); + int count = 0; + for (const Move &move : moves) { + if (move.From.rank == expected.rank && move.From.file == expected.file) { + count++; + } + } + return count; +} + +int main() { + board white{}; + white.turn = true; + white.pieces[52] = createPiece(PAWN, true); // e2 + white.pieces[43] = createPiece(ROOK, false); // d3 + white.pieces[45] = createPiece(ROOK, true); // f3 + + std::vector<Move> whiteMoves = GetLegalMoves(&white); + assert(CountMovesFrom(whiteMoves, 52) == 3); + assert(HasMove(whiteMoves, 52, 44)); // e2-e3 + assert(HasMove(whiteMoves, 52, 36)); // e2-e4 + assert(HasMove(whiteMoves, 52, 43)); // e2xd3 + + white.pieces[44] = createPiece(KING, true); // block e3 and e4 + std::vector<Move> blockedMoves = GetLegalMoves(&white); + assert(CountMovesFrom(blockedMoves, 52) == 1); + assert(HasMove(blockedMoves, 52, 43)); // capture remains legal + + board black{}; + black.turn = false; + black.pieces[12] = createPiece(PAWN, false); // e7 + + std::vector<Move> blackMoves = GetLegalMoves(&black); + assert(CountMovesFrom(blackMoves, 12) == 2); + assert(HasMove(blackMoves, 12, 20)); // e7-e6 + assert(HasMove(blackMoves, 12, 28)); // e7-e5 +} |
