Skip to content

Commit 1ab98d9

Browse files
Jlisowskyykryczkal
andauthored
Search algorithm refinements (#60)
* Added stable sort instead swapping * Added stable move pick * Fix small mate bug * Reverted some changes * Generate new type of king ring * First possible version * Polished the implementation * Added some comments * Applied clang-format * Added promotion moves to the quisce search * mend * Added simple IID implementation * Applied clang-format * Fixed eval command * Started SEE implementation * First see implementation ready * Cleaned perft implementation * Moved SEE to ChessMechanics * Moved find fig to ChessMechanics * Made the MoveGeneartor to inherit from ChessMechanics * Applied clang-format * Update TestRunner.py * Delete test_output.csv --------- Co-authored-by: Łukasz Kryczka <60490378+kryczkal@users.noreply.github.com>
1 parent b12cb91 commit 1ab98d9

File tree

12 files changed

+432
-478
lines changed

12 files changed

+432
-478
lines changed

Tests/searchTests.csv

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
3r2k1/B7/4q3/1R4P1/1P3r2/8/2P2P1p/R4K2 w - - 0 49, 9
2-
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1, 8
3-
r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1, 8
4-
8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1, 8
5-
r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1, 8
6-
r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1, 8
7-
rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8, 8
8-
r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10, 8
9-
3rr1k1/1pq2pp1/p2nb2p/2pp4/6PR/2PBPN2/PPQ2PP1/K2R4 b - - 0 20, 8
10-
7k/r2q1ppp/1p1p4/p1bPrPPb/P1PNPR1P/1PQ5/2B5/R5K1 w - - 23 16, 8
1+
3r2k1/B7/4q3/1R4P1/1P3r2/8/2P2P1p/R4K2 w - - 0 49, 10
2+
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1, 10
3+
r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1, 10
4+
8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1, 10
5+
r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1, 10
6+
r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1, 10
7+
rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8, 10
8+
r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10, 10
9+
3rr1k1/1pq2pp1/p2nb2p/2pp4/6PR/2PBPN2/PPQ2PP1/K2R4 b - - 0 20, 10
10+
7k/r2q1ppp/1p1p4/p1bPrPPb/P1PNPR1P/1PQ5/2B5/R5K1 w - - 23 16, 10

include/Board.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ struct Board
113113

114114
static bool Comp(const Board &a, const Board &b);
115115

116-
constexpr uint64_t GetFigBoard(int col, size_t figDesc) { return BitBoards[col * BitBoardsPerCol + figDesc]; }
116+
constexpr uint64_t GetFigBoard(int col, size_t figDesc) const { return BitBoards[col * BitBoardsPerCol + figDesc]; }
117117

118118
// ------------------------------
119119
// Class fields

include/CompilationConstants.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,25 @@ static constexpr int16_t SPECIAL_DRAW_SCORE = 0;
2525
static constexpr int RESERVED_SCORE_VALUES = 64;
2626
static constexpr int TIME_STOP_RESERVED_VALUE = std::numeric_limits<int16_t>::max() - 1;
2727
static constexpr int NO_EVAL = std::numeric_limits<int16_t>::max() - 2;
28-
static constexpr int NEGATIVE_INFINITY = std::numeric_limits<int16_t>::min() + RESERVED_SCORE_VALUES;
28+
static constexpr int NEGATIVE_INFINITY = std::numeric_limits<int16_t>::min() + RESERVED_SCORE_VALUES + 1;
2929
static constexpr int POSITIVE_INFINITY = std::numeric_limits<int16_t>::max() - RESERVED_SCORE_VALUES;
3030
static constexpr int BEST_MATE_VALUE = NEGATIVE_INFINITY + MAX_SEARCH_DEPTH;
3131
static constexpr int BEST_MATE_VALUE_ABS = -(BEST_MATE_VALUE);
3232
static constexpr uint16_t QUIESENCE_AGE_DIFF_REPLACE = 16;
3333
static constexpr uint16_t DEFAULT_AGE_DIFF_REPLACE = 10;
3434

35+
/* Depth from which Internal Iterative Deepening (IID) is used */
36+
static constexpr int IID_MIN_DEPTH = 6;
37+
38+
/* Ply reduction for IID case*/
39+
static constexpr int IID_REDUCTION = 2;
40+
41+
/* Minimal depth from which Aspiration Windows are used*/
42+
static constexpr int ASP_WND_MIN_DEPTH = 7;
43+
3544
// Initial Aspiration Window Delta its cp value is equal to INITIAL_ASP_WINDOW_DELTA * BoardEvaluator::ScoreGrain
3645
// (probably 8) ~= 48
37-
static constexpr int16_t INITIAL_ASP_WINDOW_DELTA = 6;
46+
static constexpr int16_t INITIAL_ASP_WINDOW_DELTA = 3;
3847
static constexpr int MAX_ASP_WINDOW_RETRIES = 4;
3948

4049
// ------------------------------

include/Evaluation/KingSafetyEval.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,34 @@ struct KingSafetyEval
139139
// ------------------------------
140140

141141
private:
142+
static constexpr std::array<uint64_t, Board::BitBoardFields> _kingRings = []() constexpr
143+
{
144+
constexpr int MovesOffsets[] = {-1, 1, 8, -8};
145+
146+
std::array<uint64_t, Board::BitBoardFields> rv{};
147+
148+
const int range = static_cast<int>(Board::BitBoardFields);
149+
for (int msbInd = 0; msbInd < range; ++msbInd)
150+
{
151+
const uint64_t basicMoves = KingMap::GetMoves(msbInd);
152+
uint64_t mask = basicMoves;
153+
154+
for (int offset : MovesOffsets)
155+
{
156+
const int newMsbPos = msbInd + offset;
157+
158+
// first of all we check whether we do not exceed possible range,
159+
// secondly we check to not accidentally put king on the other side of the board
160+
if (newMsbPos >= 0 && newMsbPos <= 63 && ((MaxMsbPossible >> newMsbPos) & basicMoves) != 0)
161+
mask |= KingMap::GetMoves(newMsbPos);
162+
}
163+
164+
rv[msbInd] = mask;
165+
}
166+
167+
return rv;
168+
}();
169+
142170
static constexpr std::array<std::array<uint64_t, Board::BitBoardFields>, 2> _kingPawnDefenseFields = []() constexpr
143171
{
144172
std::array<std::array<uint64_t, Board::BitBoardFields>, 2> rv{};

include/MoveGeneration/ChessMechanics.h

Lines changed: 106 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "../Board.h"
1010

1111
#include "BishopMap.h"
12+
#include "Move.h"
1213
#include "RookMap.h"
1314

1415
struct ChessMechanics
@@ -35,7 +36,7 @@ struct ChessMechanics
3536

3637
ChessMechanics() = delete;
3738

38-
explicit ChessMechanics(Board &bd) : _board(bd) {}
39+
explicit ChessMechanics(const Board &bd) : _board(bd) {}
3940

4041
ChessMechanics(ChessMechanics &other) = default;
4142

@@ -49,12 +50,35 @@ struct ChessMechanics
4950

5051
[[nodiscard]] bool IsCheck() const;
5152

52-
[[nodiscard]] uint64_t GetFullBitMap() const;
53+
// Gets occupancy maps, which simply indicates whether some field is occupied or not. Does not distinguish colors.
54+
[[nodiscard]] INLINE uint64_t GetFullBitMap() const
55+
{
56+
uint64_t map = 0;
57+
for (const auto m : _board.BitBoards) map |= m;
58+
return map;
59+
}
60+
61+
// Gets occupancy maps, which simply indicates whether some field is occupied or not, by desired color figures.
62+
[[nodiscard]] INLINE uint64_t GetColBitMap(const int col) const
63+
{
64+
TraceIfFalse(col == 1 || col == 0, "Invalid color!");
5365

54-
[[nodiscard]] uint64_t GetColBitMap(int col) const;
66+
uint64_t map = 0;
67+
for (size_t i = 0; i < Board::BitBoardsPerCol; ++i) map |= _board.BitBoards[Board::BitBoardsPerCol * col + i];
68+
return map;
69+
}
5570

5671
// does not check kings BitBoards!!!
57-
[[nodiscard]] size_t GetIndexOfContainingBitBoard(uint64_t map, int col) const;
72+
[[nodiscard]] INLINE size_t GetIndexOfContainingBitBoard(const uint64_t map, const int col) const
73+
{
74+
const size_t colIndex = col * Board::BitBoardsPerCol;
75+
size_t rv = 0;
76+
for (size_t i = 0; i < Board::BitBoardsPerCol; ++i)
77+
{
78+
rv += ((_board.BitBoards[colIndex + i] & map) != 0) * i;
79+
}
80+
return colIndex + rv;
81+
}
5882

5983
// [blockedFigMap, checksCount, checkType]
6084
[[nodiscard]] std::tuple<uint64_t, uint8_t, uint8_t> GetBlockedFieldBitMap(uint64_t fullMap) const;
@@ -67,15 +91,90 @@ struct ChessMechanics
6791

6892
[[nodiscard]] uint64_t GetAllowedTilesWhenCheckedByNonSliding() const;
6993

94+
[[nodiscard]] INLINE uint64_t GetLeastValuablePiece(uint64_t pieces, int color, int &pieceIndOut) const
95+
{
96+
const int range = static_cast<int>(kingIndex);
97+
for (int ind = 0; ind < range; ++ind)
98+
{
99+
const int colIndex = color * static_cast<int>(Board::BitBoardsPerCol) + ind;
100+
const uint64_t intersection = pieces & _board.BitBoards[colIndex];
101+
102+
if (intersection)
103+
{
104+
pieceIndOut = ind;
105+
return ExtractLsbBit(intersection);
106+
}
107+
}
108+
109+
return 0;
110+
}
111+
112+
/*
113+
* SEE - Static Exchange Evaluation - function used to get approximated gain
114+
* after making given move, that is: it performs every exchange on field given by the move
115+
* */
116+
[[nodiscard]] int SEE(Move mv) const;
117+
118+
/* Function finds index of figure type based on given single bit BitBoard */
119+
static INLINE int FindFigType(const uint64_t BitBoard, const Board &bd)
120+
{
121+
int rv = 0;
122+
constexpr int range = static_cast<int>(Board::BitBoardsPerCol);
123+
for (int i = 0; i < range; ++i)
124+
{
125+
rv += ((bd.BitBoards[i] & BitBoard) != 0) * i;
126+
rv += ((bd.BitBoards[wPawnsIndex + i] & BitBoard) != 0) * i;
127+
}
128+
return rv;
129+
}
130+
70131
// ------------------------------
71132
// private methods
72133
// ------------------------------
73134

135+
private:
136+
[[nodiscard]] INLINE uint64_t _updateAttackers(const uint64_t fullMap, const int msbPos) const
137+
{
138+
const uint64_t bishops = (_board.BitBoards[wQueensIndex] | _board.BitBoards[bQueensIndex] |
139+
_board.BitBoards[wBishopsIndex] | _board.BitBoards[bBishopsIndex]) &
140+
fullMap;
141+
const uint64_t rooks = (_board.BitBoards[wQueensIndex] | _board.BitBoards[bQueensIndex] |
142+
_board.BitBoards[wRooksIndex] | _board.BitBoards[bRooksIndex]) &
143+
fullMap;
144+
145+
uint64_t attackers = 0;
146+
attackers |= (BishopMap::GetMoves(msbPos, fullMap) & bishops) | (RookMap::GetMoves(msbPos, fullMap) & rooks);
147+
148+
return attackers;
149+
}
150+
151+
struct _seePackage
152+
{
153+
uint64_t attackersBitBoard;
154+
uint64_t fullMap;
155+
uint64_t xrayMap;
156+
};
157+
158+
[[nodiscard]] inline INLINE _seePackage _prepareForSEE(int msbPos) const;
159+
74160
static std::pair<uint64_t, uint8_t>
75161
_getRookBlockedMap(uint64_t rookMap, uint64_t fullMapWoutKing, uint64_t kingMap);
76162

77163
template <class MoveGeneratorT>
78-
[[nodiscard]] static uint64_t _blockIterativeGenerator(uint64_t board, MoveGeneratorT mGen);
164+
[[nodiscard]] INLINE static uint64_t _blockIterativeGenerator(uint64_t board, MoveGeneratorT mGen)
165+
{
166+
uint64_t blockedMap = 0;
167+
168+
while (board != 0)
169+
{
170+
const int figPos = ExtractMsbPos(board);
171+
board ^= (MaxMsbPossible >> figPos);
172+
173+
blockedMap |= mGen(figPos);
174+
}
175+
176+
return blockedMap;
177+
}
79178

80179
// returns [ pinnedFigMap, allowedTilesMap ]
81180
template <class MoveMapT, PinnedFigGen type>
@@ -85,7 +184,8 @@ struct ChessMechanics
85184
// Class fields
86185
// ------------------------------
87186

88-
Board &_board;
187+
protected:
188+
const Board &_board;
89189
};
90190

91191
template <ChessMechanics::PinnedFigGen genType>
@@ -107,21 +207,6 @@ std::pair<uint64_t, uint64_t> ChessMechanics::GetPinnedFigsMap(const int col, co
107207
return {pinnedByBishops | pinnedByRooks, allowedBishops | allowedRooks};
108208
}
109209

110-
template <class MoveGeneratorT> uint64_t ChessMechanics::_blockIterativeGenerator(uint64_t board, MoveGeneratorT mGen)
111-
{
112-
uint64_t blockedMap = 0;
113-
114-
while (board != 0)
115-
{
116-
const int figPos = ExtractMsbPos(board);
117-
board ^= (MaxMsbPossible >> figPos);
118-
119-
blockedMap |= mGen(figPos);
120-
}
121-
122-
return blockedMap;
123-
}
124-
125210
template <class MoveMapT, ChessMechanics::PinnedFigGen type>
126211
std::pair<uint64_t, uint64_t>
127212
ChessMechanics::_getPinnedFigMaps(const uint64_t fullMap, const uint64_t possiblePinningFigs) const

0 commit comments

Comments
 (0)