commit 3339ad957adba20630645faafc9751f114436587
parent b14ec9be9a45282c4dab765129595acb33bcb32f
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Sun, 3 Sep 2023 22:40:19 +0200
Major refactor
Diffstat:
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 ©, const Move move) {
void stats_move_make_pruning(Board ©) {
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