stellar

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 15:30:42 +0200

Fix almost all of the bugs...

Diffstat:
Msrc/attacks/attacks.cpp | 4++--
Msrc/attacks/internal.cpp | 2+-
Dsrc/attacks/internal.h | 30------------------------------
Msrc/board/board.cpp | 22+++++++++-------------
Msrc/include/board.hpp | 12++++++------
Msrc/include/piece.hpp | 7+++----
Msrc/moves/moves_generate.cpp | 42++++++++++++++++++++++++------------------
Msrc/perft/CMakeLists.txt | 7-------
Msrc/perft/perft.cpp | 10+++-------
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) {