stellar

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

commitb3660d9286bcd94407d954d7932be4f0956e8592
parent1857c3ab3da2587974a169e7414f3add950a7a5e
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateSat, 26 Aug 2023 14:54:53 +0200

Restructure project, CMake precompiled headers

Diffstat:
MCMakeLists.txt|+++++++
Asrc/attack/CMakeLists.txt|++++
Asrc/attack/attack.hpp|+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/board/CMakeLists.txt|+++++++++--
Msrc/board/board.cpp|++--------------------------------------------------------------------------------
Asrc/board/board.hpp|+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/board/zobrist.hpp|+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/engine/CMakeLists.txt|++
Msrc/engine/engine.cpp|++--
Msrc/engine/transposition.hpp|+-
Dsrc/include/attack.hpp|---------------------------------------------------------------------------------
Dsrc/include/board.hpp|----------------------------------------------------------------------------
Dsrc/include/magic.hpp|--------------------------------------------
Dsrc/include/move.hpp|--------------------------------------------------------------------
Dsrc/include/movelist.hpp|-----------------------------------
Dsrc/include/piece.hpp|---------------------------------------------------------------------------------
Dsrc/include/random.hpp|-----------------------------------------
Dsrc/include/utils_cpp.hpp|---------------------------------------------------------------------------------
Dsrc/include/zobrist.hpp|---------------------------------------------------------------------------------
Msrc/move/CMakeLists.txt|++++++--
Msrc/move/move.cpp|+++++-------
Asrc/move/move.hpp|++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/move/movelist.hpp|+++++++++++++++++++++++++++++++++++
Msrc/perft/CMakeLists.txt|++++++++--
Msrc/perft/perft.cpp|+-
Asrc/piece/CMakeLists.txt|++++++++++
Asrc/piece/piece.hpp|+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/random/CMakeLists.txt|++++
Asrc/random/random.hpp|+++++++++++++++++++++++++++++++++++++++++
Asrc/utils/CMakeLists.txt|+++
Asrc/utils/utils.hpp|+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

31 files changed, 1199 insertions(+), 1158 deletions(-)


diff --git a/CMakeLists.txt b/CMakeLists.txt

@@ -15,6 +15,13 @@ set(CMAKE_CXX_EXTENSIONS OFF)

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 -fno-fat-lto-objects" COMPILER_SUPPORTS_LTO)
if(COMPILER_SUPPORTS_LTO)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -fno-fat-lto-objects")

diff --git a/src/attack/CMakeLists.txt b/src/attack/CMakeLists.txt

@@ -0,0 +1,4 @@

add_library(attack INTERFACE)
target_link_libraries(attack INTERFACE utils)
target_include_directories(attack INTERFACE .)
stellar_target_precompile_headers(attack INTERFACE "attack.hpp")

diff --git a/src/attack/attack.hpp b/src/attack/attack.hpp

@@ -0,0 +1,365 @@

#ifndef STELLAR_ATTAKCS_INTERNAL_H
#define STELLAR_ATTAKCS_INTERNAL_H
#include "utils.hpp"
#include <array>
namespace attack {
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),
};
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),
};
class Slider {
public:
virtual constexpr U32 hash(U64 key, Square square) const = 0;
virtual constexpr U64 mask(Square square) const = 0;
virtual constexpr U64 mask_fly(Square square, U64 block) const = 0;
static inline constexpr U64 occupancy(U64 index, uint8_t bits_in_mask, U64 attack_mask) {
U64 occupancy = C64(0);
for (uint8_t count = 0; count < bits_in_mask; count++) {
uint8_t square = bit_lsb_index(attack_mask);
bit_pop(attack_mask, square);
if (bit_get(index, count)) bit_set(occupancy, square);
}
return occupancy;
}
protected:
static inline constexpr U64 mask_slide(Square square, U64 block, const direction_f dir[4],
const int len[4]) {
U64 bitboard = C64(0), attacks = C64(0);
bit_set(bitboard, to_underlying(square));
for (int i = 0; i < 4; i++) {
U64 tmp = bitboard;
for (int j = 0; j < len[i]; j++) {
attacks |= tmp = (dir[i])(tmp);
if (tmp & block) break;
}
}
return attacks;
}
};
class SliderRook : public Slider {
public:
virtual constexpr U32 hash(U64 key, Square square) const override {
uint8_t square_i = to_underlying(square);
return (key * rook_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]);
}
virtual constexpr U64 mask(Square square) const override { return masks[to_underlying(square)]; }
virtual constexpr U64 mask_fly(Square square, U64 block) const override {
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 mask_slide(square, block, dir, len);
}
private:
static inline constexpr const direction_f dir[4] = {westOne, soutOne, eastOne, nortOne};
// clang-format off
static inline constexpr const int relevant_bits[64] = {
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
static inline constexpr const std::array<U64, 64> masks = []() constexpr -> std::array<U64, 64> {
std::array<U64, 64> masks;
for (const Square square : SquareIter()) {
const uint8_t square_i = to_underlying(square);
const int tr = square_i / 8, tf = square_i % 8;
const int len[4] = {tf - 1, tr - 1, 6 - tf, 6 - tr};
masks[square_i] = mask_slide(square, C64(0), dir, len);
}
return masks;
}();
};
class SliderBishop : public Slider {
public:
virtual constexpr U32 hash(U64 key, Square square) const override {
uint8_t square_i = to_underlying(square);
return (key * bishop_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]);
}
virtual constexpr U64 mask(Square square) const override { return masks[to_underlying(square)]; }
virtual constexpr U64 mask_fly(Square square, U64 block) const override {
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 mask_slide(square, block, dir, len);
}
private:
static inline constexpr const direction_f dir[4] = {noEaOne, noWeOne, soEaOne, soWeOne};
// clang-format off
static inline constexpr const int relevant_bits[64] = {
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
static inline constexpr const std::array<U64, 64> masks = []() constexpr -> std::array<U64, 64> {
std::array<U64, 64> masks;
for (const Square square : SquareIter()) {
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) - 1, std::min(tf, 7 - tr) - 1, std::min(7 - tf, tr) - 1,
std::min(tf, tr) - 1};
masks[square_i] = mask_slide(square, C64(0), dir, len);
}
return masks;
}();
};
inline constexpr const SliderRook slider_rook;
inline constexpr const SliderBishop slider_bishop;
class Attack {
public:
virtual constexpr U64 operator()(Square square, U64 occupancy) const = 0;
protected:
template <std::size_t size> using slider_attack_array = std::array<std::array<U64, size>, 64>;
static inline constexpr const auto slider_attacks =
[]<std::size_t size>(const Slider &slider) constexpr -> slider_attack_array<size> {
slider_attack_array<size> attacks;
for (const Square square : SquareIter()) {
uint8_t square_i = to_underlying(square);
U64 attack_mask = slider.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 = slider.hash(occupancy, square);
attacks[square_i][magic_index] = slider.mask_fly(square, occupancy);
}
}
return attacks;
};
};
class Rook : public Attack {
public:
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
occupancy &= slider_rook.mask(square);
occupancy = slider_rook.hash(occupancy, square);
return attacks[to_underlying(square)][occupancy];
}
private:
static inline constexpr const slider_attack_array<4096> attacks =
slider_attacks.operator()<4096>(slider_rook);
};
class Bishop : public Attack {
public:
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
occupancy &= slider_bishop.mask(square);
occupancy = slider_bishop.hash(occupancy, square);
return attacks[to_underlying(square)][occupancy];
}
private:
static inline constexpr const slider_attack_array<512> attacks =
slider_attacks.operator()<512>(slider_bishop);
};
class King : public Attack {
public:
constexpr King() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
}
private:
static constexpr U64 mask(Square square) {
U64 bitboard = C64(0), attacks = C64(0);
bit_set(bitboard, to_underlying(square));
attacks |= westOne(bitboard) | eastOne(bitboard);
attacks |= soutOne(bitboard) | nortOne(bitboard);
attacks |= soutOne(bitboard) | nortOne(bitboard);
attacks |= soEaOne(bitboard) | noEaOne(bitboard);
attacks |= soWeOne(bitboard) | noWeOne(bitboard);
return attacks;
}
typedef std::array<U64, 64> attack_array;
const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (const Square square : SquareIter())
attacks[to_underlying(square)] = mask(square);
return attacks;
}();
};
class Knight : public Attack {
public:
constexpr Knight() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
}
private:
static constexpr U64 mask(Square square) {
U64 bitboard = C64(0), attacks = C64(0), tmp;
bit_set(bitboard, to_underlying(square));
tmp = nortOne(nortOne(bitboard));
attacks |= westOne(tmp) | eastOne(tmp);
tmp = soutOne(soutOne(bitboard));
attacks |= westOne(tmp) | eastOne(tmp);
tmp = westOne(westOne(bitboard));
attacks |= soutOne(tmp) | nortOne(tmp);
tmp = eastOne(eastOne(bitboard));
attacks |= soutOne(tmp) | nortOne(tmp);
return attacks;
}
typedef std::array<U64, 64> attack_array;
const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (const Square square : SquareIter())
attacks[to_underlying(square)] = mask(square);
return attacks;
}();
};
class PawnW : public Attack {
public:
constexpr PawnW() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
}
private:
static constexpr U64 mask(Square square) {
U64 bitboard = C64(0);
bit_set(bitboard, to_underlying(square));
return noWeOne(bitboard) | noEaOne(bitboard);
}
typedef std::array<U64, 64> attack_array;
const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (const Square square : SquareIter())
attacks[to_underlying(square)] = mask(square);
return attacks;
}();
};
class PawnB : public Attack {
public:
constexpr PawnB() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
}
private:
static constexpr U64 mask(Square square) {
U64 bitboard = C64(0);
bit_set(bitboard, to_underlying(square));
return soWeOne(bitboard) | soEaOne(bitboard);
}
typedef std::array<U64, 64> attack_array;
const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (const Square square : SquareIter())
attacks[to_underlying(square)] = mask(square);
return attacks;
}();
};
inline constexpr const Rook rook;
inline constexpr const Bishop bishop;
inline constexpr const King king;
inline constexpr const Knight knight;
inline constexpr const PawnW pawnW;
inline constexpr const PawnB pawnB;
class Queen : public Attack {
public:
constexpr Queen() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return rook(square, occupancy) | bishop(square, occupancy);
}
};
inline constexpr const Queen queen;
} // namespace attack
#endif

