stellar

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

commit 12abec85ea91fce6605ed4f197efa5aa75d9ca88
parent ff9e899cbc8545891ed223f9d75cc0546621ac50
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Wed,  9 Aug 2023 20:25:44 +0200

Rewrite attack, piece and board

Diffstat:
MCMakeLists.txt | 2+-
Msrc/attacks/CMakeLists.txt | 14+++++++-------
Dsrc/attacks/attacks.c | 93-------------------------------------------------------------------------------
Asrc/attacks/attacks.cpp | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/attacks/internal.c | 141-------------------------------------------------------------------------------
Asrc/attacks/internal.cpp | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/attacks/internal.h | 5++---
Asrc/attacks/internal.hpp | 30++++++++++++++++++++++++++++++
Dsrc/attacks/magic.c | 51---------------------------------------------------
Asrc/attacks/magic.cpp | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/attacks/magic.h | 9---------
Asrc/attacks/magic.hpp | 9+++++++++
Rsrc/attacks/magic_generate.c -> src/attacks/magic_generate.cpp | 0
Dsrc/board/board.c | 210-------------------------------------------------------------------------------
Asrc/board/board.cpp | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/board/zobrist.c | 73-------------------------------------------------------------------------
Asrc/board/zobrist.cpp | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/include/attacks.h | 16----------------
Asrc/include/attacks.hpp | 17+++++++++++++++++
Dsrc/include/board.h | 59-----------------------------------------------------------
Asrc/include/board.hpp | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/include/piece.h | 36------------------------------------
Asrc/include/piece.hpp | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/include/random.h | 2+-
Asrc/include/random.hpp | 10++++++++++
Msrc/include/utils.h | 6+++---
Asrc/include/utils_cpp.hpp | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/include/zobrist.h | 14--------------
Asrc/include/zobrist.hpp | 14++++++++++++++
Msrc/perft/CMakeLists.txt | 2+-
Msrc/piece/CMakeLists.txt | 2+-
Dsrc/piece/piece.c | 51---------------------------------------------------
Asrc/piece/piece.cpp | 6++++++
Msrc/utils/utils.c | 2+-
34 files changed, 1005 insertions(+), 771 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -6,7 +6,7 @@ project( VERSION 0.0.18 DESCRIPTION "Chess engine written in C" HOMEPAGE_URL https://git.dimitrijedobrota.com/stellar.git - LANGUAGES C + LANGUAGES C CXX ) set(CMAKE_C_STANDARD 99) diff --git a/src/attacks/CMakeLists.txt b/src/attacks/CMakeLists.txt @@ -1,7 +1,7 @@ add_library(attacks OBJECT - attacks.c - internal.c - magic.c + attacks.cpp + internal.cpp + magic.cpp ) target_include_directories(attacks @@ -14,14 +14,14 @@ project( MagicGenerator VERSION 1.0.0 DESCRIPTION "Generator of magic numbers for bishup and rook attacks" - LANGUAGES C + LANGUAGES CXX ) add_executable(magic - internal.c - magic.c - magic_generate.c + internal.cpp + magic.cpp + magic_generate.cpp ) target_link_libraries(magic diff --git a/src/attacks/attacks.c b/src/attacks/attacks.c @@ -1,93 +0,0 @@ -#include "attacks.h" -#include "internal.h" -#include "magic.h" - -#define UNUSED(x) (void)(x) - -// Magic constants - -U64 attacks_wpawn_get(Square square, U64 occupancy) { - UNUSED(occupancy); - return pawn_attacks[WHITE][square]; -} - -U64 attacks_bpawn_get(Square square, U64 occupancy) { - UNUSED(occupancy); - return pawn_attacks[BLACK][square]; -} - -U64 attacks_knight_get(Square square, U64 occupancy) { - UNUSED(occupancy); - return knight_attacks[square]; -} - -U64 attakcs_king_get(Square square, U64 occupancy) { - UNUSED(occupancy); - return king_attacks[square]; -} - -U64 attacks_bishop_get(Square square, U64 occupancy) { - occupancy &= bishop_masks[square]; - occupancy = hash(occupancy, bishop_magic_numbers[square], - bishop_relevant_bits[square]); - return bishop_attacks[square][occupancy]; -} - -U64 attacks_rook_get(Square square, U64 occupancy) { - occupancy &= rook_masks[square]; - occupancy = - hash(occupancy, rook_magic_numbers[square], rook_relevant_bits[square]); - return rook_attacks[square][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 = 0; square < 64; square++) { - pawn_attacks[WHITE][square] = pawn_mask(WHITE, square); - pawn_attacks[BLACK][square] = pawn_mask(BLACK, square); - knight_attacks[square] = knight_mask(square); - king_attacks[square] = king_mask(square); - } -} - -void attacks_init_sliders(int bishop) { - for (Square square = 0; square < 64; square++) { - U64 attack_mask; - - if (bishop) { - bishop_masks[square] = bishop_mask(square); - attack_mask = bishop_masks[square]; - } else { - rook_masks[square] = rook_mask(square); - attack_mask = rook_masks[square]; - } - - 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]) >> - (64 - bishop_relevant_bits[square]); - bishop_attacks[square][magic_index] = - bishop_on_the_fly(square, occupancy); - } else { - int magic_index = hash(occupancy, rook_magic_numbers[square], - rook_relevant_bits[square]); - rook_attacks[square][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/attacks.cpp b/src/attacks/attacks.cpp @@ -0,0 +1,99 @@ +#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; + 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; + 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.c b/src/attacks/internal.c @@ -1,141 +0,0 @@ -#include "internal.h" - -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++) { - Square 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, 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(int side, Square square) { - U64 bitboard = C64(0); - - bit_set(bitboard, square); - if (side == 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, 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, 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) { - int tr = square / 8, tf = square % 8; - int len[4] = {MIN(7 - tf, 7 - tr) - 1, MIN(tf, 7 - tr) - 1, - MIN(7 - tf, tr) - 1, MIN(tf, tr) - 1}; - return attacks_slide_mask(square, C64(0), attacks_bishop_direction, len); -} - -U64 rook_mask(Square square) { - int tr = square / 8, tf = square % 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) { - int tr = square / 8, tf = square % 8; - int len[4] = {MIN(7 - tf, 7 - tr), MIN(tf, 7 - tr), MIN(7 - tf, tr), - MIN(tf, tr)}; - - return attacks_slide_mask(square, block, attacks_bishop_direction, len); -} - -U64 rook_on_the_fly(Square square, U64 block) { - int tr = square / 8, tf = square % 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.cpp b/src/attacks/internal.cpp @@ -0,0 +1,148 @@ +#include "internal.h" +#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.h b/src/attacks/internal.h @@ -1,8 +1,7 @@ #ifndef STELLAR_ATTAKCS_INTERNAL_H #define STELLAR_ATTAKCS_INTERNAL_H -#include "piece.h" // BLACK, WHITE -#include "utils.h" +#include "utils_cpp.hpp" extern U64 king_attacks[64]; // king attack table [square] extern U64 knight_attacks[64]; // knight attack table [square] @@ -24,7 +23,7 @@ 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(int side, Square square); +U64 pawn_mask(Color side, Square square); U64 rook_mask(Square square); U64 rook_on_the_fly(Square square, U64 block); diff --git a/src/attacks/internal.hpp b/src/attacks/internal.hpp @@ -0,0 +1,30 @@ +#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.c b/src/attacks/magic.c @@ -1,51 +0,0 @@ -#include "magic.h" - -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.cpp b/src/attacks/magic.cpp @@ -0,0 +1,51 @@ +#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.h b/src/attacks/magic.h @@ -1,9 +0,0 @@ -#ifndef STELLAR_ATTACKS_MAGIC_H -#define STELLAR_ATTACKS_MAGIC_H - -#include "utils.h" - -extern const U64 bishop_magic_numbers[64]; -extern const U64 rook_magic_numbers[64]; - -#endif diff --git a/src/attacks/magic.hpp b/src/attacks/magic.hpp @@ -0,0 +1,9 @@ +#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.c b/src/attacks/magic_generate.cpp diff --git a/src/board/board.c b/src/board/board.c @@ -1,210 +0,0 @@ -#include <ctype.h> -#include <stdio.h> -#include <string.h> - -#include <cul/assert.h> -#include <cul/mem.h> - -#include "board.h" -#include "utils.h" -#include "zobrist.h" - -Board *board_new(void) { - Board *p; - NEW0(p); - return p; -} - -void board_free(Board **p) { FREE(*p); } - -void board_copy(const Board *self, Board *dest) { *dest = *self; } - -Square board_enpassant(const Board *self) { return self->enpassant; } -eCastle board_castle(const Board *self) { return self->castle; } -eColor board_side(const Board *self) { return self->side; } -U64 board_color(const Board *self, eColor color) { return self->color[color]; } -U64 board_piece(const Board *self, ePiece piece) { return self->piece[piece]; } -U64 board_hash(const Board *self) { return self->hash; } - -U64 board_occupancy(const Board *self) { - return self->color[WHITE] | self->color[BLACK]; -} - -U64 board_pieceSet(const Board *self, Piece piece) { - return self->piece[piece_piece(piece)] & self->color[piece_color(piece)]; -} - -void board_color_pop(Board *self, eColor color, Square target) { - bit_pop(self->color[color], target); -} - -void board_color_set(Board *self, eColor color, Square target) { - bit_set(self->color[color], target); -} - -U64 board_color_get(const Board *self, eColor color, Square target) { - return bit_get(self->color[color], target); -} - -int board_piece_get(const Board *self, Square square) { - for (int i = 0; i < 6; i++) - if (bit_get(self->piece[i], square)) return i; - return -1; -} - -void board_piece_pop(Board *self, Piece piece, Square square) { - bit_pop(self->piece[piece_piece(piece)], square); - bit_pop(self->color[piece_color(piece)], square); -} - -void board_piece_set(Board *self, Piece piece, Square square) { - bit_set(self->piece[piece_piece(piece)], square); - bit_set(self->color[piece_color(piece)], square); -} - -U64 board_piece_attacks(const Board *self, Piece piece, Square src) { - return piece_attacks(piece)(src, board_occupancy(self)); -} - -int board_isCheck(const Board *self) { - U64 king = self->piece[KING] & self->color[self->side]; - return board_square_isAttack(self, bit_lsb_index(king), !self->side); -} -int board_square_isOccupied(const Board *self, Square square) { - return bit_get(board_occupancy(self), square); -} - -int board_square_isAttack(const Board *self, Square square, eColor side) { - U64 occupancy = self->color[WHITE] | self->color[BLACK]; - - for (int i = KING; i >= PAWN; i--) { - if (piece_attacks(piece_get(i, !side))(square, occupancy) & - self->piece[i] & self->color[side]) - return 1; - } - - return 0; -} - -void board_side_switch(Board *self) { - self->side = !self->side; - self->hash ^= zobrist_key_side(); -} - -void board_enpassant_set(Board *self, Square target) { - if (self->enpassant != no_sq) - self->hash ^= zobrist_key_enpassant(self->enpassant); - - if (target != no_sq) self->hash ^= zobrist_key_enpassant(target); - self->enpassant = target; -} - -void board_castle_and(Board *self, int exp) { self->castle &= exp; } - -Piece board_square_piece(const Board *self, Square square, eColor color) { - for (ePiece i = 0; i < 6; i++) - if (bit_get(self->piece[i], square)) return piece_get(i, color); - return NULL; -} - -Board *board_from_FEN(Board *board, const char *fen) { - if (!board) NEW(board); - - memset(board, 0, sizeof(*board)); - - board->side = -1; - board->enpassant = no_sq; - board->castle = 0; - - int file = 0, rank = 7; - for (Piece piece; *fen != ' '; fen++) { - Square square = rank * 8 + file; - if (isalpha(*fen)) { - if (!(piece = piece_from_code(*fen))) assert(0); - bit_set(board->color[piece_color(piece)], square); - bit_set(board->piece[piece_piece(piece)], square); - file++; - } else if (isdigit(*fen)) { - file += *fen - '0'; - } else if (*fen == '/') { - file = 0; - rank--; - } else { - assert(0); - } - } - - fen++; - if (*fen == 'w') - board->side = WHITE; - else if (*fen == 'b') - board->side = BLACK; - else - assert(0); - - for (fen += 2; *fen != ' '; fen++) { - switch (*fen) { - case 'K': - board->castle |= WK; - break; - case 'Q': - board->castle |= WQ; - break; - case 'k': - board->castle |= BK; - break; - case 'q': - board->castle |= BQ; - break; - case '-': - break; - default: - assert(0); - } - } - - fen++; - if (*fen != '-') { - board->enpassant = coordinates_to_square(fen); - } - - board->hash = zobrist_hash(board); - return board; -} - -void board_print(const Board *self) { - for (int rank = 0; rank < 8; rank++) { - for (int file = 0; file < 8; file++) { - Square square = (7 - rank) * 8 + file; - Piece piece = NULL; - - int color = -1; - if (bit_get(self->color[WHITE], square)) - color = WHITE; - else if (bit_get(self->color[BLACK], square)) - color = BLACK; - - if (color != -1) { - for (int piece_index = 0; piece_index < 6; piece_index++) { - if (bit_get(self->piece[piece_index], square)) { - piece = piece_get(piece_index, color); - break; - } - } - } - - if (!file) printf(" %d ", 8 - rank); - - printf("%c ", (piece) ? piece_asci(piece) : '.'); - } - printf("\n"); - } - printf(" A B C D E F G H\n"); - printf(" Side: %s\n", (self->side == WHITE) ? "white" : "black"); - printf("Enpassant: %s\n", square_to_coordinates[self->enpassant]); - printf(" Castling: %c%c%c%c\n", (self->castle & WK) ? 'K' : '-', - (self->castle & WQ) ? 'Q' : '-', (self->castle & BK) ? 'k' : '-', - (self->castle & BQ) ? 'q' : '-'); - printf(" Hash: %llx\n", self->hash); - printf("\n"); -} diff --git a/src/board/board.cpp b/src/board/board.cpp @@ -0,0 +1,210 @@ +#include <ctype.h> +#include <stdio.h> +#include <string.h> + +#include "board.hpp" +#include "piece.hpp" +#include "utils_cpp.hpp" +#include "zobrist.hpp" + +/* 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; } + +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)]; +} + +U64 Board::get_bitboard_piece(piece::Type piece) const { + return pieces[to_underlying(piece)]; +} + +U64 Board::get_bitboard_piece(const piece::Piece &piece) const { + return get_bitboard_piece(piece.type, piece.color); +} + +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 { + 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()); +} + +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; + 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; + } + throw std::exception(); +} + +const piece::Piece &Board::get_square_piece(Square square) const { + return piece::get(get_square_piece_type(square), + get_square_piece_color(square)); +} + +/* Setters */ + +void Board::and_castle(Castle right) { castle &= to_underlying(right); } + +void Board::switch_side(void) { + side = (side == Color::BLACK) ? Color::WHITE : Color::BLACK; + hash ^= zobrist_key_side(); +} + +void Board::set_enpassant(Square target) { + if (enpassant != Square::no_sq) hash ^= zobrist_key_enpassant(enpassant); + + if (target != Square::no_sq) hash ^= zobrist_key_enpassant(target); + enpassant = target; +} + +void Board::pop_bitboard_color(Color color, Square square) { + bit_pop(colors[to_underlying(color)], to_underlying(square)); +} + +void Board::set_bitboard_color(Color color, Square square) { + bit_set(colors[to_underlying(color)], to_underlying(square)); +} + +void Board::pop_bitboard_piece(const piece::Piece &piece, Square square) { + bit_pop(pieces[to_underlying(piece.type)], to_underlying(square)); +} + +void Board::set_bitboard_piece(const piece::Piece &piece, Square square) { + bit_set(pieces[to_underlying(piece.type)], to_underlying(square)); +} + +void Board::pop_piece(const piece::Piece &piece, Square square) { + pop_bitboard_color(piece.color, square); + pop_bitboard_piece(piece, square); +} + +void Board::set_piece(const piece::Piece &piece, Square square) { + set_bitboard_color(piece.color, square); + set_bitboard_piece(piece, square); +} + +/* Queries */ + +bool Board::is_square_occupied(Square square) const { + return bit_get(get_bitboard_occupancy(), to_underlying(square)); +} + +bool Board::is_square_attacked(Square square, Color side) const { + // side switch because of pawns + Color side_other = (side == Color::BLACK) ? Color::WHITE : Color::BLACK; + + for (piece::Type type : piece::TypeIter()) { + const piece::Piece &piece = piece::get(type, side_other); + if (get_bitboard_piece_attacks(piece, square) & + get_bitboard_piece(piece)) + return 1; + } + + return 0; +} + +bool Board::is_check(void) const { + U64 king = + pieces[to_underlying(piece::Type::KING)] & colors[to_underlying(side)]; + Square square = static_cast<Square>(bit_lsb_index(king)); + return is_square_attacked(square, side); +} + +Board::Board(const std::string &fen) { + *this = {0}; + + side = Color::WHITE; + enpassant = Square::no_sq; + castle = 0; + + int file = 0, rank = 7, i; + for (i = 0; i < fen.size(); i++) { + if (isalpha(fen[i])) { + set_piece(piece::get_from_code(fen[i]), + static_cast<Square>(rank * 8 + file)); + file++; + } else if (isdigit(fen[i])) { + file += fen[i] - '0'; + } else if (fen[i] == '/') { + file = 0; + rank--; + } else { + throw std::exception(); + } + } + + i++; + if (fen[i] == 'w') + side = Color::WHITE; + else if (fen[i] == 'b') + side = Color::BLACK; + else + throw std::exception(); + + for (i += 2; fen[i] != ' '; i++) { + if (fen[i] == 'K') + castle |= to_underlying(Castle::WK); + else if (fen[i] == 'Q') + castle |= to_underlying(Castle::WQ); + else if (fen[i] == 'k') + castle |= to_underlying(Castle::BK); + else if (fen[i] == 'q') + castle |= to_underlying(Castle::BQ); + else + throw std::exception(); + } + + if (fen[++i] != '-') enpassant = square_from_coordinates(fen.data() + i); + hash = zobrist_hash(*this); +} + +std::ostream &operator<<(std::ostream &os, const Board &board) { + for (int rank = 0; rank < 8; rank++) { + for (int file = 0; file < 8; file++) { + try { + Square square = static_cast<Square>((7 - rank) * 8 + file); + os << board.get_square_piece(square).code; + } catch (std::exception e) { + os << ". "; + } + } + printf("\n"); + } + os << " A B C D E F G H\n"; + os << " Side: "; + os << ((board.side == Color::WHITE) ? "white" : "black") << "\n"; + os << "Enpassant: " << square_to_coordinates(board.enpassant) << "\n"; + os << " Castle:"; + os << ((board.castle & to_underlying(Board::Castle::WK)) ? 'K' : '-'); + os << ((board.castle & to_underlying(Board::Castle::WQ)) ? 'Q' : '-'); + os << ((board.castle & to_underlying(Board::Castle::BK)) ? 'k' : '-'); + os << ((board.castle & to_underlying(Board::Castle::BQ)) ? 'q' : '-'); + os << "\n Hash:" << board.hash << "\n\n"; + + return os; +} diff --git a/src/board/zobrist.c b/src/board/zobrist.c @@ -1,73 +0,0 @@ -#include "zobrist.h" -#include "board.h" -#include "piece.h" -#include "random.h" -#include "utils.h" - -U64 castle_keys[16]; -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_enpassant(Square square) { return enpassant_keys[square]; } -U64 zobrist_key_piece(Piece piece, Square square) { - return piece_keys[piece_index(piece)][square]; -} - -void init_hash_keys() { - random_state_reset(); - - for (int piece = PAWN; piece <= KING; piece++) { - int piece_index_white = piece_index(piece_get(piece, WHITE)); - int piece_index_black = piece_index(piece_get(piece, BLACK)); - for (int square = 0; square < 64; square++) { - piece_keys[piece_index_white][square] = random_get_U64(); - piece_keys[piece_index_black][square] = random_get_U64(); - } - } - - for (int square = 0; square < 64; square++) { - enpassant_keys[square] = random_get_U64(); - } - - for (int castle = 0; castle < 16; castle++) { - castle_keys[castle] = random_get_U64(); - } - - side_key = random_get_U64(); -} - -void zobrist_init(void) { init_hash_keys(); } - -U64 zobrist_hash(const Board *board) { - U64 key_final = C64(0); - Square square; - - for (int piece = PAWN; piece <= KING; piece++) { - Piece piece_white = piece_get(piece, WHITE); - U64 bitboard_white = board_pieceSet(board, piece_white); - int piece_white_index = piece_index(piece_white); - - bitboard_for_each_bit(square, bitboard_white) { - key_final ^= piece_keys[piece_white_index][square]; - } - - Piece piece_black = piece_get(piece, BLACK); - U64 bitboard_black = board_pieceSet(board, piece_black); - int piece_black_index = piece_index(piece_black); - - bitboard_for_each_bit(square, bitboard_black) { - key_final ^= piece_keys[piece_black_index][square]; - } - } - - key_final ^= castle_keys[board_castle(board)]; - - if (board_side(board)) key_final ^= side_key; - if (board_enpassant(board) != no_sq) - key_final ^= enpassant_keys[board_enpassant(board)]; - - return key_final; -} diff --git a/src/board/zobrist.cpp b/src/board/zobrist.cpp @@ -0,0 +1,74 @@ +#include "zobrist.hpp" +#include "piece.hpp" +#include "random.hpp" +#include "utils_cpp.hpp" + +U64 castle_keys[16]; +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_enpassant(Square square) { + return enpassant_keys[to_underlying(square)]; +} +U64 zobrist_key_piece(const piece::Piece &piece, Square square) { + return piece_keys[piece.index][to_underlying(square)]; +} + +void init_hash_keys() { + random_state_reset(); + + for (piece::Type type : piece::TypeIter()) { + int piece_index_white = piece::get(type, Color::WHITE).index; + int piece_index_black = piece::get(type, Color::BLACK).index; + for (int square = 0; square < 64; square++) { + piece_keys[piece_index_white][square] = random_get_U64(); + piece_keys[piece_index_black][square] = random_get_U64(); + } + } + + for (int square = 0; square < 64; square++) { + enpassant_keys[square] = random_get_U64(); + } + + for (int castle = 0; castle < 16; castle++) { + castle_keys[castle] = random_get_U64(); + } + + side_key = random_get_U64(); +} + +void zobrist_init(void) { init_hash_keys(); } + +U64 zobrist_hash(const Board &board) { + U64 key_final = C64(0); + uint8_t square; + + for (piece::Type type : piece::TypeIter()) { + const piece::Piece &piece_white = piece::get(type, Color::WHITE); + int piece_white_index = piece_white.index; + U64 bitboard_white = board.get_bitboard_piece(piece_white); + + bitboard_for_each_bit(square, bitboard_white) { + key_final ^= piece_keys[piece_white_index][square]; + } + + const piece::Piece &piece_black = piece::get(type, Color::BLACK); + int piece_black_index = piece_white.index; + U64 bitboard_black = board.get_bitboard_piece(piece_black); + + bitboard_for_each_bit(square, bitboard_black) { + key_final ^= piece_keys[piece_black_index][square]; + } + } + + key_final ^= castle_keys[board.get_castle()]; + + if (board.get_side() == Color::BLACK) key_final ^= side_key; + if (board.get_enpassant() != Square::no_sq) + key_final ^= enpassant_keys[to_underlying(board.get_enpassant())]; + + return key_final; +} diff --git a/src/include/attacks.h b/src/include/attacks.h @@ -1,16 +0,0 @@ -#ifndef STELLAR_ATTACKS_H -#define STELLAR_ATTACKS_H - -#include "utils.h" - -void attacks_init(void); - -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 attakcs_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/attacks.hpp b/src/include/attacks.hpp @@ -0,0 +1,17 @@ +#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.h b/src/include/board.h @@ -1,59 +0,0 @@ -#ifndef STELLAR_BOARD_H -#define STELLAR_BOARD_H - -#include "piece.h" - -enum enumCastle { - WK = 1, - WQ = 2, - BK = 4, - BQ = 8 -}; -typedef enum enumCastle eCastle; - -typedef struct Board Board; -struct Board { - U64 color[2]; - U64 piece[6]; - U64 hash; - eColor side; - Square enpassant; - eCastle castle; -}; - -Board *board_new(void); -void board_free(Board **p); -void board_copy(const Board *self, Board *dest); - -U64 board_color(const Board *self, eColor color); -U64 board_occupancy(const Board *self); -U64 board_piece(const Board *self, ePiece piece); -eCastle board_castle(const Board *self); -eColor board_side(const Board *self); -Square board_enpassant(const Board *self); -U64 board_hash(const Board *self); - -void board_side_switch(Board *self); -void board_enpassant_set(Board *self, Square target); -void board_castle_and(Board *self, int exp); - -U64 board_pieceSet(const Board *self, Piece piece); -U64 board_piece_attacks(const Board *self, Piece piece, Square src); - -void board_piece_pop(Board *self, Piece Piece, Square square); -void board_piece_set(Board *self, Piece Piece, Square square); -int board_piece_get(const Board *self, Square square); - -U64 board_color_get(const Board *self, eColor color, Square target); -void board_color_pop(Board *self, eColor color, Square target); -void board_color_set(Board *self, eColor color, Square target); - -Piece board_square_piece(const Board *self, Square square, eColor side); -int board_square_isAttack(const Board *self, Square square, eColor side); -int board_square_isOccupied(const Board *self, Square square); - -Board *board_from_FEN(Board *board, const char *fen); -int board_isCheck(const Board *self); -void board_print(const Board *self); - -#endif diff --git a/src/include/board.hpp b/src/include/board.hpp @@ -0,0 +1,84 @@ +#ifndef STELLAR_BOARD_H +#define STELLAR_BOARD_H + +#include "piece.hpp" +#include "utils_cpp.hpp" + +#include <iostream> +#include <string> + +typedef struct Board Board; +class Board { + public: + enum class Castle : uint8_t { + WK = 1, + WQ = 2, + BK = 4, + BQ = 8 + }; + + Board() {} + Board(const std::string &fen); + + friend std::ostream &operator<<(std::ostream &os, const Board &board); + + /* Getters */ + + U64 get_hash(void) const; + Color get_side(void) const; + uint8_t get_castle(void) const; + Square get_enpassant(void) const; + + U64 get_bitboard_color(Color side) const; + U64 get_bitboard_occupancy(void) const; + + U64 get_bitboard_piece(piece::Type piece) const; + 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; + + // exception if not found + Color get_square_piece_color(Square square) const; + piece::Type get_square_piece_type(Square square) const; + const piece::Piece &get_square_piece(Square square) const; + + /* Setters */ + + void switch_side(void); + void and_castle(Castle right); + void set_enpassant(Square target); + + void pop_bitboard_color(Color color, Square square); + void set_bitboard_color(Color color, Square square); + + void pop_bitboard_piece(const piece::Piece &piece, Square square); + void set_bitboard_piece(const piece::Piece &piece, Square square); + + void pop_piece(const piece::Piece &piece, Square square); + void set_piece(const piece::Piece &piece, Square square); + + /* Queries */ + + bool is_square_attacked(Square Square, Color side) const; + bool is_square_occupied(Square Square) const; + bool is_check(void) const; + + private: + U64 colors[2]; + U64 pieces[6]; + U64 hash; + Color side; + Square enpassant; + uint8_t castle; +}; + +const piece::Piece &board_square_piece(const Board *self, Square square, + Color side); + +void board_print(const Board *self); + +#endif diff --git a/src/include/piece.h b/src/include/piece.h @@ -1,36 +0,0 @@ -#ifndef STELLAR_PIECE_H -#define STELLAR_PIECE_H - -#include "attacks.h" - -typedef const struct Piece *Piece; - -typedef enum enumColor eColor; -enum enumColor { - WHITE = 0, - BLACK -}; - -typedef enum enumPiece ePiece; -enum enumPiece { - PAWN = 0, - KNIGHT, - BISHOP, - ROOK, - QUEEN, - KING -}; - -char piece_asci(Piece self); -attack_f piece_attacks(Piece self); -char piece_code(Piece self); -char *piece_unicode(Piece self); -eColor piece_color(Piece self); -ePiece piece_piece(Piece self); -int piece_index(Piece self); - -Piece piece_get(ePiece piece, eColor color); -Piece piece_from_code(char code); -Piece piece_from_index(int index); - -#endif diff --git a/src/include/piece.hpp b/src/include/piece.hpp @@ -0,0 +1,113 @@ +#ifndef STELLAR_PIECE_H +#define STELLAR_PIECE_H + +#include "attacks.hpp" +#include "utils_cpp.hpp" + +#include <cctype> + +namespace piece { + +enum class Type { + PAWN = 0, + KNIGHT, + BISHOP, + ROOK, + QUEEN, + KING, + TypeSIZE +}; +typedef Iterator<Type, Type::PAWN, Type::KING> TypeIter; + +class Piece { + public: + 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()) {} + + constexpr int index_calc() { + return to_underlying(Type::TypeSIZE) * to_underlying(color) * + to_underlying(type); + } +}; + +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) { + } +}; + +class Knight : public Piece { + public: + constexpr Knight(Color color) + : Piece(Type::KNIGHT, color, color == Color::WHITE ? 'N' : 'n', + color == Color::WHITE ? "■ " : "■ ", attacks_knight_get) {} +}; + +class Bishop : public Piece { + public: + constexpr Bishop(Color color) + : Piece(Type::BISHOP, color, color == Color::WHITE ? 'B' : 'b', + color == Color::WHITE ? "■ " : "■ ", attacks_bishop_get) {} +}; + +class Rook : public Piece { + public: + constexpr Rook(Color color) + : Piece(Type::ROOK, color, color == Color::WHITE ? 'R' : 'r', + color == Color::WHITE ? "■ " : "■ ", attacks_rook_get) {} +}; + +class Queen : public Piece { + public: + constexpr Queen(Color color) + : Piece(Type::QUEEN, color, color == Color::WHITE ? 'Q' : 'q', + color == Color::WHITE ? "■ " : "■ ", attacks_queen_get) {} +}; + +class King : public Piece { + public: + constexpr King(Color color) + : Piece(Type::KING, color, color == Color::WHITE ? 'K' : 'k', + color == Color::WHITE ? "■ " : "■ ", attacks_king_get) {} +}; + +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)}, +}; + +constexpr const Piece &get(Type type, Color color) { + return table[static_cast<int>(color)][static_cast<int>(type)]; +} + +constexpr const Piece &get_from_code(char code) { + Color color = isupper(code) ? Color::WHITE : Color::BLACK; + + for (Type type : TypeIter()) { + const Piece &piece = get(type, color); + if (piece.code == code) return piece; + } + + throw std::exception(); +} + +// constexpr const Piece &get_from_index(uint8_t index); + +} // namespace piece + +#endif diff --git a/src/include/random.h b/src/include/random.h @@ -1,7 +1,7 @@ #ifndef STELLAR_RANDOM_H #define STELLAR_RANDOM_H -#include "utils.h" +#include "utils.hpp" void random_state_reset(); U32 random_get_U32(); diff --git a/src/include/random.hpp b/src/include/random.hpp @@ -0,0 +1,10 @@ +#ifndef STELLAR_RANDOM_H +#define STELLAR_RANDOM_H + +#include "utils_cpp.hpp" + +void random_state_reset(); +U32 random_get_U32(); +U64 random_get_U64(); + +#endif diff --git a/src/include/utils.h b/src/include/utils.h @@ -48,10 +48,10 @@ enum enumSquare { a8, b8, c8, d8, e8, f8, g8, h8, no_sq }; // clang-format on -typedef enum enumSquare Square; +typedef enum enumSquare eSquare; extern const char *square_to_coordinates[]; -Square coordinates_to_square(const char *cord); +eSquare coordinates_to_square(const char *cord); // board moving typedef U64 (*direction_f)(U64); @@ -70,7 +70,7 @@ U64 rotateRight(U64 x, int s); int get_time_ms(void); -typedef U64 (*attack_f)(Square square, U64 occupancy); +typedef U64 (*attack_f)(eSquare square, U64 occupancy); #define empty_board "8/8/8/8/8/8/8/8 w - - " #define start_position \ diff --git a/src/include/utils_cpp.hpp b/src/include/utils_cpp.hpp @@ -0,0 +1,123 @@ +#ifndef STELLAR_UTILS_CPP_H +#define STELLAR_UTILS_CPP_H + +#include <cstdint> +#include <exception> +#include <type_traits> + +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); +} + +template <typename C, C beginVal, C endVal> class Iterator { + typedef typename std::underlying_type<C>::type val_t; + int val; + + public: + 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 Iterator end() { + // static const Iterator endIter = ++Iterator(endVal); + // return endIter; + return ++Iterator(endVal); + } + constexpr bool operator!=(const Iterator &i) { return val != i.val; } +}; + +#define C64(constantU64) constantU64##ULL +typedef uint64_t U64; +typedef uint32_t U32; + +enum class Color : uint8_t { + WHITE = 0, + BLACK +}; + +// clang-format off +enum class Square: uint8_t { + a1, b1, c1, d1, e1, f1, g1, h1, + a2, b2, c2, d2, e2, f2, g2, h2, + a3, b3, c3, d3, e3, f3, g3, h3, + a4, b4, c4, d4, e4, f4, g4, h4, + a5, b5, c5, d5, e5, f5, g5, h5, + a6, b6, c6, d6, e6, f6, g6, h6, + a7, b7, c7, d7, e7, f7, g7, h7, + a8, b8, c8, d8, e8, f8, g8, h8, no_sq +}; +// clang-format on + +typedef Iterator<Square, Square::a1, Square::h8> SquareIter; + +inline Square square_from_coordinates(const char *cord) { + return static_cast<Square>((cord[1] - '1') * 8 + (cord[0] - 'a')); +} + +// clang-format off +inline const char *square_to_coordinates(Square square) { + static const char *map[]={ + "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1", + "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2", + "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3", + "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4", + "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5", + "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6", + "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7", + "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8", " " + }; + return map[to_underlying(square)]; +} +// clang-format on + +// useful bit functions +#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))) + +inline uint8_t bit_count(U64 bitboard) { +#if __has_builtin(__builtin_popcountll) + return __builtin_popcountll(bitboard); +#endif + + int count = 0; + for (; bitboard > 0; bitboard &= bitboard - 1) + count++; + return count; +} + +inline uint8_t bit_lsb_index(U64 bitboard) { +#if __has_builtin(__builtin_ffsll) + return __builtin_ffsll(bitboard) - 1; +#endif + + if (!bitboard) return -1; + return bit_count((bitboard & -bitboard) - 1); +} + +#define bit_lsb_pop(bitboard) ((bitboard) &= (bitboard) & ((bitboard)-1)) + +#define bitboard_for_each_bit(var, bb) \ + for (var = bit_lsb_index(bb); bb; bit_lsb_pop(bb), var = bit_lsb_index(bb)) + +// board moving +const U64 universe = C64(0xffffffffffffffff); +const U64 notAFile = C64(0xfefefefefefefefe); +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; } + +#endif diff --git a/src/include/zobrist.h b/src/include/zobrist.h @@ -1,14 +0,0 @@ -#ifndef STELLAR_ZOBRIST_H -#define STELLAR_ZOBRIST_H - -#include "board.h" - -void zobrist_init(void); -U64 zobrist_hash(const Board *board); - -U64 zobrist_key_side(void); -U64 zobrist_key_castle(int exp); -U64 zobrist_key_enpassant(Square square); -U64 zobrist_key_piece(Piece piece, Square square); - -#endif diff --git a/src/include/zobrist.hpp b/src/include/zobrist.hpp @@ -0,0 +1,14 @@ +#ifndef STELLAR_ZOBRIST_H +#define STELLAR_ZOBRIST_H + +#include "board.hpp" + +void zobrist_init(void); +U64 zobrist_hash(const Board &board); + +U64 zobrist_key_side(void); +U64 zobrist_key_castle(int exp); +U64 zobrist_key_enpassant(Square square); +U64 zobrist_key_piece(const piece::Piece &piece, Square square); + +#endif diff --git a/src/perft/CMakeLists.txt b/src/perft/CMakeLists.txt @@ -2,7 +2,7 @@ project( perft VERSION 1.1.0 DESCRIPTION "Performance Test" - LANGUAGES C + LANGUAGES C CXX ) add_executable(perft perft.c) diff --git a/src/piece/CMakeLists.txt b/src/piece/CMakeLists.txt @@ -1,5 +1,5 @@ add_library(piece OBJECT - piece.c + piece.cpp ) target_include_directories(piece diff --git a/src/piece/piece.c b/src/piece/piece.c @@ -1,51 +0,0 @@ -#include <ctype.h> -#include <stdlib.h> - -#include "piece.h" - -struct Piece { - attack_f attacks; - char *unicode; - ePiece piece; - eColor color; - char code; - char asci; -}; - -// clang-format off -const struct Piece Pieces[2][6] = { -[WHITE] = { - [KNIGHT] = {.color = WHITE, .code = 'N', .asci = 'N', .unicode = "♘ ", .piece = KNIGHT, .attacks = attacks_knight_get}, - [BISHOP] = {.color = WHITE, .code = 'B', .asci = 'B', .unicode = "♗ ", .piece = BISHOP, .attacks = attacks_bishop_get}, - [QUEEN] = {.color = WHITE, .code = 'Q', .asci = 'Q', .unicode = "♕ ", .piece = QUEEN, .attacks = attacks_queen_get}, - [KING] = {.color = WHITE, .code = 'K', .asci = 'K', .unicode = "♔ ", .piece = KING, .attacks = attakcs_king_get}, - [PAWN] = {.color = WHITE, .code = 'P', .asci = 'P', .unicode = "♙ ", .piece = PAWN, .attacks = attacks_wpawn_get}, - [ROOK] = {.color = WHITE, .code = 'R', .asci = 'R', .unicode = "♖ ", .piece = ROOK, .attacks = attacks_rook_get}, - }, -[BLACK] = { - [KNIGHT] = {.color = BLACK, .code = 'n', .asci = 'n', .unicode = "♞ ", .piece = KNIGHT, .attacks = attacks_knight_get}, - [BISHOP] = {.color = BLACK, .code = 'b', .asci = 'b', .unicode = "♝ ", .piece = BISHOP, .attacks = attacks_bishop_get}, - [QUEEN] = {.color = BLACK, .code = 'q', .asci = 'q', .unicode = "♛ ", .piece = QUEEN, .attacks = attacks_queen_get}, - [KING] = {.color = BLACK, .code = 'k', .asci = 'k', .unicode = "♚ ", .piece = KING, .attacks = attakcs_king_get}, - [PAWN] = {.color = BLACK, .code = 'p', .asci = 'p', .unicode = "♟ ", .piece = PAWN, .attacks = attacks_bpawn_get}, - [ROOK] = {.color = BLACK, .code = 'r', .asci = 'r', .unicode = "♜ ", .piece = ROOK, .attacks = attacks_rook_get}, - }, -}; -// clang-format on - -attack_f piece_attacks(Piece self) { return self->attacks; } -char piece_asci(Piece self) { return self->asci; } -char piece_code(Piece self) { return self->code; } -char *piece_unicode(Piece self) { return self->unicode; } -eColor piece_color(Piece self) { return self->color; } -ePiece piece_piece(Piece self) { return self->piece; } -int piece_index(Piece self) { return self->color * 8 + self->piece; } - -Piece piece_get(ePiece piece, eColor color) { return &Pieces[color][piece]; } -Piece piece_from_index(int index) { return &Pieces[index / 8][index % 8]; } -Piece piece_from_code(char code) { - int color = (isupper(code)) ? WHITE : BLACK; - for (int i = 0; i < 6; i++) - if (Pieces[color][i].code == code) return &Pieces[color][i]; - return NULL; -} diff --git a/src/piece/piece.cpp b/src/piece/piece.cpp @@ -0,0 +1,6 @@ +#include "piece.hpp" + +#include <iostream> +int main(void) { + std::cout << piece::get(piece::Type::PAWN, Color::WHITE).code << std::endl; +} diff --git a/src/utils/utils.c b/src/utils/utils.c @@ -53,7 +53,7 @@ const char *square_to_coordinates[]={ }; // clang-format on -Square coordinates_to_square(const char *cord) { +eSquare coordinates_to_square(const char *cord) { return (cord[1] - '1') * 8 + (cord[0] - 'a'); }