stellar

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 21:02:31 +0200

Attack generation at compile time with constexpr

Diffstat:
M.clang-format | 4++--
MCMakeLists.txt | 8+++++++-
Dsrc/attacks/CMakeLists.txt | 35-----------------------------------
Dsrc/attacks/attacks.cpp | 99-------------------------------------------------------------------------------
Dsrc/attacks/internal.cpp | 148-------------------------------------------------------------------------------
Dsrc/attacks/internal.hpp | 30------------------------------
Dsrc/attacks/magic.cpp | 51---------------------------------------------------
Dsrc/attacks/magic.hpp | 9---------
Dsrc/attacks/magic_generate.cpp | 69---------------------------------------------------------------------
Msrc/board/board.cpp | 55+++++++++++++++++++++++++++++--------------------------
Msrc/board/zobrist.cpp | 12+++++++++---
Msrc/engine/CMakeLists.txt | 2--
Msrc/engine/engine.cpp | 68++++++++++++++++++++++++++++----------------------------------------
Msrc/engine/transposition.cpp | 12++++--------
Msrc/engine/transposition.hpp | 15++++++++-------
Asrc/include/attack.hpp | 337+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/include/attacks.hpp | 17-----------------
Msrc/include/board.hpp | 12+++++-------
Asrc/include/magic.hpp | 44++++++++++++++++++++++++++++++++++++++++++++
Msrc/include/moves.hpp | 5++---
Msrc/include/piece.hpp | 57++++++++++++++++++++++++++++++++++-----------------------
Msrc/include/utils_cpp.hpp | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/moves/moves.cpp | 22++++++++++------------
Msrc/moves/moves_generate.cpp | 117+++++++++++++++++++++++++++++--------------------------------------------------
Msrc/moves/moves_make.cpp | 21+++++++--------------
Msrc/perft/CMakeLists.txt | 2--
Msrc/perft/perft.cpp | 29+++++++++++++----------------
Dsrc/piece/CMakeLists.txt | 7-------
Dsrc/piece/piece.cpp | 1-
Msrc/utils/random.cpp | 4+++-
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 +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;