stellar

Stellar - UCI 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 23:17:56 +0200

Trim Move town to 16bits

Diffstat:
Msrc/engine/engine.cpp | 17+++++++++++------
Msrc/include/move.hpp | 56+++++++++++++++++++++++++++++++++++---------------------
Msrc/move/move.cpp | 35++++++++++++++++++++---------------
Msrc/move/movelist.cpp | 35+++++++++++++++++------------------
Msrc/perft/perft.cpp | 4++--
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