stellar

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

movelist.cpp (5384B)


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