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