stellar

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

commit664eeb29d4722c4663863878105d1561ce7d9bb4
parent75e27270d7d82dceb3274989abbe149546584541
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateMon, 11 Mar 2024 17:55:44 +0100

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

Diffstat:
MCMakeLists.txt|+++++++++----------------------------------
Msrc/arena/arena.cpp|+++
Msrc/arena/engine.hpp|++
Msrc/arena/logger.hpp|+
Msrc/attack/CMakeLists.txt|+------------
Msrc/attack/attack.cpp|+++++++++
Msrc/attack/attack.hpp|++--
Asrc/attack/bishop.cpp|+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/attack/bishop.hpp|++++------------------------------------------------------------------------------
Msrc/attack/queen.hpp|+-
Asrc/attack/rook.cpp|+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/attack/rook.hpp|+++-------------------------------------------------------------------------------
Msrc/attack/slider.hpp|++
Msrc/board/CMakeLists.txt|---
Msrc/board/board.cpp|++++++++----
Msrc/board/board.hpp|++++++++++++-----------
Msrc/board/zobrist.hpp|+++++++++++++++++++++++++++++++++++-----------------------------------------------
Msrc/engine/CMakeLists.txt|+
Msrc/engine/engine.cpp|++++++----
Msrc/move/move.cpp|++--
Msrc/perft/CMakeLists.txt|----
Msrc/perft/perft.cpp|+++
Msrc/piece/CMakeLists.txt|--
Msrc/random/CMakeLists.txt|-
Msrc/utils/CMakeLists.txt|------
Msrc/utils/bit.hpp|+++--------------------
Msrc/utils/timer.hpp|+++----

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 +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