stellar

Stellar - UCI Chess engine written in C++20
git clone git://git.dimitrijedobrota.com/stellar.git
Log | Files | Refs | README | LICENSE

commit 664eeb29d4722c4663863878105d1561ce7d9bb4
parent 75e27270d7d82dceb3274989abbe149546584541
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Mon, 11 Mar 2024 18:55:44 +0100

Merge pull request #2 from DimitrijeDobrota/1-windows-exe

Solved: 1 windows exe
Diffstat:
MCMakeLists.txt | 43+++++++++----------------------------------
Msrc/arena/arena.cpp | 3+++
Msrc/arena/engine.hpp | 2++
Msrc/arena/logger.hpp | 1+
Msrc/attack/CMakeLists.txt | 13+------------
Msrc/attack/attack.cpp | 9+++++++++
Msrc/attack/attack.hpp | 4++--
Asrc/attack/bishop.cpp | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/attack/bishop.hpp | 95++++---------------------------------------------------------------------------
Msrc/attack/queen.hpp | 2+-
Asrc/attack/rook.cpp | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/attack/rook.hpp | 91++-----------------------------------------------------------------------------
Msrc/attack/slider.hpp | 2++
Msrc/board/CMakeLists.txt | 3---
Msrc/board/board.cpp | 12++++++++----
Msrc/board/board.hpp | 23++++++++++++-----------
Msrc/board/zobrist.hpp | 81+++++++++++++++++++++++++++++++++----------------------------------------------
Msrc/engine/CMakeLists.txt | 1+
Msrc/engine/engine.cpp | 10++++++----
Msrc/move/move.cpp | 4++--
Msrc/perft/CMakeLists.txt | 4----
Msrc/perft/perft.cpp | 3+++
Msrc/piece/CMakeLists.txt | 2--
Msrc/random/CMakeLists.txt | 1-
Msrc/utils/CMakeLists.txt | 6------
Msrc/utils/bit.hpp | 23+++--------------------
Msrc/utils/timer.hpp | 7+++----
27 files changed, 295 insertions(+), 337 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project( Stellar - VERSION 1.2.0 + VERSION 1.2.6 DESCRIPTION "Chess engine written in C++" HOMEPAGE_URL https://git.dimitrijedobrota.com/stellar.git LANGUAGES CXX @@ -25,39 +25,14 @@ set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING FORCE ) +add_subdirectory(src) -include(CheckCXXCompilerFlag) - -option(STELLAR_ENABLE_PCH "Build using pre-compiled headers" ON) -function(stellar_target_precompile_headers) - if(STELLAR_ENABLE_PCH) - target_precompile_headers(${ARGV}) - endif() -endfunction() - -CHECK_CXX_COMPILER_FLAG("-flto" COMPILER_SUPPORTS_LTO) -if(COMPILER_SUPPORTS_LTO) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") -endif() - -CHECK_CXX_COMPILER_FLAG("-fno-fat-lto-objects" COMPILER_SUPPORTS_LTO_NOFAT) -if(COMPILER_SUPPORTS_LTO_NOFAT) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-fat-lto-objects") -endif() - -CHECK_CXX_COMPILER_FLAG("-fconstexpr-ops-limit=10000000000" COMPILER_SUPPORTS_CONSTEXPR_OPS_LIMIT) -if(COMPILER_SUPPORTS_CONSTEXPR_OPS_LIMIT) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fconstexpr-ops-limit=1000000000") -endif() - -CHECK_CXX_COMPILER_FLAG("-fconstexpr-steps=1000000000" COMPILER_SUPPORTS_CONSTEXPR_STEPS) -if(COMPILER_SUPPORTS_CONSTEXPR_STEPS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fconstexpr-steps=1000000000") -endif() +include(CheckIPOSupported) +check_ipo_supported(RESULT lto_supported OUTPUT lto_error) -CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE) -if(COMPILER_SUPPORTS_MARCH_NATIVE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") +if( lto_supported ) + message(STATUS "IPO / LTO enabled") + set_property(TARGET engine PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) +else() + message(STATUS "IPO / LTO not supported: <${error}>") endif() - -add_subdirectory(src) diff --git a/src/arena/arena.cpp b/src/arena/arena.cpp @@ -7,6 +7,7 @@ #include <bits/getopt_core.h> #include <stdexcept> +#include "attack.hpp" #include "logger.hpp" #include "match.hpp" @@ -95,6 +96,8 @@ int main(int argc, char *argv[]) { for (int i = optind; i < argc; i++) positions.emplace_back(!strcmp(argv[i], "-") ? start_position : argv[i]); + attack::init(); + zobrist::init(); Arena arena(engine1, engine2); arena(positions, settings1, settings2); diff --git a/src/arena/engine.hpp b/src/arena/engine.hpp @@ -1,7 +1,9 @@ #ifndef STELLAR_ARENA_ENGINE_H #define STELLAR_ARENA_ENGINE_H +#include <cstdint> #include <queue> +#include <string> class Engine { public: diff --git a/src/arena/logger.hpp b/src/arena/logger.hpp @@ -5,6 +5,7 @@ #include <cerrno> #include <cstring> #include <format> +#include <iostream> namespace logger { diff --git a/src/attack/CMakeLists.txt b/src/attack/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(attack attack.cpp) +add_library(attack attack.cpp bishop.cpp rook.cpp) target_link_libraries(attack PRIVATE bit @@ -9,14 +9,3 @@ target_link_libraries(attack ) target_include_directories(attack INTERFACE .) - -stellar_target_precompile_headers(attack - PRIVATE "bishop.hpp" - PRIVATE "king.hpp" - PRIVATE "knight.hpp" - PRIVATE "pawnb.hpp" - PRIVATE "pawnw.hpp" - PRIVATE "queen.hpp" - PRIVATE "rook.hpp" - PRIVATE "slider.hpp" -) diff --git a/src/attack/attack.cpp b/src/attack/attack.cpp @@ -1 +1,10 @@ #include "attack.hpp" + +namespace attack { + +void init(void) { + bishop::init(); + rook::init(); +} + +} // namespace attack diff --git a/src/attack/attack.hpp b/src/attack/attack.hpp @@ -11,12 +11,12 @@ #include "pawnw.hpp" #include "queen.hpp" #include "rook.hpp" -#include "slider.hpp" namespace attack { +void init(void); using attack_f = U64 (*)(const square::Square, U64); -} +} // namespace attack #endif diff --git a/src/attack/bishop.cpp b/src/attack/bishop.cpp @@ -0,0 +1,94 @@ +#include "bishop.hpp" +#include "bit.hpp" +#include "bitboard.hpp" +#include "slider.hpp" + +#include <array> +#include <iostream> + +namespace attack { +namespace bishop { + +inline constexpr const U64 bishop_magic_numbers[64] = { + C64(0x40040844404084), C64(0x2004208a004208), C64(0x10190041080202), C64(0x108060845042010), + C64(0x581104180800210), C64(0x2112080446200010), C64(0x1080820820060210), C64(0x3c0808410220200), + C64(0x4050404440404), C64(0x21001420088), C64(0x24d0080801082102), C64(0x1020a0a020400), + C64(0x40308200402), C64(0x4011002100800), C64(0x401484104104005), C64(0x801010402020200), + C64(0x400210c3880100), C64(0x404022024108200), C64(0x810018200204102), C64(0x4002801a02003), + C64(0x85040820080400), C64(0x810102c808880400), C64(0xe900410884800), C64(0x8002020480840102), + C64(0x220200865090201), C64(0x2010100a02021202), C64(0x152048408022401), C64(0x20080002081110), + C64(0x4001001021004000), C64(0x800040400a011002), C64(0xe4004081011002), C64(0x1c004001012080), + C64(0x8004200962a00220), C64(0x8422100208500202), C64(0x2000402200300c08), C64(0x8646020080080080), + C64(0x80020a0200100808), C64(0x2010004880111000), C64(0x623000a080011400), C64(0x42008c0340209202), + C64(0x209188240001000), C64(0x400408a884001800), C64(0x110400a6080400), C64(0x1840060a44020800), + C64(0x90080104000041), C64(0x201011000808101), C64(0x1a2208080504f080), C64(0x8012020600211212), + C64(0x500861011240000), C64(0x180806108200800), C64(0x4000020e01040044), C64(0x300000261044000a), + C64(0x802241102020002), C64(0x20906061210001), C64(0x5a84841004010310), C64(0x4010801011c04), + C64(0xa010109502200), C64(0x4a02012000), C64(0x500201010098b028), C64(0x8040002811040900), + C64(0x28000010020204), C64(0x6000020202d0240), C64(0x8918844842082200), C64(0x4010011029020020), +}; + +static inline constexpr const int relevant_bits[64] = { + // clang-format off + 6, 5, 5, 5, 5, 5, 5, 6, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 7, 7, 7, 7, 5, 5, + 5, 5, 7, 9, 9, 7, 5, 5, + 5, 5, 7, 9, 9, 7, 5, 5, + 5, 5, 7, 7, 7, 7, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 5, 5, 5, 5, 5, 5, 6, + // clang-format on +}; + +inline constexpr const bitboard::direction_f dir[4] = {bitboard::noEaOne, bitboard::noWeOne, + bitboard::soEaOne, bitboard::soWeOne}; + +inline constexpr U32 hash(const U64 key, const square::Square square) { + uint8_t square_i = to_underlying(square); + return (key * bishop_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]); +} + +inline constexpr U64 mask_fly(const square::Square square, U64 block) { + uint8_t square_i = to_underlying(square); + int tr = square_i / 8, tf = square_i % 8; + int len[4] = {std::min(7 - tf, 7 - tr), std::min(tf, 7 - tr), std::min(7 - tf, tr), std::min(tf, tr)}; + + return attack::slider::mask(square, block, dir, len); +} + +std::array<U64, 64> masks = {{0}}; +inline U64 mask(const square::Square square) { return masks[to_underlying(square)]; } + +std::array<std::array<U64, 4098>, 64> attacks = {{{0}}}; + +void init(void) { + for (uint8_t square = 0; square < 64; square++) { + int tr = square / 8, tf = square % 8; + int len[4] = {std::min(7 - tf, 7 - tr) - 1, std::min(tf, 7 - tr) - 1, std::min(7 - tf, tr) - 1, + std::min(tf, tr) - 1}; + masks[square] = attack::slider::mask(static_cast<square::Square>(square), C64(0), dir, len); + } + + for (uint8_t square = 0; square < 64; square++) { + square::Square Square = static_cast<square::Square>(square); + U64 attack_mask = mask(Square); + uint8_t relevant_bits = bit::count(attack_mask); + U64 occupancy_indices = C64(1) << relevant_bits; + + for (U64 idx = 0; idx < occupancy_indices; idx++) { + U64 occupancy = attack::slider::occupancy(idx, relevant_bits, attack_mask); + U32 magic_index = hash(occupancy, Square); + attacks[square][magic_index] = mask_fly(Square, occupancy); + } + } +} + +U64 attack(const square::Square square, U64 occupancy) { + occupancy &= mask(square); + occupancy = hash(occupancy, square); + return attacks[to_underlying(square)][occupancy]; +} + +} // namespace bishop +} // namespace attack diff --git a/src/attack/bishop.hpp b/src/attack/bishop.hpp @@ -1,103 +1,16 @@ -#ifndef STELLAR_ATTACK_BISHOP_H -#define STELLAR_ATTACK_BISHOP_H +#ifndef STELLAR_BISHOP_H +#define STELLAR_BISHOP_H -#include "bit.hpp" -#include "bitboard.hpp" -#include "slider.hpp" #include "square.hpp" #include "utils.hpp" -#include <array> - namespace attack { namespace bishop { -inline constexpr const U64 bishop_magic_numbers[64] = { - C64(0x40040844404084), C64(0x2004208a004208), C64(0x10190041080202), C64(0x108060845042010), - C64(0x581104180800210), C64(0x2112080446200010), C64(0x1080820820060210), C64(0x3c0808410220200), - C64(0x4050404440404), C64(0x21001420088), C64(0x24d0080801082102), C64(0x1020a0a020400), - C64(0x40308200402), C64(0x4011002100800), C64(0x401484104104005), C64(0x801010402020200), - C64(0x400210c3880100), C64(0x404022024108200), C64(0x810018200204102), C64(0x4002801a02003), - C64(0x85040820080400), C64(0x810102c808880400), C64(0xe900410884800), C64(0x8002020480840102), - C64(0x220200865090201), C64(0x2010100a02021202), C64(0x152048408022401), C64(0x20080002081110), - C64(0x4001001021004000), C64(0x800040400a011002), C64(0xe4004081011002), C64(0x1c004001012080), - C64(0x8004200962a00220), C64(0x8422100208500202), C64(0x2000402200300c08), C64(0x8646020080080080), - C64(0x80020a0200100808), C64(0x2010004880111000), C64(0x623000a080011400), C64(0x42008c0340209202), - C64(0x209188240001000), C64(0x400408a884001800), C64(0x110400a6080400), C64(0x1840060a44020800), - C64(0x90080104000041), C64(0x201011000808101), C64(0x1a2208080504f080), C64(0x8012020600211212), - C64(0x500861011240000), C64(0x180806108200800), C64(0x4000020e01040044), C64(0x300000261044000a), - C64(0x802241102020002), C64(0x20906061210001), C64(0x5a84841004010310), C64(0x4010801011c04), - C64(0xa010109502200), C64(0x4a02012000), C64(0x500201010098b028), C64(0x8040002811040900), - C64(0x28000010020204), C64(0x6000020202d0240), C64(0x8918844842082200), C64(0x4010011029020020), -}; - -static inline constexpr const int relevant_bits[64] = { - // clang-format off - 6, 5, 5, 5, 5, 5, 5, 6, - 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 7, 7, 7, 7, 5, 5, - 5, 5, 7, 9, 9, 7, 5, 5, - 5, 5, 7, 9, 9, 7, 5, 5, - 5, 5, 7, 7, 7, 7, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 6, 5, 5, 5, 5, 5, 5, 6, - // clang-format on -}; +void init(void); +U64 attack(const square::Square square, U64 occupancy); -inline constexpr const bitboard::direction_f dir[4] = {bitboard::noEaOne, bitboard::noWeOne, - bitboard::soEaOne, bitboard::soWeOne}; - -inline constexpr U32 hash(const U64 key, const square::Square square) { - uint8_t square_i = to_underlying(square); - return (key * bishop_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]); } - -inline constexpr U64 mask_fly(const square::Square square, U64 block) { - uint8_t square_i = to_underlying(square); - int tr = square_i / 8, tf = square_i % 8; - int len[4] = {std::min(7 - tf, 7 - tr), std::min(tf, 7 - tr), std::min(7 - tf, tr), std::min(tf, tr)}; - - return slider::mask(square, block, dir, len); -} - -inline constexpr const std::array<U64, 64> masks = []() constexpr -> std::array<U64, 64> { - std::array<U64, 64> masks; - for (uint8_t square = 0; square < 64; square++) { - int tr = square / 8, tf = square % 8; - int len[4] = {std::min(7 - tf, 7 - tr) - 1, std::min(tf, 7 - tr) - 1, std::min(7 - tf, tr) - 1, - std::min(tf, tr) - 1}; - masks[square] = slider::mask(static_cast<square::Square>(square), C64(0), dir, len); - } - return masks; -}(); - -inline constexpr U64 mask(const square::Square square) { return masks[to_underlying(square)]; } - -using attack_array = std::array<std::array<U64, 4096>, 64>; -inline constexpr const attack_array attacks = []() constexpr -> attack_array { - attack_array attacks = {{{0}}}; - for (uint8_t square = 0; square < 64; square++) { - square::Square Square = static_cast<square::Square>(square); - U64 attack_mask = mask(Square); - uint8_t relevant_bits = bit::count(attack_mask); - U64 occupancy_indices = C64(1) << relevant_bits; - - for (U64 idx = 0; idx < occupancy_indices; idx++) { - U64 occupancy = slider::occupancy(idx, relevant_bits, attack_mask); - U32 magic_index = hash(occupancy, Square); - attacks[square][magic_index] = mask_fly(Square, occupancy); - } - } - return attacks; -}(); - -inline constexpr U64 attack(const square::Square square, U64 occupancy) { - occupancy &= mask(square); - occupancy = hash(occupancy, square); - return attacks[to_underlying(square)][occupancy]; -} - -} // namespace bishop } // namespace attack #endif diff --git a/src/attack/queen.hpp b/src/attack/queen.hpp @@ -7,7 +7,7 @@ namespace attack { namespace queen { -inline constexpr U64 attack(const square::Square square, U64 occupancy) { +inline U64 attack(const square::Square square, U64 occupancy) { return rook::attack(square, occupancy) | bishop::attack(square, occupancy); } diff --git a/src/attack/rook.cpp b/src/attack/rook.cpp @@ -0,0 +1,93 @@ +#include "rook.hpp" +#include "bit.hpp" +#include "bitboard.hpp" +#include "slider.hpp" + +#include <array> + +namespace attack { +namespace rook { + +inline constexpr const int relevant_bits[64] = { + // clang-format off + 12, 11, 11, 11, 11, 11, 11, 12, + 11, 10, 10, 10, 10, 10, 10, 11, + 11, 10, 10, 10, 10, 10, 10, 11, + 11, 10, 10, 10, 10, 10, 10, 11, + 11, 10, 10, 10, 10, 10, 10, 11, + 11, 10, 10, 10, 10, 10, 10, 11, + 11, 10, 10, 10, 10, 10, 10, 11, + 12, 11, 11, 11, 11, 11, 11, 12, + // clang-format on +}; + +inline constexpr const U64 rook_magic_numbers[64] = { + C64(0x8a80104000800020), C64(0x140002000100040), C64(0x2801880a0017001), C64(0x100081001000420), + C64(0x200020010080420), C64(0x3001c0002010008), C64(0x8480008002000100), C64(0x2080088004402900), + C64(0x800098204000), C64(0x2024401000200040), C64(0x100802000801000), C64(0x120800800801000), + C64(0x208808088000400), C64(0x2802200800400), C64(0x2200800100020080), C64(0x801000060821100), + C64(0x80044006422000), C64(0x100808020004000), C64(0x12108a0010204200), C64(0x140848010000802), + C64(0x481828014002800), C64(0x8094004002004100), C64(0x4010040010010802), C64(0x20008806104), + C64(0x100400080208000), C64(0x2040002120081000), C64(0x21200680100081), C64(0x20100080080080), + C64(0x2000a00200410), C64(0x20080800400), C64(0x80088400100102), C64(0x80004600042881), + C64(0x4040008040800020), C64(0x440003000200801), C64(0x4200011004500), C64(0x188020010100100), + C64(0x14800401802800), C64(0x2080040080800200), C64(0x124080204001001), C64(0x200046502000484), + C64(0x480400080088020), C64(0x1000422010034000), C64(0x30200100110040), C64(0x100021010009), + C64(0x2002080100110004), C64(0x202008004008002), C64(0x20020004010100), C64(0x2048440040820001), + C64(0x101002200408200), C64(0x40802000401080), C64(0x4008142004410100), C64(0x2060820c0120200), + C64(0x1001004080100), C64(0x20c020080040080), C64(0x2935610830022400), C64(0x44440041009200), + C64(0x280001040802101), C64(0x2100190040002085), C64(0x80c0084100102001), C64(0x4024081001000421), + C64(0x20030a0244872), C64(0x12001008414402), C64(0x2006104900a0804), C64(0x1004081002402), +}; + +inline constexpr const bitboard::direction_f dir[4] = {bitboard::westOne, bitboard::soutOne, + bitboard::eastOne, bitboard::nortOne}; + +inline constexpr U32 hash(const U64 key, const square::Square square) { + uint8_t square_i = to_underlying(square); + return (key * rook_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]); +} + +inline constexpr U64 mask_fly(const square::Square square, U64 block) { + uint8_t square_i = to_underlying(square); + int tr = square_i / 8, tf = square_i % 8; + int len[4] = {tf, tr, 7 - tf, 7 - tr}; + + return attack::slider::mask(square, block, dir, len); +} + +std::array<U64, 64> masks = {{0}}; +U64 mask(const square::Square square) { return masks[to_underlying(square)]; } + +std::array<std::array<U64, 4096>, 64> attacks = {{{0}}}; + +void init(void) { + for (uint8_t square = 0; square < 64; square++) { + const int tr = square / 8, tf = square % 8; + const int len[4] = {tf - 1, tr - 1, 6 - tf, 6 - tr}; + + masks[square] = attack::slider::mask(static_cast<square::Square>(square), C64(0), dir, len); + } + + for (uint8_t square = 0; square < 64; square++) { + square::Square Square = static_cast<square::Square>(square); + U64 attack_mask = mask(Square); + uint8_t relevant_bits = bit::count(attack_mask); + U64 occupancy_indices = C64(1) << relevant_bits; + + for (U64 idx = 0; idx < occupancy_indices; idx++) { + U64 occupancy = attack::slider::occupancy(idx, relevant_bits, attack_mask); + U32 magic_index = hash(occupancy, Square); + attacks[square][magic_index] = mask_fly(Square, occupancy); + } + } +} + +U64 attack(const square::Square square, U64 occupancy) { + occupancy &= mask(square); + occupancy = hash(occupancy, square); + return attacks[to_underlying(square)][occupancy]; +} + +} // namespace rook +} // namespace attack diff --git a/src/attack/rook.hpp b/src/attack/rook.hpp @@ -1,101 +1,14 @@ #ifndef STELLAR_ATTACK_ROOK_H #define STELLAR_ATTACK_ROOK_H -#include "bit.hpp" -#include "bitboard.hpp" -#include "slider.hpp" #include "square.hpp" #include "utils.hpp" -#include <array> - namespace attack { namespace rook { -inline constexpr const int relevant_bits[64] = { - // clang-format off - 12, 11, 11, 11, 11, 11, 11, 12, - 11, 10, 10, 10, 10, 10, 10, 11, - 11, 10, 10, 10, 10, 10, 10, 11, - 11, 10, 10, 10, 10, 10, 10, 11, - 11, 10, 10, 10, 10, 10, 10, 11, - 11, 10, 10, 10, 10, 10, 10, 11, - 11, 10, 10, 10, 10, 10, 10, 11, - 12, 11, 11, 11, 11, 11, 11, 12, - // clang-format on -}; - -inline constexpr const U64 rook_magic_numbers[64] = { - C64(0x8a80104000800020), C64(0x140002000100040), C64(0x2801880a0017001), C64(0x100081001000420), - C64(0x200020010080420), C64(0x3001c0002010008), C64(0x8480008002000100), C64(0x2080088004402900), - C64(0x800098204000), C64(0x2024401000200040), C64(0x100802000801000), C64(0x120800800801000), - C64(0x208808088000400), C64(0x2802200800400), C64(0x2200800100020080), C64(0x801000060821100), - C64(0x80044006422000), C64(0x100808020004000), C64(0x12108a0010204200), C64(0x140848010000802), - C64(0x481828014002800), C64(0x8094004002004100), C64(0x4010040010010802), C64(0x20008806104), - C64(0x100400080208000), C64(0x2040002120081000), C64(0x21200680100081), C64(0x20100080080080), - C64(0x2000a00200410), C64(0x20080800400), C64(0x80088400100102), C64(0x80004600042881), - C64(0x4040008040800020), C64(0x440003000200801), C64(0x4200011004500), C64(0x188020010100100), - C64(0x14800401802800), C64(0x2080040080800200), C64(0x124080204001001), C64(0x200046502000484), - C64(0x480400080088020), C64(0x1000422010034000), C64(0x30200100110040), C64(0x100021010009), - C64(0x2002080100110004), C64(0x202008004008002), C64(0x20020004010100), C64(0x2048440040820001), - C64(0x101002200408200), C64(0x40802000401080), C64(0x4008142004410100), C64(0x2060820c0120200), - C64(0x1001004080100), C64(0x20c020080040080), C64(0x2935610830022400), C64(0x44440041009200), - C64(0x280001040802101), C64(0x2100190040002085), C64(0x80c0084100102001), C64(0x4024081001000421), - C64(0x20030a0244872), C64(0x12001008414402), C64(0x2006104900a0804), C64(0x1004081002402), -}; - -inline constexpr const bitboard::direction_f dir[4] = {bitboard::westOne, bitboard::soutOne, - bitboard::eastOne, bitboard::nortOne}; - -inline constexpr U32 hash(const U64 key, const square::Square square) { - uint8_t square_i = to_underlying(square); - return (key * rook_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]); -} - -inline constexpr U64 mask_fly(const square::Square square, U64 block) { - uint8_t square_i = to_underlying(square); - int tr = square_i / 8, tf = square_i % 8; - int len[4] = {tf, tr, 7 - tf, 7 - tr}; - - return slider::mask(square, block, dir, len); -} - -inline constexpr const std::array<U64, 64> masks = []() constexpr -> std::array<U64, 64> { - std::array<U64, 64> masks; - for (uint8_t square = 0; square < 64; square++) { - const int tr = square / 8, tf = square % 8; - const int len[4] = {tf - 1, tr - 1, 6 - tf, 6 - tr}; - - masks[square] = slider::mask(static_cast<square::Square>(square), C64(0), dir, len); - } - return masks; -}(); - -inline constexpr U64 mask(const square::Square square) { return masks[to_underlying(square)]; } - -using attack_array = std::array<std::array<U64, 4096>, 64>; -inline constexpr const attack_array attacks = []() constexpr -> attack_array { - attack_array attacks = {{{0}}}; - for (uint8_t square = 0; square < 64; square++) { - square::Square Square = static_cast<square::Square>(square); - U64 attack_mask = mask(Square); - uint8_t relevant_bits = bit::count(attack_mask); - U64 occupancy_indices = C64(1) << relevant_bits; - - for (U64 idx = 0; idx < occupancy_indices; idx++) { - U64 occupancy = slider::occupancy(idx, relevant_bits, attack_mask); - U32 magic_index = hash(occupancy, Square); - attacks[square][magic_index] = mask_fly(Square, occupancy); - } - } - return attacks; -}(); - -inline constexpr U64 attack(const square::Square square, U64 occupancy) { - occupancy &= mask(square); - occupancy = hash(occupancy, square); - return attacks[to_underlying(square)][occupancy]; -} +void init(void); +U64 attack(const square::Square square, U64 occupancy); } // namespace rook } // namespace attack diff --git a/src/attack/slider.hpp b/src/attack/slider.hpp @@ -1,6 +1,8 @@ #ifndef STELLAR_ATTAKC_SLIDER_H #define STELLAR_ATTAKC_SLIDER_H +#include "bit.hpp" +#include "bitboard.hpp" #include "square.hpp" #include "utils.hpp" diff --git a/src/board/CMakeLists.txt b/src/board/CMakeLists.txt @@ -9,6 +9,3 @@ target_link_libraries(board ) target_include_directories(board INTERFACE .) -stellar_target_precompile_headers(board INTERFACE "board.hpp") - - diff --git a/src/board/board.cpp b/src/board/board.cpp @@ -1,7 +1,7 @@ #include <cctype> -#include <exception> #include <cstdio> #include <cstring> +#include <exception> #include "board.hpp" #include "piece.hpp" @@ -9,6 +9,11 @@ #include "utils.hpp" #include "zobrist.hpp" +/* Init arrays for Zobris hashing */ +std::array<std::array<U64, 64>, 12> zobrist::keys_piece = {{{0}}}; +std::array<U64, 64> zobrist::keys_enpassant = {{0}}; +std::array<U64, 16> zobrist::keys_castle = {{0}}; + /* Getters */ Board::Board(const std::string &fen) { @@ -34,8 +39,7 @@ Board::Board(const std::string &fen) { : throw std::runtime_error("Invalid player char"); for (i += 2; fen[i] != ' '; i++) { - if (fen[i] == 'K') - castle |= to_underlying(Castle::WK); + if (fen[i] == 'K') castle |= to_underlying(Castle::WK); else if (fen[i] == 'Q') castle |= to_underlying(Castle::WQ); else if (fen[i] == 'k') @@ -51,7 +55,7 @@ Board::Board(const std::string &fen) { enpassant = fen[++i] != '-' ? square::from_coordinates(fen.substr(i, 2)) : square::no_sq; - hash = Zobrist::hash(*this); + hash = zobrist::hash(*this); } std::ostream &operator<<(std::ostream &os, const Board &board) { diff --git a/src/board/board.hpp b/src/board/board.hpp @@ -41,11 +41,11 @@ class Board { [[nodiscard]] inline constexpr U64 get_bitboard_piece(piece::Type piece, color::Color color) const; [[nodiscard]] inline constexpr U64 get_bitboard_piece_attacks(piece::Type piece, color::Color color, - square::Square from) const; + square::Square from) const; [[nodiscard]] inline constexpr U64 get_bitboard_piece_moves(piece::Type piece, color::Color color, - square::Square from) const; + square::Square from) const; [[nodiscard]] inline constexpr U64 get_bitboard_square_land(square::Square land, piece::Type piece, - color::Color side) const; + color::Color side) const; [[nodiscard]] inline constexpr color::Color get_square_piece_color(square::Square square) const; [[nodiscard]] inline constexpr piece::Type get_square_piece_type(square::Square square) const; @@ -71,8 +71,9 @@ class Board { [[nodiscard]] inline constexpr bool is_square_attacked(square::Square square, color::Color side) const; [[nodiscard]] inline constexpr bool is_square_occupied(square::Square square) const; - [[nodiscard]] inline constexpr bool is_piece_attack_square(piece::Type type, color::Color color, square::Square source, - square::Square target) const; + [[nodiscard]] inline constexpr bool is_piece_attack_square(piece::Type type, color::Color color, + square::Square source, + square::Square target) const; [[nodiscard]] inline constexpr bool is_check() const; private: @@ -142,19 +143,19 @@ constexpr const piece::Piece *Board::get_square_piece(square::Square square) con constexpr void Board::xor_hash(U64 op) { hash ^= op; } constexpr void Board::and_castle(uint8_t right) { - hash ^= Zobrist::key_castle(castle); + hash ^= zobrist::key_castle(castle); castle &= right; - hash ^= Zobrist::key_castle(castle); + hash ^= zobrist::key_castle(castle); } constexpr void Board::switch_side() { side = color::other(side); - hash ^= Zobrist::key_side(); + hash ^= zobrist::key_side(); } constexpr void Board::set_enpassant(square::Square target) { - if (enpassant != square::Square::no_sq) hash ^= Zobrist::key_enpassant(enpassant); - if (target != square::Square::no_sq) hash ^= Zobrist::key_enpassant(target); + if (enpassant != square::Square::no_sq) hash ^= zobrist::key_enpassant(enpassant); + if (target != square::Square::no_sq) hash ^= zobrist::key_enpassant(target); enpassant = target; } @@ -214,7 +215,7 @@ constexpr bool Board::is_check() const { return is_square_attacked(square, side_other); } -U64 Zobrist::hash(const Board &board) { +U64 zobrist::hash(const Board &board) { U64 key_final = C64(0); uint8_t square = 0; diff --git a/src/board/zobrist.hpp b/src/board/zobrist.hpp @@ -9,57 +9,44 @@ #include <random> class Board; -class Zobrist { - public: - Zobrist() = delete; - - static inline U64 hash(const Board &board); - static inline constexpr U64 key_side() { return keys_side; } - static inline constexpr U64 key_castle(int exp) { return keys_castle[exp]; } - static inline constexpr U64 key_enpassant(square::Square square) { - return keys_enpassant[to_underlying(square)]; - } - static inline constexpr U64 key_piece(piece::Type type, color::Color color, square::Square square) { - return keys_piece[piece::get_index(type, color)][to_underlying(square)]; +namespace zobrist { + +extern std::array<std::array<U64, 64>, 12> keys_piece; +extern std::array<U64, 64> keys_enpassant; +extern std::array<U64, 16> keys_castle; + +const U64 keys_side = Random(C32(1699391443))(); + +inline void init() { + Random gen1(C64(1804289383)); + for (piece::Type type : piece::TypeIter()) { + int piece_index_white = piece::get(type, color::Color::WHITE).index; + int piece_index_black = piece::get(type, color::Color::BLACK).index; + for (int square = 0; square < 64; square++) { + keys_piece[piece_index_white][square] = gen1(); + keys_piece[piece_index_black][square] = gen1(); + } } - private: - using key_piece_array = std::array<std::array<U64, 64>, 12>; - static inline constexpr const key_piece_array keys_piece = []() constexpr -> key_piece_array { - key_piece_array key_piece; - Random gen(C64(1804289383)); - for (piece::Type type : piece::TypeIter()) { - int piece_index_white = piece::get(type, color::Color::WHITE).index; - int piece_index_black = piece::get(type, color::Color::BLACK).index; - for (int square = 0; square < 64; square++) { - key_piece[piece_index_white][square] = gen(); - key_piece[piece_index_black][square] = gen(); - } - } - return key_piece; - }(); + Random gen2(C32(337245213)); + for (int castle = 0; castle < 64; castle++) { + keys_enpassant[castle] = gen2(); + } - using key_enpassant_array = std::array<U64, 64>; - static inline constexpr const key_enpassant_array keys_enpassant = []() constexpr -> key_enpassant_array { - key_enpassant_array key_enpassant; - Random gen(C32(337245213)); - for (int castle = 0; castle < 64; castle++) { - key_enpassant[castle] = gen(); - } - return key_enpassant; - }(); + Random gen3(C32(3642040919)); + for (int castle = 0; castle < 16; castle++) { + keys_castle[castle] = gen3(); + } +}; - using key_castle_array = std::array<U64, 16>; - static inline constexpr const key_castle_array keys_castle = []() constexpr -> key_castle_array { - key_castle_array key_castle; - Random gen(C32(3642040919)); - for (int castle = 0; castle < 16; castle++) { - key_castle[castle] = gen(); - } - return key_castle; - }(); +inline U64 hash(const Board &board); +inline constexpr U64 key_side() { return keys_side; } +inline constexpr U64 key_castle(int exp) { return keys_castle[exp]; } +inline constexpr U64 key_enpassant(square::Square square) { return keys_enpassant[to_underlying(square)]; } +inline constexpr U64 key_piece(piece::Type type, color::Color color, square::Square square) { + return keys_piece[piece::get_index(type, color)][to_underlying(square)]; +} - static inline constexpr const U64 keys_side = Random(C32(1699391443))(); -}; +}; // namespace zobrist #endif diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(engine engine.cpp ) + target_link_libraries(engine PRIVATE Stellar_version PRIVATE board diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp @@ -17,13 +17,13 @@ #include "utils.hpp" enum { -FULL_DEPTH = 4, -REDUCTION_LIMIT = 3, -REDUCTION_MOVE = 2 + FULL_DEPTH = 4, + REDUCTION_LIMIT = 3, + REDUCTION_MOVE = 2 }; enum { -WINDOW = 50 + WINDOW = 50 }; namespace engine { @@ -473,6 +473,8 @@ Move search_position(const uci::Settings &settingsr) { } // namespace engine int main() { + attack::init(); + zobrist::init(); uci::loop(); return 0; } diff --git a/src/move/move.cpp b/src/move/move.cpp @@ -6,12 +6,12 @@ void Move::piece_remove(Board &board, piece::Type type, color::Color color, square::Square square) const { board.pop_piece(type, color, square); - board.xor_hash(Zobrist::key_piece(type, color, square)); + board.xor_hash(zobrist::key_piece(type, color, square)); } void Move::piece_set(Board &board, piece::Type type, color::Color color, square::Square square) const { board.set_piece(type, color, square); - board.xor_hash(Zobrist::key_piece(type, color, square)); + board.xor_hash(zobrist::key_piece(type, color, square)); } void Move::piece_move(Board &board, piece::Type type, color::Color color, square::Square source, diff --git a/src/perft/CMakeLists.txt b/src/perft/CMakeLists.txt @@ -12,10 +12,6 @@ target_link_libraries(perft PRIVATE utils ) -target_precompile_headers(perft - REUSE_FROM engine -) - set_target_properties(perft PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR} diff --git a/src/perft/perft.cpp b/src/perft/perft.cpp @@ -2,6 +2,7 @@ #include <semaphore> #include <thread> +#include "attack.hpp" #include "board.hpp" #include "move.hpp" #include "movelist.hpp" @@ -151,6 +152,8 @@ int main(int argc, char *argv[]) { } } + attack::init(); + zobrist::init(); perft_test(fen, depth, thread_num); return 0; } diff --git a/src/piece/CMakeLists.txt b/src/piece/CMakeLists.txt @@ -7,5 +7,3 @@ target_link_libraries(piece ) target_include_directories(piece INTERFACE .) -stellar_target_precompile_headers(piece INTERFACE "piece.hpp") - diff --git a/src/random/CMakeLists.txt b/src/random/CMakeLists.txt @@ -1,4 +1,3 @@ add_library(random INTERFACE) target_link_libraries(piece INTERFACE utils) target_include_directories(random INTERFACE .) -stellar_target_precompile_headers(random INTERFACE "random.hpp") diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt @@ -1,23 +1,17 @@ add_library(bit INTERFACE) target_include_directories(bit INTERFACE .) -stellar_target_precompile_headers(bit INTERFACE "bit.hpp") add_library(bitboard INTERFACE bitboard.cpp) target_include_directories(bitboard INTERFACE .) -stellar_target_precompile_headers(bitboard INTERFACE "bitboard.hpp") add_library(color INTERFACE) target_include_directories(color INTERFACE .) -stellar_target_precompile_headers(color INTERFACE "color.hpp") add_library(square INTERFACE) target_include_directories(square INTERFACE .) -stellar_target_precompile_headers(square INTERFACE "square.hpp") add_library(timer INTERFACE) target_include_directories(timer INTERFACE .) -stellar_target_precompile_headers(timer INTERFACE "timer.hpp") add_library(utils INTERFACE) target_include_directories(utils INTERFACE .) -stellar_target_precompile_headers(utils INTERFACE "utils.hpp") diff --git a/src/utils/bit.hpp b/src/utils/bit.hpp @@ -2,6 +2,7 @@ #define STELLAR_BIT_H #include "utils.hpp" +#include <bit> namespace bit { @@ -9,26 +10,8 @@ inline constexpr bool get(const U64 &bitboard, uint8_t square) { return (bitboar inline constexpr void set(U64 &bitboard, uint8_t square) { bitboard |= (C64(1) << square); } inline constexpr void pop(U64 &bitboard, uint8_t square) { bitboard &= ~(C64(1) << (square)); } -inline constexpr uint8_t count(U64 bitboard) { -#if __has_builtin(__builtin_popcountll) - return __builtin_popcountll(bitboard); -#else - int count = 0; - for (; bitboard > 0; bitboard &= bitboard - 1) - count++; - return count; -#endif -} - -inline constexpr uint8_t lsb_index(U64 bitboard) { -#if __has_builtin(__builtin_ffsll) - return __builtin_ffsll(bitboard) - 1; -#else - if (!bitboard) return -1; - return bit_count((bitboard & -bitboard) - 1); -#endif -} - +inline constexpr uint8_t count(U64 bitboard) { return std::popcount(bitboard); } +inline constexpr uint8_t lsb_index(U64 bitboard) { return std::countr_zero(bitboard); } inline constexpr U64 &lsb_pop(U64 &bitboard) { return bitboard &= bitboard & (bitboard - 1); } #define bitboard_for_each_bit(var, bb) \ diff --git a/src/utils/timer.hpp b/src/utils/timer.hpp @@ -1,14 +1,13 @@ #ifndef STELLAR_TIME_H #define STELLAR_TIME_H -#include <sys/time.h> +#include <chrono> namespace timer { inline uint32_t get_ms() { - struct timeval time{}; - gettimeofday(&time, nullptr); - return time.tv_sec * 1000 + time.tv_usec / 1000; + const auto duration = std::chrono::system_clock::now().time_since_epoch(); + return std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(); } } // namespace timer