aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/moves.cpp95
-rw-r--r--tests/pawn_moves_test.cpp54
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
+}