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:
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');
}