stellar

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

commit67c3102f90a864a87055d35c03d2b17f41fa99fd
parentb3231023f2f855d0f1b27d7e834bba800bb6da5a
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateMon, 14 Aug 2023 14:58:21 +0200

Fix performance issue, slight problem with engine...

Diffstat:
Msrc/board/board.cpp|+++++++++++++++++++++--------------------------------
Msrc/engine/engine.cpp|++++++++------
Msrc/include/board.hpp|+++++++----------
Msrc/include/move.hpp|++++++++++++++++-------------------
Msrc/include/piece.hpp|+++++++-
Msrc/include/zobrist.hpp|++++++----------
Msrc/move/move.cpp|+++++++++++++++++++++++++++++-----------------------------
Msrc/move/movelist.cpp|+++++++++++++++++++++++++++++++++------------------------------------
Msrc/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";