stellarUCI 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 ©, 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;