X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fmovegen.cpp;h=7273ca9ad6ebbf50a1aca42734381446a8e948e5;hp=54af3222e5b21b7657edf691a791d1fbc8d5cbf1;hb=c97104e8540b72ee2c6c9c13d3773d2c0f9ec32f;hpb=af5743837d1fc52466d40ecd6394bee9db7a053d diff --git a/src/movegen.cpp b/src/movegen.cpp index 54af3222..7273ca9a 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -25,6 +25,9 @@ #include "movegen.h" +// Simple macro to wrap a very common while loop, no facny, no flexibility, +// hardcoded list name 'mlist' and from square 'from'. +#define SERIALIZE_MOVES(b) while (b) (*mlist++).move = make_move(from, pop_1st_bit(&b)) //// //// Local definitions @@ -119,15 +122,16 @@ int generate_captures(const Position& pos, MoveStack* mlist) { Bitboard target = pos.pieces_of_color(opposite_color(us)); MoveStack* mlist_start = mlist; + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + if (us == WHITE) mlist = generate_pawn_captures(pos, mlist); else mlist = generate_pawn_captures(pos, mlist); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); mlist = generate_piece_moves(pos, mlist, us, target); return int(mlist - mlist_start); } @@ -303,26 +307,26 @@ int generate_evasions(const Position& pos, MoveStack* mlist) { // Pawn moves. Because a blocking evasion can never be a capture, we // only generate pawn pushes. if (us == WHITE) - generate_pawn_blocking_evasions(pos, not_pinned, blockSquares, mlist); + mlist = generate_pawn_blocking_evasions(pos, not_pinned, blockSquares, mlist); else - generate_pawn_blocking_evasions(pos, not_pinned, blockSquares, mlist); + mlist = generate_pawn_blocking_evasions(pos, not_pinned, blockSquares, mlist); // Pieces moves b1 = pos.knights(us) & not_pinned; if (b1) - generate_piece_blocking_evasions(pos, b1, blockSquares, mlist); + mlist = generate_piece_blocking_evasions(pos, b1, blockSquares, mlist); b1 = pos.bishops(us) & not_pinned; if (b1) - generate_piece_blocking_evasions(pos, b1, blockSquares, mlist); + mlist = generate_piece_blocking_evasions(pos, b1, blockSquares, mlist); b1 = pos.rooks(us) & not_pinned; if (b1) - generate_piece_blocking_evasions(pos, b1, blockSquares, mlist); + mlist = generate_piece_blocking_evasions(pos, b1, blockSquares, mlist); b1 = pos.queens(us) & not_pinned; if (b1) - generate_piece_blocking_evasions(pos, b1, blockSquares, mlist); + mlist = generate_piece_blocking_evasions(pos, b1, blockSquares, mlist); } // Finally, the ugly special case of en passant captures. An en passant @@ -382,24 +386,25 @@ int generate_legal_moves(const Position& pos, MoveStack* mlist) { // Remove illegal moves from the list for (int i = 0; i < n; i++) - if (!pos.move_is_legal(mlist[i].move, pinned)) + if (!pos.pl_move_is_legal(mlist[i].move, pinned)) mlist[i--].move = mlist[--n].move; return n; } -/// generate_move_if_legal() takes a position and a (not necessarily -/// pseudo-legal) move and a pinned pieces bitboard as input, and tests -/// whether the move is legal. If the move is legal, the move itself is -/// returned. If not, the function returns MOVE_NONE. This function must +/// move_is_legal() takes a position and a (not necessarily pseudo-legal) +/// move and a pinned pieces bitboard as input, and tests whether +/// the move is legal. If the move is legal, the move itself is +/// returned. If not, the function returns false. This function must /// only be used when the side to move is not in check. -Move generate_move_if_legal(const Position& pos, Move m, Bitboard pinned) { +bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) { assert(pos.is_ok()); assert(!pos.is_check()); assert(move_is_ok(m)); + assert(pinned == pos.pinned_pieces(pos.side_to_move())); Color us = pos.side_to_move(); Color them = opposite_color(us); @@ -409,7 +414,7 @@ Move generate_move_if_legal(const Position& pos, Move m, Bitboard pinned) { // If the from square is not occupied by a piece belonging to the side to // move, the move is obviously not legal. if (color_of_piece(pc) != us) - return MOVE_NONE; + return false; Square to = move_to(m); @@ -420,13 +425,13 @@ Move generate_move_if_legal(const Position& pos, Move m, Bitboard pinned) { // en passant square. if ( type_of_piece(pc) != PAWN || to != pos.ep_square()) - return MOVE_NONE; + return false; assert(pos.square_is_empty(to)); assert(pos.piece_on(to - pawn_push(us)) == pawn_of_color(them)); - // The move is pseudo-legal. If it is legal, return it. - return (pos.move_is_legal(m) ? m : MOVE_NONE); + // The move is pseudo-legal, check if it is also legal + return pos.pl_move_is_legal(m, pinned); } // Castling moves @@ -436,7 +441,7 @@ Move generate_move_if_legal(const Position& pos, Move m, Bitboard pinned) { // the right to castle kingside. if ( type_of_piece(pc) != KING ||!pos.can_castle_kingside(us)) - return MOVE_NONE; + return false; assert(from == pos.king_square(us)); assert(to == pos.initial_kr_square(us)); @@ -460,7 +465,7 @@ Move generate_move_if_legal(const Position& pos, Move m, Bitboard pinned) { if (s != from && s != to && !pos.square_is_empty(s)) illegal = true; - return (!illegal ? m : MOVE_NONE); + return !illegal; } if (move_is_long_castle(m)) @@ -469,7 +474,7 @@ Move generate_move_if_legal(const Position& pos, Move m, Bitboard pinned) { // the right to castle kingside. if ( type_of_piece(pc) != KING ||!pos.can_castle_queenside(us)) - return MOVE_NONE; + return false; assert(from == pos.king_square(us)); assert(to == pos.initial_qr_square(us)); @@ -494,14 +499,14 @@ Move generate_move_if_legal(const Position& pos, Move m, Bitboard pinned) { || pos.piece_on(to + DELTA_W) == queen_of_color(them))) illegal = true; - return (!illegal ? m : MOVE_NONE); + return !illegal; } // Normal moves // The destination square cannot be occupied by a friendly piece if (pos.color_of_piece_on(to) == us) - return MOVE_NONE; + return false; // Proceed according to the type of the moving piece. if (type_of_piece(pc) == PAWN) @@ -511,7 +516,7 @@ Move generate_move_if_legal(const Position& pos, Move m, Bitboard pinned) { if ( ( (square_rank(to) == RANK_8 && us == WHITE) ||(square_rank(to) == RANK_1 && us != WHITE)) && !move_promotion(m)) - return MOVE_NONE; + return false; // Proceed according to the square delta between the source and // destionation squares. @@ -524,14 +529,14 @@ Move generate_move_if_legal(const Position& pos, Move m, Bitboard pinned) { // Capture. The destination square must be occupied by an enemy // piece (en passant captures was handled earlier). if (pos.color_of_piece_on(to) != them) - return MOVE_NONE; + return false; break; case DELTA_N: case DELTA_S: // Pawn push. The destination square must be empty. if (!pos.square_is_empty(to)) - return MOVE_NONE; + return false; break; case DELTA_NN: @@ -541,7 +546,7 @@ Move generate_move_if_legal(const Position& pos, Move m, Bitboard pinned) { if ( square_rank(to) != RANK_4 || !pos.square_is_empty(to) || !pos.square_is_empty(from + DELTA_N)) - return MOVE_NONE; + return false; break; case DELTA_SS: @@ -551,20 +556,20 @@ Move generate_move_if_legal(const Position& pos, Move m, Bitboard pinned) { if ( square_rank(to) != RANK_5 || !pos.square_is_empty(to) || !pos.square_is_empty(from + DELTA_S)) - return MOVE_NONE; + return false; break; default: - return MOVE_NONE; + return false; } - // The move is pseudo-legal. Return it if it is legal. - return (pos.move_is_legal(m) ? m : MOVE_NONE); + // The move is pseudo-legal, check if it is also legal + return pos.pl_move_is_legal(m, pinned); } // Luckly we can handle all the other pieces in one go return ( pos.piece_attacks_square(from, to) - && pos.move_is_legal(m) - && !move_promotion(m) ? m : MOVE_NONE); + && pos.pl_move_is_legal(m, pinned) + && !move_promotion(m)); } @@ -573,18 +578,14 @@ namespace { template MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) { - Square from, to; + Square from; Bitboard b; for (int i = 0, e = pos.piece_count(us, Piece); i < e; i++) { from = pos.piece_list(us, Piece, i); b = pos.piece_attacks(from) & target; - while (b) - { - to = pop_1st_bit(&b); - (*mlist++).move = make_move(from, to); - } + SERIALIZE_MOVES(b); } return mlist; } @@ -593,14 +594,10 @@ namespace { MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) { Bitboard b; - Square to, from = pos.king_square(us); + Square from = pos.king_square(us); b = pos.piece_attacks(from) & target; - while (b) - { - to = pop_1st_bit(&b); - (*mlist++).move = make_move(from, to); - } + SERIALIZE_MOVES(b); return mlist; } @@ -611,11 +608,7 @@ namespace { { Square from = pop_1st_bit(&b); Bitboard bb = pos.piece_attacks(from) & blockSquares; - while (bb) - { - Square to = pop_1st_bit(&bb); - (*mlist++).move = make_move(from, to); - } + SERIALIZE_MOVES(bb); } return mlist; } @@ -624,9 +617,9 @@ namespace { template - MoveStack* do_generate_pawn_captures(const Position& pos, MoveStack* mlist) { + MoveStack* do_generate_pawn_captures(const Position& pos, MoveStack* mlist) { - Square sq; + Square to; Bitboard pawns = pos.pawns(Us); Bitboard enemyPieces = pos.pieces_of_color(Them); @@ -637,16 +630,16 @@ namespace { Bitboard b2 = b1 & TRank8BB; while (b2) { - sq = pop_1st_bit(&b2); - (*mlist++).move = make_promotion_move(sq - TDELTA_NE, sq, QUEEN); + to = pop_1st_bit(&b2); + (*mlist++).move = make_promotion_move(to - TDELTA_NE, to, QUEEN); } // Capturing non-promotions b2 = b1 & ~TRank8BB; while (b2) { - sq = pop_1st_bit(&b2); - (*mlist++).move = make_move(sq - TDELTA_NE, sq); + to = pop_1st_bit(&b2); + (*mlist++).move = make_move(to - TDELTA_NE, to); } // Captures in the h1-a8 (h8-a1 for black) direction @@ -656,24 +649,24 @@ namespace { b2 = b1 & TRank8BB; while (b2) { - sq = pop_1st_bit(&b2); - (*mlist++).move = make_promotion_move(sq - TDELTA_NW, sq, QUEEN); + to = pop_1st_bit(&b2); + (*mlist++).move = make_promotion_move(to - TDELTA_NW, to, QUEEN); } // Capturing non-promotions b2 = b1 & ~TRank8BB; while (b2) { - sq = pop_1st_bit(&b2); - (*mlist++).move = make_move(sq - TDELTA_NW, sq); + to = pop_1st_bit(&b2); + (*mlist++).move = make_move(to - TDELTA_NW, to); } // Non-capturing promotions b1 = (Us == WHITE ? pawns << 8 : pawns >> 8) & pos.empty_squares() & TRank8BB; while (b1) { - sq = pop_1st_bit(&b1); - (*mlist++).move = make_promotion_move(sq - TDELTA_N, sq, QUEEN); + to = pop_1st_bit(&b1); + (*mlist++).move = make_promotion_move(to - TDELTA_N, to, QUEEN); } // En passant captures @@ -687,8 +680,8 @@ namespace { while (b1) { - sq = pop_1st_bit(&b1); - (*mlist++).move = make_ep_move(sq, pos.ep_square()); + to = pop_1st_bit(&b1); + (*mlist++).move = make_ep_move(to, pos.ep_square()); } } return mlist; @@ -697,32 +690,32 @@ namespace { template - MoveStack* do_generate_pawn_noncaptures(const Position& pos, MoveStack* mlist) { + MoveStack* do_generate_pawn_noncaptures(const Position& pos, MoveStack* mlist) { Bitboard pawns = pos.pawns(Us); Bitboard enemyPieces = pos.pieces_of_color(Them); Bitboard emptySquares = pos.empty_squares(); Bitboard b1, b2; - Square sq; + Square to; // Underpromotion captures in the a1-h8 (a8-h1 for black) direction b1 = (Us == WHITE ? pawns << 9 : pawns >> 7) & ~FileABB & enemyPieces & TRank8BB; while (b1) { - sq = pop_1st_bit(&b1); - (*mlist++).move = make_promotion_move(sq - TDELTA_NE, sq, ROOK); - (*mlist++).move = make_promotion_move(sq - TDELTA_NE, sq, BISHOP); - (*mlist++).move = make_promotion_move(sq - TDELTA_NE, sq, KNIGHT); + to = pop_1st_bit(&b1); + (*mlist++).move = make_promotion_move(to - TDELTA_NE, to, ROOK); + (*mlist++).move = make_promotion_move(to - TDELTA_NE, to, BISHOP); + (*mlist++).move = make_promotion_move(to - TDELTA_NE, to, KNIGHT); } // Underpromotion captures in the h1-a8 (h8-a1 for black) direction b1 = (Us == WHITE ? pawns << 7 : pawns >> 9) & ~FileHBB & enemyPieces & TRank8BB; while (b1) { - sq = pop_1st_bit(&b1); - (*mlist++).move = make_promotion_move(sq - TDELTA_NW, sq, ROOK); - (*mlist++).move = make_promotion_move(sq - TDELTA_NW, sq, BISHOP); - (*mlist++).move = make_promotion_move(sq - TDELTA_NW, sq, KNIGHT); + to = pop_1st_bit(&b1); + (*mlist++).move = make_promotion_move(to - TDELTA_NW, to, ROOK); + (*mlist++).move = make_promotion_move(to - TDELTA_NW, to, BISHOP); + (*mlist++).move = make_promotion_move(to - TDELTA_NW, to, KNIGHT); } // Single pawn pushes @@ -730,24 +723,24 @@ namespace { b2 = b1 & TRank8BB; while (b2) { - sq = pop_1st_bit(&b2); - (*mlist++).move = make_promotion_move(sq - TDELTA_N, sq, ROOK); - (*mlist++).move = make_promotion_move(sq - TDELTA_N, sq, BISHOP); - (*mlist++).move = make_promotion_move(sq - TDELTA_N, sq, KNIGHT); + to = pop_1st_bit(&b2); + (*mlist++).move = make_promotion_move(to - TDELTA_N, to, ROOK); + (*mlist++).move = make_promotion_move(to - TDELTA_N, to, BISHOP); + (*mlist++).move = make_promotion_move(to - TDELTA_N, to, KNIGHT); } b2 = b1 & ~TRank8BB; while (b2) { - sq = pop_1st_bit(&b2); - (*mlist++).move = make_move(sq - TDELTA_N, sq); + to = pop_1st_bit(&b2); + (*mlist++).move = make_move(to - TDELTA_N, to); } // Double pawn pushes b2 = (Us == WHITE ? (b1 & TRank3BB) << 8 : (b1 & TRank3BB) >> 8) & emptySquares; while (b2) { - sq = pop_1st_bit(&b2); - (*mlist++).move = make_move(sq - TDELTA_N - TDELTA_N, sq); + to = pop_1st_bit(&b2); + (*mlist++).move = make_move(to - TDELTA_N - TDELTA_N, to); } return mlist; } @@ -816,11 +809,7 @@ namespace { { Square from = pop_1st_bit(&b); Bitboard bb = pos.piece_attacks(from) & pos.empty_squares(); - while (bb) - { - Square to = pop_1st_bit(&bb); - (*mlist++).move = make_move(from, to); - } + SERIALIZE_MOVES(bb); } // Direct checks b = target & ~dc; @@ -829,11 +818,7 @@ namespace { { Square from = pop_1st_bit(&b); Bitboard bb = pos.piece_attacks(from) & checkSqs; - while (bb) - { - Square to = pop_1st_bit(&bb); - (*mlist++).move = make_move(from, to); - } + SERIALIZE_MOVES(bb); } return mlist; } @@ -845,11 +830,7 @@ namespace { Bitboard b = pos.piece_attacks(from) & pos.empty_squares() & ~QueenPseudoAttacks[ksq]; - while (b) - { - Square to = pop_1st_bit(&b); - (*mlist++).move = make_move(from, to); - } + SERIALIZE_MOVES(b); } return mlist; } @@ -858,6 +839,8 @@ namespace { template MoveStack* do_generate_pawn_blocking_evasions(const Position& pos, Bitboard not_pinned, Bitboard blockSquares, MoveStack* mlist) { + Square to; + // Find non-pinned pawns Bitboard b1 = pos.pawns(Us) & not_pinned; @@ -866,7 +849,7 @@ namespace { Bitboard b2 = (Us == WHITE ? b1 << 8 : b1 >> 8) & blockSquares; while (b2) { - Square to = pop_1st_bit(&b2); + to = pop_1st_bit(&b2); assert(pos.piece_on(to) == EMPTY); @@ -885,7 +868,7 @@ namespace { b2 = (Us == WHITE ? b2 << 8 : b2 >> 8) & blockSquares;; while (b2) { - Square to = pop_1st_bit(&b2); + to = pop_1st_bit(&b2); assert(pos.piece_on(to) == EMPTY); assert(Us != WHITE || square_rank(to) == RANK_4);