stellar

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

commit efb266c91585d3dcfe9ade481bc13199b9508418
parent d02e946f5b524acd6871c196d4ef505cfa0b5e0a
author Dimitrije Dobrota <mail@dimitrijedobrota.com>
date Thu, 10 Aug 2023 13:30:42 +0200

Fix almost all of the bugs...

Diffstat:
M src/attacks/attacks.cpp | ++ --
M src/attacks/internal.cpp | + -
D src/attacks/internal.h | ------------------------------
M src/board/board.cpp | +++++++++ -------------
M src/include/board.hpp | ++++++ ------
M src/include/piece.hpp | +++ ----
M src/moves/moves_generate.cpp | ++++++++++++++++++++++++ ------------------
M src/perft/CMakeLists.txt | -------
M src/perft/perft.cpp | +++ -------

9 files changed, 48 insertions(+), 88 deletions(-)


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

@@ -48,7 +48,7 @@ U64 attacks_queen_get(Square square, U64 occupancy) { void attacks_init_leapers(void) { for (Square square : SquareIter()) {
uint8_t square_i;
uint8_t square_i = to_underlying(square);
pawn_attacks[to_underlying(Color::WHITE)][square_i] = pawn_mask(Color::WHITE, square); pawn_attacks[to_underlying(Color::BLACK)][square_i] =

@@ -60,7 +60,7 @@ void attacks_init_leapers(void) { void attacks_init_sliders(int bishop) { for (Square square : SquareIter()) {
uint8_t square_i;
uint8_t square_i = to_underlying(square);
U64 attack_mask; if (bishop) {

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

@@ -1,4 +1,4 @@
#include "internal.h"
#include "internal.hpp"
#include "utils_cpp.hpp" #include <algorithm> // std::min

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

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

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

@@ -121,13 +121,11 @@ bool Board::is_square_occupied(Square square) const { } 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))
if (get_bitboard_piece_attacks(piece::get(type, side_other), square) &
get_bitboard_piece(piece::get(type, side)))
return 1; }

@@ -137,19 +135,14 @@ bool Board::is_square_attacked(Square square, Color side) const { bool Board::is_check(void) const { U64 king = pieces[to_underlying(piece::Type::KING)] & colors[to_underlying(side)];
Color side_other = (side == Color::BLACK) ? Color::WHITE : Color::BLACK;
Square square = static_cast<Square>(bit_lsb_index(king));
return is_square_attacked(square, side);
return is_square_attacked(square, side_other);
} 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++) {
for (i = 0; fen[i] != ' '; i++) {
if (isalpha(fen[i])) { set_piece(piece::get_from_code(fen[i]), static_cast<Square>(rank * 8 + file));

@@ -181,6 +174,8 @@ Board::Board(const std::string &fen) { castle |= to_underlying(Castle::BK); else if (fen[i] == 'q') castle |= to_underlying(Castle::BQ);
else if (fen[i] == '-')
break;
else throw std::exception(); }

@@ -192,13 +187,14 @@ Board::Board(const std::string &fen) { std::ostream &operator<<(std::ostream &os, const Board &board) { for (int rank = 0; rank < 8; rank++) { for (int file = 0; file < 8; file++) {
if (!file) os << 8 - rank << " ";
Square square = static_cast<Square>((7 - rank) * 8 + file); const piece::Piece *piece = board.get_square_piece(square); os << (piece ? piece->code : '.') << " "; } printf("\n"); }
os << " A B C D E F G H\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";

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

@@ -69,12 +69,12 @@ class Board { bool is_check(void) const; private:
U64 colors[2];
U64 pieces[6];
U64 hash;
Color side;
Square enpassant;
uint8_t castle;
U64 colors[2] = {0};
U64 pieces[6] = {0};
U64 hash = 0;
Color side = Color::WHITE;
Square enpassant = Square::no_sq;
uint8_t castle = 0;
}; const piece::Piece &board_square_piece(const Board *self, Square square,

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

@@ -32,11 +32,10 @@ class Piece { 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()) {}
attacks(attacks), index(index_calc(color, type)) {}
constexpr int index_calc() {
return to_underlying(Type::TypeSIZE) * to_underlying(color) *
to_underlying(type);
constexpr uint8_t index_calc(Color color, Type type) {
return to_underlying(color) * 6 + to_underlying(type);
} };

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

@@ -15,19 +15,19 @@ #define pawn_promote(source, target, piece, capture) \ res.push_back( \
{move_encode(source, target, &piece, 0, \
{move_encode(source, target, &piece, capture, \
&piece::get(piece::Type::KNIGHT, color), 0, 0, 0), \ 0}); \ res.push_back( \
{move_encode(source, target, &piece, 0, \
{move_encode(source, target, &piece, capture, \
&piece::get(piece::Type::BISHOP, color), 0, 0, 0), \ 0}); \ res.push_back( \
{move_encode(source, target, &piece, 0, \
{move_encode(source, target, &piece, capture, \
&piece::get(piece::Type::ROOK, color), 0, 0, 0), \ 0}); \ res.push_back( \
{move_encode(source, target, &piece, 0, \
{move_encode(source, target, &piece, capture, \
&piece::get(piece::Type::QUEEN, color), 0, 0, 0), \ 0});

@@ -53,22 +53,24 @@ std::vector<MoveE> move_list_generate(const Board &board) { if (!board.is_square_occupied(tgt)) { if (pawn_canPromote(color, src)) { pawn_promote(src_i, tgt_i, piece, nullptr);
continue;
}
res.push_back(
{move_encode(src_i, tgt_i, &piece, 0, 0, 0, 0, 0), 0});
// two ahead
if (pawn_onStart(color, src) && !board.is_square_occupied(tgt))
} else {
res.push_back(
{move_encode(src_i, tgt_i + add, &piece, 0, 0, 1, 0, 0),
0});
{move_encode(src_i, tgt_i, &piece, 0, 0, 0, 0, 0), 0});
// two ahead
Square tgt = static_cast<Square>(tgt_i + add);
if (pawn_onStart(color, src) && !board.is_square_occupied(tgt))
res.push_back(
{move_encode(src_i, tgt_i + add, &piece, 0, 0, 1, 0, 0),
0});
}
} // capture U64 attack = board.get_bitboard_piece_attacks(piece, src) & board.get_bitboard_color(colorOther); bitboard_for_each_bit(tgt_i, attack) {
Square tgt = static_cast<Square>(tgt_i);
const piece::Piece *capture = board.get_square_piece(tgt); if (pawn_canPromote(color, src)) { pawn_promote(src_i, tgt_i, piece, capture);

@@ -92,11 +94,12 @@ std::vector<MoveE> move_list_generate(const Board &board) { } // All piece move
for (piece::Type type : ++piece::TypeIter()) {
const piece::Piece &piece = piece::get(type, color);
auto type_it = piece::TypeIter().begin();
for (++type_it; type_it != type_it.end(); ++type_it) {
const piece::Piece &piece = piece::get(*type_it, color);
U64 bitboard = board.get_bitboard_piece(piece);
Square src = static_cast<Square>(src_i);
bitboard_for_each_bit(src_i, bitboard) {
Square src = static_cast<Square>(src_i);
U64 attack = board.get_bitboard_piece_attacks(piece, src) & ~board.get_bitboard_color(color); bitboard_for_each_bit(tgt_i, attack) {

@@ -111,7 +114,8 @@ std::vector<MoveE> move_list_generate(const Board &board) { // Castling if (color == Color::WHITE) {
const piece::Piece &piece = piece::get(piece::Type::KING, Color::WHITE);
static const piece::Piece &piece =
piece::get(piece::Type::KING, Color::WHITE);
if (board.get_castle() & to_underlying(Board::Castle::WK)) { if (!board.is_square_occupied(Square::f1) && !board.is_square_occupied(Square::g1) &&

@@ -134,7 +138,8 @@ std::vector<MoveE> move_list_generate(const Board &board) { 0}); } } else {
const piece::Piece &piece = piece::get(piece::Type::KING, Color::BLACK);
static const piece::Piece &piece =
piece::get(piece::Type::KING, Color::BLACK);
if (board.get_castle() & to_underlying(Board::Castle::BK)) { if (!board.is_square_occupied(Square::f8) && !board.is_square_occupied(Square::g8) &&

@@ -158,5 +163,6 @@ std::vector<MoveE> move_list_generate(const Board &board) { } }
res.resize(res.size());
return res; }

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

@@ -1,10 +1,3 @@
project(
perft
VERSION 1.1.0
DESCRIPTION "Performance Test"
LANGUAGES C CXX
)
add_executable(perft perft.cpp) option(WITH_FULL_COUNT "Make count on types of moves" OFF)

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

@@ -14,10 +14,6 @@ // FEN debug positions #define tricky_position \ "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1 "
#define killer_position \
"rnbqkb1r/pp1p1pPp/8/2p1pP2/1P1P4/3P3P/P1P1P3/RNBQKBNR w KQkq e6 0 1"
#define cmk_position \
"r2q1rk1/ppp2ppp/2n1bn2/2b1p3/3pP3/3P1NPP/PPP1NPB1/R1BQ1RK1 b - - 0 9 "
void perft_result_print(PerftResult res) { printf(" - Perft Results -\n\n");

@@ -66,7 +62,7 @@ void perft_driver(Board &board, MoveList *moveList, int depth, } else { result->node++; #ifdef USE_FULL_COUNT
if (board_isCheck(copy)) result->check++;
if (copy.is_check()) result->check++;
if (move_capture(move)) result->capture++; if (move_enpassant(move)) result->enpassant++; if (move_castle(move)) result->castle++;

@@ -113,7 +109,7 @@ void *perft_thread(void *arg) { } else { result.node++; #ifdef USE_FULL_COUNT
if (board_isCheck(copy)) result.check++;
if (copy.is_check()) result.check++;
if (move_capture(move)) result.capture++; if (move_enpassant(move)) result.enpassant++; if (move_castle(move)) result.castle++;

@@ -145,7 +141,7 @@ PerftResult perft_test(const char *fen, int depth, int thread_num) { int main(int argc, char *argv[]) { int c, depth = 1, thread_num = 1;
std::string s(start_position);
std::string s(tricky_position);
const char *fen = s.data(); while ((c = getopt(argc, argv, "t:f:d:")) != -1) { switch (c) {