stellar

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

movelist.cpp (5720B)


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