stellar

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

movelist.cpp (5720B)


0 #include "movelist.hpp"
1 #include "color.hpp"
2 #include "piece.hpp"
3 #include <iomanip>
5 #define pawn_canPromote(color, source) \
6 ((color == color::WHITE && source >= square::a7 && source <= square::h7) || \
7 (color == color::BLACK && source >= square::a2 && source <= square::h2))
9 #define pawn_onStart(color, source) \
10 ((color == color::BLACK && source >= square::a7 && source <= square::h7) || \
11 (color == color::WHITE && source >= square::a2 && source <= square::h2))
13 using piece::Type::PAWN;
15 void MoveList::generate(const Board &board, bool attacks_only) {
16 uint8_t src_i, tgt_i;
18 const color::Color color = board.get_side(), colorOther = color::other(color);
20 // pawn moves
21 const int add = (color == color::WHITE) ? +8 : -8;
23 U64 bitboard = board.get_bitboard_piece(PAWN, color);
24 bitboard_for_each_bit(src_i, bitboard) {
25 const square::Square src = static_cast<square::Square>(src_i);
26 const square::Square tgt = static_cast<square::Square>(tgt_i = src_i + add);
27 if (!attacks_only && !board.is_square_occupied(tgt)) {
28 if (pawn_canPromote(color, src)) {
29 list.push_back({src, tgt, Move::PKNIGHT});
30 list.push_back({src, tgt, Move::PBISHOP});
31 list.push_back({src, tgt, Move::PROOK});
32 list.push_back({src, tgt, Move::PQUEEN});
33 } else {
34 list.push_back({src, tgt, Move::PQUIET});
36 // two ahead
37 const square::Square tgt = static_cast<square::Square>(tgt_i + add);
38 if (pawn_onStart(color, src) && !board.is_square_occupied(tgt))
39 list.push_back({src, tgt, Move::DOUBLE});
40 }
41 }
43 // capture
44 U64 attack =
45 board.get_bitboard_piece_attacks(PAWN, color, src) & board.get_bitboard_color(colorOther);
46 bitboard_for_each_bit(tgt_i, attack) {
47 const square::Square tgt = static_cast<square::Square>(tgt_i);
48 if (pawn_canPromote(color, src)) {
49 list.push_back({src, tgt, Move::PCKNIGHT});
50 list.push_back({src, tgt, Move::PCBISHOP});
51 list.push_back({src, tgt, Move::PCROOK});
52 list.push_back({src, tgt, Move::PCQUEEN});
53 } else {
54 list.push_back({src, tgt, Move::CAPTURE});
55 }
56 }
58 // en passant
59 const square::Square enpassant = board.get_enpassant();
60 if (enpassant != square::no_sq && board.is_piece_attack_square(PAWN, color, src, enpassant))
61 list.push_back({src, enpassant, Move::ENPASSANT});
62 }
64 // All piece move
65 for (const piece::Type type : ++piece::TypeIter()) {
66 U64 bitboard = board.get_bitboard_piece(type, color);
67 bitboard_for_each_bit(src_i, bitboard) {
68 const square::Square src = static_cast<square::Square>(src_i);
69 U64 attack = board.get_bitboard_piece_moves(type, color, src);
70 bitboard_for_each_bit(tgt_i, attack) {
71 const square::Square tgt = static_cast<square::Square>(tgt_i);
72 if (board.is_square_occupied(tgt)) {
73 list.push_back({src, tgt, Move::CAPTURE});
74 } else {
75 if (attacks_only) continue;
76 list.push_back({src, tgt, Move::QUIET});
77 }
78 }
79 }
80 }
82 if (attacks_only) return;
84 // Castling
85 if (color == color::WHITE) {
86 if (!board.is_square_attacked(square::e1, color::BLACK)) {
87 if (board.get_castle() & to_underlying(Board::Castle::WK)) {
88 if (!board.is_square_occupied(square::f1) && !board.is_square_occupied(square::g1) &&
89 !board.is_square_attacked(square::f1, color::BLACK))
90 list.push_back({square::e1, square::g1, Move::CASTLEK});
91 }
92 if (board.get_castle() & to_underlying(Board::Castle::WQ)) {
93 if (!board.is_square_occupied(square::d1) && !board.is_square_occupied(square::c1) &&
94 !board.is_square_occupied(square::b1) &&
95 !board.is_square_attacked(square::d1, color::BLACK) &&
96 !board.is_square_attacked(square::c1, color::BLACK))
97 list.push_back({square::e1, square::c1, Move::CASTLEQ});
98 }
99 }
100 } else {
101 if (!board.is_square_attacked(square::e8, color::WHITE)) {
102 if (board.get_castle() & to_underlying(Board::Castle::BK)) {
103 if (!board.is_square_occupied(square::f8) && !board.is_square_occupied(square::g8) &&
104 !board.is_square_attacked(square::f8, color::WHITE))
105 list.push_back({square::Square::e8, square::Square::g8, Move::CASTLEK});
107 if (board.get_castle() & to_underlying(Board::Castle::BQ)) {
108 if (!board.is_square_occupied(square::d8) && !board.is_square_occupied(square::c8) &&
109 !board.is_square_occupied(square::b8) &&
110 !board.is_square_attacked(square::d8, color::WHITE) &&
111 !board.is_square_attacked(square::c8, color::WHITE))
112 list.push_back({square::e8, square::c8, Move::CASTLEQ});
118 std::ostream &operator<<(std::ostream &os, const MoveList &list) {
119 os << "Size: " << std::dec << list.size() << "\n";
120 for (const Move move : list.list) {
121 os << move << "\n";
123 return os;