X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fmovegen.cpp;h=0db293ccc7eb713901e139665578821a3b077a9f;hp=0af95e2d34f0b5cc7320201a9afe1f456788bb87;hb=4dded4e72f9b9582db8adc9a478e9eda5841d8c5;hpb=deecb3757ca03fa2c9ebc87fd9efe4c2ba05f740 diff --git a/src/movegen.cpp b/src/movegen.cpp index 0af95e2d..0db293cc 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -1,7 +1,7 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2009 Marco Costalba + Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -57,8 +57,7 @@ namespace { MoveStack* generate_castle_moves(const Position&, MoveStack*); template - MoveStack* generate_pawn_moves(const Position&, MoveStack*, Bitboard = EmptyBoardBB, - Square = SQ_NONE, Bitboard = EmptyBoardBB); + MoveStack* generate_pawn_moves(const Position&, MoveStack*, Bitboard, Square); // Template generate_piece_moves (captures and non-captures) with specializations and overloads template @@ -68,19 +67,19 @@ namespace { MoveStack* generate_piece_moves(const Position&, MoveStack*, Color, Bitboard); template - inline MoveStack* generate_piece_moves(const Position& p, MoveStack* m, Color us) { + inline MoveStack* generate_piece_moves(const Position& p, MoveStack* m, Color us, Bitboard t) { assert(Piece == PAWN); - assert(Type == CAPTURE || Type == NON_CAPTURE); + assert(Type == CAPTURE || Type == NON_CAPTURE || Type == EVASION); - return (us == WHITE ? generate_pawn_moves(p, m) - : generate_pawn_moves(p, m)); + return (us == WHITE ? generate_pawn_moves(p, m, t, SQ_NONE) + : generate_pawn_moves(p, m, t, SQ_NONE)); } // Templates for non-capture checks generation template - MoveStack* generate_discovered_checks(const Position& pos, Square from, MoveStack* mlist); + MoveStack* generate_discovered_checks(const Position&, MoveStack*, Square); template MoveStack* generate_direct_checks(const Position&, MoveStack*, Color, Bitboard, Square); @@ -91,18 +90,6 @@ namespace { return (us == WHITE ? generate_pawn_moves(p, m, dc, ksq) : generate_pawn_moves(p, m, dc, ksq)); } - - // Template generate_piece_evasions with specializations - template - MoveStack* generate_piece_evasions(const Position&, MoveStack*, Color, Bitboard, Bitboard); - - template<> - inline MoveStack* generate_piece_evasions(const Position& p, MoveStack* m, - Color us, Bitboard t, Bitboard pnd) { - - return (us == WHITE ? generate_pawn_moves(p, m, pnd, SQ_NONE, t) - : generate_pawn_moves(p, m, pnd, SQ_NONE, t)); - } } @@ -126,7 +113,7 @@ MoveStack* generate_captures(const Position& pos, MoveStack* 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); + mlist = generate_piece_moves(pos, mlist, us, target); return generate_piece_moves(pos, mlist, us, target); } @@ -142,7 +129,7 @@ MoveStack* generate_noncaptures(const Position& pos, MoveStack* mlist) { Color us = pos.side_to_move(); Bitboard target = pos.empty_squares(); - mlist = generate_piece_moves(pos, mlist, us); + 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); @@ -153,31 +140,60 @@ MoveStack* generate_noncaptures(const Position& pos, MoveStack* mlist) { } -/// generate_non_capture_checks() generates all pseudo-legal non-captures and +/// generate_non_evasions() generates all pseudo-legal captures and +/// non-captures. Returns a pointer to the end of the move list. + +MoveStack* generate_non_evasions(const Position& pos, MoveStack* mlist) { + + assert(pos.is_ok()); + assert(!pos.is_check()); + + Color us = pos.side_to_move(); + Bitboard target = pos.pieces_of_color(opposite_color(us)); + + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, pos.empty_squares()); + + target |= pos.empty_squares(); + + 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); + mlist = generate_castle_moves(pos, mlist); + return generate_castle_moves(pos, mlist); +} + + +/// generate_non_capture_checks() generates all pseudo-legal non-captures and knight /// underpromotions that give check. Returns a pointer to the end of the move list. -MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard dc) { +MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist) { assert(pos.is_ok()); assert(!pos.is_check()); + Bitboard b, dc; + Square from; Color us = pos.side_to_move(); Square ksq = pos.king_square(opposite_color(us)); assert(pos.piece_on(ksq) == piece_of_color_and_type(opposite_color(us), KING)); // Discovered non-capture checks - Bitboard b = dc; + b = dc = pos.discovered_check_candidates(us); + while (b) { - Square from = pop_1st_bit(&b); + from = pop_1st_bit(&b); switch (pos.type_of_piece_on(from)) { case PAWN: /* Will be generated togheter with pawns direct checks */ break; - case KNIGHT: mlist = generate_discovered_checks(pos, from, mlist); break; - case BISHOP: mlist = generate_discovered_checks(pos, from, mlist); break; - case ROOK: mlist = generate_discovered_checks(pos, from, mlist); break; - case KING: mlist = generate_discovered_checks(pos, from, mlist); break; + case KNIGHT: mlist = generate_discovered_checks(pos, mlist, from); break; + case BISHOP: mlist = generate_discovered_checks(pos, mlist, from); break; + case ROOK: mlist = generate_discovered_checks(pos, mlist, from); break; + case KING: mlist = generate_discovered_checks(pos, mlist, from); break; default: assert(false); break; } } @@ -194,16 +210,15 @@ MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bi /// generate_evasions() generates all pseudo-legal check evasions when /// the side to move is in check. Returns a pointer to the end of the move list. -MoveStack* generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { +MoveStack* generate_evasions(const Position& pos, MoveStack* mlist) { assert(pos.is_ok()); assert(pos.is_check()); - Bitboard b; - Square from, to, checksq; + Bitboard b, target; + Square from, checksq; int checkersCnt = 0; Color us = pos.side_to_move(); - Color them = opposite_color(us); Square ksq = pos.king_square(us); Bitboard checkers = pos.checkers(); Bitboard sliderAttacks = EmptyBoardBB; @@ -220,7 +235,7 @@ MoveStack* generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pin checkersCnt++; checksq = pop_1st_bit(&b); - assert(pos.color_of_piece_on(checksq) == them); + assert(pos.color_of_piece_on(checksq) == opposite_color(us)); switch (pos.type_of_piece_on(checksq)) { @@ -229,7 +244,7 @@ MoveStack* generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pin case QUEEN: // In case of a queen remove also squares attacked in the other direction to // avoid possible illegal moves when queen and king are on adjacent squares. - if (direction_is_straight(checksq, ksq)) + if (squares_straight_aligned(checksq, ksq)) sliderAttacks |= RookPseudoAttacks[checksq] | pos.attacks_from(checksq); else sliderAttacks |= BishopPseudoAttacks[checksq] | pos.attacks_from(checksq); @@ -247,62 +262,15 @@ MoveStack* generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pin if (checkersCnt > 1) return mlist; - Bitboard target = squares_between(checksq, ksq); - - // Pawn captures - b = pos.attacks_from(checksq, them) & pos.pieces(PAWN, us) & ~pinned; - while (b) - { - from = pop_1st_bit(&b); - if (relative_rank(us, checksq) == RANK_8) - { - (*mlist++).move = make_promotion_move(from, checksq, QUEEN); - (*mlist++).move = make_promotion_move(from, checksq, ROOK); - (*mlist++).move = make_promotion_move(from, checksq, BISHOP); - (*mlist++).move = make_promotion_move(from, checksq, KNIGHT); - } else - (*mlist++).move = make_move(from, checksq); - } + // Find squares where a blocking evasion or a capture of the + // checker piece is possible. + target = squares_between(checksq, ksq) | checkers; - // Pawn blocking evasions (possible only if the checking piece is a slider) - if (sliderAttacks) - mlist = generate_piece_evasions(pos, mlist, us, target, pinned); - - // Add the checking piece to the target squares - target |= checkers; - - // Captures and blocking evasions for the other pieces + 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); - - // Finally, the special case of en passant captures. An en passant - // capture can only be a check evasion if the check is not a discovered - // check. If pos.ep_square() is set, the last move made must have been - // a double pawn push. If, furthermore, the checking piece is a pawn, - // an en passant check evasion may be possible. - if (pos.ep_square() != SQ_NONE && (checkers & pos.pieces(PAWN, them))) - { - to = pos.ep_square(); - b = pos.attacks_from(to, them) & pos.pieces(PAWN, us); - - // The checking pawn cannot be a discovered (bishop) check candidate - // otherwise we were in check also before last double push move. - assert(!bit_is_set(pos.discovered_check_candidates(them), checksq)); - assert(count_1s(b) == 1 || count_1s(b) == 2); - - b &= ~pinned; - while (b) - { - from = pop_1st_bit(&b); - // Move is always legal because checking pawn is not a discovered - // check candidate and our capturing pawn has been already tested - // against pinned pieces. - (*mlist++).move = make_ep_move(from, to); - } - } - return mlist; + return generate_piece_moves(pos, mlist, us, target); } @@ -314,26 +282,22 @@ MoveStack* generate_moves(const Position& pos, MoveStack* mlist, bool pseudoLega assert(pos.is_ok()); - MoveStack* last; + MoveStack *last, *cur = mlist; Bitboard pinned = pos.pinned_pieces(pos.side_to_move()); // Generate pseudo-legal moves - if (pos.is_check()) - last = generate_evasions(pos, mlist, pinned); - else { - last = generate_captures(pos, mlist); - last = generate_noncaptures(pos, last); - } + last = pos.is_check() ? generate_evasions(pos, mlist) + : generate_non_evasions(pos, mlist); if (pseudoLegal) return last; // Remove illegal moves from the list - for (MoveStack* cur = mlist; cur != last; cur++) - if (!pos.pl_move_is_legal(cur->move, pinned)) - { + while (cur != last) + if (pos.pl_move_is_legal(cur->move, pinned)) + cur++; + else cur->move = (--last)->move; - cur--; - } + return last; } @@ -344,11 +308,12 @@ MoveStack* generate_moves(const Position& pos, MoveStack* mlist, bool pseudoLega bool move_is_legal(const Position& pos, const Move m) { - MoveStack mlist[256]; - MoveStack* last = generate_moves(pos, mlist, true); - for (MoveStack* cur = mlist; cur != last; cur++) + MoveStack mlist[MOVES_MAX]; + MoveStack *cur, *last = generate_moves(pos, mlist, true); + + for (cur = mlist; cur != last; cur++) if (cur->move == m) - return pos.pl_move_is_legal(m); + return pos.pl_move_is_legal(m, pos.pinned_pieces(pos.side_to_move())); return false; } @@ -356,25 +321,23 @@ bool move_is_legal(const Position& pos, const Move m) { /// Fast version of move_is_legal() that takes a position a move and a /// bitboard of pinned pieces as input, and tests whether the move is legal. -/// This version must only be used when the side to move is not in check. 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())); - // Use a slower but simpler function for uncommon cases - if (move_is_ep(m) || move_is_castle(m)) - return move_is_legal(pos, m); - Color us = pos.side_to_move(); Color them = opposite_color(us); Square from = move_from(m); Square to = move_to(m); Piece pc = pos.piece_on(from); + // Use a slower but simpler function for uncommon cases + if (move_is_special(m)) + return move_is_legal(pos, m); + // 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) @@ -392,10 +355,9 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) { if ((us == WHITE) != (direction > 0)) return false; - // A pawn move is a promotion iff the destination square is - // on the 8/1th rank. - if (( (square_rank(to) == RANK_8 && us == WHITE) - ||(square_rank(to) == RANK_1 && us != WHITE)) != bool(move_is_promotion(m))) + // We have already handled promotion moves, so destination + // cannot be on the 8/1th rank. + if (square_rank(to) == RANK_8 || square_rank(to) == RANK_1) return false; // Proceed according to the square delta between the origin and @@ -442,14 +404,12 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) { default: return false; } - // The move is pseudo-legal, check if it is also legal - return pos.pl_move_is_legal(m, pinned); } + else if (!bit_is_set(pos.attacks_from(pc, from), to)) + return false; - // Luckly we can handle all the other pieces in one go - return ( bit_is_set(pos.attacks_from(pc, from), to) - && pos.pl_move_is_legal(m, pinned) - && !move_is_promotion(m)); + // The move is pseudo-legal, check if it is also legal + return pos.is_check() ? pos.pl_move_is_evasion(m, pinned) : pos.pl_move_is_legal(m, pinned); } @@ -458,14 +418,17 @@ namespace { template MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) { - Square from; Bitboard b; + Square from; const Square* ptr = pos.piece_list_begin(us, Piece); - while ((from = *ptr++) != SQ_NONE) + if (*ptr != SQ_NONE) { - b = pos.attacks_from(from) & target; - SERIALIZE_MOVES(b); + do { + from = *ptr; + b = pos.attacks_from(from) & target; + SERIALIZE_MOVES(b); + } while (*++ptr != SQ_NONE); } return mlist; } @@ -481,177 +444,158 @@ namespace { return mlist; } - template - MoveStack* generate_piece_evasions(const Position& pos, MoveStack* mlist, - Color us, Bitboard target, Bitboard pinned) { - Square from; - Bitboard b; - const Square* ptr = pos.piece_list_begin(us, Piece); - - while ((from = *ptr++) != SQ_NONE) - { - if (pinned && bit_is_set(pinned, from)) - continue; + template + inline Bitboard move_pawns(Bitboard p) { - b = pos.attacks_from(from) & target; - SERIALIZE_MOVES(b); - } - return mlist; + return Delta == DELTA_N ? p << 8 : Delta == DELTA_S ? p >> 8 : + Delta == DELTA_NE ? p << 9 : Delta == DELTA_SE ? p >> 7 : + Delta == DELTA_NW ? p << 7 : Delta == DELTA_SW ? p >> 9 : p; } - template - inline Bitboard move_pawns(Bitboard p) { + template + inline MoveStack* generate_pawn_captures(MoveStack* mlist, Bitboard pawns, Bitboard target) { + + const Bitboard TFileABB = (Delta == DELTA_NE || Delta == DELTA_SE ? FileABB : FileHBB); - if (Direction == DELTA_N) - return Us == WHITE ? p << 8 : p >> 8; - else if (Direction == DELTA_NE) - return Us == WHITE ? p << 9 : p >> 7; - else if (Direction == DELTA_NW) - return Us == WHITE ? p << 7 : p >> 9; - else - return p; + Bitboard b; + Square to; + + // Captures in the a1-h8 (a8-h1 for black) diagonal or in the h1-a8 (h8-a1 for black) + b = move_pawns(pawns) & target & ~TFileABB; + SERIALIZE_MOVES_D(b, -Delta); + return mlist; } - template - MoveStack* generate_pawn_diagonal_captures(MoveStack* mlist, Bitboard pawns, Bitboard enemyPieces, bool promotion) { + template + inline MoveStack* generate_promotions(const Position& pos, MoveStack* mlist, Bitboard pawnsOn7, Bitboard target) { - // Calculate our parametrized parameters at compile time - const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB); - const Bitboard TFileABB = (Diagonal == DELTA_NE ? FileABB : FileHBB); - const SquareDelta TDELTA_NE = (Us == WHITE ? DELTA_NE : DELTA_SE); - const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW); - const SquareDelta TTDELTA_NE = (Diagonal == DELTA_NE ? TDELTA_NE : TDELTA_NW); + const Bitboard TFileABB = (Delta == DELTA_NE || Delta == DELTA_SE ? FileABB : FileHBB); + Bitboard b; Square to; - // Captures in the a1-h8 (a8-h1 for black) diagonal or in the h1-a8 (h8-a1 for black) - Bitboard b1 = move_pawns(pawns) & ~TFileABB & enemyPieces; + // Promotions and under-promotions, both captures and non-captures + b = move_pawns(pawnsOn7) & target; + + if (Delta != DELTA_N && Delta != DELTA_S) + b &= ~TFileABB; - // Capturing promotions - if (promotion) + while (b) { - Bitboard b2 = b1 & TRank8BB; - b1 &= ~TRank8BB; - while (b2) + to = pop_1st_bit(&b); + + if (Type == CAPTURE || Type == EVASION) + (*mlist++).move = make_promotion_move(to - Delta, to, QUEEN); + + if (Type == NON_CAPTURE || Type == EVASION) { - to = pop_1st_bit(&b2); - (*mlist++).move = make_promotion_move(to - TTDELTA_NE, to, QUEEN); + (*mlist++).move = make_promotion_move(to - Delta, to, ROOK); + (*mlist++).move = make_promotion_move(to - Delta, to, BISHOP); + (*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT); } - } - // Capturing non-promotions - SERIALIZE_MOVES_D(b1, -TTDELTA_NE); + // This is the only possible under promotion that can give a check + // not already included in the queen-promotion. + if ( Type == CHECK + && bit_is_set(pos.attacks_from(to), pos.king_square(opposite_color(Us)))) + (*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT); + else (void)pos; // Silence a warning under MSVC + } return mlist; } template - MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, Bitboard dcp, - Square ksq, Bitboard blockSquares) { - - // Calculate our parametrized parameters at compile time - const Color Them = (Us == WHITE ? BLACK : WHITE); - const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB); - const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); - const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); + MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, Bitboard target, Square ksq) { + + // Calculate our parametrized parameters at compile time, named + // according to the point of view of white side. + const Color Them = (Us == WHITE ? BLACK : WHITE); + const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); + const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); + const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S); const SquareDelta TDELTA_NE = (Us == WHITE ? DELTA_NE : DELTA_SE); const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW); - const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S); - Bitboard b1, b2, dcPawns1, dcPawns2; Square to; - Bitboard pawns = (Type == EVASION ? pos.pieces(PAWN, Us) & ~dcp : pos.pieces(PAWN, Us)); - bool possiblePromotion = pawns & TRank7BB; + Bitboard b1, b2, dc1, dc2, pawnPushes, emptySquares; + Bitboard pawns = pos.pieces(PAWN, Us); + Bitboard pawnsOn7 = pawns & TRank7BB; + Bitboard enemyPieces = (Type == CAPTURE ? target : pos.pieces_of_color(Them)); - if (Type == CAPTURE) + // Pre-calculate pawn pushes before changing emptySquares definition + if (Type != CAPTURE) { - // Standard captures and capturing promotions in both directions - Bitboard enemyPieces = pos.pieces_of_color(opposite_color(Us)); - mlist = generate_pawn_diagonal_captures(mlist, pawns, enemyPieces, possiblePromotion); - mlist = generate_pawn_diagonal_captures(mlist, pawns, enemyPieces, possiblePromotion); + emptySquares = (Type == NON_CAPTURE ? target : pos.empty_squares()); + pawnPushes = move_pawns(pawns & ~TRank7BB) & emptySquares; } - if (possiblePromotion) + if (Type == EVASION) { - // When generating checks consider under-promotion moves (both captures - // and non captures) only if can give a discovery check. Note that dcp - // is dc bitboard or pinned bitboard when Type == EVASION. - Bitboard pp = (Type == CHECK ? pawns & dcp : pawns); - - if (Type != EVASION && Type != CAPTURE) - { - Bitboard enemyPieces = pos.pieces_of_color(opposite_color(Us)); - - // Underpromotion captures in the a1-h8 (a8-h1 for black) direction - b1 = move_pawns(pp) & ~FileABB & enemyPieces & TRank8BB; - while (b1) - { - 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 = move_pawns(pp) & ~FileHBB & enemyPieces & TRank8BB; - while (b1) - { - 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); - } - } + emptySquares &= target; // Only blocking squares + enemyPieces &= target; // Capture only the checker piece + } - // Underpromotion pawn pushes. Also queen promotions for evasions and captures. - b1 = move_pawns(pp) & TRank8BB; - b1 &= (Type == EVASION ? blockSquares : pos.empty_squares()); + // Promotions and underpromotions + if (pawnsOn7) + { + if (Type == CAPTURE) + emptySquares = pos.empty_squares(); - while (b1) - { - to = pop_1st_bit(&b1); - if (Type == EVASION || Type == CAPTURE) - (*mlist++).move = make_promotion_move(to - TDELTA_N, to, QUEEN); + pawns &= ~TRank7BB; + mlist = generate_promotions(pos, mlist, pawnsOn7, enemyPieces); + mlist = generate_promotions(pos, mlist, pawnsOn7, enemyPieces); + mlist = generate_promotions(pos, mlist, pawnsOn7, emptySquares); + } - if (Type != CAPTURE) - { - (*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); - } - } + // Standard captures + if (Type == CAPTURE || Type == EVASION) + { + mlist = generate_pawn_captures(mlist, pawns, enemyPieces); + mlist = generate_pawn_captures(mlist, pawns, enemyPieces); } + // Single and double pawn pushes if (Type != CAPTURE) { - Bitboard emptySquares = pos.empty_squares(); - dcPawns1 = dcPawns2 = EmptyBoardBB; - if (Type == CHECK && (pawns & dcp)) - { - // Pawn moves which gives discovered check. This is possible only if the - // pawn is not on the same file as the enemy king, because we don't - // generate captures. - dcPawns1 = move_pawns(pawns & dcp & ~file_bb(ksq)) & emptySquares & ~TRank8BB; - dcPawns2 = move_pawns(dcPawns1 & TRank3BB) & emptySquares; - } + b1 = pawnPushes & emptySquares; + b2 = move_pawns(pawnPushes & TRank3BB) & emptySquares; - // Single pawn pushes - b1 = move_pawns(pawns) & emptySquares & ~TRank8BB; - b2 = (Type == CHECK ? (b1 & pos.attacks_from(ksq, Them)) | dcPawns1 : - (Type == EVASION ? b1 & blockSquares : b1)); - SERIALIZE_MOVES_D(b2, -TDELTA_N); + if (Type == CHECK) + { + // Condider only pawn moves which give direct checks + b1 &= pos.attacks_from(ksq, Them); + b2 &= pos.attacks_from(ksq, Them); + + // Add pawn moves which gives discovered check. This is possible only + // if the pawn is not on the same file as the enemy king, because we + // don't generate captures. + if (pawns & target) // For CHECK type target is dc bitboard + { + dc1 = move_pawns(pawns & target & ~file_bb(ksq)) & emptySquares; + dc2 = move_pawns(dc1 & TRank3BB) & emptySquares; - // Double pawn pushes - b1 = move_pawns(b1 & TRank3BB) & emptySquares; - b2 = (Type == CHECK ? (b1 & pos.attacks_from(ksq, Them)) | dcPawns2 : - (Type == EVASION ? b1 & blockSquares : b1)); + b1 |= dc1; + b2 |= dc2; + } + } + SERIALIZE_MOVES_D(b1, -TDELTA_N); SERIALIZE_MOVES_D(b2, -TDELTA_N -TDELTA_N); } - else if (pos.ep_square() != SQ_NONE) // En passant captures + + // En passant captures + if ((Type == CAPTURE || Type == EVASION) && pos.ep_square() != SQ_NONE) { assert(Us != WHITE || square_rank(pos.ep_square()) == RANK_6); assert(Us != BLACK || square_rank(pos.ep_square()) == RANK_3); + // An en passant capture can be an evasion only if the checking piece + // is the double pushed pawn and so is in the target. Otherwise this + // is a discovery check and we are forced to do otherwise. + if (Type == EVASION && !bit_is_set(target, pos.ep_square() - TDELTA_N)) + return mlist; + b1 = pawns & pos.attacks_from(pos.ep_square(), Them); + assert(b1 != EmptyBoardBB); while (b1) @@ -664,7 +608,7 @@ namespace { } template - MoveStack* generate_discovered_checks(const Position& pos, Square from, MoveStack* mlist) { + MoveStack* generate_discovered_checks(const Position& pos, MoveStack* mlist, Square from) { assert(Piece != QUEEN); @@ -683,8 +627,8 @@ namespace { Bitboard dc, Square ksq) { assert(Piece != KING); + Bitboard checkSqs, b; Square from; - Bitboard checkSqs; const Square* ptr = pos.piece_list_begin(us, Piece); if ((from = *ptr++) == SQ_NONE) @@ -702,8 +646,8 @@ namespace { if (dc && bit_is_set(dc, from)) continue; - Bitboard bb = pos.attacks_from(from) & checkSqs; - SERIALIZE_MOVES(bb); + b = pos.attacks_from(from) & checkSqs; + SERIALIZE_MOVES(b); } while ((from = *ptr++) != SQ_NONE); @@ -715,7 +659,7 @@ namespace { Color us = pos.side_to_move(); - if ( (Side == KING_SIDE && pos.can_castle_kingside(us)) + if ( (Side == KING_SIDE && pos.can_castle_kingside(us)) ||(Side == QUEEN_SIDE && pos.can_castle_queenside(us))) { Color them = opposite_color(us);