stellar

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

commit b3660d9286bcd94407d954d7932be4f0956e8592
parent 1857c3ab3da2587974a169e7414f3add950a7a5e
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Sat, 26 Aug 2023 16:54:53 +0200

Restructure project, CMake precompiled headers

Diffstat:
MCMakeLists.txt | 7+++++++
Asrc/attack/CMakeLists.txt | 4++++
Asrc/attack/attack.hpp | 365+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/board/CMakeLists.txt | 11+++++++++--
Msrc/board/board.cpp | 120+------------------------------------------------------------------------------
Asrc/board/board.hpp | 223+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/board/zobrist.hpp | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/engine/CMakeLists.txt | 2++
Msrc/engine/engine.cpp | 4++--
Msrc/engine/transposition.hpp | 2+-
Dsrc/include/attack.hpp | 328-------------------------------------------------------------------------------
Dsrc/include/board.hpp | 76----------------------------------------------------------------------------
Dsrc/include/magic.hpp | 44--------------------------------------------
Dsrc/include/move.hpp | 68--------------------------------------------------------------------
Dsrc/include/movelist.hpp | 35-----------------------------------
Dsrc/include/piece.hpp | 214-------------------------------------------------------------------------------
Dsrc/include/random.hpp | 41-----------------------------------------
Dsrc/include/zobrist.hpp | 89-------------------------------------------------------------------------------
Msrc/move/CMakeLists.txt | 8++++++--
Msrc/move/move.cpp | 12+++++-------
Asrc/move/move.hpp | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/move/movelist.hpp | 35+++++++++++++++++++++++++++++++++++
Msrc/perft/CMakeLists.txt | 10++++++++--
Msrc/perft/perft.cpp | 2+-
Asrc/piece/CMakeLists.txt | 10++++++++++
Asrc/piece/piece.hpp | 214+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/random/CMakeLists.txt | 4++++
Asrc/random/random.hpp | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/utils/CMakeLists.txt | 3+++
Rsrc/include/utils_cpp.hpp -> src/utils/utils.hpp | 0
30 files changed, 1072 insertions(+), 1031 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/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/include/utils_cpp.hpp b/src/utils/utils.hpp