Skip to content

Commit 702549c

Browse files
authored
Not very good, but faster than v0.0.3b
1 parent d25f275 commit 702549c

File tree

7 files changed

+164
-153
lines changed

7 files changed

+164
-153
lines changed

chess.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ namespace utils {
131131
// Split a string by a delimiter
132132
[[nodiscard]] inline std::vector<std::string_view> splitString(std::string_view string, const char &delimiter) {
133133
std::vector<std::string_view> result;
134+
result.reserve(100);
134135
size_t start = 0;
135136
size_t end = string.find(delimiter);
136137

@@ -1824,6 +1825,7 @@ class Board {
18241825
std::vector<Move> move_stack;
18251826
explicit Board(std::string_view fen = constants::STARTPOS, bool chess960 = false) {
18261827
prev_states_.reserve(256);
1828+
move_stack.reserve(200);
18271829
chess960_ = chess960;
18281830
setFenInternal<true>(fen);
18291831
}

eval.cpp

Lines changed: 59 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,63 @@
11
#include "eval.h"
22

3-
std::map<unsigned long long, int> transposition;
4-
int eval(chess::Board board){
5-
if (transposition.count(board.hash())) return transposition[board.hash()];
6-
U64 hash=board.hash();
7-
//Game over
8-
if (board.inCheck()&&board.isGameOver().first!=chess::GameResultReason::NONE)return MAX;
9-
else if (board.isGameOver().first!=chess::GameResultReason::NONE)return 0;
10-
int eval=0;
11-
//Material
12-
eval+=Pawn*board.pieces(chess::PieceType::underlying::PAWN,chess::Color::underlying::WHITE).count();
13-
eval+=Knight*board.pieces(chess::PieceType::underlying::KNIGHT,chess::Color::underlying::WHITE).count();
14-
eval+=Bishop*board.pieces(chess::PieceType::underlying::BISHOP,chess::Color::underlying::WHITE).count();
15-
eval+=Rook*board.pieces(chess::PieceType::underlying::ROOK,chess::Color::underlying::WHITE).count();
16-
eval+=Queen*board.pieces(chess::PieceType::underlying::QUEEN,chess::Color::underlying::WHITE).count();
17-
eval-=Pawn*board.pieces(chess::PieceType::underlying::PAWN,chess::Color::underlying::BLACK).count();
18-
eval-=Knight*board.pieces(chess::PieceType::underlying::KNIGHT,chess::Color::underlying::BLACK).count();
19-
eval-=Bishop*board.pieces(chess::PieceType::underlying::BISHOP,chess::Color::underlying::BLACK).count();
20-
eval-=Rook*board.pieces(chess::PieceType::underlying::ROOK,chess::Color::underlying::BLACK).count();
21-
eval-=Queen*board.pieces(chess::PieceType::underlying::QUEEN,chess::Color::underlying::BLACK).count();
22-
//Pawns
23-
eval -= isolated(board);
24-
eval -= dblisolated(board);
25-
eval -= weaks(board);
26-
eval -= blockage(board);
27-
eval += pawnIslands(board);
28-
eval -= holes(board);
29-
eval += pawnRace(board);
30-
eval -= underpromote(board);
31-
eval -= weakness(board);
32-
eval += pawnShield(board);
33-
eval += pawnStorm(board);
34-
eval += pawnLevers(board);
35-
eval += outpost(board);
36-
eval -= evaluatePawnRams(board);
37-
eval += evaluateUnfreePawns(board);
38-
eval += evaluateOpenPawns(board);
39-
eval -= evaluateBadBishops(board);
40-
eval += evaluateFianchetto(board);
41-
eval -= evaluateTrappedPieces(board);
42-
eval -= evaluateKnightForks(board);
43-
eval += evaluateRooksOnFiles(board);
3+
std::unordered_map<U64, int> transposition; // Faster lookup
4+
5+
// Declare only missing functions
6+
int evaluatePawnStructure(const chess::Board& board);
7+
int evaluatePieces(const chess::Board& board);
8+
9+
int eval(const chess::Board& board) {
10+
U64 hash = board.hash();
11+
12+
// Faster lookup & insertion
13+
auto [it, inserted] = transposition.emplace(hash, 0);
14+
if (!inserted) return it->second; // Already exists, return stored evaluation
15+
16+
if (board.inCheck() && board.isGameOver().first != chess::GameResultReason::NONE) return MAX;
17+
if (board.isGameOver().first != chess::GameResultReason::NONE) return 0;
18+
19+
// Precompute piece counts (avoid multiple function calls)
20+
int pieceCount[10] = {
21+
board.pieces(chess::PieceType::PAWN, chess::Color::WHITE).count(),
22+
board.pieces(chess::PieceType::KNIGHT, chess::Color::WHITE).count(),
23+
board.pieces(chess::PieceType::BISHOP, chess::Color::WHITE).count(),
24+
board.pieces(chess::PieceType::ROOK, chess::Color::WHITE).count(),
25+
board.pieces(chess::PieceType::QUEEN, chess::Color::WHITE).count(),
26+
board.pieces(chess::PieceType::PAWN, chess::Color::BLACK).count(),
27+
board.pieces(chess::PieceType::KNIGHT, chess::Color::BLACK).count(),
28+
board.pieces(chess::PieceType::BISHOP, chess::Color::BLACK).count(),
29+
board.pieces(chess::PieceType::ROOK, chess::Color::BLACK).count(),
30+
board.pieces(chess::PieceType::QUEEN, chess::Color::BLACK).count(),
31+
};
32+
33+
// Compute material score
34+
int eval = (Pawn * (pieceCount[0] - pieceCount[5])) +
35+
(Knight * (pieceCount[1] - pieceCount[6])) +
36+
(Bishop * (pieceCount[2] - pieceCount[7])) +
37+
(Rook * (pieceCount[3] - pieceCount[8])) +
38+
(Queen * (pieceCount[4] - pieceCount[9]));
39+
40+
// Evaluate positional aspects
41+
eval += evaluatePawnStructure(board);
42+
eval += evaluatePieces(board);
4443
eval += evaluateKingSafety(board);
45-
eval += evaluateKingPawnTropism(board);
46-
eval += evaluateKingMobility(board);
47-
eval += evaluateSpaceControl(board);
48-
eval -= evaluateTactics(board);
49-
board.pop();
50-
eval -= -isolated(board);
51-
eval -= -dblisolated(board);
52-
eval -= -weaks(board);
53-
eval -= -blockage(board);
54-
eval += -pawnIslands(board);
55-
eval -= -holes(board);
56-
eval += -pawnRace(board);
57-
eval -= -underpromote(board);
58-
eval -= -weakness(board);
59-
eval += -pawnShield(board);
60-
eval += -pawnStorm(board);
61-
eval += -pawnLevers(board);
62-
eval += -outpost(board);
63-
eval -= -evaluatePawnRams(board);
64-
eval += -evaluateUnfreePawns(board);
65-
eval += -evaluateOpenPawns(board);
66-
eval -= -evaluateBadBishops(board);
67-
eval += -evaluateFianchetto(board);
68-
eval -= -evaluateTrappedPieces(board);
69-
eval -= -evaluateKnightForks(board);
70-
eval += -evaluateRooksOnFiles(board);
71-
eval += -evaluateKingSafety(board);
72-
eval += -evaluateKingPawnTropism(board);
73-
eval += -evaluateKingMobility(board);
74-
eval += -evaluateSpaceControl(board);
75-
eval -= -evaluateTactics(board);
76-
transposition[hash]=eval;
77-
return eval;
44+
eval += evaluateTactics(board);
45+
46+
it->second = eval; // Store result
47+
return eval;
48+
}
49+
50+
// Use `const chess::Board&` to avoid copies
51+
int evaluatePawnStructure(const chess::Board& board) {
52+
chess::Board b=board;
53+
return -(isolated(board) + dblisolated(board) + weaks(board) + blockage(board) +
54+
holes(board) + underpromote(b) + weakness(board) + evaluatePawnRams(board)) +
55+
(pawnIslands(board) + pawnRace(board) + pawnShield(board) + pawnStorm(board) +
56+
pawnLevers(board) + outpost(board) + evaluateUnfreePawns(board) + evaluateOpenPawns(board));
57+
}
58+
59+
// Use `const chess::Board&` to avoid copies
60+
int evaluatePieces(const chess::Board& board) {
61+
return -(evaluateBadBishops(board) + evaluateTrappedPieces(board) + evaluateKnightForks(board)) +
62+
(evaluateFianchetto(board) + evaluateRooksOnFiles(board));
7863
}

eval.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
#define Queen 900
1414
#define MATE(i) MAX-i
1515
#define MATE_DISTANCE(i) i-MAX_MATE
16-
int eval(chess::Board);
16+
int eval(const chess::Board&);

patterns.cpp

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,41 +37,54 @@ inline bool isTrappedPiece(const chess::Board& board, chess::Square pieceSq) {
3737
return true;
3838
}
3939

40+
// A knight is trapped if it has **no safe squares to jump to**
41+
U64 pieceBB = 1ULL << pieceSq.index(); // Precompute once
42+
U64 knightAttacks = getKnightAttacks(pieceBB, board.occ()), bishopAttacks=getBishopAttacks(pieceSq, board.occ()),
43+
rookAttacks = getRookAttacks(1ULL<<pieceSq.index(), board.occ()), queenAttacks=getQueenAttacks(pieceSq, board.occ());
44+
chess::Piece p;
4045
// **3. Special Conditions for Specific Pieces**
4146
switch (type) {
4247
case chess::KNIGHT:
43-
// A knight is trapped if it has **no safe squares to jump to**
44-
for (chess::Square sq : scan_reversed(getKnightAttacks(1ULL << pieceSq.index(),board.occ()))) {
45-
if (board.at(sq) == chess::Piece::NONE || board.at(sq).color() != side) {
48+
while (knightAttacks) {
49+
int sq = __builtin_ctzll(knightAttacks); // Extract LSB (fast)
50+
p=board.at(sq);
51+
if (p == chess::Piece::NONE || p.color() != side) {
4652
return false; // The knight has a safe escape
4753
}
48-
}
54+
knightAttacks &= knightAttacks - 1; // Remove LSB
55+
}
4956
return true;
5057

5158
case chess::BISHOP:
52-
// A bishop is trapped if **all diagonal escape squares are blocked**
53-
for (chess::Square sq : scan_reversed(getBishopAttacks(pieceSq, board.occ()))) {
54-
if (board.at(sq) == chess::Piece::NONE || board.at(sq).color() != side) {
59+
while (bishopAttacks) {
60+
int sq = __builtin_ctzll(bishopAttacks); // Extract LSB (fast)
61+
p=board.at(sq);
62+
if (p == chess::Piece::NONE || p.color() != side) {
5563
return false;
5664
}
57-
}
65+
bishopAttacks &= bishopAttacks - 1; // Remove LSB
66+
}
5867
return true;
5968

6069
case chess::ROOK:
61-
// A rook is trapped if **all rank/file escape squares are blocked**
62-
for (chess::Square sq : scan_reversed(getRookAttacks(1ULL<<pieceSq.index(), board.occ()))) {
63-
if (board.at(sq) == chess::Piece::NONE || board.at(sq).color() != side) {
70+
while (rookAttacks) {
71+
int sq = __builtin_ctzll(rookAttacks); // Extract LSB (fast)
72+
p=board.at(sq);
73+
if (p == chess::Piece::NONE || p.color() != side) {
6474
return false;
6575
}
76+
rookAttacks &= rookAttacks - 1; // Remove LSB
6677
}
6778
return true;
6879

6980
case chess::QUEEN:
70-
// A queen is trapped if **both bishop and rook movements are blocked**
71-
for (chess::Square sq : scan_reversed(getQueenAttacks(pieceSq, board.occ()))) {
72-
if (board.at(sq) == chess::Piece::NONE || board.at(sq).color() != side) {
81+
while (queenAttacks) {
82+
int sq = __builtin_ctzll(queenAttacks); // Extract LSB (fast)
83+
p=board.at(sq);
84+
if (p == chess::Piece::NONE || p.color() != side) {
7385
return false;
7486
}
87+
queenAttacks &= queenAttacks - 1; // Remove LSB
7588
}
7689
return true;
7790

@@ -95,8 +108,11 @@ inline bool isPinned(chess::Board& board, chess::Square pieceSq) {
95108

96109
return isPinned;
97110
}
98-
111+
std::unordered_map<U64, int> tacticsCache;
99112
int evaluateTactics(const chess::Board& board) {
113+
U64 hash = board.hash();
114+
if (tacticsCache.find(hash) != tacticsCache.end()) return tacticsCache[hash];
115+
100116
int score = 0;
101117

102118
chess::Square myKing = board.kingSq(board.sideToMove());
@@ -143,15 +159,14 @@ int evaluateTactics(const chess::Board& board) {
143159
}
144160
}
145161
}
162+
tacticsCache[hash] = score;
146163
return score;
147164
}
148165

149-
150166
// **8. King Patterns (Mobility & Escape Routes)**
151167
inline U64 getKingMobility(U64 king, U64 friendlyPieces) {
152168
return (king << 8 | king >> 8 | king << 1 | king >> 1) & ~friendlyPieces;
153169
}
154-
155170
bool isLosingQueenPromotion(int pawn, U64 enemyKing, U64 enemyPieces, U64 friendlyPieces) {
156171
// **1. Stalemate Check**
157172
U64 kingMobility = getKingMobility(enemyKing, enemyPieces | friendlyPieces);

0 commit comments

Comments
 (0)