aboutsummaryrefslogtreecommitdiff
path: root/src/moves.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/moves.cpp')
-rw-r--r--src/moves.cpp198
1 files changed, 90 insertions, 108 deletions
diff --git a/src/moves.cpp b/src/moves.cpp
index 4cd7076..2f60e13 100644
--- a/src/moves.cpp
+++ b/src/moves.cpp
@@ -74,20 +74,20 @@ void GeneratePawnMoves(Game *b, int from, std::vector<Move> &moves,
return;
}
Position position = IndexToPosition(from);
- int step = (pawn.color ? -1 : 1) * 8;
+ 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) {
+ 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 (quietMoves) {
if (b->pieces[next].type == NONEPIECE) {
- if (position.rank + (pawn.color ? -1 : 1) == 0 ||
- position.rank + (pawn.color ? -1 : 1) == 7) {
+ if (position.rank + (pawn.color ? 1 : -1) == 0 ||
+ position.rank + (pawn.color ? 1 : -1) == 7) {
moves.push_back({position, IndexToPosition(next), QUEEN});
moves.push_back({position, IndexToPosition(next), ROOK});
moves.push_back({position, IndexToPosition(next), BISHOP});
@@ -96,7 +96,7 @@ void GeneratePawnMoves(Game *b, int from, std::vector<Move> &moves,
moves.push_back({position, IndexToPosition(next)});
}
- int startingRank = pawn.color ? 6 : 1;
+ int startingRank = pawn.color ? 1 : 6;
int twoSteps = from + step * 2;
if (position.rank == startingRank &&
b->pieces[twoSteps].type == NONEPIECE) {
@@ -107,7 +107,7 @@ void GeneratePawnMoves(Game *b, int from, std::vector<Move> &moves,
for (int fileOffset : {-1, 1}) {
int targetFile = position.file + fileOffset;
- int targetRank = position.rank + (pawn.color ? -1 : 1);
+ int targetRank = position.rank + (pawn.color ? 1 : -1);
if (targetFile < 0 || targetFile >= 8)
continue;
@@ -203,182 +203,158 @@ std::vector<Move> GetPseudoLegalMoves(Game *b, bool GenerateQuietMoves) {
}
if (piece.type == KING) {
GenerateKingMoves(b, i, moves, GenerateQuietMoves);
- GenerateCastlingMoves(i, b, moves);
+ if (GenerateQuietMoves) {
+ GenerateCastlingMoves(i, b, moves);
+ }
};
};
return moves;
}
-std::vector<Move> GetLegalMoves(Game *g, bool quietMove) {
- std::vector<Move> moves = GetPseudoLegalMoves(g, quietMove);
- std::vector<Move> legalMoves;
- legalMoves.reserve(moves.size());
-
- for (const Move &move : moves) {
- UndoMove 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;
- }
-
- UnMakeMove(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;
- }
- if (g->halfMoveClock >= 50) {
- g->state = DRAW;
- }
-
- auto legalMoves = GetLegalMoves(g);
-
- if (legalMoves.empty()) {
- Position kingPosition = FindKing(g, g->turn);
-
- bool check = IsSquareAttacked(g, kingPosition, !g->turn);
-
- if (check) {
- g->state = g->turn ? BLACK_WON : WHITE_WON;
- } else {
- g->state = DRAW;
- }
- }
- return g->state;
-}
-bool IsSquareAttacked(Game *g, Position square, bool white) {
+bool IsSquareAttacked(Game *g, Position square, bool byColor) {
int target = PositionToIndex(square);
- // Pawn attacks
- int pawnDir = white ? -1 : 1;
-
- int pawnRank = square.rank - pawnDir;
+ // Pawn attacks: a pawn of byColor attacks diagonally "forward" from its
+ // own perspective. White pawns (rank increases toward rank 7) attack from
+ // one rank below the target; Black pawns attack from one rank above.
+ int pawnRank = square.rank + (byColor ? -1 : 1);
if (pawnRank >= 0 && pawnRank < 8) {
for (int fileOffset : {-1, 1}) {
int file = square.file + fileOffset;
-
if (file < 0 || file >= 8)
continue;
Piece p = g->pieces[pawnRank * 8 + file];
-
- if (p.type == PAWN && p.color == white)
+ if (p.type == PAWN && p.color == byColor)
return true;
}
}
// Knight attacks
constexpr std::array<int, 8> knightOffsets{-17, -15, -10, -6, 6, 10, 15, 17};
-
for (int offset : knightOffsets) {
int from = target + offset;
-
if (from < 0 || from >= 64)
continue;
- int fileDiff = abs((from % 8) - (target % 8));
-
+ int fileDiff = std::abs((from % 8) - (target % 8));
if (fileDiff != 1 && fileDiff != 2)
continue;
Piece p = g->pieces[from];
-
- if (p.type == KNIGHT && p.color == white)
+ if (p.type == KNIGHT && p.color == byColor)
return true;
}
// King attacks
constexpr std::array<int, 8> kingOffsets{-9, -8, -7, -1, 1, 7, 8, 9};
-
for (int offset : kingOffsets) {
int from = target + offset;
-
if (from < 0 || from >= 64)
continue;
-
- if (abs((from % 8) - (target % 8)) > 1)
+ if (std::abs((from % 8) - (target % 8)) > 1)
continue;
Piece p = g->pieces[from];
-
- if (p.type == KING && p.color == white)
+ if (p.type == KING && p.color == byColor)
return true;
}
- // Sliding pieces
+ // Rooks + queens (orthogonal rays)
constexpr std::array<int, 4> rookDirs{-8, 8, -1, 1};
-
- constexpr std::array<int, 4> bishopDirs{-9, 9, -7, 7};
-
- // Rooks + queens
for (int dir : rookDirs) {
int pos = target;
-
while (true) {
int next = pos + dir;
-
if (next < 0 || next >= 64)
break;
-
- // horizontal wrap
if ((dir == 1 || dir == -1) && next / 8 != pos / 8)
- break;
+ break; // horizontal wrap
Piece p = g->pieces[next];
-
if (p.type != NONEPIECE) {
- if (p.color == white && (p.type == ROOK || p.type == QUEEN))
+ if (p.color == byColor && (p.type == ROOK || p.type == QUEEN))
return true;
-
break;
}
-
pos = next;
}
}
- // Bishops + queens
+ // Bishops + queens (diagonal rays)
+ constexpr std::array<int, 4> bishopDirs{-9, 9, -7, 7};
for (int dir : bishopDirs) {
int pos = target;
-
while (true) {
int next = pos + dir;
-
if (next < 0 || next >= 64)
break;
-
- if (abs((next % 8) - (pos % 8)) != 1)
- break;
+ if (std::abs((next % 8) - (pos % 8)) != 1)
+ break; // diagonal wrap
Piece p = g->pieces[next];
-
if (p.type != NONEPIECE) {
- if (p.color == white && (p.type == BISHOP || p.type == QUEEN))
+ if (p.color == byColor && (p.type == BISHOP || p.type == QUEEN))
return true;
-
break;
}
-
pos = next;
}
}
return false;
}
+std::vector<Move> GetLegalMoves(Game *g, bool quietMove) {
+ std::vector<Move> moves = GetPseudoLegalMoves(g, quietMove);
+ std::vector<Move> legalMoves;
+ legalMoves.reserve(moves.size());
+
+ for (const Move &move : moves) {
+ UndoMove 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;
+ }
+
+ UnMakeMove(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;
+ }
+ if (g->halfMoveClock >= 50) {
+ g->state = DRAW;
+ }
+
+ auto legalMoves = GetLegalMoves(g);
+
+ if (legalMoves.empty()) {
+ Position kingPosition = FindKing(g, g->turn);
+
+ bool check = IsSquareAttacked(g, kingPosition, !g->turn);
+
+ if (check) {
+ g->state = g->turn ? BLACK_WON : WHITE_WON;
+ } else {
+ g->state = DRAW;
+ }
+ }
+ return g->state;
+}
Position IndexToPosition(int i) {
uint8_t rank = static_cast<uint8_t>(i / 8); // 0-7
@@ -431,10 +407,10 @@ void GenerateCastlingMoves(int from, Game *g, std::vector<Move> &moves) {
std::cout << "Internal error\n";
exit(1);
}
- if (from != 4 && !g->turn) {
+ if (from != 60 && !g->turn) {
return;
}
- if (from != 60 && g->turn) {
+ if (from != 4 && g->turn) {
return;
}
bool oneToRight = g->PieceBitboard & (1ULL << (from + 1));
@@ -449,24 +425,30 @@ void GenerateCastlingMoves(int from, Game *g, std::vector<Move> &moves) {
if (check) {
return;
}
+ auto pathIsSafe = [&](int step) {
+ return !IsSquareAttacked(g, IndexToPosition(from + step), !g->turn) &&
+ !IsSquareAttacked(g, IndexToPosition(from + 2 * step), !g->turn);
+ };
if (g->turn) {
// white
- if (!oneToRight && !twoToRight && g->whiteCastleKing) {
+ if (!oneToRight && !twoToRight && g->whiteCastleKing && pathIsSafe(1)) {
moves.push_back(
{.From = IndexToPosition(from), .To = IndexToPosition(from + 2)});
}
- if (!oneToLeft && !twoToLeft && !threeToLeft && g->whiteCastleQueen) {
+ if (!oneToLeft && !twoToLeft && !threeToLeft && g->whiteCastleQueen &&
+ pathIsSafe(-1)) {
moves.push_back(
{.From = IndexToPosition(from), .To = IndexToPosition(from - 2)});
}
}
if (!g->turn) {
// black
- if (!oneToRight && !twoToRight && g->blackCastleKing) {
+ if (!oneToRight && !twoToRight && g->blackCastleKing && pathIsSafe(1)) {
moves.push_back(
{.From = IndexToPosition(from), .To = IndexToPosition(from + 2)});
}
- if (!oneToLeft && !twoToLeft && !threeToLeft && g->blackCastleQueen) {
+ if (!oneToLeft && !twoToLeft && !threeToLeft && g->blackCastleQueen &&
+ pathIsSafe(-1)) {
moves.push_back(
{.From = IndexToPosition(from), .To = IndexToPosition(from - 2)});
}