diff --git a/src/board/CMakeLists.txt b/src/board/CMakeLists.txt

@@ -2,6 +2,13 @@ add_library(board OBJECT

board.cpp
)
target_include_directories(board
PUBLIC "${PROJECT_SOURCE_DIR}/src/include"
target_link_libraries(board
PRIVATE piece
PRIVATE utils
PUBLIC random
)
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

@@ -5,129 +5,11 @@

#include "board.hpp"
#include "piece.hpp"
#include "utils_cpp.hpp"
#include "utils.hpp"
#include "zobrist.hpp"
/* Getters */
Color Board::get_side(void) const { return side; }
U64 Board::get_hash(void) const { return hash; }
uint8_t Board::get_castle(void) const { return castle; }
Square Board::get_enpassant(void) const { return enpassant; }
U64 Board::get_bitboard_color(Color side) const { return colors[to_underlying(side)]; }
U64 Board::get_bitboard_occupancy(void) const {
return colors[to_underlying(Color::WHITE)] | colors[to_underlying(Color::BLACK)];
}
U64 Board::get_bitboard_piece(piece::Type piece) const { return pieces[to_underlying(piece)]; }
U64 Board::get_bitboard_piece(piece::Type piece, Color color) const {
return pieces[to_underlying(piece)] & colors[to_underlying(color)];
}
U64 Board::get_bitboard_piece_attacks(piece::Type type, Color color, Square from) const {
return piece::get_attack(type, color, from, get_bitboard_occupancy());
}
U64 Board::get_bitboard_piece_moves(piece::Type type, Color color, Square square) const {
return get_bitboard_piece_attacks(type, color, square) & ~get_bitboard_color(color);
}
Color Board::get_square_piece_color(Square square) const {
if (bit_get(colors[to_underlying(Color::WHITE)], to_underlying(square))) return Color::WHITE;
if (bit_get(colors[to_underlying(Color::BLACK)], to_underlying(square))) return Color::BLACK;
throw std::exception();
}
piece::Type Board::get_square_piece_type(Square square) const {
for (piece::Type type : piece::TypeIter()) {
if (bit_get(pieces[to_underlying(type)], to_underlying(square))) return type;
}
return piece::Type::NONE;
}
const piece::Piece *Board::get_square_piece(Square square) const {
try {
return &piece::get(get_square_piece_type(square), get_square_piece_color(square));
} catch (std::exception &e) {
return nullptr;
}
}
/* Setters */
void Board::xor_hash(U64 op) { hash ^= op; }
void Board::and_castle(uint8_t right) { castle &= right; }
void Board::switch_side(void) {
side = (side == Color::BLACK) ? Color::WHITE : Color::BLACK;
hash ^= Zobrist::key_side();
}
void Board::set_enpassant(Square target) {
if (enpassant != Square::no_sq) hash ^= Zobrist::key_enpassant(enpassant);
if (target != Square::no_sq) hash ^= Zobrist::key_enpassant(target);
enpassant = target;
}
void Board::pop_bitboard_color(Color color, Square square) {
bit_pop(colors[to_underlying(color)], to_underlying(square));
}
void Board::set_bitboard_color(Color color, Square square) {
bit_set(colors[to_underlying(color)], to_underlying(square));
}
void Board::pop_bitboard_piece(piece::Type type, Square square) {
bit_pop(pieces[to_underlying(type)], to_underlying(square));
}
void Board::set_bitboard_piece(piece::Type type, Square square) {
bit_set(pieces[to_underlying(type)], to_underlying(square));
}
void Board::pop_piece(piece::Type type, Color side, Square square) {
pop_bitboard_color(side, square);
pop_bitboard_piece(type, square);
}
void Board::set_piece(piece::Type type, Color side, Square square) {
set_bitboard_color(side, square);
set_bitboard_piece(type, square);
}
/* Queries */
bool Board::is_square_occupied(Square square) const {
return bit_get(get_bitboard_occupancy(), to_underlying(square));
}
bool Board::is_square_attacked(Square square, Color side) const {
Color side_other = (side == Color::BLACK) ? Color::WHITE : Color::BLACK;
for (piece::Type type : piece::TypeIter()) {
if (get_bitboard_piece_attacks(type, side_other, square) & get_bitboard_piece(type, side)) {
return 1;
}
}
return 0;
}
bool Board::is_piece_attack_square(piece::Type type, Color color, Square source, Square target) const {
return get_bitboard_piece_attacks(type, color, source) & (C64(1) << to_underlying(target));
}
bool Board::is_check(void) const {
U64 king = pieces[to_underlying(piece::Type::KING)] & colors[to_underlying(side)];
Color side_other = (side == Color::BLACK) ? Color::WHITE : Color::BLACK;
Square square = static_cast<Square>(bit_lsb_index(king));
return is_square_attacked(square, side_other);
}
Board::Board(const std::string &fen) {
int file = 0, rank = 7, i;
for (i = 0; fen[i] != ' '; i++) {

diff --git a/src/board/board.hpp b/src/board/board.hpp

@@ -0,0 +1,223 @@

#ifndef STELLAR_BOARD_H
#define STELLAR_BOARD_H
#include "piece.hpp"
#include "utils.hpp"
#include "zobrist.hpp"
#include <iostream>
#include <string>
class Board {
public:
enum class Castle : uint8_t {
WK = 1,
WQ = 2,
BK = 4,
BQ = 8
};
Board() = default;
Board(const std::string &fen);
friend std::ostream &operator<<(std::ostream &os, const Board &board);
/* Getters */
inline constexpr U64 get_hash(void) const;
inline constexpr Color get_side(void) const;
inline constexpr uint8_t get_castle(void) const;
inline constexpr Square get_enpassant(void) const;
inline constexpr U64 get_bitboard_color(Color side) const;
inline constexpr U64 get_bitboard_occupancy(void) const;
inline constexpr U64 get_bitboard_piece(piece::Type piece) const;
inline constexpr U64 get_bitboard_piece(piece::Type piece, Color color) const;
inline constexpr U64 get_bitboard_piece_attacks(piece::Type piece, Color color, Square from) const;
inline constexpr U64 get_bitboard_piece_moves(piece::Type piece, Color color, Square from) const;
inline constexpr Color get_square_piece_color(Square square) const;
inline constexpr piece::Type get_square_piece_type(Square square) const;
inline constexpr const piece::Piece *get_square_piece(Square square) const;
/* Setters */
inline constexpr void xor_hash(U64 op);
inline constexpr void switch_side(void);
inline constexpr void and_castle(uint8_t right);
inline constexpr void set_enpassant(Square target);
inline constexpr void pop_bitboard_color(Color color, Square square);
inline constexpr void set_bitboard_color(Color color, Square square);
inline constexpr void pop_bitboard_piece(piece::Type type, Square square);
inline constexpr void set_bitboard_piece(piece::Type type, Square square);
inline constexpr void pop_piece(piece::Type type, Color side, Square square);
inline constexpr void set_piece(piece::Type type, Color side, Square square);
/* Queries */
inline constexpr bool is_square_attacked(Square Square, Color side) const;
inline constexpr bool is_square_occupied(Square Square) const;
inline constexpr bool is_piece_attack_square(piece::Type type, Color color, Square source,
Square target) const;
inline constexpr bool is_check(void) const;
private:
U64 colors[2] = {0};
U64 pieces[6] = {0};
U64 hash = 0;
Color side = Color::WHITE;
Square enpassant = Square::no_sq;
uint8_t castle = 0;
};
constexpr Color Board::get_side(void) const { return side; }
constexpr U64 Board::get_hash(void) const { return hash; }
constexpr uint8_t Board::get_castle(void) const { return castle; }
constexpr Square Board::get_enpassant(void) const { return enpassant; }
constexpr U64 Board::get_bitboard_color(Color side) const { return colors[to_underlying(side)]; }
constexpr U64 Board::get_bitboard_occupancy(void) const {
return colors[to_underlying(Color::WHITE)] | colors[to_underlying(Color::BLACK)];
}
constexpr U64 Board::get_bitboard_piece(piece::Type piece) const { return pieces[to_underlying(piece)]; }
constexpr U64 Board::get_bitboard_piece(piece::Type piece, Color color) const {
return pieces[to_underlying(piece)] & colors[to_underlying(color)];
}
constexpr U64 Board::get_bitboard_piece_attacks(piece::Type type, Color color, Square from) const {
return piece::get_attack(type, color, from, get_bitboard_occupancy());
}
constexpr U64 Board::get_bitboard_piece_moves(piece::Type type, Color color, Square square) const {
return get_bitboard_piece_attacks(type, color, square) & ~get_bitboard_color(color);
}
constexpr Color Board::get_square_piece_color(Square square) const {
if (bit_get(colors[to_underlying(Color::WHITE)], to_underlying(square))) return Color::WHITE;
if (bit_get(colors[to_underlying(Color::BLACK)], to_underlying(square))) return Color::BLACK;
throw std::exception();
}
constexpr piece::Type Board::get_square_piece_type(Square square) const {
for (piece::Type type : piece::TypeIter()) {
if (bit_get(pieces[to_underlying(type)], to_underlying(square))) return type;
}
return piece::Type::NONE;
}
constexpr const piece::Piece *Board::get_square_piece(Square square) const {
try {
return &piece::get(get_square_piece_type(square), get_square_piece_color(square));
} catch (std::exception &e) {
return nullptr;
}
}
/* Setters */
constexpr void Board::xor_hash(U64 op) { hash ^= op; }
constexpr void Board::and_castle(uint8_t right) {
hash ^= Zobrist::key_castle(castle);
castle &= right;
hash ^= Zobrist::key_castle(castle);
}
constexpr void Board::switch_side(void) {
side = (side == Color::BLACK) ? Color::WHITE : Color::BLACK;
hash ^= Zobrist::key_side();
}
constexpr void Board::set_enpassant(Square target) {
if (enpassant != Square::no_sq) hash ^= Zobrist::key_enpassant(enpassant);
if (target != Square::no_sq) hash ^= Zobrist::key_enpassant(target);
enpassant = target;
}
constexpr void Board::pop_bitboard_color(Color color, Square square) {
bit_pop(colors[to_underlying(color)], to_underlying(square));
}
constexpr void Board::set_bitboard_color(Color color, Square square) {
bit_set(colors[to_underlying(color)], to_underlying(square));
}
constexpr void Board::pop_bitboard_piece(piece::Type type, Square square) {
bit_pop(pieces[to_underlying(type)], to_underlying(square));
}
constexpr void Board::set_bitboard_piece(piece::Type type, Square square) {
bit_set(pieces[to_underlying(type)], to_underlying(square));
}
constexpr void Board::pop_piece(piece::Type type, Color side, Square square) {
pop_bitboard_color(side, square);
pop_bitboard_piece(type, square);
}
constexpr void Board::set_piece(piece::Type type, Color side, Square square) {
set_bitboard_color(side, square);
set_bitboard_piece(type, square);
}
/* Queries */
constexpr bool Board::is_square_occupied(Square square) const {
return bit_get(get_bitboard_occupancy(), to_underlying(square));
}
constexpr bool Board::is_square_attacked(Square square, Color side) const {
Color side_other = (side == Color::BLACK) ? Color::WHITE : Color::BLACK;
for (piece::Type type : piece::TypeIter()) {
if (get_bitboard_piece_attacks(type, side_other, square) & get_bitboard_piece(type, side)) {
return 1;
}
}
return 0;
}
constexpr bool Board::is_piece_attack_square(piece::Type type, Color color, Square source,
Square target) const {
return get_bitboard_piece_attacks(type, color, source) & (C64(1) << to_underlying(target));
}
constexpr bool Board::is_check(void) const {
U64 king = pieces[to_underlying(piece::Type::KING)] & colors[to_underlying(side)];
Color side_other = (side == Color::BLACK) ? Color::WHITE : Color::BLACK;
Square square = static_cast<Square>(bit_lsb_index(king));
return is_square_attacked(square, side_other);
}
U64 Zobrist::hash(const Board &board) {
U64 key_final = C64(0);
uint8_t square;
for (piece::Type type : piece::TypeIter()) {
int piece_white_index = piece::get_index(type, Color::WHITE);
U64 bitboard_white = board.get_bitboard_piece(type, Color::WHITE);
bitboard_for_each_bit(square, bitboard_white) { key_final ^= keys_piece[piece_white_index][square]; }
int piece_black_index = piece::get_index(type, Color::BLACK);
U64 bitboard_black = board.get_bitboard_piece(type, Color::BLACK);
bitboard_for_each_bit(square, bitboard_black) { key_final ^= keys_piece[piece_black_index][square]; }
}
key_final ^= keys_castle[board.get_castle()];
if (board.get_side() == Color::BLACK) key_final ^= keys_side;
if (board.get_enpassant() != Square::no_sq)
key_final ^= keys_enpassant[to_underlying(board.get_enpassant())];
return key_final;
}
#endif

diff --git a/src/board/zobrist.hpp b/src/board/zobrist.hpp

@@ -0,0 +1,63 @@

#ifndef STELLAR_ZOBRIST_H
#define STELLAR_ZOBRIST_H
#include "piece.hpp"
#include "random.hpp"
#include <algorithm>
#include <array>
#include <random>
class Board;
class Zobrist {
public:
Zobrist() = delete;
static inline U64 hash(const Board &board);
static inline constexpr U64 key_side(void) { return keys_side; }
static inline constexpr U64 key_castle(int exp) { return keys_castle[exp]; }
static inline constexpr U64 key_enpassant(Square square) { return keys_enpassant[to_underlying(square)]; }
static inline constexpr U64 key_piece(piece::Type type, Color color, Square square) {
return keys_piece[piece::get_index(type, color)][to_underlying(square)];
}
private:
typedef std::array<std::array<U64, 64>, 12> key_piece_array;
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::WHITE).index;
int piece_index_black = piece::get(type, 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;
}();
typedef std::array<U64, 64> key_enpassant_array;
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;
}();
typedef std::array<U64, 16> key_castle_array;
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;
}();
static inline constexpr const U64 keys_side = Random(C32(1699391443))();
};
#endif

diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt

@@ -6,6 +6,8 @@ add_executable(engine

target_link_libraries(engine
PRIVATE board
PRIVATE moves
PRIVATE piece
PRIVATE utils
)
set_target_properties(engine PROPERTIES

diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp

@@ -2,6 +2,7 @@

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include "attack.hpp"
#include "board.hpp"

@@ -10,8 +11,7 @@

#include "piece.hpp"
#include "score.hpp"
#include "transposition.hpp"
#include "utils_cpp.hpp"
#include "zobrist.hpp"
#include "utils.hpp"
#define MAX_PLY 64
#define FULL_DEPTH 4

diff --git a/src/engine/transposition.hpp b/src/engine/transposition.hpp

@@ -2,7 +2,7 @@

#define STELLAR_TRANSPOSITION_H
#include "move.hpp"
#include "utils_cpp.hpp"
#include "utils.hpp"
#include <vector>

diff --git a/src/include/attack.hpp b/src/include/attack.hpp

@@ -1,328 +0,0 @@

#ifndef STELLAR_ATTAKCS_INTERNAL_H
#define STELLAR_ATTAKCS_INTERNAL_H
#include "magic.hpp"
#include "utils_cpp.hpp"
#include <array>
namespace attack {
class Slider {
public:
virtual constexpr U32 hash(U64 key, Square square) const = 0;
virtual constexpr U64 mask(Square square) const = 0;
virtual constexpr U64 mask_fly(Square square, U64 block) const = 0;
static inline constexpr U64 occupancy(U64 index, uint8_t bits_in_mask, U64 attack_mask) {
U64 occupancy = C64(0);
for (uint8_t count = 0; count < bits_in_mask; count++) {
uint8_t square = bit_lsb_index(attack_mask);
bit_pop(attack_mask, square);
if (bit_get(index, count)) bit_set(occupancy, square);
}
return occupancy;
}
protected:
static inline constexpr U64 mask_slide(Square square, U64 block, const direction_f dir[4],
const int len[4]) {
U64 bitboard = C64(0), attacks = C64(0);
bit_set(bitboard, to_underlying(square));
for (int i = 0; i < 4; i++) {
U64 tmp = bitboard;
for (int j = 0; j < len[i]; j++) {
attacks |= tmp = (dir[i])(tmp);
if (tmp & block) break;
}
}
return attacks;
}
};
class SliderRook : public Slider {
public:
virtual constexpr U32 hash(U64 key, Square square) const override {
uint8_t square_i = to_underlying(square);
return (key * rook_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]);
}
virtual constexpr U64 mask(Square square) const override { return masks[to_underlying(square)]; }
virtual constexpr U64 mask_fly(Square square, U64 block) const override {
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 mask_slide(square, block, dir, len);
}
private:
static inline constexpr const direction_f dir[4] = {westOne, soutOne, eastOne, nortOne};
// clang-format off
static inline constexpr const int relevant_bits[64] = {
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
static inline constexpr const std::array<U64, 64> masks = []() constexpr -> std::array<U64, 64> {
std::array<U64, 64> masks;
for (const Square square : SquareIter()) {
const uint8_t square_i = to_underlying(square);
const int tr = square_i / 8, tf = square_i % 8;
const int len[4] = {tf - 1, tr - 1, 6 - tf, 6 - tr};
masks[square_i] = mask_slide(square, C64(0), dir, len);
}
return masks;
}();
};
class SliderBishop : public Slider {
public:
virtual constexpr U32 hash(U64 key, Square square) const override {
uint8_t square_i = to_underlying(square);
return (key * bishop_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]);
}
virtual constexpr U64 mask(Square square) const override { return masks[to_underlying(square)]; }
virtual constexpr U64 mask_fly(Square square, U64 block) const override {
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 mask_slide(square, block, dir, len);
}
private:
static inline constexpr const direction_f dir[4] = {noEaOne, noWeOne, soEaOne, soWeOne};
// clang-format off
static inline constexpr const int relevant_bits[64] = {
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
static inline constexpr const std::array<U64, 64> masks = []() constexpr -> std::array<U64, 64> {
std::array<U64, 64> masks;
for (const Square square : SquareIter()) {
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) - 1, std::min(tf, 7 - tr) - 1, std::min(7 - tf, tr) - 1,
std::min(tf, tr) - 1};
masks[square_i] = mask_slide(square, C64(0), dir, len);
}
return masks;
}();
};
inline constexpr const SliderRook slider_rook;
inline constexpr const SliderBishop slider_bishop;
class Attack {
public:
virtual constexpr U64 operator()(Square square, U64 occupancy) const = 0;
protected:
template <std::size_t size> using slider_attack_array = std::array<std::array<U64, size>, 64>;
static inline constexpr const auto slider_attacks =
[]<std::size_t size>(const Slider &slider) constexpr -> slider_attack_array<size> {
slider_attack_array<size> attacks;
for (const Square square : SquareIter()) {
uint8_t square_i = to_underlying(square);
U64 attack_mask = slider.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 = slider.hash(occupancy, square);
attacks[square_i][magic_index] = slider.mask_fly(square, occupancy);
}
}
return attacks;
};
};
class Rook : public Attack {
public:
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
occupancy &= slider_rook.mask(square);
occupancy = slider_rook.hash(occupancy, square);
return attacks[to_underlying(square)][occupancy];
}
private:
static inline constexpr const slider_attack_array<4096> attacks =
slider_attacks.operator()<4096>(slider_rook);
};
class Bishop : public Attack {
public:
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
occupancy &= slider_bishop.mask(square);
occupancy = slider_bishop.hash(occupancy, square);
return attacks[to_underlying(square)][occupancy];
}
private:
static inline constexpr const slider_attack_array<512> attacks =
slider_attacks.operator()<512>(slider_bishop);
};
class King : public Attack {
public:
constexpr King() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
}
private:
static constexpr U64 mask(Square square) {
U64 bitboard = C64(0), attacks = C64(0);
bit_set(bitboard, to_underlying(square));
attacks |= westOne(bitboard) | eastOne(bitboard);
attacks |= soutOne(bitboard) | nortOne(bitboard);
attacks |= soutOne(bitboard) | nortOne(bitboard);
attacks |= soEaOne(bitboard) | noEaOne(bitboard);
attacks |= soWeOne(bitboard) | noWeOne(bitboard);
return attacks;
}
typedef std::array<U64, 64> attack_array;
const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (const Square square : SquareIter())
attacks[to_underlying(square)] = mask(square);
return attacks;
}();
};
class Knight : public Attack {
public:
constexpr Knight() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
}
private:
static constexpr U64 mask(Square square) {
U64 bitboard = C64(0), attacks = C64(0), tmp;
bit_set(bitboard, to_underlying(square));
tmp = nortOne(nortOne(bitboard));
attacks |= westOne(tmp) | eastOne(tmp);
tmp = soutOne(soutOne(bitboard));
attacks |= westOne(tmp) | eastOne(tmp);
tmp = westOne(westOne(bitboard));
attacks |= soutOne(tmp) | nortOne(tmp);
tmp = eastOne(eastOne(bitboard));
attacks |= soutOne(tmp) | nortOne(tmp);
return attacks;
}
typedef std::array<U64, 64> attack_array;
const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (const Square square : SquareIter())
attacks[to_underlying(square)] = mask(square);
return attacks;
}();
};
class PawnW : public Attack {
public:
constexpr PawnW() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
}
private:
static constexpr U64 mask(Square square) {
U64 bitboard = C64(0);
bit_set(bitboard, to_underlying(square));
return noWeOne(bitboard) | noEaOne(bitboard);
}
typedef std::array<U64, 64> attack_array;
const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (const Square square : SquareIter())
attacks[to_underlying(square)] = mask(square);
return attacks;
}();
};
class PawnB : public Attack {
public:
constexpr PawnB() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
}
private:
static constexpr U64 mask(Square square) {
U64 bitboard = C64(0);
bit_set(bitboard, to_underlying(square));
return soWeOne(bitboard) | soEaOne(bitboard);
}
typedef std::array<U64, 64> attack_array;
const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (const Square square : SquareIter())
attacks[to_underlying(square)] = mask(square);
return attacks;
}();
};
inline constexpr const Rook rook;
inline constexpr const Bishop bishop;
inline constexpr const King king;
inline constexpr const Knight knight;
inline constexpr const PawnW pawnW;
inline constexpr const PawnB pawnB;
class Queen : public Attack {
public:
constexpr Queen() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return rook(square, occupancy) | bishop(square, occupancy);
}
};
inline constexpr const Queen queen;
} // namespace attack
#endif

