diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..a431afa --- /dev/null +++ b/.clang-format @@ -0,0 +1,65 @@ +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: None +AlignOperands: Align +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Always +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: true +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +ColumnLimit: 0 +CompactNamespaces: false +ContinuationIndentWidth: 8 +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PointerAlignment: Right +ReflowComments: false +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 0 +SpacesInAngles: Never +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3f40bfc..e9914b5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,34 +13,34 @@ jobs: strategy: matrix: config: - - { - name: "Ubuntu g++ popcnt", - os: ubuntu-latest, - compiler: g++-11, - arch: popcnt, - target: BlackCore-popcnt-linux, - } - - { - name: "Ubuntu g++ modern", - os: ubuntu-latest, - compiler: g++-11, - arch: modern, - target: BlackCore-modern-linux, - } - - { - name: "Ubuntu g++ avx2", - os: ubuntu-latest, - compiler: g++-11, - arch: avx2, - target: BlackCore-avx2-linux, - } - - { - name: "Ubuntu g++ bmi2", - os: ubuntu-latest, - compiler: g++-11, - arch: bmi2, - target: BlackCore-bmi2-linux, - } + #- { + # name: "Ubuntu g++ popcnt", + # os: ubuntu-latest, + # compiler: g++-11, + # arch: popcnt, + # target: BlackCore-popcnt-linux, + #} + #- { + # name: "Ubuntu g++ modern", + # os: ubuntu-latest, + # compiler: g++-11, + # arch: modern, + # target: BlackCore-modern-linux, + #} + #- { + # name: "Ubuntu g++ avx2", + # os: ubuntu-latest, + # compiler: g++-11, + # arch: avx2, + # target: BlackCore-avx2-linux, + #} + #- { + # name: "Ubuntu g++ bmi2", + # os: ubuntu-latest, + # compiler: g++-11, + # arch: bmi2, + # target: BlackCore-bmi2-linux, + #} - { name: "Windows g++ popcnt", os: windows-latest, diff --git a/src/Makefile b/src/Makefile index 522569f..3303477 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,7 +2,7 @@ CXX = g++ TARGET_FLAGS = -static -static-libgcc -static-libstdc++ ARCH=native NAME = BlackCore -VERSION_MAJOR = 2 +VERSION_MAJOR = 3 VERSION_MINOR = 0 OBJECT_DIR = objects SOURCES := $(wildcard *.cpp) @@ -14,7 +14,6 @@ else uname_S := $(shell uname -s) endif - ifeq ($(uname_S), Windows) SUFFIX = .exe else @@ -44,8 +43,8 @@ ifeq ($(ARCH), popcnt) ARCH_FLAGS = -march=x86-64 -mpopcnt endif -CXXFLAGS = -std=c++20 -O3 -flto -pthread -Wall -Wno-class-memaccess $(DEFINE_FLAGS) $(ARCH_FLAGS) -EXE = $(NAME)_v$(VERSION_MAJOR)-$(VERSION_MINOR)$(SUFFIX) +CXXFLAGS = -std=c++20 -O3 -flto -pthread -Wall -Wno-class-memaccess -DVERSION=\"v$(VERSION_MAJOR).$(VERSION_MINOR)\" $(DEFINE_FLAGS) $(ARCH_FLAGS) +EXE = $(NAME)-v$(VERSION_MAJOR)-$(VERSION_MINOR)$(SUFFIX) default: $(EXE) diff --git a/src/bench.cpp b/src/bench.cpp index eb956cc..08d05d9 100644 --- a/src/bench.cpp +++ b/src/bench.cpp @@ -14,14 +14,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include -#include -#include -#include #include "bench.h" -#include "tt.h" #include "search.h" #include "timeman.h" +#include "tt.h" +#include +#include +#include +#include struct TestPosition { std::string fen; @@ -31,25 +31,24 @@ struct TestPosition { const unsigned int posCount = 10; -const unsigned int searchTestHashSize = 16; +const unsigned int searchTestHashSize = 32; -const Depth SEARCH_DEPTH = 13; +const Depth SEARCH_DEPTH = 15; const TestPosition testPositions[posCount] = { // Positions from CPW - {"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 ", 6, 119060324}, - {"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - ", 5, 193690690}, - {"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -", 7, 178633661}, - {"r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 5, 15833292}, - {"r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1 ", 5, 15833292}, - {"rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8 ", 5, 89941194}, + {"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 ", 6, 119060324}, + {"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - ", 5, 193690690}, + {"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -", 7, 178633661}, + {"r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 5, 15833292}, + {"r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1 ", 5, 15833292}, + {"rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8 ", 5, 89941194}, {"r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10 ", 5, 164075551}, // Own positions - {"r3kb1r/1p3ppp/pqn1pn2/1Bpp1b2/3P1B2/1QP1PN2/PP1N1PPP/R3K2R w KQkq - 0 9", 5, 140824446}, - {"rnb1k2r/pppp1ppp/5q2/2b5/2BNP3/2N5/PPP2KPP/R1BQ3R w kq - 1 8", 5, 19782759}, - {"8/pp5p/8/2p2kp1/2Pp4/3P1KPP/PP6/8 w - - 0 32", 7, 13312960} -}; + {"r3kb1r/1p3ppp/pqn1pn2/1Bpp1b2/3P1B2/1QP1PN2/PP1N1PPP/R3K2R w KQkq - 0 9", 5, 140824446}, + {"rnb1k2r/pppp1ppp/5q2/2b5/2BNP3/2N5/PPP2KPP/R1BQ3R w kq - 1 8", 5, 19782759}, + {"8/pp5p/8/2p2kp1/2Pp4/3P1KPP/PP6/8 w - - 0 32", 7, 13312960}}; void testPerft() { initSearch(); @@ -71,7 +70,8 @@ void testPerft() { U64 nps = totalNodes * 1000 / elapsedTime; if (ok) { - std::cout << "PERFT OK\n" << totalNodes << " nodes " << nps << " nps" << std::endl; + std::cout << "PERFT OK\n" + << totalNodes << " nodes " << nps << " nps" << std::endl; } else { std::cout << "PERFT FAILED" << std::endl; exit(1); @@ -82,13 +82,20 @@ void testSearch() { initSearch(); ttResize(searchTestHashSize); - startSearch(0, 0, 0, 0); + U64 totalNodes = 0; + U64 nps; + for (const TestPosition &tPos : testPositions) { ttClear(); Position pos = {tPos.fen}; - std::atomic a; - iterativeDeepening(pos, SEARCH_DEPTH, false, std::ref(a)); + SearchInfo info; + info.maxDepth = SEARCH_DEPTH; + info.uciMode = false; + startSearch(info, pos, 1); + joinThread(true); + totalNodes += nodeCount; + nps += getNps(); } - std::cout << nodeCount << " nodes " << getNps() << " nps" << std::endl; + std::cout << totalNodes << " nodes " << nps / posCount << " nps" << std::endl; } diff --git a/src/bench.h b/src/bench.h index 3c5e280..a2be07b 100644 --- a/src/bench.h +++ b/src/bench.h @@ -20,11 +20,14 @@ #include "movegen.h" +#include + template U64 perft(Position &position, Depth depth) { Move moves[200]; Move *movesEnd = generateMoves(position, moves, false); - if (depth == 1) return movesEnd - moves; + if (depth == 1) + return movesEnd - moves; U64 nodes = 0; for (Move *it = moves; it != movesEnd; it++) { position.makeMove(*it); @@ -42,4 +45,4 @@ void testPerft(); void testSearch(); -#endif //BLACKCORE_BENCH_H +#endif//BLACKCORE_BENCH_H diff --git a/src/bitboard.cpp b/src/bitboard.cpp index ef3d805..fb5605a 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -14,13 +14,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include -#include #include "bitboard.h" #include "utils.h" +#include +#include -Bitboard bitMasks[64], pawnMasks[64][2], knightMasks[64], kingMasks[64], fileMasks[64], rankMasks[64], rookMasks[64], diagonalMasks[64], antiDiagonalMasks[64], bishopMasks[64], - rookAttackTable[102400], bishopAttackTable[5248], commonRay[64][64], adjacentFileMasks[64], adjacentNorthMasks[64], adjacentSouthMasks[64]; +Bitboard bitMasks[64], pawnMasks[64][2], knightMasks[64], kingMasks[64], fileMasks[64], rankMasks[64], rookMasks[64], + diagonalMasks[64], antiDiagonalMasks[64], bishopMasks[64], + rookAttackTable[102400], bishopAttackTable[5248], commonRay[64][64], adjacentFileMasks[64], adjacentNorthMasks[64], + adjacentSouthMasks[64]; LineType lineType[64][64]; void initBitboard() { @@ -67,7 +69,8 @@ void initBitboard() { ~fileMask(sq) & (adjacentNorthMasks[sq] | adjacentSouthMasks[sq] | step(sq) | step(sq)); for (Square sq2 = A1; sq2 < 64; sq2 += 1) { - if (sq == sq2) continue; + if (sq == sq2) + continue; for (Direction dir : DIRECTIONS) { Bitboard value = slide(dir, sq) & slide(-dir, sq2); @@ -101,7 +104,6 @@ void initBitboard() { initMagic(rookMagics, ROOK); initMagic(bishopMagics, BISHOP); - } Bitboard slidingAttacks(Square square, Bitboard occupied, PieceType type) { @@ -160,8 +162,10 @@ void findMagics(Bitboard *attackTable, Magic *magics, PieceType type) { magic.mask = slidingAttacks(square, 0, type) & ~edge; magic.shift = magic.mask.popCount(); - if (square == A1) magic.ptr = attackTable; - else magic.ptr = magics[square - 1].ptr + length; + if (square == A1) + magic.ptr = attackTable; + else + magic.ptr = magics[square - 1].ptr + length; // Carry-Ripler trick for reference check out: https://www.chessprogramming.org/Traversing_Subsets_of_a_Set length = 0; @@ -178,7 +182,8 @@ void findMagics(Bitboard *attackTable, Magic *magics, PieceType type) { while (true) { magic.magic = randBB() & randBB() & randBB(); - if (((magic.magic * magic.mask) >> 56).popCount() < 6) continue; + if (((magic.magic * magic.mask) >> 56).popCount() < 6) + continue; std::memset(used, 0, sizeof(used)); @@ -204,7 +209,6 @@ void findMagics(Bitboard *attackTable, Magic *magics, PieceType type) { std::cout << " {bishopAttackTable + " << magic.ptr - bishopAttackTable << ", " << BBToHex(magic.mask) << ", " << BBToHex(magic.magic) << ", " << magic.shift << "},\n"; - } std::cout << "};\n"; diff --git a/src/bitboard.h b/src/bitboard.h index 7f963c9..31f7cc1 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -17,9 +17,9 @@ #ifndef BLACKCORE_BITBOARD_H #define BLACKCORE_BITBOARD_H +#include "constants.h" #include #include -#include "constants.h" #ifdef _MSC_VER #include @@ -30,26 +30,33 @@ struct Bitboard { U64 bb = 0; - constexpr Bitboard(U64 value) { bb = value; } + constexpr Bitboard(U64 value) { + bb = value; + } inline Bitboard(Square square); constexpr Bitboard() = default; - constexpr bool get(Square square) const { return (bb >> square) & 1; } + constexpr bool get(Square square) const { + return (bb >> square) & 1; + } - constexpr void set(Square square) { bb |= 1ULL << square; } + constexpr void set(Square square) { + bb |= 1ULL << square; + } - constexpr void clear(Square square) { bb &= ~(1ULL << square); } + constexpr void clear(Square square) { + bb &= ~(1ULL << square); + } constexpr int popCount() const { #if defined(_MSC_VER) || defined(__INTEL_COMPILER) - return (int)_mm_popcnt_u64(bb); + return (int) _mm_popcnt_u64(bb); #else return __builtin_popcountll(bb); #endif - } constexpr Square lsb() const { @@ -63,7 +70,6 @@ struct Bitboard { #else #error "Unsupported compiler!" #endif - } constexpr Square popLsb() { @@ -72,41 +78,77 @@ struct Bitboard { return square; } - constexpr Bitboard operator*(Bitboard a) const { return bb * a.bb; } + constexpr Bitboard operator*(Bitboard a) const { + return bb * a.bb; + } - constexpr bool operator==(Bitboard a) const { return bb == a.bb; } + constexpr bool operator==(Bitboard a) const { + return bb == a.bb; + } - constexpr bool operator!=(Bitboard a) const { return bb != a.bb; } + constexpr bool operator!=(Bitboard a) const { + return bb != a.bb; + } - constexpr Bitboard operator+(Bitboard a) const { return bb + a.bb; } + constexpr Bitboard operator+(Bitboard a) const { + return bb + a.bb; + } - constexpr Bitboard operator-(Bitboard a) const { return bb - a.bb; } + constexpr Bitboard operator-(Bitboard a) const { + return bb - a.bb; + } - constexpr Bitboard operator&(Bitboard a) const { return bb & a.bb; } + constexpr Bitboard operator&(Bitboard a) const { + return bb & a.bb; + } - constexpr Bitboard operator|(Bitboard a) const { return bb | a.bb; } + constexpr Bitboard operator|(Bitboard a) const { + return bb | a.bb; + } - constexpr Bitboard operator^(Bitboard a) const { return bb ^ a.bb; } + constexpr Bitboard operator^(Bitboard a) const { + return bb ^ a.bb; + } - constexpr Bitboard operator~() const { return ~bb; } + constexpr Bitboard operator~() const { + return ~bb; + } - constexpr Bitboard operator<<(const unsigned int a) const { return bb << a; } + constexpr Bitboard operator<<(const unsigned int a) const { + return bb << a; + } - constexpr Bitboard operator>>(const unsigned int a) const { return bb >> a; } + constexpr Bitboard operator>>(const unsigned int a) const { + return bb >> a; + } - constexpr void operator&=(Bitboard a) { bb &= a.bb; } + constexpr void operator&=(Bitboard a) { + bb &= a.bb; + } - constexpr void operator|=(Bitboard a) { bb |= a.bb; } + constexpr void operator|=(Bitboard a) { + bb |= a.bb; + } - constexpr void operator^=(Bitboard a) { bb ^= a.bb; } + constexpr void operator^=(Bitboard a) { + bb ^= a.bb; + } - constexpr void operator<<=(const unsigned int a) { bb <<= a; } + constexpr void operator<<=(const unsigned int a) { + bb <<= a; + } - constexpr void operator>>=(const unsigned int a) { bb >>= a; } + constexpr void operator>>=(const unsigned int a) { + bb >>= a; + } - constexpr explicit operator bool() const { return bb; } + constexpr explicit operator bool() const { + return bb; + } - constexpr explicit operator U64() const { return bb; } + constexpr explicit operator U64() const { + return bb; + } }; struct Magic { @@ -123,137 +165,137 @@ extern Bitboard bishopAttackTable[5248]; // To generate the attackTables from them use initMagic // To generate new magic numbers use findMagics constexpr Magic rookMagics[64] = { - {rookAttackTable + 0, 0x101010101017eULL, 0x200102084420100ULL, 12}, - {rookAttackTable + 4096, 0x202020202027cULL, 0x40200040001000ULL, 11}, - {rookAttackTable + 6144, 0x404040404047aULL, 0x4100082000104300ULL, 11}, - {rookAttackTable + 8192, 0x8080808080876ULL, 0x480049000080080ULL, 11}, - {rookAttackTable + 10240, 0x1010101010106eULL, 0x100040211000800ULL, 11}, - {rookAttackTable + 12288, 0x2020202020205eULL, 0x2500240002080100ULL, 11}, - {rookAttackTable + 14336, 0x4040404040403eULL, 0x280120001000080ULL, 11}, - {rookAttackTable + 16384, 0x8080808080807eULL, 0x200004086002b04ULL, 12}, - {rookAttackTable + 20480, 0x1010101017e00ULL, 0x401800280400020ULL, 11}, - {rookAttackTable + 22528, 0x2020202027c00ULL, 0x8601400050002000ULL, 10}, - {rookAttackTable + 23552, 0x4040404047a00ULL, 0x802801000200280ULL, 10}, - {rookAttackTable + 24576, 0x8080808087600ULL, 0x411001001002008ULL, 10}, - {rookAttackTable + 25600, 0x10101010106e00ULL, 0x11000410080300ULL, 10}, - {rookAttackTable + 26624, 0x20202020205e00ULL, 0x20a000804108200ULL, 10}, - {rookAttackTable + 27648, 0x40404040403e00ULL, 0x84006850240102ULL, 10}, - {rookAttackTable + 28672, 0x80808080807e00ULL, 0x24800049000080ULL, 11}, - {rookAttackTable + 30720, 0x10101017e0100ULL, 0x208000400080ULL, 11}, - {rookAttackTable + 32768, 0x20202027c0200ULL, 0x101020020804202ULL, 10}, - {rookAttackTable + 33792, 0x40404047a0400ULL, 0x20828010022000ULL, 10}, - {rookAttackTable + 34816, 0x8080808760800ULL, 0x801230009001000ULL, 10}, - {rookAttackTable + 35840, 0x101010106e1000ULL, 0x5608808004020801ULL, 10}, - {rookAttackTable + 36864, 0x202020205e2000ULL, 0x3086008080040002ULL, 10}, - {rookAttackTable + 37888, 0x404040403e4000ULL, 0x40041221008ULL, 10}, - {rookAttackTable + 38912, 0x808080807e8000ULL, 0x8000020000811044ULL, 11}, - {rookAttackTable + 40960, 0x101017e010100ULL, 0x21c00180002081ULL, 11}, - {rookAttackTable + 43008, 0x202027c020200ULL, 0xa010024140002000ULL, 10}, - {rookAttackTable + 44032, 0x404047a040400ULL, 0x1040200280100080ULL, 10}, - {rookAttackTable + 45056, 0x8080876080800ULL, 0x2100100200b00ULL, 10}, - {rookAttackTable + 46080, 0x1010106e101000ULL, 0x8014008080040800ULL, 10}, - {rookAttackTable + 47104, 0x2020205e202000ULL, 0x840200120008904cULL, 10}, - {rookAttackTable + 48128, 0x4040403e404000ULL, 0x10020400811058ULL, 10}, - {rookAttackTable + 49152, 0x8080807e808000ULL, 0x8280040200004081ULL, 11}, - {rookAttackTable + 51200, 0x1017e01010100ULL, 0xa000408001002100ULL, 11}, - {rookAttackTable + 53248, 0x2027c02020200ULL, 0x210904000802000ULL, 10}, - {rookAttackTable + 54272, 0x4047a04040400ULL, 0x200204082001200ULL, 10}, - {rookAttackTable + 55296, 0x8087608080800ULL, 0x2204201042000a00ULL, 10}, - {rookAttackTable + 56320, 0x10106e10101000ULL, 0x6c80040801001100ULL, 10}, - {rookAttackTable + 57344, 0x20205e20202000ULL, 0x8040080800200ULL, 10}, - {rookAttackTable + 58368, 0x40403e40404000ULL, 0x2b0900804001663ULL, 10}, - {rookAttackTable + 59392, 0x80807e80808000ULL, 0x4074800040800100ULL, 11}, - {rookAttackTable + 61440, 0x17e0101010100ULL, 0x4000400080208000ULL, 11}, - {rookAttackTable + 63488, 0x27c0202020200ULL, 0x1a40500020004001ULL, 10}, - {rookAttackTable + 64512, 0x47a0404040400ULL, 0x1004020010018ULL, 10}, - {rookAttackTable + 65536, 0x8760808080800ULL, 0x20201200420008ULL, 10}, - {rookAttackTable + 66560, 0x106e1010101000ULL, 0xc24008008008005ULL, 10}, - {rookAttackTable + 67584, 0x205e2020202000ULL, 0x4002010804020010ULL, 10}, - {rookAttackTable + 68608, 0x403e4040404000ULL, 0xb015081002040001ULL, 10}, - {rookAttackTable + 69632, 0x807e8080808000ULL, 0x4000408c020029ULL, 11}, - {rookAttackTable + 71680, 0x7e010101010100ULL, 0xb840004020800080ULL, 11}, - {rookAttackTable + 73728, 0x7c020202020200ULL, 0x60804001002100ULL, 10}, - {rookAttackTable + 74752, 0x7a040404040400ULL, 0x210810a285420200ULL, 10}, - {rookAttackTable + 75776, 0x76080808080800ULL, 0xa000080010008080ULL, 10}, - {rookAttackTable + 76800, 0x6e101010101000ULL, 0x800050010080100ULL, 10}, - {rookAttackTable + 77824, 0x5e202020202000ULL, 0x4040002008080ULL, 10}, - {rookAttackTable + 78848, 0x3e404040404000ULL, 0x80b4011042080400ULL, 10}, - {rookAttackTable + 79872, 0x7e808080808000ULL, 0x6014004114008200ULL, 11}, + {rookAttackTable + 0, 0x101010101017eULL, 0x200102084420100ULL, 12}, + {rookAttackTable + 4096, 0x202020202027cULL, 0x40200040001000ULL, 11}, + {rookAttackTable + 6144, 0x404040404047aULL, 0x4100082000104300ULL, 11}, + {rookAttackTable + 8192, 0x8080808080876ULL, 0x480049000080080ULL, 11}, + {rookAttackTable + 10240, 0x1010101010106eULL, 0x100040211000800ULL, 11}, + {rookAttackTable + 12288, 0x2020202020205eULL, 0x2500240002080100ULL, 11}, + {rookAttackTable + 14336, 0x4040404040403eULL, 0x280120001000080ULL, 11}, + {rookAttackTable + 16384, 0x8080808080807eULL, 0x200004086002b04ULL, 12}, + {rookAttackTable + 20480, 0x1010101017e00ULL, 0x401800280400020ULL, 11}, + {rookAttackTable + 22528, 0x2020202027c00ULL, 0x8601400050002000ULL, 10}, + {rookAttackTable + 23552, 0x4040404047a00ULL, 0x802801000200280ULL, 10}, + {rookAttackTable + 24576, 0x8080808087600ULL, 0x411001001002008ULL, 10}, + {rookAttackTable + 25600, 0x10101010106e00ULL, 0x11000410080300ULL, 10}, + {rookAttackTable + 26624, 0x20202020205e00ULL, 0x20a000804108200ULL, 10}, + {rookAttackTable + 27648, 0x40404040403e00ULL, 0x84006850240102ULL, 10}, + {rookAttackTable + 28672, 0x80808080807e00ULL, 0x24800049000080ULL, 11}, + {rookAttackTable + 30720, 0x10101017e0100ULL, 0x208000400080ULL, 11}, + {rookAttackTable + 32768, 0x20202027c0200ULL, 0x101020020804202ULL, 10}, + {rookAttackTable + 33792, 0x40404047a0400ULL, 0x20828010022000ULL, 10}, + {rookAttackTable + 34816, 0x8080808760800ULL, 0x801230009001000ULL, 10}, + {rookAttackTable + 35840, 0x101010106e1000ULL, 0x5608808004020801ULL, 10}, + {rookAttackTable + 36864, 0x202020205e2000ULL, 0x3086008080040002ULL, 10}, + {rookAttackTable + 37888, 0x404040403e4000ULL, 0x40041221008ULL, 10}, + {rookAttackTable + 38912, 0x808080807e8000ULL, 0x8000020000811044ULL, 11}, + {rookAttackTable + 40960, 0x101017e010100ULL, 0x21c00180002081ULL, 11}, + {rookAttackTable + 43008, 0x202027c020200ULL, 0xa010024140002000ULL, 10}, + {rookAttackTable + 44032, 0x404047a040400ULL, 0x1040200280100080ULL, 10}, + {rookAttackTable + 45056, 0x8080876080800ULL, 0x2100100200b00ULL, 10}, + {rookAttackTable + 46080, 0x1010106e101000ULL, 0x8014008080040800ULL, 10}, + {rookAttackTable + 47104, 0x2020205e202000ULL, 0x840200120008904cULL, 10}, + {rookAttackTable + 48128, 0x4040403e404000ULL, 0x10020400811058ULL, 10}, + {rookAttackTable + 49152, 0x8080807e808000ULL, 0x8280040200004081ULL, 11}, + {rookAttackTable + 51200, 0x1017e01010100ULL, 0xa000408001002100ULL, 11}, + {rookAttackTable + 53248, 0x2027c02020200ULL, 0x210904000802000ULL, 10}, + {rookAttackTable + 54272, 0x4047a04040400ULL, 0x200204082001200ULL, 10}, + {rookAttackTable + 55296, 0x8087608080800ULL, 0x2204201042000a00ULL, 10}, + {rookAttackTable + 56320, 0x10106e10101000ULL, 0x6c80040801001100ULL, 10}, + {rookAttackTable + 57344, 0x20205e20202000ULL, 0x8040080800200ULL, 10}, + {rookAttackTable + 58368, 0x40403e40404000ULL, 0x2b0900804001663ULL, 10}, + {rookAttackTable + 59392, 0x80807e80808000ULL, 0x4074800040800100ULL, 11}, + {rookAttackTable + 61440, 0x17e0101010100ULL, 0x4000400080208000ULL, 11}, + {rookAttackTable + 63488, 0x27c0202020200ULL, 0x1a40500020004001ULL, 10}, + {rookAttackTable + 64512, 0x47a0404040400ULL, 0x1004020010018ULL, 10}, + {rookAttackTable + 65536, 0x8760808080800ULL, 0x20201200420008ULL, 10}, + {rookAttackTable + 66560, 0x106e1010101000ULL, 0xc24008008008005ULL, 10}, + {rookAttackTable + 67584, 0x205e2020202000ULL, 0x4002010804020010ULL, 10}, + {rookAttackTable + 68608, 0x403e4040404000ULL, 0xb015081002040001ULL, 10}, + {rookAttackTable + 69632, 0x807e8080808000ULL, 0x4000408c020029ULL, 11}, + {rookAttackTable + 71680, 0x7e010101010100ULL, 0xb840004020800080ULL, 11}, + {rookAttackTable + 73728, 0x7c020202020200ULL, 0x60804001002100ULL, 10}, + {rookAttackTable + 74752, 0x7a040404040400ULL, 0x210810a285420200ULL, 10}, + {rookAttackTable + 75776, 0x76080808080800ULL, 0xa000080010008080ULL, 10}, + {rookAttackTable + 76800, 0x6e101010101000ULL, 0x800050010080100ULL, 10}, + {rookAttackTable + 77824, 0x5e202020202000ULL, 0x4040002008080ULL, 10}, + {rookAttackTable + 78848, 0x3e404040404000ULL, 0x80b4011042080400ULL, 10}, + {rookAttackTable + 79872, 0x7e808080808000ULL, 0x6014004114008200ULL, 11}, {rookAttackTable + 81920, 0x7e01010101010100ULL, 0x1001002018408202ULL, 12}, - {rookAttackTable + 86016, 0x7c02020202020200ULL, 0x2400104128421ULL, 11}, - {rookAttackTable + 88064, 0x7a04040404040400ULL, 0x407600010408901ULL, 11}, + {rookAttackTable + 86016, 0x7c02020202020200ULL, 0x2400104128421ULL, 11}, + {rookAttackTable + 88064, 0x7a04040404040400ULL, 0x407600010408901ULL, 11}, {rookAttackTable + 90112, 0x7608080808080800ULL, 0x108448a01001000dULL, 11}, {rookAttackTable + 92160, 0x6e10101010101000ULL, 0x8402011008842002ULL, 11}, - {rookAttackTable + 94208, 0x5e20202020202000ULL, 0x11000204000801ULL, 11}, + {rookAttackTable + 94208, 0x5e20202020202000ULL, 0x11000204000801ULL, 11}, {rookAttackTable + 96256, 0x3e40404040404000ULL, 0x4026000108208452ULL, 11}, - {rookAttackTable + 98304, 0x7e80808080808000ULL, 0x800081004c2c06ULL, 12}, + {rookAttackTable + 98304, 0x7e80808080808000ULL, 0x800081004c2c06ULL, 12}, }; constexpr Magic bishopMagics[64] = { - {bishopAttackTable + 0, 0x40201008040200ULL, 0x4100216240212ULL, 6}, - {bishopAttackTable + 64, 0x402010080400ULL, 0x8080110420002ULL, 5}, - {bishopAttackTable + 96, 0x4020100a00ULL, 0x4280091000005ULL, 5}, - {bishopAttackTable + 128, 0x40221400ULL, 0x24410020801400ULL, 5}, - {bishopAttackTable + 160, 0x2442800ULL, 0x4242000000311ULL, 5}, - {bishopAttackTable + 192, 0x204085000ULL, 0x882021006148000ULL, 5}, - {bishopAttackTable + 224, 0x20408102000ULL, 0xb440a0210260800ULL, 5}, - {bishopAttackTable + 256, 0x2040810204000ULL, 0x80840c0a011c00ULL, 6}, - {bishopAttackTable + 320, 0x20100804020000ULL, 0x1000040488080100ULL, 5}, - {bishopAttackTable + 352, 0x40201008040000ULL, 0x800a200202284112ULL, 5}, - {bishopAttackTable + 384, 0x4020100a0000ULL, 0xcc00098401020000ULL, 5}, - {bishopAttackTable + 416, 0x4022140000ULL, 0x8000080a00202000ULL, 5}, - {bishopAttackTable + 448, 0x244280000ULL, 0x8821210000824ULL, 5}, - {bishopAttackTable + 480, 0x20408500000ULL, 0xc000088230400020ULL, 5}, - {bishopAttackTable + 512, 0x2040810200000ULL, 0x2904494808a41024ULL, 5}, - {bishopAttackTable + 544, 0x4081020400000ULL, 0x2302882301004ULL, 5}, - {bishopAttackTable + 576, 0x10080402000200ULL, 0x910200610100104ULL, 5}, - {bishopAttackTable + 608, 0x20100804000400ULL, 0x910800850008080ULL, 5}, - {bishopAttackTable + 640, 0x4020100a000a00ULL, 0x30080010004d4009ULL, 7}, - {bishopAttackTable + 768, 0x402214001400ULL, 0x4108000c20222001ULL, 7}, - {bishopAttackTable + 896, 0x24428002800ULL, 0x22000400942005ULL, 7}, - {bishopAttackTable + 1024, 0x2040850005000ULL, 0xa021100512400ULL, 7}, - {bishopAttackTable + 1152, 0x4081020002000ULL, 0xa001000041301024ULL, 5}, - {bishopAttackTable + 1184, 0x8102040004000ULL, 0x8000420206021981ULL, 5}, - {bishopAttackTable + 1216, 0x8040200020400ULL, 0x1008480004606800ULL, 5}, - {bishopAttackTable + 1248, 0x10080400040800ULL, 0x4a8280003100100ULL, 5}, - {bishopAttackTable + 1280, 0x20100a000a1000ULL, 0x3480010182240ULL, 7}, + {bishopAttackTable + 0, 0x40201008040200ULL, 0x4100216240212ULL, 6}, + {bishopAttackTable + 64, 0x402010080400ULL, 0x8080110420002ULL, 5}, + {bishopAttackTable + 96, 0x4020100a00ULL, 0x4280091000005ULL, 5}, + {bishopAttackTable + 128, 0x40221400ULL, 0x24410020801400ULL, 5}, + {bishopAttackTable + 160, 0x2442800ULL, 0x4242000000311ULL, 5}, + {bishopAttackTable + 192, 0x204085000ULL, 0x882021006148000ULL, 5}, + {bishopAttackTable + 224, 0x20408102000ULL, 0xb440a0210260800ULL, 5}, + {bishopAttackTable + 256, 0x2040810204000ULL, 0x80840c0a011c00ULL, 6}, + {bishopAttackTable + 320, 0x20100804020000ULL, 0x1000040488080100ULL, 5}, + {bishopAttackTable + 352, 0x40201008040000ULL, 0x800a200202284112ULL, 5}, + {bishopAttackTable + 384, 0x4020100a0000ULL, 0xcc00098401020000ULL, 5}, + {bishopAttackTable + 416, 0x4022140000ULL, 0x8000080a00202000ULL, 5}, + {bishopAttackTable + 448, 0x244280000ULL, 0x8821210000824ULL, 5}, + {bishopAttackTable + 480, 0x20408500000ULL, 0xc000088230400020ULL, 5}, + {bishopAttackTable + 512, 0x2040810200000ULL, 0x2904494808a41024ULL, 5}, + {bishopAttackTable + 544, 0x4081020400000ULL, 0x2302882301004ULL, 5}, + {bishopAttackTable + 576, 0x10080402000200ULL, 0x910200610100104ULL, 5}, + {bishopAttackTable + 608, 0x20100804000400ULL, 0x910800850008080ULL, 5}, + {bishopAttackTable + 640, 0x4020100a000a00ULL, 0x30080010004d4009ULL, 7}, + {bishopAttackTable + 768, 0x402214001400ULL, 0x4108000c20222001ULL, 7}, + {bishopAttackTable + 896, 0x24428002800ULL, 0x22000400942005ULL, 7}, + {bishopAttackTable + 1024, 0x2040850005000ULL, 0xa021100512400ULL, 7}, + {bishopAttackTable + 1152, 0x4081020002000ULL, 0xa001000041301024ULL, 5}, + {bishopAttackTable + 1184, 0x8102040004000ULL, 0x8000420206021981ULL, 5}, + {bishopAttackTable + 1216, 0x8040200020400ULL, 0x1008480004606800ULL, 5}, + {bishopAttackTable + 1248, 0x10080400040800ULL, 0x4a8280003100100ULL, 5}, + {bishopAttackTable + 1280, 0x20100a000a1000ULL, 0x3480010182240ULL, 7}, {bishopAttackTable + 1408, 0x40221400142200ULL, 0x2048080102820042ULL, 9}, - {bishopAttackTable + 1920, 0x2442800284400ULL, 0x4001020004008400ULL, 9}, - {bishopAttackTable + 2432, 0x4085000500800ULL, 0x204004048080200ULL, 7}, - {bishopAttackTable + 2560, 0x8102000201000ULL, 0x2008200040212a0ULL, 5}, - {bishopAttackTable + 2592, 0x10204000402000ULL, 0x10c013002430400ULL, 5}, - {bishopAttackTable + 2624, 0x4020002040800ULL, 0x4300a5082214480ULL, 5}, - {bishopAttackTable + 2656, 0x8040004081000ULL, 0x401041000215900ULL, 5}, - {bishopAttackTable + 2688, 0x100a000a102000ULL, 0x104804048040408ULL, 7}, - {bishopAttackTable + 2816, 0x22140014224000ULL, 0x800400808208200ULL, 9}, - {bishopAttackTable + 3328, 0x44280028440200ULL, 0x8002400054101ULL, 9}, - {bishopAttackTable + 3840, 0x8500050080400ULL, 0x2001004502020102ULL, 7}, + {bishopAttackTable + 1920, 0x2442800284400ULL, 0x4001020004008400ULL, 9}, + {bishopAttackTable + 2432, 0x4085000500800ULL, 0x204004048080200ULL, 7}, + {bishopAttackTable + 2560, 0x8102000201000ULL, 0x2008200040212a0ULL, 5}, + {bishopAttackTable + 2592, 0x10204000402000ULL, 0x10c013002430400ULL, 5}, + {bishopAttackTable + 2624, 0x4020002040800ULL, 0x4300a5082214480ULL, 5}, + {bishopAttackTable + 2656, 0x8040004081000ULL, 0x401041000215900ULL, 5}, + {bishopAttackTable + 2688, 0x100a000a102000ULL, 0x104804048040408ULL, 7}, + {bishopAttackTable + 2816, 0x22140014224000ULL, 0x800400808208200ULL, 9}, + {bishopAttackTable + 3328, 0x44280028440200ULL, 0x8002400054101ULL, 9}, + {bishopAttackTable + 3840, 0x8500050080400ULL, 0x2001004502020102ULL, 7}, {bishopAttackTable + 3968, 0x10200020100800ULL, 0x1988080110006100ULL, 5}, {bishopAttackTable + 4000, 0x20400040201000ULL, 0x1282009200102201ULL, 5}, - {bishopAttackTable + 4032, 0x2000204081000ULL, 0xa208010420001280ULL, 5}, - {bishopAttackTable + 4064, 0x4000408102000ULL, 0x4004010809000200ULL, 5}, - {bishopAttackTable + 4096, 0xa000a10204000ULL, 0x43008150006100ULL, 7}, - {bishopAttackTable + 4224, 0x14001422400000ULL, 0x2410145000801ULL, 7}, - {bishopAttackTable + 4352, 0x28002844020000ULL, 0x280104006040ULL, 7}, - {bishopAttackTable + 4480, 0x50005008040200ULL, 0x4012042000902ULL, 7}, - {bishopAttackTable + 4608, 0x20002010080400ULL, 0x28100482080a82ULL, 5}, + {bishopAttackTable + 4032, 0x2000204081000ULL, 0xa208010420001280ULL, 5}, + {bishopAttackTable + 4064, 0x4000408102000ULL, 0x4004010809000200ULL, 5}, + {bishopAttackTable + 4096, 0xa000a10204000ULL, 0x43008150006100ULL, 7}, + {bishopAttackTable + 4224, 0x14001422400000ULL, 0x2410145000801ULL, 7}, + {bishopAttackTable + 4352, 0x28002844020000ULL, 0x280104006040ULL, 7}, + {bishopAttackTable + 4480, 0x50005008040200ULL, 0x4012042000902ULL, 7}, + {bishopAttackTable + 4608, 0x20002010080400ULL, 0x28100482080a82ULL, 5}, {bishopAttackTable + 4640, 0x40004020100800ULL, 0x80040c2400240240ULL, 5}, - {bishopAttackTable + 4672, 0x20408102000ULL, 0x80c1101101044a0ULL, 5}, - {bishopAttackTable + 4704, 0x40810204000ULL, 0x180804802310808ULL, 5}, - {bishopAttackTable + 4736, 0xa1020400000ULL, 0x8048080064ULL, 5}, - {bishopAttackTable + 4768, 0x142240000000ULL, 0x8c8400020880000ULL, 5}, - {bishopAttackTable + 4800, 0x284402000000ULL, 0x30001010020a2000ULL, 5}, - {bishopAttackTable + 4832, 0x500804020000ULL, 0x80600282220010ULL, 5}, - {bishopAttackTable + 4864, 0x201008040200ULL, 0x120228228010000ULL, 5}, - {bishopAttackTable + 4896, 0x402010080400ULL, 0xc08020802042300ULL, 5}, - {bishopAttackTable + 4928, 0x2040810204000ULL, 0x2a008048221000ULL, 6}, - {bishopAttackTable + 4992, 0x4081020400000ULL, 0x4601204100901002ULL, 5}, - {bishopAttackTable + 5024, 0xa102040000000ULL, 0x821200104052400ULL, 5}, - {bishopAttackTable + 5056, 0x14224000000000ULL, 0x8200084208810ULL, 5}, + {bishopAttackTable + 4672, 0x20408102000ULL, 0x80c1101101044a0ULL, 5}, + {bishopAttackTable + 4704, 0x40810204000ULL, 0x180804802310808ULL, 5}, + {bishopAttackTable + 4736, 0xa1020400000ULL, 0x8048080064ULL, 5}, + {bishopAttackTable + 4768, 0x142240000000ULL, 0x8c8400020880000ULL, 5}, + {bishopAttackTable + 4800, 0x284402000000ULL, 0x30001010020a2000ULL, 5}, + {bishopAttackTable + 4832, 0x500804020000ULL, 0x80600282220010ULL, 5}, + {bishopAttackTable + 4864, 0x201008040200ULL, 0x120228228010000ULL, 5}, + {bishopAttackTable + 4896, 0x402010080400ULL, 0xc08020802042300ULL, 5}, + {bishopAttackTable + 4928, 0x2040810204000ULL, 0x2a008048221000ULL, 6}, + {bishopAttackTable + 4992, 0x4081020400000ULL, 0x4601204100901002ULL, 5}, + {bishopAttackTable + 5024, 0xa102040000000ULL, 0x821200104052400ULL, 5}, + {bishopAttackTable + 5056, 0x14224000000000ULL, 0x8200084208810ULL, 5}, {bishopAttackTable + 5088, 0x28440200000000ULL, 0x8c022040a80b0408ULL, 5}, {bishopAttackTable + 5120, 0x50080402000000ULL, 0x2140201012100512ULL, 5}, - {bishopAttackTable + 5152, 0x20100804020000ULL, 0x10210240128120aULL, 5}, - {bishopAttackTable + 5184, 0x40201008040200ULL, 0x208600082060020ULL, 6}, + {bishopAttackTable + 5152, 0x20100804020000ULL, 0x10210240128120aULL, 5}, + {bishopAttackTable + 5184, 0x40201008040200ULL, 0x208600082060020ULL, 6}, }; constexpr Bitboard fileA = 0x101010101010101ULL; @@ -307,31 +349,57 @@ extern LineType lineType[64][64]; void initBitboard(); -inline Bitboard::Bitboard(Square square) { bb = bitMasks[square].bb; } +inline Bitboard::Bitboard(Square square) { + bb = bitMasks[square].bb; +} -inline Bitboard adjacentFileMask(Square square) { return adjacentFileMasks[square]; } +inline Bitboard adjacentFileMask(Square square) { + return adjacentFileMasks[square]; +} -inline Bitboard adjacentNorthMask(Square square) { return adjacentNorthMasks[square]; } +inline Bitboard adjacentNorthMask(Square square) { + return adjacentNorthMasks[square]; +} -inline Bitboard adjacentSouthMask(Square square) { return adjacentSouthMasks[square]; } +inline Bitboard adjacentSouthMask(Square square) { + return adjacentSouthMasks[square]; +} -inline Bitboard pawnMask(Square square, Color color) { return pawnMasks[square][color]; } +inline Bitboard pawnMask(Square square, Color color) { + return pawnMasks[square][color]; +} -inline Bitboard knightMask(Square square) { return knightMasks[square]; } +inline Bitboard knightMask(Square square) { + return knightMasks[square]; +} -inline Bitboard kingMask(Square square) { return kingMasks[square]; } +inline Bitboard kingMask(Square square) { + return kingMasks[square]; +} -inline Bitboard fileMask(Square square) { return fileMasks[square]; } +inline Bitboard fileMask(Square square) { + return fileMasks[square]; +} -inline Bitboard rankMask(Square square) { return rankMasks[square]; } +inline Bitboard rankMask(Square square) { + return rankMasks[square]; +} -inline Bitboard rookMask(Square square) { return rookMasks[square]; } +inline Bitboard rookMask(Square square) { + return rookMasks[square]; +} -inline Bitboard diagonalMask(Square square) { return diagonalMasks[square]; } +inline Bitboard diagonalMask(Square square) { + return diagonalMasks[square]; +} -inline Bitboard antiDiagonalMask(Square square) { return antiDiagonalMasks[square]; } +inline Bitboard antiDiagonalMask(Square square) { + return antiDiagonalMasks[square]; +} -inline Bitboard bishopMask(Square square) { return bishopMasks[square]; } +inline Bitboard bishopMask(Square square) { + return bishopMasks[square]; +} inline unsigned int getMagicIndex(const Magic &m, Bitboard occ) { #ifdef BMI2 @@ -494,4 +562,4 @@ void initMagic(const Magic *magics, PieceType type); void findMagics(Bitboard *attackTable, Magic *magics, PieceType type); -#endif //BLACKCORE_BITBOARD_H +#endif//BLACKCORE_BITBOARD_H diff --git a/src/constants.h b/src/constants.h index 11f6488..397647a 100644 --- a/src/constants.h +++ b/src/constants.h @@ -29,7 +29,6 @@ #define AVX2 #endif - typedef uint64_t U64; typedef int32_t Score; typedef int32_t Depth; @@ -41,19 +40,77 @@ constexpr Score MATE_VALUE = 100000; constexpr Score WORST_MATE = MATE_VALUE - 100; constexpr Score DRAW_VALUE = 0; +const Ply MAX_PLY = 100; + const std::string STARTING_FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; constexpr unsigned int RANDOM_SEED = 1254383; enum Square : int { - A1 = 0, B1 = 1, C1 = 2, D1 = 3, E1 = 4, F1 = 5, G1 = 6, H1 = 7, - A2 = 8, B2 = 9, C2 = 10, D2 = 11, E2 = 12, F2 = 13, G2 = 14, H2 = 15, - A3 = 16, B3 = 17, C3 = 18, D3 = 19, E3 = 20, F3 = 21, G3 = 22, H3 = 23, - A4 = 24, B4 = 25, C4 = 26, D4 = 27, E4 = 28, F4 = 29, G4 = 30, H4 = 31, - A5 = 32, B5 = 33, C5 = 34, D5 = 35, E5 = 36, F5 = 37, G5 = 38, H5 = 39, - A6 = 40, B6 = 41, C6 = 42, D6 = 43, E6 = 44, F6 = 45, G6 = 46, H6 = 47, - A7 = 48, B7 = 49, C7 = 50, D7 = 51, E7 = 52, F7 = 53, G7 = 54, H7 = 55, - A8 = 56, B8 = 57, C8 = 58, D8 = 59, E8 = 60, F8 = 61, G8 = 62, H8 = 63, + A1 = 0, + B1 = 1, + C1 = 2, + D1 = 3, + E1 = 4, + F1 = 5, + G1 = 6, + H1 = 7, + A2 = 8, + B2 = 9, + C2 = 10, + D2 = 11, + E2 = 12, + F2 = 13, + G2 = 14, + H2 = 15, + A3 = 16, + B3 = 17, + C3 = 18, + D3 = 19, + E3 = 20, + F3 = 21, + G3 = 22, + H3 = 23, + A4 = 24, + B4 = 25, + C4 = 26, + D4 = 27, + E4 = 28, + F4 = 29, + G4 = 30, + H4 = 31, + A5 = 32, + B5 = 33, + C5 = 34, + D5 = 35, + E5 = 36, + F5 = 37, + G5 = 38, + H5 = 39, + A6 = 40, + B6 = 41, + C6 = 42, + D6 = 43, + E6 = 44, + F6 = 45, + G6 = 46, + H6 = 47, + A7 = 48, + B7 = 49, + C7 = 50, + D7 = 51, + E7 = 52, + F7 = 53, + G7 = 54, + H7 = 55, + A8 = 56, + B8 = 57, + C8 = 58, + D8 = 59, + E8 = 60, + F8 = 61, + G8 = 62, + H8 = 63, NULL_SQUARE = 64 }; @@ -62,13 +119,21 @@ constexpr unsigned char WQ_MASK = 2; constexpr unsigned char BK_MASK = 4; constexpr unsigned char BQ_MASK = 8; -inline Square operator+(Square &a, int b) { return Square(int(a) + b); } +inline Square operator+(Square &a, int b) { + return Square(int(a) + b); +} -inline Square operator-(Square &a, int b) { return Square(int(a) - b); } +inline Square operator-(Square &a, int b) { + return Square(int(a) - b); +} -inline Square operator+=(Square &a, int b) { return a = a + b; } +inline Square operator+=(Square &a, int b) { + return a = a + b; +} -inline Square operator-=(Square &a, int b) { return a = a - b; } +inline Square operator-=(Square &a, int b) { + return a = a - b; +} inline Square stringToSquare(std::string s) { if (s[0] == '-') { @@ -92,25 +157,53 @@ inline std::istream &operator>>(std::istream &is, Square &square) { } enum LineType : int { - HORIZONTAL = 0, VERTICAL = 1, DIAGONAL = 2, ANTI_DIAGONAL = 3 + HORIZONTAL = 0, + VERTICAL = 1, + DIAGONAL = 2, + ANTI_DIAGONAL = 3 }; enum Direction : int { - NORTH = 8, WEST = -1, SOUTH = -8, EAST = 1, NORTH_EAST = 9, NORTH_WEST = 7, SOUTH_WEST = -9, SOUTH_EAST = -7 + NORTH = 8, + WEST = -1, + SOUTH = -8, + EAST = 1, + NORTH_EAST = 9, + NORTH_WEST = 7, + SOUTH_WEST = -9, + SOUTH_EAST = -7 }; constexpr Direction DIRECTIONS[8] = {NORTH, WEST, NORTH_EAST, NORTH_WEST, SOUTH, EAST, SOUTH_WEST, SOUTH_EAST}; -constexpr Direction opposite(Direction direction) { return Direction(-direction); } +constexpr Direction opposite(Direction direction) { + return Direction(-direction); +} -constexpr Direction operator-(Direction direction) { return opposite(direction); } +constexpr Direction operator-(Direction direction) { + return opposite(direction); +} enum PieceType { - PIECE_EMPTY = 6, KING = 0, PAWN = 1, KNIGHT = 2, BISHOP = 3, ROOK = 4, QUEEN = 5 + PIECE_EMPTY = 6, + KING = 0, + PAWN = 1, + KNIGHT = 2, + BISHOP = 3, + ROOK = 4, + QUEEN = 5 }; enum Color { - COLOR_EMPTY = 2, WHITE = 0, BLACK = 1 + COLOR_EMPTY = 2, + WHITE = 0, + BLACK = 1 +}; + +enum NodeType { + ROOT_NODE, + PV_NODE, + NON_PV_NODE }; constexpr PieceType PIECE_TYPES_BY_VALUE[6] = {PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING}; @@ -126,7 +219,9 @@ struct Piece { color = c; } - constexpr bool isNull() const { return type == PIECE_EMPTY || color == COLOR_EMPTY; } + constexpr bool isNull() const { + return type == PIECE_EMPTY || color == COLOR_EMPTY; + } }; // 2 colors * 6 types * 64 square = 768 @@ -532,4 +627,4 @@ constexpr U64 const *castlingRandTable = randTable + 768; constexpr U64 const *epRandTable = randTable + 772; constexpr U64 const *blackRand = randTable + 780; -#endif //BLACKCORE_CONSTANTS_H +#endif//BLACKCORE_CONSTANTS_H diff --git a/src/corenet.bin b/src/corenet.bin index 64126dc..2df2179 100644 Binary files a/src/corenet.bin and b/src/corenet.bin differ diff --git a/src/eval.cpp b/src/eval.cpp index 3812435..6ed3ed8 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -19,13 +19,6 @@ #ifdef TUNE Score PIECE_VALUES[6] = { - 0, 150, 762, 892, 1254, 1651 -}; + 0, 170, 610, 660, 780, 1200}; #endif - -Score eval(const Position &pos) { - - Score score = pos.getState()->accumulator.forward(); - return (pos.getSideToMove() == WHITE ? score : -score) + TEMPO_SCORE; -} \ No newline at end of file diff --git a/src/eval.h b/src/eval.h index 4a1a2c6..eb81004 100644 --- a/src/eval.h +++ b/src/eval.h @@ -27,13 +27,12 @@ extern Score PIECE_VALUES[6]; #else constexpr Score PIECE_VALUES[6] = { - 0, 150, 762, 892, 1254, 1651 -}; + 0, 156, 561, 608, 736, 1022}; #endif -constexpr Score TEMPO_SCORE = 10; +inline Score eval(const Position &pos) { + return pos.getState()->accumulator.forward(pos.getSideToMove()); +} -Score eval(const Position &pos); - -#endif //BLACKCORE_EVAL_H +#endif//BLACKCORE_EVAL_H diff --git a/src/main.cpp b/src/main.cpp index 5c6d43f..d225164 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,14 +14,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include -#include "bitboard.h" #include "bench.h" -#include "uci.h" -#include "search.h" +#include "bitboard.h" #include "eval.h" -#include "tuner.h" #include "nnue.h" +#include "search.h" +#include "tuner.h" +#include "uci.h" +#include int main(int argc, char **argv) { diff --git a/src/move.cpp b/src/move.cpp index c39748d..05f2ffe 100644 --- a/src/move.cpp +++ b/src/move.cpp @@ -20,10 +20,14 @@ std::string Move::str() const { std::string token; if (isPromo()) { - if (!isSpecial1() && !isSpecial2()) token += "n"; - else if (!isSpecial1() && isSpecial2()) token += "b"; - else if (isSpecial1() && !isSpecial2()) token += "r"; - else token += "q"; + if (!isSpecial1() && !isSpecial2()) + token += "n"; + else if (!isSpecial1() && isSpecial2()) + token += "b"; + else if (isSpecial1() && !isSpecial2()) + token += "r"; + else + token += "q"; } return formatSquare(getFrom()) + formatSquare(getTo()) + token; } @@ -32,4 +36,3 @@ std::ostream &operator<<(std::ostream &os, const Move &move) { os << move.str(); return os; } - diff --git a/src/move.h b/src/move.h index 0ed6ed4..d191ee3 100644 --- a/src/move.h +++ b/src/move.h @@ -18,13 +18,13 @@ #ifndef CHESS_MOVE_H #define CHESS_MOVE_H -#include "utils.h" #include "constants.h" +#include "utils.h" -constexpr unsigned int PROMO_FLAG = 0x8; // 0b1000 -constexpr unsigned int CAPTURE_FLAG = 0x4; // 0b0100 -constexpr unsigned int SPECIAL1_FLAG = 0x2; // 0b0010 -constexpr unsigned int SPECIAL2_FLAG = 0x1; // 0b0001 +constexpr unsigned int PROMO_FLAG = 0x8; // 0b1000 +constexpr unsigned int CAPTURE_FLAG = 0x4; // 0b0100 +constexpr unsigned int SPECIAL1_FLAG = 0x2;// 0b0010 +constexpr unsigned int SPECIAL2_FLAG = 0x1;// 0b0001 constexpr unsigned int QUIET_MOVE = 0; constexpr unsigned int CAPTURE = CAPTURE_FLAG; @@ -45,7 +45,6 @@ constexpr unsigned int PROMO_CAPTURE_QUEEN = CAPTURE_FLAG | PROMO_FLAG | SPECIAL constexpr unsigned int KING_CASTLE = SPECIAL1_FLAG; constexpr unsigned int QUEEN_CASTLE = SPECIAL1_FLAG | SPECIAL2_FLAG; - class Move { public: constexpr Move(Square from, Square to, unsigned int flags) { @@ -58,31 +57,57 @@ class Move { constexpr Move() = default; - constexpr Square getTo() const { return Square(data & 0x3f); } + constexpr Square getTo() const { + return Square(data & 0x3f); + } - constexpr Square getFrom() const { return Square((data >> 6) & 0x3f); } + constexpr Square getFrom() const { + return Square((data >> 6) & 0x3f); + } - constexpr bool isFlag(unsigned int flag) const { return (data >> 12) & flag; } + constexpr bool isFlag(unsigned int flag) const { + return (data >> 12) & flag; + } - constexpr bool equalFlag(unsigned int flag) const { return (data >> 12) == flag; } + constexpr bool equalFlag(unsigned int flag) const { + return (data >> 12) == flag; + } - constexpr bool isNull() const { return data == 0; } + constexpr bool isNull() const { + return data == 0; + } - constexpr bool isCapture() const { return isFlag(CAPTURE_FLAG); } + constexpr bool isCapture() const { + return isFlag(CAPTURE_FLAG); + } - constexpr bool isPromo() const { return isFlag(PROMO_FLAG); } + constexpr bool isPromo() const { + return isFlag(PROMO_FLAG); + } - constexpr bool isSpecial1() const { return isFlag(SPECIAL1_FLAG); } + constexpr bool isSpecial1() const { + return isFlag(SPECIAL1_FLAG); + } - constexpr bool isSpecial2() const { return isFlag(SPECIAL2_FLAG); } + constexpr bool isSpecial2() const { + return isFlag(SPECIAL2_FLAG); + } - constexpr bool isQuiet() const { return !isCapture(); } + constexpr bool isQuiet() const { + return !isCapture(); + } - constexpr explicit operator bool() const { return !isNull(); } + constexpr explicit operator bool() const { + return !isNull(); + } - constexpr bool operator==(Move a) const { return (data & 0xFFFF) == (a.data & 0xFFFF); } + constexpr bool operator==(Move a) const { + return (data & 0xFFFF) == (a.data & 0xFFFF); + } - constexpr bool operator!=(Move a) const { return (data & 0xFFFF) != (a.data & 0xFFFF); } + constexpr bool operator!=(Move a) const { + return (data & 0xFFFF) != (a.data & 0xFFFF); + } std::string str() const; @@ -92,4 +117,4 @@ class Move { std::ostream &operator<<(std::ostream &os, const Move &move); -#endif //CHESS_MOVE_H +#endif//CHESS_MOVE_H diff --git a/src/move_ordering.cpp b/src/move_ordering.cpp index 6ec7c30..dbdbdec 100644 --- a/src/move_ordering.cpp +++ b/src/move_ordering.cpp @@ -15,32 +15,25 @@ // along with this program. If not, see . #include "move_ordering.h" -#include "tt.h" #include "search.h" +#include "tt.h" #include -constexpr Score winningCapture[6][6] = { -// KING PAWN KNIGHT BISHOP ROOK QUEEN - {0, 0, 0, 0, 0, 0}, // KING - {0, 800004, 800104, 800204, 800304, 800404}, // PAWN - {0, 800003, 800103, 800203, 800303, 800403}, // KNIGHT - {0, 800002, 800102, 800202, 800302, 800402}, // BISHOP - {0, 800001, 800101, 800201, 800301, 800401}, // ROOK - {0, 800000, 800100, 800200, 800300, 800400}, // QUEEN +constexpr Score MVV_LVA[6][6] = { + // KING PAWN KNIGHT BISHOP ROOK QUEEN + {0, 0, 0, 0, 0, 0}, // KING + {0, 800004, 800104, 800204, 800304, 800404},// PAWN + {0, 800003, 800103, 800203, 800303, 800403},// KNIGHT + {0, 800002, 800102, 800202, 800302, 800402},// BISHOP + {0, 800001, 800101, 800201, 800301, 800401},// ROOK + {0, 800000, 800100, 800200, 800300, 800400},// QUEEN }; -constexpr Score losingCapture[6][6] = { -// KING PAWN KNIGHT BISHOP ROOK QUEEN - {0, 0, 0, 0, 0, 0}, // KING - {0, 200004, 200104, 200204, 200304, 200404}, // PAWN - {0, 200003, 200103, 200203, 200303, 200403}, // KNIGHT - {0, 200002, 200102, 200202, 200302, 200402}, // BISHOP - {0, 200001, 200101, 200201, 200301, 200401}, // ROOK - {0, 200000, 200100, 200200, 200300, 200400}, // QUEEN -}; +constexpr Score winningCapture = 800000; +constexpr Score losingCapture = 200000; -Move killerMoves[101][2]; +Move killerMoves[MAX_PLY + 1][2]; // TODO Counter move history Score historyTable[2][64][64]; @@ -63,17 +56,18 @@ Score scoreQMove(const Position &pos, Move m) { if (m == getHashMove(pos.getHash())) { return 1000000; } else if (m.isPromo()) { - if (m.isSpecial1() && m.isSpecial2()) { // Queen promo + if (m.isSpecial1() && m.isSpecial2()) {// Queen promo return 900000; - } else { // Anything else, under promotions should only be played in really few cases + } else {// Anything else, under promotions should only be played in really few cases return -100000; } } else { Score seeScore = see(pos, m); + if (seeScore >= 0) - return 800000 + seeScore; + return winningCapture + seeScore; else - return seeScore; + return losingCapture + seeScore; } } @@ -81,19 +75,18 @@ Score scoreMove(const Position &pos, Move m, Ply ply) { if (m == getHashMove(pos.getHash())) { return 1000000; } else if (m.isPromo()) { - if (m.isSpecial1() && m.isSpecial2()) { // Queen promo + if (m.isSpecial1() && m.isSpecial2()) {// Queen promo return 900000; - } else { // Anything else, under promotions should only be played in really few cases + } else {// Anything else, under promotions should only be played in really few cases return -100000; } } else if (m.isCapture()) { - Square from = m.getFrom(); - Square to = m.getTo(); + Score seeScore = see(pos, m); if (see(pos, m) >= 0) - return winningCapture[pos.pieceAt(from).type][pos.pieceAt(to).type]; + return winningCapture + seeScore; else - return losingCapture[pos.pieceAt(from).type][pos.pieceAt(to).type]; + return losingCapture + seeScore; } else if (killerMoves[ply][0] == m) { return 750000; } else if (killerMoves[ply][1] == m) { diff --git a/src/move_ordering.h b/src/move_ordering.h index d736f1c..6c218ef 100644 --- a/src/move_ordering.h +++ b/src/move_ordering.h @@ -20,7 +20,7 @@ #include "move.h" #include "position.h" -extern Move killerMoves[101][2]; +extern Move killerMoves[MAX_PLY + 1][2]; Score scoreMove(const Position &pos, Move m, Ply ply); @@ -32,4 +32,4 @@ void recordKillerMove(Move m, Ply ply); void recordHHMove(Move move, Color color, Depth depth); -#endif //BLACKCORE_MOVE_ORDERING_H +#endif//BLACKCORE_MOVE_ORDERING_H diff --git a/src/movegen.cpp b/src/movegen.cpp index d66550e..e072ed2 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -78,7 +78,6 @@ inline Move *generateMovesFromPieces(const Position &pos, Move *moves, Bitboard } return moves; - } template @@ -287,7 +286,6 @@ inline Move *generateSliderAndJumpMoves(const Position &pos, Move *moves, Bitboa moves = generateMovesFromPieces(pos, moves, pinnedDA, checkMask & pinDA, occupied, empty, enemy); - return moves; } @@ -327,7 +325,8 @@ Move *generateMoves(const Position &pos, Move *moves) { Bitboard possiblePinners = (pieceAttacks(king, occupied) ^ seenSquares) & enemy; Bitboard pinners = ((pieceAttacks(king, occupied) & pos.pieces()) | (pieceAttacks(king, occupied) & pos.pieces()) | - (pieceAttacks(king, occupied) & pos.pieces())) & possiblePinners; + (pieceAttacks(king, occupied) & pos.pieces())) & + possiblePinners; Bitboard pinH, pinV, pinD, pinA, pinHV, pinDA, moveH, moveV, moveD, moveA; diff --git a/src/movegen.h b/src/movegen.h index 4c8f462..e77a87c 100644 --- a/src/movegen.h +++ b/src/movegen.h @@ -17,9 +17,9 @@ #ifndef BLACKCORE_MOVEGEN_H #define BLACKCORE_MOVEGEN_H -#include "position.h" #include "move.h" #include "move_ordering.h" +#include "position.h" template inline Bitboard getAttackers(const Position &pos, Square square) { @@ -29,7 +29,8 @@ inline Bitboard getAttackers(const Position &pos, Square square) { (pieceAttacks(square, occupied) & pos.pieces()) | (pieceAttacks(square, occupied) & pos.pieces()) | (pieceAttacks(square, occupied) & pos.pieces()) | - (pieceAttacks(square, occupied) & pos.pieces())) & enemy; + (pieceAttacks(square, occupied) & pos.pieces())) & + enemy; } inline Bitboard getAttackers(const Position &pos, Square square) { @@ -85,5 +86,4 @@ struct MoveList { } }; - -#endif //BLACKCORE_MOVEGEN_H +#endif//BLACKCORE_MOVEGEN_H diff --git a/src/nnue.cpp b/src/nnue.cpp index 995520a..c5d6549 100644 --- a/src/nnue.cpp +++ b/src/nnue.cpp @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include "nnue.h" +#include "position.h" #include #include #include -#include "nnue.h" -#include "position.h" #include "incbin/incbin.h" @@ -29,120 +29,144 @@ namespace NNUE { alignas(64) int16_t L_0_WEIGHTS[L_0_SIZE * L_1_SIZE]; alignas(64) int16_t L_0_BIASES[L_1_SIZE]; - alignas(64) int16_t L_1_WEIGHTS[L_1_SIZE * 1]; + alignas(64) int16_t L_1_WEIGHTS[L_1_SIZE * 2]; alignas(64) int16_t L_1_BIASES[1]; void Accumulator::loadAccumulator(NNUE::Accumulator &accumulator) { + for (Color perspective : {WHITE, BLACK}) { #ifdef AVX2 - for (int i = 0; i < chunkNum; i += 4) { - const int offset1 = (i + 0) * regWidth; - const int offset2 = (i + 1) * regWidth; - const int offset3 = (i + 2) * regWidth; - const int offset4 = (i + 3) * regWidth; - - __m256i ac1 = _mm256_loadu_si256((__m256i *) &accumulator.hiddenLayer[offset1]); - __m256i ac2 = _mm256_loadu_si256((__m256i *) &accumulator.hiddenLayer[offset2]); - __m256i ac3 = _mm256_loadu_si256((__m256i *) &accumulator.hiddenLayer[offset3]); - __m256i ac4 = _mm256_loadu_si256((__m256i *) &accumulator.hiddenLayer[offset4]); - - _mm256_storeu_si256((__m256i *) &hiddenLayer[offset1], ac1); - _mm256_storeu_si256((__m256i *) &hiddenLayer[offset2], ac2); - _mm256_storeu_si256((__m256i *) &hiddenLayer[offset3], ac3); - _mm256_storeu_si256((__m256i *) &hiddenLayer[offset4], ac4); - } + for (int i = 0; i < chunkNum; i += 4) { + const int offset1 = (i + 0) * regWidth; + const int offset2 = (i + 1) * regWidth; + const int offset3 = (i + 2) * regWidth; + const int offset4 = (i + 3) * regWidth; + + __m256i ac1 = _mm256_loadu_si256((__m256i *) &accumulator.hiddenLayer[perspective][offset1]); + __m256i ac2 = _mm256_loadu_si256((__m256i *) &accumulator.hiddenLayer[perspective][offset2]); + __m256i ac3 = _mm256_loadu_si256((__m256i *) &accumulator.hiddenLayer[perspective][offset3]); + __m256i ac4 = _mm256_loadu_si256((__m256i *) &accumulator.hiddenLayer[perspective][offset4]); + + _mm256_storeu_si256((__m256i *) &hiddenLayer[perspective][offset1], ac1); + _mm256_storeu_si256((__m256i *) &hiddenLayer[perspective][offset2], ac2); + _mm256_storeu_si256((__m256i *) &hiddenLayer[perspective][offset3], ac3); + _mm256_storeu_si256((__m256i *) &hiddenLayer[perspective][offset4], ac4); + } #else - std::memcpy(hiddenLayer, accumulator.hiddenLayer, sizeof(int16_t) * L_1_SIZE); + std::memcpy(hiddenLayer[perspective], accumulator.hiddenLayer[perspective], sizeof(int16_t) * L_1_SIZE * 1); #endif + } } void Accumulator::refresh(const Position &pos) { - std::memcpy(hiddenLayer, L_0_BIASES, sizeof(int16_t) * L_1_SIZE); + for (Color perspective : {WHITE, BLACK}) { + std::memcpy(hiddenLayer[perspective], L_0_BIASES, sizeof(int16_t) * L_1_SIZE); + } for (Square sq = A1; sq < 64; sq += 1) { Piece p = pos.pieceAt(sq); if (!p.isNull()) { - addFeature(getAccumulatorIndex(p.color, p.type, sq)); + addFeature(p.color, p.type, sq); } } } - void Accumulator::addFeature(int index) { + void Accumulator::addFeature(Color pieceColor, PieceType pieceType, Square sq) { + for (Color perspective : {WHITE, BLACK}) { + unsigned int index = getAccumulatorIndex(perspective, pieceColor, pieceType, sq); #ifdef AVX2 - for (int i = 0; i < chunkNum; i += 4) { - const int offset1 = (i + 0) * regWidth; - const int offset2 = (i + 1) * regWidth; - const int offset3 = (i + 2) * regWidth; - const int offset4 = (i + 3) * regWidth; - - __m256i ac1 = _mm256_loadu_si256((__m256i *) &hiddenLayer[offset1]); - __m256i ac2 = _mm256_loadu_si256((__m256i *) &hiddenLayer[offset2]); - __m256i ac3 = _mm256_loadu_si256((__m256i *) &hiddenLayer[offset3]); - __m256i ac4 = _mm256_loadu_si256((__m256i *) &hiddenLayer[offset4]); - - __m256i we1 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset1]); - __m256i we2 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset2]); - __m256i we3 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset3]); - __m256i we4 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset4]); - - __m256i sum1 = _mm256_add_epi16(ac1, we1); - __m256i sum2 = _mm256_add_epi16(ac2, we2); - __m256i sum3 = _mm256_add_epi16(ac3, we3); - __m256i sum4 = _mm256_add_epi16(ac4, we4); - - _mm256_storeu_si256((__m256i *) &hiddenLayer[offset1], sum1); - _mm256_storeu_si256((__m256i *) &hiddenLayer[offset2], sum2); - _mm256_storeu_si256((__m256i *) &hiddenLayer[offset3], sum3); - _mm256_storeu_si256((__m256i *) &hiddenLayer[offset4], sum4); - } + for (int i = 0; i < chunkNum; i += 4) { + const int offset1 = (i + 0) * regWidth; + const int offset2 = (i + 1) * regWidth; + const int offset3 = (i + 2) * regWidth; + const int offset4 = (i + 3) * regWidth; + + __m256i ac1 = _mm256_loadu_si256((__m256i *) &hiddenLayer[perspective][offset1]); + __m256i ac2 = _mm256_loadu_si256((__m256i *) &hiddenLayer[perspective][offset2]); + __m256i ac3 = _mm256_loadu_si256((__m256i *) &hiddenLayer[perspective][offset3]); + __m256i ac4 = _mm256_loadu_si256((__m256i *) &hiddenLayer[perspective][offset4]); + + __m256i we1 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset1]); + __m256i we2 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset2]); + __m256i we3 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset3]); + __m256i we4 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset4]); + + __m256i sum1 = _mm256_add_epi16(ac1, we1); + __m256i sum2 = _mm256_add_epi16(ac2, we2); + __m256i sum3 = _mm256_add_epi16(ac3, we3); + __m256i sum4 = _mm256_add_epi16(ac4, we4); + + _mm256_storeu_si256((__m256i *) &hiddenLayer[perspective][offset1], sum1); + _mm256_storeu_si256((__m256i *) &hiddenLayer[perspective][offset2], sum2); + _mm256_storeu_si256((__m256i *) &hiddenLayer[perspective][offset3], sum3); + _mm256_storeu_si256((__m256i *) &hiddenLayer[perspective][offset4], sum4); + } #else - for (int i = 0; i < L_1_SIZE; i++) { - hiddenLayer[i] += L_0_WEIGHTS[index * L_1_SIZE + i]; - } + for (int i = 0; i < L_1_SIZE; i++) { + hiddenLayer[perspective][i] += L_0_WEIGHTS[index * L_1_SIZE + i]; + } #endif + } } - void Accumulator::removeFeature(int index) { + void Accumulator::removeFeature(Color pieceColor, PieceType pieceType, Square sq) { + for (Color perspective : {WHITE, BLACK}) { + unsigned int index = getAccumulatorIndex(perspective, pieceColor, pieceType, sq); #ifdef AVX2 - for (int i = 0; i < chunkNum; i += 4) { - - const int offset1 = (i + 0) * regWidth; - const int offset2 = (i + 1) * regWidth; - const int offset3 = (i + 2) * regWidth; - const int offset4 = (i + 3) * regWidth; - - __m256i ac1 = _mm256_loadu_si256((__m256i *) &hiddenLayer[offset1]); - __m256i ac2 = _mm256_loadu_si256((__m256i *) &hiddenLayer[offset2]); - __m256i ac3 = _mm256_loadu_si256((__m256i *) &hiddenLayer[offset3]); - __m256i ac4 = _mm256_loadu_si256((__m256i *) &hiddenLayer[offset4]); - - __m256i we1 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset1]); - __m256i we2 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset2]); - __m256i we3 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset3]); - __m256i we4 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset4]); - - __m256i sum1 = _mm256_sub_epi16(ac1, we1); - __m256i sum2 = _mm256_sub_epi16(ac2, we2); - __m256i sum3 = _mm256_sub_epi16(ac3, we3); - __m256i sum4 = _mm256_sub_epi16(ac4, we4); - - _mm256_storeu_si256((__m256i *) &hiddenLayer[offset1], sum1); - _mm256_storeu_si256((__m256i *) &hiddenLayer[offset2], sum2); - _mm256_storeu_si256((__m256i *) &hiddenLayer[offset3], sum3); - _mm256_storeu_si256((__m256i *) &hiddenLayer[offset4], sum4); - } + for (int i = 0; i < chunkNum; i += 4) { + + const int offset1 = (i + 0) * regWidth; + const int offset2 = (i + 1) * regWidth; + const int offset3 = (i + 2) * regWidth; + const int offset4 = (i + 3) * regWidth; + + __m256i ac1 = _mm256_loadu_si256((__m256i *) &hiddenLayer[perspective][offset1]); + __m256i ac2 = _mm256_loadu_si256((__m256i *) &hiddenLayer[perspective][offset2]); + __m256i ac3 = _mm256_loadu_si256((__m256i *) &hiddenLayer[perspective][offset3]); + __m256i ac4 = _mm256_loadu_si256((__m256i *) &hiddenLayer[perspective][offset4]); + + __m256i we1 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset1]); + __m256i we2 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset2]); + __m256i we3 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset3]); + __m256i we4 = _mm256_loadu_si256((__m256i *) &L_0_WEIGHTS[index * L_1_SIZE + offset4]); + + __m256i sum1 = _mm256_sub_epi16(ac1, we1); + __m256i sum2 = _mm256_sub_epi16(ac2, we2); + __m256i sum3 = _mm256_sub_epi16(ac3, we3); + __m256i sum4 = _mm256_sub_epi16(ac4, we4); + + _mm256_storeu_si256((__m256i *) &hiddenLayer[perspective][offset1], sum1); + _mm256_storeu_si256((__m256i *) &hiddenLayer[perspective][offset2], sum2); + _mm256_storeu_si256((__m256i *) &hiddenLayer[perspective][offset3], sum3); + _mm256_storeu_si256((__m256i *) &hiddenLayer[perspective][offset4], sum4); + } #else - for (int i = 0; i < L_1_SIZE; i++) { - hiddenLayer[i] -= L_0_WEIGHTS[index * L_1_SIZE + i]; - } + for (int i = 0; i < L_1_SIZE; i++) { + hiddenLayer[perspective][i] -= L_0_WEIGHTS[index * L_1_SIZE + i]; + } #endif + } } - Score Accumulator::forward() { + Score Accumulator::forward(Color stm) { int32_t output = L_1_BIASES[0]; - for (int i = 0; i < L_1_SIZE; i++) { - output += ReLU(hiddenLayer[i]) * L_1_WEIGHTS[i]; + if (stm == WHITE) { + for (int i = 0; i < L_1_SIZE; i++) { + output += ReLU(hiddenLayer[WHITE][i]) * L_1_WEIGHTS[i]; + } + + for (int i = 0; i < L_1_SIZE; i++) { + output += ReLU(hiddenLayer[BLACK][i]) * L_1_WEIGHTS[L_1_SIZE + i]; + } + } else { + for (int i = 0; i < L_1_SIZE; i++) { + output += ReLU(hiddenLayer[BLACK][i]) * L_1_WEIGHTS[i]; + } + + for (int i = 0; i < L_1_SIZE; i++) { + output += ReLU(hiddenLayer[WHITE][i]) * L_1_WEIGHTS[L_1_SIZE + i]; + } } return output * 400 / (255 * 255); @@ -155,8 +179,8 @@ namespace NNUE { ptr += sizeof(int16_t) * L_0_SIZE * L_1_SIZE; std::memcpy(L_0_BIASES, gNetData + ptr, sizeof(int16_t) * L_1_SIZE); ptr += sizeof(int16_t) * L_1_SIZE; - std::memcpy(L_1_WEIGHTS, gNetData + ptr, sizeof(int16_t) * L_1_SIZE * 1); - ptr += sizeof(int16_t) * L_1_SIZE * 1; + std::memcpy(L_1_WEIGHTS, gNetData + ptr, sizeof(int16_t) * L_1_SIZE * 2); + ptr += sizeof(int16_t) * L_1_SIZE * 2; std::memcpy(L_1_BIASES, gNetData + ptr, sizeof(int16_t) * 1); // Currently loading net from a file is not supported @@ -168,9 +192,9 @@ namespace NNUE { fread(L_0_WEIGHTS, sizeof(int16_t), L_0_SIZE * L_1_SIZE, file); fread(L_0_BIASES, sizeof(int16_t), L_1_SIZE, file); - fread(L_1_WEIGHTS, sizeof(int16_t), L_1_SIZE * 1, file); + fread(L_1_WEIGHTS, sizeof(int16_t), L_1_SIZE * 2, file); fread(L_1_BIASES, sizeof(int16_t), 1, file); }*/ } -} \ No newline at end of file +}// namespace NNUE diff --git a/src/nnue.h b/src/nnue.h index 6391a30..0032624 100644 --- a/src/nnue.h +++ b/src/nnue.h @@ -23,21 +23,22 @@ class Position; namespace NNUE { - /* +-----------------------+ - * | NNUE Architecture | - * | 768->256->1 | - * | Activation: ReLU | - * +-----------------------+ - * - * L_0_IN = features count - * - * L_1_WEIGHTS = in features -> L_1 (768 -> 32) - * L_1_BIASES = L_1 biases - * - * L_2_WEIGHTS = L_1 -> L_2 (32 -> 32) - * L_2_BIASES = L_2 biases - * - */ + /* + * +-----------------------+ + * | NNUE Architecture | + * | 2x(768->256)->1 | + * | Activation: ReLU | + * +-----------------------+ + * + * L_0_SIZE = features count + * + * L_0_WEIGHTS = in features -> L_1 (768 -> 256) + * L_0_BIASES = L_1 biases + * + * L_1_WEIGHTS = 2xL_1 -> L_2 (2x256 -> 1) + * L_1_BIASES = L_2 biases + * + */ constexpr int L_0_SIZE = 768; @@ -47,23 +48,25 @@ namespace NNUE { constexpr int chunkNum = 256 / regWidth; struct Accumulator { - alignas(32) int16_t hiddenLayer[L_1_SIZE]; + alignas(32) int16_t hiddenLayer[2][L_1_SIZE]; - constexpr Accumulator() {} + constexpr Accumulator() { + } void loadAccumulator(Accumulator &accumulator); void refresh(const Position &pos); - void addFeature(int index); + void addFeature(Color pieceColor, PieceType pieceType, Square sq); - void removeFeature(int index); + void removeFeature(Color pieceColor, PieceType pieceType, Square sq); - Score forward(); + Score forward(Color stm); }; - constexpr int getAccumulatorIndex(Color color, PieceType type, Square square) { - return color * 384 + type * 64 + square; + constexpr int getAccumulatorIndex(Color perspective, Color pieceColor, PieceType pieceType, Square square) { + return (perspective == WHITE ? pieceColor : 1 - pieceColor) * 384 + pieceType * 64 + + (perspective == WHITE ? square : square ^ 56); } constexpr int16_t ReLU(int16_t in) { @@ -71,6 +74,6 @@ namespace NNUE { } void init(); -} +}// namespace NNUE -#endif //BLACKCORE_NNUE_H +#endif//BLACKCORE_NNUE_H diff --git a/src/position.cpp b/src/position.cpp index 9034eed..e131c51 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -17,9 +17,9 @@ #include "position.h" #include "eval.h" +#include #include #include -#include #define state states.top() @@ -73,17 +73,22 @@ bool Position::isRepetition() { } void Position::display() const { - state->accumulator.forward(); + std::vector text; text.emplace_back(string("Hash: ") + std::to_string(state->hash)); if (getEpSquare() != NULL_SQUARE) text.emplace_back(string("En passant square: ") + formatSquare(getEpSquare())); string cr; - if (getCastleRight(WK_MASK)) cr += 'K'; - if (getCastleRight(WQ_MASK)) cr += 'Q'; - if (getCastleRight(BK_MASK)) cr += 'k'; - if (getCastleRight(BQ_MASK)) cr += 'q'; - if (cr.empty()) cr = "None"; + if (getCastleRight(WK_MASK)) + cr += 'K'; + if (getCastleRight(WQ_MASK)) + cr += 'Q'; + if (getCastleRight(BK_MASK)) + cr += 'k'; + if (getCastleRight(BQ_MASK)) + cr += 'q'; + if (cr.empty()) + cr = "None"; text.emplace_back(string("Castling rights: ") + cr); text.emplace_back(string("Side to move: ") + string(getSideToMove() == WHITE ? "White" : "Black")); // TODO FEN, full-half move counter @@ -105,7 +110,8 @@ void Position::display() const { } cout << "\n"; } - cout << " +---+---+---+---+---+---+---+---+\n\n" << std::endl; + cout << " +---+---+---+---+---+---+---+---+\n\n" + << std::endl; } void Position::displayEval() { @@ -134,7 +140,8 @@ void Position::displayEval() { } cout << "\n"; } - cout << " +-----+-----+-----+-----+-----+-----+-----+-----+\n" << std::endl; + cout << " +-----+-----+-----+-----+-----+-----+-----+-----+\n" + << std::endl; cout << "Eval: " << score << std::endl; } diff --git a/src/position.h b/src/position.h index 6079f5b..0750833 100644 --- a/src/position.h +++ b/src/position.h @@ -17,11 +17,11 @@ #ifndef BLACKCORE_POSITION_H #define BLACKCORE_POSITION_H -#include #include "bitboard.h" -#include "utils.h" #include "move.h" #include "nnue.h" +#include "utils.h" +#include extern U64 nodeCount; @@ -69,72 +69,116 @@ struct StateStack { currState--; } - inline BoardState *top() const { return currState; } + inline BoardState *top() const { + return currState; + } inline void clear() { currState = stateStart; *currState = {}; } - inline Ply getMove50() const { return currState - currState->lastIrreversibleMove; } - + inline Ply getMove50() const { + return currState - currState->lastIrreversibleMove; + } }; #define state states.top() class Position { public: - - constexpr Piece pieceAt(Square square) const { return board[square]; } + constexpr Piece pieceAt(Square square) const { + return board[square]; + } // This will be mostly used with constant color and type so this will result a nicer code // pieces<{ROOK, WHITE}>() --> pieces() template - constexpr Bitboard pieces() const { return pieceBB[type] & allPieceBB[color]; } + constexpr Bitboard pieces() const { + return pieceBB[type] & allPieceBB[color]; + } template - constexpr Bitboard pieces(PieceType type) const { return pieceBB[type] & allPieceBB[color]; } + constexpr Bitboard pieces(PieceType type) const { + return pieceBB[type] & allPieceBB[color]; + } template - constexpr Bitboard pieces(Color color) const { return pieceBB[type] & allPieceBB[color]; } + constexpr Bitboard pieces(Color color) const { + return pieceBB[type] & allPieceBB[color]; + } - constexpr Bitboard pieces(Color color, PieceType type) const { return pieceBB[type] & allPieceBB[color]; } + constexpr Bitboard pieces(Color color, PieceType type) const { + return pieceBB[type] & allPieceBB[color]; + } template - constexpr Bitboard pieces() const { return pieceBB[type]; } + constexpr Bitboard pieces() const { + return pieceBB[type]; + } - constexpr Bitboard pieces(PieceType type) const { return pieceBB[type]; } + constexpr Bitboard pieces(PieceType type) const { + return pieceBB[type]; + } template - constexpr Bitboard friendly() const { return allPieceBB[color]; } + constexpr Bitboard friendly() const { + return allPieceBB[color]; + } - constexpr Bitboard friendly(Color color) const { return allPieceBB[color]; } + constexpr Bitboard friendly(Color color) const { + return allPieceBB[color]; + } template - constexpr Bitboard enemy() const { return allPieceBB[EnemyColor()]; } + constexpr Bitboard enemy() const { + return allPieceBB[EnemyColor()]; + } template - constexpr Bitboard enemyOrEmpty() const { return ~friendly(); } + constexpr Bitboard enemyOrEmpty() const { + return ~friendly(); + } - inline Bitboard occupied() const { return allPieceBB[WHITE] | allPieceBB[BLACK]; } + inline Bitboard occupied() const { + return allPieceBB[WHITE] | allPieceBB[BLACK]; + } - inline Bitboard empty() const { return ~occupied(); } + inline Bitboard empty() const { + return ~occupied(); + } - inline Color getSideToMove() const { return state->stm; } + inline Color getSideToMove() const { + return state->stm; + } - inline Square getEpSquare() const { return state->epSquare; } + inline Square getEpSquare() const { + return state->epSquare; + } - inline bool getCastleRight(unsigned char castleRight) const { return castleRight & state->castlingRights; } + inline bool getCastleRight(unsigned char castleRight) const { + return castleRight & state->castlingRights; + } - inline unsigned char getCastlingRights() const { return state->castlingRights; } + inline unsigned char getCastlingRights() const { + return state->castlingRights; + } - inline BoardState *getState() { return state; } + inline BoardState *getState() { + return state; + } - inline BoardState *getState() const { return state; } + inline BoardState *getState() const { + return state; + } - inline U64 getHash() const { return state->hash; } + inline U64 getHash() const { + return state->hash; + } - inline Ply getMove50() const { return states.getMove50(); } + inline Ply getMove50() const { + return states.getMove50(); + } inline void makeMove(Move move); @@ -161,7 +205,6 @@ class Position { Position(const std::string &fen); private: - template void clearSquare(Square square); @@ -171,9 +214,13 @@ class Position { template void movePiece(Square from, Square to); - inline void setCastleRight(unsigned char castleRight) { state->castlingRights |= castleRight; } + inline void setCastleRight(unsigned char castleRight) { + state->castlingRights |= castleRight; + } - inline void removeCastleRight(unsigned char castleRight) { state->castlingRights &= ~castleRight; } + inline void removeCastleRight(unsigned char castleRight) { + state->castlingRights &= ~castleRight; + } void clearPosition(); @@ -205,7 +252,7 @@ void Position::clearSquare(Square square) { state->hash ^= pieceRandTable[12 * square + 6 * piece.color + piece.type]; if constexpr (updateAccumulator) { - state->accumulator.removeFeature(NNUE::getAccumulatorIndex(piece.color, piece.type, square)); + state->accumulator.removeFeature(piece.color, piece.type, square); } } @@ -220,7 +267,7 @@ void Position::setSquare(Square square, Piece piece) { state->hash ^= pieceRandTable[12 * square + 6 * p.color + p.type]; if constexpr (updateAccumulator) { - state->accumulator.removeFeature(NNUE::getAccumulatorIndex(p.color, p.type, square)); + state->accumulator.removeFeature(p.color, p.type, square); } } @@ -231,7 +278,7 @@ void Position::setSquare(Square square, Piece piece) { state->hash ^= pieceRandTable[12 * square + 6 * piece.color + piece.type]; if constexpr (updateAccumulator) { - state->accumulator.addFeature(NNUE::getAccumulatorIndex(piece.color, piece.type, square)); + state->accumulator.addFeature(piece.color, piece.type, square); } } @@ -345,7 +392,6 @@ void Position::undoMove(Move move) { movePiece(to, from); - if (move.equalFlag(KING_CASTLE)) { if constexpr (enemyColor == WHITE) { movePiece(F1, H1); @@ -372,15 +418,19 @@ void Position::undoMove(Move move) { } inline void Position::makeMove(Move move) { - if (getSideToMove() == WHITE) makeMove(move); - else makeMove(move); + if (getSideToMove() == WHITE) + makeMove(move); + else + makeMove(move); } inline void Position::undoMove(Move move) { - if (getSideToMove() == WHITE) undoMove(move); - else undoMove(move); + if (getSideToMove() == WHITE) + undoMove(move); + else + undoMove(move); } #undef state -#endif //BLACKCORE_POSITION_H +#endif//BLACKCORE_POSITION_H diff --git a/src/search.cpp b/src/search.cpp index c73f775..b0c0bb4 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -15,22 +15,23 @@ // along with this program. If not, see . #include "search.h" +#include "eval.h" #include "timeman.h" #include "tt.h" -#include "eval.h" #include "uci.h" +#include #include #ifdef TUNE -Score DELTA_MARGIN = 307; +Score DELTA_MARGIN = 252; -Score RAZOR_MARGIN = 146; +Score RAZOR_MARGIN = 155; Depth RFP_DEPTH = 8; -Score RFP_DEPTH_MULTIPLIER = 60; -Score RFP_IMPROVING_MULTIPLIER = 56; +Score RFP_DEPTH_MULTIPLIER = 56; +Score RFP_IMPROVING_MULTIPLIER = 46; Depth NULL_MOVE_DEPTH = 2; Depth NULL_MOVE_BASE_R = 3; @@ -38,9 +39,8 @@ Depth NULL_MOVE_R_SCALE = 3; Depth LMR_DEPTH = 3; double LMR_BASE = 1; -double LMR_SCALE = 1.75; -int LMR_MIN_I = 2; -int LMR_PVNODE_I = 1; +double LMR_SCALE = 1.65; +int LMR_INDEX = 2; Depth LMP_DEPTH = 4; int LMP_MOVES = 5; @@ -50,7 +50,6 @@ Score ASPIRATION_DELTA = 28; Score ASPIRATION_BOUND = 3000; Score SEE_MARGIN = 2; -Depth SEE_DEPTH = 4; #endif @@ -58,15 +57,13 @@ Ply selectiveDepth = 0; Move bestPV; // Move index -> depth -Depth reductions[200][64]; +Depth reductions[200][MAX_PLY + 1]; void initLmr() { for (int moveIndex = 0; moveIndex < 200; moveIndex++) { - for (Depth depth = 0; depth < 64; depth++) { - - reductions[moveIndex][depth] = std::max(2, Depth( - LMR_BASE + (log((double) moveIndex) * log((double) depth) / LMR_SCALE))); + for (Depth depth = 0; depth < MAX_PLY; depth++) { + reductions[moveIndex][depth] = std::max(2, Depth(LMR_BASE + (log((double) moveIndex) * log((double) depth) / LMR_SCALE))); } } } @@ -87,7 +84,8 @@ Bitboard getAllAttackers(const Position &pos, Square square, Bitboard occ) { (pieceAttacks(square, occ) & pos.pieces()) | (pieceAttacks(square, occ) & pos.pieces()) | (pieceAttacks(square, occ) & pos.pieces()) | - (pieceAttacks(square, occ) & pos.pieces())) & occ; + (pieceAttacks(square, occ) & pos.pieces())) & + occ; } Score see(const Position &pos, Move move) { @@ -96,7 +94,7 @@ Score see(const Position &pos, Move move) { Square from = move.getFrom(); Square to = move.getTo(); - e[0] = PIECE_VALUES[pos.pieceAt(to).type]; + e[0] = move.equalFlag(EP_CAPTURE) ? PIECE_VALUES[PAWN] : PIECE_VALUES[pos.pieceAt(to).type]; Bitboard rooks = pos.pieces() | pos.pieces(); Bitboard bishops = pos.pieces() | pos.pieces(); @@ -111,7 +109,8 @@ Score see(const Position &pos, Move move) { d++; e[d] = PIECE_VALUES[type] - e[d - 1]; - if (std::max(-e[d - 1], e[d]) < 0) break; + if (std::max(-e[d - 1], e[d]) < 0) + break; occ ^= attacker; attackers ^= attacker; @@ -131,21 +130,31 @@ Score see(const Position &pos, Move move) { return e[0]; } - +template Score quiescence(Position &pos, Score alpha, Score beta, Ply ply) { - if (shouldEnd()) return UNKNOWN_SCORE; + constexpr bool pvNode = type != NON_PV_NODE; + constexpr bool nonPvNode = !pvNode; + + if (shouldEnd()) + return UNKNOWN_SCORE; if (ply > selectiveDepth) { selectiveDepth = ply; } - bool ttHit; - Score ttScore = ttProbe(pos.getHash(), ttHit, 0, alpha, beta); - if (ttScore != UNKNOWN_SCORE) return ttScore; + bool ttHit = false; + TTEntry *ttEntry = ttProbe(pos.getHash(), ttHit, 0, alpha, beta); + if (ttHit && nonPvNode && (ttEntry->flag == EXACT || (ttEntry->flag == ALPHA && ttEntry->eval <= alpha) || (ttEntry->flag == BETA && ttEntry->eval >= beta))) { + return ttEntry->eval; + } Score staticEval = eval(pos); + if (ply >= MAX_PLY) { + return staticEval; + } + if (staticEval >= beta) { return beta; } @@ -164,7 +173,8 @@ Score quiescence(Position &pos, Score alpha, Score beta, Ply ply) { // Delta pruning if (m.isPromo() * PIECE_VALUES[QUEEN] + PIECE_VALUES[pos.pieceAt(m.getTo()).type] + - staticEval + DELTA_MARGIN < alpha) + staticEval + DELTA_MARGIN < + alpha) continue; // SEE pruning @@ -173,11 +183,12 @@ Score quiescence(Position &pos, Score alpha, Score beta, Ply ply) { pos.makeMove(m); - Score score = -quiescence(pos, -beta, -alpha, ply + 1); + Score score = -quiescence(pos, -beta, -alpha, ply + 1); pos.undoMove(m); - if (shouldEnd()) return UNKNOWN_SCORE; + if (shouldEnd()) + return UNKNOWN_SCORE; if (score >= beta) { ttSave(pos.getHash(), 0, score, BETA, m); @@ -189,95 +200,120 @@ Score quiescence(Position &pos, Score alpha, Score beta, Ply ply) { ttFlag = EXACT; bestMove = m; } - } - // TODO elo test storing null move instead of bestMove ttSave(pos.getHash(), 0, alpha, ttFlag, bestMove); return alpha; } -Score search(Position &pos, SearchState *state, Depth depth, Score alpha, Score beta, Ply ply) { +template +Score search(Position &pos, SearchStack *stack, Depth depth, Score alpha, Score beta, Ply ply) { - if (shouldEnd()) return UNKNOWN_SCORE; + constexpr bool rootNode = type == ROOT_NODE; + constexpr bool pvNode = type != NON_PV_NODE; + constexpr bool notRootNode = !rootNode; + constexpr bool nonPvNode = !pvNode; + constexpr NodeType nextPv = rootNode ? PV_NODE : type; - if (pos.getMove50() >= 4 && ply > 0 && pos.isRepetition()) return DRAW_VALUE; + if (shouldEnd()) + return UNKNOWN_SCORE; + + if (notRootNode && pos.getMove50() >= 3 && pos.isRepetition()) { + alpha = DRAW_VALUE; + if (alpha >= beta) + return alpha; + } bool ttHit = false; - bool pvNode = beta - alpha > 1; Score matePly = MATE_VALUE - ply; - Score ttScore = ttProbe(pos.getHash(), ttHit, depth, alpha, beta); - if (!pvNode && ttScore != UNKNOWN_SCORE) return ttScore; + TTEntry *ttEntry = ttProbe(pos.getHash(), ttHit, depth, alpha, beta); + + if (ttHit && nonPvNode && + ttEntry->depth >= depth && (ttEntry->flag == EXACT || (ttEntry->flag == ALPHA && ttEntry->eval <= alpha) || (ttEntry->flag == BETA && ttEntry->eval >= beta))) { + return ttEntry->eval; + } // Mate distance pruning - if (ply > 0) { - if (alpha < -matePly) alpha = -matePly; - if (beta > matePly - 1) beta = matePly - 1; - if (alpha >= beta) return alpha; + if (notRootNode) { + if (alpha < -matePly) + alpha = -matePly; + if (beta > matePly - 1) + beta = matePly - 1; + if (alpha >= beta) + return alpha; } - if (depth <= 0) return quiescence(pos, alpha, beta, ply); + if (ply >= MAX_PLY) { + return eval(pos); + } - MoveList moves = {pos, ply, false}; + if (depth <= 0) + return quiescence(pos, alpha, beta, ply); Color color = pos.getSideToMove(); bool inCheck = bool(getAttackers(pos, pos.pieces(color).lsb())); - if (moves.count == 0) { - if (inCheck) { - return -matePly; - } else { - return DRAW_VALUE; - } - } + Score staticEval = stack->eval = eval(pos); - Score staticEval = state->eval = eval(pos); + bool improving = ply >= 2 && staticEval >= (stack - 2)->eval; - if (ply > 0 && !inCheck) { - - bool improving = ply >= 2 && staticEval >= (state - 2)->eval; + if (notRootNode && !inCheck) { // Razoring - if (depth == 1 && !pvNode && staticEval + RAZOR_MARGIN < alpha) { - return quiescence(pos, alpha, beta, ply); + if (depth == 1 && nonPvNode && staticEval + RAZOR_MARGIN < alpha) { + return quiescence(pos, alpha, beta, ply); } // Reverse futility pruning if (depth <= RFP_DEPTH && - staticEval - RFP_DEPTH_MULTIPLIER * (int) depth + RFP_IMPROVING_MULTIPLIER * improving >= beta && + staticEval - RFP_DEPTH_MULTIPLIER * depth + RFP_IMPROVING_MULTIPLIER * improving >= beta && std::abs(beta) < WORST_MATE) return beta; // Null move pruning - if (!pvNode && !(state - 1)->move.isNull() && depth >= NULL_MOVE_DEPTH && staticEval >= beta) { + if (nonPvNode && !(stack - 1)->move.isNull() && depth >= NULL_MOVE_DEPTH && staticEval >= beta) { // We don't want to make a null move in a Zugzwang position if (pos.pieces(color) | pos.pieces(color) | pos.pieces(color) | pos.pieces(color)) { Depth R = NULL_MOVE_BASE_R + depth / NULL_MOVE_R_SCALE; - state->move = Move(); + stack->move = Move(); pos.makeNullMove(); - Score score = -search(pos, state + 1, depth - R, -beta, -beta + 1, ply + 1); + Score score = -search(pos, stack + 1, depth - R, -beta, -beta + 1, ply + 1); pos.undoNullMove(); if (score >= beta) { - if (std::abs(score) > WORST_MATE) return beta; + if (std::abs(score) > WORST_MATE) + return beta; return score; } } } // Internal iterative deepening - if (!ttHit && !pvNode) depth--; + if (!ttHit && pvNode) + depth--; + if (!ttHit && depth >= 5) + depth--; - if (depth <= 0) return quiescence(pos, alpha, beta, ply); + if (depth <= 0) + return quiescence(pos, alpha, beta, ply); } // Check extension if (inCheck) depth++; + MoveList moves = {pos, ply, false}; + if (moves.count == 0) { + if (inCheck) { + return -matePly; + } else { + return DRAW_VALUE; + } + } + Move bestMove; EntryFlag ttFlag = ALPHA; int index = 0; @@ -285,14 +321,20 @@ Score search(Position &pos, SearchState *state, Depth depth, Score alpha, Score while (!moves.empty()) { Move m = moves.nextMove(); - state->move = m; + stack->move = m; Score score; // We can prune the move in some cases - if (ply > 0 && !pvNode && !inCheck && alpha > -WORST_MATE) { + if (notRootNode && nonPvNode && !inCheck && alpha > -WORST_MATE) { + + if (depth <= FUTILITY_DEPTH && m.isQuiet() && + staticEval + FUTILITY_MARGIN + FUTILITY_MARGIN_DEPTH * depth + FUTILITY_MARGIN_IMPROVING * improving < + alpha) + continue; // Late move/movecount pruning + // This will also prune losing captures if (depth <= LMP_DEPTH && index >= LMP_MOVES + depth * depth && m.isQuiet()) break; } @@ -301,32 +343,36 @@ Score search(Position &pos, SearchState *state, Depth depth, Score alpha, Score ttPrefetch(pos.getHash()); - if (index == 0) { - score = -search(pos, state + 1, depth - 1, -beta, -alpha, ply + 1); - } else { - // Late move reduction - if (!inCheck && depth >= LMR_DEPTH && index >= LMR_MIN_I + pvNode * LMR_PVNODE_I && !m.isPromo() && - m.isQuiet() && m != killerMoves[ply][0] && m != killerMoves[ply][1]) { + // Late move reduction + if (!inCheck && depth >= LMR_DEPTH && index >= LMR_INDEX && !m.isPromo() && + m.isQuiet()) { - score = -search(pos, state + 1, depth - reductions[index][depth], -alpha - 1, -alpha, - ply + 1); - } else score = alpha + 1; + Depth R = reductions[index][depth]; + R += improving; + R -= pvNode; - // Principal variation search - if (score > alpha) { - score = -search(pos, state + 1, depth - 1, -alpha - 1, -alpha, ply + 1); + Depth newDepth = std::clamp(depth - R, 1, depth - 1); - if (score > alpha) { - score = -search(pos, state + 1, depth - 1, -beta, -alpha, ply + 1); - } + score = -search(pos, stack + 1, newDepth, + -alpha - 1, -alpha, ply + 1); + + if (score > alpha && R > 1) { + score = -search(pos, stack + 1, depth - 1, -alpha - 1, -alpha, ply + 1); } + } else if (nonPvNode || index != 0) { + score = -search(pos, stack + 1, depth - 1, -alpha - 1, -alpha, ply + 1); + } + + if (pvNode && (index == 0 || (score > alpha && score < beta))) { + score = -search(pos, stack + 1, depth - 1, -beta, -alpha, ply + 1); } pos.undoMove(m); - if (shouldEnd()) return UNKNOWN_SCORE; + if (shouldEnd()) + return UNKNOWN_SCORE; if (score >= beta) { @@ -370,7 +416,7 @@ Score searchRoot(Position &pos, Score prevScore, Depth depth, bool uci) { globalAge++; clearTables(); selectiveDepth = 0; - SearchState stateStack[100]; + SearchStack stateStack[MAX_PLY + 1]; Score alpha = -INF_SCORE; Score beta = INF_SCORE; @@ -381,14 +427,18 @@ Score searchRoot(Position &pos, Score prevScore, Depth depth, bool uci) { int iter = 1; while (true) { - if (shouldEnd()) return UNKNOWN_SCORE; + if (shouldEnd()) + return UNKNOWN_SCORE; - if (alpha < -ASPIRATION_BOUND) alpha = -INF_SCORE; - if (beta > ASPIRATION_BOUND) beta = INF_SCORE; + if (alpha < -ASPIRATION_BOUND) + alpha = -INF_SCORE; + if (beta > ASPIRATION_BOUND) + beta = INF_SCORE; - Score score = search(pos, stateStack + 1, depth, alpha, beta, 0); + Score score = search(pos, stateStack + 1, depth, alpha, beta, 0); - if (score == UNKNOWN_SCORE) return UNKNOWN_SCORE; + if (score == UNKNOWN_SCORE) + return UNKNOWN_SCORE; if (score <= alpha) { alpha = std::max(alpha - iter * iter * ASPIRATION_DELTA, -INF_SCORE); @@ -426,12 +476,10 @@ Score searchRoot(Position &pos, Score prevScore, Depth depth, bool uci) { } } -void iterativeDeepening(Position pos, Depth depth, bool uci, std::atomic &searchRunning) { +void iterativeDeepening(Position pos, Depth depth, bool uci) { pos.getState()->accumulator.refresh(pos); - searchRunning = true; - Score prevScore; Move bestMove; @@ -439,12 +487,13 @@ void iterativeDeepening(Position pos, Depth depth, bool uci, std::atomic & for (Depth currDepth = 1; currDepth <= depth; currDepth++) { Score score = searchRoot(pos, prevScore, currDepth, uci); - if (score == UNKNOWN_SCORE) break; + if (score == UNKNOWN_SCORE) + break; // We only care about stability if we searched enough depth - if (currDepth >= 12) { + if (currDepth >= 16) { if (bestMove != bestPV) { - stability -= 6; + stability -= 10; } else { if (std::abs(prevScore - score) >= std::max(prevScore / 10, 50)) { stability -= 4; @@ -464,5 +513,31 @@ void iterativeDeepening(Position pos, Depth depth, bool uci, std::atomic & out("bestmove", bestMove); } - searchRunning = false; + searchStopped() = true; +} + +#include + +std::thread th; + +void joinThread(bool waitToFinish) { + if (!waitToFinish) + stopSearch(); + + if (th.joinable()) + th.join(); +} + +void startSearch(SearchInfo &searchInfo, Position &pos, int threadCount) { + + joinThread(false); + + Color stm = pos.getSideToMove(); + if (stm == WHITE) { + initTimeMan(searchInfo.wtime, searchInfo.winc, searchInfo.movestogo, searchInfo.movetime, searchInfo.maxNodes); + } else { + initTimeMan(searchInfo.btime, searchInfo.binc, searchInfo.movestogo, searchInfo.movetime, searchInfo.maxNodes); + } + + th = std::thread(iterativeDeepening, pos, searchInfo.maxDepth, searchInfo.uciMode); } \ No newline at end of file diff --git a/src/search.h b/src/search.h index 1fbc19d..61459dc 100644 --- a/src/search.h +++ b/src/search.h @@ -17,8 +17,9 @@ #ifndef BLACKCORE_SEARCH_H #define BLACKCORE_SEARCH_H -#include #include "movegen.h" +#include "uci.h" +#include #ifdef TUNE @@ -37,8 +38,7 @@ extern Depth NULL_MOVE_R_SCALE; extern Depth LMR_DEPTH; extern double LMR_BASE; extern double LMR_SCALE; -extern int LMR_MIN_I; -extern int LMR_PVNODE_I; +extern int LMR_INDEX; extern Depth LMP_DEPTH; extern int LMP_MOVES; @@ -51,27 +51,31 @@ extern Score SEE_MARGIN; #else -constexpr Score DELTA_MARGIN = 307; +constexpr Score DELTA_MARGIN = 252; -constexpr Score RAZOR_MARGIN = 146; +constexpr Score RAZOR_MARGIN = 155; constexpr Depth RFP_DEPTH = 8; -constexpr Score RFP_DEPTH_MULTIPLIER = 60; -constexpr Score RFP_IMPROVING_MULTIPLIER = 56; +constexpr Score RFP_DEPTH_MULTIPLIER = 42; +constexpr Score RFP_IMPROVING_MULTIPLIER = 66; constexpr Depth NULL_MOVE_DEPTH = 2; -constexpr Depth NULL_MOVE_BASE_R = 3; -constexpr Depth NULL_MOVE_R_SCALE = 3; +constexpr Depth NULL_MOVE_BASE_R = 4; +constexpr Depth NULL_MOVE_R_SCALE = 2; constexpr Depth LMR_DEPTH = 3; constexpr double LMR_BASE = 1; -constexpr double LMR_SCALE = 1.75; -constexpr int LMR_MIN_I = 2; -constexpr int LMR_PVNODE_I = 1; +constexpr double LMR_SCALE = 1.65; +constexpr int LMR_INDEX = 2; constexpr Depth LMP_DEPTH = 4; constexpr int LMP_MOVES = 5; +constexpr Depth FUTILITY_DEPTH = 3; +constexpr Score FUTILITY_MARGIN = 30; +constexpr Score FUTILITY_MARGIN_DEPTH = 60; +constexpr Score FUTILITY_MARGIN_IMPROVING = 80; + constexpr Depth ASPIRATION_DEPTH = 9; constexpr Score ASPIRATION_DELTA = 28; constexpr Score ASPIRATION_BOUND = 3000; @@ -80,7 +84,7 @@ constexpr Score SEE_MARGIN = 2; #endif -struct SearchState { +struct SearchStack { Move move; Score eval = 0; }; @@ -95,6 +99,8 @@ inline void initSearch() { Score see(const Position &pos, Move move); -void iterativeDeepening(Position pos, Depth depth, bool uci, std::atomic &searchRunning); +void joinThread(bool waitToFinish); + +void startSearch(SearchInfo &searchInfo, Position &pos, int threadCount); -#endif //BLACKCORE_SEARCH_H +#endif//BLACKCORE_SEARCH_H diff --git a/src/timeman.cpp b/src/timeman.cpp index 0dccf57..1e0a515 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -16,50 +16,49 @@ #include "timeman.h" #include "position.h" - #include unsigned int MOVE_OVERHEAD = 10; -constexpr U64 mask = (1ULL << 15) - 1; - -U64 startedSearch; -U64 shouldSearch; -U64 searchTime; -U64 maxSearch; -U64 stabilityTime; +constexpr U64 mask = 1023; +U64 startedSearch, shouldSearch, searchTime, maxSearch, stabilityTime, maxNodes; -bool stop = false; +bool stopping = true; +bool stopped = true; U64 getTime() { return std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()).count(); + std::chrono::system_clock::now().time_since_epoch()) + .count(); } -void startSearch(U64 time, U64 inc, U64 movesToGo, U64 moveTime) { +void initTimeMan(U64 time, U64 inc, U64 movesToGo, U64 moveTime, U64 nodes) { nodeCount = 0; - movesToGo = movesToGo == 0 ? 15 : movesToGo; + movesToGo = movesToGo == 0 ? 20 : movesToGo + 1; startedSearch = getTime(); stabilityTime = 0; - stop = false; + stopping = false; + stopped = false; - if (time == 0) { - // We have infinite time - shouldSearch = 0; - maxSearch = 0; - } else if (moveTime != 0) { + maxNodes = nodes; + + if (moveTime != 0) { // We are limited how much can we search shouldSearch = moveTime - MOVE_OVERHEAD; maxSearch = moveTime - MOVE_OVERHEAD; + } else if (time == 0) { + // We have infinite time + shouldSearch = 0; + maxSearch = 0; } else { U64 panicTime = time / (movesToGo + 10) + 2 * inc; - stabilityTime = time / 400; + stabilityTime = time / 500; - shouldSearch = std::min(time - MOVE_OVERHEAD, time / (movesToGo + 5) + inc * 3 / 4 - MOVE_OVERHEAD); + shouldSearch = std::min(time - MOVE_OVERHEAD, time / movesToGo + inc * 3 / 4 - MOVE_OVERHEAD); maxSearch = std::min(time - MOVE_OVERHEAD, shouldSearch + panicTime); } @@ -67,7 +66,11 @@ void startSearch(U64 time, U64 inc, U64 movesToGo, U64 moveTime) { } void stopSearch() { - stop = true; + stopping = true; +} + +bool &searchStopped() { + return stopped; } void allocateTime(int stability) { @@ -76,10 +79,10 @@ void allocateTime(int stability) { } bool shouldEnd() { - if ((nodeCount & mask) == 0 && maxSearch != 0 && !stop) { - stop = getSearchTime() >= searchTime; + if ((nodeCount & mask) == 0 && !stopping) { + stopping = (maxSearch != 0 && getSearchTime() >= searchTime) || (maxNodes != 0 && nodeCount > maxNodes); } - return stop; + return stopping; } U64 getSearchTime() { diff --git a/src/timeman.h b/src/timeman.h index 8dbb40f..ef6d339 100644 --- a/src/timeman.h +++ b/src/timeman.h @@ -21,16 +21,18 @@ extern unsigned int MOVE_OVERHEAD; -void startSearch(U64 time, U64 inc, U64 movesToGo, U64 moveTime); +void initTimeMan(U64 time, U64 inc, U64 movesToGo, U64 moveTime, U64 nodes); bool shouldEnd(); void stopSearch(); +bool &searchStopped(); + void allocateTime(int stability); U64 getSearchTime(); U64 getNps(); -#endif //BLACKCORE_TIMEMAN_H +#endif//BLACKCORE_TIMEMAN_H diff --git a/src/tt.cpp b/src/tt.cpp index 5ff7476..3e8273e 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -14,8 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include #include "tt.h" +#include #ifdef __linux__ @@ -45,12 +45,12 @@ void ttResize(unsigned int MBSize) { ttFree(); unsigned int i = 10; - while ((1ULL << i) <= MBSize * 1024 * 1024 / sizeof(TTBucket)) i++; + while ((1ULL << i) <= MBSize * 1024 * 1024 / sizeof(TTBucket)) + i++; tt.bucketCount = (1ULL << (i - 1)); tt.mask = tt.bucketCount - 1ULL; - #ifdef __linux__ // Allocate memory with 1MB alignment tt.table = static_cast(aligned_alloc((1ULL << 20), tt.bucketCount * sizeof(TTBucket))); @@ -58,14 +58,13 @@ void ttResize(unsigned int MBSize) { // For reference see https://man7.org/linux/man-pages/man2/madvise.2.html on MADV HUGEPAGE madvise(tt.table, tt.bucketCount * sizeof(TTBucket), MADV_HUGEPAGE); #else - tt.table = (TTBucket*)malloc(tt.bucketCount * sizeof(TTBucket)); + tt.table = (TTBucket *) malloc(tt.bucketCount * sizeof(TTBucket)); #endif ttClear(); - } -Score ttProbe(U64 hash, bool &ttHit, Depth depth, Score alpha, Score beta) { +TTEntry *ttProbe(U64 hash, bool &ttHit, Depth depth, Score alpha, Score beta) { TTBucket *bucket = getBucket(hash); TTEntry *entry; if (bucket->entryA.hash == hash) { @@ -74,25 +73,14 @@ Score ttProbe(U64 hash, bool &ttHit, Depth depth, Score alpha, Score beta) { } else if (bucket->entryB.hash == hash) { entry = &bucket->entryB; } else { - return UNKNOWN_SCORE; + return nullptr; } - ttHit = true; - if (std::abs(entry->eval) > MATE_VALUE - 100) return UNKNOWN_SCORE; - - if (entry->depth >= depth) { - if (entry->flag == EXACT) { - return entry->eval; - } - if (entry->flag == ALPHA && entry->eval <= alpha) { - return alpha; - } - if (entry->flag == BETA && entry->eval >= beta) { - return beta; - } - } + if (std::abs(entry->eval) > MATE_VALUE - 100) + return nullptr; - return UNKNOWN_SCORE; + ttHit = true; + return entry; } void ttSave(U64 hash, Depth depth, Score eval, EntryFlag flag, Move bestMove) { @@ -114,13 +102,14 @@ void ttSave(U64 hash, Depth depth, Score eval, EntryFlag flag, Move bestMove) { entry->hashMove = bestMove; entry->age = globalAge; } - } Move getHashMove(U64 hash) { TTBucket *bucket = getBucket(hash); - if (bucket->entryA.hash == hash) return bucket->entryA.hashMove; - else if (bucket->entryB.hash == hash) return bucket->entryB.hashMove; + if (bucket->entryA.hash == hash) + return bucket->entryA.hashMove; + else if (bucket->entryB.hash == hash) + return bucket->entryB.hashMove; return {}; } diff --git a/src/tt.h b/src/tt.h index d7d9434..0c4582f 100644 --- a/src/tt.h +++ b/src/tt.h @@ -23,22 +23,25 @@ extern uint16_t globalAge; enum EntryFlag : uint16_t { - NONE = 0, EXACT = 1, ALPHA = 2, BETA = 3 + NONE = 0, + EXACT = 1, + ALPHA = 2, + BETA = 3 }; -struct TTEntry { // Total: 21 bytes -> compiler makes it 24 - U64 hash; // 8 bytes - Depth depth; // 4 bytes - Score eval; // 4 bytes - Move hashMove; // 2 bytes - EntryFlag flag; // 1 bytes - uint16_t age; // 2 bytes +struct TTEntry { // Total: 21 bytes -> compiler makes it 24 + U64 hash; // 8 bytes + Depth depth; // 4 bytes + Score eval; // 4 bytes + Move hashMove; // 2 bytes + EntryFlag flag;// 1 bytes + uint16_t age; // 2 bytes }; -struct TTBucket { // 64 bytes - TTEntry entryA; // 24 bytes - TTEntry entryB; // 24 bytes - U64 _padding1, _padding2; // 16 bytes +struct TTBucket { // 64 bytes + TTEntry entryA; // 24 bytes + TTEntry entryB; // 24 bytes + U64 _padding1, _padding2;// 16 bytes }; struct TTable { @@ -53,7 +56,7 @@ void ttClear(); void ttFree(); -Score ttProbe(U64 hash, bool &ttHit, Depth depth, Score alpha, Score beta); +TTEntry *ttProbe(U64 hash, bool &ttHit, Depth depth, Score alpha, Score beta); void ttSave(U64 hash, Depth depth, Score eval, EntryFlag flag, Move bestMove); @@ -61,4 +64,4 @@ Move getHashMove(U64 hash); void ttPrefetch(U64 hash); -#endif //BLACKCORE_TT_H +#endif//BLACKCORE_TT_H diff --git a/src/tuner.cpp b/src/tuner.cpp index 79f4e4c..f41a5f9 100644 --- a/src/tuner.cpp +++ b/src/tuner.cpp @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include -#include -#include #include "tuner.h" #include "eval.h" +#include +#include +#include double K = 0.2; @@ -37,13 +37,11 @@ double E(const std::vector &data) { double predicted = 1 / double(1 + pow(10, -K * score / 400)); error += (entry.result - predicted) * (entry.result - predicted); - } error /= double(data.size()); return error; - } void saveResults(const unsigned int paramCnt, EvalParameter *evalParameters) { @@ -83,7 +81,6 @@ void saveResults(const unsigned int paramCnt, EvalParameter *evalParameters) { params << "\t"; } } - } params << "};\n"; } @@ -135,8 +132,7 @@ void tune(const std::string &inputFile) { const unsigned int PSQTparamCnt = 768; const unsigned int paramCnt = 0; - EvalParameter params[paramCnt] = { - }; + EvalParameter params[paramCnt] = {}; while (improved) { diff --git a/src/tuner.h b/src/tuner.h index ec118c4..6a48381 100644 --- a/src/tuner.h +++ b/src/tuner.h @@ -17,11 +17,11 @@ #ifndef BLACKCORE_TUNER_H #define BLACKCORE_TUNER_H -#include -#include +#include "position.h" #include #include -#include "position.h" +#include +#include struct DataEntry { RawState pos; @@ -36,4 +36,4 @@ struct EvalParameter { void tune(const std::string &inputFile); -#endif //BLACKCORE_TUNER_H +#endif//BLACKCORE_TUNER_H diff --git a/src/uci.cpp b/src/uci.cpp index 01ca1a2..9927bce 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -14,15 +14,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include -#include -#include #include "uci.h" -#include "tt.h" +#include "bench.h" +#include "eval.h" +#include "position.h" #include "search.h" #include "timeman.h" -#include "position.h" -#include "bench.h" +#include "tt.h" +#include +#include Move stringToMove(const Position &pos, const std::string &s) { Square from = stringToSquare(s.substr(0, 2)); @@ -67,12 +67,16 @@ Move stringToMove(const Position &pos, const std::string &s) { void uciLoop() { // Identifying ourselves - out("id", "name", "BlackCore_v2-0-H1"); +#ifdef VERSION + out("id", "name", "BlackCore", VERSION); +#else + out("id", "name", "BlackCore"); +#endif out("id", "author", "SzilBalazs"); // We tell the GUI what options we have - out("option", "name", "Hash", "type", "spin", "default", 16, "min", 1, "max", 1024); + out("option", "name", "Hash", "type", "spin", "default", 32, "min", 1, "max", 4096); out("option", "name", "Threads", "type", "spin", "default", 1, "min", 1, "max", 1); out("option", "name", "Ponder", "type", "check", "default", "false"); out("option", "name", "Move Overhead", "type", "spin", "default", 10, "min", 0, "max", 10000); @@ -80,28 +84,29 @@ void uciLoop() { #ifdef TUNE tuneOut("DELTA_MARGIN", 400, 200, 500); tuneOut("RAZOR_MARGIN", 130, 50, 200); - tuneOut("RFP_DEPTH", 5, 3, 8); + tuneOut("RFP_DEPTH", 5, 3, 10); tuneOut("RFP_DEPTH_MULTIPLIER", 70, 30, 200); tuneOut("RFP_IMPROVING_MULTIPLIER", 80, 30, 200); tuneOut("NULL_MOVE_DEPTH", 3, 1, 6); tuneOut("NULL_MOVE_BASE_R", 4, 2, 6); tuneOut("NULL_MOVE_R_SCALE", 5, 2, 10); tuneOut("LMR_DEPTH", 4, 2, 10); - tuneOut("LMR_MIN_I", 3, 1, 10); - tuneOut("LMR_PVNODE_I", 2, 1, 10); + tuneOut("LMR_INDEX", 3, 1, 10); tuneOut("LMP_DEPTH", 4, 1, 10); tuneOut("LMP_MOVES", 5, 1, 10); tuneOut("ASPIRATION_DEPTH", 9, 5, 20); tuneOut("ASPIRATION_DELTA", 30, 10, 100); tuneOut("SEE_MARGIN", 0, 0, 200); tuneOut("PAWN_VALUE", 150, 100, 200); - tuneOut("KNIGHT_VALUE", 750, 500, 1000); - tuneOut("BISHOP_VALUE", 850, 500, 1000); - tuneOut("ROOK_VALUE", 1250, 1000, 1500); - tuneOut("QUEEN_VALUE", 1600, 1200, 2000); + tuneOut("KNIGHT_VALUE", 750, 300, 1000); + tuneOut("BISHOP_VALUE", 850, 300, 1000); + tuneOut("ROOK_VALUE", 800, 300, 1000); + tuneOut("QUEEN_VALUE", 1000, 500, 1500); + tuneOut("LMR_BASE", 10, 1, 30); + tuneOut("LMR_SCALE", 17, 10, 40); #endif - ttResize(16); + ttResize(32); // We have sent all the parameters out("uciok"); @@ -110,9 +115,7 @@ void uciLoop() { initSearch(); Position pos = {STARTING_FEN}; - std::thread searchThread; - - std::atomic searchRunning(false); + int threadCount = 1; while (true) { std::string line, command, token; @@ -130,10 +133,10 @@ void uciLoop() { if (command == "isready") { out("readyok"); } else if (command == "quit") { - stopSearch(); + joinThread(false); break; } else if (command == "stop") { - stopSearch(); + joinThread(false); } else if (command == "ucinewgame") { ttClear(); } else if (command == "setoption") { @@ -164,10 +167,8 @@ void uciLoop() { NULL_MOVE_R_SCALE = std::stoi(tokens[3]); } else if (tokens[1] == "LMR_DEPTH") { LMR_DEPTH = std::stoi(tokens[3]); - } else if (tokens[1] == "LMR_MIN_I") { - LMR_MIN_I = std::stoi(tokens[3]); - } else if (tokens[1] == "LMR_PVNODE_I") { - LMR_PVNODE_I = std::stoi(tokens[3]); + } else if (tokens[1] == "LMR_INDEX") { + LMR_INDEX = std::stoi(tokens[3]); } else if (tokens[1] == "LMP_DEPTH") { LMP_DEPTH = std::stoi(tokens[3]); } else if (tokens[1] == "LMP_MOVES") { @@ -188,6 +189,10 @@ void uciLoop() { PIECE_VALUES[ROOK] = std::stoi(tokens[3]); } else if (tokens[1] == "QUEEN_VALUE") { PIECE_VALUES[QUEEN] = std::stoi(tokens[3]); + } else if (tokens[1] == "LMR_BASE") { + LMR_BASE = double(std::stoi(tokens[3])) / 10; + } else if (tokens[1] == "LMR_SCALE") { + LMR_SCALE = double(std::stoi(tokens[3])) / 10; } #endif } @@ -208,7 +213,8 @@ void uciLoop() { unsigned int i = 0; bool move = false; while (i < tokens.size()) { - if (tokens[i] == "moves") move = true; + if (tokens[i] == "moves") + move = true; else if (move) { pos.makeMove(stringToMove(pos, tokens[i])); } @@ -220,41 +226,30 @@ void uciLoop() { } else if (command == "go") { - if (searchRunning) { - out("Search is already running!", "To stop it use the \"stop\" command."); - continue; - } - - U64 wtime = 0, btime = 0, winc = 0, binc = 0, movestogo = 0, movetime = 0; - Depth depth = 64; + SearchInfo searchInfo; for (unsigned int i = 0; i < tokens.size(); i += 2) { if (tokens[i] == "wtime") { - wtime = std::stoi(tokens[i + 1]); + searchInfo.wtime = std::stoi(tokens[i + 1]); } else if (tokens[i] == "btime") { - btime = std::stoi(tokens[i + 1]); + searchInfo.btime = std::stoi(tokens[i + 1]); } else if (tokens[i] == "winc") { - winc = std::stoi(tokens[i + 1]); + searchInfo.winc = std::stoi(tokens[i + 1]); } else if (tokens[i] == "binc") { - binc = std::stoi(tokens[i + 1]); + searchInfo.binc = std::stoi(tokens[i + 1]); } else if (tokens[i] == "movestogo") { - movestogo = std::stoi(tokens[i + 1]); + searchInfo.movestogo = std::stoi(tokens[i + 1]); } else if (tokens[i] == "depth") { - depth = std::stoi(tokens[i + 1]); + searchInfo.maxDepth = std::stoi(tokens[i + 1]); } else if (tokens[i] == "movetime") { - movetime = std::stoi(tokens[i + 1]); + searchInfo.movetime = std::stoi(tokens[i + 1]); + } else if (tokens[i] == "nodes") { + searchInfo.maxNodes = std::stoi(tokens[i + 1]); } else if (tokens[i] == "infinite") { - depth = 64; } } - if (pos.getSideToMove() == WHITE) - startSearch(wtime, winc, movestogo, movetime); - else - startSearch(btime, binc, movestogo, movetime); - - searchThread = std::thread(iterativeDeepening, pos, depth, true, std::ref(searchRunning)); - searchThread.detach(); + startSearch(searchInfo, pos, threadCount); } else if (command == "d" || command == "display") { pos.display(); diff --git a/src/uci.h b/src/uci.h index 2479f5e..0a1c15c 100644 --- a/src/uci.h +++ b/src/uci.h @@ -17,22 +17,31 @@ #ifndef BLACKCORE_UCI_H #define BLACKCORE_UCI_H +#include "constants.h" #include -inline void _out() { - std::cout << std::endl; -} +struct SearchInfo { + U64 wtime = 0, btime = 0, winc = 0, binc = 0, movestogo = 0, movetime = 0, maxNodes = 0; + Depth maxDepth = MAX_PLY; + bool uciMode = true; +}; -template -inline void _out(T a, Args... args) { - std::cout << " " << a; - _out(args...); -} +namespace BlackCore { + inline void _out() { + std::cout << std::endl; + } + + template + inline void _out(T a, Args... args) { + std::cout << " " << a; + _out(args...); + } +}// namespace BlackCore template inline void out(T a, Args... args) { std::cout << a; - _out(args...); + BlackCore::_out(args...); } inline void tuneOut(const std::string &name, int value, int min, int max) { @@ -43,4 +52,4 @@ inline void tuneOut(const std::string &name, int value, int min, int max) { void uciLoop(); -#endif //BLACKCORE_UCI_H +#endif//BLACKCORE_UCI_H diff --git a/src/utils.cpp b/src/utils.cpp index bc5ca08..dc7f64b 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include "utils.h" #include #include -#include "utils.h" std::string formatSquare(Square square) { return std::string() + (char) ('a' + (char) square % 8) + (char) ('1' + (char) (square / 8)); @@ -46,7 +46,8 @@ char pieceToChar(Piece piece) { default: base = ' '; } - if (base != ' ' && piece.color == WHITE) base -= 32; + if (base != ' ' && piece.color == WHITE) + base -= 32; return base; } @@ -112,7 +113,8 @@ void displayBB(Bitboard b) { } std::cout << "\n"; } - std::cout << " +---+---+---+---+---+---+---+---+\n\n" << std::endl; + std::cout << " +---+---+---+---+---+---+---+---+\n\n" + << std::endl; } // source: https://web.archive.org/web/20071031100138/http://www.brucemo.com/compchess/programming/zobrist.htm diff --git a/src/utils.h b/src/utils.h index 1850201..9ae61d3 100644 --- a/src/utils.h +++ b/src/utils.h @@ -17,30 +17,40 @@ #ifndef BLACKCORE_UTILS_H #define BLACKCORE_UTILS_H -#include -#include "constants.h" #include "bitboard.h" +#include "constants.h" +#include constexpr PieceType indexToType[7] = {KING, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, PIECE_EMPTY}; constexpr Color indexToColor[3] = {WHITE, BLACK, COLOR_EMPTY}; template constexpr Color EnemyColor() { - if constexpr (color == WHITE) return BLACK; - else return WHITE; + if constexpr (color == WHITE) + return BLACK; + else + return WHITE; } -inline Color EnemyColor(Color color) { return color == WHITE ? BLACK : WHITE; } +inline Color EnemyColor(Color color) { + return color == WHITE ? BLACK : WHITE; +} -constexpr unsigned int squareToRank(Square square) { return square >> 3; } +constexpr unsigned int squareToRank(Square square) { + return square >> 3; +} -constexpr unsigned int squareToFile(Square square) { return square & 7; } +constexpr unsigned int squareToFile(Square square) { + return square & 7; +} constexpr Square mirrorSquare(Square square) { return Square(56 - square + squareToFile(square)); } -constexpr unsigned char encodePiece(Piece piece) { return (piece.color << 3) | piece.type; } +constexpr unsigned char encodePiece(Piece piece) { + return (piece.color << 3) | piece.type; +} constexpr Piece decodePiece(unsigned char encodedPiece) { return {indexToType[encodedPiece & 7], indexToColor[encodedPiece >> 3]}; @@ -60,4 +70,4 @@ Bitboard randBB(); std::string BBToHex(Bitboard bb); -#endif //BLACKCORE_UTILS_H +#endif//BLACKCORE_UTILS_H