stellar

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

commit f58bf4bfaba4974e1a4af873afc8d74c66bbc285
parent efb266c91585d3dcfe9ade481bc13199b9508418
author Dimitrije Dobrota <mail@dimitrijedobrota.com>
date Thu, 10 Aug 2023 19:02:31 +0200

Attack generation at compile time with constexpr

Diffstat:
M .clang-format | ++ --
M CMakeLists.txt | +++++++ -
D src/attacks/CMakeLists.txt | -----------------------------------
D src/attacks/attacks.cpp | ---------------------------------------------------------------------------------
D src/attacks/internal.cpp | ---------------------------------------------------------------------------------
D src/attacks/internal.hpp | ------------------------------
D src/attacks/magic.cpp | ---------------------------------------------------
D src/attacks/magic.hpp | ---------
D src/attacks/magic_generate.cpp | ---------------------------------------------------------------------
M src/board/board.cpp | +++++++++++++++++++++++++++++ --------------------------
M src/board/zobrist.cpp | +++++++++ ---
M src/engine/CMakeLists.txt | --
M src/engine/engine.cpp | ++++++++++++++++++++++++++++ ----------------------------------------
M src/engine/transposition.cpp | ++++ --------
M src/engine/transposition.hpp | ++++++++ -------
A src/include/attack.hpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
D src/include/attacks.hpp | -----------------
M src/include/board.hpp | +++++ -------
A src/include/magic.hpp | ++++++++++++++++++++++++++++++++++++++++++++
M src/include/moves.hpp | ++ ---
M src/include/piece.hpp | ++++++++++++++++++++++++++++++++++ -----------------------
M src/include/utils_cpp.hpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++ ---------------------------
M src/moves/moves.cpp | ++++++++++ ------------
M src/moves/moves_generate.cpp | ++++++++++++++++++++++++++++++ ----------------------------------------------------
M src/moves/moves_make.cpp | +++++++ --------------
M src/perft/CMakeLists.txt | --
M src/perft/perft.cpp | +++++++++++++ ----------------
D src/piece/CMakeLists.txt | -------
D src/piece/piece.cpp | -
M src/utils/random.cpp | +++ -

30 files changed, 642 insertions(+), 734 deletions(-)


diff --git a/ .clang-format b/ .clang-format

@@ -36,7 +36,7 @@ AllowAllParametersOfDeclarationOnNextLine: true AllowShortEnumsOnASingleLine: false AllowShortBlocksOnASingleLine: Never AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: true
AllowShortFunctionsOnASingleLine: false
AllowShortLambdasOnASingleLine: All AllowShortIfStatementsOnASingleLine: true AllowShortLoopsOnASingleLine: false

@@ -77,7 +77,7 @@ BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true
ColumnLimit: 80
ColumnLimit: 110
CommentPragmas: '^ IWYU pragma:' QualifierAlignment: Leave CompactNamespaces: false

diff --git a/ CMakeLists.txt b/ CMakeLists.txt

@@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project( Stellar
VERSION 0.0.18
VERSION 0.0.19
DESCRIPTION "Chess engine written in C" HOMEPAGE_URL https://git.dimitrijedobrota.com/stellar.git LANGUAGES C CXX

@@ -13,4 +13,10 @@ set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fconstexpr-ops-limit=1000000000")
add_subdirectory(src)

diff --git a/ src/attacks/CMakeLists.txt b/ src/attacks/CMakeLists.txt

@@ -1,35 +0,0 @@
add_library(attacks OBJECT
attacks.cpp
internal.cpp
magic.cpp
)
target_include_directories(attacks
PUBLIC "${PROJECT_SOURCE_DIR}/src/include"
PRIVATE "internal"
)
project(
MagicGenerator
VERSION 1.0.0
DESCRIPTION "Generator of magic numbers for bishup and rook attacks"
LANGUAGES CXX
)
add_executable(magic
internal.cpp
magic.cpp
magic_generate.cpp
)
target_link_libraries(magic
PRIVATE random
)
set_target_properties(magic PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)

diff --git a/ src/attacks/attacks.cpp b/ src/attacks/attacks.cpp

@@ -1,99 +0,0 @@
#include "attacks.hpp"
#include "internal.hpp"
#include "magic.hpp"
#include "utils_cpp.hpp"
#define UNUSED(x) (void)(x)
U64 attacks_wpawn_get(Square square, U64 occupancy) {
UNUSED(occupancy);
return pawn_attacks[to_underlying(Color::WHITE)][to_underlying(square)];
}
U64 attacks_bpawn_get(Square square, U64 occupancy) {
UNUSED(occupancy);
return pawn_attacks[to_underlying(Color::BLACK)][to_underlying(square)];
}
U64 attacks_knight_get(Square square, U64 occupancy) {
UNUSED(occupancy);
return knight_attacks[to_underlying(square)];
}
U64 attacks_king_get(Square square, U64 occupancy) {
UNUSED(occupancy);
return king_attacks[to_underlying(square)];
}
U64 attacks_bishop_get(Square square, U64 occupancy) {
int square_i = to_underlying(square);
occupancy &= bishop_masks[square_i];
occupancy = hash(occupancy, bishop_magic_numbers[square_i],
bishop_relevant_bits[square_i]);
return bishop_attacks[square_i][occupancy];
}
U64 attacks_rook_get(Square square, U64 occupancy) {
int square_i = to_underlying(square);
occupancy &= rook_masks[square_i];
occupancy = hash(occupancy, rook_magic_numbers[square_i],
rook_relevant_bits[square_i]);
return rook_attacks[square_i][occupancy];
}
U64 attacks_queen_get(Square square, U64 occupancy) {
return (attacks_bishop_get(square, occupancy) |
attacks_rook_get(square, occupancy));
}
void attacks_init_leapers(void) {
for (Square square : SquareIter()) {
uint8_t square_i = to_underlying(square);
pawn_attacks[to_underlying(Color::WHITE)][square_i] =
pawn_mask(Color::WHITE, square);
pawn_attacks[to_underlying(Color::BLACK)][square_i] =
pawn_mask(Color::BLACK, square);
knight_attacks[square_i] = knight_mask(square);
king_attacks[square_i] = king_mask(square);
}
}
void attacks_init_sliders(int bishop) {
for (Square square : SquareIter()) {
uint8_t square_i = to_underlying(square);
U64 attack_mask;
if (bishop) {
bishop_masks[square_i] = bishop_mask(square);
attack_mask = bishop_masks[square_i];
} else {
rook_masks[square_i] = rook_mask(square);
attack_mask = rook_masks[square_i];
}
int relevant_bits = bit_count(attack_mask);
int occupancy_indicies = 1 << relevant_bits;
for (int index = 0; index < occupancy_indicies; index++) {
U64 occupancy = set_occupancy(index, relevant_bits, attack_mask);
if (bishop) {
int magic_index =
(occupancy * bishop_magic_numbers[square_i]) >>
(64 - bishop_relevant_bits[square_i]);
bishop_attacks[square_i][magic_index] =
bishop_on_the_fly(square, occupancy);
} else {
int magic_index = hash(occupancy, rook_magic_numbers[square_i],
rook_relevant_bits[square_i]);
rook_attacks[square_i][magic_index] =
rook_on_the_fly(square, occupancy);
}
}
}
}
void attacks_init(void) {
attacks_init_leapers();
attacks_init_sliders(0);
attacks_init_sliders(1);
}

diff --git a/ src/attacks/internal.cpp b/ src/attacks/internal.cpp

@@ -1,148 +0,0 @@
#include "internal.hpp"
#include "utils_cpp.hpp"
#include <algorithm> // std::min
U64 king_attacks[64];
U64 knight_attacks[64];
U64 pawn_attacks[2][64];
U64 rook_attacks[64][4096]; // 2048K
U64 bishop_attacks[64][512]; // 256 K
U64 rook_masks[64];
U64 bishop_masks[64];
// clang-format off
const int bishop_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,
};
const int rook_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
int hash(U64 key, U64 magic, int relevant_bits) {
return (key * magic) >> (64 - relevant_bits);
}
U64 set_occupancy(int index, int bits_in_mask, U64 attack_mask) {
U64 occupancy = C64(0);
for (int count = 0; count < bits_in_mask; count++) {
uint8_t square = bit_lsb_index(attack_mask);
bit_pop(attack_mask, square);
if (index & (1 << count)) bit_set(occupancy, square);
}
return occupancy;
}
U64 attacks_slide_mask(Square square, U64 block, const direction_f dir[4],
int len[4]) {
U64 bitboard = C64(0), attacks = C64(0), tmp;
int i, j;
bit_set(bitboard, to_underlying(square));
for (i = 0; i < 4; i++) {
for (j = 0, tmp = bitboard; j < len[i]; j++) {
attacks |= tmp = (dir[i])(tmp);
if (tmp & block) break;
}
}
return attacks;
}
// Mask Attacks
const direction_f attacks_bishop_direction[4] = {noEaOne, noWeOne, soEaOne,
soWeOne};
const direction_f attacks_rook_direction[4] = {westOne, soutOne, eastOne,
nortOne};
U64 pawn_mask(Color side, Square square) {
U64 bitboard = C64(0);
bit_set(bitboard, to_underlying(square));
if (side == Color::WHITE)
return noWeOne(bitboard) | noEaOne(bitboard);
else
return soWeOne(bitboard) | soEaOne(bitboard);
}
U64 knight_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;
}
U64 king_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;
}
U64 bishop_mask(Square square) {
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};
return attacks_slide_mask(square, C64(0), attacks_bishop_direction, len);
}
U64 rook_mask(Square square) {
uint8_t square_i = to_underlying(square);
int tr = square_i / 8, tf = square_i % 8;
int len[4] = {tf - 1, tr - 1, 6 - tf, 6 - tr};
return attacks_slide_mask(square, C64(0), attacks_rook_direction, len);
}
U64 bishop_on_the_fly(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 attacks_slide_mask(square, block, attacks_bishop_direction, len);
}
U64 rook_on_the_fly(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 attacks_slide_mask(square, block, attacks_rook_direction, len);
}

