stellar

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

commit 67c3102f90a864a87055d35c03d2b17f41fa99fd
parent b3231023f2f855d0f1b27d7e834bba800bb6da5a
author Dimitrije Dobrota <mail@dimitrijedobrota.com>
date Mon, 14 Aug 2023 14:58:21 +0200

Fix performance issue, slight problem with engine...

Diffstat:
M src/board/board.cpp | +++++++++++++++++++++ --------------------------------
M src/engine/engine.cpp | ++++++++ ------
M src/include/board.hpp | +++++++ ----------
M src/include/move.hpp | ++++++++++++++++ -------------------
M src/include/piece.hpp | +++++++ -
M src/include/zobrist.hpp | ++++++ ----------
M src/move/move.cpp | +++++++++++++++++++++++++++++ -----------------------------
M src/move/movelist.cpp | +++++++++++++++++++++++++++++++++ ------------------------------------
M src/perft/perft.cpp | ++++++++++++++++ -------

9 files changed, 143 insertions(+), 150 deletions(-)


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

@@ -23,28 +23,16 @@ U64 Board::get_bitboard_occupancy(void) const { 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(square, get_bitboard_occupancy());
U64 Board::get_bitboard_piece_attacks(piece::Type type, Color color, Square from) const {
return piece::get_attack(type, color, from, get_bitboard_occupancy());
}
U64 Board::get_bitboard_piece_moves(piece::Type piece, Color color, Square square) const {
return get_bitboard_piece_moves(piece::get(piece, color), square);
}
U64 Board::get_bitboard_piece_moves(const piece::Piece &piece, Square square) const {
return get_bitboard_piece_attacks(piece, square) & ~get_bitboard_color(piece.color);
U64 Board::get_bitboard_piece_moves(piece::Type type, Color color, Square square) const {
return get_bitboard_piece_attacks(type, color, square) & ~get_bitboard_color(color);
} Color Board::get_square_piece_color(Square square) const {

@@ -57,7 +45,7 @@ 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();
return piece::Type::NONE;
} const piece::Piece *Board::get_square_piece(Square square) const {

@@ -93,22 +81,22 @@ 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::pop_bitboard_piece(piece::Type type, Square square) {
bit_pop(pieces[to_underlying(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::set_bitboard_piece(piece::Type type, Square square) {
bit_set(pieces[to_underlying(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::pop_piece(piece::Type type, Color side, Square square) {
pop_bitboard_color(side, square);
pop_bitboard_piece(type, square);
}
void Board::set_piece(const piece::Piece &piece, Square square) {
set_bitboard_color(piece.color, square);
set_bitboard_piece(piece, square);
void Board::set_piece(piece::Type type, Color side, Square square) {
set_bitboard_color(side, square);
set_bitboard_piece(type, square);
} /* Queries */

@@ -121,16 +109,16 @@ bool Board::is_square_attacked(Square square, Color side) const { Color side_other = (side == Color::BLACK) ? Color::WHITE : Color::BLACK; for (piece::Type type : piece::TypeIter()) {
if (get_bitboard_piece_attacks(piece::get(type, side_other), square) &
get_bitboard_piece(piece::get(type, side)))
if (get_bitboard_piece_attacks(type, side_other, square) & get_bitboard_piece(type, side)) {
return 1;
}
} return 0; }
bool Board::is_piece_attack_square(const piece::Piece &piece, Square source, Square target) const {
return get_bitboard_piece_attacks(piece, source) & (C64(1) << to_underlying(target));
bool Board::is_piece_attack_square(piece::Type type, Color color, Square source, Square target) const {
return get_bitboard_piece_attacks(type, color, source) & (C64(1) << to_underlying(target));
} bool Board::is_check(void) const {

@@ -144,7 +132,8 @@ Board::Board(const std::string &fen) { int file = 0, rank = 7, i; for (i = 0; fen[i] != ' '; i++) { if (isalpha(fen[i])) {
set_piece(piece::get_from_code(fen[i]), static_cast<Square>(rank * 8 + file));
const piece::Piece &piece = piece::get_from_code(fen[i]);
set_piece(piece.type, piece.color, static_cast<Square>(rank * 8 + file));
file++; } else if (isdigit(fen[i])) { file += fen[i] - '0';

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

@@ -23,7 +23,7 @@ Board board; TTable ttable(C64(0x400000)); Move pv_table[MAX_PLY][MAX_PLY]; Move killer[2][MAX_PLY];
U32 history[16][64];
U32 history[12][64];
int pv_length[MAX_PLY]; bool follow_pv; U64 nodes;

@@ -31,8 +31,8 @@ U32 ply; Move move_list_best_move; U32 inline move_list_score(Move move) {
const piece::Type type = move.piece().type;
if (move.is_capture()) return piece::score(type, move.piece_capture().type) + 10000;
const piece::Type type = move.piece();
if (move.is_capture()) return piece::score(type, move.captured()) + 10000;
if (killer[0][ply] == move) return 9000; if (killer[1][ply] == move) return 8000; return history[to_underlying(type)][to_underlying(move.target())];

@@ -268,7 +268,8 @@ int negamax(int alpha, int beta, int depth, bool null) { if (score > alpha) { if (!move.is_capture()) {
history[move.piece().index][to_underlying(move.target())] += depth;
int index = piece::get(move.piece(), board.get_side()).index;
history[index][to_underlying(move.target())] += depth;
} alpha = score;

@@ -302,7 +303,7 @@ int negamax(int alpha, int beta, int depth, bool null) { void move_print_UCI(Move move) { std::cout << square_to_coordinates(move.source()) << square_to_coordinates(move.target());
if (move.is_promote()) std::cout << move.piece_promote().code;
// if (move.is_promote()) std::cout << move.piece_promote().code;
} void search_position(int depth) {

@@ -413,7 +414,8 @@ Move parse_move(char *move_string) { const Move move = list[i]; if (move.source() == source && move.target() == target) { if (move_string[4]) {
if (tolower(move.piece_promote().code) != move_string[4]) continue;
char code = piece::get(move.promoted(), board.get_side()).code;
if (tolower(code) != move_string[4]) continue;
} return move; }

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

@@ -33,12 +33,9 @@ class Board { 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;
U64 get_bitboard_piece_moves(piece::Type piece, Color color, Square square) const;
U64 get_bitboard_piece_moves(const piece::Piece &piece, Square square) const;
U64 get_bitboard_piece_attacks(piece::Type piece, Color color, Square from) const;
U64 get_bitboard_piece_moves(piece::Type piece, Color color, Square from) const;
Color get_square_piece_color(Square square) const; piece::Type get_square_piece_type(Square square) const;

@@ -54,17 +51,17 @@ class Board { 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_bitboard_piece(piece::Type type, Square square);
void set_bitboard_piece(piece::Type type, Square square);
void pop_piece(const piece::Piece &piece, Square square);
void set_piece(const piece::Piece &piece, Square square);
void pop_piece(piece::Type type, Color side, Square square);
void set_piece(piece::Type type, Color side, Square square);
/* Queries */ bool is_square_attacked(Square Square, Color side) const; bool is_square_occupied(Square Square) const;
bool is_piece_attack_square(const piece::Piece &piece, Square source, Square target) const;
bool is_piece_attack_square(piece::Type type, Color color, Square source, Square target) const;
bool is_check(void) const; private:

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

@@ -11,12 +11,11 @@ struct Move { Move() = default;
Move(Square source, Square target, const piece::Piece *piece, const piece::Piece *capture,
const piece::Piece *promote, bool dbl, bool enpassant, bool castle)
: source_i(to_underlying(source)), target_i(to_underlying(target)), piece_i(piece->index),
piece_capture_i(capture ? capture->index : 0), piece_promote_i(promote ? promote->index : 0),
dbl(dbl), enpassant(enpassant), castle(castle), capture(capture != NULL), promote(promote != NULL) {
}
Move(Square source, Square target, piece::Type piece, piece::Type capture, piece::Type promote, bool dbl,
bool enpassant, bool castle)
: source_i(to_underlying(source)), target_i(to_underlying(target)), piece_i(to_underlying(piece)),
capture_i(to_underlying(capture)), promote_i(to_underlying(promote)), dbl(dbl),
enpassant(enpassant), castle(castle) {}
bool operator==(const Move &m) const = default;

@@ -26,32 +25,30 @@ struct Move { bool is_double(void) const { return dbl; } bool is_enpassant(void) const { return enpassant; } bool is_castle(void) const { return castle; }
bool is_capture(void) const { return capture; }
bool is_promote(void) const { return promote; }
bool is_capture(void) const { return capture_i != to_underlying(piece::Type::NONE); }
bool is_promote(void) const { return promote_i != to_underlying(piece::Type::NONE); }
const piece::Piece &piece(void) const { return piece::get_from_index(piece_i); }
const piece::Piece &piece_capture(void) const { return piece::get_from_index(piece_capture_i); }
const piece::Piece &piece_promote(void) const { return piece::get_from_index(piece_promote_i); }
const piece::Type piece(void) const { return static_cast<piece::Type>(piece_i); }
const piece::Type captured(void) const { return static_cast<piece::Type>(capture_i); }
const piece::Type promoted(void) const { return static_cast<piece::Type>(promote_i); }
bool make(Board &board, bool attack_only) const; friend std::ostream &operator<<(std::ostream &os, Move move); private:
inline void piece_remove(Board &board, const piece::Piece &piece, Square square) const;
inline void piece_set(Board &board, const piece::Piece &piece, Square square) const;
inline void piece_move(Board &board, const piece::Piece &piece, Square source, Square target) const;
inline void piece_remove(Board &board, piece::Type type, Color color, Square square) const;
inline void piece_set(Board &board, piece::Type type, Color color, Square square) const;
inline void piece_move(Board &board, piece::Type type, Color color, Square source, Square target) const;
unsigned source_i : 6; unsigned target_i : 6;
unsigned piece_i : 5;
unsigned piece_capture_i : 5;
unsigned piece_promote_i : 5;
unsigned piece_i : 3;
unsigned capture_i : 3;
unsigned promote_i : 3;
bool dbl : 1; bool enpassant : 1; bool castle : 1;
bool capture : 1;
bool promote : 1;
}; #endif

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

@@ -15,7 +15,7 @@ enum class Type { ROOK, QUEEN, KING,
TypeSIZE
NONE = 7,
}; typedef Iterator<Type, Type::PAWN, Type::KING> TypeIter;

@@ -96,6 +96,12 @@ constexpr const Piece &get(Type type, Color color) { return table[static_cast<int>(color)][static_cast<int>(type)]; }
constexpr const U64 get_attack(Type type, Color color, Square from, U64 occupancy) {
return get(type, color)(from, occupancy);
}
constexpr const char get_code(Type type, Color color = Color::WHITE) { return get(type, color).code; }
constexpr const U64 get_index(Type type, Color color) { return get(type, color).index; }
constexpr const Piece &get_from_code(char code) { Color color = isupper(code) ? Color::WHITE : Color::BLACK;

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

@@ -16,8 +16,8 @@ class Zobrist { static inline constexpr U64 key_side(void) { return keys_side; } static inline constexpr U64 key_castle(int exp) { return keys_castle[exp]; } static inline constexpr U64 key_enpassant(Square square) { return keys_enpassant[to_underlying(square)]; }
static inline constexpr U64 key_piece(const piece::Piece &piece, Square square) {
return keys_piece[piece.index][to_underlying(square)];
static inline constexpr U64 key_piece(piece::Type type, Color color, Square square) {
return keys_piece[piece::get_index(type, color)][to_underlying(square)];
} static inline U64 hash(const Board &board) {

@@ -25,18 +25,14 @@ class Zobrist { 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);
int piece_white_index = piece::get_index(type, Color::WHITE);
U64 bitboard_white = board.get_bitboard_piece(type, Color::WHITE);
bitboard_for_each_bit(square, bitboard_white) { key_final ^= keys_piece[piece_white_index][square]; }
const piece::Piece &piece_black = piece::get(type, Color::BLACK);
int piece_black_index = piece_black.index;
U64 bitboard_black = board.get_bitboard_piece(piece_black);
int piece_black_index = piece::get_index(type, Color::BLACK);
U64 bitboard_black = board.get_bitboard_piece(type, Color::BLACK);
bitboard_for_each_bit(square, bitboard_black) { key_final ^= keys_piece[piece_black_index][square]; }

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

@@ -5,21 +5,23 @@ #include <algorithm> #include <iomanip>
void Move::piece_remove(Board &board, const piece::Piece &piece, Square square) const {
board.pop_piece(piece, square);
board.xor_hash(Zobrist::key_piece(piece, square));
void Move::piece_remove(Board &board, piece::Type type, Color color, Square square) const {
board.pop_piece(type, color, square);
board.xor_hash(Zobrist::key_piece(type, color, square));
}
void Move::piece_set(Board &board, const piece::Piece &piece, Square square) const {
board.set_piece(piece, square);
board.xor_hash(Zobrist::key_piece(piece, square));
void Move::piece_set(Board &board, piece::Type type, Color color, Square square) const {
board.set_piece(type, color, square);
board.xor_hash(Zobrist::key_piece(type, color, square));
}
void Move::piece_move(Board &board, const piece::Piece &piece, Square source, Square target) const {
piece_remove(board, piece, source);
piece_set(board, piece, target);
void Move::piece_move(Board &board, piece::Type type, Color color, Square source, Square target) const {
piece_remove(board, type, color, source);
piece_set(board, type, color, target);
}
using piece::Type::ROOK;
bool Move::make(Board &board, bool attack_only) const { static constexpr const int castling_rights[64] = { // clang-format off

@@ -38,8 +40,8 @@ bool Move::make(Board &board, bool attack_only) const { if (is_capture()) return make(board, false); return 0; } else {
const piece::Piece &piece = this->piece();
const Color color = board.get_side();
Color colorOther = color == Color::BLACK ? Color::WHITE : Color::BLACK;
const Square source = this->source(); const Square target = this->target();

@@ -48,34 +50,32 @@ bool Move::make(Board &board, bool attack_only) const { if (!is_capture()) { if (is_promote()) {
piece_remove(board, piece, source);
piece_set(board, piece_promote(), target);
piece_remove(board, piece(), color, source);
piece_set(board, promoted(), color, target);
} else {
piece_move(board, piece, source, target);
piece_move(board, piece(), color, source, target);
} } else { if (is_enpassant()) {
piece_move(board, piece, source, target);
piece_remove(board, piece_capture(), ntarget);
piece_move(board, piece(), color, source, target);
piece_remove(board, captured(), colorOther, ntarget);
} else if (is_promote()) {
piece_remove(board, piece, source);
piece_remove(board, piece_capture(), target);
piece_set(board, piece_promote(), target);
piece_remove(board, piece(), color, source);
piece_remove(board, captured(), colorOther, target);
piece_set(board, promoted(), color, target);
} else {
piece_remove(board, piece_capture(), target);
piece_move(board, piece, source, target);
piece_remove(board, captured(), colorOther, target);
piece_move(board, piece(), color, source, target);
} } board.set_enpassant(is_double() ? ntarget : Square::no_sq); if (is_castle()) {
static constexpr const piece::Piece &rook_white = piece::get(piece::Type::ROOK, Color::WHITE);
static constexpr const piece::Piece &rook_black = piece::get(piece::Type::ROOK, Color::BLACK);
if (target == Square::g1) piece_move(board, rook_white, Square::h1, Square::f1);
if (target == Square::c1) piece_move(board, rook_white, Square::a1, Square::d1);
if (target == Square::g8) piece_move(board, rook_black, Square::h8, Square::f8);
if (target == Square::c8) piece_move(board, rook_black, Square::a8, Square::d8);
if (target == Square::g1) piece_move(board, ROOK, Color::WHITE, Square::h1, Square::f1);
if (target == Square::c1) piece_move(board, ROOK, Color::WHITE, Square::a1, Square::d1);
if (target == Square::g8) piece_move(board, ROOK, Color::BLACK, Square::h8, Square::f8);
if (target == Square::c8) piece_move(board, ROOK, Color::BLACK, Square::a8, Square::d8);
} board.xor_hash(Zobrist::key_castle(board.get_castle()));

@@ -94,9 +94,9 @@ bool Move::make(Board &board, bool attack_only) const { std::ostream &operator<<(std::ostream &os, Move move) { os << square_to_coordinates(move.source()) << " "; os << square_to_coordinates(move.target()) << " ";
os << move.piece().code << " ";
os << (move.is_capture() ? move.piece_capture().code : '.') << " ";
os << (move.is_promote() ? move.piece_promote().code : '.') << " ";
os << piece::get_code(move.piece()) << " ";
os << (move.is_capture() ? piece::get_code(move.captured()) : '.') << " ";
os << (move.is_promote() ? piece::get_code(move.promoted()) : '.') << " ";
os << move.is_double() << " "; os << move.is_enpassant() << " "; os << move.is_castle();

diff --git a/ src/move/movelist.cpp b/ src/move/movelist.cpp

@@ -1,4 +1,5 @@ #include "movelist.hpp"
#include "piece.hpp"
#include <iomanip> #define pawn_canPromote(color, source) \

@@ -9,6 +10,14 @@ ((color == Color::BLACK && source >= Square::a7 && source <= Square::h7) || \ (color == Color::WHITE && source >= Square::a2 && source <= Square::h2))
using piece::Type::BISHOP;
using piece::Type::KING;
using piece::Type::KNIGHT;
using piece::Type::NONE;
using piece::Type::PAWN;
using piece::Type::QUEEN;
using piece::Type::ROOK;
void MoveList::generate(const Board &board) { this->clear();

@@ -18,104 +27,92 @@ void MoveList::generate(const Board &board) { Color colorOther = color == Color::BLACK ? Color::WHITE : Color::BLACK; // pawn moves
const piece::Piece &pawn = piece::get(piece::Type::PAWN, color);
const int add = (color == Color::WHITE) ? +8 : -8;
U64 bitboard = board.get_bitboard_piece(pawn);
U64 bitboard = board.get_bitboard_piece(PAWN, color);
bitboard_for_each_bit(src_i, bitboard) { const Square src = static_cast<Square>(src_i); const Square tgt = static_cast<Square>(tgt_i = src_i + add); if (!board.is_square_occupied(tgt)) { if (pawn_canPromote(color, src)) {
list.push_back(
Move(src, tgt, &pawn, nullptr, &piece::get(piece::Type::KNIGHT, color), 0, 0, 0));
list.push_back(
Move(src, tgt, &pawn, nullptr, &piece::get(piece::Type::BISHOP, color), 0, 0, 0));
list.push_back(
Move(src, tgt, &pawn, nullptr, &piece::get(piece::Type::ROOK, color), 0, 0, 0));
list.push_back(
Move(src, tgt, &pawn, nullptr, &piece::get(piece::Type::QUEEN, color), 0, 0, 0));
list.push_back(Move(src, tgt, PAWN, NONE, KNIGHT, 0, 0, 0));
list.push_back(Move(src, tgt, PAWN, NONE, BISHOP, 0, 0, 0));
list.push_back(Move(src, tgt, PAWN, NONE, ROOK, 0, 0, 0));
list.push_back(Move(src, tgt, PAWN, NONE, QUEEN, 0, 0, 0));
} else {
list.push_back(Move(src, tgt, &pawn, 0, 0, 0, 0, 0));
list.push_back(Move(src, tgt, PAWN, NONE, NONE, 0, 0, 0));
// two ahead const Square tgt = static_cast<Square>(tgt_i + add); if (pawn_onStart(color, src) && !board.is_square_occupied(tgt))
list.push_back(Move(src, tgt, &pawn, 0, 0, 1, 0, 0));
list.push_back(Move(src, tgt, PAWN, NONE, NONE, 1, 0, 0));
} } // capture
U64 attack = board.get_bitboard_piece_attacks(pawn, src) & board.get_bitboard_color(colorOther);
U64 attack =
board.get_bitboard_piece_attacks(PAWN, color, src) & board.get_bitboard_color(colorOther);
bitboard_for_each_bit(tgt_i, attack) { const Square tgt = static_cast<Square>(tgt_i);
const piece::Piece *capture = board.get_square_piece(tgt);
const piece::Type capture = board.get_square_piece_type(tgt);
if (pawn_canPromote(color, src)) {
list.push_back(
Move(src, tgt, &pawn, capture, &piece::get(piece::Type::KNIGHT, color), 0, 0, 0));
list.push_back(
Move(src, tgt, &pawn, capture, &piece::get(piece::Type::BISHOP, color), 0, 0, 0));
list.push_back(
Move(src, tgt, &pawn, capture, &piece::get(piece::Type::ROOK, color), 0, 0, 0));
list.push_back(
Move(src, tgt, &pawn, capture, &piece::get(piece::Type::QUEEN, color), 0, 0, 0));
list.push_back(Move(src, tgt, PAWN, capture, KNIGHT, 0, 0, 0));
list.push_back(Move(src, tgt, PAWN, capture, BISHOP, 0, 0, 0));
list.push_back(Move(src, tgt, PAWN, capture, ROOK, 0, 0, 0));
list.push_back(Move(src, tgt, PAWN, capture, QUEEN, 0, 0, 0));
} else {
list.push_back(Move(src, tgt, &pawn, capture, 0, 0, 0, 0));
list.push_back(Move(src, tgt, PAWN, capture, NONE, 0, 0, 0));
} } // en passant const Square enpassant = board.get_enpassant();
if (enpassant != Square::no_sq && board.is_piece_attack_square(pawn, src, enpassant))
list.push_back(
Move(src, enpassant, &pawn, &piece::get(piece::Type::PAWN, colorOther), 0, 0, 1, 0));
if (enpassant != Square::no_sq && board.is_piece_attack_square(PAWN, color, src, enpassant))
list.push_back(Move(src, enpassant, PAWN, PAWN, NONE, 0, 1, 0));
} // All piece move for (const piece::Type type : ++piece::TypeIter()) {
const piece::Piece &piece = piece::get(type, color);
U64 bitboard = board.get_bitboard_piece(piece);
U64 bitboard = board.get_bitboard_piece(type, color);
bitboard_for_each_bit(src_i, bitboard) { const Square src = static_cast<Square>(src_i);
U64 attack = board.get_bitboard_piece_moves(piece, src);
U64 attack = board.get_bitboard_piece_moves(type, color, src);
bitboard_for_each_bit(tgt_i, attack) { const Square tgt = static_cast<Square>(tgt_i);
list.push_back(Move(src, tgt, &piece, board.get_square_piece(tgt), 0, 0, 0, 0));
list.push_back(Move(src, tgt, type, board.get_square_piece_type(tgt), NONE, 0, 0, 0));
} } } // Castling if (color == Color::WHITE) {
static const piece::Piece &piece = piece::get(piece::Type::KING, Color::WHITE);
if (!board.is_square_attacked(Square::e1, Color::BLACK)) { if (board.get_castle() & to_underlying(Board::Castle::WK)) { if (!board.is_square_occupied(Square::f1) && !board.is_square_occupied(Square::g1) && !board.is_square_attacked(Square::f1, Color::BLACK))
list.push_back(Move(Square::e1, Square::g1, &piece, 0, 0, 0, 0, 1));
list.push_back(Move(Square::e1, Square::g1, KING, NONE, NONE, 0, 0, 1));
} if (board.get_castle() & to_underlying(Board::Castle::WQ)) { if (!board.is_square_occupied(Square::d1) && !board.is_square_occupied(Square::c1) && !board.is_square_occupied(Square::b1) && !board.is_square_attacked(Square::d1, Color::BLACK) && !board.is_square_attacked(Square::c1, Color::BLACK))
list.push_back(Move(Square::e1, Square::c1, &piece, 0, 0, 0, 0, 1));
list.push_back(Move(Square::e1, Square::c1, KING, NONE, NONE, 0, 0, 1));
} } } else {
static const piece::Piece &piece = piece::get(piece::Type::KING, Color::BLACK);
if (!board.is_square_attacked(Square::e8, Color::WHITE)) { if (board.get_castle() & to_underlying(Board::Castle::BK)) { if (!board.is_square_occupied(Square::f8) && !board.is_square_occupied(Square::g8) && !board.is_square_attacked(Square::f8, Color::WHITE))
list.push_back(Move(Square::e8, Square::g8, &piece, 0, 0, 0, 0, 1));
list.push_back(Move(Square::e8, Square::g8, KING, NONE, NONE, 0, 0, 1));
} if (board.get_castle() & to_underlying(Board::Castle::BQ)) { if (!board.is_square_occupied(Square::d8) && !board.is_square_occupied(Square::c8) && !board.is_square_occupied(Square::b8) && !board.is_square_attacked(Square::d8, Color::WHITE) && !board.is_square_attacked(Square::c8, Color::WHITE))
list.push_back(Move(Square::e8, Square::c8, &piece, 0, 0, 0, 0, 1));
list.push_back(Move(Square::e8, Square::c8, KING, NONE, NONE, 0, 0, 1));
} } }

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

@@ -17,14 +17,16 @@ class Perft { typedef std::counting_semaphore<THREAD_MAX> semaphore_t; Perft(semaphore_t &sem) : sem(sem) {} void operator()(const Board &board_start, Move move, int depth) {
sem.acquire();
Board board = board_start;
if (move.make(board, 0)) {
if (depth > 1)
test(board, depth - 1);
else
score(board, move);
if (!move.make(board, 0)) return;
sem.acquire();
if (depth > 1) {
test(board, depth - 1);
} else {
score(board, move);
}
mutex.acquire(); result += local; mutex.release();

@@ -67,6 +69,13 @@ class Perft { score(copy, list[i]); } }
void debug(const Board &before, Move move, const Board &after) {
std::cout << std::setw(16) << std::hex << before.get_hash() << " ";
std::cout << move << " ";
std::cout << std::setw(16) << std::hex << after.get_hash() << "\n";
}
void score(const Board &board, Move move) { local.node++; #ifdef USE_FULL_COUNT

@@ -77,7 +86,6 @@ class Perft { if (move.is_promote()) local.promote++; #endif }
result_t local; semaphore_t &sem; static std::binary_semaphore mutex;

@@ -100,6 +108,7 @@ void perft_test(const char *fen, int depth, int thread_num) { for (auto &thread : threads) thread.join();
std::cout << std::dec;
std::cout << " Nodes: " << Perft::result.node << "\n"; #ifdef USE_FULL_COUNT std::cout << " Captures: " << Perft::result.capture << "\n";