aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdam <adammegarules1@gmail.com>2026-08-03 21:56:36 +0200
committerAdam <adammegarules1@gmail.com>2026-08-03 21:56:36 +0200
commit27e879c62ecc019591201b1b1068b0c41870cfab (patch)
treec012f4f9991af93ed6b0c1b73dabf72815696707 /src
parent9acc4d8b4fb616e8a0b0d2fed85a752c3a86ccc6 (diff)
a big hell of a commit
Diffstat (limited to 'src')
-rw-r--r--src/board/board.cpp69
-rw-r--r--src/board/fen.cpp15
-rw-r--r--src/evaluate.cpp2
-rw-r--r--src/moves.cpp198
-rw-r--r--src/moves.hpp2
-rw-r--r--src/uci.cpp8
6 files changed, 165 insertions, 129 deletions
diff --git a/src/board/board.cpp b/src/board/board.cpp
index 16efbd3..28183a2 100644
--- a/src/board/board.cpp
+++ b/src/board/board.cpp
@@ -61,6 +61,19 @@ UndoMove MakeMove(Move move, Game *g) {
undo.wasEnPassantCapture = true;
undo.enPassantCapturedSquare = capturedPawn;
undo.enPassantCapturedPiece = g->pieces[PositionToIndex(capturedPawn)];
+
+ bool captuaredColor = !piece.color;
+ uint64_t square = 1ULL << PositionToIndex(capturedPawn);
+
+ g->PieceBitboards[captuaredColor][PAWN] ^= square;
+
+ if (captuaredColor)
+ g->WhitePieceBitboard ^= square;
+ else
+ g->BlackPieceBitboard ^= square;
+
+ g->PieceBitboard = g->WhitePieceBitboard | g->BlackPieceBitboard;
+
g->pieces[PositionToIndex(capturedPawn)] = {false, NONEPIECE};
}
@@ -69,11 +82,11 @@ UndoMove MakeMove(Move move, Game *g) {
// Adding enpassant
if (piece.type == PAWN) {
Position to = move.To;
- to.rank -= static_cast<uint8_t>(piece.color ? -2 : 2);
+ to.rank -= static_cast<uint8_t>(piece.color ? 2 : -2);
if (to == move.From) {
g->canEnpassant = true;
Position target = move.From;
- target.rank += static_cast<uint8_t>(piece.color ? -1 : 1);
+ target.rank += static_cast<uint8_t>(piece.color ? 1 : -1);
g->enPassant = target;
};
}
@@ -98,6 +111,19 @@ UndoMove MakeMove(Move move, Game *g) {
Position rookTo = move.From;
rookTo.file = 5;
+ uint64_t from = 1ULL << PositionToIndex(rookFrom);
+ uint64_t to = 1ULL << PositionToIndex(rookTo);
+
+ g->PieceBitboards[piece.color][ROOK] ^= from;
+ g->PieceBitboards[piece.color][ROOK] ^= to;
+
+ if (piece.color)
+ g->WhitePieceBitboard ^= from | to;
+ else
+ g->BlackPieceBitboard ^= from | to;
+
+ g->PieceBitboard = g->WhitePieceBitboard | g->BlackPieceBitboard;
+
g->pieces[PositionToIndex(rookTo)] = g->pieces[PositionToIndex(rookFrom)];
g->pieces[PositionToIndex(rookFrom)] = {false, NONEPIECE};
} else {
@@ -108,6 +134,19 @@ UndoMove MakeMove(Move move, Game *g) {
Position rookTo = move.From;
rookTo.file = 3;
+ uint64_t from = 1ULL << PositionToIndex(rookFrom);
+ uint64_t to = 1ULL << PositionToIndex(rookTo);
+
+ g->PieceBitboards[piece.color][ROOK] ^= from;
+ g->PieceBitboards[piece.color][ROOK] ^= to;
+
+ if (piece.color)
+ g->WhitePieceBitboard ^= from | to;
+ else
+ g->BlackPieceBitboard ^= from | to;
+
+ g->PieceBitboard = g->WhitePieceBitboard | g->BlackPieceBitboard;
+
g->pieces[PositionToIndex(rookTo)] = g->pieces[PositionToIndex(rookFrom)];
g->pieces[PositionToIndex(rookFrom)] = {false, NONEPIECE};
}
@@ -162,6 +201,31 @@ UndoMove MakeMove(Move move, Game *g) {
}
// playing the moves
+ uint64_t from = 1ULL << PositionToIndex(move.From);
+ uint64_t to = 1ULL << PositionToIndex(move.To);
+
+ // remove moving piece from source
+ g->PieceBitboards[piece.color][undo.movedPiece.type] ^= from;
+
+ // remove captured piece
+ if (piece2.type != NONEPIECE) {
+ g->PieceBitboards[piece2.color][piece2.type] ^= to;
+
+ if (piece2.color)
+ g->WhitePieceBitboard ^= to;
+ else
+ g->BlackPieceBitboard ^= to;
+ }
+
+ // add moving piece to destination
+ g->PieceBitboards[piece.color][piece.type] ^= to;
+
+ if (piece.color)
+ g->WhitePieceBitboard ^= from | to;
+ else
+ g->BlackPieceBitboard ^= from | to;
+
+ g->PieceBitboard = g->WhitePieceBitboard | g->BlackPieceBitboard;
g->pieces[PositionToIndex(move.To)] = piece;
g->pieces[PositionToIndex(move.From)] = {false, NONEPIECE};
@@ -182,7 +246,6 @@ UndoMove MakeMove(Move move, Game *g) {
if (g->halfMoveClock >= 50) {
g->state = DRAW;
}
- UpdateHelpers(g);
return undo;
};
void UnMakeMove(UndoMove undo, Game *g) {
diff --git a/src/board/fen.cpp b/src/board/fen.cpp
index fc52bfe..c4c5e7a 100644
--- a/src/board/fen.cpp
+++ b/src/board/fen.cpp
@@ -2,7 +2,6 @@
#include "board.hpp"
#include <cassert>
#include <cctype>
-#include <cstdint>
#include <cstdlib>
#include <print>
#include <string>
@@ -14,7 +13,7 @@ bool BLACK = false;
void setBoardFen(const std::string fen, Game *g) {
// example fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
int file = 0;
- int rank = 0;
+ int rank = 7;
Position enpassant = {};
enum parserState {
@@ -52,14 +51,6 @@ void setBoardFen(const std::string fen, Game *g) {
}
}
if (parser_state == ENPASSANT) {
- if (toupper(c) >= 'A' && toupper(c) <= 'H') {
- enpassant.file = static_cast<uint8_t>(toupper(c) - 'A');
- g->canEnpassant = true;
- }
- if (c >= '1' && c <= '8') {
- enpassant.rank = static_cast<uint8_t>(c - '0');
- g->canEnpassant = true;
- }
continue;
}
if (parser_state == CASTLE) {
@@ -111,8 +102,8 @@ void setBoardFen(const std::string fen, Game *g) {
}
if (c == '/') {
file = 0;
- rank++;
- if (rank >= 8) {
+ rank--;
+ if (rank < 0) {
std::println("Fatal: rank was to big");
assert(false && "Malformed rank");
exit(1);
diff --git a/src/evaluate.cpp b/src/evaluate.cpp
index 25c2117..f08080d 100644
--- a/src/evaluate.cpp
+++ b/src/evaluate.cpp
@@ -88,7 +88,7 @@ int EvaluateBoard(Game *g) {
* this function just takes square and if color is black rotate it
*/
static int RotateBoardForBlack(const int square, const bool color) {
- return color ? square : (56 ^ square);
+ return !color ? square : (56 ^ square);
}
static int ForceKingToEdgeBonus(const Position enemyKing,
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)});
}
diff --git a/src/moves.hpp b/src/moves.hpp
index 3764be4..57d1467 100644
--- a/src/moves.hpp
+++ b/src/moves.hpp
@@ -14,8 +14,8 @@ void GenerateKingMoves(Game *g, int from, std::vector<Move> &moves,
bool GenerateQuietMoves);
void GeneratePawnMoves(Game *b, int from, std::vector<Move> &moves,
bool GenerateQuietMoves);
+bool IsSquareAttacked(Game *g, Position square, bool byColor);
void GenerateCastlingMoves(int from, Game *g, std::vector<Move> &moves);
-bool IsSquareAttacked(Game *g, Position square, bool byWhite);
GameState GetNewGameState(Game *g);
#endif /* SRC_MOVES_H_ */
diff --git a/src/uci.cpp b/src/uci.cpp
index 31c4e43..ffab5bc 100644
--- a/src/uci.cpp
+++ b/src/uci.cpp
@@ -42,10 +42,10 @@ Move UciToMove(const string uci) {
Position to;
from.file = static_cast<uint8_t>(uci[0] - 'a');
- from.rank = static_cast<uint8_t>('8' - uci[1]);
+ from.rank = static_cast<uint8_t>(uci[1] - '1');
to.file = static_cast<uint8_t>(uci[2] - 'a');
- to.rank = static_cast<uint8_t>('8' - uci[3]);
+ to.rank = static_cast<uint8_t>(uci[3] - '1');
return {from, to};
}
@@ -181,8 +181,8 @@ void Uci() {
Move best = GetBestMove(&game, depth);
cout << "bestmove ";
- cout << static_cast<char>(best.From.file + 'a') << 8 - best.From.rank
- << static_cast<char>(best.To.file + 'a') << 8 - best.To.rank;
+ cout << static_cast<char>(best.From.file + 'a') << 1 + best.From.rank
+ << static_cast<char>(best.To.file + 'a') << 1 + best.To.rank;
if (best.promotion != NONEPIECE) {
switch (best.promotion) {