diff --git a/ src/attacks/internal.hpp b/ src/attacks/internal.hpp

@@ -1,30 +0,0 @@
#ifndef STELLAR_ATTAKCS_INTERNAL_H
#define STELLAR_ATTAKCS_INTERNAL_H
#include "utils_cpp.hpp"
extern U64 king_attacks[64]; // king attack table [square]
extern U64 knight_attacks[64]; // knight attack table [square]
extern U64 pawn_attacks[2][64]; // pawn attack table [side][square]
extern U64 rook_attacks[64][4096]; // rook attack table [square][occupancies]
extern U64 bishop_attacks[64][512]; // bishop attack table [square][occupancies]
extern U64 rook_masks[64]; // rook attack mask
extern U64 bishop_masks[64]; // bishop attack mask
extern const int rook_relevant_bits[64];
extern const int bishop_relevant_bits[64];
int hash(U64 key, U64 magic, int relevant_bits);
U64 set_occupancy(int index, int bits_in_mask, U64 attack_mask);
U64 bishop_mask(Square square);
U64 bishop_on_the_fly(Square square, U64 block);
U64 king_mask(Square square);
U64 knight_mask(Square square);
U64 pawn_mask(Color side, Square square);
U64 rook_mask(Square square);
U64 rook_on_the_fly(Square square, U64 block);
#endif

diff --git a/ src/attacks/magic.cpp b/ src/attacks/magic.cpp

@@ -1,51 +0,0 @@
#include "magic.hpp"
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),
};
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),
};

diff --git a/ src/attacks/magic.hpp b/ src/attacks/magic.hpp

@@ -1,9 +0,0 @@
#ifndef STELLAR_ATTACKS_MAGIC_H
#define STELLAR_ATTACKS_MAGIC_H
#include "utils_cpp.hpp"
extern const U64 bishop_magic_numbers[64];
extern const U64 rook_magic_numbers[64];
#endif

diff --git a/ src/attacks/magic_generate.cpp b/ src/attacks/magic_generate.cpp

@@ -1,69 +0,0 @@
#include "internal.hpp"
#include "random.hpp"
#include "utils_cpp.hpp"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
const char *FORMAT = "C64(0x%llx),\n";
U64 generate_magic_number() {
return random_get_U64() & random_get_U64() & random_get_U64();
}
U64 find_magic_number(Square square, int relevant_bits, int bishop) {
U64 occupancies[4096], attacks[4096], used_attacks[4096];
U64 attack_mask = bishop ? bishop_mask(square) : rook_mask(square);
int occupancy_indicies = 1 << relevant_bits;
for (int index = 0; index < occupancy_indicies; index++) {
occupancies[index] = set_occupancy(index, relevant_bits, attack_mask);
attacks[index] = bishop ? bishop_on_the_fly(square, occupancies[index])
: rook_on_the_fly(square, occupancies[index]);
}
for (int random_count = 0; random_count < 100000000; random_count++) {
U64 magic_number = generate_magic_number();
if (bit_count((attack_mask * magic_number) & C64(0xFF00000000000000)) <
6)
continue;
memset(used_attacks, C64(0), sizeof(used_attacks));
int index, fail;
for (index = 0, fail = 0; !fail && index < occupancy_indicies;
index++) {
int magic_index =
hash(occupancies[index], magic_number, relevant_bits);
if (used_attacks[magic_index] == C64(0))
used_attacks[magic_index] = attacks[index];
else if (used_attacks[magic_index] != attacks[index])
fail = 1;
}
if (!fail) return magic_number;
}
return C64(0);
}
int main(void) {
random_state_reset();
printf("Bishup Magic Numbers:\n");
for (Square square : SquareIter())
printf(FORMAT,
find_magic_number(
square, bishop_relevant_bits[to_underlying(square)], 1));
printf("Rook Magic Numbers:\n");
for (Square square : SquareIter())
printf(FORMAT,
find_magic_number(square,
rook_relevant_bits[to_underlying(square)], 0));
return 0;
}

diff --git a/ src/board/board.cpp b/ src/board/board.cpp

