stellar

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

movelist.cpp (5384B)


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