diff --git a/src/include/board.hpp b/src/include/board.hpp

@@ -1,76 +0,0 @@

#ifndef STELLAR_BOARD_H
#define STELLAR_BOARD_H
#include "piece.hpp"
#include "utils_cpp.hpp"
#include <iostream>
#include <string>
class Board {
public:
enum class Castle : uint8_t {
WK = 1,
WQ = 2,
BK = 4,
BQ = 8
};
Board() = default;
Board(const std::string &fen);
friend std::ostream &operator<<(std::ostream &os, const Board &board);
/* Getters */
U64 get_hash(void) const;
Color get_side(void) const;
uint8_t get_castle(void) const;
Square get_enpassant(void) const;
U64 get_bitboard_color(Color side) const;
U64 get_bitboard_occupancy(void) const;
U64 get_bitboard_piece(piece::Type piece) const;
U64 get_bitboard_piece(piece::Type piece, Color color) const;
U64 get_bitboard_piece_attacks(piece::Type piece, Color color, Square from) const;
U64 get_bitboard_piece_moves(piece::Type piece, Color color, Square from) const;
Color get_square_piece_color(Square square) const;
piece::Type get_square_piece_type(Square square) const;
const piece::Piece *get_square_piece(Square square) const;
/* Setters */
void xor_hash(U64 op);
void switch_side(void);
void and_castle(uint8_t right);
void set_enpassant(Square target);
void pop_bitboard_color(Color color, Square square);
void set_bitboard_color(Color color, Square square);
void pop_bitboard_piece(piece::Type type, Square square);
void set_bitboard_piece(piece::Type type, Square square);
void pop_piece(piece::Type type, Color side, Square square);
void set_piece(piece::Type type, Color side, Square square);
/* Queries */
bool is_square_attacked(Square Square, Color side) const;
bool is_square_occupied(Square Square) const;
bool is_piece_attack_square(piece::Type type, Color color, Square source, Square target) const;
bool is_check(void) const;
private:
U64 colors[2] = {0};
U64 pieces[6] = {0};
U64 hash = 0;
Color side = Color::WHITE;
Square enpassant = Square::no_sq;
uint8_t castle = 0;
};
#endif

diff --git a/src/include/magic.hpp b/src/include/magic.hpp

@@ -1,44 +0,0 @@

#ifndef STELLAR_ATTACKS_MAGIC_H
#define STELLAR_ATTACKS_MAGIC_H
#include "utils_cpp.hpp"
static 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 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),
};
#endif

diff --git a/src/include/move.hpp b/src/include/move.hpp

@@ -1,68 +0,0 @@

#ifndef STELLAR_MOVES_H
#define STELLAR_MOVES_H
#include "board.hpp"
#include "piece.hpp"
#include "utils_cpp.hpp"
#include <iostream>
#include <vector>
struct Move {
enum Flag : uint8_t {
QUIET,
DOUBLE,
CASTLEK,
CASTLEQ,
CAPTURE,
ENPASSANT,
PKNIGHT = 8,
PBISHOP,
PROOK,
PQUEEN,
PCKNIGHT,
PCBISHOP,
PCROOK,
PCQUEEN,
};
Move() = default;
Move(Square source, Square target, Flag flags)
: source_i(to_underlying(source)), target_i(to_underlying(target)), flags_i(flags) {}
bool operator==(Move &m) const {
return source_i == m.source_i && target_i == m.target_i && flags_i == m.flags_i;
}
Square source(void) const { return static_cast<Square>(source_i); }
Square target(void) const { return static_cast<Square>(target_i); }
bool is_capture(void) const { return flags_i & CAPTURE; }
bool is_promote(void) const { return flags_i & 0x8; }
bool is_quiet(void) const { return flags_i == QUIET; }
bool is_double(void) const { return flags_i == DOUBLE; }
bool is_castle(void) const { return flags_i == CASTLEK || flags_i == CASTLEQ; }
bool is_castle_king(void) const { return flags_i == CASTLEK; }
bool is_castle_queen(void) const { return flags_i == CASTLEQ; }
bool is_enpassant(void) const { return flags_i == ENPASSANT; }
const piece::Type promoted(void) const { return static_cast<piece::Type>((flags_i & 0x3) + 1); }
bool make(Board &board, bool attack_only) const;
friend std::ostream &operator<<(std::ostream &os, Move move);
private:
inline void piece_remove(Board &board, piece::Type type, Color color, Square square) const;
inline void piece_set(Board &board, piece::Type type, Color color, Square square) const;
inline void piece_move(Board &board, piece::Type type, Color color, Square source, Square target) const;
unsigned source_i : 6;
unsigned target_i : 6;
unsigned flags_i : 4;
};
#endif