@@ -10,18 +10,25 @@ /* Getters */
Color Board::get_side(void) const { return side; }
U64 Board::get_hash(void) const { return hash; }
uint8_t Board::get_castle(void) const { return castle; }
Square Board::get_enpassant(void) const { return enpassant; }
Color Board::get_side(void) const {
return side;
}
U64 Board::get_hash(void) const {
return hash;
}
uint8_t Board::get_castle(void) const {
return castle;
}
Square Board::get_enpassant(void) const {
return enpassant;
}
U64 Board::get_bitboard_color(Color side) const { return colors[to_underlying(side)]; } U64 Board::get_bitboard_occupancy(void) const {
return colors[to_underlying(Color::WHITE)] |
colors[to_underlying(Color::BLACK)];
return colors[to_underlying(Color::WHITE)] | colors[to_underlying(Color::BLACK)];
} U64 Board::get_bitboard_piece(piece::Type piece) const {

@@ -36,45 +43,43 @@ U64 Board::get_bitboard_piece(piece::Type piece, Color color) const { return pieces[to_underlying(piece)] & colors[to_underlying(color)]; }
U64 Board::get_bitboard_piece_attacks(piece::Type piece, Color color,
Square square) const {
U64 Board::get_bitboard_piece_attacks(piece::Type piece, Color color, Square square) const {
return get_bitboard_piece_attacks(piece::get(piece, color), square); }
U64 Board::get_bitboard_piece_attacks(const piece::Piece &piece,
Square square) const {
return piece.attacks(square, get_bitboard_occupancy());
U64 Board::get_bitboard_piece_attacks(const piece::Piece &piece, Square square) const {
return piece(square, get_bitboard_occupancy());
} 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;
if (bit_get(colors[to_underlying(Color::WHITE)], to_underlying(square))) return Color::WHITE;
if (bit_get(colors[to_underlying(Color::BLACK)], to_underlying(square))) return Color::BLACK;
throw std::exception(); } piece::Type Board::get_square_piece_type(Square square) const { for (piece::Type type : piece::TypeIter()) {
if (bit_get(pieces[to_underlying(type)], to_underlying(square)))
return type;
if (bit_get(pieces[to_underlying(type)], to_underlying(square))) return type;
} throw std::exception(); } const piece::Piece *Board::get_square_piece(Square square) const { try {
return &piece::get(get_square_piece_type(square),
get_square_piece_color(square));
} catch (std::exception e) {
return &piece::get(get_square_piece_type(square), get_square_piece_color(square));
} catch (std::exception &e) {
return nullptr; } } /* Setters */
void Board::xor_hash(U64 op) { hash ^= op; }
void Board::and_castle(uint8_t right) { castle &= right; }
void Board::xor_hash(U64 op) {
hash ^= op;
}
void Board::and_castle(uint8_t right) {
castle &= right;
}
void Board::switch_side(void) { side = (side == Color::BLACK) ? Color::WHITE : Color::BLACK;

@@ -133,8 +138,7 @@ bool Board::is_square_attacked(Square square, Color side) const { } bool Board::is_check(void) const {
U64 king =
pieces[to_underlying(piece::Type::KING)] & colors[to_underlying(side)];
U64 king = pieces[to_underlying(piece::Type::KING)] & colors[to_underlying(side)];
Color side_other = (side == Color::BLACK) ? Color::WHITE : Color::BLACK; Square square = static_cast<Square>(bit_lsb_index(king)); return is_square_attacked(square, side_other);

@@ -144,8 +148,7 @@ Board::Board(const std::string &fen) { int file = 0, rank = 7, i; for (i = 0; fen[i] != ' '; i++) { if (isalpha(fen[i])) {
set_piece(piece::get_from_code(fen[i]),
static_cast<Square>(rank * 8 + file));
set_piece(piece::get_from_code(fen[i]), static_cast<Square>(rank * 8 + file));
file++; } else if (isdigit(fen[i])) { file += fen[i] - '0';

diff --git a/ src/board/zobrist.cpp b/ src/board/zobrist.cpp

@@ -8,8 +8,12 @@ U64 enpassant_keys[64]; U64 piece_keys[16][64]; U64 side_key;
U64 zobrist_key_side(void) { return side_key; }
U64 zobrist_key_castle(int exp) { return castle_keys[exp]; }
U64 zobrist_key_side(void) {
return side_key;
}
U64 zobrist_key_castle(int exp) {
return castle_keys[exp];
}
U64 zobrist_key_enpassant(Square square) { return enpassant_keys[to_underlying(square)]; }

@@ -40,7 +44,9 @@ void init_hash_keys() { side_key = random_get_U64(); }
void zobrist_init(void) { init_hash_keys(); }
void zobrist_init(void) {
init_hash_keys();
}
U64 zobrist_hash(const Board &board) { U64 key_final = C64(0);

diff --git a/ src/engine/CMakeLists.txt b/ src/engine/CMakeLists.txt

@@ -5,10 +5,8 @@ add_executable(engine ) target_link_libraries(engine
PRIVATE attacks
PRIVATE board PRIVATE moves
PRIVATE piece
PRIVATE random )

diff --git a/ src/engine/engine.cpp b/ src/engine/engine.cpp

@@ -3,7 +3,7 @@ #include <stdlib.h> #include <string.h>
#include "attacks.hpp"
#include "attack.hpp"
#include "board.hpp" #include "moves.hpp" #include "score.hpp"

@@ -65,7 +65,9 @@ int evaluate(const Board &board) { return score; }
int is_repetition() { return 0; }
int is_repetition() {
return 0;
}
int stats_move_make(Stats &stats, Board &copy, Move move, int flag) { copy = stats.board;

@@ -110,7 +112,7 @@ int quiescence(Stats &stats, int alpha, int beta) { Board copy; std::vector<MoveE> list = move_list_generate(stats.board); Score_move_list(stats, list);
move_list_sort_pv(list, stats, (Move){0});
move_list_sort_pv(list, stats, {0});
move_list_sort(list); for (const auto [move, _] : list) {

@@ -170,8 +172,7 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) { // null move pruning if (stats.ply && depth > 2 && staticEval >= beta) { stats_move_make_pruning(stats, copy);
score = -negamax(stats, -beta, -beta + 1,
depth - 1 - REDUCTION_MOVE, false);
score = -negamax(stats, -beta, -beta + 1, depth - 1 - REDUCTION_MOVE, false);
stats_move_unmake(stats, copy); if (score >= beta) return beta; }

@@ -186,16 +187,13 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) { score += Score_value(piece::Type::PAWN); if (score < beta && depth < 4) {
if (scoreNew < beta)
return (scoreNew > score) ? scoreNew : score;
if (scoreNew < beta) return (scoreNew > score) ? scoreNew : score;
} } // futility pruning condition static const int margin[] = {0, 100, 300, 500};
if (depth < 4 && abs(alpha) < MATE_SCORE &&
staticEval + margin[depth] <= alpha)
futility = 1;
if (depth < 4 && abs(alpha) < MATE_SCORE && staticEval + margin[depth] <= alpha) futility = 1;
} std::vector<MoveE> list = move_list_generate(stats.board);

@@ -210,8 +208,7 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) { legal_moves++; // futility pruning
if (futility && searched && !move_capture(move) &&
!move_promote(move) && !stats.board.is_check()) {
if (futility && searched && !move_capture(move) && !move_promote(move) && !stats.board.is_check()) {
stats_move_unmake(stats, copy); continue; }

@@ -220,15 +217,12 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) { score = -negamax(stats, -beta, -alpha, depth - 1, true); } else { // Late Move Reduction
if (!pv_node && searched >= FULL_DEPTH &&
depth >= REDUCTION_LIMIT && !isCheck && !move_capture(move) &&
!move_promote(move) &&
if (!pv_node && searched >= FULL_DEPTH && depth >= REDUCTION_LIMIT && !isCheck &&
!move_capture(move) && !move_promote(move) &&
(move_source(move) != move_source(stats.killer[0][stats.ply]) ||
move_target(move) !=
move_target(stats.killer[0][stats.ply])) &&
move_target(move) != move_target(stats.killer[0][stats.ply])) &&
(move_source(move) != move_source(stats.killer[1][stats.ply]) ||
move_target(move) !=
move_target(stats.killer[1][stats.ply]))) {
move_target(move) != move_target(stats.killer[1][stats.ply]))) {
score = -negamax(stats, -alpha - 1, -alpha, depth - 2, true); } else score = alpha + 1;

@@ -249,8 +243,7 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) { if (score > alpha) { if (!move_capture(move)) {
stats.history[move_piece(move).index][move_target(move)] +=
depth;
stats.history[move_piece(move).index][move_target(move)] += depth;
} alpha = score;

@@ -259,8 +252,7 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) { stats_pv_store(stats, move); if (score >= beta) {
stats.ttable.write(stats, bestMove, beta, depth,
HasheFlag::Beta);
stats.ttable.write(stats, bestMove, beta, depth, HasheFlag::Beta);
if (!move_capture(move)) { stats.killer[1][stats.ply] = stats.killer[0][stats.ply];

@@ -284,8 +276,7 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) { } void move_print_UCI(Move move) {
printf("%s%s",
square_to_coordinates(static_cast<Square>(move_source(move))),
printf("%s%s", square_to_coordinates(static_cast<Square>(move_source(move))),
square_to_coordinates(static_cast<Square>(move_target(move)))); if (move_promote(move)) printf("%c", (move_piece_promote(move).code)); }

@@ -309,14 +300,13 @@ void search_position(Board &board, int depth) { if (stats.pv_length[0]) { if (score > -MATE_VALUE && score < -MATE_SCORE) {
printf("info score mate %d depth %d nodes %ld pv ",
-(score + MATE_VALUE) / 2 - 1, crnt, stats.nodes);
printf("info score mate %d depth %d nodes %ld pv ", -(score + MATE_VALUE) / 2 - 1, crnt,
stats.nodes);
} else if (score > MATE_SCORE && score < MATE_VALUE) {
printf("info score mate %d depth %d nodes %ld pv ",
(MATE_VALUE - score) / 2 + 1, crnt, stats.nodes);
} else {
printf("info score cp %d depth %d nodes %ld pv ", score, crnt,
printf("info score mate %d depth %d nodes %ld pv ", (MATE_VALUE - score) / 2 + 1, crnt,
stats.nodes);
} else {
printf("info score cp %d depth %d nodes %ld pv ", score, crnt, stats.nodes);
} for (int i = 0; i < stats.pv_length[0]; i++) {

@@ -364,7 +354,9 @@ void Instruction_free(Instruction **p) { delete (*p); }
char *Instruction_token(Instruction *self) { return self->token; }
char *Instruction_token(Instruction *self) {
return self->token;
}
char *Instruction_token_n(Instruction *self, int n) { while (isspace(*self->crnt) && *self->crnt != '\0') self->crnt++;

@@ -376,8 +368,7 @@ char *Instruction_token_n(Instruction *self, int n) { char *p = self->token; while (n--) {
while (!isspace(*self->crnt) && *self->crnt != '\0' &&
*self->crnt != ';')
while (!isspace(*self->crnt) && *self->crnt != '\0' && *self->crnt != ';')
*p++ = *self->crnt++; if (*self->crnt == '\0') { p++;

@@ -405,8 +396,7 @@ Move parse_move(Board &board, char *move_string) { for (const auto [move, _] : list) { if (move_source(move) == source && move_target(move) == target) { if (move_string[4]) {
if (tolower(move_piece_promote(move).code) != move_string[4])
continue;
if (tolower(move_piece_promote(move).code) != move_string[4]) continue;
} result = move; break;

@@ -444,7 +434,7 @@ Board *Instruction_parse(Instruction *self, Board &board) { if (strcmp(token, "moves") == 0) { while ((token = Instruction_token_next(self))) { Move move = parse_move(board, token);
if (!move_cmp(move, (Move){0})) {
if (!move_cmp(move, {0})) {
move_make(move, board, 0); } else { printf("Invalid move %s!\n", token);

@@ -456,8 +446,7 @@ Board *Instruction_parse(Instruction *self, Board &board) { if (strcmp(token, "go") == 0) { int depth = 6;
for (token = Instruction_token_next(self); token;
token = Instruction_token_next(self)) {
for (token = Instruction_token_next(self); token; token = Instruction_token_next(self)) {
if (token && strcmp(token, "depth") == 0) { token = Instruction_token_next(self);

@@ -509,7 +498,6 @@ void uci_loop(void) { /* MAIN */ void init(void) {
attacks_init();
zobrist_init(); }

diff --git a/ src/engine/transposition.cpp b/ src/engine/transposition.cpp

@@ -2,8 +2,7 @@ #include "board.hpp" #include "score.hpp"
int TTable::read(const Stats &stats, Move *best, int alpha, int beta,
int depth) const {
int TTable::read(const Stats &stats, Move *best, int alpha, int beta, int depth) const {
U64 hash = stats.board.get_hash(); const Hashe &phashe = table[hash % table.size()];

@@ -15,18 +14,15 @@ int TTable::read(const Stats &stats, Move *best, int alpha, int beta, if (score > MATE_SCORE) score -= stats.ply; if (phashe.flag == HasheFlag::Exact) return score;
if ((phashe.flag == HasheFlag::Alpha) && (score <= alpha))
return alpha;
if ((phashe.flag == HasheFlag::Beta) && (score >= beta))
return beta;
if ((phashe.flag == HasheFlag::Alpha) && (score <= alpha)) return alpha;
if ((phashe.flag == HasheFlag::Beta) && (score >= beta)) return beta;
} *best = phashe.best; } return TTABLE_UNKNOWN; }
void TTable::write(const Stats &stats, Move best, int score, int depth,
HasheFlag flag) {
void TTable::write(const Stats &stats, Move best, int score, int depth, HasheFlag flag) {
U64 hash = stats.board.get_hash(); Hashe &phashe = table[hash % table.size()];

diff --git a/ src/engine/transposition.hpp b/ src/engine/transposition.hpp

@@ -28,13 +28,14 @@ struct Hashe { class TTable { public:
TTable(U64 size) : table(size, {0}) {}
void clear() { table.clear(); };
void write(const Stats &stats, Move best, int score, int depth,
HasheFlag flag);
int read(const Stats &stats, Move *best, int alpha, int beta,
int depth) const;
TTable(U64 size) : table(size, {0}) {
}
void clear() {
table.clear();
};
void write(const Stats &stats, Move best, int score, int depth, HasheFlag flag);
int read(const Stats &stats, Move *best, int alpha, int beta, int depth) const;
private: std::vector<Hashe> table;

diff --git a/ src/include/attack.hpp b/ src/include/attack.hpp

@@ -0,0 +1,337 @@
#ifndef STELLAR_ATTAKCS_INTERNAL_H
#define STELLAR_ATTAKCS_INTERNAL_H
#include "magic.hpp"
#include "utils_cpp.hpp"
#include <array>
namespace attack {
class Slider {
public:
virtual constexpr U32 hash(U64 key, Square square) const = 0;
virtual constexpr U64 mask(Square square) const = 0;
virtual constexpr U64 mask_fly(Square square, U64 block) const = 0;
static inline constexpr U64 occupancy(U64 index, uint8_t bits_in_mask, U64 attack_mask) {
U64 occupancy = C64(0);
for (uint8_t count = 0; count < bits_in_mask; count++) {
uint8_t square = bit_lsb_index(attack_mask);
bit_pop(attack_mask, square);
if (bit_get(index, count)) bit_set(occupancy, square);
}
return occupancy;
}
protected:
static inline constexpr U64 mask_slide(Square square, U64 block, const direction_f dir[4],
const int len[4]) {
U64 bitboard = C64(0), attacks = C64(0);
bit_set(bitboard, to_underlying(square));
for (int i = 0; i < 4; i++) {
U64 tmp = bitboard;
for (int j = 0; j < len[i]; j++) {
attacks |= tmp = (dir[i])(tmp);
if (tmp & block) break;
}
}
return attacks;
}
};
class SliderRook : public Slider {
public:
virtual constexpr U32 hash(U64 key, Square square) const override {
uint8_t square_i = to_underlying(square);
return (key * rook_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]);
}
virtual constexpr U64 mask(Square square) const override {
return masks[to_underlying(square)];
}
virtual constexpr U64 mask_fly(Square square, U64 block) const override {
uint8_t square_i = to_underlying(square);
int tr = square_i / 8, tf = square_i % 8;
int len[4] = {tf, tr, 7 - tf, 7 - tr};
return mask_slide(square, block, dir, len);
}
private:
static inline constexpr const direction_f dir[4] = {westOne, soutOne, eastOne, nortOne};
// clang-format off
static inline constexpr const int relevant_bits[64] = {
12, 11, 11, 11, 11, 11, 11, 12,
11, 10, 10, 10, 10, 10, 10, 11,
11, 10, 10, 10, 10, 10, 10, 11,
11, 10, 10, 10, 10, 10, 10, 11,
11, 10, 10, 10, 10, 10, 10, 11,
11, 10, 10, 10, 10, 10, 10, 11,
11, 10, 10, 10, 10, 10, 10, 11,
12, 11, 11, 11, 11, 11, 11, 12,
};
// clang-format on
static inline constexpr const std::array<U64, 64> masks = []() constexpr -> std::array<U64, 64> {
std::array<U64, 64> masks;
for (const Square square : SquareIter()) {
const uint8_t square_i = to_underlying(square);
const int tr = square_i / 8, tf = square_i % 8;
const int len[4] = {tf - 1, tr - 1, 6 - tf, 6 - tr};
masks[square_i] = mask_slide(square, C64(0), dir, len);
}
return masks;
}();
};
class SliderBishop : public Slider {
public:
virtual constexpr U32 hash(U64 key, Square square) const override {
uint8_t square_i = to_underlying(square);
return (key * bishop_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]);
}
virtual constexpr U64 mask(Square square) const override {
return masks[to_underlying(square)];
}
virtual constexpr U64 mask_fly(Square square, U64 block) const override {
uint8_t square_i = to_underlying(square);
int tr = square_i / 8, tf = square_i % 8;
int len[4] = {std::min(7 - tf, 7 - tr), std::min(tf, 7 - tr), std::min(7 - tf, tr), std::min(tf, tr)};
return mask_slide(square, block, dir, len);
}
private:
static inline constexpr const direction_f dir[4] = {noEaOne, noWeOne, soEaOne, soWeOne};
// clang-format off
static inline constexpr const int relevant_bits[64] = {
6, 5, 5, 5, 5, 5, 5, 6,
5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 7, 7, 7, 7, 5, 5,
5, 5, 7, 9, 9, 7, 5, 5,
5, 5, 7, 9, 9, 7, 5, 5,
5, 5, 7, 7, 7, 7, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5,
6, 5, 5, 5, 5, 5, 5, 6,
};
// clang-format on
static inline constexpr const std::array<U64, 64> masks = []() constexpr -> std::array<U64, 64> {
std::array<U64, 64> masks;
for (const Square square : SquareIter()) {
uint8_t square_i = to_underlying(square);
int tr = square_i / 8, tf = square_i % 8;
int len[4] = {std::min(7 - tf, 7 - tr) - 1, std::min(tf, 7 - tr) - 1, std::min(7 - tf, tr) - 1,
std::min(tf, tr) - 1};
masks[square_i] = mask_slide(square, C64(0), dir, len);
}
return masks;
}();
};
inline constexpr const SliderRook slider_rook;
inline constexpr const SliderBishop slider_bishop;
class Attack {
public:
virtual constexpr U64 operator()(Square square, U64 occupancy) const = 0;
protected:
template <std::size_t size> using slider_attack_array = std::array<std::array<U64, size>, 64>;
static inline constexpr const auto slider_attacks =
[]<std::size_t size>(const Slider &slider) constexpr -> slider_attack_array<size> {
slider_attack_array<size> attacks;
for (const Square square : SquareIter()) {
uint8_t square_i = to_underlying(square);
U64 attack_mask = slider.mask(square);
uint8_t relevant_bits = bit_count(attack_mask);
U64 occupancy_indices = C64(1) << relevant_bits;
for (U64 idx = 0; idx < occupancy_indices; idx++) {
U64 occupancy = Slider::occupancy(idx, relevant_bits, attack_mask);
U32 magic_index = slider.hash(occupancy, square);
attacks[square_i][magic_index] = slider.mask_fly(square, occupancy);
}
}
return attacks;
};
};
class Rook : public Attack {
public:
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
occupancy &= slider_rook.mask(square);
occupancy = slider_rook.hash(occupancy, square);
return attacks[to_underlying(square)][occupancy];
}
private:
static inline constexpr const slider_attack_array<4096> attacks =
slider_attacks.operator()<4096>(slider_rook);
};
class Bishop : public Attack {
public:
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
occupancy &= slider_bishop.mask(square);
occupancy = slider_bishop.hash(occupancy, square);
return attacks[to_underlying(square)][occupancy];
}
private:
static inline constexpr const slider_attack_array<512> attacks =
slider_attacks.operator()<512>(slider_bishop);
};
class King : public Attack {
public:
constexpr King() {
}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
}
private:
static constexpr U64 mask(Square square) {
U64 bitboard = C64(0), attacks = C64(0);
bit_set(bitboard, to_underlying(square));
attacks |= westOne(bitboard) | eastOne(bitboard);
attacks |= soutOne(bitboard) | nortOne(bitboard);
attacks |= soutOne(bitboard) | nortOne(bitboard);
attacks |= soEaOne(bitboard) | noEaOne(bitboard);
attacks |= soWeOne(bitboard) | noWeOne(bitboard);
return attacks;
}
typedef std::array<U64, 64> attack_array;
const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (const Square square : SquareIter())
attacks[to_underlying(square)] = mask(square);
return attacks;
}();
};
class Knight : public Attack {
public:
constexpr Knight() {
}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
}
private:
static constexpr U64 mask(Square square) {
U64 bitboard = C64(0), attacks = C64(0), tmp;
bit_set(bitboard, to_underlying(square));
tmp = nortOne(nortOne(bitboard));
attacks |= westOne(tmp) | eastOne(tmp);
tmp = soutOne(soutOne(bitboard));
attacks |= westOne(tmp) | eastOne(tmp);
tmp = westOne(westOne(bitboard));
attacks |= soutOne(tmp) | nortOne(tmp);
tmp = eastOne(eastOne(bitboard));
attacks |= soutOne(tmp) | nortOne(tmp);
return attacks;
}
typedef std::array<U64, 64> attack_array;
const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (const Square square : SquareIter())
attacks[to_underlying(square)] = mask(square);
return attacks;
}();
};
class PawnW : public Attack {
public:
constexpr PawnW() {
}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
}
private:
static constexpr U64 mask(Square square) {
U64 bitboard = C64(0);
bit_set(bitboard, to_underlying(square));
return noWeOne(bitboard) | noEaOne(bitboard);
}
typedef std::array<U64, 64> attack_array;
const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (const Square square : SquareIter())
attacks[to_underlying(square)] = mask(square);
return attacks;
}();
};
class PawnB : public Attack {
public:
constexpr PawnB() {
}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
}
private:
static constexpr U64 mask(Square square) {
U64 bitboard = C64(0);
bit_set(bitboard, to_underlying(square));
return soWeOne(bitboard) | soEaOne(bitboard);
}
typedef std::array<U64, 64> attack_array;
const attack_array attacks = []() -> attack_array {
std::array<U64, 64> attacks;
for (const Square square : SquareIter())
attacks[to_underlying(square)] = mask(square);
return attacks;
}();
};
inline constexpr const Rook rook;
inline constexpr const Bishop bishop;
inline constexpr const King king;
inline constexpr const Knight knight;
inline constexpr const PawnW pawnW;
inline constexpr const PawnB pawnB;
class Queen : public Attack {
public:
constexpr Queen() {
}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return rook(square, occupancy) | bishop(square, occupancy);
}
};
inline constexpr const Queen queen;
} // namespace attack
#endif

diff --git a/ src/include/attacks.hpp b/ src/include/attacks.hpp

@@ -1,17 +0,0 @@
#ifndef STELLAR_ATTACKS_H
#define STELLAR_ATTACKS_H
#include "utils_cpp.hpp"
void attacks_init(void);
typedef U64 (*attack_get_f)(Square square, U64 occupancy);
U64 attacks_wpawn_get(Square square, U64 occupancy);
U64 attacks_bpawn_get(Square square, U64 occupancy);
U64 attacks_knight_get(Square square, U64 occupancy);
U64 attacks_king_get(Square square, U64 occupancy);
U64 attacks_bishop_get(Square square, U64 occupancy);
U64 attacks_rook_get(Square square, U64 occupancy);
U64 attacks_queen_get(Square square, U64 occupancy);
#endif

diff --git a/ src/include/board.hpp b/ src/include/board.hpp

@@ -17,7 +17,8 @@ class Board { BQ = 8 };
Board() {}
Board() {
}
Board(const std::string &fen); friend std::ostream &operator<<(std::ostream &os, const Board &board);

@@ -36,10 +37,8 @@ class Board { U64 get_bitboard_piece(piece::Type piece, Color color) const; U64 get_bitboard_piece(const piece::Piece &piece) const;
U64 get_bitboard_piece_attacks(piece::Type piece, Color color,
Square square) const;
U64 get_bitboard_piece_attacks(const piece::Piece &piece,
Square square) const;
U64 get_bitboard_piece_attacks(piece::Type piece, Color color, Square square) const;
U64 get_bitboard_piece_attacks(const piece::Piece &piece, Square square) const;
// exception if not found Color get_square_piece_color(Square square) const;

@@ -77,7 +76,6 @@ class Board { uint8_t castle = 0; };
const piece::Piece &board_square_piece(const Board *self, Square square,
Color side);
const piece::Piece &board_square_piece(const Board *self, Square square, Color side);
#endif

diff --git a/ src/include/magic.hpp b/ src/include/magic.hpp

@@ -0,0 +1,44 @@
#ifndef STELLAR_ATTACKS_MAGIC_H
#define STELLAR_ATTACKS_MAGIC_H
#include "utils_cpp.hpp"
static inline constexpr const U64 bishop_magic_numbers[64] = {
C64(0x40040844404084), C64(0x2004208a004208), C64(0x10190041080202), C64(0x108060845042010),
C64(0x581104180800210), C64(0x2112080446200010), C64(0x1080820820060210), C64(0x3c0808410220200),
C64(0x4050404440404), C64(0x21001420088), C64(0x24d0080801082102), C64(0x1020a0a020400),
C64(0x40308200402), C64(0x4011002100800), C64(0x401484104104005), C64(0x801010402020200),
C64(0x400210c3880100), C64(0x404022024108200), C64(0x810018200204102), C64(0x4002801a02003),
C64(0x85040820080400), C64(0x810102c808880400), C64(0xe900410884800), C64(0x8002020480840102),
C64(0x220200865090201), C64(0x2010100a02021202), C64(0x152048408022401), C64(0x20080002081110),
C64(0x4001001021004000), C64(0x800040400a011002), C64(0xe4004081011002), C64(0x1c004001012080),
C64(0x8004200962a00220), C64(0x8422100208500202), C64(0x2000402200300c08), C64(0x8646020080080080),
C64(0x80020a0200100808), C64(0x2010004880111000), C64(0x623000a080011400), C64(0x42008c0340209202),
C64(0x209188240001000), C64(0x400408a884001800), C64(0x110400a6080400), C64(0x1840060a44020800),
C64(0x90080104000041), C64(0x201011000808101), C64(0x1a2208080504f080), C64(0x8012020600211212),
C64(0x500861011240000), C64(0x180806108200800), C64(0x4000020e01040044), C64(0x300000261044000a),
C64(0x802241102020002), C64(0x20906061210001), C64(0x5a84841004010310), C64(0x4010801011c04),
C64(0xa010109502200), C64(0x4a02012000), C64(0x500201010098b028), C64(0x8040002811040900),
C64(0x28000010020204), C64(0x6000020202d0240), C64(0x8918844842082200), C64(0x4010011029020020),
};
static inline constexpr const U64 rook_magic_numbers[64] = {
C64(0x8a80104000800020), C64(0x140002000100040), C64(0x2801880a0017001), C64(0x100081001000420),
C64(0x200020010080420), C64(0x3001c0002010008), C64(0x8480008002000100), C64(0x2080088004402900),
C64(0x800098204000), C64(0x2024401000200040), C64(0x100802000801000), C64(0x120800800801000),
C64(0x208808088000400), C64(0x2802200800400), C64(0x2200800100020080), C64(0x801000060821100),
C64(0x80044006422000), C64(0x100808020004000), C64(0x12108a0010204200), C64(0x140848010000802),
C64(0x481828014002800), C64(0x8094004002004100), C64(0x4010040010010802), C64(0x20008806104),
C64(0x100400080208000), C64(0x2040002120081000), C64(0x21200680100081), C64(0x20100080080080),
C64(0x2000a00200410), C64(0x20080800400), C64(0x80088400100102), C64(0x80004600042881),
C64(0x4040008040800020), C64(0x440003000200801), C64(0x4200011004500), C64(0x188020010100100),
C64(0x14800401802800), C64(0x2080040080800200), C64(0x124080204001001), C64(0x200046502000484),
C64(0x480400080088020), C64(0x1000422010034000), C64(0x30200100110040), C64(0x100021010009),
C64(0x2002080100110004), C64(0x202008004008002), C64(0x20020004010100), C64(0x2048440040820001),
C64(0x101002200408200), C64(0x40802000401080), C64(0x4008142004410100), C64(0x2060820c0120200),
C64(0x1001004080100), C64(0x20c020080040080), C64(0x2935610830022400), C64(0x44440041009200),
C64(0x280001040802101), C64(0x2100190040002085), C64(0x80c0084100102001), C64(0x4024081001000421),
C64(0x20030a0244872), C64(0x12001008414402), C64(0x2006104900a0804), C64(0x1004081002402),
};
#endif

diff --git a/ src/include/moves.hpp b/ src/include/moves.hpp

@@ -24,9 +24,8 @@ struct MoveE { int score; };
Move move_encode(uint8_t src, uint8_t tgt, const piece::Piece *piece,
const piece::Piece *capture, const piece::Piece *promote,
bool dbl, bool enpassant, bool castle);
Move move_encode(uint8_t src, uint8_t tgt, const piece::Piece *piece, const piece::Piece *capture,
const piece::Piece *promote, bool dbl, bool enpassant, bool castle);
std::vector<MoveE> move_list_generate(const Board &board); int move_make(Move move, Board &board, int flag); void move_list_sort(std::vector<MoveE> &list);

diff --git a/ src/include/piece.hpp b/ src/include/piece.hpp

@@ -1,7 +1,7 @@ #ifndef STELLAR_PIECE_H #define STELLAR_PIECE_H
#include "attacks.hpp"
#include "attack.hpp"
#include "utils_cpp.hpp" #include <cctype>

@@ -21,73 +21,84 @@ typedef Iterator<Type, Type::PAWN, Type::KING> TypeIter; class Piece { public:
constexpr U64 operator()(Square square, U64 occupancy) const {
return attack(square, occupancy);
}
const Type type; const Color color; const char code; const char *symbol;
const attack_get_f attacks;
const uint8_t index; protected:
constexpr Piece(Type type, Color color, char code, const char *symbol,
attack_get_f attacks)
: type(type), color(color), code(code), symbol(symbol),
attacks(attacks), index(index_calc(color, type)) {}
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 ? attacks_wpawn_get : attacks_bpawn_get) {
: Piece(Type::PAWN, color, color == Color::WHITE ? 'P' : 'p', color == Color::WHITE ? "■ " : "■ ",
color == Color::WHITE ? *(attack::Attack *)&attack::pawnW
: *(attack::Attack *)&attack::pawnB) {
} }; class Knight : public Piece { public: constexpr Knight(Color color)
: Piece(Type::KNIGHT, color, color == Color::WHITE ? 'N' : 'n',
color == Color::WHITE ? "■ " : "■ ", attacks_knight_get) {}
: 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 ? "■ " : "■ ", attacks_bishop_get) {}
: 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 ? "■ " : "■ ", attacks_rook_get) {}
: 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 ? "■ " : "■ ", attacks_queen_get) {}
: Piece(Type::QUEEN, color, color == Color::WHITE ? 'Q' : 'q', color == Color::WHITE ? "■ " : "■ ",
attack::queen) {
}
}; class King : public Piece { public: constexpr King(Color color)
: Piece(Type::KING, color, color == Color::WHITE ? 'K' : 'k',
color == Color::WHITE ? "■ " : "■ ", attacks_king_get) {}
: Piece(Type::KING, color, color == Color::WHITE ? 'K' : 'k', color == Color::WHITE ? "■ " : "■ ",
attack::king) {
}
}; const constexpr Piece table[2][6] = {
{Pawn(Color::WHITE), Knight(Color::WHITE), Bishop(Color::WHITE),
Rook(Color::WHITE), Queen(Color::WHITE), King(Color::WHITE)},
{Pawn(Color::BLACK), Knight(Color::BLACK), Bishop(Color::BLACK),
Rook(Color::BLACK), Queen(Color::BLACK), King(Color::BLACK)},
{Pawn(Color::WHITE), Knight(Color::WHITE), Bishop(Color::WHITE), Rook(Color::WHITE), Queen(Color::WHITE),
King(Color::WHITE)},
{Pawn(Color::BLACK), Knight(Color::BLACK), Bishop(Color::BLACK), Rook(Color::BLACK), Queen(Color::BLACK),
King(Color::BLACK)},
}; constexpr const Piece &get(Type type, Color color) {

diff --git a/ src/include/utils_cpp.hpp b/ src/include/utils_cpp.hpp

@@ -5,8 +5,7 @@ #include <exception> #include <type_traits>
template <typename E>
constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept {
template <typename E> constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept {
return static_cast<typename std::underlying_type<E>::type>(e); }

@@ -15,20 +14,28 @@ template <typename C, C beginVal, C endVal> class Iterator { int val; public:
constexpr Iterator(const C &f) : val(static_cast<val_t>(f)) {}
constexpr Iterator() : val(static_cast<val_t>(beginVal)) {}
constexpr Iterator(const C &f) : val(static_cast<val_t>(f)) {
}
constexpr Iterator() : val(static_cast<val_t>(beginVal)) {
}
constexpr Iterator operator++() { ++val; return *this; }
constexpr C operator*() { return static_cast<C>(val); }
constexpr Iterator begin() { return *this; }
constexpr C operator*() {
return static_cast<C>(val);
}
constexpr Iterator begin() {
return *this;
}
constexpr Iterator end() { // static const Iterator endIter = ++Iterator(endVal); // return endIter; return ++Iterator(endVal); }
constexpr bool operator!=(const Iterator &i) { return val != i.val; }
constexpr bool operator!=(const Iterator &i) {
return val != i.val;
}
}; #define C64(constantU64) constantU64##ULL

@@ -77,11 +84,19 @@ inline const char *square_to_coordinates(Square square) { // clang-format on // useful bit functions
#define bit_get(bitboard, square) (((bitboard) >> (square)) & C64(1))
#define bit_set(bitboard, square) ((bitboard) |= C64(1) << (square))
#define bit_pop(bitboard, square) ((bitboard) &= ~(C64(1) << (square)))
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));
}
inline uint8_t bit_count(U64 bitboard) {
constexpr uint8_t bit_count(U64 bitboard) {
#if __has_builtin(__builtin_popcountll) return __builtin_popcountll(bitboard); #endif

@@ -92,7 +107,7 @@ inline uint8_t bit_count(U64 bitboard) { return count; }
inline uint8_t bit_lsb_index(U64 bitboard) {
constexpr uint8_t bit_lsb_index(U64 bitboard) {
#if __has_builtin(__builtin_ffsll) return __builtin_ffsll(bitboard) - 1; #endif

@@ -103,25 +118,40 @@ inline uint8_t bit_lsb_index(U64 bitboard) { #define bit_lsb_pop(bitboard) ((bitboard) &= (bitboard) & ((bitboard)-1))
#define bitboard_for_each_bit(var, bb) \
#define bitboard_for_each_bit(var, bb) \
for (var = bit_lsb_index(bb); bb; bit_lsb_pop(bb), var = bit_lsb_index(bb)) // board moving
const U64 universe = C64(0xffffffffffffffff);
const U64 notAFile = C64(0xfefefefefefefefe);
const U64 notHFile = C64(0x7f7f7f7f7f7f7f7f);
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 U64 soutOne(U64 b) { return b >> 8; }
inline U64 nortOne(U64 b) { return b << 8; }
inline U64 eastOne(U64 b) { return (b & notHFile) << 1; }
inline U64 westOne(U64 b) { return (b & notAFile) >> 1; }
inline U64 soEaOne(U64 b) { return (b & notHFile) >> 7; }
inline U64 soWeOne(U64 b) { return (b & notAFile) >> 9; }
inline U64 noEaOne(U64 b) { return (b & notHFile) << 9; }
inline U64 noWeOne(U64 b) { return (b & notAFile) << 7; }
#define start_position \
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 "
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

diff --git a/ src/moves/moves.cpp b/ src/moves/moves.cpp

@@ -4,12 +4,13 @@ #include <algorithm> #include <cstdio>
int move_cmp(Move a, Move b) { return *(uint32_t *)&a == *(uint32_t *)&b; }
int move_cmp(Move a, Move b) {
return *(uint32_t *)&a == *(uint32_t *)&b;
}
Move move_encode(uint8_t src, uint8_t tgt, const piece::Piece *piece,
const piece::Piece *capture, const piece::Piece *promote,
bool dbl, bool enpassant, bool castle) {
return (Move){
Move move_encode(uint8_t src, uint8_t tgt, const piece::Piece *piece, const piece::Piece *capture,
const piece::Piece *promote, bool dbl, bool enpassant, bool castle) {
return {
.source = src, .target = tgt, .piece = piece->index,

@@ -26,18 +27,15 @@ Move move_encode(uint8_t src, uint8_t tgt, const piece::Piece *piece, void move_print(Move move) { printf("%5s %5s %2c %2c %2c %4d %4d %4d %4d %4d\n", square_to_coordinates(static_cast<Square>(move_source(move))),
square_to_coordinates(static_cast<Square>(move_target(move))),
move_piece(move).code,
square_to_coordinates(static_cast<Square>(move_target(move))), move_piece(move).code,
move_capture(move) ? move_piece_capture(move).code : '.',
move_promote(move) ? move_piece_promote(move).code : '.',
move_double(move) ? 1 : 0, move_enpassant(move) ? 1 : 0,
move_castle(move) ? 1 : 0, move_capture(move) ? 1 : 0,
move_promote(move) ? move_piece_promote(move).code : '.', move_double(move) ? 1 : 0,
move_enpassant(move) ? 1 : 0, move_castle(move) ? 1 : 0, move_capture(move) ? 1 : 0,
move_promote(move) ? 1 : 0); } void move_list_sort(std::vector<MoveE> &list) {
std::sort(list.begin(), list.end(),
[](const MoveE &a, const MoveE &b) { return a.score < b.score; });
std::sort(list.begin(), list.end(), [](const MoveE &a, const MoveE &b) { return a.score < b.score; });
} void move_list_print(const std::vector<MoveE> &list) {

diff --git a/ src/moves/moves_generate.cpp b/ src/moves/moves_generate.cpp

@@ -3,36 +3,27 @@ #include "piece.hpp" #include "utils_cpp.hpp"
#define pawn_canPromote(color, source) \
((color == Color::WHITE && source >= Square::a7 && \
source <= Square::h7) || \
#define pawn_canPromote(color, source) \
((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) || \
#define pawn_onStart(color, source) \
((color == Color::BLACK && source >= Square::a7 && source <= Square::h7) || \
(color == Color::WHITE && source >= Square::a2 && source <= Square::h2))
#define pawn_promote(source, target, piece, capture) \
res.push_back( \
{move_encode(source, target, &piece, capture, \
&piece::get(piece::Type::KNIGHT, color), 0, 0, 0), \
0}); \
res.push_back( \
{move_encode(source, target, &piece, capture, \
&piece::get(piece::Type::BISHOP, color), 0, 0, 0), \
0}); \
res.push_back( \
{move_encode(source, target, &piece, capture, \
&piece::get(piece::Type::ROOK, color), 0, 0, 0), \
0}); \
res.push_back( \
{move_encode(source, target, &piece, capture, \
&piece::get(piece::Type::QUEEN, color), 0, 0, 0), \
0});
#define pawn_promote(source, target, piece, capture) \
res.push_back( \
{move_encode(source, target, &piece, capture, &piece::get(piece::Type::KNIGHT, color), 0, 0, 0), \
0}); \
res.push_back( \
{move_encode(source, target, &piece, capture, &piece::get(piece::Type::BISHOP, color), 0, 0, 0), \
0}); \
res.push_back( \
{move_encode(source, target, &piece, capture, &piece::get(piece::Type::ROOK, color), 0, 0, 0), 0}); \
res.push_back( \
{move_encode(source, target, &piece, capture, &piece::get(piece::Type::QUEEN, color), 0, 0, 0), 0});
std::vector<MoveE> move_list_generate(const Board &board) {
Move move;
uint8_t src_i, tgt_i; Color color = board.get_side();

@@ -54,43 +45,34 @@ std::vector<MoveE> move_list_generate(const Board &board) { if (pawn_canPromote(color, src)) { pawn_promote(src_i, tgt_i, piece, nullptr); } else {
res.push_back(
{move_encode(src_i, tgt_i, &piece, 0, 0, 0, 0, 0), 0});
res.push_back({move_encode(src_i, tgt_i, &piece, 0, 0, 0, 0, 0), 0});
// two ahead Square tgt = static_cast<Square>(tgt_i + add); if (pawn_onStart(color, src) && !board.is_square_occupied(tgt))
res.push_back(
{move_encode(src_i, tgt_i + add, &piece, 0, 0, 1, 0, 0),
0});
res.push_back({move_encode(src_i, tgt_i + add, &piece, 0, 0, 1, 0, 0), 0});
} } // capture
U64 attack = board.get_bitboard_piece_attacks(piece, src) &
board.get_bitboard_color(colorOther);
U64 attack = board.get_bitboard_piece_attacks(piece, src) & board.get_bitboard_color(colorOther);
bitboard_for_each_bit(tgt_i, attack) { Square tgt = static_cast<Square>(tgt_i); const piece::Piece *capture = board.get_square_piece(tgt); if (pawn_canPromote(color, src)) { pawn_promote(src_i, tgt_i, piece, capture); } else {
res.push_back(
{move_encode(src_i, tgt_i, &piece, capture, 0, 0, 0, 0),
0});
res.push_back({move_encode(src_i, tgt_i, &piece, capture, 0, 0, 0, 0), 0});
} } // en passant if (board.get_enpassant() != Square::no_sq &&
board.get_bitboard_piece_attacks(piece,
static_cast<Square>(src_i)) &
board.get_bitboard_piece_attacks(piece, static_cast<Square>(src_i)) &
(C64(1) << to_underlying(board.get_enpassant())))
res.push_back(
{move_encode(src_i, to_underlying(board.get_enpassant()),
&piece, &piece::get(piece::Type::PAWN, colorOther),
0, 0, 1, 0),
0});
res.push_back({move_encode(src_i, to_underlying(board.get_enpassant()), &piece,
&piece::get(piece::Type::PAWN, colorOther), 0, 0, 1, 0),
0});
} // All piece move

@@ -100,66 +82,53 @@ std::vector<MoveE> move_list_generate(const Board &board) { U64 bitboard = board.get_bitboard_piece(piece); bitboard_for_each_bit(src_i, bitboard) { Square src = static_cast<Square>(src_i);
U64 attack = board.get_bitboard_piece_attacks(piece, src) &
~board.get_bitboard_color(color);
U64 attack = board.get_bitboard_piece_attacks(piece, src) & ~board.get_bitboard_color(color);
bitboard_for_each_bit(tgt_i, attack) { Square tgt = static_cast<Square>(tgt_i); res.push_back(
{move_encode(src_i, tgt_i, &piece,
board.get_square_piece(tgt), 0, 0, 0, 0),
0});
{move_encode(src_i, tgt_i, &piece, board.get_square_piece(tgt), 0, 0, 0, 0), 0});
} } } // Castling if (color == Color::WHITE) {
static const piece::Piece &piece =
piece::get(piece::Type::KING, Color::WHITE);
static const piece::Piece &piece = piece::get(piece::Type::KING, Color::WHITE);
if (board.get_castle() & to_underlying(Board::Castle::WK)) {
if (!board.is_square_occupied(Square::f1) &&
!board.is_square_occupied(Square::g1) &&
if (!board.is_square_occupied(Square::f1) && !board.is_square_occupied(Square::g1) &&
!board.is_square_attacked(Square::e1, Color::BLACK) && !board.is_square_attacked(Square::f1, Color::BLACK))
res.push_back({move_encode(to_underlying(Square::e1),
to_underlying(Square::g1), &piece, 0,
0, 0, 0, 1),
0});
res.push_back(
{move_encode(to_underlying(Square::e1), to_underlying(Square::g1), &piece, 0, 0, 0, 0, 1),
0});
} if (board.get_castle() & to_underlying(Board::Castle::WQ)) {
if (!board.is_square_occupied(Square::d1) &&
!board.is_square_occupied(Square::c1) &&
if (!board.is_square_occupied(Square::d1) && !board.is_square_occupied(Square::c1) &&
!board.is_square_occupied(Square::b1) && !board.is_square_attacked(Square::e1, Color::BLACK) && !board.is_square_attacked(Square::d1, Color::BLACK))
res.push_back({move_encode(to_underlying(Square::e1),
to_underlying(Square::c1), &piece, 0,
0, 0, 0, 1),
0});
res.push_back(
{move_encode(to_underlying(Square::e1), to_underlying(Square::c1), &piece, 0, 0, 0, 0, 1),
0});
} } else {
static const piece::Piece &piece =
piece::get(piece::Type::KING, Color::BLACK);
static const piece::Piece &piece = piece::get(piece::Type::KING, Color::BLACK);
if (board.get_castle() & to_underlying(Board::Castle::BK)) {
if (!board.is_square_occupied(Square::f8) &&
!board.is_square_occupied(Square::g8) &&
if (!board.is_square_occupied(Square::f8) && !board.is_square_occupied(Square::g8) &&
!board.is_square_attacked(Square::e8, Color::WHITE) && !board.is_square_attacked(Square::f8, Color::WHITE))
res.push_back({move_encode(to_underlying(Square::e8),
to_underlying(Square::g8), &piece, 0,
0, 0, 0, 1),
0});
res.push_back(
{move_encode(to_underlying(Square::e8), to_underlying(Square::g8), &piece, 0, 0, 0, 0, 1),
0});
} if (board.get_castle() & to_underlying(Board::Castle::BQ)) {
if (!board.is_square_occupied(Square::d8) &&
!board.is_square_occupied(Square::c8) &&
if (!board.is_square_occupied(Square::d8) && !board.is_square_occupied(Square::c8) &&
!board.is_square_occupied(Square::b8) && !board.is_square_attacked(Square::e8, Color::WHITE) && !board.is_square_attacked(Square::d8, Color::WHITE))
res.push_back({move_encode(to_underlying(Square::e8),
to_underlying(Square::c8), &piece, 0,
0, 0, 0, 1),
0});
res.push_back(
{move_encode(to_underlying(Square::e8), to_underlying(Square::c8), &piece, 0, 0, 0, 0, 1),
0});
} }

diff --git a/ src/moves/moves_make.cpp b/ src/moves/moves_make.cpp

@@ -25,8 +25,7 @@ void _piece_set(Board &board, const piece::Piece &piece, Square square) { board.xor_hash(zobrist_key_piece(piece, square)); }
void _piece_move(Board &board, const piece::Piece &piece, Square source,
Square target) {
void _piece_move(Board &board, const piece::Piece &piece, Square source, Square target) {
_piece_remove(board, piece, source); _piece_set(board, piece, target); }

@@ -40,8 +39,7 @@ int move_make(Move move, Board &board, int flag) { const Color color = board.get_side(); const Square source = static_cast<Square>(move_source(move)); const Square target = static_cast<Square>(move_target(move));
const Square ntarget = static_cast<Square>(
move_target(move) + (color == Color::WHITE ? -8 : +8));
const Square ntarget = static_cast<Square>(move_target(move) + (color == Color::WHITE ? -8 : +8));
if (!move_capture(move)) { if (move_promote(move)) {

@@ -68,16 +66,11 @@ int move_make(Move move, Board &board, int flag) { board.set_enpassant(move_double(move) ? ntarget : Square::no_sq); if (move_castle(move)) {
static const piece::Piece &rook =
piece::get(piece::Type::ROOK, board.get_side());
if (target == Square::g1)
_piece_move(board, rook, Square::h1, Square::f1);
if (target == Square::c1)
_piece_move(board, rook, Square::a1, Square::d1);
if (target == Square::g8)
_piece_move(board, rook, Square::h8, Square::f8);
if (target == Square::c8)
_piece_move(board, rook, Square::a8, Square::d8);
static const piece::Piece &rook = piece::get(piece::Type::ROOK, board.get_side());
if (target == Square::g1) _piece_move(board, rook, Square::h1, Square::f1);
if (target == Square::c1) _piece_move(board, rook, Square::a1, Square::d1);
if (target == Square::g8) _piece_move(board, rook, Square::h8, Square::f8);
if (target == Square::c8) _piece_move(board, rook, Square::a8, Square::d8);
} board.xor_hash(zobrist_key_castle(board.get_castle()));

diff --git a/ src/perft/CMakeLists.txt b/ src/perft/CMakeLists.txt

@@ -6,10 +6,8 @@ if(WITH_FULL_COUNT) endif() target_link_libraries(perft
PRIVATE attacks
PRIVATE board PRIVATE moves
PRIVATE piece
PRIVATE random )

diff --git a/ src/perft/perft.cpp b/ src/perft/perft.cpp

@@ -4,7 +4,7 @@ #include <stdlib.h> #include <unistd.h>
#include "attacks.hpp"
#include "attack.hpp"
#include "board.hpp" #include "moves.hpp" #include "perft.hpp"

@@ -12,8 +12,7 @@ #include "zobrist.hpp" // FEN debug positions
#define tricky_position \
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1 "
#define tricky_position "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1 "
void perft_result_print(PerftResult res) { printf(" - Perft Results -\n\n");

@@ -48,17 +47,16 @@ void perft_result_add(PerftResult *base, PerftResult *add) { typedef std::vector<MoveE> MoveList;
void perft_driver(Board &board, MoveList *moveList, int depth,
PerftResult *result) {
moveList[depth] = move_list_generate(board);
void perft_driver(Board &board, int depth, PerftResult *result) {
MoveList moveList = move_list_generate(board);
Board copy;
for (const auto [move, _] : moveList[depth]) {
for (const auto [move, _] : moveList) {
copy = board; if (!move_make(move, copy, 0)) continue; if (depth != 1) {
perft_driver(copy, moveList, depth - 1, result);
perft_driver(copy, depth - 1, result);
} else { result->node++; #ifdef USE_FULL_COUNT

@@ -85,8 +83,6 @@ struct perf_shared { void *perft_thread(void *arg) { PerftResult result = {0}; perf_shared *shared = (perf_shared *)arg;
MoveList moveList[shared->depth + 1];
Board board = Board(shared->fen), copy; while (1) {

@@ -99,13 +95,14 @@ void *perft_thread(void *arg) { Move move = shared->list[shared->index++].move; pthread_mutex_unlock(&shared->mutex);
result = (PerftResult){0};
result = {0};
copy = board; if (!move_make(move, copy, 0)) continue;
// std::cout << copy << std::endl;
if (shared->depth != 1) {
perft_driver(copy, moveList, shared->depth - 1, &result);
perft_driver(copy, shared->depth - 1, &result);
} else { result.node++; #ifdef USE_FULL_COUNT

@@ -121,8 +118,8 @@ void *perft_thread(void *arg) { } PerftResult perft_test(const char *fen, int depth, int thread_num) {
pthread_t threads[thread_num];
perf_shared shared = (perf_shared){
pthread_t *threads = new pthread_t(thread_num);
perf_shared shared = {
.list = move_list_generate(Board(fen)), .depth = depth, .fen = fen,

@@ -135,13 +132,14 @@ PerftResult perft_test(const char *fen, int depth, int thread_num) { for (int i = 0; i < thread_num; i++) pthread_join(threads[i], NULL);
delete threads;
return shared.result; } int main(int argc, char *argv[]) { int c, depth = 1, thread_num = 1;
std::string s(tricky_position);
std::string s(start_position);
const char *fen = s.data(); while ((c = getopt(argc, argv, "t:f:d:")) != -1) { switch (c) {

@@ -161,7 +159,6 @@ int main(int argc, char *argv[]) { } }
attacks_init();
zobrist_init(); PerftResult res = perft_test(fen, depth, thread_num);

diff --git a/ src/piece/CMakeLists.txt b/ src/piece/CMakeLists.txt

@@ -1,7 +0,0 @@
add_library(piece OBJECT
piece.cpp
)
target_include_directories(piece
PUBLIC "${PROJECT_SOURCE_DIR}/src/include"
)

diff --git a/ src/piece/piece.cpp b/ src/piece/piece.cpp

@@ -1,1 +0,0 @@
#include "piece.hpp"

diff --git a/ src/utils/random.cpp b/ src/utils/random.cpp

@@ -2,7 +2,9 @@ U32 state = C32(1804289383);
void random_state_reset() { state = C32(1804289383); }
void random_state_reset() {
state = C32(1804289383);
}
U32 random_get_U32() { U32 number = state;