stellar

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

commit 3339ad957adba20630645faafc9751f114436587
parent b14ec9be9a45282c4dab765129595acb33bcb32f
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Sun,  3 Sep 2023 22:40:19 +0200

Major refactor

Diffstat:
MCMakeLists.txt | 2+-
Msrc/attack/CMakeLists.txt | 24+++++++++++++++++++++---
Asrc/attack/attack.cpp | 1+
Msrc/attack/attack.hpp | 369+++----------------------------------------------------------------------------
Asrc/attack/bishop.hpp | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/attack/king.hpp | 42++++++++++++++++++++++++++++++++++++++++++
Asrc/attack/knight.hpp | 45+++++++++++++++++++++++++++++++++++++++++++++
Asrc/attack/pawnb.hpp | 36++++++++++++++++++++++++++++++++++++
Asrc/attack/pawnw.hpp | 36++++++++++++++++++++++++++++++++++++
Asrc/attack/queen.hpp | 17+++++++++++++++++
Asrc/attack/rook.hpp | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/attack/slider.hpp | 39+++++++++++++++++++++++++++++++++++++++
Msrc/board/board.cpp | 29++++++++++++++---------------
Msrc/board/board.hpp | 135++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/board/zobrist.hpp | 10++++++----
Msrc/engine/engine.cpp | 12++++++------
Msrc/engine/evaluate.cpp | 88++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/engine/score.hpp | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/engine/uci.cpp | 10+++++-----
Msrc/move/move.cpp | 37++++++++++++++++++++-----------------
Msrc/move/move.hpp | 13+++++++------
Msrc/move/movelist.cpp | 68++++++++++++++++++++++++++++++++++----------------------------------
Msrc/piece/CMakeLists.txt | 1+
Msrc/piece/piece.hpp | 207+++++++++++++++----------------------------------------------------------------
Msrc/utils/CMakeLists.txt | 20++++++++++++++++++--
Asrc/utils/bit.hpp | 39+++++++++++++++++++++++++++++++++++++++
Asrc/utils/bitboard.cpp | 20++++++++++++++++++++
Asrc/utils/bitboard.hpp | 25+++++++++++++++++++++++++
Asrc/utils/color.hpp | 15+++++++++++++++
Asrc/utils/square.hpp | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/utils/utils.cpp | 16----------------
Msrc/utils/utils.hpp | 105++++++-------------------------------------------------------------------------
32 files changed, 986 insertions(+), 839 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project( Stellar - VERSION 0.0.32 + VERSION 0.0.33 DESCRIPTION "Chess engine written in C" HOMEPAGE_URL https://git.dimitrijedobrota.com/stellar.git LANGUAGES C CXX diff --git a/src/attack/CMakeLists.txt b/src/attack/CMakeLists.txt @@ -1,4 +1,22 @@ -add_library(attack INTERFACE) -target_link_libraries(attack INTERFACE utils) +add_library(attack attack.cpp) + +target_link_libraries(attack + PRIVATE bit + PRIVATE bitboard + PRIVATE color + PRIVATE square + PRIVATE utils +) + target_include_directories(attack INTERFACE .) -stellar_target_precompile_headers(attack INTERFACE "attack.hpp") + +stellar_target_precompile_headers(attack + PRIVATE "bishop.hpp" + PRIVATE "king.hpp" + PRIVATE "knight.hpp" + PRIVATE "pawnb.hpp" + PRIVATE "pawnw.hpp" + PRIVATE "queen.hpp" + PRIVATE "rook.hpp" + PRIVATE "slider.hpp" +) diff --git a/src/attack/attack.cpp b/src/attack/attack.cpp @@ -0,0 +1 @@ +#include "attack.hpp" diff --git a/src/attack/attack.hpp b/src/attack/attack.hpp @@ -1,365 +1,22 @@ -#ifndef STELLAR_ATTAKCS_INTERNAL_H -#define STELLAR_ATTAKCS_INTERNAL_H +#ifndef STELLAR_ATTACK_H +#define STELLAR_ATTACK_H +#include "square.hpp" #include "utils.hpp" -#include <array> +#include "bishop.hpp" +#include "king.hpp" +#include "knight.hpp" +#include "pawnb.hpp" +#include "pawnw.hpp" +#include "queen.hpp" +#include "rook.hpp" +#include "slider.hpp" 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), -}; +typedef U64 (*attack_f)(const square::Square square, U64 occupancy); -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 = {{{0}}}; - 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/attack/bishop.hpp b/src/attack/bishop.hpp @@ -0,0 +1,103 @@ +#ifndef STELLAR_ATTACK_BISHOP_H +#define STELLAR_ATTACK_BISHOP_H + +#include "bit.hpp" +#include "bitboard.hpp" +#include "slider.hpp" +#include "square.hpp" +#include "utils.hpp" + +#include <array> + +namespace attack { +namespace bishop { + +inline constexpr const U64 bishop_magic_numbers[64] = { + C64(0x40040844404084), C64(0x2004208a004208), C64(0x10190041080202), C64(0x108060845042010), + C64(0x581104180800210), C64(0x2112080446200010), C64(0x1080820820060210), C64(0x3c0808410220200), + C64(0x4050404440404), C64(0x21001420088), C64(0x24d0080801082102), C64(0x1020a0a020400), + C64(0x40308200402), C64(0x4011002100800), C64(0x401484104104005), C64(0x801010402020200), + C64(0x400210c3880100), C64(0x404022024108200), C64(0x810018200204102), C64(0x4002801a02003), + C64(0x85040820080400), C64(0x810102c808880400), C64(0xe900410884800), C64(0x8002020480840102), + C64(0x220200865090201), C64(0x2010100a02021202), C64(0x152048408022401), C64(0x20080002081110), + C64(0x4001001021004000), C64(0x800040400a011002), C64(0xe4004081011002), C64(0x1c004001012080), + C64(0x8004200962a00220), C64(0x8422100208500202), C64(0x2000402200300c08), C64(0x8646020080080080), + C64(0x80020a0200100808), C64(0x2010004880111000), C64(0x623000a080011400), C64(0x42008c0340209202), + C64(0x209188240001000), C64(0x400408a884001800), C64(0x110400a6080400), C64(0x1840060a44020800), + C64(0x90080104000041), C64(0x201011000808101), C64(0x1a2208080504f080), C64(0x8012020600211212), + C64(0x500861011240000), C64(0x180806108200800), C64(0x4000020e01040044), C64(0x300000261044000a), + C64(0x802241102020002), C64(0x20906061210001), C64(0x5a84841004010310), C64(0x4010801011c04), + C64(0xa010109502200), C64(0x4a02012000), C64(0x500201010098b028), C64(0x8040002811040900), + C64(0x28000010020204), C64(0x6000020202d0240), C64(0x8918844842082200), C64(0x4010011029020020), +}; + +static inline constexpr const int relevant_bits[64] = { + // clang-format off + 6, 5, 5, 5, 5, 5, 5, 6, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 7, 7, 7, 7, 5, 5, + 5, 5, 7, 9, 9, 7, 5, 5, + 5, 5, 7, 9, 9, 7, 5, 5, + 5, 5, 7, 7, 7, 7, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 5, 5, 5, 5, 5, 5, 6, + // clang-format on +}; + +inline constexpr const bitboard::direction_f dir[4] = {bitboard::noEaOne, bitboard::noWeOne, + bitboard::soEaOne, bitboard::soWeOne}; + +inline constexpr U32 hash(const U64 key, const square::Square square) { + uint8_t square_i = to_underlying(square); + return (key * bishop_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]); +} + +inline constexpr U64 mask_fly(const square::Square square, U64 block) { + uint8_t square_i = to_underlying(square); + int tr = square_i / 8, tf = square_i % 8; + int len[4] = {std::min(7 - tf, 7 - tr), std::min(tf, 7 - tr), std::min(7 - tf, tr), std::min(tf, tr)}; + + return slider::mask(square, block, dir, len); +} + +inline constexpr const std::array<U64, 64> masks = []() constexpr -> std::array<U64, 64> { + std::array<U64, 64> masks; + for (uint8_t square = 0; square < 64; square++) { + int tr = square / 8, tf = square % 8; + int len[4] = {std::min(7 - tf, 7 - tr) - 1, std::min(tf, 7 - tr) - 1, std::min(7 - tf, tr) - 1, + std::min(tf, tr) - 1}; + masks[square] = slider::mask(static_cast<square::Square>(square), C64(0), dir, len); + } + return masks; +}(); + +inline constexpr U64 mask(const square::Square square) { return masks[to_underlying(square)]; } + +using attack_array = std::array<std::array<U64, 4096>, 64>; +inline constexpr const attack_array attacks = []() constexpr -> attack_array { + attack_array attacks = {{{0}}}; + for (uint8_t square = 0; square < 64; square++) { + square::Square Square = static_cast<square::Square>(square); + U64 attack_mask = mask(Square); + uint8_t relevant_bits = bit::count(attack_mask); + U64 occupancy_indices = C64(1) << relevant_bits; + + for (U64 idx = 0; idx < occupancy_indices; idx++) { + U64 occupancy = slider::occupancy(idx, relevant_bits, attack_mask); + U32 magic_index = hash(occupancy, Square); + attacks[square][magic_index] = mask_fly(Square, occupancy); + } + } + return attacks; +}(); + +inline constexpr U64 attack(const square::Square square, U64 occupancy) { + occupancy &= mask(square); + occupancy = hash(occupancy, square); + return attacks[to_underlying(square)][occupancy]; +} + +} // namespace bishop +} // namespace attack + +#endif diff --git a/src/attack/king.hpp b/src/attack/king.hpp @@ -0,0 +1,42 @@ +#ifndef STELLAR_ATTACK_KING_H +#define STELLAR_ATTACK_KING_H + +#include "bit.hpp" +#include "bitboard.hpp" +#include "square.hpp" +#include "utils.hpp" + +#include <array> + +namespace attack { +namespace king { + +static constexpr U64 mask(const square::Square square) { + U64 bitboard = C64(0), attacks = C64(0); + + bit::set(bitboard, to_underlying(square)); + attacks |= bitboard::westOne(bitboard) | bitboard::eastOne(bitboard); + attacks |= bitboard::soutOne(bitboard) | bitboard::nortOne(bitboard); + attacks |= bitboard::soutOne(bitboard) | bitboard::nortOne(bitboard); + attacks |= bitboard::soEaOne(bitboard) | bitboard::noEaOne(bitboard); + attacks |= bitboard::soWeOne(bitboard) | bitboard::noWeOne(bitboard); + + return attacks; +} + +typedef std::array<U64, 64> attack_array; +const attack_array attacks = []() -> attack_array { + std::array<U64, 64> attacks; + for (uint8_t square = 0; square < 64; square++) + attacks[square] = mask(static_cast<square::Square>(square)); + return attacks; +}(); + +inline constexpr U64 attack(const square::Square square, U64 occupancy) { + return attacks[to_underlying(square)]; +} + +} // namespace king +} // namespace attack + +#endif diff --git a/src/attack/knight.hpp b/src/attack/knight.hpp @@ -0,0 +1,45 @@ +#ifndef STELLAR_ATTACK_KNIGHT_H +#define STELLAR_ATTACK_KNIGHT_H + +#include "bit.hpp" +#include "bitboard.hpp" +#include "square.hpp" +#include "utils.hpp" + +#include <array> + +namespace attack { +namespace knight { + +static constexpr U64 mask(const square::Square square) { + U64 bitboard = C64(0), attacks = C64(0), tmp; + + bit::set(bitboard, to_underlying(square)); + tmp = bitboard::nortOne(bitboard::nortOne(bitboard)); + attacks |= bitboard::westOne(tmp) | bitboard::eastOne(tmp); + tmp = bitboard::soutOne(bitboard::soutOne(bitboard)); + attacks |= bitboard::westOne(tmp) | bitboard::eastOne(tmp); + tmp = bitboard::westOne(bitboard::westOne(bitboard)); + attacks |= bitboard::soutOne(tmp) | bitboard::nortOne(tmp); + tmp = bitboard::eastOne(bitboard::eastOne(bitboard)); + attacks |= bitboard::soutOne(tmp) | bitboard::nortOne(tmp); + + return attacks; +} + +typedef std::array<U64, 64> attack_array; +const attack_array attacks = []() -> attack_array { + std::array<U64, 64> attacks; + for (uint8_t square = 0; square < 64; square++) + attacks[square] = mask(static_cast<square::Square>(square)); + return attacks; +}(); + +inline constexpr U64 attack(const square::Square square, U64 occupancy) { + return attacks[to_underlying(square)]; +} + +} // namespace knight +} // namespace attack + +#endif diff --git a/src/attack/pawnb.hpp b/src/attack/pawnb.hpp @@ -0,0 +1,36 @@ +#ifndef STELLAR_ATTACK_PAWNB_H +#define STELLAR_ATTACK_PAWNB_H + +#include "bit.hpp" +#include "bitboard.hpp" +#include "square.hpp" +#include "utils.hpp" + +#include <array> + +namespace attack { +namespace pawnb { + +static constexpr U64 mask(const square::Square square) { + U64 bitboard = C64(0); + + bit::set(bitboard, to_underlying(square)); + return bitboard::soWeOne(bitboard) | bitboard::soEaOne(bitboard); +} + +typedef std::array<U64, 64> attack_array; +const attack_array attacks = []() -> attack_array { + std::array<U64, 64> attacks; + for (uint8_t square = 0; square < 64; square++) + attacks[square] = mask(static_cast<square::Square>(square)); + return attacks; +}(); + +inline constexpr U64 attack(const square::Square square, U64 occupancy) { + return attacks[to_underlying(square)]; +} + +} // namespace pawnb +}; // namespace attack + +#endif diff --git a/src/attack/pawnw.hpp b/src/attack/pawnw.hpp @@ -0,0 +1,36 @@ +#ifndef STELLAR_ATTACK_PAWNW_H +#define STELLAR_ATTACK_PAWNW_H + +#include "bit.hpp" +#include "bitboard.hpp" +#include "square.hpp" +#include "utils.hpp" + +#include <array> + +namespace attack { +namespace pawnw { + +static constexpr U64 mask(const square::Square square) { + U64 bitboard = C64(0); + + bit::set(bitboard, to_underlying(square)); + return bitboard::noWeOne(bitboard) | bitboard::noEaOne(bitboard); +} + +typedef std::array<U64, 64> attack_array; +const attack_array attacks = []() -> attack_array { + std::array<U64, 64> attacks; + for (uint8_t square = 0; square < 64; square++) + attacks[square] = mask(static_cast<square::Square>(square)); + return attacks; +}(); + +inline constexpr U64 attack(const square::Square square, U64 occupancy) { + return attacks[to_underlying(square)]; +} + +} // namespace pawnw +} // namespace attack + +#endif diff --git a/src/attack/queen.hpp b/src/attack/queen.hpp @@ -0,0 +1,17 @@ +#ifndef STELLAR_ATTACK_QUEEN_H +#define STELLAR_ATTACK_QUEEN_H + +#include "bishop.hpp" +#include "rook.hpp" + +namespace attack { +namespace queen { + +inline constexpr U64 attack(const square::Square square, U64 occupancy) { + return rook::attack(square, occupancy) | bishop::attack(square, occupancy); +} + +} // namespace queen +} // namespace attack + +#endif diff --git a/src/attack/rook.hpp b/src/attack/rook.hpp @@ -0,0 +1,103 @@ +#ifndef STELLAR_ATTACK_ROOK_H +#define STELLAR_ATTACK_ROOK_H + +#include "bit.hpp" +#include "bitboard.hpp" +#include "slider.hpp" +#include "square.hpp" +#include "utils.hpp" + +#include <array> + +namespace attack { +namespace rook { + +inline constexpr const int relevant_bits[64] = { + // clang-format off + 12, 11, 11, 11, 11, 11, 11, 12, + 11, 10, 10, 10, 10, 10, 10, 11, + 11, 10, 10, 10, 10, 10, 10, 11, + 11, 10, 10, 10, 10, 10, 10, 11, + 11, 10, 10, 10, 10, 10, 10, 11, + 11, 10, 10, 10, 10, 10, 10, 11, + 11, 10, 10, 10, 10, 10, 10, 11, + 12, 11, 11, 11, 11, 11, 11, 12, + // clang-format on +}; + +inline constexpr const U64 rook_magic_numbers[64] = { + C64(0x8a80104000800020), C64(0x140002000100040), C64(0x2801880a0017001), C64(0x100081001000420), + C64(0x200020010080420), C64(0x3001c0002010008), C64(0x8480008002000100), C64(0x2080088004402900), + C64(0x800098204000), C64(0x2024401000200040), C64(0x100802000801000), C64(0x120800800801000), + C64(0x208808088000400), C64(0x2802200800400), C64(0x2200800100020080), C64(0x801000060821100), + C64(0x80044006422000), C64(0x100808020004000), C64(0x12108a0010204200), C64(0x140848010000802), + C64(0x481828014002800), C64(0x8094004002004100), C64(0x4010040010010802), C64(0x20008806104), + C64(0x100400080208000), C64(0x2040002120081000), C64(0x21200680100081), C64(0x20100080080080), + C64(0x2000a00200410), C64(0x20080800400), C64(0x80088400100102), C64(0x80004600042881), + C64(0x4040008040800020), C64(0x440003000200801), C64(0x4200011004500), C64(0x188020010100100), + C64(0x14800401802800), C64(0x2080040080800200), C64(0x124080204001001), C64(0x200046502000484), + C64(0x480400080088020), C64(0x1000422010034000), C64(0x30200100110040), C64(0x100021010009), + C64(0x2002080100110004), C64(0x202008004008002), C64(0x20020004010100), C64(0x2048440040820001), + C64(0x101002200408200), C64(0x40802000401080), C64(0x4008142004410100), C64(0x2060820c0120200), + C64(0x1001004080100), C64(0x20c020080040080), C64(0x2935610830022400), C64(0x44440041009200), + C64(0x280001040802101), C64(0x2100190040002085), C64(0x80c0084100102001), C64(0x4024081001000421), + C64(0x20030a0244872), C64(0x12001008414402), C64(0x2006104900a0804), C64(0x1004081002402), +}; + +inline constexpr const bitboard::direction_f dir[4] = {bitboard::westOne, bitboard::soutOne, + bitboard::eastOne, bitboard::nortOne}; + +inline constexpr U32 hash(const U64 key, const square::Square square) { + uint8_t square_i = to_underlying(square); + return (key * rook_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]); +} + +inline constexpr U64 mask_fly(const square::Square square, U64 block) { + uint8_t square_i = to_underlying(square); + int tr = square_i / 8, tf = square_i % 8; + int len[4] = {tf, tr, 7 - tf, 7 - tr}; + + return slider::mask(square, block, dir, len); +} + +inline constexpr const std::array<U64, 64> masks = []() constexpr -> std::array<U64, 64> { + std::array<U64, 64> masks; + for (uint8_t square = 0; square < 64; square++) { + const int tr = square / 8, tf = square % 8; + const int len[4] = {tf - 1, tr - 1, 6 - tf, 6 - tr}; + + masks[square] = slider::mask(static_cast<square::Square>(square), C64(0), dir, len); + } + return masks; +}(); + +inline constexpr U64 mask(const square::Square square) { return masks[to_underlying(square)]; } + +using attack_array = std::array<std::array<U64, 4096>, 64>; +inline constexpr const attack_array attacks = []() constexpr -> attack_array { + attack_array attacks = {{{0}}}; + for (uint8_t square = 0; square < 64; square++) { + square::Square Square = static_cast<square::Square>(square); + U64 attack_mask = mask(Square); + uint8_t relevant_bits = bit::count(attack_mask); + U64 occupancy_indices = C64(1) << relevant_bits; + + for (U64 idx = 0; idx < occupancy_indices; idx++) { + U64 occupancy = slider::occupancy(idx, relevant_bits, attack_mask); + U32 magic_index = hash(occupancy, Square); + attacks[square][magic_index] = mask_fly(Square, occupancy); + } + } + return attacks; +}(); + +inline constexpr U64 attack(const square::Square square, U64 occupancy) { + occupancy &= mask(square); + occupancy = hash(occupancy, square); + return attacks[to_underlying(square)][occupancy]; +} + +} // namespace rook +} // namespace attack + +#endif diff --git a/src/attack/slider.hpp b/src/attack/slider.hpp @@ -0,0 +1,39 @@ +#ifndef STELLAR_ATTAKC_SLIDER_H +#define STELLAR_ATTAKC_SLIDER_H + +#include "square.hpp" +#include "utils.hpp" + +namespace attack { +namespace slider { + +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::lsb_pop(attack_mask); + + if (bit::get(index, count)) bit::set(occupancy, square); + } + + return occupancy; +} + +inline constexpr U64 mask(const square::Square square, U64 block, const bitboard::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; +} + +} // namespace slider +} // namespace attack +#endif diff --git a/src/board/board.cpp b/src/board/board.cpp @@ -5,6 +5,7 @@ #include "board.hpp" #include "piece.hpp" +#include "square.hpp" #include "utils.hpp" #include "zobrist.hpp" @@ -15,11 +16,12 @@ Board::Board(const std::string &fen) { for (i = 0; fen[i] != ' '; i++) { if (isalpha(fen[i])) { const piece::Piece &piece = piece::get_from_code(fen[i]); - set_piece(piece.type, piece.color, static_cast<Square>(rank * 8 + file)); + set_piece(piece.type, piece.color, static_cast<square::Square>(rank * 8 + file)); file++; } else if (isdigit(fen[i])) { file += fen[i] - '0'; } else if (fen[i] == '/') { + if (file != 8) throw std::runtime_error("File is not complete"); file = 0; rank--; } else { @@ -27,13 +29,9 @@ Board::Board(const std::string &fen) { } } - i++; - if (fen[i] == 'w') - side = Color::WHITE; - else if (fen[i] == 'b') - side = Color::BLACK; - else - throw std::runtime_error("Invalid player char"); + side = fen[++i] == 'w' ? color::WHITE + : fen[i] == 'b' ? color::BLACK + : throw std::runtime_error("Invalid player char"); for (i += 2; fen[i] != ' '; i++) { if (fen[i] == 'K') @@ -44,14 +42,15 @@ Board::Board(const std::string &fen) { castle |= to_underlying(Castle::BK); else if (fen[i] == 'q') castle |= to_underlying(Castle::BQ); - else if (fen[i] == '-') + else if (fen[i] == '-') { + i++; break; - else + } else throw std::runtime_error("Invalid castle rights"); } - i++; - if (fen[++i] != '-') enpassant = square_from_coordinates(fen.data() + i); + enpassant = fen[++i] != '-' ? square::from_coordinates(fen.substr(i, 2)) : square::no_sq; + hash = Zobrist::hash(*this); } @@ -59,7 +58,7 @@ std::ostream &operator<<(std::ostream &os, const Board &board) { for (int rank = 0; rank < 8; rank++) { for (int file = 0; file < 8; file++) { if (!file) os << 8 - rank << " "; - Square square = static_cast<Square>((7 - rank) * 8 + file); + square::Square square = static_cast<square::Square>((7 - rank) * 8 + file); const piece::Piece *piece = board.get_square_piece(square); os << (piece ? piece->code : '.') << " "; } @@ -67,8 +66,8 @@ std::ostream &operator<<(std::ostream &os, const Board &board) { } os << " A B C D E F G H\n"; os << " Side: "; - os << ((board.side == Color::WHITE) ? "white" : "black") << "\n"; - os << "Enpassant: " << square_to_coordinates(board.enpassant) << "\n"; + os << ((board.side == color::WHITE) ? "white" : "black") << "\n"; + os << "Enpassant: " << square::to_coordinates(board.enpassant) << "\n"; os << " Castle:"; os << ((board.castle & to_underlying(Board::Castle::WK)) ? 'K' : '-'); os << ((board.castle & to_underlying(Board::Castle::WQ)) ? 'Q' : '-'); diff --git a/src/board/board.hpp b/src/board/board.hpp @@ -1,13 +1,18 @@ #ifndef STELLAR_BOARD_H #define STELLAR_BOARD_H +#include "bit.hpp" +#include "color.hpp" #include "piece.hpp" +#include "square.hpp" #include "utils.hpp" #include "zobrist.hpp" #include <iostream> #include <string> +#define start_position "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 " + class Board { public: enum class Castle : uint8_t { @@ -25,95 +30,99 @@ class Board { /* Getters */ inline constexpr U64 get_hash(void) const; - inline constexpr Color get_side(void) const; + inline constexpr color::Color get_side(void) const; inline constexpr uint8_t get_castle(void) const; - inline constexpr Square get_enpassant(void) const; + inline constexpr square::Square get_enpassant(void) const; - inline constexpr U64 get_bitboard_color(Color side) const; + inline constexpr U64 get_bitboard_color(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(piece::Type piece, color::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 U64 get_bitboard_piece_attacks(piece::Type piece, color::Color color, + square::Square from) const; + inline constexpr U64 get_bitboard_piece_moves(piece::Type piece, color::Color color, + square::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; + inline constexpr color::Color get_square_piece_color(square::Square square) const; + inline constexpr piece::Type get_square_piece_type(square::Square square) const; + inline constexpr const piece::Piece *get_square_piece(square::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 set_enpassant(square::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_color(color::Color color, square::Square square); + inline constexpr void set_bitboard_color(color::Color color, square::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_bitboard_piece(piece::Type type, square::Square square); + inline constexpr void set_bitboard_piece(piece::Type type, square::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); + inline constexpr void pop_piece(piece::Type type, color::Color side, square::Square square); + inline constexpr void set_piece(piece::Type type, color::Color side, square::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_square_attacked(square::Square square, color::Color side) const; + inline constexpr bool is_square_occupied(square::Square square) const; + inline constexpr bool is_piece_attack_square(piece::Type type, color::Color color, square::Square source, + square::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; + color::Color side = color::WHITE; + square::Square enpassant = square::Square::no_sq; uint8_t castle = 0; }; -constexpr Color Board::get_side(void) const { return side; } +constexpr color::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 square::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_color(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)]; + 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 { +constexpr U64 Board::get_bitboard_piece(piece::Type piece, color::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 { +constexpr U64 Board::get_bitboard_piece_attacks(piece::Type type, color::Color color, + square::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 { +constexpr U64 Board::get_bitboard_piece_moves(piece::Type type, color::Color color, + square::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; +constexpr color::Color Board::get_square_piece_color(square::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 { +constexpr piece::Type Board::get_square_piece_type(square::Square square) const { for (piece::Type type : piece::TypeIter()) { - if (bit_get(pieces[to_underlying(type)], to_underlying(square))) return type; + 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 { +constexpr const piece::Piece *Board::get_square_piece(square::Square square) const { try { return &piece::get(get_square_piece_type(square), get_square_piece_color(square)); } catch (std::exception &e) { @@ -131,50 +140,50 @@ constexpr void Board::and_castle(uint8_t right) { } constexpr void Board::switch_side(void) { - side = (side == Color::BLACK) ? Color::WHITE : Color::BLACK; + side = color::other(side); 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); +constexpr void Board::set_enpassant(square::Square target) { + if (enpassant != square::Square::no_sq) hash ^= Zobrist::key_enpassant(enpassant); + if (target != square::Square::no_sq) hash ^= Zobrist::key_enpassant(target); enpassant = target; } -constexpr void Board::pop_bitboard_color(Color color, Square square) { - bit_pop(colors[to_underlying(color)], to_underlying(square)); +constexpr void Board::pop_bitboard_color(color::Color color, square::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::set_bitboard_color(color::Color color, square::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::pop_bitboard_piece(piece::Type type, square::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::set_bitboard_piece(piece::Type type, square::Square square) { + bit::set(pieces[to_underlying(type)], to_underlying(square)); } -constexpr void Board::pop_piece(piece::Type type, Color side, Square square) { +constexpr void Board::pop_piece(piece::Type type, color::Color side, square::Square square) { pop_bitboard_color(side, square); pop_bitboard_piece(type, square); } -constexpr void Board::set_piece(piece::Type type, Color side, Square square) { +constexpr void Board::set_piece(piece::Type type, color::Color side, square::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_occupied(square::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; +constexpr bool Board::is_square_attacked(square::Square square, color::Color side) const { + const color::Color side_other = color::other(side); for (piece::Type type : piece::TypeIter()) { if (get_bitboard_piece_attacks(type, side_other, square) & get_bitboard_piece(type, side)) { @@ -185,15 +194,15 @@ constexpr bool Board::is_square_attacked(Square square, Color side) const { return 0; } -constexpr bool Board::is_piece_attack_square(piece::Type type, Color color, Square source, - Square target) const { +constexpr bool Board::is_piece_attack_square(piece::Type type, color::Color color, square::Square source, + square::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)); + color::Color side_other = (side == color::BLACK) ? color::WHITE : color::BLACK; + square::Square square = static_cast<square::Square>(bit::lsb_index(king)); return is_square_attacked(square, side_other); } @@ -202,19 +211,19 @@ U64 Zobrist::hash(const Board &board) { 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); + 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); + 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) + if (board.get_side() == color::BLACK) key_final ^= keys_side; + if (board.get_enpassant() != square::Square::no_sq) key_final ^= keys_enpassant[to_underlying(board.get_enpassant())]; return key_final; diff --git a/src/board/zobrist.hpp b/src/board/zobrist.hpp @@ -16,8 +16,10 @@ class Zobrist { 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) { + static inline constexpr U64 key_enpassant(square::Square square) { + return keys_enpassant[to_underlying(square)]; + } + static inline constexpr U64 key_piece(piece::Type type, color::Color color, square::Square square) { return keys_piece[piece::get_index(type, color)][to_underlying(square)]; } @@ -27,8 +29,8 @@ class Zobrist { 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; + int piece_index_white = piece::get(type, color::Color::WHITE).index; + int piece_index_black = piece::get(type, color::Color::BLACK).index; for (int square = 0; square < 64; square++) { key_piece[piece_index_white][square] = gen(); key_piece[piece_index_black][square] = gen(); diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp @@ -121,7 +121,7 @@ U32 inline move_list_score(Move move) { const piece::Type type = board.get_square_piece_type(move.source()); if (move.is_capture()) { const piece::Type captured = board.get_square_piece_type(move.target()); - return piece::score(type, captured) + 10000; + return score::get(type, captured) + 10000; } if (killer[0][ply] == move) return 9000; if (killer[1][ply] == move) return 8000; @@ -172,7 +172,7 @@ int stats_move_make(Board &copy, const Move move) { void stats_move_make_pruning(Board &copy) { copy = board; board.switch_side(); - board.set_enpassant(Square::no_sq); + board.set_enpassant(square::no_sq); ply++; } @@ -264,7 +264,7 @@ int16_t negamax(int16_t alpha, int16_t beta, uint8_t depth, bool null) { // if (ply > MAX_PLY - 1) return evaluate::score_position(board); if (!pv_node && !isCheck) { - static constexpr const U32 score_pawn = piece::score(piece::Type::PAWN); + static constexpr const U32 score_pawn = score::get(piece::Type::PAWN); int16_t staticEval = evaluate::score_position(board); // evaluation pruning @@ -301,9 +301,9 @@ int16_t negamax(int16_t alpha, int16_t beta, uint8_t depth, bool null) { // futility pruning condition static constexpr const int16_t margin[] = { 0, - piece::score(piece::Type::PAWN), - piece::score(piece::Type::KNIGHT), - piece::score(piece::Type::ROOK), + score::get(piece::Type::PAWN), + score::get(piece::Type::KNIGHT), + score::get(piece::Type::ROOK), }; if (depth < 4 && abs(alpha) < MATE_SCORE && staticEval + margin[depth] <= alpha) futility = 1; } diff --git a/src/engine/evaluate.cpp b/src/engine/evaluate.cpp @@ -1,5 +1,11 @@ #include "evaluate.hpp" +#include "bit.hpp" +#include "bitboard.hpp" +#include "piece.hpp" +#include "score.hpp" +#include "square.hpp" #include "utils.hpp" + #include <array> namespace evaluate { @@ -10,7 +16,7 @@ inline constexpr const mask_fr_array mask_rank = []() constexpr -> mask_fr_array U64 mask = 0xFF; for (uint8_t rank = 0; rank < 8; rank++) { mask_rank[rank] = mask; - mask = nortOne(mask); + mask = bitboard::nortOne(mask); } return mask_rank; }(); @@ -20,7 +26,7 @@ inline constexpr const mask_fr_array mask_file = []() constexpr -> mask_fr_array U64 mask = 0x0101010101010101; for (uint8_t file = 0; file < 8; file++) { mask_file[file] = mask; - mask = eastOne(mask); + mask = bitboard::eastOne(mask); } return mask_file; }(); @@ -33,7 +39,7 @@ inline constexpr const mask_fr_array mask_isolated = []() constexpr -> mask_fr_a U64 mask = 0x0505050505050505; for (uint8_t file = 1; file < 8; file++) { mask_isolated[file] = mask; - mask = eastOne(mask); + mask = bitboard::eastOne(mask); } return mask_isolated; @@ -47,10 +53,10 @@ inline constexpr const mask_passed_array mask_passed = []() constexpr -> mask_pa for (uint8_t file = 0; file < 8; file++) { maskW = maskB = mask_file[file] | mask_isolated[file]; for (uint8_t rank = 0; rank < 8; rank++) { - maskW = nortOne(maskW); + maskW = bitboard::nortOne(maskW); mask_passed[0][rank * 8 + file] = maskW; - maskB = soutOne(maskB); + maskB = bitboard::soutOne(maskB); mask_passed[1][(7 - rank) * 8 + file] = maskB; } } @@ -58,18 +64,6 @@ inline constexpr const mask_passed_array mask_passed = []() constexpr -> mask_pa return mask_passed; }(); -inline constexpr uint8_t get_file(uint8_t square) { return square & 0x07; } -inline constexpr uint8_t get_rank(uint8_t square) { return square >> 3; } - -inline constexpr const int8_t penalty_pawn_double = -10; -inline constexpr const int8_t penalty_pawn_isolated = -10; - -inline constexpr const int8_t score_open_semi = 10; -inline constexpr const int8_t score_open = 15; - -inline constexpr const std::array<std::array<int16_t, 8>, 2> bonus_pawn_passed = { - {{0, 10, 30, 50, 75, 100, 150, 200}, {200, 150, 100, 75, 50, 30, 10, 0}}}; - using piece::Type::BISHOP; using piece::Type::KING; using piece::Type::KNIGHT; @@ -77,9 +71,9 @@ using piece::Type::PAWN; using piece::Type::QUEEN; using piece::Type::ROOK; -int16_t score_position_side(const Board &board, const Color side) { +int16_t score_position_side(const Board &board, const color::Color side) { U64 bitboard; - int16_t score = 0; + int16_t total = 0; int8_t square_i; const uint8_t side_i = to_underlying(side); @@ -89,62 +83,68 @@ int16_t score_position_side(const Board &board, const Color side) { bitboard = board.get_bitboard_piece(PAWN, side); bitboard_for_each_bit(square_i, bitboard) { - score += piece::score(PAWN); - score += piece::score(PAWN, side, square_i); + const square::Square square = static_cast<square::Square>(square_i); + total += score::get(PAWN, side, square); + total += score::get(PAWN); // check isolated, doubled and passed pawns - const uint8_t file = get_file(square_i), rank = get_rank(square_i); - if (!(mask_isolated[file] & pawnsS)) score += penalty_pawn_isolated; - if (bit_count(pawnsS & mask_file[file]) > 1) score += penalty_pawn_double; - if (!(pawnsO & mask_passed[side_i][square_i])) score += bonus_pawn_passed[side_i][rank]; + const uint8_t file = square::file(square), rank = square::rank(square); + if (!(mask_isolated[file] & pawnsS)) total -= score::pawn_isolated; + if (bit::count(pawnsS & mask_file[file]) > 1) total -= score::pawn_double; + if (!(pawnsO & mask_passed[side_i][square_i])) total += score::pawn_passed[side_i][rank]; } bitboard = board.get_bitboard_piece(KNIGHT, side); bitboard_for_each_bit(square_i, bitboard) { - score += piece::score(KNIGHT); - score += piece::score(KNIGHT, side, square_i); + const square::Square square = static_cast<square::Square>(square_i); + total += score::get(KNIGHT, side, square); + total += score::get(KNIGHT); } bitboard = board.get_bitboard_piece(BISHOP, side); bitboard_for_each_bit(square_i, bitboard) { - score += piece::score(BISHOP); - score += piece::score(BISHOP, side, square_i); + const square::Square square = static_cast<square::Square>(square_i); + total += score::get(BISHOP, side, square); + total += score::get(BISHOP); } bitboard = board.get_bitboard_piece(ROOK, side); bitboard_for_each_bit(square_i, bitboard) { - score += piece::score(ROOK); - score += piece::score(ROOK, side, square_i); + const square::Square square = static_cast<square::Square>(square_i); + total += score::get(ROOK, side, square); + total += score::get(ROOK); // rook on open and semi-open files - const uint8_t file = get_file(square_i); - if (!(pawns & mask_file[file])) score += score_open; - if (!(pawnsS & mask_file[file])) score += score_open_semi; + const uint8_t file = square::file(square); + if (!(pawns & mask_file[file])) total += score::score_open; + if (!(pawnsS & mask_file[file])) total += score::score_open_semi; } bitboard = board.get_bitboard_piece(QUEEN, side); bitboard_for_each_bit(square_i, bitboard) { - score += piece::score(QUEEN); - score += piece::score(QUEEN, side, square_i); + const square::Square square = static_cast<square::Square>(square_i); + total += score::get(QUEEN, side, square); + total += score::get(QUEEN); } bitboard = board.get_bitboard_piece(KING, side); bitboard_for_each_bit(square_i, bitboard) { - score += piece::score(KING); - score += piece::score(KING, side, square_i); + const square::Square square = static_cast<square::Square>(square_i); + total += score::get(KING, side, square); + total += score::get(KING); // king on open and semi-open files - const uint8_t file = get_file(square_i); - if (!(pawns & mask_file[file])) score -= score_open; - if (!(pawnsS & mask_file[file])) score -= score_open_semi; + const uint8_t file = square::file(square); + if (!(pawns & mask_file[file])) total -= score::score_open; + if (!(pawnsS & mask_file[file])) total -= score::score_open_semi; } - return score; + return total; } int16_t score_position(const Board &board) { - const int16_t score = score_position_side(board, Color::WHITE) - score_position_side(board, Color::BLACK); - return board.get_side() == Color::WHITE ? score : -score; + const int16_t score = score_position_side(board, color::WHITE) - score_position_side(board, color::BLACK); + return board.get_side() == color::WHITE ? score : -score; } } // namespace evaluate diff --git a/src/engine/score.hpp b/src/engine/score.hpp @@ -7,4 +7,98 @@ #define MATE_VALUE 31000 #define MATE_SCORE 30000 +namespace score { + +inline constexpr const uint16_t value[6] = {100, 300, 350, 500, 1000, 10000}; +inline constexpr 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 +}; + +inline constexpr 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 +}; + +inline constexpr uint16_t get(const piece::Type piece) { return value[to_underlying(piece)]; } +inline constexpr uint16_t get(const piece::Type piece, const piece::Type captured) { + return capture[to_underlying(piece)][to_underlying(captured)]; +} + +inline constexpr int8_t get(const piece::Type type, const color::Color color, const square::Square square) { + uint8_t square_i = to_underlying(color == color::WHITE ? square : square::mirror(square)); + return position[to_underlying(type)][square_i]; +} + +inline constexpr const uint8_t pawn_double = 10; +inline constexpr const uint8_t pawn_isolated = 10; +inline constexpr const std::array<std::array<int16_t, 8>, 2> pawn_passed = { + {{0, 10, 30, 50, 75, 100, 150, 200}, {200, 150, 100, 75, 50, 30, 10, 0}}}; + +inline constexpr const uint8_t score_open_semi = 10; +inline constexpr const uint8_t score_open = 15; + +} // namespace score + #endif diff --git a/src/engine/uci.cpp b/src/engine/uci.cpp @@ -16,7 +16,7 @@ uint32_t get_time_ms(void) { } void move_print(const Board &board, Move move) { - std::cout << square_to_coordinates(move.source()) << square_to_coordinates(move.target()); + std::cout << square::to_coordinates(move.source()) << square::to_coordinates(move.target()); if (move.is_promote()) std::cout << piece::get_code(move.promoted(), board.get_side()); } @@ -48,8 +48,8 @@ void communicate(const uci::Settings *settings) { } inline bool parse_move(const Board &board, Move &move, const std::string &move_string) { - Square source = square_from_coordinates(move_string.substr(0, 2)); - Square target = square_from_coordinates(move_string.substr(2, 2)); + const square::Square source = square::from_coordinates(move_string.substr(0, 2)); + const square::Square target = square::from_coordinates(move_string.substr(2, 2)); const MoveList list(board); for (int i = 0; i < list.size(); i++) { @@ -144,7 +144,7 @@ void loop(void) { } settings.starttime = get_time_ms(); - uint32_t time = (settings.board.get_side() == Color::WHITE) ? wtime : btime; + uint32_t time = (settings.board.get_side() == color::WHITE) ? wtime : btime; if (movetime != 0) { time = movetime; @@ -152,7 +152,7 @@ void loop(void) { } if (time != 0) { - uint16_t inc = (settings.board.get_side() == Color::WHITE) ? winc : binc; + uint16_t inc = (settings.board.get_side() == color::WHITE) ? winc : binc; time /= movestogo; time -= 50; settings.stoptime = settings.starttime += time + inc; diff --git a/src/move/move.cpp b/src/move/move.cpp @@ -4,17 +4,18 @@ #include <algorithm> #include <iomanip> -void Move::piece_remove(Board &board, piece::Type type, Color color, Square square) const { +void Move::piece_remove(Board &board, piece::Type type, color::Color color, square::Square square) const { board.pop_piece(type, color, square); board.xor_hash(Zobrist::key_piece(type, color, square)); } -void Move::piece_set(Board &board, piece::Type type, Color color, Square square) const { +void Move::piece_set(Board &board, piece::Type type, color::Color color, square::Square square) const { board.set_piece(type, color, square); board.xor_hash(Zobrist::key_piece(type, color, square)); } -void Move::piece_move(Board &board, piece::Type type, Color color, Square source, Square target) const { +void Move::piece_move(Board &board, piece::Type type, color::Color color, square::Square source, + square::Square target) const { piece_remove(board, type, color, source); piece_set(board, type, color, target); } @@ -36,13 +37,11 @@ bool Move::make(Board &board) const { // clang-format on }; - const Color color = board.get_side(); - const Color colorOther = color == Color::BLACK ? Color::WHITE : Color::BLACK; - const Square source = this->source(); - const Square target = this->target(); + const color::Color color = board.get_side(), colorOther = color::other(color); + const square::Square source = this->source(), target = this->target(); - const Square ntarget = - static_cast<Square>(to_underlying(this->target()) + (color == Color::WHITE ? -8 : +8)); + const square::Square ntarget = + static_cast<square::Square>(to_underlying(this->target()) + (color == color::Color::WHITE ? -8 : +8)); const piece::Type piece = board.get_square_piece_type(source); @@ -68,15 +67,19 @@ bool Move::make(Board &board) const { } } - board.set_enpassant(is_double() ? ntarget : Square::no_sq); + board.set_enpassant(is_double() ? ntarget : square::Square::no_sq); if (is_castle()) { - if (color == Color::WHITE) { - if (is_castle_king()) piece_move(board, ROOK, Color::WHITE, Square::h1, Square::f1); - if (is_castle_queen()) piece_move(board, ROOK, Color::WHITE, Square::a1, Square::d1); + if (color == color::Color::WHITE) { + if (is_castle_king()) + piece_move(board, ROOK, color::Color::WHITE, square::Square::h1, square::Square::f1); + if (is_castle_queen()) + piece_move(board, ROOK, color::Color::WHITE, square::Square::a1, square::Square::d1); } else { - if (is_castle_king()) piece_move(board, ROOK, Color::BLACK, Square::h8, Square::f8); - if (is_castle_queen()) piece_move(board, ROOK, Color::BLACK, Square::a8, Square::d8); + if (is_castle_king()) + piece_move(board, ROOK, color::Color::BLACK, square::Square::h8, square::Square::f8); + if (is_castle_queen()) + piece_move(board, ROOK, color::Color::BLACK, square::Square::a8, square::Square::d8); } } @@ -91,8 +94,8 @@ bool Move::make(Board &board) const { } std::ostream &operator<<(std::ostream &os, Move move) { - os << square_to_coordinates(move.source()) << " "; - os << square_to_coordinates(move.target()) << " "; + os << square::to_coordinates(move.source()) << " "; + os << square::to_coordinates(move.target()) << " "; os << (move.is_promote() ? piece::get_code(move.promoted()) : '.') << " "; os << move.is_double() << " "; os << move.is_enpassant() << " "; diff --git a/src/move/move.hpp b/src/move/move.hpp @@ -28,15 +28,15 @@ struct Move { }; Move() : source_i(0), target_i(0), flags_i(0) {} - Move(Square source, Square target, Flag flags) + Move(square::Square source, square::Square target, Flag flags) : source_i(to_underlying(source)), target_i(to_underlying(target)), flags_i(flags) {} friend bool operator==(const Move a, const Move b) { return a.source_i == b.source_i && a.target_i == b.target_i && a.flags_i == b.flags_i; } - Square source(void) const { return static_cast<Square>(source_i); } - Square target(void) const { return static_cast<Square>(target_i); } + square::Square source(void) const { return static_cast<square::Square>(source_i); } + square::Square target(void) const { return static_cast<square::Square>(target_i); } bool is_capture(void) const { return flags_i != PQUIET && (flags_i & CAPTURE); } bool is_promote(void) const { return flags_i & 0x8; } @@ -58,9 +58,10 @@ struct Move { 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; + inline void piece_remove(Board &board, piece::Type type, color::Color color, square::Square square) const; + inline void piece_set(Board &board, piece::Type type, color::Color color, square::Square square) const; + inline void piece_move(Board &board, piece::Type type, color::Color color, square::Square source, + square::Square target) const; unsigned source_i : 6; unsigned target_i : 6; diff --git a/src/move/movelist.cpp b/src/move/movelist.cpp @@ -3,28 +3,28 @@ #include <iomanip> #define pawn_canPromote(color, source) \ - ((color == Color::WHITE && source >= Square::a7 && source <= Square::h7) || \ - (color == Color::BLACK && source >= Square::a2 && source <= Square::h2)) + ((color == color::WHITE && source >= square::a7 && source <= square::h7) || \ + (color == color::BLACK && source >= square::a2 && source <= square::h2)) #define pawn_onStart(color, source) \ - ((color == Color::BLACK && source >= Square::a7 && source <= Square::h7) || \ - (color == Color::WHITE && source >= Square::a2 && source <= Square::h2)) + ((color == color::BLACK && source >= square::a7 && source <= square::h7) || \ + (color == color::WHITE && source >= square::a2 && source <= square::h2)) using piece::Type::PAWN; void MoveList::generate(const Board &board, bool attacks_only) { uint8_t src_i, tgt_i; - Color color = board.get_side(); - Color colorOther = color == Color::BLACK ? Color::WHITE : Color::BLACK; + const color::Color color = board.get_side(); + const color::Color colorOther = color == color::BLACK ? color::WHITE : color::BLACK; // pawn moves - const int add = (color == Color::WHITE) ? +8 : -8; + const int add = (color == color::WHITE) ? +8 : -8; U64 bitboard = board.get_bitboard_piece(PAWN, color); bitboard_for_each_bit(src_i, bitboard) { - const Square src = static_cast<Square>(src_i); - const Square tgt = static_cast<Square>(tgt_i = src_i + add); + const square::Square src = static_cast<square::Square>(src_i); + const square::Square tgt = static_cast<square::Square>(tgt_i = src_i + add); if (!attacks_only && !board.is_square_occupied(tgt)) { if (pawn_canPromote(color, src)) { list.push_back({src, tgt, Move::PKNIGHT}); @@ -35,7 +35,7 @@ void MoveList::generate(const Board &board, bool attacks_only) { list.push_back({src, tgt, Move::PQUIET}); // two ahead - const Square tgt = static_cast<Square>(tgt_i + add); + const square::Square tgt = static_cast<square::Square>(tgt_i + add); if (pawn_onStart(color, src) && !board.is_square_occupied(tgt)) list.push_back({src, tgt, Move::DOUBLE}); } @@ -45,7 +45,7 @@ void MoveList::generate(const Board &board, bool attacks_only) { U64 attack = board.get_bitboard_piece_attacks(PAWN, color, src) & board.get_bitboard_color(colorOther); bitboard_for_each_bit(tgt_i, attack) { - const Square tgt = static_cast<Square>(tgt_i); + const square::Square tgt = static_cast<square::Square>(tgt_i); if (pawn_canPromote(color, src)) { list.push_back({src, tgt, Move::PCKNIGHT}); list.push_back({src, tgt, Move::PCBISHOP}); @@ -57,8 +57,8 @@ void MoveList::generate(const Board &board, bool attacks_only) { } // en passant - const Square enpassant = board.get_enpassant(); - if (enpassant != Square::no_sq && board.is_piece_attack_square(PAWN, color, src, enpassant)) + const square::Square enpassant = board.get_enpassant(); + if (enpassant != square::no_sq && board.is_piece_attack_square(PAWN, color, src, enpassant)) list.push_back({src, enpassant, Move::ENPASSANT}); } @@ -66,10 +66,10 @@ void MoveList::generate(const Board &board, bool attacks_only) { for (const piece::Type type : ++piece::TypeIter()) { U64 bitboard = board.get_bitboard_piece(type, color); bitboard_for_each_bit(src_i, bitboard) { - const Square src = static_cast<Square>(src_i); + const square::Square src = static_cast<square::Square>(src_i); U64 attack = board.get_bitboard_piece_moves(type, color, src); bitboard_for_each_bit(tgt_i, attack) { - const Square tgt = static_cast<Square>(tgt_i); + const square::Square tgt = static_cast<square::Square>(tgt_i); if (board.is_square_occupied(tgt)) { list.push_back({src, tgt, Move::CAPTURE}); } else { @@ -83,34 +83,34 @@ void MoveList::generate(const Board &board, bool attacks_only) { if (attacks_only) return; // Castling - if (color == Color::WHITE) { - if (!board.is_square_attacked(Square::e1, Color::BLACK)) { + if (color == color::WHITE) { + if (!board.is_square_attacked(square::e1, color::BLACK)) { if (board.get_castle() & to_underlying(Board::Castle::WK)) { - if (!board.is_square_occupied(Square::f1) && !board.is_square_occupied(Square::g1) && - !board.is_square_attacked(Square::f1, Color::BLACK)) - list.push_back({Square::e1, Square::g1, Move::CASTLEK}); + if (!board.is_square_occupied(square::f1) && !board.is_square_occupied(square::g1) && + !board.is_square_attacked(square::f1, color::BLACK)) + list.push_back({square::e1, square::g1, Move::CASTLEK}); } if (board.get_castle() & to_underlying(Board::Castle::WQ)) { - if (!board.is_square_occupied(Square::d1) && !board.is_square_occupied(Square::c1) && - !board.is_square_occupied(Square::b1) && - !board.is_square_attacked(Square::d1, Color::BLACK) && - !board.is_square_attacked(Square::c1, Color::BLACK)) - list.push_back({Square::e1, Square::c1, Move::CASTLEQ}); + if (!board.is_square_occupied(square::d1) && !board.is_square_occupied(square::c1) && + !board.is_square_occupied(square::b1) && + !board.is_square_attacked(square::d1, color::BLACK) && + !board.is_square_attacked(square::c1, color::BLACK)) + list.push_back({square::e1, square::c1, Move::CASTLEQ}); } } } else { - if (!board.is_square_attacked(Square::e8, Color::WHITE)) { + if (!board.is_square_attacked(square::e8, color::WHITE)) { if (board.get_castle() & to_underlying(Board::Castle::BK)) { - if (!board.is_square_occupied(Square::f8) && !board.is_square_occupied(Square::g8) && - !board.is_square_attacked(Square::f8, Color::WHITE)) - list.push_back({Square::e8, Square::g8, Move::CASTLEK}); + if (!board.is_square_occupied(square::f8) && !board.is_square_occupied(square::g8) && + !board.is_square_attacked(square::f8, color::WHITE)) + list.push_back({square::Square::e8, square::Square::g8, Move::CASTLEK}); } if (board.get_castle() & to_underlying(Board::Castle::BQ)) { - if (!board.is_square_occupied(Square::d8) && !board.is_square_occupied(Square::c8) && - !board.is_square_occupied(Square::b8) && - !board.is_square_attacked(Square::d8, Color::WHITE) && - !board.is_square_attacked(Square::c8, Color::WHITE)) - list.push_back({Square::e8, Square::c8, Move::CASTLEQ}); + if (!board.is_square_occupied(square::d8) && !board.is_square_occupied(square::c8) && + !board.is_square_occupied(square::b8) && + !board.is_square_attacked(square::d8, color::WHITE) && + !board.is_square_attacked(square::c8, color::WHITE)) + list.push_back({square::e8, square::c8, Move::CASTLEQ}); } } } diff --git a/src/piece/CMakeLists.txt b/src/piece/CMakeLists.txt @@ -3,6 +3,7 @@ add_library(piece INTERFACE) target_link_libraries(piece INTERFACE attack INTERFACE utils + INTERFACE color ) target_include_directories(piece INTERFACE .) diff --git a/src/piece/piece.hpp b/src/piece/piece.hpp @@ -2,13 +2,14 @@ #define STELLAR_PIECE_H #include "attack.hpp" +#include "color.hpp" #include "utils.hpp" #include <cctype> namespace piece { -enum class Type { +enum Type { PAWN = 0, KNIGHT, BISHOP, @@ -19,91 +20,53 @@ enum class Type { }; typedef Iterator<Type, Type::PAWN, Type::KING> TypeIter; -class Piece { - public: - constexpr U64 operator()(Square from, U64 occupancy) const { return attack(from, occupancy); } - +struct Piece { + const uint8_t index; const Type type; - const Color color; + const color::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) {} + const attack::attack_f attack; }; -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) {} +inline constexpr const Piece table[2][6] = { + // clang-format off + { + { .index = 0, .type = PAWN, .color = color::WHITE, .code = 'P', .attack = attack::pawnw::attack }, + { .index = 1, .type = KNIGHT, .color = color::WHITE, .code = 'N', .attack = attack::knight::attack }, + { .index = 2, .type = BISHOP, .color = color::WHITE, .code = 'B', .attack = attack::bishop::attack }, + { .index = 3, .type = ROOK, .color = color::WHITE, .code = 'R', .attack = attack::rook::attack }, + { .index = 4, .type = QUEEN, .color = color::WHITE, .code = 'Q', .attack = attack::queen::attack }, + { .index = 5, .type = KING, .color = color::WHITE, .code = 'K', .attack = attack::king::attack }, + }, { + { .index = 6, .type = PAWN, .color = color::BLACK, .code = 'p', .attack = attack::pawnb::attack }, + { .index = 7, .type = KNIGHT, .color = color::BLACK, .code = 'n', .attack = attack::knight::attack }, + { .index = 8, .type = BISHOP, .color = color::BLACK, .code = 'b', .attack = attack::bishop::attack }, + { .index = 9, .type = ROOK, .color = color::BLACK, .code = 'r', .attack = attack::rook::attack }, + {.index = 10, .type = QUEEN, .color = color::BLACK, .code = 'q', .attack = attack::queen::attack }, + {.index = 11, .type = KING, .color = color::BLACK, .code = 'k', .attack = attack::king::attack }, + }, + // clang-format on }; -class King : public Piece { - public: - constexpr King(Color color) - : Piece(Type::KING, color, color == Color::WHITE ? 'K' : 'k', color == Color::WHITE ? "■ " : "■ ", - attack::king) {} -}; +inline constexpr const Piece &get(const Type type, const color::Color color) { + return table[static_cast<uint8_t>(color)][static_cast<uint8_t>(type)]; +} -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)}, -}; +inline constexpr const U64 get_attack(const Type type, const color::Color color, const square::Square from, + const U64 occupancy) { + return get(type, color).attack(from, occupancy); +} -constexpr const Piece &get(Type type, Color color) { - return table[static_cast<int>(color)][static_cast<int>(type)]; +inline constexpr const char get_code(const Type type, const color::Color color = color::WHITE) { + return get(type, color).code; } -constexpr const U64 get_attack(Type type, Color color, Square from, U64 occupancy) { - return get(type, color)(from, occupancy); +inline constexpr const U64 get_index(const Type type, const color::Color color) { + return get(type, color).index; } -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; +inline constexpr const Piece &get_from_code(const char code) { + color::Color color = isupper(code) ? color::WHITE : color::BLACK; for (Type type : TypeIter()) { const Piece &piece = get(type, color); @@ -113,101 +76,7 @@ constexpr const Piece &get_from_code(char code) { 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, uint8_t square_i) { - if (color == Color::BLACK) square_i = to_underlying(mirror[square_i]); - return position[to_underlying(type)][square_i]; -} +inline constexpr const Piece &get_from_index(const uint8_t index) { return table[index / 6][index % 6]; } } // namespace piece diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt @@ -1,3 +1,19 @@ -add_library(utils utils.cpp) +add_library(bit INTERFACE) +target_include_directories(bit INTERFACE .) +stellar_target_precompile_headers(bit INTERFACE "bit.hpp") + +add_library(bitboard INTERFACE bitboard.cpp) +target_include_directories(bitboard INTERFACE .) +stellar_target_precompile_headers(bitboard INTERFACE "bitboard.hpp") + +add_library(color INTERFACE) +target_include_directories(color INTERFACE .) +stellar_target_precompile_headers(color INTERFACE "color.hpp") + +add_library(square INTERFACE) +target_include_directories(square INTERFACE .) +stellar_target_precompile_headers(square INTERFACE "square.hpp") + +add_library(utils INTERFACE) target_include_directories(utils INTERFACE .) -stellar_target_precompile_headers(attack INTERFACE "utils.hpp") +stellar_target_precompile_headers(utils INTERFACE "utils.hpp") diff --git a/src/utils/bit.hpp b/src/utils/bit.hpp @@ -0,0 +1,39 @@ +#ifndef STELLAR_BIT_H +#define STELLAR_BIT_H + +#include "utils.hpp" + +namespace bit { + +inline constexpr bool get(const U64 &bitboard, uint8_t square) { return (bitboard >> (square)) & C64(1); } +inline constexpr void set(U64 &bitboard, uint8_t square) { bitboard |= (C64(1) << square); } +inline constexpr void pop(U64 &bitboard, uint8_t square) { bitboard &= ~(C64(1) << (square)); } + +inline constexpr uint8_t count(U64 bitboard) { +#if __has_builtin(__builtin_popcountll) + return __builtin_popcountll(bitboard); +#else + int count = 0; + for (; bitboard > 0; bitboard &= bitboard - 1) + count++; + return count; +#endif +} + +inline constexpr uint8_t lsb_index(U64 bitboard) { +#if __has_builtin(__builtin_ffsll) + return __builtin_ffsll(bitboard) - 1; +#else + if (!bitboard) return -1; + return bit_count((bitboard & -bitboard) - 1); +#endif +} + +inline constexpr U64 &lsb_pop(U64 &bitboard) { return 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)) + +} // namespace bit + +#endif diff --git a/src/utils/bitboard.cpp b/src/utils/bitboard.cpp @@ -0,0 +1,20 @@ +#include "bitboard.hpp" +#include "bit.hpp" + +#include <iostream> + +namespace bitboard { +void print(U64 bitboard) { + for (int rank = 0; rank < 8; rank++) { + for (int file = 0; file < 8; file++) { + uint8_t square = (7 - rank) * 8 + file; + if (!file) printf(" %d ", 8 - rank); + std::cout << bit::get(bitboard, square) << " "; + } + std::cout << "\n"; + } + + std::cout << "\n A B C D E F G H\n\n"; + std::cout << " Bitboard: " << std::hex << bitboard << std::dec << std::endl; +} +} // namespace bitboard diff --git a/src/utils/bitboard.hpp b/src/utils/bitboard.hpp @@ -0,0 +1,25 @@ +#ifndef STELLAR_BITBOARD_H +#define STELLAR_BITBOARD_H + +#include "utils.hpp" + +namespace bitboard { + +void print(U64 bitboard); + +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; } + +} // namespace bitboard + +#endif diff --git a/src/utils/color.hpp b/src/utils/color.hpp @@ -0,0 +1,15 @@ +#ifndef STELLAR_COLOR_H +#define STELLAR_COLOR_H + +namespace color { + +enum Color { + WHITE = 0, + BLACK +}; + +inline constexpr const Color other(const Color color) { return color == WHITE ? BLACK : WHITE; } + +} // namespace color + +#endif diff --git a/src/utils/square.hpp b/src/utils/square.hpp @@ -0,0 +1,64 @@ +#ifndef STELLAR_SQUARE_H +#define STELLAR_SQUARE_H + +#include "utils.hpp" +#include <string> + +namespace square { + +enum Square { + // clang-format off + 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> Iter; + +inline constexpr const Square mirror_array[]{ + // clang-format off + a8, b8, c8, d8, e8, f8, g8, h8, + a7, b7, c7, d7, e7, f7, g7, h7, + a6, b6, c6, d6, e6, f6, g6, h6, + a5, b5, c5, d5, e5, f5, g5, h5, + a4, b4, c4, d4, e4, f4, g4, h4, + a3, b3, c3, d3, e3, f3, g3, h3, + a2, b2, c2, d2, e2, f2, g2, h2, + a1, b1, c1, d1, e1, f1, g1, h1, no_sq + // clang-format on +}; + +inline constexpr const char *coordinates_array[] = { + // clang-format off + "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", " " + // clang-format on +}; + +inline constexpr const uint8_t file(const Square square) { return to_underlying(square) & 0x07; } +inline constexpr const uint8_t rank(const Square square) { return to_underlying(square) >> 3; } +inline constexpr const Square mirror(const Square square) { return mirror_array[square]; } + +inline constexpr const char *to_coordinates(const Square square) { + return coordinates_array[to_underlying(square)]; +} + +inline const Square from_coordinates(const std::string &cord) { + return static_cast<Square>((cord[1] - '1') * 8 + (cord[0] - 'a')); +} + +} // namespace square + +#endif diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp @@ -1,16 +0,0 @@ -#include "utils.hpp" -#include <iostream> - -void bitboard_print(U64 bitboard) { - for (int rank = 0; rank < 8; rank++) { - for (int file = 0; file < 8; file++) { - uint8_t square = (7 - rank) * 8 + file; - if (!file) printf(" %d ", 8 - rank); - std::cout << bit_get(bitboard, square) << " "; - } - std::cout << "\n"; - } - - std::cout << "\n A B C D E F G H\n\n"; - std::cout << " Bitboard: " << std::hex << bitboard << std::dec << std::endl; -} diff --git a/src/utils/utils.hpp b/src/utils/utils.hpp @@ -2,8 +2,13 @@ #define STELLAR_UTILS_CPP_H #include <cstdint> -#include <exception> -#include <string> + +#define C64(constantU64) constantU64##ULL +#define C32(constantU64) constantU64##UL + +typedef uint64_t U64; +typedef uint32_t U32; + #include <type_traits> template <typename E> constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept { @@ -31,100 +36,4 @@ template <typename C, C beginVal, C endVal> class Iterator { 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 std::string &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)) - -void bitboard_print(U64 bitboard); - -// 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