diff --git a/src/include/movelist.hpp b/src/include/movelist.hpp

@@ -1,35 +0,0 @@

#ifndef STELLAR_MOVE_LIST_H
#define STELLAR_MOVE_LIST_H
#include "board.hpp"
#include "move.hpp"
#include "utils_cpp.hpp"
#include <iostream>
#include <numeric>
#include <vector>
class MoveList {
private:
using list_t = std::vector<Move>;
using index_t = std::vector<int>;
public:
MoveList(const Board &board) : list() {
list.reserve(256);
generate(board);
}
int size() const { return list.size(); }
const Move operator[](size_t idx) const { return list[idx]; }
friend std::ostream &operator<<(std::ostream &os, const MoveList &list);
private:
void generate(const Board &board);
void clear() { list.clear(); }
list_t list;
};
#endif

diff --git a/src/include/piece.hpp b/src/include/piece.hpp

@@ -1,214 +0,0 @@

#ifndef STELLAR_PIECE_H
#define STELLAR_PIECE_H
#include "attack.hpp"
#include "utils_cpp.hpp"
#include <cctype>
namespace piece {
enum class Type {
PAWN = 0,
KNIGHT,
BISHOP,
ROOK,
QUEEN,
KING,
NONE = 7,
};
typedef Iterator<Type, Type::PAWN, Type::KING> TypeIter;
class Piece {
public:
constexpr U64 operator()(Square from, U64 occupancy) const { return attack(from, occupancy); }
const Type type;
const Color color;
const char code;
const char *symbol;
const uint8_t index;
protected:
constexpr Piece(Type type, Color color, char code, const char *symbol, const attack::Attack &attack)
: type(type), color(color), code(code), symbol(symbol), index(index_calc(color, type)),
attack(attack) {}
constexpr uint8_t index_calc(Color color, Type type) {
return to_underlying(color) * 6 + to_underlying(type);
}
private:
const attack::Attack &attack;
};
class Pawn : public Piece {
public:
constexpr Pawn(Color color)
: Piece(Type::PAWN, color, color == Color::WHITE ? 'P' : 'p', color == Color::WHITE ? "■ " : "■ ",
color == Color::WHITE ? *(attack::Attack *)&attack::pawnW
: *(attack::Attack *)&attack::pawnB) {}
};
class Knight : public Piece {
public:
constexpr Knight(Color color)
: Piece(Type::KNIGHT, color, color == Color::WHITE ? 'N' : 'n', color == Color::WHITE ? "■ " : "■ ",
attack::knight) {}
};
class Bishop : public Piece {
public:
constexpr Bishop(Color color)
: Piece(Type::BISHOP, color, color == Color::WHITE ? 'B' : 'b', color == Color::WHITE ? "■ " : "■ ",
attack::bishop) {}
};
class Rook : public Piece {
public:
constexpr Rook(Color color)
: Piece(Type::ROOK, color, color == Color::WHITE ? 'R' : 'r', color == Color::WHITE ? "■ " : "■ ",
attack::rook) {}
};
class Queen : public Piece {
public:
constexpr Queen(Color color)
: Piece(Type::QUEEN, color, color == Color::WHITE ? 'Q' : 'q', color == Color::WHITE ? "■ " : "■ ",
attack::queen) {}
};
class King : public Piece {
public:
constexpr King(Color color)
: Piece(Type::KING, color, color == Color::WHITE ? 'K' : 'k', color == Color::WHITE ? "■ " : "■ ",
attack::king) {}
};
const constexpr Piece table[2][6] = {
{Pawn(Color::WHITE), Knight(Color::WHITE), Bishop(Color::WHITE), Rook(Color::WHITE), Queen(Color::WHITE),
King(Color::WHITE)},
{Pawn(Color::BLACK), Knight(Color::BLACK), Bishop(Color::BLACK), Rook(Color::BLACK), Queen(Color::BLACK),
King(Color::BLACK)},
};
constexpr const Piece &get(Type type, Color color) {
return table[static_cast<int>(color)][static_cast<int>(type)];
}
constexpr const U64 get_attack(Type type, Color color, Square from, U64 occupancy) {
return get(type, color)(from, occupancy);
}
constexpr const char get_code(Type type, Color color = Color::WHITE) { return get(type, color).code; }
constexpr const U64 get_index(Type type, Color color) { return get(type, color).index; }
constexpr const Piece &get_from_code(char code) {
Color color = isupper(code) ? Color::WHITE : Color::BLACK;
for (Type type : TypeIter()) {
const Piece &piece = get(type, color);
if (piece.code == code) return piece;
}
throw std::exception();
}
constexpr const Piece &get_from_index(uint8_t index) { return table[index / 6][index % 6]; }
inline constexpr const Square mirror[65] = {
// clang-format off
Square::a8, Square::b8, Square::c8, Square::d8, Square::e8, Square::f8, Square::g8, Square::h8,
Square::a7, Square::b7, Square::c7, Square::d7, Square::e7, Square::f7, Square::g7, Square::h7,
Square::a6, Square::b6, Square::c6, Square::d6, Square::e6, Square::f6, Square::g6, Square::h6,
Square::a5, Square::b5, Square::c5, Square::d5, Square::e5, Square::f5, Square::g5, Square::h5,
Square::a4, Square::b4, Square::c4, Square::d4, Square::e4, Square::f4, Square::g4, Square::h4,
Square::a3, Square::b3, Square::c3, Square::d3, Square::e3, Square::f3, Square::g3, Square::h3,
Square::a2, Square::b2, Square::c2, Square::d2, Square::e2, Square::f2, Square::g2, Square::h2,
Square::a1, Square::b1, Square::c1, Square::d1, Square::e1, Square::f1, Square::g1, Square::h1, Square::no_sq,
// clang-format on
};
constexpr inline const uint16_t value[6] = {100, 300, 350, 500, 1000, 10000};
constexpr inline const uint16_t capture[6][6] = {
// clang-format off
{105, 205, 305, 405, 505, 605},
{104, 204, 304, 404, 504, 604},
{103, 203, 303, 403, 503, 603},
{102, 202, 302, 402, 502, 602},
{101, 201, 301, 401, 501, 601},
{100, 200, 300, 400, 500, 600},
// clang-format on
};
constexpr inline const int8_t position[6][64] = {
// clang-format off
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, -10, -10, 0, 0, 0,
0, 0, 0, 5, 5, 0, 0, 0,
5, 5, 10, 20, 20, 5, 5, 5,
10, 10, 10, 20, 20, 10, 10, 10,
20, 20, 20, 30, 30, 30, 20, 20,
30, 30, 30, 40, 40, 30, 30, 30,
90, 90, 90, 90, 90, 90, 90, 90
}, {
-5, -10 , 0, 0, 0, 0, -10, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 5, 20, 10, 10, 20, 5, -5,
-5, 10, 20, 30, 30, 20, 10, -5,
-5, 10, 20, 30, 30, 20, 10, -5,
-5, 5, 20, 20, 20, 20, 5, -5,
-5, 0, 0, 10, 10, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5
}, {
0, 0, -10, 0, 0, -10, 0, 0,
0, 30, 0, 0, 0, 0, 30, 0,
0, 10, 0, 0, 0, 0, 10, 0,
0, 0, 10, 20, 20, 10, 0, 0,
0, 0, 10, 20, 20, 10, 0, 0,
0, 0, 0, 10, 10, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
}, {
0, 0, 0, 20, 20, 0, 0, 0,
0, 0, 10, 20, 20, 10, 0, 0,
0, 0, 10, 20, 20, 10, 0, 0,
0, 0, 10, 20, 20, 10, 0, 0,
0, 0, 10, 20, 20, 10, 0, 0,
0, 0, 10, 20, 20, 10, 0, 0,
50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50
}, {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
}, {
0, 0, 5, 0, -15, 0, 10, 0,
0, 5, 5, -5, -5, 0, 5, 0,
0, 0, 5, 10, 10, 5, 0, 0,
0, 5, 10, 20, 20, 10, 5, 0,
0, 5, 10, 20, 20, 10, 5, 0,
0, 5, 5, 10, 10, 5, 5, 0,
0, 0, 5, 5, 5, 5, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
},
// clang-format on
};
constexpr uint16_t score(Type piece) { return value[to_underlying(piece)]; }
constexpr uint16_t score(Type piece, Type captured) {
return capture[to_underlying(piece)][to_underlying(captured)];
}
constexpr int8_t score(Type type, Color color, Square square) {
if (color == Color::BLACK) square = mirror[to_underlying(square)];
return position[to_underlying(type)][to_underlying(square)];
}
} // namespace piece
#endif

