From 27e879c62ecc019591201b1b1068b0c41870cfab Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 3 Aug 2026 21:56:36 +0200 Subject: a big hell of a commit --- src/moves.cpp | 198 ++++++++++++++++++++++++++-------------------------------- 1 file changed, 90 insertions(+), 108 deletions(-) (limited to 'src/moves.cpp') 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 &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 &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 &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 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 GetLegalMoves(Game *g, bool quietMove) { - std::vector moves = GetPseudoLegalMoves(g, quietMove); - std::vector 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 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 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 rookDirs{-8, 8, -1, 1}; - - constexpr std::array 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 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 GetLegalMoves(Game *g, bool quietMove) { + std::vector moves = GetPseudoLegalMoves(g, quietMove); + std::vector 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(i / 8); // 0-7 @@ -431,10 +407,10 @@ void GenerateCastlingMoves(int from, Game *g, std::vector &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 &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)}); } -- cgit v1.2.3