diff options
| author | Adam <adammegarules1@gmail.com> | 2026-08-15 17:01:54 +0200 |
|---|---|---|
| committer | Adam <adammegarules1@gmail.com> | 2026-08-15 17:01:54 +0200 |
| commit | 4eb36e67eca586a662298bfe8cc5392fbfa698e0 (patch) | |
| tree | 6c232d59d1566377fbaeec035f4f799618f63421 | |
| parent | c1d6113da12bfbe92ae718d93dd56e25556e52cb (diff) | |
implementing memory optimazied move using uint16_t instead of a four integers and one byte
| -rw-r--r-- | src/board/board.cpp | 120 | ||||
| -rw-r--r-- | src/board/board.hpp | 18 | ||||
| -rw-r--r-- | src/bot.cpp | 76 | ||||
| -rw-r--r-- | src/bot.hpp | 3 | ||||
| -rw-r--r-- | src/moves.cpp | 144 | ||||
| -rw-r--r-- | src/moves.hpp | 14 | ||||
| -rw-r--r-- | src/uci.cpp | 24 | ||||
| -rw-r--r-- | src/uci.hpp | 3 |
8 files changed, 213 insertions, 189 deletions
diff --git a/src/board/board.cpp b/src/board/board.cpp index 3b1383a..a533b63 100644 --- a/src/board/board.cpp +++ b/src/board/board.cpp @@ -88,14 +88,18 @@ uint8_t getToValueFromMove(uint16_t move) { return (move >> 8) & 63; }; Position FindKing(Game *g, bool color) { return IndexToPosition(__builtin_ctzll(g->PieceBitboards[color][KING])); } -UndoMove MakeMove(Move move, Game *g) { +UndoMove MakeMove(uint16_t move, Game *g) { + uint8_t fromSquare = getFromValueFromMove(move); + uint8_t toSquare = getToValueFromMove(move); + PieceType promotion = getPromotionTypeFromMove(move); + UndoMove undo = {}; - undo.from = move.From; - undo.to = move.To; + undo.from = fromSquare; + undo.to = toSquare; - undo.movedPiece = g->pieces[PositionToIndex(move.From)]; - undo.capturedPiece = g->pieces[PositionToIndex(move.To)]; + undo.movedPiece = g->pieces[fromSquare]; + undo.capturedPiece = g->pieces[toSquare]; undo.oldTurn = g->turn; undo.oldCanEnpassant = g->canEnpassant; @@ -112,8 +116,8 @@ UndoMove MakeMove(Move move, Game *g) { undo.OldBlackCastleQueen = g->blackCastleQueen; // play move - Piece piece = g->pieces[PositionToIndex(move.From)]; - Piece piece2 = g->pieces[PositionToIndex(move.To)]; + Piece piece = g->pieces[fromSquare]; + Piece piece2 = g->pieces[toSquare]; if (piece2.type != NONEPIECE) { if (piece2.color == g->turn) { @@ -130,8 +134,9 @@ UndoMove MakeMove(Move move, Game *g) { } // Playing enpasstant - if (piece.type == PAWN && g->canEnpassant && move.To == g->enPassant) { - Position capturedPawn = move.To; + if (piece.type == PAWN && g->canEnpassant && + IndexToPosition(toSquare) == g->enPassant) { + Position capturedPawn = IndexToPosition(toSquare); capturedPawn.rank += piece.color ? -1 : 1; undo.wasEnPassantCapture = true; @@ -157,33 +162,37 @@ UndoMove MakeMove(Move move, Game *g) { // Adding enpassant if (piece.type == PAWN) { - Position to = move.To; - to.rank -= piece.color ? 2 : -2; - if (to == move.From) { + int to = toSquare; + // check if a pawn has moved two squares + to -= piece.color ? 2 * 8 : -2 * 8; + if (to == fromSquare) { g->canEnpassant = true; - Position target = move.From; - target.rank += piece.color ? 1 : -1; - g->enPassant = target; + int target = fromSquare; + target += piece.color ? 8 : -8; + g->enPassant = IndexToPosition(target); }; } - // Promotions - if (piece.type == PAWN && move.To.rank == (piece.color ? 7 : 0)) { - piece.type = move.promotion == NONEPIECE ? QUEEN : move.promotion; + // promotion is always set and should only be aplied when reached final rank + // (default: knight) + if (piece.type == PAWN && + IndexToPosition(toSquare).rank == (piece.color ? 7 : 0)) { + piece.type = promotion; } // caslte - if (piece.type == KING && move.From.rank == (piece.color ? 0 : 7) && - std::abs(move.To.file - move.From.file) == 2) { + if (piece.type == KING && + IndexToPosition(fromSquare).rank == (piece.color ? 0 : 7) && + std::abs(toSquare - fromSquare) == 2) { undo.wasCastle = true; - undo.CastledSide = move.To.file > move.From.file; + undo.CastledSide = toSquare > fromSquare; if (undo.CastledSide) { - Position rookFrom = move.From; + Position rookFrom = IndexToPosition(fromSquare); rookFrom.file = 7; - Position rookTo = move.From; + Position rookTo = IndexToPosition(toSquare); rookTo.file = 5; uint64_t from = 1ULL << PositionToIndex(rookFrom); @@ -203,10 +212,10 @@ UndoMove MakeMove(Move move, Game *g) { g->pieces[PositionToIndex(rookFrom)] = {false, NONEPIECE}; } else { // Queenside: a -> d - Position rookFrom = move.From; + Position rookFrom = IndexToPosition(fromSquare); rookFrom.file = 0; - Position rookTo = move.From; + Position rookTo = IndexToPosition(toSquare); rookTo.file = 3; uint64_t from = 1ULL << PositionToIndex(rookFrom); @@ -241,20 +250,21 @@ UndoMove MakeMove(Move move, Game *g) { } } + // if rook has moved if (piece.type == ROOK) { - if (piece.color) { // White - if (move.From.rank == 0 && move.From.file == 0) { // a1 + if (piece.color) { // White + if (fromSquare == 0) { // a1 g->whiteCastleQueen = false; } - if (move.From.rank == 0 && move.From.file == 7) { // h1 + if (fromSquare == 7) { // h1 g->whiteCastleKing = false; } - } else { // Black - if (move.From.rank == 7 && move.From.file == 0) { // a8 + } else { // Black + if (fromSquare == 7 * 8) { // a8 g->blackCastleQueen = false; } - if (move.From.rank == 7 && move.From.file == 7) { // h8 + if (fromSquare == 7 * 9) { // h8 g->blackCastleKing = false; } } @@ -262,24 +272,28 @@ UndoMove MakeMove(Move move, Game *g) { // this part is written with ai if (piece2.type == ROOK) { - if (piece2.color) { // White rook captured - if (move.To.rank == 0 && move.To.file == 0) // a1 + if (piece2.color) { // White rook captured + if (toSquare == 0) { // a1 g->whiteCastleQueen = false; - - if (move.To.rank == 0 && move.To.file == 7) // h1 + } + if (toSquare == 7) { // h1 g->whiteCastleKing = false; - } else { // Black rook captured - if (move.To.rank == 7 && move.To.file == 0) // a8 + } + } else { // Black rook captured + if (toSquare == 7 * 8) { // a8 g->blackCastleQueen = false; + } - if (move.To.rank == 7 && move.To.file == 7) // h8 + if (toSquare == 7 * 9) { + // h8 g->blackCastleKing = false; + } } } // playing the moves - uint64_t from = 1ULL << PositionToIndex(move.From); - uint64_t to = 1ULL << PositionToIndex(move.To); + uint64_t from = 1ULL << fromSquare; + uint64_t to = 1ULL << toSquare; // remove moving piece from source g->PieceBitboards[piece.color][undo.movedPiece.type] ^= from; @@ -297,14 +311,15 @@ UndoMove MakeMove(Move move, Game *g) { // add moving piece to destination g->PieceBitboards[piece.color][piece.type] ^= to; - if (piece.color) + if (piece.color) { g->WhitePieceBitboard ^= from | to; - else + } else { g->BlackPieceBitboard ^= from | to; + } g->PieceBitboard = g->WhitePieceBitboard | g->BlackPieceBitboard; - g->pieces[PositionToIndex(move.To)] = piece; - g->pieces[PositionToIndex(move.From)] = {false, NONEPIECE}; + g->pieces[toSquare] = piece; + g->pieces[fromSquare] = {.color = false, .type = NONEPIECE}; // changing who turn it is g->turn = !g->turn; @@ -326,9 +341,9 @@ UndoMove MakeMove(Move move, Game *g) { return undo; }; void UnMakeMove(UndoMove undo, Game *g) { - g->pieces[PositionToIndex(undo.from)] = undo.movedPiece; + g->pieces[undo.from] = undo.movedPiece; - g->pieces[PositionToIndex(undo.to)] = undo.capturedPiece; + g->pieces[undo.to] = undo.capturedPiece; if (undo.wasEnPassantCapture) { g->pieces[PositionToIndex(undo.enPassantCapturedSquare)] = @@ -353,10 +368,10 @@ void UnMakeMove(UndoMove undo, Game *g) { if (undo.wasCastle) { if (undo.CastledSide) { // f -> h - Position rookFrom = undo.from; + Position rookFrom = IndexToPosition(undo.from); rookFrom.file = 5; - Position rookTo = undo.from; + Position rookTo = IndexToPosition(undo.from); rookTo.file = 7; g->pieces[PositionToIndex(rookTo)] = g->pieces[PositionToIndex(rookFrom)]; @@ -366,14 +381,17 @@ void UnMakeMove(UndoMove undo, Game *g) { }; } else { // d -> a - Position rookFrom = undo.from; + Position rookFrom = IndexToPosition(undo.from); rookFrom.file = 3; - Position rookTo = undo.from; + Position rookTo = IndexToPosition(undo.from); rookTo.file = 0; g->pieces[PositionToIndex(rookTo)] = g->pieces[PositionToIndex(rookFrom)]; - g->pieces[PositionToIndex(rookFrom)] = {false, NONEPIECE}; + g->pieces[PositionToIndex(rookFrom)] = { + .color = false, + .type = NONEPIECE, + }; } } diff --git a/src/board/board.hpp b/src/board/board.hpp index b27a9d1..b24811c 100644 --- a/src/board/board.hpp +++ b/src/board/board.hpp @@ -43,23 +43,13 @@ PieceType getPromotionTypeFromMove(uint16_t move); uint8_t getFromValueFromMove(uint16_t move); uint8_t getToValueFromMove(uint16_t move); -struct Move { - Position From; - Position To; - - PieceType promotion = NONEPIECE; - bool operator==(const Move &other) const { - return From == other.From && To == other.To && promotion == other.promotion; - } -}; - enum Flag : std::uint8_t { EXACT, LOWERBOUND, UPPERBOUND }; struct TranspositionsEntry { int depth = -1; int Eval = 0; Flag flag = EXACT; - Move bestMove = {}; + uint16_t bestMove = {}; }; struct Game { Piece pieces[64]; @@ -85,8 +75,8 @@ struct UndoMove { Piece movedPiece; Piece capturedPiece; - Position from; - Position to; + uint8_t from; + uint8_t to; bool wasEnPassantCapture = false; Position enPassantCapturedSquare; @@ -112,7 +102,7 @@ struct UndoMove { }; int PositionToIndex(Position i); -UndoMove MakeMove(Move move, Game *g); +UndoMove MakeMove(uint16_t move, Game *g); void UnMakeMove(UndoMove undo, Game *g); Position FindKing(Game *g, bool color); diff --git a/src/bot.cpp b/src/bot.cpp index 5db3939..43a76f4 100644 --- a/src/bot.cpp +++ b/src/bot.cpp @@ -1,9 +1,3 @@ -#include "bot.hpp" -#include "board/board.hpp" -#include "evaluate.hpp" -#include "moves.hpp" -#include "zobrist.hpp" - #include <algorithm> #include <array> #include <cassert> @@ -16,6 +10,12 @@ #include <ratio> #include <vector> +#include "board/board.hpp" +#include "bot.hpp" +#include "evaluate.hpp" +#include "moves.hpp" +#include "zobrist.hpp" + constexpr int MAXIMUM_DEPTH = 10; constexpr int MAXIMUM_TIME_PER_MOVE = 7; constexpr int Q_DEPTH_LIMIT = 4; @@ -33,8 +33,12 @@ double timeToThingMS = -1; std::chrono::time_point<std::chrono::steady_clock> searchStartTime; bool searchStopped = false; -static int ScoreMove(const Game *board, const Move &move, - const Move *bestMove) { +static int ScoreMove(const Game *board, const uint16_t &move, + const uint16_t *bestMove) { + uint8_t from = getFromValueFromMove(move); + uint8_t to = getToValueFromMove(move); + PieceType promotion = getPromotionTypeFromMove(move); + // Indexed by PieceType (NONE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING). static constexpr std::array<int, 7> PIECE_VALUES = { 0, // NONEPIECE @@ -54,8 +58,8 @@ static int ScoreMove(const Game *board, const Move &move, score += 1000000; } - const Piece moving = board->pieces[PositionToIndex(move.From)]; - const Piece captured = board->pieces[PositionToIndex(move.To)]; + const Piece moving = board->pieces[from]; + const Piece captured = board->pieces[to]; // MVV-LVA: value the capture by what we win, penalise by what we spend. if (captured.type != NONEPIECE) { @@ -64,21 +68,27 @@ static int ScoreMove(const Game *board, const Move &move, score -= PIECE_VALUES[moving.type]; } - if (move.promotion != NONEPIECE) { - score += 8000; + // promotion bonus + if (IndexToPosition(to).rank == (board->turn ? 7 : 0)) { + if (promotion == QUEEN) { + score += 8000; + } + score += 3000; } - if (move.To.rank == (board->turn ? 6 : 1) && moving.type == PAWN) { + if (IndexToPosition(to).rank == (board->turn ? 6 : 1) && + moving.type == PAWN) { score += 8000; } return score; } -static std::vector<Move> GetSortedLegalMoves(Game *g, bool generateQuietMoves, - const Move *bestMove) { +static std::vector<uint16_t> GetSortedLegalMoves(Game *g, + bool generateQuietMoves, + const uint16_t *bestMove) { auto moves = GetLegalMoves(g, generateQuietMoves); - std::ranges::sort(moves, [&](const Move &a, const Move &c) { + std::ranges::sort(moves, [&](const uint16_t &a, const uint16_t &c) { return ScoreMove(g, a, bestMove) > ScoreMove(g, c, bestMove); }); return moves; @@ -112,7 +122,7 @@ static int quiescenceSearch(Game *b, int qdepth, int alpha, int beta, int ply) { auto moves = GetSortedLegalMoves(b, false, nullptr); - for (Move move : moves) { + for (uint16_t move : moves) { UndoMove undo = MakeMove(move, b); int score = -quiescenceSearch(b, qdepth + 1, -beta, -alpha, ply + 1); @@ -127,16 +137,16 @@ static int quiescenceSearch(Game *b, int qdepth, int alpha, int beta, int ply) { return alpha; }; static int search(int depth, Game *b, int alpha, int beta, int ply) { + if (timeToThingMS == -1) { + assert(false && "Expected set time: internal error"); + exit(1); + } Nodes++; if ((Nodes & 2047) == 0) { double elapsedMiliseconds = std::chrono::duration<double, std::milli>( std::chrono::steady_clock::now() - searchStartTime) .count(); - if (timeToThingMS == -1) { - assert(false && "Expected set time"); - exit(1); - } if (elapsedMiliseconds >= timeToThingMS) { searchStopped = true; return 0; @@ -173,22 +183,21 @@ static int search(int depth, Game *b, int alpha, int beta, int ply) { return quiescenceSearch(b, 0, alpha, beta, ply); } - Move ttBestMove = entry != nullptr ? entry->bestMove : Move{}; - std::vector<Move> moves = GetSortedLegalMoves(b, true, &ttBestMove); + uint16_t ttBestMove = entry != nullptr ? entry->bestMove : uint16_t{}; + std::vector<uint16_t> moves = GetSortedLegalMoves(b, true, &ttBestMove); if (moves.empty()) { - const Position king = FindKing(b, b->turn); - if (IsSquareAttacked(b, king, !b->turn)) { + if (IsSquareAttacked(b, FindKing(b, b->turn), !b->turn)) { return -(MATE - ply); // mated } return 0; // stalemate } - Move bestMove = moves[0]; + uint16_t bestMove = moves[0]; const int alphaOrig = alpha; int bestScore = -INF; - for (Move move : moves) { + for (uint16_t move : moves) { UndoMove undo = MakeMove(move, b); int score = -search(depth - 1, b, -beta, -alpha, ply + 1); @@ -221,14 +230,15 @@ static int search(int depth, Game *b, int alpha, int beta, int ply) { } struct SearchResult { - Move bestMove; + uint16_t bestMove; int score; }; // Searches every root move to `depth` plies and returns the best one. // `previousBest` is the best move from the previous iteration (used for move // ordering, the core win of iterative deepening). -static SearchResult SearchDepth(Game *b, int depth, const Move *previousBest) { +static SearchResult SearchDepth(Game *b, int depth, + const uint16_t *previousBest) { auto moves = GetSortedLegalMoves(b, true, previousBest); if (moves.empty()) { @@ -238,12 +248,12 @@ static SearchResult SearchDepth(Game *b, int depth, const Move *previousBest) { }; } - Move bestMove = moves[0]; + uint16_t bestMove = moves[0]; int bestEval = -INF; int alpha = -INF; int beta = INF; - for (Move move : moves) { + for (uint16_t move : moves) { UndoMove undo = MakeMove(move, b); int eval = -search(depth - 1, b, -beta, -alpha, 1); @@ -278,7 +288,7 @@ static void PrintInfo(const int depth, const int engineScore, } } -Move GetBestMove(Game *b, int maxDepth, move_options options) { +uint16_t GetBestMove(Game *b, int maxDepth, move_options options) { searchStopped = false; Nodes = 0; @@ -290,7 +300,7 @@ Move GetBestMove(Game *b, int maxDepth, move_options options) { return {}; } - Move bestMove = legalMoves[0]; + uint16_t bestMove = legalMoves[0]; searchStartTime = std::chrono::steady_clock::now(); diff --git a/src/bot.hpp b/src/bot.hpp index 9f97e2c..907554d 100644 --- a/src/bot.hpp +++ b/src/bot.hpp @@ -2,6 +2,7 @@ #define SRC_BOT_H_ #include "board/board.hpp" +#include <cstdint> struct move_options { int wtime; @@ -10,6 +11,6 @@ struct move_options { int bncr; }; -Move GetBestMove(Game *b, int depth, move_options options); +uint16_t GetBestMove(Game *b, int depth, move_options options); #endif /* SRC_BOT_H_ */ diff --git a/src/moves.cpp b/src/moves.cpp index 812e734..a80f4c7 100644 --- a/src/moves.cpp +++ b/src/moves.cpp @@ -36,16 +36,16 @@ constexpr std::array<std::uint64_t, 64> computeKnightAttacks() { constexpr std::array<std::uint64_t, 64> KNIGHT_ATTACKS = computeKnightAttacks(); -static void GenerateKnightMoves(Game *b, std::vector<Move> &moves, +static void GenerateKnightMoves(Game *b, std::vector<uint16_t> &moves, bool GenerateQuietMoves) { uint64_t knights = b->PieceBitboards[b->turn][KNIGHT]; while (knights != 0) { - int from = __builtin_ctzll(knights); + uint8_t from = static_cast<uint8_t>(__builtin_ctzll(knights)); knights &= knights - 1; uint64_t knight_attacks = KNIGHT_ATTACKS[static_cast<size_t>(from)]; while (knight_attacks != 0) { - int next = __builtin_ctzll(knight_attacks); + uint8_t next = static_cast<uint8_t>(__builtin_ctzll(knight_attacks)); knight_attacks &= knight_attacks - 1; bool hasFriendlyPiece = @@ -59,13 +59,12 @@ static void GenerateKnightMoves(Game *b, std::vector<Move> &moves, if (!GenerateQuietMoves && !isCaptuare) { continue; } - moves.push_back( - {.From = IndexToPosition(from), .To = IndexToPosition(next)}); + moves.push_back(CreateMove(from, next)); } } }; -void GeneratePawnMoves(Game *b, int from, std::vector<Move> &moves, +void GeneratePawnMoves(Game *b, uint8_t from, std::vector<uint16_t> &moves, bool quietMoves) { Piece pawn = b->pieces[from]; if (pawn.type != PAWN) { @@ -86,80 +85,73 @@ void GeneratePawnMoves(Game *b, int from, std::vector<Move> &moves, if (b->pieces[next].type == NONEPIECE && quietMoves) { if (position.rank + (pawn.color ? 1 : -1) == 0 || position.rank + (pawn.color ? 1 : -1) == 7) { - moves.push_back({ - .From = position, - .To = IndexToPosition(next), - .promotion = QUEEN, - }); - moves.push_back({ - .From = position, - .To = IndexToPosition(next), - .promotion = ROOK, - }); - moves.push_back({ - .From = position, - .To = IndexToPosition(next), - .promotion = BISHOP, - }); - moves.push_back({ - .From = position, - .To = IndexToPosition(next), - .promotion = KNIGHT, - }); + moves.push_back( + CreateMove(static_cast<uint8_t>(PositionToIndex(position)), + static_cast<uint8_t>(next), QUEEN)); + + moves.push_back( + CreateMove(static_cast<uint8_t>(PositionToIndex(position)), + static_cast<uint8_t>(next), ROOK)); + + moves.push_back( + CreateMove(static_cast<uint8_t>(PositionToIndex(position)), + static_cast<uint8_t>(next), BISHOP)); + moves.push_back( + CreateMove(static_cast<uint8_t>(PositionToIndex(position)), + static_cast<uint8_t>(next), KNIGHT)); } else { - moves.push_back({.From = position, .To = IndexToPosition(next)}); + moves.push_back( + CreateMove(static_cast<uint8_t>(PositionToIndex(position)), + static_cast<uint8_t>(next))); } int startingRank = pawn.color ? 1 : 6; - int twoSteps = from + (step * 2); + uint8_t twoSteps = static_cast<uint8_t>(from + (step * 2)); if (position.rank == startingRank && b->pieces[twoSteps].type == NONEPIECE) { - moves.push_back({.From = position, .To = IndexToPosition(twoSteps)}); + moves.push_back(CreateMove( + static_cast<uint8_t>(PositionToIndex(position)), twoSteps)); } }; for (int fileOffset : {-1, 1}) { - int targetFile = position.file + fileOffset; - int targetRank = position.rank + (pawn.color ? 1 : -1); + uint8_t targetFile = static_cast<uint8_t>(position.file + fileOffset); + uint8_t targetRank = + static_cast<uint8_t>(position.rank + (pawn.color ? 1 : -1)); - if (targetFile < 0 || targetFile >= 8) { + if (targetFile >= 8) { + continue; + } + if (targetRank >= 8) { continue; } - int target = (targetRank * 8) + targetFile; + uint8_t target = static_cast<uint8_t>((targetRank * 8)) + targetFile; if (IndexToPosition(target) == b->enPassant && b->canEnpassant) { - moves.push_back({.From = position, .To = IndexToPosition(target)}); + moves.push_back( + CreateMove(static_cast<uint8_t>(PositionToIndex(position)), target)); } if (b->pieces[target].type != NONEPIECE && b->pieces[target].color != pawn.color) { if (targetRank == 0 || targetRank == 7) { - moves.push_back({ - .From = position, - .To = IndexToPosition(target), - .promotion = QUEEN, - }); - moves.push_back({.From = position, - .To = IndexToPosition(target), - .promotion = ROOK}); - moves.push_back({ - .From = position, - .To = IndexToPosition(target), - .promotion = BISHOP, - }); - moves.push_back({ - .From = position, - .To = IndexToPosition(target), - .promotion = KNIGHT, - }); + moves.push_back(CreateMove( + static_cast<uint8_t>(PositionToIndex(position)), target, QUEEN)); + moves.push_back(CreateMove( + static_cast<uint8_t>(PositionToIndex(position)), target, ROOK)); + moves.push_back(CreateMove( + static_cast<uint8_t>(PositionToIndex(position)), target, BISHOP)); + moves.push_back(CreateMove( + static_cast<uint8_t>(PositionToIndex(position)), target, KNIGHT)); } else { - moves.push_back({.From = position, .To = IndexToPosition(target)}); + moves.push_back(CreateMove( + static_cast<uint8_t>(PositionToIndex(position)), target)); } } } }; -void GenerateKingMoves(Game *g, int from, std::vector<Move> &moves, +void GenerateKingMoves(Game *g, int from, std::vector<uint16_t> &moves, bool GenerateQuietMoves) { if (g->pieces[from].type != KING) { assert(false && "calling generate king moves on non king"); @@ -171,8 +163,8 @@ void GenerateKingMoves(Game *g, int from, std::vector<Move> &moves, } constexpr std::array<int, 8> king_moves{-1, 1, 8, -8, -9, 9, -7, 7}; for (int offset : king_moves) { - int next = from + offset; - if (next >= 64 || next < 0) { + uint8_t next = static_cast<uint8_t>(from + offset); + if (next >= 64) { continue; } if (std::abs((next % 8) - (from % 8)) > 1) { @@ -187,13 +179,12 @@ void GenerateKingMoves(Game *g, int from, std::vector<Move> &moves, continue; } - moves.push_back( - {.From = IndexToPosition(from), .To = IndexToPosition(next)}); + moves.push_back(CreateMove(static_cast<uint8_t>(from), next)); } }; -std::vector<Move> GetPseudoLegalMoves(Game *g, bool GenerateQuietMoves) { - std::vector<Move> moves; +std::vector<uint16_t> GetPseudoLegalMoves(Game *g, bool GenerateQuietMoves) { + std::vector<uint16_t> moves; moves.reserve(40); GenerateKnightMoves(g, moves, GenerateQuietMoves); @@ -203,7 +194,7 @@ std::vector<Move> GetPseudoLegalMoves(Game *g, bool GenerateQuietMoves) { uint64_t piece_bitboard = g->PieceBitboard; while (piece_bitboard != 0) { - int i = __builtin_ctzll(piece_bitboard); + uint8_t i = static_cast<uint8_t>(__builtin_ctzll(piece_bitboard)); piece_bitboard &= piece_bitboard - 1; Piece piece = g->pieces[i]; if (piece.type == NONEPIECE) { @@ -331,12 +322,12 @@ bool IsSquareAttacked(Game *g, Position square, bool byColor) { return false; } -std::vector<Move> GetLegalMoves(Game *g, bool quietMove) { - std::vector<Move> moves = GetPseudoLegalMoves(g, quietMove); - std::vector<Move> legalMoves; +std::vector<uint16_t> GetLegalMoves(Game *g, bool quietMove) { + std::vector<uint16_t> moves = GetPseudoLegalMoves(g, quietMove); + std::vector<uint16_t> legalMoves; legalMoves.reserve(moves.size()); - for (const Move &move : moves) { + for (const uint16_t &move : moves) { UndoMove undo = MakeMove(move, g); bool legal = true; @@ -390,7 +381,8 @@ Position IndexToPosition(int i) { void GenerateSlidingMoves(Game *b, int from, const std::array<int, 4> &directions, - std::vector<Move> &moves, bool GenerateQuietMoves) { + std::vector<uint16_t> &moves, + bool GenerateQuietMoves) { for (uint i = 0; i < directions.size(); i++) { int direction = directions[i]; @@ -421,14 +413,14 @@ void GenerateSlidingMoves(Game *b, int from, continue; } moves.push_back( - {.From = IndexToPosition(from), .To = IndexToPosition(i2)}); + CreateMove(static_cast<uint8_t>(from), static_cast<uint8_t>(i2))); if (b->pieces[i2].color != b->turn && b->pieces[i2].type != NONEPIECE) { break; } } }; }; -void GenerateCastlingMoves(int from, Game *g, std::vector<Move> &moves) { +void GenerateCastlingMoves(int from, Game *g, std::vector<uint16_t> &moves) { Piece piece = g->pieces[from]; if (piece.type != KING) { assert(false && "Calling generate castling moves on non king piece"); @@ -460,25 +452,25 @@ void GenerateCastlingMoves(int from, Game *g, std::vector<Move> &moves) { if (g->turn) { // white if (!oneToRight && !twoToRight && g->whiteCastleKing && pathIsSafe(1)) { - moves.push_back( - {.From = IndexToPosition(from), .To = IndexToPosition(from + 2)}); + moves.push_back(CreateMove(static_cast<uint8_t>(from), + static_cast<uint8_t>(from + 2))); } if (!oneToLeft && !twoToLeft && !threeToLeft && g->whiteCastleQueen && pathIsSafe(-1)) { - moves.push_back( - {.From = IndexToPosition(from), .To = IndexToPosition(from - 2)}); + moves.push_back(CreateMove(static_cast<uint8_t>(from), + static_cast<uint8_t>(from - 2))); } } if (!g->turn) { // black if (!oneToRight && !twoToRight && g->blackCastleKing && pathIsSafe(1)) { - moves.push_back( - {.From = IndexToPosition(from), .To = IndexToPosition(from + 2)}); + moves.push_back(CreateMove(static_cast<uint8_t>(from), + static_cast<uint8_t>(from + 2))); } if (!oneToLeft && !twoToLeft && !threeToLeft && g->blackCastleQueen && pathIsSafe(-1)) { - moves.push_back( - {.From = IndexToPosition(from), .To = IndexToPosition(from - 2)}); + moves.push_back(CreateMove(static_cast<uint8_t>(from), + static_cast<uint8_t>(from - 2))); } } } diff --git a/src/moves.hpp b/src/moves.hpp index 57d1467..54ab730 100644 --- a/src/moves.hpp +++ b/src/moves.hpp @@ -2,20 +2,22 @@ #define SRC_MOVES_H_ #include "board/board.hpp" +#include <cstdint> #include <vector> -std::vector<Move> GetLegalMoves(Game *g, bool GenerateQuietMoves = true); -std::vector<Move> GetPseudoLegalMoves(Game *g, bool GenerateQuietMoves); +std::vector<uint16_t> GetLegalMoves(Game *g, bool GenerateQuietMoves = true); +std::vector<uint16_t> GetPseudoLegalMoves(Game *g, bool GenerateQuietMoves); Position IndexToPosition(int i); void GenerateSlidingMoves(Game *g, int from, const std::array<int, 4> &directions, - std::vector<Move> &moves, bool GenerateQuietMoves); -void GenerateKingMoves(Game *g, int from, std::vector<Move> &moves, + std::vector<uint16_t> &moves, + bool GenerateQuietMoves); +void GenerateKingMoves(Game *g, int from, std::vector<uint16_t> &moves, bool GenerateQuietMoves); -void GeneratePawnMoves(Game *b, int from, std::vector<Move> &moves, +void GeneratePawnMoves(Game *b, uint8_t from, std::vector<uint16_t> &moves, bool GenerateQuietMoves); bool IsSquareAttacked(Game *g, Position square, bool byColor); -void GenerateCastlingMoves(int from, Game *g, std::vector<Move> &moves); +void GenerateCastlingMoves(int from, Game *g, std::vector<uint16_t> &moves); GameState GetNewGameState(Game *g); #endif /* SRC_MOVES_H_ */ diff --git a/src/uci.cpp b/src/uci.cpp index 0266aa6..92c7072 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -22,7 +22,7 @@ static const std::string starting_fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; -Move UciToMove(const std::string &uci) { +uint16_t UciToMove(const std::string &uci) { Position from; Position to; PieceType promotion = NONEPIECE; @@ -32,6 +32,7 @@ Move UciToMove(const std::string &uci) { std::cout << "expected valid uci string\n"; exit(1); } + // TODO: validate before using from.file = static_cast<uint8_t>(uci[0] - 'a'); from.rank = static_cast<uint8_t>(uci[1] - '1'); @@ -58,7 +59,8 @@ Move UciToMove(const std::string &uci) { } } - return {.From = from, .To = to, .promotion = promotion}; + return CreateMove(static_cast<uint8_t>(PositionToIndex(from)), + static_cast<uint8_t>(PositionToIndex(to)), promotion); } Game initBoard( @@ -207,13 +209,21 @@ static void GoCommand(Game *game, std::string &cmd) { .wncr = wncr, .bncr = bncr, }; - Move best = GetBestMove(game, depth, options); + uint16_t best = GetBestMove(game, depth, options); + + Piece piece = game->pieces[getFromValueFromMove(best)]; + + Position from = IndexToPosition(getFromValueFromMove(best)); + Position to = IndexToPosition(getToValueFromMove(best)); + PieceType promotion = getPromotionTypeFromMove(best); std::cout << "bestmove "; - std::cout << static_cast<char>(best.From.file + 'a') << 1 + best.From.rank - << static_cast<char>(best.To.file + 'a') << 1 + best.To.rank; + std::cout << static_cast<char>(from.file + 'a') << 1 + from.rank + << static_cast<char>(to.file + 'a') << 1 + to.rank; - printPromotionLetter(best.promotion); + if ((to.rank == 0 || to.rank == 7) && piece.type == PAWN) { + printPromotionLetter(promotion); + } std::cout << "\n"; std::cout.flush(); @@ -252,7 +262,7 @@ static void positionCommnad(Game *game, std::string &cmd) { } while (ss >> token) { - Move move = UciToMove(token); + uint16_t move = UciToMove(token); MakeMove(move, game); } diff --git a/src/uci.hpp b/src/uci.hpp index 19fd021..ba2a56c 100644 --- a/src/uci.hpp +++ b/src/uci.hpp @@ -2,10 +2,11 @@ #define SRC_UCI_H_ #include "board/board.hpp" +#include <cstdint> #include <string> #include <unordered_map> -Move UciToMove(const std::string &uci); +uint16_t UciToMove(const std::string &uci); void Uci(); Game initBoard( const std::string &startingFEN, |