diff --git a/src/include/random.hpp b/src/include/random.hpp

@@ -1,41 +0,0 @@

#ifndef STELLAR_RANDOM_H
#define STELLAR_RANDOM_H
#include "utils_cpp.hpp"
class Random {
public:
constexpr Random(void) = default;
constexpr Random(U64 seed) : state(seed) {}
constexpr U64 operator()(void) { return get_U64(); }
constexpr void reset(void) { state = seed; }
constexpr U32 get_U32(void) {
U32 number = state;
number ^= number << 13;
number ^= number >> 17;
number ^= number << 5;
return state = number;
}
constexpr U64 get_U64(void) {
U64 n1, n2, n3, n4;
n1 = (U64)(get_U32()) & C64(0xFFFF);
n2 = (U64)(get_U32()) & C64(0xFFFF);
n3 = (U64)(get_U32()) & C64(0xFFFF);
n4 = (U64)(get_U32()) & C64(0xFFFF);
return n1 | (n2 << 16) | (n3 << 32) | (n4 << 48);
}
private:
static inline constexpr const U32 seed = C32(1804289383);
U32 state = seed;
};
#endif

diff --git a/src/include/utils_cpp.hpp b/src/include/utils_cpp.hpp

@@ -1,127 +0,0 @@

#ifndef STELLAR_UTILS_CPP_H
#define STELLAR_UTILS_CPP_H
#include <cstdint>
#include <exception>
#include <type_traits>
template <typename E> constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept {
return static_cast<typename std::underlying_type<E>::type>(e);
}
template <typename C, C beginVal, C endVal> class Iterator {
typedef typename std::underlying_type<C>::type val_t;
int val;
public:
constexpr Iterator(const C &f) : val(static_cast<val_t>(f)) {}
constexpr Iterator() : val(static_cast<val_t>(beginVal)) {}
constexpr Iterator operator++() {
++val;
return *this;
}
constexpr C operator*() { return static_cast<C>(val); }
constexpr Iterator begin() { return *this; }
constexpr Iterator end() {
// static const Iterator endIter = ++Iterator(endVal);
// return endIter;
return ++Iterator(endVal);
}
constexpr bool operator!=(const Iterator &i) { return val != i.val; }
};
#define C64(constantU64) constantU64##ULL
#define C32(constantU64) constantU64##UL
typedef uint64_t U64;
typedef uint32_t U32;
enum class Color : bool {
WHITE = 0,
BLACK
};
// clang-format off
enum class Square: uint8_t {
a1, b1, c1, d1, e1, f1, g1, h1,
a2, b2, c2, d2, e2, f2, g2, h2,
a3, b3, c3, d3, e3, f3, g3, h3,
a4, b4, c4, d4, e4, f4, g4, h4,
a5, b5, c5, d5, e5, f5, g5, h5,
a6, b6, c6, d6, e6, f6, g6, h6,
a7, b7, c7, d7, e7, f7, g7, h7,
a8, b8, c8, d8, e8, f8, g8, h8, no_sq
};
// clang-format on
typedef Iterator<Square, Square::a1, Square::h8> SquareIter;
inline Square square_from_coordinates(const char *cord) {
return static_cast<Square>((cord[1] - '1') * 8 + (cord[0] - 'a'));
}
// clang-format off
inline const char *square_to_coordinates(Square square) {
static const char *map[]={
"a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1",
"a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2",
"a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3",
"a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4",
"a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5",
"a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6",
"a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7",
"a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8", " "
};
return map[to_underlying(square)];
}
// clang-format on
// useful bit functions
constexpr bool bit_get(const U64 &bitboard, uint8_t square) { return (bitboard >> (square)) & C64(1); }
constexpr void bit_set(U64 &bitboard, uint8_t square) { bitboard |= (C64(1) << square); }
constexpr void bit_pop(U64 &bitboard, uint8_t square) { bitboard &= ~(C64(1) << (square)); }
constexpr uint8_t bit_count(U64 bitboard) {
#if __has_builtin(__builtin_popcountll)
return __builtin_popcountll(bitboard);
#endif
int count = 0;
for (; bitboard > 0; bitboard &= bitboard - 1)
count++;
return count;
}
constexpr uint8_t bit_lsb_index(U64 bitboard) {
#if __has_builtin(__builtin_ffsll)
return __builtin_ffsll(bitboard) - 1;
#endif
if (!bitboard) return -1;
return bit_count((bitboard & -bitboard) - 1);
}
#define bit_lsb_pop(bitboard) ((bitboard) &= (bitboard) & ((bitboard)-1))
#define bitboard_for_each_bit(var, bb) \
for (var = bit_lsb_index(bb); bb; bit_lsb_pop(bb), var = bit_lsb_index(bb))
// board moving
inline constexpr const U64 universe = C64(0xffffffffffffffff);
inline constexpr const U64 notAFile = C64(0xfefefefefefefefe);
inline constexpr const U64 notHFile = C64(0x7f7f7f7f7f7f7f7f);
typedef U64 (*direction_f)(U64);
inline constexpr U64 soutOne(U64 b) { return b >> 8; }
inline constexpr U64 nortOne(U64 b) { return b << 8; }
inline constexpr U64 eastOne(U64 b) { return (b & notHFile) << 1; }
inline constexpr U64 westOne(U64 b) { return (b & notAFile) >> 1; }
inline constexpr U64 soEaOne(U64 b) { return (b & notHFile) >> 7; }
inline constexpr U64 soWeOne(U64 b) { return (b & notAFile) >> 9; }
inline constexpr U64 noEaOne(U64 b) { return (b & notHFile) << 9; }
inline constexpr U64 noWeOne(U64 b) { return (b & notAFile) << 7; }
#define start_position "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 "
#endif

diff --git a/src/include/zobrist.hpp b/src/include/zobrist.hpp

@@ -1,89 +0,0 @@

#ifndef STELLAR_ZOBRIST_H
#define STELLAR_ZOBRIST_H
#include "board.hpp"
#include "piece.hpp"
#include "random.hpp"
#include <algorithm>
#include <array>
#include <random>
class Zobrist {
public:
Zobrist() = delete;
static inline constexpr U64 key_side(void) { return keys_side; }
static inline constexpr U64 key_castle(int exp) { return keys_castle[exp]; }
static inline constexpr U64 key_enpassant(Square square) { return keys_enpassant[to_underlying(square)]; }
static inline constexpr U64 key_piece(piece::Type type, Color color, Square square) {
return keys_piece[piece::get_index(type, color)][to_underlying(square)];
}
static inline U64 hash(const Board &board) {
U64 key_final = C64(0);
uint8_t square;
for (piece::Type type : piece::TypeIter()) {
int piece_white_index = piece::get_index(type, Color::WHITE);
U64 bitboard_white = board.get_bitboard_piece(type, Color::WHITE);
bitboard_for_each_bit(square, bitboard_white) {
key_final ^= keys_piece[piece_white_index][square];
}
int piece_black_index = piece::get_index(type, Color::BLACK);
U64 bitboard_black = board.get_bitboard_piece(type, Color::BLACK);
bitboard_for_each_bit(square, bitboard_black) {
key_final ^= keys_piece[piece_black_index][square];
}
}
key_final ^= keys_castle[board.get_castle()];
if (board.get_side() == Color::BLACK) key_final ^= keys_side;
if (board.get_enpassant() != Square::no_sq)
key_final ^= keys_enpassant[to_underlying(board.get_enpassant())];
return key_final;
}
private:
typedef std::array<std::array<U64, 64>, 12> key_piece_array;
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::WHITE).index;
int piece_index_black = piece::get(type, 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;
}();
typedef std::array<U64, 64> key_enpassant_array;
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;
}();
typedef std::array<U64, 16> key_castle_array;
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;
}();
static inline constexpr const U64 keys_side = Random(C32(1699391443))();
};
#endif

diff --git a/src/move/CMakeLists.txt b/src/move/CMakeLists.txt

