Skip to content

Commit 8a7c6a4

Browse files
don't search unnecessarily
1 parent f4518e2 commit 8a7c6a4

11 files changed

+79
-99
lines changed

main.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "MoveGenerator.h"
77
#include "Evaluator.h"
88
#include "Search.h"
9+
#include "MoveParser.h"
910
#include <cstring>
1011
#include <string>
1112

@@ -40,7 +41,7 @@ char* move(const int start, const int end, int flag, int promotionType, int play
4041

4142
EMSCRIPTEN_KEEPALIVE
4243
char* parseandmove(const char* movestring){
43-
Move move = Interface::CLI::parseMove(movestring, board);
44+
Move move = parseMove(movestring, board);
4445
board.makeMove(move);
4546
const std::string fen = board.fen();
4647
const int length = fen.length();

src/CLI.cpp

+1-39
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#include "CLI.h"
22
#include <iostream>
33
#include <sstream>
4-
#include <unordered_map>
54
#include <thread>
65

76
#include "MoveGenerator.h"
87
#include "Search.h"
8+
#include "MoveParser.h"
99

1010
namespace Interface {
1111
void CLI::start() {
@@ -41,44 +41,6 @@ namespace Interface {
4141
return Instruction(command, std::vector(strings.begin() + 1, strings.end()));
4242
}
4343

44-
Move CLI::parseMove(const std::string &string, const ChessBoard &board) {
45-
const int startPos = Util::stringToPosition(string.substr(0, 2));
46-
const int endPos = Util::stringToPosition(string.substr(2, 2));
47-
Type promotionType = EMPTY;
48-
MoveFlag flag = QUIET;
49-
50-
if (string.length() > 4) {
51-
promotionType = Util::charToPiece(string[4]).type;
52-
}
53-
const Square &startSquare = board.squares[startPos];
54-
const Square &endSquare = board.squares[endPos];
55-
if (endSquare.type != EMPTY && endSquare.color != board.sideToMove) {
56-
flag = static_cast<MoveFlag>(endSquare.type);
57-
} else {
58-
if (startSquare.type == PAWN) {
59-
if (startPos / 8 == 1 && endPos / 8 == 3 || startPos / 8 == 6 && endPos / 8 == 4) {
60-
flag = DOUBLEPAWNPUSH;
61-
} else if (abs(startPos - endPos) == 7 || abs(startPos - endPos) == 9) {
62-
flag = ENPASSANT;
63-
}
64-
} else {
65-
if (startSquare.type == KING) {
66-
if (startPos == 4 && startSquare.color == BLACK) {
67-
if (endPos == 2) flag = CASTLEQUEENSIDE;
68-
else if (endPos == 6) flag = CASTLEKINGSIDE;
69-
}
70-
if (startPos == 60 && startSquare.color == WHITE) {
71-
if (endPos == 58) flag = CASTLEQUEENSIDE;
72-
else if (endPos == 62) flag = CASTLEKINGSIDE;
73-
}
74-
}
75-
}
76-
}
77-
78-
return Move(startPos, endPos, promotionType, flag, board.sideToMove);
79-
}
80-
81-
8244
void CLI::handleInstruction(const Instruction &instr) {
8345
switch (instr.command) {
8446
case uci:

src/CLI.h

-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ namespace Interface {
4040
public:
4141
void start();
4242

43-
static Move parseMove(const std::string&string, const ChessBoard&board);
44-
4543
private:
4644
ChessBoard board;
4745

src/MoveParser.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "Move.h"
55
#include "ChessBoard.h"
66

7-
Move parseMove(const std::string&string, const ChessBoard&board) {
7+
static Move parseMove(const std::string&string, const ChessBoard&board) {
88
const int startPos = Util::stringToPosition(string.substr(0, 2));
99
const int endPos = Util::stringToPosition(string.substr(2, 2));
1010
Type promotionType = EMPTY;

src/Search.cpp

+21-13
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ Move Search::search(ChessBoard &board, const int timeAllowed) {
3232

3333
const auto timeAvailable = start + timeOut - std::chrono::steady_clock::now();
3434

35-
3635
if (search.cv.wait_for(lk, timeAvailable, [&] { return search.finished; })) {
3736
thread.join();
3837
} else {
@@ -41,7 +40,12 @@ Move Search::search(ChessBoard &board, const int timeAllowed) {
4140
break;
4241
}
4342

44-
search.lastPV = search.collectPV(i);
43+
bool endEarly = false;
44+
45+
search.lastPV = search.collectPV(i, endEarly);
46+
47+
if (endEarly) break;
48+
4549
if (search.lastPV.size() > i) {
4650
i = search.lastPV.size();
4751
}
@@ -334,7 +338,7 @@ void Search::storeKillerMove(const Move &move, const int ply) {
334338
Search::Search(ChessBoard &board) : board(board) {
335339
}
336340

337-
std::vector<Move> Search::collectPV(const int depth) const {
341+
std::vector<Move> Search::collectPV(const int depth, bool &endEarly) const {
338342
std::vector<Move> pv;
339343
std::unordered_set<uint64_t> pvPositions;
340344
std::vector<int> scores;
@@ -348,14 +352,8 @@ std::vector<Move> Search::collectPV(const int depth) const {
348352
break;
349353
Move move = entry.bestMove;
350354

351-
if (pvPositions.contains(board.hashCode)) {
352-
std::cout << "Cycle in PV!" << std::endl;
353-
board.makeMove(move);
354-
pv.push_back(move);
355-
scores.push_back(entry.score);
356-
pvDepth++;
357-
break;
358-
}
355+
if (TranspositionTable::isMateScore(entry.score) || entry.nodeType == TranspositionTable::BOOK)
356+
endEarly = true;
359357
#ifdef DEBUG
360358
auto moves = MoveGenerator::pseudoLegalMoves(board);
361359
if (moves.empty()) break;
@@ -374,12 +372,16 @@ std::vector<Move> Search::collectPV(const int depth) const {
374372
break;
375373
}
376374
#endif
377-
378375
pvPositions.insert(board.hashCode);
379376
board.makeMove(move);
380377
pv.push_back(move);
381378
scores.push_back(entry.score);
382379
pvDepth++;
380+
381+
if (pvPositions.contains(board.hashCode)) {
382+
std::cout << "Cycle in PV!" << std::endl;
383+
break;
384+
}
383385
}
384386
std::string pvString;
385387
std::string pvStringWithScores = "info PV: ";
@@ -398,6 +400,12 @@ std::vector<Move> Search::collectPV(const int depth) const {
398400
return pv;
399401
}
400402

403+
std::vector<Move> Search::collectPV(int depth) const {
404+
bool unused = false;
405+
return collectPV(depth, unused);
406+
}
407+
408+
401409
bool Search::getTransposition(const uint64_t hash, const int depth, const int ply, int &score, const int &alpha,
402410
const int &beta, Move &hashMove) {
403411
if (tt.contains(hash)) {
@@ -432,4 +440,4 @@ bool Search::getTransposition(const uint64_t hash, const int depth, const int pl
432440
}
433441

434442
return false;
435-
}
443+
}

src/Search.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ class Search {
5656

5757
void storeKillerMove(const Move&move, int ply);
5858

59-
std::vector<Move> collectPV(int depth) const;
59+
std::vector<Move> collectPV(int depth) const;
60+
std::vector<Move> collectPV(int depth, bool& endEarly) const;
6061
};
6162

6263
#endif

src/TranspositionTable.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ TranspositionTable::Entry TranspositionTable::getEntry(const uint64_t key, const
1111
const int index = key % TT_SIZE;
1212
Entry entry = entries[index];
1313

14-
if (abs(entry.score) >= MIN_MATE_SCORE) {
14+
if (isMateScore(entry.score)) {
1515
const int sign = entry.score > 0 ? 1 : -1;
1616
entry.score = sign * (abs(entry.score) - ply);
1717
}
@@ -33,7 +33,7 @@ void TranspositionTable::setEntry(const ChessBoard &board, const Move bestMove,
3333
const NodeType nodeType, const int ply) {
3434
const int index = board.hashCode % TT_SIZE;
3535

36-
if (abs(score) >= MIN_MATE_SCORE) {
36+
if (isMateScore(score)) {
3737
const int sign = score > 0 ? 1 : -1;
3838
score = sign * (abs(score) + ply);
3939
}
@@ -106,3 +106,7 @@ void TranspositionTable::loadOpenings(ChessBoard &board) {
106106

107107
file.close();
108108
}
109+
110+
bool TranspositionTable::isMateScore(int32_t score) {
111+
return abs(score) >= MIN_MATE_SCORE;
112+
}

src/TranspositionTable.h

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class TranspositionTable {
3333

3434
void setEntry(const ChessBoard &board, Move bestMove, int depth, int score, NodeType nodeType, int ply);
3535

36+
static bool isMateScore(int32_t score) ;
37+
3638
int reads;
3739
int writes;
3840
int collisions;

tests/HashTest.cpp

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <catch2/catch_test_macros.hpp>
22

3-
#include "CLI.h"
3+
#include "ChessBoard.h"
4+
#include "MoveParser.h"
45

56
TEST_CASE("HASH - Initial Code", "[HashTests]") {
67
ChessBoard board = ChessBoard();
@@ -19,7 +20,7 @@ TEST_CASE("HASH - Capturing a piece", "[HashTests]") {
1920
const HashCodes codes = board.hashCodes;
2021
board.setPosition("4k3/8/8/3p4/4P3/8/8/4K3 w - - 0 1");
2122
const uint64_t originalCode = board.hashCode;
22-
board.makeMove(Interface::CLI::parseMove("e4d5", board));
23+
board.makeMove(parseMove("e4d5", board));
2324
const uint64_t targetCode = originalCode
2425
^ codes.pieceCode(PAWN, WHITE, 36)
2526
^ codes.pieceCode(PAWN, BLACK, 27)
@@ -33,7 +34,7 @@ TEST_CASE("HASH - Losing one castling right", "[HashTests]") {
3334
const HashCodes codes = board.hashCodes;
3435
board.setPosition("4k3/8/8/3p4/4P3/8/8/R3K2R w KQ - 0 1");
3536
const uint64_t originalCode = board.hashCode;
36-
board.makeMove(Interface::CLI::parseMove("h1h2", board));
37+
board.makeMove(parseMove("h1h2", board));
3738
const uint64_t targetCode = originalCode
3839
^ codes.pieceCode(ROOK, WHITE, 63)
3940
^ codes.pieceCode(ROOK, WHITE, 55)
@@ -48,7 +49,7 @@ TEST_CASE("HASH - Losing two castling rights", "[HashTests]") {
4849
const HashCodes codes = board.hashCodes;
4950
board.setPosition("4k3/8/8/3p4/4P3/8/8/R3K2R w KQ - 0 1");
5051
const uint64_t originalCode = board.hashCode;
51-
board.makeMove(Interface::CLI::parseMove("e1e2", board));
52+
board.makeMove(parseMove("e1e2", board));
5253
const uint64_t targetCode = originalCode
5354
^ codes.pieceCode(KING, WHITE, 60)
5455
^ codes.pieceCode(KING, WHITE, 52)
@@ -63,15 +64,15 @@ TEST_CASE("HASH - En passant", "[HashTests]") {
6364
const HashCodes codes = board.hashCodes;
6465
board.setPosition("4k3/3p4/8/8/8/8/4P3/4K3 w - - 0 1");
6566
uint64_t originalCode = board.hashCode;
66-
board.makeMove(Interface::CLI::parseMove("e2e4", board));
67+
board.makeMove(parseMove("e2e4", board));
6768
uint64_t targetCode = originalCode
6869
^ codes.pieceCode(PAWN, WHITE, 52)
6970
^ codes.pieceCode(PAWN, WHITE, 36)
7071
^ codes.blackToMoveCode
7172
^ codes.enPassantFileCode[4];
7273
CHECK(board.hashCode == targetCode);
7374
originalCode = board.hashCode;
74-
board.makeMove(Interface::CLI::parseMove("d7d6", board));
75+
board.makeMove(parseMove("d7d6", board));
7576
targetCode = originalCode
7677
^ codes.pieceCode(PAWN, BLACK, 11)
7778
^ codes.pieceCode(PAWN, BLACK, 19)

tests/RepetitionTest.cpp

+27-25
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,77 @@
11
#include <catch2/catch_test_macros.hpp>
2-
#include "CLI.h"
2+
3+
#include "ChessBoard.h"
4+
#include "MoveParser.h"
35

46
TEST_CASE("Repetitions - by White", "[RepetitionTests]") {
57
ChessBoard board = ChessBoard();
68
board.setPosition("2r2rk1/1q1b1pp1/2nppn1p/3p4/N2P1N1P/4PB2/1P1Q1PP1/2R1R1K1 b - - 6 23");
79
CHECK(!board.isDraw());
8-
board.makeMove(Interface::CLI::parseMove("f6e4", board));
10+
board.makeMove(parseMove("f6e4", board));
911
CHECK(!board.isDraw());
10-
board.makeMove(Interface::CLI::parseMove("d2d1", board));
12+
board.makeMove(parseMove("d2d1", board));
1113
CHECK(!board.isDraw());
12-
board.makeMove(Interface::CLI::parseMove("e4f6", board));
14+
board.makeMove(parseMove("e4f6", board));
1315
CHECK(!board.isDraw());
14-
board.makeMove(Interface::CLI::parseMove("d1d2", board));
16+
board.makeMove(parseMove("d1d2", board));
1517
CHECK(board.isDraw());
1618
}
1719

1820
TEST_CASE("Repetitions - by Black", "[RepetitionTests]") {
1921
ChessBoard board = ChessBoard();
2022
board.setPosition("2r2rk1/1q1b1pp1/2nppn1p/3p4/N2P1N1P/4PB2/1P3PP1/2RQR1K1 w - - 5 23");
2123
CHECK(!board.isDraw());
22-
board.makeMove(Interface::CLI::parseMove("d1d2", board));
24+
board.makeMove(parseMove("d1d2", board));
2325
CHECK(!board.isDraw());
24-
board.makeMove(Interface::CLI::parseMove("f6e4", board));
26+
board.makeMove(parseMove("f6e4", board));
2527
CHECK(!board.isDraw());
26-
board.makeMove(Interface::CLI::parseMove("d2d1", board));
28+
board.makeMove(parseMove("d2d1", board));
2729
CHECK(!board.isDraw());
28-
board.makeMove(Interface::CLI::parseMove("e4f6", board));
30+
board.makeMove(parseMove("e4f6", board));
2931
CHECK(board.isDraw());
3032
}
3133

3234
TEST_CASE("Repetitions - No repetition by White", "[RepetitionTests]") {
3335
ChessBoard board = ChessBoard();
3436
board.setPosition("2r2rk1/1q1b1pp1/2nppn1p/3p4/N2P1N1P/4PB2/1P1Q1PP1/2R1R1K1 b - - 6 23");
3537
CHECK(!board.isDraw());
36-
board.makeMove(Interface::CLI::parseMove("f6e4", board));
38+
board.makeMove(parseMove("f6e4", board));
3739
CHECK(!board.isDraw());
38-
board.makeMove(Interface::CLI::parseMove("d2d1", board));
40+
board.makeMove(parseMove("d2d1", board));
3941
CHECK(!board.isDraw());
40-
board.makeMove(Interface::CLI::parseMove("e4f6", board));
42+
board.makeMove(parseMove("e4f6", board));
4143
CHECK(!board.isDraw());
42-
board.makeMove(Interface::CLI::parseMove("a4b6", board));
44+
board.makeMove(parseMove("a4b6", board));
4345
CHECK(!board.isDraw());
4446
}
4547

4648
TEST_CASE("Repetitions - No repetition by Black", "[RepetitionTests]") {
4749
ChessBoard board = ChessBoard();
4850
board.setPosition("2r2rk1/1q1b1pp1/2nppn1p/3p4/N2P1N1P/4PB2/1P3PP1/2RQR1K1 w - - 5 23");
4951
CHECK(!board.isDraw());
50-
board.makeMove(Interface::CLI::parseMove("d1d2", board));
52+
board.makeMove(parseMove("d1d2", board));
5153
CHECK(!board.isDraw());
52-
board.makeMove(Interface::CLI::parseMove("f6e4", board));
54+
board.makeMove(parseMove("f6e4", board));
5355
CHECK(!board.isDraw());
54-
board.makeMove(Interface::CLI::parseMove("d2d1", board));
56+
board.makeMove(parseMove("d2d1", board));
5557
CHECK(!board.isDraw());
56-
board.makeMove(Interface::CLI::parseMove("c6a5", board));
58+
board.makeMove(parseMove("c6a5", board));
5759
CHECK(!board.isDraw());
5860
}
5961

6062
TEST_CASE("Repetitions - after irreversible move", "[RepetitionTests]") {
6163
ChessBoard board = ChessBoard();
6264
board.setPosition("2r2rk1/1q1b1pp1/2nppn1p/3p4/N2P1N1P/4PB2/1P3PP1/2RQR1K1 w - - 5 23");
6365
CHECK(!board.isDraw());
64-
board.makeMove(Interface::CLI::parseMove("h4h5", board));
66+
board.makeMove(parseMove("h4h5", board));
6567
CHECK(!board.isDraw());
66-
board.makeMove(Interface::CLI::parseMove("f6e4", board));
68+
board.makeMove(parseMove("f6e4", board));
6769
CHECK(!board.isDraw());
68-
board.makeMove(Interface::CLI::parseMove("d1d2", board));
70+
board.makeMove(parseMove("d1d2", board));
6971
CHECK(!board.isDraw());
70-
board.makeMove(Interface::CLI::parseMove("e4f6", board));
72+
board.makeMove(parseMove("e4f6", board));
7173
CHECK(!board.isDraw());
72-
board.makeMove(Interface::CLI::parseMove("d2d1", board));
74+
board.makeMove(parseMove("d2d1", board));
7375
CHECK(board.isDraw());
7476
}
7577

@@ -80,17 +82,17 @@ TEST_CASE("Repetitions - Irreversible Moves", "[RepetitionTests]") {
8082
CHECK(board.irreversibleIndices.empty());
8183
CHECK(board.positionHistory.empty());
8284
// PAWN move
83-
board.makeMove(Interface::CLI::parseMove("b2b4", board));
85+
board.makeMove(parseMove("b2b4", board));
8486
CHECK(board.positionHistory.size() == 1);
8587
CHECK(board.irreversibleIndices.size() == 1);
8688
CHECK(board.irreversibleIndices[0] == 0);
8789
// CAPTURE
88-
board.makeMove(Interface::CLI::parseMove("c6b4", board));
90+
board.makeMove(parseMove("c6b4", board));
8991
CHECK(board.positionHistory.size() == 2);
9092
CHECK(board.irreversibleIndices.size() == 2);
9193
CHECK(board.irreversibleIndices[1] == 1);
9294
// QUIET MOVE
93-
board.makeMove(Interface::CLI::parseMove("a4c3", board));
95+
board.makeMove(parseMove("a4c3", board));
9496
CHECK(board.positionHistory.size() == 3);
9597
CHECK(board.irreversibleIndices.size() == 2);
9698
board.unMakeMove();

0 commit comments

Comments
 (0)