stellarUCI Chess engine written in C++20 |
git clone git://git.dimitrijedobrota.com/stellar.git |
Log | Files | Refs | README | LICENSE | |
commit | 3339ad957adba20630645faafc9751f114436587 |
parent | b14ec9be9a45282c4dab765129595acb33bcb32f |
author | Dimitrije Dobrota <mail@dimitrijedobrota.com> |
date | Sun, 3 Sep 2023 20:40:19 +0200 |
Major refactor
Diffstat:M | CMakeLists.txt | | | +- |
M | src/attack/CMakeLists.txt | | | +++++++++++++++++++++--- |
A | src/attack/attack.cpp | | | + |
M | src/attack/attack.hpp | | | ++++------------------------------------------------------------------------------ |
A | src/attack/bishop.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/attack/king.hpp | | | ++++++++++++++++++++++++++++++++++++++++++ |
A | src/attack/knight.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++ |
A | src/attack/pawnb.hpp | | | ++++++++++++++++++++++++++++++++++++ |
A | src/attack/pawnw.hpp | | | ++++++++++++++++++++++++++++++++++++ |
A | src/attack/queen.hpp | | | +++++++++++++++++ |
A | src/attack/rook.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/attack/slider.hpp | | | +++++++++++++++++++++++++++++++++++++++ |
M | src/board/board.cpp | | | ++++++++++++++--------------- |
M | src/board/board.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
M | src/board/zobrist.hpp | | | ++++++---- |
M | src/engine/engine.cpp | | | ++++++------ |
M | src/engine/evaluate.cpp | | | +++++++++++++++++++++++++++++++++++++++++----------------------------------------- |
M | src/engine/score.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/engine/uci.cpp | | | +++++----- |
M | src/move/move.cpp | | | ++++++++++++++++++++----------------- |
M | src/move/move.hpp | | | +++++++------ |
M | src/move/movelist.cpp | | | ++++++++++++++++++++++++++++++++++---------------------------------- |
M | src/piece/CMakeLists.txt | | | + |
M | src/piece/piece.hpp | | | ++++++++++++++++------------------------------------------------------------------ |
M | src/utils/CMakeLists.txt | | | ++++++++++++++++++-- |
A | src/utils/bit.hpp | | | +++++++++++++++++++++++++++++++++++++++ |
A | src/utils/bitboard.cpp | | | ++++++++++++++++++++ |
A | src/utils/bitboard.hpp | | | +++++++++++++++++++++++++ |
A | src/utils/color.hpp | | | +++++++++++++++ |
A | src/utils/square.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | src/utils/utils.cpp | | | ---------------- |
M | src/utils/utils.hpp | | | ++++++---------------------------------------------------------------------------- |
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,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