@@ -3,6 +3,10 @@ add_library(moves OBJECT

movelist.cpp
)
target_include_directories(moves
PUBLIC "${PROJECT_SOURCE_DIR}/src/include"
target_link_libraries(moves
PRIVATE piece
PRIVATE board
PRIVATE utils
)
target_include_directories(moves INTERFACE .)

diff --git a/src/move/move.cpp b/src/move/move.cpp

@@ -1,6 +1,5 @@

#include "move.hpp"
#include "utils_cpp.hpp"
#include "zobrist.hpp"
#include "utils.hpp"
#include <algorithm>
#include <iomanip>

@@ -42,7 +41,7 @@ bool Move::make(Board &board, bool attack_only) const {

return 0;
} else {
const Color color = board.get_side();
Color colorOther = color == Color::BLACK ? Color::WHITE : Color::BLACK;
const Color colorOther = color == Color::BLACK ? Color::WHITE : Color::BLACK;
const Square source = this->source();
const Square target = this->target();

@@ -85,10 +84,9 @@ bool Move::make(Board &board, bool attack_only) const {

}
}
board.xor_hash(Zobrist::key_castle(board.get_castle()));
board.and_castle(castling_rights[to_underlying(this->source())]);
board.and_castle(castling_rights[to_underlying(this->target())]);
board.xor_hash(Zobrist::key_castle(board.get_castle()));
const U64 mask =
castling_rights[to_underlying(this->source())] && castling_rights[to_underlying(this->target())];
board.and_castle(mask);
if (!board.is_check()) {
board.switch_side();

diff --git a/src/move/move.hpp b/src/move/move.hpp

@@ -0,0 +1,68 @@

#ifndef STELLAR_MOVES_H
#define STELLAR_MOVES_H
#include "board.hpp"
#include "piece.hpp"
#include "utils.hpp"
#include <iostream>
#include <vector>
struct Move {
enum Flag : uint8_t {
QUIET,
DOUBLE,
CASTLEK,
CASTLEQ,
CAPTURE,
ENPASSANT,
PKNIGHT = 8,
PBISHOP,
PROOK,
PQUEEN,
PCKNIGHT,
PCBISHOP,
PCROOK,
PCQUEEN,
};
Move() = default;
Move(Square source, Square target, Flag flags)
: source_i(to_underlying(source)), target_i(to_underlying(target)), flags_i(flags) {}
bool operator==(Move &m) const {
return source_i == m.source_i && target_i == m.target_i && flags_i == m.flags_i;
}
Square source(void) const { return static_cast<Square>(source_i); }
Square target(void) const { return static_cast<Square>(target_i); }
bool is_capture(void) const { return flags_i & CAPTURE; }
bool is_promote(void) const { return flags_i & 0x8; }
bool is_quiet(void) const { return flags_i == QUIET; }
bool is_double(void) const { return flags_i == DOUBLE; }
bool is_castle(void) const { return flags_i == CASTLEK || flags_i == CASTLEQ; }
bool is_castle_king(void) const { return flags_i == CASTLEK; }
bool is_castle_queen(void) const { return flags_i == CASTLEQ; }
bool is_enpassant(void) const { return flags_i == ENPASSANT; }
const piece::Type promoted(void) const { return static_cast<piece::Type>((flags_i & 0x3) + 1); }
bool make(Board &board, bool attack_only) const;
friend std::ostream &operator<<(std::ostream &os, Move move);
private:
inline void piece_remove(Board &board, piece::Type type, Color color, Square square) const;
inline void piece_set(Board &board, piece::Type type, Color color, Square square) const;
inline void piece_move(Board &board, piece::Type type, Color color, Square source, Square target) const;
unsigned source_i : 6;
unsigned target_i : 6;
unsigned flags_i : 4;
};
#endif

diff --git a/src/move/movelist.hpp b/src/move/movelist.hpp

@@ -0,0 +1,35 @@

#ifndef STELLAR_MOVE_LIST_H
#define STELLAR_MOVE_LIST_H
#include "board.hpp"
#include "move.hpp"
#include "utils.hpp"
#include <iostream>
#include <numeric>
#include <vector>
class MoveList {
private:
using list_t = std::vector<Move>;
using index_t = std::vector<int>;
public:
MoveList(const Board &board) : list() {
list.reserve(256);
generate(board);
}
int size() const { return list.size(); }
const Move operator[](size_t idx) const { return list[idx]; }
friend std::ostream &operator<<(std::ostream &os, const MoveList &list);
private:
void generate(const Board &board);
void clear() { list.clear(); }
list_t list;
};
#endif

diff --git a/src/perft/CMakeLists.txt b/src/perft/CMakeLists.txt

@@ -1,13 +1,19 @@

add_executable(perft perft.cpp)
option(WITH_FULL_COUNT "Make count on types of moves" OFF)
if(WITH_FULL_COUNT)
option(STELLAR_FULL_COUNT "Make count on types of moves" OFF)
if(STELLAR_FULL_COUNT)
add_definitions(-DUSE_FULL_COUNT)
endif()
target_link_libraries(perft
PRIVATE board
PRIVATE moves
PRIVATE piece
PRIVATE utils
)
target_precompile_headers(perft
REUSE_FROM engine
)
set_target_properties(perft PROPERTIES

diff --git a/src/perft/perft.cpp b/src/perft/perft.cpp

@@ -5,7 +5,7 @@

#include "board.hpp"
#include "move.hpp"
#include "movelist.hpp"
#include "utils_cpp.hpp"
#include "utils.hpp"
// FEN debug positions
#define tricky_position "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1 "

diff --git a/src/piece/CMakeLists.txt b/src/piece/CMakeLists.txt

@@ -0,0 +1,10 @@

add_library(piece INTERFACE)
target_link_libraries(piece
INTERFACE attack
INTERFACE utils
)
target_include_directories(piece INTERFACE .)
stellar_target_precompile_headers(piece INTERFACE "piece.hpp")

diff --git a/src/piece/piece.hpp b/src/piece/piece.hpp

@@ -0,0 +1,214 @@

#ifndef STELLAR_PIECE_H
#define STELLAR_PIECE_H
#include "attack.hpp"
#include "utils.hpp"
#include <cctype>
namespace piece {
enum class Type {
PAWN = 0,
KNIGHT,
BISHOP,
ROOK,
QUEEN,
KING,
NONE = 7,
};
typedef Iterator<Type, Type::PAWN, Type::KING> TypeIter;
class Piece {
public:
constexpr U64 operator()(Square from, U64 occupancy) const { return attack(from, occupancy); }
const Type type;
const Color color;
const char code;
const char *symbol;
const uint8_t index;
protected:
constexpr Piece(Type type, Color color, char code, const char *symbol, const attack::Attack &attack)
: type(type), color(color), code(code), symbol(symbol), index(index_calc(color, type)),
attack(attack) {}
constexpr uint8_t index_calc(Color color, Type type) {
return to_underlying(color) * 6 + to_underlying(type);
}
private:
const attack::Attack &attack;
};
class Pawn : public Piece {
public:
constexpr Pawn(Color color)
: Piece(Type::PAWN, color, color == Color::WHITE ? 'P' : 'p', color == Color::WHITE ? "■ " : "■ ",
color == Color::WHITE ? *(attack::Attack *)&attack::pawnW
: *(attack::Attack *)&attack::pawnB) {}
};
class Knight : public Piece {
public:
constexpr Knight(Color color)
: Piece(Type::KNIGHT, color, color == Color::WHITE ? 'N' : 'n', color == Color::WHITE ? "■ " : "■ ",
attack::knight) {}
};
class Bishop : public Piece {
public:
constexpr Bishop(Color color)
: Piece(Type::BISHOP, color, color == Color::WHITE ? 'B' : 'b', color == Color::WHITE ? "■ " : "■ ",
attack::bishop) {}
};
class Rook : public Piece {
public:
constexpr Rook(Color color)
: Piece(Type::ROOK, color, color == Color::WHITE ? 'R' : 'r', color == Color::WHITE ? "■ " : "■ ",
attack::rook) {}
};
class Queen : public Piece {
public:
constexpr Queen(Color color)
: Piece(Type::QUEEN, color, color == Color::WHITE ? 'Q' : 'q', color == Color::WHITE ? "■ " : "■ ",
attack::queen) {}
};
class King : public Piece {
public:
constexpr King(Color color)
: Piece(Type::KING, color, color == Color::WHITE ? 'K' : 'k', color == Color::WHITE ? "■ " : "■ ",
attack::king) {}
};
const constexpr Piece table[2][6] = {
{Pawn(Color::WHITE), Knight(Color::WHITE), Bishop(Color::WHITE), Rook(Color::WHITE), Queen(Color::WHITE),
King(Color::WHITE)},
{Pawn(Color::BLACK), Knight(Color::BLACK), Bishop(Color::BLACK), Rook(Color::BLACK), Queen(Color::BLACK),
King(Color::BLACK)},
};
constexpr const Piece &get(Type type, Color color) {
return table[static_cast<int>(color)][static_cast<int>(type)];
}
constexpr const U64 get_attack(Type type, Color color, Square from, U64 occupancy) {
return get(type, color)(from, occupancy);
}
constexpr const char get_code(Type type, Color color = Color::WHITE) { return get(type, color).code; }
constexpr const U64 get_index(Type type, Color color) { return get(type, color).index; }
constexpr const Piece &get_from_code(char code) {
Color color = isupper(code) ? Color::WHITE : Color::BLACK;
for (Type type : TypeIter()) {
const Piece &piece = get(type, color);
if (piece.code == code) return piece;
}
throw std::exception();
}
constexpr const Piece &get_from_index(uint8_t index) { return table[index / 6][index % 6]; }
inline constexpr const Square mirror[65] = {
// clang-format off
Square::a8, Square::b8, Square::c8, Square::d8, Square::e8, Square::f8, Square::g8, Square::h8,
Square::a7, Square::b7, Square::c7, Square::d7, Square::e7, Square::f7, Square::g7, Square::h7,
Square::a6, Square::b6, Square::c6, Square::d6, Square::e6, Square::f6, Square::g6, Square::h6,
Square::a5, Square::b5, Square::c5, Square::d5, Square::e5, Square::f5, Square::g5, Square::h5,
Square::a4, Square::b4, Square::c4, Square::d4, Square::e4, Square::f4, Square::g4, Square::h4,
Square::a3, Square::b3, Square::c3, Square::d3, Square::e3, Square::f3, Square::g3, Square::h3,
Square::a2, Square::b2, Square::c2, Square::d2, Square::e2, Square::f2, Square::g2, Square::h2,
Square::a1, Square::b1, Square::c1, Square::d1, Square::e1, Square::f1, Square::g1, Square::h1, Square::no_sq,
// clang-format on
};
constexpr inline const uint16_t value[6] = {100, 300, 350, 500, 1000, 10000};
constexpr inline const uint16_t capture[6][6] = {
// clang-format off
{105, 205, 305, 405, 505, 605},
{104, 204, 304, 404, 504, 604},
{103, 203, 303, 403, 503, 603},
{102, 202, 302, 402, 502, 602},
{101, 201, 301, 401, 501, 601},
{100, 200, 300, 400, 500, 600},
// clang-format on
};
constexpr inline const int8_t position[6][64] = {
// clang-format off
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, -10, -10, 0, 0, 0,
0, 0, 0, 5, 5, 0, 0, 0,
5, 5, 10, 20, 20, 5, 5, 5,
10, 10, 10, 20, 20, 10, 10, 10,
20, 20, 20, 30, 30, 30, 20, 20,
30, 30, 30, 40, 40, 30, 30, 30,
90, 90, 90, 90, 90, 90, 90, 90
}, {
-5, -10 , 0, 0, 0, 0, -10, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 5, 20, 10, 10, 20, 5, -5,
-5, 10, 20, 30, 30, 20, 10, -5,
-5, 10, 20, 30, 30, 20, 10, -5,
-5, 5, 20, 20, 20, 20, 5, -5,
-5, 0, 0, 10, 10, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5
}, {
0, 0, -10, 0, 0, -10, 0, 0,
0, 30, 0, 0, 0, 0, 30, 0,
0, 10, 0, 0, 0, 0, 10, 0,
0, 0, 10, 20, 20, 10, 0, 0,
0, 0, 10, 20, 20, 10, 0, 0,
0, 0, 0, 10, 10, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
}, {
0, 0, 0, 20, 20, 0, 0, 0,
0, 0, 10, 20, 20, 10, 0, 0,
0, 0, 10, 20, 20, 10, 0, 0,
0, 0, 10, 20, 20, 10, 0, 0,
0, 0, 10, 20, 20, 10, 0, 0,
0, 0, 10, 20, 20, 10, 0, 0,
50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50
}, {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
}, {
0, 0, 5, 0, -15, 0, 10, 0,
0, 5, 5, -5, -5, 0, 5, 0,
0, 0, 5, 10, 10, 5, 0, 0,
0, 5, 10, 20, 20, 10, 5, 0,
0, 5, 10, 20, 20, 10, 5, 0,
0, 5, 5, 10, 10, 5, 5, 0,
0, 0, 5, 5, 5, 5, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
},
// clang-format on
};
constexpr uint16_t score(Type piece) { return value[to_underlying(piece)]; }
constexpr uint16_t score(Type piece, Type captured) {
return capture[to_underlying(piece)][to_underlying(captured)];
}
constexpr int8_t score(Type type, Color color, Square square) {
if (color == Color::BLACK) square = mirror[to_underlying(square)];
return position[to_underlying(type)][to_underlying(square)];
}
} // namespace piece
#endif

diff --git a/src/random/CMakeLists.txt b/src/random/CMakeLists.txt

@@ -0,0 +1,4 @@

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/random/random.hpp b/src/random/random.hpp

@@ -0,0 +1,41 @@

#ifndef STELLAR_RANDOM_H
#define STELLAR_RANDOM_H
#include "utils.hpp"
class Random {
public:
constexpr Random(void) = default;
constexpr Random(U64 seed) : state(seed) {}
constexpr U64 operator()(void) { return get_U64(); }
constexpr void reset(void) { state = seed; }
constexpr U32 get_U32(void) {
U32 number = state;
number ^= number << 13;
number ^= number >> 17;
number ^= number << 5;
return state = number;
}
constexpr U64 get_U64(void) {
U64 n1, n2, n3, n4;
n1 = (U64)(get_U32()) & C64(0xFFFF);
n2 = (U64)(get_U32()) & C64(0xFFFF);
n3 = (U64)(get_U32()) & C64(0xFFFF);
n4 = (U64)(get_U32()) & C64(0xFFFF);
return n1 | (n2 << 16) | (n3 << 32) | (n4 << 48);
}
private:
static inline constexpr const U32 seed = C32(1804289383);
U32 state = seed;
};
#endif

diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt

@@ -0,0 +1,3 @@

add_library(utils INTERFACE)
target_include_directories(utils INTERFACE .)
stellar_target_precompile_headers(attack INTERFACE "utils.hpp")

diff --git a/src/utils/utils.hpp b/src/utils/utils.hpp

@@ -0,0 +1,127 @@

#ifndef STELLAR_UTILS_CPP_H
#define STELLAR_UTILS_CPP_H
#include <cstdint>
#include <exception>
#include <type_traits>
template <typename E> constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept {
return static_cast<typename std::underlying_type<E>::type>(e);
}
template <typename C, C beginVal, C endVal> class Iterator {
typedef typename std::underlying_type<C>::type val_t;
int val;
public:
constexpr Iterator(const C &f) : val(static_cast<val_t>(f)) {}
constexpr Iterator() : val(static_cast<val_t>(beginVal)) {}
constexpr Iterator operator++() {
++val;
return *this;
}
constexpr C operator*() { return static_cast<C>(val); }
constexpr Iterator begin() { return *this; }
constexpr Iterator end() {
// static const Iterator endIter = ++Iterator(endVal);
// return endIter;
return ++Iterator(endVal);
}
constexpr bool operator!=(const Iterator &i) { return val != i.val; }
};
#define C64(constantU64) constantU64##ULL
#define C32(constantU64) constantU64##UL
typedef uint64_t U64;
typedef uint32_t U32;
enum class Color : bool {
WHITE = 0,
BLACK
};
// clang-format off
enum class Square: uint8_t {
a1, b1, c1, d1, e1, f1, g1, h1,
a2, b2, c2, d2, e2, f2, g2, h2,
a3, b3, c3, d3, e3, f3, g3, h3,
a4, b4, c4, d4, e4, f4, g4, h4,
a5, b5, c5, d5, e5, f5, g5, h5,
a6, b6, c6, d6, e6, f6, g6, h6,
a7, b7, c7, d7, e7, f7, g7, h7,
a8, b8, c8, d8, e8, f8, g8, h8, no_sq
};
// clang-format on
typedef Iterator<Square, Square::a1, Square::h8> SquareIter;
inline Square square_from_coordinates(const char *cord) {
return static_cast<Square>((cord[1] - '1') * 8 + (cord[0] - 'a'));
}
// clang-format off
inline const char *square_to_coordinates(Square square) {
static const char *map[]={
"a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1",
"a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2",
"a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3",
"a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4",
"a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5",
"a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6",
"a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7",
"a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8", " "
};
return map[to_underlying(square)];
}
// clang-format on
// useful bit functions
constexpr bool bit_get(const U64 &bitboard, uint8_t square) { return (bitboard >> (square)) & C64(1); }
constexpr void bit_set(U64 &bitboard, uint8_t square) { bitboard |= (C64(1) << square); }
constexpr void bit_pop(U64 &bitboard, uint8_t square) { bitboard &= ~(C64(1) << (square)); }
constexpr uint8_t bit_count(U64 bitboard) {
#if __has_builtin(__builtin_popcountll)
return __builtin_popcountll(bitboard);
#endif
int count = 0;
for (; bitboard > 0; bitboard &= bitboard - 1)
count++;
return count;
}
constexpr uint8_t bit_lsb_index(U64 bitboard) {
#if __has_builtin(__builtin_ffsll)
return __builtin_ffsll(bitboard) - 1;
#endif
if (!bitboard) return -1;
return bit_count((bitboard & -bitboard) - 1);
}
#define bit_lsb_pop(bitboard) ((bitboard) &= (bitboard) & ((bitboard)-1))
#define bitboard_for_each_bit(var, bb) \
for (var = bit_lsb_index(bb); bb; bit_lsb_pop(bb), var = bit_lsb_index(bb))
// board moving
inline constexpr const U64 universe = C64(0xffffffffffffffff);
inline constexpr const U64 notAFile = C64(0xfefefefefefefefe);
inline constexpr const U64 notHFile = C64(0x7f7f7f7f7f7f7f7f);
typedef U64 (*direction_f)(U64);
inline constexpr U64 soutOne(U64 b) { return b >> 8; }
inline constexpr U64 nortOne(U64 b) { return b << 8; }
inline constexpr U64 eastOne(U64 b) { return (b & notHFile) << 1; }
inline constexpr U64 westOne(U64 b) { return (b & notAFile) >> 1; }
inline constexpr U64 soEaOne(U64 b) { return (b & notHFile) >> 7; }
inline constexpr U64 soWeOne(U64 b) { return (b & notAFile) >> 9; }
inline constexpr U64 noEaOne(U64 b) { return (b & notHFile) << 9; }
inline constexpr U64 noWeOne(U64 b) { return (b & notAFile) << 7; }
#define start_position "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 "
#endif