aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdam <adammegarules1@gmail.com>2026-07-30 16:40:17 +0200
committerAdam <adammegarules1@gmail.com>2026-07-30 16:40:17 +0200
commit8df9e390a71eeb2835eab06ec4b474c8cad63ecd (patch)
tree4788195fc373baa22bb349f1532e62d3db9dc99b /src
parent72646d9beb20e338569d578fee38a37be06faabe (diff)
improving bot
Diffstat (limited to 'src')
-rw-r--r--src/board/board.cpp24
-rw-r--r--src/board/board.hpp19
-rw-r--r--src/bot.cpp173
-rw-r--r--src/bot.hpp6
-rw-r--r--src/moves.cpp7
-rw-r--r--src/uci.cpp2
6 files changed, 141 insertions, 90 deletions
diff --git a/src/board/board.cpp b/src/board/board.cpp
index 22db36e..d0cf4c1 100644
--- a/src/board/board.cpp
+++ b/src/board/board.cpp
@@ -43,10 +43,10 @@ UndoMove MakeMove(Move move, Game *g) {
undo.oldState = g->state;
- undo.OldwhiteCastleKing = g->whiteCastleKing;
- undo.OldwhiteCastleQueen = g->whiteCastleQueen;
- undo.OldblackCastleKing = g->blackCastleKing;
- undo.OldblackCastleQueen = g->blackCastleQueen;
+ undo.OldWhiteCastleKing = g->whiteCastleKing;
+ undo.OldWhiteCastleQueen = g->whiteCastleQueen;
+ undo.OldBlackCastleKing = g->blackCastleKing;
+ undo.OldBlackCastleQueen = g->blackCastleQueen;
// play move
Piece piece = g->pieces[PositionToIndex(move.From)];
@@ -184,7 +184,7 @@ UndoMove MakeMove(Move move, Game *g) {
// 3 fold check
uint64_t key = GenerateZobristKey(g);
- undo.zobristKey = key;
+ undo.ZobristKey = key;
g->ThreeFoldMap[key]++;
@@ -218,10 +218,10 @@ void UnMakeMove(UndoMove undo, Game *g) {
g->state = undo.oldState;
- g->whiteCastleKing = undo.OldwhiteCastleKing;
- g->whiteCastleQueen = undo.OldwhiteCastleQueen;
- g->blackCastleKing = undo.OldblackCastleKing;
- g->blackCastleQueen = undo.OldblackCastleQueen;
+ g->whiteCastleKing = undo.OldWhiteCastleKing;
+ g->whiteCastleQueen = undo.OldWhiteCastleQueen;
+ g->blackCastleKing = undo.OldBlackCastleKing;
+ g->blackCastleQueen = undo.OldBlackCastleQueen;
if (undo.wasCastle) {
if (undo.CastledSide) {
@@ -247,8 +247,8 @@ void UnMakeMove(UndoMove undo, Game *g) {
}
}
- g->ThreeFoldMap[undo.zobristKey] -= 1;
- if (g->ThreeFoldMap[undo.zobristKey] <= 0) {
- g->ThreeFoldMap.erase(undo.zobristKey);
+ g->ThreeFoldMap[undo.ZobristKey] -= 1;
+ if (g->ThreeFoldMap[undo.ZobristKey] <= 0) {
+ g->ThreeFoldMap.erase(undo.ZobristKey);
};
};
diff --git a/src/board/board.hpp b/src/board/board.hpp
index bd8efba..b35773d 100644
--- a/src/board/board.hpp
+++ b/src/board/board.hpp
@@ -18,12 +18,11 @@ enum GameState {
TURN,
WHITE_WON,
BLACK_WON,
- STALEMATE,
DRAW,
};
struct Piece {
- bool color = 0;
+ bool color = false;
PieceType type = NONEPIECE;
};
@@ -35,7 +34,7 @@ struct Position {
};
struct TranspositionsEntry {
int depth;
- float Eval;
+ int Eval;
};
struct BitBoards {
uint64_t whitePawns;
@@ -54,7 +53,7 @@ struct BitBoards {
};
struct Game {
Piece pieces[64];
- bool turn = 1; // 1 white; 0 black
+ bool turn = true; // 1 white; 0 black
bool whiteCastleKing = false;
bool whiteCastleQueen = false;
bool blackCastleKing = false;
@@ -62,7 +61,7 @@ struct Game {
uint8_t halfMoveClock = 0;
uint16_t MoveClock = 0;
Position enPassant;
- bool canEnpassant = 0;
+ bool canEnpassant = false;
GameState state = TURN;
std::unordered_map<uint64_t, int> ThreeFoldMap;
std::unordered_map<uint64_t, TranspositionsEntry> *Transpositions = nullptr;
@@ -92,14 +91,14 @@ struct UndoMove {
bool oldCanEnpassant;
Position oldEnPassant;
- bool OldwhiteCastleKing;
- bool OldwhiteCastleQueen;
- bool OldblackCastleKing;
- bool OldblackCastleQueen;
+ bool OldWhiteCastleKing;
+ bool OldWhiteCastleQueen;
+ bool OldBlackCastleKing;
+ bool OldBlackCastleQueen;
int oldHalfMoveClock;
int oldMoveClock;
- uint64_t zobristKey;
+ uint64_t ZobristKey;
GameState oldState;
// castling
diff --git a/src/bot.cpp b/src/bot.cpp
index 9a489dd..f05c303 100644
--- a/src/bot.cpp
+++ b/src/bot.cpp
@@ -10,16 +10,17 @@
#include <iostream>
#include <vector>
-const int DEFAULT_DEPTH = 4;
+constexpr int DEFAULT_DEPTH = 4;
+constexpr int Q_DEPTH_LIMIT = 6;
-const int PAWN_VALUE = 100;
-const int KNIGHT_VALUE = 320;
-const int BISHOP_VALUE = 400;
-const int ROOK_VALUE = 500;
-const int QUEEN_VALUE = 900;
-const int MATE = 10000;
+constexpr int PAWN_VALUE = 100;
+constexpr int KNIGHT_VALUE = 320;
+constexpr int BISHOP_VALUE = 400;
+constexpr int ROOK_VALUE = 500;
+constexpr int QUEEN_VALUE = 900;
+constexpr int MATE = 10000;
-const int PAWN_TABLE[64] = {
+static int PAWN_TABLE[64] = {
0, 0, 0, 0, 0, 0, 0, 0, // last rank promotes to a quuen
50, 50, 50, 50, 50, 50, 50, 50, // comments to stop formating to ruin it
10, 10, 20, 35, 35, 20, 10, 10, //
@@ -30,7 +31,7 @@ const int PAWN_TABLE[64] = {
0, 0, 0, 0, 0, 0, 0, 0 //
};
-int KNIGHT_TABLE[64] = {
+static int KNIGHT_TABLE[64] = {
-50, -40, -30, -30, -30, -30, -40, -50, //
-40, -20, 0, 0, 0, 0, -20, -40, //
-30, 0, 10, 15, 15, 10, 0, -30, //
@@ -41,7 +42,7 @@ int KNIGHT_TABLE[64] = {
-50, -40, -30, -30, -30, -30, -40, -50, //
};
-int BISHOP_TABLE[64] = {
+static int BISHOP_TABLE[64] = {
-20, -10, -10, -10, -10, -10, -10, -20, //
-10, 5, 0, 0, 0, 0, 5, -10, //
-10, 10, 10, 10, 10, 10, 10, -10, //
@@ -52,7 +53,7 @@ int BISHOP_TABLE[64] = {
-20, -10, -10, -10, -10, -10, -10, -20, //
};
-int ROOK_TABLE[64] = {
+static int ROOK_TABLE[64] = {
0, 0, 5, 10, 10, 5, 0, 0, //
5, 10, 10, 10, 10, 10, 10, 5, //
-5, 0, 0, 0, 0, 0, 0, -5, //
@@ -63,7 +64,7 @@ int ROOK_TABLE[64] = {
0, 0, 5, 10, 10, 5, 0, 0, //
};
-int QUEEN_TABLE[64] = {
+static int QUEEN_TABLE[64] = {
-20, -10, -10, -5, -5, -10, -10, -20, //
-10, 0, 0, 0, 0, 0, 0, -10, //
-10, 0, 5, 5, 5, 5, 0, -10, //
@@ -74,7 +75,7 @@ int QUEEN_TABLE[64] = {
-20, -10, -10, -5, -5, -10, -10, -20, //
};
-int KING_TABLE_EARLY[64] = {
+static int KING_TABLE_EARLY[64] = {
-30, -40, -40, -50, -50, -40, -40, -30, //
-30, -40, -40, -50, -50, -40, -40, -30, //
-30, -40, -40, -50, -50, -40, -40, -30, //
@@ -88,8 +89,8 @@ int KING_TABLE_EARLY[64] = {
int ScoreMove(const Game *board, const Move &move) {
int score = 0;
- Piece moving = board->pieces[PositionToIndex(move.From)];
- Piece captured = board->pieces[PositionToIndex(move.To)];
+ const Piece moving = board->pieces[PositionToIndex(move.From)];
+ const Piece captured = board->pieces[PositionToIndex(move.To)];
// Captures (MVV-LVA)
if (captured.type != NONEPIECE) {
@@ -118,32 +119,33 @@ int ScoreMove(const Game *board, const Move &move) {
std::vector<Move> GetSortedLegalMoves(Game *g) {
auto moves = GetLegalMoves(g);
- if (moves.size() == 0) {
+ if (moves.empty()) {
return moves;
}
- std::sort(moves.begin(), moves.end(), [&](const Move &a, const Move &c) {
+ std::ranges::sort(moves, [&](const Move &a, const Move &c) {
return ScoreMove(g, a) > ScoreMove(g, c);
});
return moves;
}
-Move EngineGetBestMove(Game *b, int depth) {
- int usedDepth = (depth != -1 ? depth : DEFAULT_DEPTH);
- auto moves = GetSortedLegalMoves(b);
- if (moves.size() == 0) {
+Move EngineGetBestMove(Game *b, const int depth) {
+ const int usedDepth = (depth != -1 ? depth : DEFAULT_DEPTH);
+ const auto moves = GetSortedLegalMoves(b);
+ if (moves.empty()) {
std::cout << "Expected a position with legal moves";
- assert(false && "Unhanled error zero legal moves for bot");
+ assert(false && "Error zero legal moves for bot");
exit(1);
}
Move bestMove = moves[0];
- float BestEval = (b->turn ? -INFINITY : INFINITY);
- for (Move move : moves) {
- UndoMove undo = MakeMove(move, b);
- float alpha = -INFINITY;
- float beta = INFINITY;
+ int BestEval = b->turn ? std::numeric_limits<int>::lowest()
+ : std::numeric_limits<int>::max();
+ for (const Move move : moves) {
+ const UndoMove undo = MakeMove(move, b);
+ const float alpha = -INFINITY;
+ const float beta = INFINITY;
- float eval = minimax(usedDepth - 1, b, alpha, beta);
+ const int eval = minimax(usedDepth - 1, b, alpha, beta);
UnMakeMove(undo, b);
if (b->turn) {
@@ -160,11 +162,52 @@ Move EngineGetBestMove(Game *b, int depth) {
}
return bestMove;
}
-float minimax(int depth, Game *b, float alpha, float beta) {
+int quiescenceSearch(Game *b, int Qdepth) {
+ int standPat = EvaluateBoardForWhite(b);
+ if (Qdepth >= Q_DEPTH_LIMIT) {
+ return standPat;
+ }
+ std::vector<Move> attackMoves;
+ for (Move move : GetSortedLegalMoves(b)) {
+ if (b->pieces[PositionToIndex(move.To)].type != NONEPIECE) {
+ attackMoves.push_back(move);
+ }
+ };
+ if (attackMoves.empty()) {
+ return standPat;
+ }
+
+ int bestEval = b->turn ? std::numeric_limits<int>::lowest()
+ : std::numeric_limits<int>::max();
+
+ if (b->turn) {
+ for (Move move : attackMoves) {
+ UndoMove undo = MakeMove(move, b);
+
+ int eval = quiescenceSearch(b, Qdepth + 1);
+
+ UnMakeMove(undo, b);
+ bestEval = std::max(bestEval, eval);
+ }
+ } else {
+ for (Move move : attackMoves) {
+ UndoMove undo = MakeMove(move, b);
+
+ int eval = quiescenceSearch(b, Qdepth + 1);
+
+ UnMakeMove(undo, b);
+ bestEval = std::min(bestEval, eval);
+ }
+ }
+
+ return bestEval;
+}
+
+int minimax(int depth, Game *b, float alpha, float beta) {
uint64_t gameHash = GenerateZobristKey(b);
if (b->ThreeFoldMap[gameHash] >= 2) {
- return b->turn ? -500 : 500;
+ return 0;
}
if (b->Transpositions->contains(gameHash)) {
TranspositionsEntry data = b->Transpositions->at(gameHash);
@@ -173,24 +216,29 @@ float minimax(int depth, Game *b, float alpha, float beta) {
}
}
+ if (depth <= 0) {
+ return quiescenceSearch(b, 0);
+ }
auto moves = GetSortedLegalMoves(b);
- if (depth == 0 || moves.size() == 0) {
- return EvaluateBoardForWhite(b);
+ if (moves.empty()) {
+ return quiescenceSearch(b, 0);
}
bool shouldStore = true;
- float bestEval = b->turn ? -INFINITY : INFINITY;
+ int bestEval = b->turn ? std::numeric_limits<int>::lowest()
+ : std::numeric_limits<int>::max();
+
if (b->turn) {
for (Move move : moves) {
UndoMove undo = MakeMove(move, b);
- float eval = minimax(depth - 1, b, alpha, beta);
+ int eval = minimax(depth - 1, b, alpha, beta);
UnMakeMove(undo, b);
bestEval = std::max(bestEval, eval);
- alpha = std::max(alpha, bestEval);
+ alpha = std::max(alpha, static_cast<float>(bestEval));
if (alpha >= beta) {
shouldStore = false;
@@ -201,12 +249,12 @@ float minimax(int depth, Game *b, float alpha, float beta) {
for (Move move : moves) {
UndoMove undo = MakeMove(move, b);
- float eval = minimax(depth - 1, b, alpha, beta);
+ int eval = minimax(depth - 1, b, alpha, beta);
UnMakeMove(undo, b);
bestEval = std::min(bestEval, eval);
- beta = std::min(beta, bestEval);
+ beta = std::min(beta, static_cast<float>(bestEval));
if (alpha >= beta) {
shouldStore = false;
break; // *snips*
@@ -215,24 +263,29 @@ float minimax(int depth, Game *b, float alpha, float beta) {
}
if (shouldStore) {
- b->Transpositions->operator[](gameHash) = {depth, bestEval};
+ b->Transpositions->operator[](gameHash) = {.depth = depth,
+ .Eval = bestEval};
}
return bestEval;
}
-int PSTIndex(int square, bool white) { return white ? square : (56 ^ square); }
-static int ForceKingToEdgeBonus(Position enemyKing, Position myKing) {
+static int PSTIndex(const int square, const bool white) {
+ return white ? square : (56 ^ square);
+}
+
+static int ForceKingToEdgeBonus(const Position enemyKing,
+ const Position myKing) {
int bonus = 0;
// Push enemy king toward edge
- int distToCenter =
+ const int distToCenter =
std::abs(enemyKing.file - 3) + std::abs(enemyKing.rank - 3);
bonus += distToCenter * 10;
// Bring own king closer
- int kingDistance = std::abs(myKing.file - enemyKing.file) +
- std::abs(myKing.rank - enemyKing.rank);
+ const int kingDistance = std::abs(myKing.file - enemyKing.file) +
+ std::abs(myKing.rank - enemyKing.rank);
bonus += (14 - kingDistance) * 5;
@@ -242,8 +295,8 @@ static bool IsEndgame(Game *g) {
int queens = 0;
int rooks = 0;
- for (int i = 0; i < 64; i++) {
- switch (g->pieces[i].type) {
+ for (const Piece &piece : g->pieces) {
+ switch (piece.type) {
case QUEEN:
queens++;
break;
@@ -258,11 +311,10 @@ static bool IsEndgame(Game *g) {
return queens == 0 || (queens == 2 && rooks <= 1);
}
-float EvaluateBoardForWhite(Game *g) {
- float score = 0;
+int EvaluateBoardForWhite(Game *g) {
+ int score = 0;
- GameState state = GetNewGameState(g);
- switch (state) {
+ switch (GetNewGameState(g)) {
case WHITE_WON:
return MATE;
break;
@@ -271,13 +323,11 @@ float EvaluateBoardForWhite(Game *g) {
break;
case TURN:
break;
- case STALEMATE:
- return 0;
case DRAW:
return 0;
}
for (int i = 0; i < 64; i++) {
- Piece piece = g->pieces[i];
+ const Piece piece = g->pieces[i];
if (piece.type == NONEPIECE)
continue;
@@ -316,15 +366,16 @@ float EvaluateBoardForWhite(Game *g) {
} else {
score -= value;
}
- Position whiteKing = FindKing(g, true);
- Position blackKing = FindKing(g, false);
-
- if (IsEndgame(g)) {
- score +=
- ForceKingToEdgeBonus(blackKing, whiteKing); // White attacking black
- score -=
- ForceKingToEdgeBonus(whiteKing, blackKing); // Black attacking white
- }
+ }
+
+ Position whiteKing = FindKing(g, true);
+ Position blackKing = FindKing(g, false);
+
+ if (IsEndgame(g)) {
+ score +=
+ ForceKingToEdgeBonus(blackKing, whiteKing); // White attacking black
+ score -=
+ ForceKingToEdgeBonus(whiteKing, blackKing); // Black attacking white
}
return score;
}
diff --git a/src/bot.hpp b/src/bot.hpp
index 382c9be..0796299 100644
--- a/src/bot.hpp
+++ b/src/bot.hpp
@@ -4,8 +4,10 @@
#include "board/board.hpp"
#include <vector>
Move EngineGetBestMove(Game *b, int depth);
-float EvaluateBoardForWhite(Game *b);
-float minimax(int depth, Game *b, float alpha, float beta);
+
+int EvaluateBoardForWhite(Game *b);
+
+int minimax(int depth, Game *b, float alpha, float beta);
int ScoreMove(const Game *board, const Move &move);
std::vector<Move> GetSortedLegalMoves(Game *g);
#endif /* SRC_BOT_H_ */
diff --git a/src/moves.cpp b/src/moves.cpp
index d5ad989..4deafe3 100644
--- a/src/moves.cpp
+++ b/src/moves.cpp
@@ -164,12 +164,11 @@ std::vector<Move> GetLegalMoves(Game *g) {
}
}
- return legalMoves;
+ return legalMoves;
}
GameState GetNewGameState(Game *g) {
// make sure we dont override game ending states
- if (g->state == DRAW || g->state == STALEMATE || g->state == WHITE_WON ||
- g->state == BLACK_WON) {
+ if (g->state == DRAW || g->state == WHITE_WON || g->state == BLACK_WON) {
return g->state;
}
if (g->halfMoveClock >= 50) {
@@ -186,7 +185,7 @@ GameState GetNewGameState(Game *g) {
if (check) {
g->state = g->turn ? BLACK_WON : WHITE_WON;
} else {
- g->state = STALEMATE;
+ g->state = DRAW;
}
}
return g->state;
diff --git a/src/uci.cpp b/src/uci.cpp
index ef368b3..ad1e89e 100644
--- a/src/uci.cpp
+++ b/src/uci.cpp
@@ -31,7 +31,7 @@ bool LoadTable(
uint64_t hash;
int depth;
- float eval;
+ int eval;
while (file >> hash >> depth >> eval) {
transpositions->operator[](hash) = {depth, eval};