commit e611a16b9622e0b6831048b51a87cf51a2a01792
parent 3be4123c8c5cbdadfab02532d2bfcb9bdb173083
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Sun, 13 Aug 2023 11:24:59 +0200
Improve Move and MoveList
Diffstat:
24 files changed, 523 insertions(+), 591 deletions(-)
diff --git a/.clang-format b/.clang-format
@@ -36,7 +36,7 @@ AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
-AllowShortFunctionsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: true
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: false
diff --git a/src/board/board.cpp b/src/board/board.cpp
@@ -10,30 +10,18 @@
/* Getters */
-Color Board::get_side(void) const {
- return side;
-}
-U64 Board::get_hash(void) const {
- return hash;
-}
-uint8_t Board::get_castle(void) const {
- return castle;
-}
-Square Board::get_enpassant(void) const {
- return enpassant;
-}
+Color Board::get_side(void) const { return side; }
+U64 Board::get_hash(void) const { return hash; }
+uint8_t Board::get_castle(void) const { return castle; }
+Square Board::get_enpassant(void) const { return enpassant; }
-U64 Board::get_bitboard_color(Color side) const {
- return colors[to_underlying(side)];
-}
+U64 Board::get_bitboard_color(Color side) const { return colors[to_underlying(side)]; }
U64 Board::get_bitboard_occupancy(void) const {
return colors[to_underlying(Color::WHITE)] | colors[to_underlying(Color::BLACK)];
}
-U64 Board::get_bitboard_piece(piece::Type piece) const {
- return pieces[to_underlying(piece)];
-}
+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);
@@ -51,6 +39,14 @@ U64 Board::get_bitboard_piece_attacks(const piece::Piece &piece, Square square)
return piece(square, 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);
+}
+
Color Board::get_square_piece_color(Square square) const {
if (bit_get(colors[to_underlying(Color::WHITE)], to_underlying(square))) return Color::WHITE;
if (bit_get(colors[to_underlying(Color::BLACK)], to_underlying(square))) return Color::BLACK;
@@ -74,12 +70,8 @@ const piece::Piece *Board::get_square_piece(Square square) const {
/* Setters */
-void Board::xor_hash(U64 op) {
- hash ^= op;
-}
-void Board::and_castle(uint8_t right) {
- castle &= right;
-}
+void Board::xor_hash(U64 op) { hash ^= op; }
+void Board::and_castle(uint8_t right) { castle &= right; }
void Board::switch_side(void) {
side = (side == Color::BLACK) ? Color::WHITE : Color::BLACK;
@@ -137,6 +129,10 @@ bool Board::is_square_attacked(Square square, Color side) const {
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_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;
diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp
@@ -5,7 +5,8 @@
#include "attack.hpp"
#include "board.hpp"
-#include "moves.hpp"
+#include "move.hpp"
+#include "movelist.hpp"
#include "score.hpp"
#include "stats.hpp"
#include "transposition.hpp"
@@ -18,26 +19,6 @@
#define WINDOW 50
-void move_list_sort_pv(std::vector<MoveE> &list, Stats &stats, Move best) {
- for (MoveE &move : list) {
- if (move_cmp(best, move.move)) {
- move.score = 30000;
- return;
- }
- }
-
- if (stats.ply && stats.follow_pv) {
- stats.follow_pv = 0;
- for (MoveE &move : list) {
- if (move_cmp(stats.pv_table[0][stats.ply], move.move)) {
- move.score = 20000;
- stats.follow_pv = 1;
- break;
- }
- }
- }
-}
-
/* SEARCHING */
int evaluate(const Board &board) {
@@ -65,13 +46,11 @@ int evaluate(const Board &board) {
return score;
}
-int is_repetition() {
- return 0;
-}
+int is_repetition() { return 0; }
int stats_move_make(Stats &stats, Board ©, Move move, int flag) {
copy = stats.board;
- if (!move_make(move, stats.board, flag)) {
+ if (!move.make(stats.board, flag)) {
stats.board = copy;
return 0;
}
@@ -110,12 +89,20 @@ int quiescence(Stats &stats, int alpha, int beta) {
if (score > alpha) alpha = score;
Board copy;
- std::vector<MoveE> list = move_list_generate(stats.board);
- Score_move_list(stats, list);
- move_list_sort_pv(list, stats, {0});
- move_list_sort(list);
+ bool pv_flag = false;
+ const auto score_move = [&stats, &pv_flag](Move move) -> U32 {
+ if (stats.ply && stats.follow_pv) {
+ stats.follow_pv = 0;
+ if (stats.pv_table[0][stats.ply] == move) {
+ pv_flag = true;
+ return 20000;
+ }
+ }
+ return Score_move(stats, move);
+ };
+ stats.follow_pv = pv_flag;
- for (const auto [move, _] : list) {
+ for (const auto [move, _] : MoveList(stats.board, score_move)) {
if (!stats_move_make(stats, copy, move, 1)) continue;
score = -quiescence(stats, -beta, -alpha);
stats_move_unmake(stats, copy);
@@ -133,8 +120,8 @@ int quiescence(Stats &stats, int alpha, int beta) {
int negamax(Stats &stats, int alpha, int beta, int depth, bool null) {
int pv_node = (beta - alpha) > 1;
HasheFlag flag = HasheFlag::Alpha;
- Move bestMove = {0};
int futility = 0;
+ Move bestMove;
Board copy;
stats.pv_length[stats.ply] = stats.ply;
@@ -196,19 +183,28 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) {
if (depth < 4 && abs(alpha) < MATE_SCORE && staticEval + margin[depth] <= alpha) futility = 1;
}
- std::vector<MoveE> list = move_list_generate(stats.board);
- Score_move_list(stats, list);
- move_list_sort_pv(list, stats, bestMove);
- move_list_sort(list);
+ bool pv_flag = false;
+ const auto score_move = [&stats, &bestMove, &pv_flag](Move move) -> U32 {
+ if (move == bestMove) return 30000;
+ if (stats.ply && stats.follow_pv) {
+ stats.follow_pv = 0;
+ if (stats.pv_table[0][stats.ply] == move) {
+ pv_flag = true;
+ return 20000;
+ }
+ }
+ return Score_move(stats, move);
+ };
+ stats.follow_pv = pv_flag;
int legal_moves = 0;
int searched = 0;
- for (const auto [move, _] : list) {
+ for (const auto [move, _] : MoveList(stats.board, score_move)) {
if (!stats_move_make(stats, copy, move, 0)) continue;
legal_moves++;
// futility pruning
- if (futility && searched && !move_capture(move) && !move_promote(move) && !stats.board.is_check()) {
+ if (futility && searched && !move.is_capture() && !move.is_promote() && !stats.board.is_check()) {
stats_move_unmake(stats, copy);
continue;
}
@@ -218,11 +214,11 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) {
} else {
// Late Move Reduction
if (!pv_node && searched >= FULL_DEPTH && depth >= REDUCTION_LIMIT && !isCheck &&
- !move_capture(move) && !move_promote(move) &&
- (move_source(move) != move_source(stats.killer[0][stats.ply]) ||
- move_target(move) != move_target(stats.killer[0][stats.ply])) &&
- (move_source(move) != move_source(stats.killer[1][stats.ply]) ||
- move_target(move) != move_target(stats.killer[1][stats.ply]))) {
+ !move.is_capture() && !move.is_promote() &&
+ (move.source() != stats.killer[0][stats.ply].source() ||
+ move.target() != stats.killer[0][stats.ply].target()) &&
+ (move.source() != stats.killer[1][stats.ply].source() ||
+ move.target() != stats.killer[1][stats.ply].target())) {
score = -negamax(stats, -alpha - 1, -alpha, depth - 2, true);
} else
score = alpha + 1;
@@ -242,8 +238,8 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) {
searched++;
if (score > alpha) {
- if (!move_capture(move)) {
- stats.history[move_piece(move).index][move_target(move)] += depth;
+ if (!move.is_capture()) {
+ stats.history[move.piece().index][to_underlying(move.target())] += depth;
}
alpha = score;
@@ -254,7 +250,7 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) {
if (score >= beta) {
stats.ttable.write(stats, bestMove, beta, depth, HasheFlag::Beta);
- if (!move_capture(move)) {
+ if (!move.is_capture()) {
stats.killer[1][stats.ply] = stats.killer[0][stats.ply];
stats.killer[0][stats.ply] = move;
}
@@ -276,23 +272,22 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) {
}
void move_print_UCI(Move move) {
- printf("%s%s", square_to_coordinates(static_cast<Square>(move_source(move))),
- square_to_coordinates(static_cast<Square>(move_target(move))));
- if (move_promote(move)) printf("%c", (move_piece_promote(move).code));
+ std::cout << square_to_coordinates(move.source()) << square_to_coordinates(move.target());
+ if (move.is_promote()) std::cout << move.piece_promote().code;
}
TTable ttable(C64(0x400000));
void search_position(Board &board, int depth) {
- Stats stats = {ttable, board, 0};
+ Stats stats = {ttable, board};
- int alpha = -INFINITY, beta = INFINITY;
+ int alpha = -SCORE_INFINITY, beta = SCORE_INFINITY;
for (int crnt = 1; crnt <= depth;) {
stats.follow_pv = 1;
int score = negamax(stats, alpha, beta, crnt, true);
if ((score <= alpha) || (score >= beta)) {
- alpha = -INFINITY;
- beta = INFINITY;
+ alpha = -SCORE_INFINITY;
+ beta = SCORE_INFINITY;
continue;
}
alpha = score - WINDOW;
@@ -300,27 +295,28 @@ void search_position(Board &board, int depth) {
if (stats.pv_length[0]) {
if (score > -MATE_VALUE && score < -MATE_SCORE) {
- printf("info score mate %d depth %d nodes %ld pv ", -(score + MATE_VALUE) / 2 - 1, crnt,
- stats.nodes);
+ std::cout << "info score mate " << -(score + MATE_VALUE) / 2 - 1;
} else if (score > MATE_SCORE && score < MATE_VALUE) {
- printf("info score mate %d depth %d nodes %ld pv ", (MATE_VALUE - score) / 2 + 1, crnt,
- stats.nodes);
+ std::cout << "info score mate " << (MATE_VALUE - score) / 2 + 1;
} else {
- printf("info score cp %d depth %d nodes %ld pv ", score, crnt, stats.nodes);
+ std::cout << "info score " << score;
}
+ std::cout << " depth " << crnt;
+ std::cout << " nodes " << stats.nodes;
+ std::cout << " pv ";
for (int i = 0; i < stats.pv_length[0]; i++) {
move_print_UCI(stats.pv_table[0][i]);
- printf(" ");
+ std::cout << " ";
}
- printf("\n");
+ std::cout << "\n";
}
crnt++;
}
- printf("bestmove ");
+ std::cout << "bestmove ";
move_print_UCI(stats.pv_table[0][0]);
- printf("\n");
+ std::cout << "\n";
}
void print_info(void) {
@@ -354,9 +350,7 @@ void Instruction_free(Instruction **p) {
delete (*p);
}
-char *Instruction_token(Instruction *self) {
- return self->token;
-}
+char *Instruction_token(Instruction *self) { return self->token; }
char *Instruction_token_n(Instruction *self, int n) {
while (isspace(*self->crnt) && *self->crnt != '\0')
self->crnt++;
@@ -382,28 +376,21 @@ char *Instruction_token_n(Instruction *self, int n) {
return self->token;
}
-char *Instruction_token_next(Instruction *self) {
- return Instruction_token_n(self, 1);
-}
-
-Move parse_move(Board &board, char *move_string) {
- Move result = {0};
+char *Instruction_token_next(Instruction *self) { return Instruction_token_n(self, 1); }
- uint8_t source = to_underlying(square_from_coordinates(move_string));
- uint8_t target = to_underlying(square_from_coordinates(move_string + 2));
+Move parse_move(const Board &board, char *move_string) {
+ Square source = square_from_coordinates(move_string);
+ Square target = square_from_coordinates(move_string + 2);
- std::vector<MoveE> list = move_list_generate(board);
- for (const auto [move, _] : list) {
- if (move_source(move) == source && move_target(move) == target) {
+ for (const auto [move, _] : MoveList(board)) {
+ if (move.source() == source && move.target() == target) {
if (move_string[4]) {
- if (tolower(move_piece_promote(move).code) != move_string[4]) continue;
+ if (tolower(move.piece_promote().code) != move_string[4]) continue;
}
- result = move;
- break;
+ return move;
}
}
-
- return result;
+ return {};
}
Board *Instruction_parse(Instruction *self, Board &board) {
@@ -434,8 +421,8 @@ Board *Instruction_parse(Instruction *self, Board &board) {
if (strcmp(token, "moves") == 0) {
while ((token = Instruction_token_next(self))) {
Move move = parse_move(board, token);
- if (!move_cmp(move, {0})) {
- move_make(move, board, 0);
+ if (move == Move()) {
+ move.make(board, 0);
} else {
printf("Invalid move %s!\n", token);
}
diff --git a/src/engine/score.cpp b/src/engine/score.cpp
@@ -1,5 +1,5 @@
#include "score.hpp"
-#include "moves.hpp"
+#include "move.hpp"
#include "stats.hpp"
#include "utils_cpp.hpp"
@@ -98,33 +98,26 @@ const Square mirror_score[128] =
};
// clang-format on
-int Score_value(piece::Type piece) {
- return Scores[to_underlying(piece)].value;
-}
+int Score_value(piece::Type piece) { return Scores[to_underlying(piece)].value; }
int Score_position(piece::Type piece, Color color, Square square) {
if (color == Color::BLACK) square = mirror_score[to_underlying(square)];
return Scores[to_underlying(piece)].position[to_underlying(square)];
}
-int Score_move(const Stats &stats, Move move) {
- const int piece = to_underlying(move_piece(move).type);
- const int capture = to_underlying(move_piece_capture(move).type);
-
- if (move_capture(move)) {
- return Scores[piece].capture[capture] + 10000;
- }
+U32 Score_move(const Stats &stats, Move move) {
+ const int piece = to_underlying(move.piece().type);
+ const int capture = to_underlying(move.piece_capture().type);
- if (move_cmp(stats.killer[0][stats.ply], move))
- return 9000;
- else if (move_cmp(stats.killer[1][stats.ply], move))
- return 8000;
+ if (move.is_capture()) return Scores[piece].capture[capture] + 10000;
+ if (stats.killer[0][stats.ply] == move) return 9000;
+ if (stats.killer[1][stats.ply] == move) return 8000;
- return stats.history[piece][move_target(move)];
+ return stats.history[piece][to_underlying(move.target())];
}
-void Score_move_list(const Stats &stats, std::vector<MoveE> &list) {
- for (MoveE &move : list) {
- move.score = Score_move(stats, move.move);
+void Score_move_list(const Stats &stats, MoveList &list) {
+ for (auto &moveE : list) {
+ moveE.score = Score_move(stats, moveE.move);
}
}
diff --git a/src/engine/score.hpp b/src/engine/score.hpp
@@ -2,14 +2,15 @@
#define STELLAR_SCORE_H
#include "board.hpp"
-#include "moves.hpp"
+#include "movelist.hpp"
#include "stats.hpp"
-#define INFINITY 50000
+#define SCORE_INFINITY 50000
#define MATE_VALUE 49000
#define MATE_SCORE 48000
-void Score_move_list(const Stats &stats, std::vector<MoveE> &list);
+U32 Score_move(const Stats &stats, Move move);
+void Score_move_list(const Stats &stats, MoveList &list);
int Score_position(piece::Type piece, Color color, Square square);
int Score_capture(piece::Type src, piece::Type tgt);
int Score_value(piece::Type piece);
diff --git a/src/engine/stats.hpp b/src/engine/stats.hpp
@@ -1,7 +1,7 @@
#ifndef STELLAR_STATS_H
#define STELLAR_STATS_H
-#include "moves.hpp"
+#include "move.hpp"
#include "utils_cpp.hpp"
#define MAX_PLY 64
diff --git a/src/engine/transposition.hpp b/src/engine/transposition.hpp
@@ -1,7 +1,7 @@
#ifndef STELLAR_TRANSPOSITION_H
#define STELLAR_TRANSPOSITION_H
-#include "moves.hpp"
+#include "move.hpp"
#include "stats.hpp"
#include "utils_cpp.hpp"
@@ -28,12 +28,9 @@ struct Hashe {
class TTable {
public:
- TTable(U64 size) : table(size, {0}) {
- }
+ TTable(U64 size) : table(size, {0}) {}
- void clear() {
- table.clear();
- };
+ void clear() { table.clear(); };
void write(const Stats &stats, Move best, int score, int depth, HasheFlag flag);
int read(const Stats &stats, Move *best, int alpha, int beta, int depth) const;
diff --git a/src/include/attack.hpp b/src/include/attack.hpp
@@ -50,9 +50,7 @@ class SliderRook : public Slider {
return (key * rook_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]);
}
- virtual constexpr U64 mask(Square square) const override {
- return masks[to_underlying(square)];
- }
+ virtual constexpr U64 mask(Square square) const override { return masks[to_underlying(square)]; }
virtual constexpr U64 mask_fly(Square square, U64 block) const override {
uint8_t square_i = to_underlying(square);
@@ -98,9 +96,7 @@ class SliderBishop : public Slider {
return (key * bishop_magic_numbers[square_i]) >> (64 - relevant_bits[square_i]);
}
- virtual constexpr U64 mask(Square square) const override {
- return masks[to_underlying(square)];
- }
+ virtual constexpr U64 mask(Square square) const override { return masks[to_underlying(square)]; }
virtual constexpr U64 mask_fly(Square square, U64 block) const override {
uint8_t square_i = to_underlying(square);
@@ -197,8 +193,7 @@ class Bishop : public Attack {
class King : public Attack {
public:
- constexpr King() {
- }
+ constexpr King() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
@@ -229,8 +224,7 @@ class King : public Attack {
class Knight : public Attack {
public:
- constexpr Knight() {
- }
+ constexpr Knight() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
@@ -264,8 +258,7 @@ class Knight : public Attack {
class PawnW : public Attack {
public:
- constexpr PawnW() {
- }
+ constexpr PawnW() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
@@ -290,8 +283,7 @@ class PawnW : public Attack {
class PawnB : public Attack {
public:
- constexpr PawnB() {
- }
+ constexpr PawnB() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return attacks[to_underlying(square)];
@@ -323,8 +315,7 @@ inline constexpr const PawnB pawnB;
class Queen : public Attack {
public:
- constexpr Queen() {
- }
+ constexpr Queen() {}
virtual constexpr U64 operator()(Square square, U64 occupancy) const override {
return rook(square, occupancy) | bishop(square, occupancy);
diff --git a/src/include/board.hpp b/src/include/board.hpp
@@ -17,8 +17,7 @@ class Board {
BQ = 8
};
- Board() {
- }
+ Board() {}
Board(const std::string &fen);
friend std::ostream &operator<<(std::ostream &os, const Board &board);
@@ -39,6 +38,8 @@ class Board {
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;
Color get_square_piece_color(Square square) const;
piece::Type get_square_piece_type(Square square) const;
@@ -64,6 +65,7 @@ class Board {
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_check(void) const;
private:
diff --git a/src/include/move.hpp b/src/include/move.hpp
@@ -0,0 +1,57 @@
+#ifndef STELLAR_MOVES_H
+#define STELLAR_MOVES_H
+
+#include "board.hpp"
+#include "piece.hpp"
+#include "utils_cpp.hpp"
+
+#include <iostream>
+#include <vector>
+
+struct Move {
+ Move(){};
+
+ 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) {
+ }
+
+ bool operator==(const Move &m) const = default;
+
+ 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; }
+ bool is_promote(void) const { return promote; }
+
+ 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); }
+
+ bool make(Board &board, bool attack_only) const;
+
+ friend std::ostream &operator<<(std::ostream &os, const Move &Move);
+
+ private:
+ void piece_remove(Board &board, const piece::Piece &piece, Square square) const;
+ void piece_set(Board &board, const piece::Piece &piece, Square square) const;
+ void piece_move(Board &board, const piece::Piece &piece, 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;
+ bool dbl : 1;
+ bool enpassant : 1;
+ bool castle : 1;
+ bool capture : 1;
+ bool promote : 1;
+};
+
+#endif
diff --git a/src/include/movelist.hpp b/src/include/movelist.hpp
@@ -0,0 +1,62 @@
+#ifndef STELLAR_MOVE_LIST_H
+#define STELLAR_MOVE_LIST_H
+
+#include "board.hpp"
+#include "move.hpp"
+#include "utils_cpp.hpp"
+
+#include <functional>
+#include <iostream>
+#include <vector>
+
+class MoveList {
+ public:
+ typedef std::function<U32(const Move &)> score_f;
+ struct MoveListE {
+ Move move;
+ U32 score;
+
+ auto operator<=>(const MoveListE &mle) { return mle.score <=> score; }
+ };
+
+ private:
+ using list_t = std::vector<MoveListE>;
+
+ public:
+ MoveList(const Board &board, score_f score = nullptr) : list(), score_move(score) {
+ list.reserve(256);
+ generate(board);
+ sort(list.begin(), list.end());
+ }
+
+ auto size() const { return list.size(); }
+
+ MoveListE &operator[](size_t idx) { return list[idx]; }
+ const MoveListE &operator[](size_t idx) const { return list[idx]; }
+
+ friend std::ostream &operator<<(std::ostream &os, const MoveList &list);
+
+ using iterator = list_t::iterator;
+ using const_iterator = list_t::const_iterator;
+
+ iterator begin() { return list.begin(); }
+ iterator end() { return list.end(); }
+
+ const_iterator begin() const { return list.begin(); }
+ const_iterator end() const { return list.end(); }
+ const_iterator cbegin() const { return list.cbegin(); }
+ const_iterator cend() const { return list.cend(); }
+
+ private:
+ void push_back(const MoveListE &&mle) { list.push_back(mle); }
+ void push_back(const Move &&move) { push_back({move, score_move ? score_move(move) : 0}); }
+
+ void generate(const Board &board);
+
+ void clear() { list.clear(); }
+
+ list_t list;
+ score_f score_move;
+};
+
+#endif
diff --git a/src/include/moves.hpp b/src/include/moves.hpp
@@ -1,49 +0,0 @@
-#ifndef STELLAR_MOVES_H
-#define STELLAR_MOVES_H
-
-#include "board.hpp"
-#include "piece.hpp"
-
-#include <iostream>
-#include <vector>
-
-struct Move {
- unsigned source : 6;
- unsigned target : 6;
- unsigned piece : 5;
- unsigned piece_capture : 5;
- unsigned piece_promote : 5;
- bool dbl : 1;
- bool enpassant : 1;
- bool castle : 1;
- bool capture : 1;
- bool promote : 1;
-
- friend std::ostream &operator<<(std::ostream &os, const Move &Move);
-};
-
-struct MoveE {
- Move move;
- int score;
-};
-
-Move move_encode(uint8_t src, uint8_t tgt, const piece::Piece *piece, const piece::Piece *capture,
- const piece::Piece *promote, bool dbl, bool enpassant, bool castle);
-std::vector<MoveE> move_list_generate(const Board &board);
-int move_make(Move move, Board &board, int flag);
-void move_list_sort(std::vector<MoveE> &list);
-int move_cmp(Move a, Move b);
-
-#define move_source(move) (move.source)
-#define move_target(move) (move.target)
-#define move_double(move) (move.dbl)
-#define move_enpassant(move) (move.enpassant)
-#define move_castle(move) (move.castle)
-#define move_capture(move) (move.capture)
-#define move_promote(move) (move.promote)
-
-#define move_piece(move) (piece::get_from_index(move.piece))
-#define move_piece_capture(move) (piece::get_from_index(move.piece_capture))
-#define move_piece_promote(move) (piece::get_from_index(move.piece_promote))
-
-#endif
diff --git a/src/include/piece.hpp b/src/include/piece.hpp
@@ -21,9 +21,7 @@ typedef Iterator<Type, Type::PAWN, Type::KING> TypeIter;
class Piece {
public:
- constexpr U64 operator()(Square square, U64 occupancy) const {
- return attack(square, occupancy);
- }
+ constexpr U64 operator()(Square square, U64 occupancy) const { return attack(square, occupancy); }
const Type type;
const Color color;
@@ -34,8 +32,7 @@ class Piece {
protected:
constexpr Piece(Type type, Color color, char code, const char *symbol, const attack::Attack &attack)
: type(type), color(color), code(code), symbol(symbol), index(index_calc(color, type)),
- attack(attack) {
- }
+ attack(attack) {}
constexpr uint8_t index_calc(Color color, Type type) {
return to_underlying(color) * 6 + to_underlying(type);
@@ -50,48 +47,42 @@ class Pawn : public Piece {
constexpr Pawn(Color color)
: Piece(Type::PAWN, color, color == Color::WHITE ? 'P' : 'p', color == Color::WHITE ? "■ " : "■ ",
color == Color::WHITE ? *(attack::Attack *)&attack::pawnW
- : *(attack::Attack *)&attack::pawnB) {
- }
+ : *(attack::Attack *)&attack::pawnB) {}
};
class Knight : public Piece {
public:
constexpr Knight(Color color)
: Piece(Type::KNIGHT, color, color == Color::WHITE ? 'N' : 'n', color == Color::WHITE ? "■ " : "■ ",
- attack::knight) {
- }
+ attack::knight) {}
};
class Bishop : public Piece {
public:
constexpr Bishop(Color color)
: Piece(Type::BISHOP, color, color == Color::WHITE ? 'B' : 'b', color == Color::WHITE ? "■ " : "■ ",
- attack::bishop) {
- }
+ attack::bishop) {}
};
class Rook : public Piece {
public:
constexpr Rook(Color color)
: Piece(Type::ROOK, color, color == Color::WHITE ? 'R' : 'r', color == Color::WHITE ? "■ " : "■ ",
- attack::rook) {
- }
+ attack::rook) {}
};
class Queen : public Piece {
public:
constexpr Queen(Color color)
: Piece(Type::QUEEN, color, color == Color::WHITE ? 'Q' : 'q', color == Color::WHITE ? "■ " : "■ ",
- attack::queen) {
- }
+ attack::queen) {}
};
class King : public Piece {
public:
constexpr King(Color color)
: Piece(Type::KING, color, color == Color::WHITE ? 'K' : 'k', color == Color::WHITE ? "■ " : "■ ",
- attack::king) {
- }
+ attack::king) {}
};
const constexpr Piece table[2][6] = {
@@ -116,9 +107,7 @@ constexpr const Piece &get_from_code(char code) {
throw std::exception();
}
-constexpr const Piece &get_from_index(uint8_t index) {
- return table[index / 6][index % 6];
-}
+constexpr const Piece &get_from_index(uint8_t index) { return table[index / 6][index % 6]; }
} // namespace piece
diff --git a/src/include/random.hpp b/src/include/random.hpp
@@ -5,18 +5,12 @@
class Random {
public:
- constexpr Random(void) {
- }
- constexpr Random(U64 seed) : state(seed) {
- }
+ constexpr Random(void) {}
+ constexpr Random(U64 seed) : state(seed) {}
- constexpr U64 operator()(void) {
- return get_U64();
- }
+ constexpr U64 operator()(void) { return get_U64(); }
- constexpr void reset(void) {
- state = seed;
- }
+ constexpr void reset(void) { state = seed; }
constexpr U32 get_U32(void) {
U32 number = state;
diff --git a/src/include/utils_cpp.hpp b/src/include/utils_cpp.hpp
@@ -14,28 +14,20 @@ template <typename C, C beginVal, C endVal> class Iterator {
int val;
public:
- constexpr Iterator(const C &f) : val(static_cast<val_t>(f)) {
- }
- constexpr Iterator() : val(static_cast<val_t>(beginVal)) {
- }
+ constexpr Iterator(const C &f) : val(static_cast<val_t>(f)) {}
+ constexpr Iterator() : val(static_cast<val_t>(beginVal)) {}
constexpr Iterator operator++() {
++val;
return *this;
}
- constexpr C operator*() {
- return static_cast<C>(val);
- }
- constexpr Iterator begin() {
- return *this;
- }
+ constexpr C operator*() { return static_cast<C>(val); }
+ constexpr Iterator begin() { return *this; }
constexpr Iterator end() {
// static const Iterator endIter = ++Iterator(endVal);
// return endIter;
return ++Iterator(endVal);
}
- constexpr bool operator!=(const Iterator &i) {
- return val != i.val;
- }
+ constexpr bool operator!=(const Iterator &i) { return val != i.val; }
};
#define C64(constantU64) constantU64##ULL
@@ -84,17 +76,11 @@ inline const char *square_to_coordinates(Square square) {
// clang-format on
// useful bit functions
-constexpr bool bit_get(const U64 &bitboard, uint8_t square) {
- return (bitboard >> (square)) & C64(1);
-}
+constexpr bool bit_get(const U64 &bitboard, uint8_t square) { return (bitboard >> (square)) & C64(1); }
-constexpr void bit_set(U64 &bitboard, uint8_t square) {
- bitboard |= (C64(1) << square);
-}
+constexpr void bit_set(U64 &bitboard, uint8_t square) { bitboard |= (C64(1) << square); }
-constexpr void bit_pop(U64 &bitboard, uint8_t square) {
- bitboard &= ~(C64(1) << (square));
-}
+constexpr void bit_pop(U64 &bitboard, uint8_t square) { bitboard &= ~(C64(1) << (square)); }
constexpr uint8_t bit_count(U64 bitboard) {
#if __has_builtin(__builtin_popcountll)
@@ -127,30 +113,14 @@ inline constexpr const U64 notAFile = C64(0xfefefefefefefefe);
inline constexpr const U64 notHFile = C64(0x7f7f7f7f7f7f7f7f);
typedef U64 (*direction_f)(U64);
-inline constexpr U64 soutOne(U64 b) {
- return b >> 8;
-}
-inline constexpr U64 nortOne(U64 b) {
- return b << 8;
-}
-inline constexpr U64 eastOne(U64 b) {
- return (b & notHFile) << 1;
-}
-inline constexpr U64 westOne(U64 b) {
- return (b & notAFile) >> 1;
-}
-inline constexpr U64 soEaOne(U64 b) {
- return (b & notHFile) >> 7;
-}
-inline constexpr U64 soWeOne(U64 b) {
- return (b & notAFile) >> 9;
-}
-inline constexpr U64 noEaOne(U64 b) {
- return (b & notHFile) << 9;
-}
-inline constexpr U64 noWeOne(U64 b) {
- return (b & notAFile) << 7;
-}
+inline constexpr U64 soutOne(U64 b) { return b >> 8; }
+inline constexpr U64 nortOne(U64 b) { return b << 8; }
+inline constexpr U64 eastOne(U64 b) { return (b & notHFile) << 1; }
+inline constexpr U64 westOne(U64 b) { return (b & notAFile) >> 1; }
+inline constexpr U64 soEaOne(U64 b) { return (b & notHFile) >> 7; }
+inline constexpr U64 soWeOne(U64 b) { return (b & notAFile) >> 9; }
+inline constexpr U64 noEaOne(U64 b) { return (b & notHFile) << 9; }
+inline constexpr U64 noWeOne(U64 b) { return (b & notAFile) << 7; }
#define start_position "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 "
diff --git a/src/include/zobrist.hpp b/src/include/zobrist.hpp
@@ -13,17 +13,11 @@ class Zobrist {
public:
Zobrist() = delete;
- static inline constexpr U64 key_side(void) {
- return keys_side;
- }
+ 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_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_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)];
diff --git a/src/move/CMakeLists.txt b/src/move/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_library(moves OBJECT
+ move.cpp
+ movelist.cpp
+)
+
+target_include_directories(moves
+ PUBLIC "${PROJECT_SOURCE_DIR}/src/include"
+)
diff --git a/src/move/move.cpp b/src/move/move.cpp
@@ -0,0 +1,105 @@
+#include "move.hpp"
+#include "utils_cpp.hpp"
+#include "zobrist.hpp"
+
+#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_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_move(Board &board, const piece::Piece &piece, Square source, Square target) const {
+ piece_remove(board, piece, source);
+ piece_set(board, piece, target);
+}
+
+bool Move::make(Board &board, bool attack_only) const {
+ static constexpr const int castling_rights[64] = {
+ // clang-format off
+ 13, 15, 15, 15, 12, 15, 15, 14,
+ 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15,
+ 7, 15, 15, 15, 3, 15, 15, 11,
+ // clang-format on
+ };
+
+ if (attack_only) {
+ if (is_capture()) return make(board, false);
+ return 0;
+ } else {
+ const piece::Piece &piece = this->piece();
+ const Color color = board.get_side();
+ 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));
+
+ if (!is_capture()) {
+ if (is_promote()) {
+ piece_remove(board, piece, source);
+ piece_set(board, piece_promote(), target);
+ } else {
+ piece_move(board, piece, source, target);
+ }
+ } else {
+ if (is_enpassant()) {
+ piece_move(board, piece, source, target);
+ piece_remove(board, piece_capture(), ntarget);
+ } else if (is_promote()) {
+ piece_remove(board, piece, source);
+ piece_remove(board, piece_capture(), target);
+ piece_set(board, piece_promote(), target);
+ } else {
+ piece_remove(board, piece_capture(), target);
+ piece_move(board, piece, 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);
+ }
+
+ board.xor_hash(Zobrist::key_castle(board.get_castle()));
+ board.and_castle(castling_rights[to_underlying(this->source())]);
+ board.and_castle(castling_rights[to_underlying(this->target())]);
+ board.xor_hash(Zobrist::key_castle(board.get_castle()));
+
+ if (!board.is_check()) {
+ board.switch_side();
+ return 1;
+ }
+ return 0;
+ }
+}
+
+std::ostream &operator<<(std::ostream &os, const 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 << move.is_double() << " ";
+ os << move.is_enpassant() << " ";
+ os << move.is_castle();
+
+ return os;
+}
diff --git a/src/move/movelist.cpp b/src/move/movelist.cpp
@@ -0,0 +1,120 @@
+#include "movelist.hpp"
+
+#define pawn_canPromote(color, source) \
+ ((color == Color::WHITE && source >= Square::a7 && source <= Square::h7) || \
+ (color == Color::BLACK && source >= Square::a2 && source <= Square::h2))
+
+#define pawn_onStart(color, source) \
+ ((color == Color::BLACK && source >= Square::a7 && source <= Square::h7) || \
+ (color == Color::WHITE && source >= Square::a2 && source <= Square::h2))
+
+void MoveList::generate(const Board &board) {
+ this->clear();
+
+ uint8_t src_i, tgt_i;
+
+ Color color = board.get_side();
+ 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);
+ 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)) {
+ push_back(Move(src, tgt, &pawn, nullptr, &piece::get(piece::Type::KNIGHT, color), 0, 0, 0));
+ push_back(Move(src, tgt, &pawn, nullptr, &piece::get(piece::Type::BISHOP, color), 0, 0, 0));
+ push_back(Move(src, tgt, &pawn, nullptr, &piece::get(piece::Type::ROOK, color), 0, 0, 0));
+ push_back(Move(src, tgt, &pawn, nullptr, &piece::get(piece::Type::QUEEN, color), 0, 0, 0));
+ } else {
+ push_back(Move(src, tgt, &pawn, 0, 0, 0, 0, 0));
+
+ // two ahead
+ const Square tgt = static_cast<Square>(tgt_i + add);
+ if (pawn_onStart(color, src) && !board.is_square_occupied(tgt))
+ push_back(Move(src, tgt, &pawn, 0, 0, 1, 0, 0));
+ }
+ }
+
+ // capture
+ U64 attack = board.get_bitboard_piece_attacks(pawn, 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);
+ if (pawn_canPromote(color, src)) {
+ push_back(Move(src, tgt, &pawn, capture, &piece::get(piece::Type::KNIGHT, color), 0, 0, 0));
+ push_back(Move(src, tgt, &pawn, capture, &piece::get(piece::Type::BISHOP, color), 0, 0, 0));
+ push_back(Move(src, tgt, &pawn, capture, &piece::get(piece::Type::ROOK, color), 0, 0, 0));
+ push_back(Move(src, tgt, &pawn, capture, &piece::get(piece::Type::QUEEN, color), 0, 0, 0));
+ } else {
+ push_back(Move(src, tgt, &pawn, capture, 0, 0, 0, 0));
+ }
+ }
+
+ // en passant
+ const Square enpassant = board.get_enpassant();
+ if (enpassant != Square::no_sq && board.is_piece_attack_square(pawn, src, enpassant))
+ push_back(Move(src, enpassant, &pawn, &piece::get(piece::Type::PAWN, colorOther), 0, 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);
+ bitboard_for_each_bit(src_i, bitboard) {
+ const Square src = static_cast<Square>(src_i);
+ U64 attack = board.get_bitboard_piece_moves(piece, src);
+ bitboard_for_each_bit(tgt_i, attack) {
+ const Square tgt = static_cast<Square>(tgt_i);
+ push_back(Move(src, tgt, &piece, board.get_square_piece(tgt), 0, 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))
+ push_back(Move(Square::e1, Square::g1, &piece, 0, 0, 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))
+ push_back(Move(Square::e1, Square::c1, &piece, 0, 0, 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))
+ push_back(Move(Square::e8, Square::g8, &piece, 0, 0, 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))
+ push_back(Move(Square::e8, Square::c8, &piece, 0, 0, 0, 0, 1));
+ }
+ }
+ }
+}
+
+std::ostream &operator<<(std::ostream &os, const MoveList &list) {
+ os << "Size: " << list.list.size();
+ for (const auto &moveE : list.list) {
+ os << moveE.score << ": " << moveE.move << "\n";
+ }
+ return os;
+}
diff --git a/src/moves/CMakeLists.txt b/src/moves/CMakeLists.txt
@@ -1,9 +0,0 @@
-add_library(moves OBJECT
- moves.cpp
- moves_make.cpp
- moves_generate.cpp
-)
-
-target_include_directories(moves
- PUBLIC "${PROJECT_SOURCE_DIR}/src/include"
-)
diff --git a/src/moves/moves.cpp b/src/moves/moves.cpp
@@ -1,51 +0,0 @@
-#include "moves.hpp"
-#include "utils_cpp.hpp"
-
-#include <algorithm>
-#include <iomanip>
-
-int move_cmp(Move a, Move b) {
- return *(uint32_t *)&a == *(uint32_t *)&b;
-}
-
-Move move_encode(uint8_t src, uint8_t tgt, const piece::Piece *piece, const piece::Piece *capture,
- const piece::Piece *promote, bool dbl, bool enpassant, bool castle) {
- return {
- .source = src,
- .target = tgt,
- .piece = piece->index,
- .piece_capture = capture ? capture->index : 0u,
- .piece_promote = promote ? promote->index : 0u,
- .dbl = dbl,
- .enpassant = enpassant,
- .castle = castle,
- .capture = capture != NULL,
- .promote = promote != NULL,
- };
-}
-
-void move_list_sort(std::vector<MoveE> &list) {
- std::sort(list.begin(), list.end(), [](const MoveE &a, const MoveE &b) { return a.score < b.score; });
-}
-
-void move_list_print(const std::vector<MoveE> &list) {
- printf("Score From To Pi Cap Prmt Dbl Enp Cst C P\n");
- for (const MoveE &move : list) {
- printf("%5d: ", move.score);
- // move_print(move.move);
- }
- printf("Total: %lu\n", list.size());
-}
-
-std::ostream &operator<<(std::ostream &os, const Move &move) {
- os << square_to_coordinates(static_cast<Square>(move_source(move))) << " ";
- os << square_to_coordinates(static_cast<Square>(move_target(move))) << " ";
- os << move_piece(move).code << " ";
- os << (move_capture(move) ? move_piece_capture(move).code : '.') << " ";
- os << (move_promote(move) ? move_piece_promote(move).code : '.') << " ";
- os << move_double(move) << " ";
- os << move_enpassant(move) << " ";
- os << move_castle(move);
-
- return os;
-}
diff --git a/src/moves/moves_generate.cpp b/src/moves/moves_generate.cpp
@@ -1,137 +0,0 @@
-#include "board.hpp"
-#include "moves.hpp"
-#include "piece.hpp"
-#include "utils_cpp.hpp"
-
-#define pawn_canPromote(color, source) \
- ((color == Color::WHITE && source >= Square::a7 && source <= Square::h7) || \
- (color == Color::BLACK && source >= Square::a2 && source <= Square::h2))
-
-#define pawn_onStart(color, source) \
- ((color == Color::BLACK && source >= Square::a7 && source <= Square::h7) || \
- (color == Color::WHITE && source >= Square::a2 && source <= Square::h2))
-
-#define pawn_promote(source, target, piece, capture) \
- res.push_back( \
- {move_encode(source, target, &piece, capture, &piece::get(piece::Type::KNIGHT, color), 0, 0, 0), \
- 0}); \
- res.push_back( \
- {move_encode(source, target, &piece, capture, &piece::get(piece::Type::BISHOP, color), 0, 0, 0), \
- 0}); \
- res.push_back( \
- {move_encode(source, target, &piece, capture, &piece::get(piece::Type::ROOK, color), 0, 0, 0), 0}); \
- res.push_back( \
- {move_encode(source, target, &piece, capture, &piece::get(piece::Type::QUEEN, color), 0, 0, 0), 0});
-
-std::vector<MoveE> move_list_generate(const Board &board) {
- uint8_t src_i, tgt_i;
-
- Color color = board.get_side();
- Color colorOther = color == Color::BLACK ? Color::WHITE : Color::BLACK;
-
- std::vector<MoveE> res;
- res.reserve(256);
-
- // pawn moves
- const piece::Piece &piece = piece::get(piece::Type::PAWN, color);
- U64 bitboard = board.get_bitboard_piece(piece);
- bitboard_for_each_bit(src_i, bitboard) {
- // quiet
- int add = (color == Color::WHITE) ? +8 : -8;
- tgt_i = src_i + add;
- Square src = static_cast<Square>(src_i);
- Square tgt = static_cast<Square>(tgt_i);
- if (!board.is_square_occupied(tgt)) {
- if (pawn_canPromote(color, src)) {
- pawn_promote(src_i, tgt_i, piece, nullptr);
- } else {
- res.push_back({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);
- } else {
- res.push_back({move_encode(src_i, tgt_i, &piece, capture, 0, 0, 0, 0), 0});
- }
- }
-
- // en passant
- if (board.get_enpassant() != Square::no_sq &&
- board.get_bitboard_piece_attacks(piece, static_cast<Square>(src_i)) &
- (C64(1) << to_underlying(board.get_enpassant())))
- res.push_back({move_encode(src_i, to_underlying(board.get_enpassant()), &piece,
- &piece::get(piece::Type::PAWN, colorOther), 0, 0, 1, 0),
- 0});
- }
-
- // All piece move
- 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);
- 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) {
- Square tgt = static_cast<Square>(tgt_i);
- res.push_back(
- {move_encode(src_i, tgt_i, &piece, board.get_square_piece(tgt), 0, 0, 0, 0), 0});
- }
- }
- }
-
- // Castling
- if (color == 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) &&
- !board.is_square_attacked(Square::e1, Color::BLACK) &&
- !board.is_square_attacked(Square::f1, Color::BLACK))
- res.push_back(
- {move_encode(to_underlying(Square::e1), to_underlying(Square::g1), &piece, 0, 0, 0, 0, 1),
- 0});
- }
- 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::e1, Color::BLACK) &&
- !board.is_square_attacked(Square::d1, Color::BLACK))
- res.push_back(
- {move_encode(to_underlying(Square::e1), to_underlying(Square::c1), &piece, 0, 0, 0, 0, 1),
- 0});
- }
- } else {
- 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) &&
- !board.is_square_attacked(Square::e8, Color::WHITE) &&
- !board.is_square_attacked(Square::f8, Color::WHITE))
- res.push_back(
- {move_encode(to_underlying(Square::e8), to_underlying(Square::g8), &piece, 0, 0, 0, 0, 1),
- 0});
- }
- 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::e8, Color::WHITE) &&
- !board.is_square_attacked(Square::d8, Color::WHITE))
- res.push_back(
- {move_encode(to_underlying(Square::e8), to_underlying(Square::c8), &piece, 0, 0, 0, 0, 1),
- 0});
- }
- }
-
- res.resize(res.size());
- return res;
-}
diff --git a/src/moves/moves_make.cpp b/src/moves/moves_make.cpp
@@ -1,88 +0,0 @@
-#include "board.hpp"
-#include "moves.hpp"
-#include "zobrist.hpp"
-
-// clang-format off
-const int castling_rights[64] = {
- 13, 15, 15, 15, 12, 15, 15, 14,
- 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 15, 15, 15, 3, 15, 15, 11,
-};
-// clang-format on
-
-void _piece_remove(Board &board, const piece::Piece &piece, Square square) {
- board.pop_piece(piece, square);
- board.xor_hash(Zobrist::key_piece(piece, square));
-}
-
-void _piece_set(Board &board, const piece::Piece &piece, Square square) {
- board.set_piece(piece, square);
- board.xor_hash(Zobrist::key_piece(piece, square));
-}
-
-void _piece_move(Board &board, const piece::Piece &piece, Square source, Square target) {
- _piece_remove(board, piece, source);
- _piece_set(board, piece, target);
-}
-
-int move_make(Move move, Board &board, int flag) {
- if (flag) {
- if (move_capture(move)) return move_make(move, board, 0);
- return 0;
- } else {
- const piece::Piece &piece = move_piece(move);
- const Color color = board.get_side();
- const Square source = static_cast<Square>(move_source(move));
- const Square target = static_cast<Square>(move_target(move));
- const Square ntarget = static_cast<Square>(move_target(move) + (color == Color::WHITE ? -8 : +8));
-
- if (!move_capture(move)) {
- if (move_promote(move)) {
- _piece_remove(board, piece, source);
- _piece_set(board, move_piece_promote(move), target);
- } else {
- _piece_move(board, piece, source, target);
- }
- } else {
- if (move_enpassant(move)) {
- _piece_move(board, piece, source, target);
- _piece_remove(board, move_piece_capture(move), ntarget);
- } else if (move_promote(move)) {
- _piece_remove(board, piece, source);
- _piece_remove(board, move_piece_capture(move), target);
- _piece_set(board, move_piece_promote(move), target);
- } else {
- _piece_remove(board, piece, source);
- _piece_remove(board, move_piece_capture(move), target);
- _piece_set(board, piece, target);
- }
- }
-
- board.set_enpassant(move_double(move) ? ntarget : Square::no_sq);
-
- if (move_castle(move)) {
- 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);
- }
-
- board.xor_hash(Zobrist::key_castle(board.get_castle()));
- board.and_castle(castling_rights[move_source(move)]);
- board.and_castle(castling_rights[move_target(move)]);
- board.xor_hash(Zobrist::key_castle(board.get_castle()));
-
- if (!board.is_check()) {
- board.switch_side();
- return 1;
- }
- return 0;
- }
-}
diff --git a/src/perft/perft.cpp b/src/perft/perft.cpp
@@ -7,7 +7,8 @@
#include "attack.hpp"
#include "board.hpp"
-#include "moves.hpp"
+#include "move.hpp"
+#include "movelist.hpp"
#include "perft.hpp"
#include "utils_cpp.hpp"
#include "zobrist.hpp"
@@ -46,15 +47,11 @@ void perft_result_add(PerftResult *base, PerftResult *add) {
#endif
}
-typedef std::vector<MoveE> MoveList;
-
void perft_driver(Board &board, int depth, PerftResult *result) {
- MoveList moveList = move_list_generate(board);
Board copy;
-
- for (const auto [move, _] : moveList) {
+ for (const auto [move, _] : MoveList(board)) {
copy = board;
- if (!move_make(move, copy, 0)) continue;
+ if (!move.make(copy, 0)) continue;
if (depth != 1) {
perft_driver(copy, depth - 1, result);
@@ -62,10 +59,10 @@ void perft_driver(Board &board, int depth, PerftResult *result) {
result->node++;
#ifdef USE_FULL_COUNT
if (copy.is_check()) result->check++;
- if (move_capture(move)) result->capture++;
- if (move_enpassant(move)) result->enpassant++;
- if (move_castle(move)) result->castle++;
- if (move_promote(move)) result->promote++;
+ if (move.get_capture()) result->capture++;
+ if (move.get_enpassant()) result->enpassant++;
+ if (move.get_castle()) result->castle++;
+ if (move.get_promote()) result->promote++;
#endif
}
}
@@ -73,7 +70,7 @@ void perft_driver(Board &board, int depth, PerftResult *result) {
typedef struct perf_shared perf_shared;
struct perf_shared {
- MoveList list;
+ const MoveList &list;
int depth;
const char *fen;
pthread_mutex_t mutex;
@@ -99,7 +96,7 @@ void *perft_thread(void *arg) {
result = {0};
copy = board;
- if (!move_make(move, copy, 0)) continue;
+ if (!move.make(copy, 0)) continue;
if (shared->depth != 1) {
perft_driver(copy, shared->depth - 1, &result);
@@ -107,10 +104,10 @@ void *perft_thread(void *arg) {
result.node++;
#ifdef USE_FULL_COUNT
if (copy.is_check()) result.check++;
- if (move_capture(move)) result.capture++;
- if (move_enpassant(move)) result.enpassant++;
- if (move_castle(move)) result.castle++;
- if (move_promote(move)) result.promote++;
+ if (move.get_capture()) result.capture++;
+ if (move.get_enpassant()) result.enpassant++;
+ if (move.get_castle()) result.castle++;
+ if (move.get_promote()) result.promote++;
#endif
}
}
@@ -119,8 +116,10 @@ void *perft_thread(void *arg) {
PerftResult perft_test(const char *fen, int depth, int thread_num) {
pthread_t *threads = new pthread_t(thread_num);
+ MoveList *list = new MoveList(Board(fen));
+
perf_shared shared = {
- .list = move_list_generate(Board(fen)),
+ .list = *list,
.depth = depth,
.fen = fen,
};
@@ -132,6 +131,7 @@ PerftResult perft_test(const char *fen, int depth, int thread_num) {
for (int i = 0; i < thread_num; i++)
pthread_join(threads[i], NULL);
+ delete list;
delete threads;
return shared.result;
}