stellarUCI Chess engine written in C++20 |
git clone git://git.dimitrijedobrota.com/stellar.git |
Log | Files | Refs | README | LICENSE | |
commit | 1857c3ab3da2587974a169e7414f3add950a7a5e |
parent | 2fb9a673b6887550d88a7d3be0cfd8df2a4e0536 |
author | Dimitrije Dobrota <mail@dimitrijedobrota.com> |
date | Tue, 15 Aug 2023 21:17:56 +0200 |
Trim Move town to 16bits
Diffstat:M | src/engine/engine.cpp | | | +++++++++++------ |
M | src/include/move.hpp | | | +++++++++++++++++++++++++++++++++++--------------------- |
M | src/move/move.cpp | | | ++++++++++++++++++++--------------- |
M | src/move/movelist.cpp | | | +++++++++++++++++------------------ |
M | src/perft/perft.cpp | | | ++-- |
5 files changed, 85 insertions(+), 62 deletions(-)
diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp
@@ -32,8 +32,11 @@ U32 ply;
Move move_list_best_move;
U32 inline move_list_score(Move move) {
const piece::Type type = move.piece();
if (move.is_capture()) return piece::score(type, move.captured()) + 10000;
const piece::Type type = board.get_square_piece_type(move.source());
if (move.is_capture()) {
const piece::Type captured = board.get_square_piece_type(move.target());
return piece::score(type, captured) + 10000;
}
if (killer[0][ply] == move) return 9000;
if (killer[1][ply] == move) return 8000;
return history[piece::get_index(type, board.get_side())][to_underlying(move.target())];
@@ -269,8 +272,8 @@ int negamax(int alpha, int beta, int depth, bool null) {
if (score > alpha) {
if (!move.is_capture()) {
history[piece::get_index(move.piece(), board.get_side())][to_underlying(move.target())] +=
depth;
const piece::Type piece = board.get_square_piece_type(move.source());
history[piece::get_index(piece, board.get_side())][to_underlying(move.target())] += depth;
}
alpha = score;
@@ -309,6 +312,7 @@ void move_print_UCI(Move move) {
void search_position(int depth) {
int alpha = -SCORE_INFINITY, beta = SCORE_INFINITY;
nodes = 0;
for (int crnt = 1; crnt <= depth;) {
follow_pv = 1;
@@ -327,7 +331,7 @@ void search_position(int depth) {
} else if (score > MATE_SCORE && score < MATE_VALUE) {
std::cout << "info score mate " << (MATE_VALUE - score) / 2 + 1;
} else {
std::cout << "info score " << score;
std::cout << "info score cp " << score;
}
std::cout << " depth " << crnt;
@@ -410,6 +414,7 @@ Move parse_move(char *move_string) {
Square source = square_from_coordinates(move_string);
Square target = square_from_coordinates(move_string + 2);
const MoveList list(board);
for (int i = 0; i < list.size(); i++) {
const Move move = list[i];
@@ -451,7 +456,7 @@ Board *Instruction_parse(Instruction *self) {
if (strcmp(token, "moves") == 0) {
while ((token = Instruction_token_next(self))) {
Move move = parse_move(token);
if (move == Move()) {
if (move != Move()) {
move.make(board, 0);
} else {
printf("Invalid move %s!\n", token);
diff --git a/src/include/move.hpp b/src/include/move.hpp
@@ -9,28 +9,47 @@
#include <vector>
struct Move {
Move() = default;
enum Flag : uint8_t {
QUIET,
DOUBLE,
CASTLEK,
CASTLEQ,
CAPTURE,
ENPASSANT,
PKNIGHT = 8,
PBISHOP,
PROOK,
PQUEEN,
PCKNIGHT,
PCBISHOP,
PCROOK,
PCQUEEN,
};
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) {}
Move() = default;
Move(Square source, Square target, Flag flags)
: source_i(to_underlying(source)), target_i(to_underlying(target)), flags_i(flags) {}
bool operator==(const Move &m) const = default;
bool operator==(Move &m) const {
return source_i == m.source_i && target_i == m.target_i && flags_i == m.flags_i;
}
Square source(void) const { return static_cast<Square>(source_i); }
Square target(void) const { return static_cast<Square>(target_i); }
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_i != to_underlying(piece::Type::NONE); }
bool is_promote(void) const { return promote_i != to_underlying(piece::Type::NONE); }
bool is_capture(void) const { return flags_i & CAPTURE; }
bool is_promote(void) const { return flags_i & 0x8; }
bool is_quiet(void) const { return flags_i == QUIET; }
bool is_double(void) const { return flags_i == DOUBLE; }
bool is_castle(void) const { return flags_i == CASTLEK || flags_i == CASTLEQ; }
bool is_castle_king(void) const { return flags_i == CASTLEK; }
bool is_castle_queen(void) const { return flags_i == CASTLEQ; }
bool is_enpassant(void) const { return flags_i == ENPASSANT; }
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); }
const piece::Type promoted(void) const { return static_cast<piece::Type>((flags_i & 0x3) + 1); }
bool make(Board &board, bool attack_only) const;
@@ -43,12 +62,7 @@ struct Move {
unsigned source_i : 6;
unsigned target_i : 6;
unsigned piece_i : 3;
unsigned capture_i : 3;
unsigned promote_i : 3;
bool dbl : 1;
bool enpassant : 1;
bool castle : 1;
unsigned flags_i : 4;
};
#endif
diff --git a/src/move/move.cpp b/src/move/move.cpp
@@ -20,6 +20,7 @@ void Move::piece_move(Board &board, piece::Type type, Color color, Square source
piece_set(board, type, color, target);
}
using piece::Type::PAWN;
using piece::Type::ROOK;
bool Move::make(Board &board, bool attack_only) const {
@@ -41,41 +42,47 @@ bool Move::make(Board &board, bool attack_only) const {
return 0;
} else {
const Color color = board.get_side();
Color colorOther = color == Color::BLACK ? Color::WHITE : Color::BLACK;
Color colorOther = color == Color::BLACK ? Color::WHITE : Color::BLACK;
const Square source = this->source();
const Square target = this->target();
const Square ntarget =
static_cast<Square>(to_underlying(this->target()) + (color == Color::WHITE ? -8 : +8));
const piece::Type piece = board.get_square_piece_type(source);
if (!is_capture()) {
if (is_promote()) {
piece_remove(board, piece(), color, source);
piece_remove(board, piece, color, source);
piece_set(board, promoted(), color, target);
} else {
piece_move(board, piece(), color, source, target);
piece_move(board, piece, color, source, target);
}
} else {
const piece::Type captured = board.get_square_piece_type(target);
if (is_enpassant()) {
piece_move(board, piece(), color, source, target);
piece_remove(board, captured(), colorOther, ntarget);
piece_move(board, piece, color, source, target);
piece_remove(board, PAWN, colorOther, ntarget);
} else if (is_promote()) {
piece_remove(board, piece(), color, source);
piece_remove(board, captured(), colorOther, target);
piece_remove(board, piece, color, source);
piece_remove(board, captured, colorOther, target);
piece_set(board, promoted(), color, target);
} else {
piece_remove(board, captured(), colorOther, target);
piece_move(board, piece(), color, 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()) {
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);
if (color == Color::WHITE) {
if (is_castle_king()) piece_move(board, ROOK, Color::WHITE, Square::h1, Square::f1);
if (is_castle_queen()) piece_move(board, ROOK, Color::WHITE, Square::a1, Square::d1);
} else {
if (is_castle_king()) piece_move(board, ROOK, Color::BLACK, Square::h8, Square::f8);
if (is_castle_queen()) piece_move(board, ROOK, Color::BLACK, Square::a8, Square::d8);
}
}
board.xor_hash(Zobrist::key_castle(board.get_castle()));
@@ -94,8 +101,6 @@ 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 << 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() << " ";
diff --git a/src/move/movelist.cpp b/src/move/movelist.cpp
@@ -35,17 +35,17 @@ void MoveList::generate(const Board &board) {
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, 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));
list.push_back({src, tgt, Move::PKNIGHT});
list.push_back({src, tgt, Move::PBISHOP});
list.push_back({src, tgt, Move::PROOK});
list.push_back({src, tgt, Move::PQUEEN});
} else {
list.push_back(Move(src, tgt, PAWN, NONE, NONE, 0, 0, 0));
list.push_back({src, tgt, Move::QUIET});
// 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, NONE, NONE, 1, 0, 0));
list.push_back({src, tgt, Move::DOUBLE});
}
}
@@ -54,21 +54,20 @@ void MoveList::generate(const Board &board) {
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::Type capture = board.get_square_piece_type(tgt);
if (pawn_canPromote(color, src)) {
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));
list.push_back({src, tgt, Move::PCKNIGHT});
list.push_back({src, tgt, Move::PCBISHOP});
list.push_back({src, tgt, Move::PCROOK});
list.push_back({src, tgt, Move::PCQUEEN});
} else {
list.push_back(Move(src, tgt, PAWN, capture, NONE, 0, 0, 0));
list.push_back({src, tgt, Move::CAPTURE});
}
}
// en passant
const Square enpassant = board.get_enpassant();
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));
list.push_back({src, enpassant, Move::ENPASSANT});
}
// All piece move
@@ -79,7 +78,7 @@ void MoveList::generate(const Board &board) {
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, type, board.get_square_piece_type(tgt), NONE, 0, 0, 0));
list.push_back({src, tgt, board.is_square_occupied(tgt) ? Move::CAPTURE : Move::QUIET});
}
}
}
@@ -90,14 +89,14 @@ void MoveList::generate(const Board &board) {
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, KING, NONE, NONE, 0, 0, 1));
list.push_back({Square::e1, Square::g1, Move::CASTLEK});
}
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, KING, NONE, NONE, 0, 0, 1));
list.push_back({Square::e1, Square::c1, Move::CASTLEQ});
}
}
} else {
@@ -105,14 +104,14 @@ void MoveList::generate(const Board &board) {
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, KING, NONE, NONE, 0, 0, 1));
list.push_back({Square::e8, Square::g8, Move::CASTLEK});
}
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, KING, NONE, NONE, 0, 0, 1));
list.push_back({Square::e8, Square::c8, Move::CASTLEQ});
}
}
}
diff --git a/src/perft/perft.cpp b/src/perft/perft.cpp
@@ -20,7 +20,7 @@ class Perft {
Board board = board_start;
if (!move.make(board, 0)) return;
sem.acquire();
debug(board_start, move, board);
// debug(board_start, move, board);
if (depth > 1) {
test(board, depth - 1);
@@ -64,7 +64,7 @@ class Perft {
for (int i = 0; i < list.size(); i++) {
Board copy = board;
if (!list[i].make(copy, 0)) continue;
debug(board, list[i], copy);
// debug(board, list[i], copy);
if (depth != 1)
test(copy, depth - 1);
else