From aed542d74cf57438fef19b662a56d8d810bc1965 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Mon, 21 Sep 2009 10:00:33 +0100 Subject: [PATCH] When generating checks add possibly under-promotions In qsearch at depth 0 we generate only captures and checks. Queen promotion moves are generated among the captures, but under-promotion moves (both captures and non-captures) are never generated even if they could give a discovery check. This patch fixes this limitation extending generate_pawn_noncaptures() to generate also check moves when required. Apart for adding the (rare) case of an under-promotion that gives discovery check, the patch is also a good cleanup because removes generate_pawn_checks() altoghter. This patch does the code clean-up but not enables the functional change so to allow an easier debug. No functional change and no performance change (actually a very very small speed increase). Signed-off-by: Marco Costalba --- src/movegen.cpp | 100 ++++++++++++++---------------------------------- 1 file changed, 29 insertions(+), 71 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 83f84448..ce8f54ca 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -66,11 +66,8 @@ namespace { template MoveStack* generate_pawn_captures_diagonal(MoveStack* mlist, Bitboard pawns, Bitboard enemyPieces, bool promotion); - template - MoveStack* generate_pawn_noncaptures(const Position& pos, MoveStack* mlist); - - template - MoveStack* generate_pawn_checks(const Position&, Bitboard, Square, MoveStack*); + template + MoveStack* generate_pawn_noncaptures(const Position& pos, MoveStack* mlist, Bitboard dc = EmptyBoardBB, Square ksq = SQ_NONE); template inline Bitboard move_pawns(Bitboard p) { @@ -92,8 +89,8 @@ namespace { template<> inline MoveStack* generate_piece_checks(const Position& p, MoveStack* m, Color us, Bitboard dc, Square ksq) { - return (us == WHITE ? generate_pawn_checks(p, dc, ksq, m) - : generate_pawn_checks(p, dc, ksq, m)); + return (us == WHITE ? generate_pawn_noncaptures(p, m, dc, ksq) + : generate_pawn_noncaptures(p, m, dc, ksq)); } // Template generate_piece_moves() with specializations and overloads @@ -112,8 +109,8 @@ namespace { return (us == WHITE ? generate_pawn_captures(p, m) : generate_pawn_captures(p, m)); else - return (us == WHITE ? generate_pawn_noncaptures(p, m) - : generate_pawn_noncaptures(p, m)); + return (us == WHITE ? generate_pawn_noncaptures(p, m) + : generate_pawn_noncaptures(p, m)); } template @@ -712,10 +709,11 @@ namespace { return mlist; } - template - MoveStack* generate_pawn_noncaptures(const Position& pos, MoveStack* mlist) { + template + MoveStack* generate_pawn_noncaptures(const Position& pos, MoveStack* mlist, Bitboard dc, Square ksq) { // 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); @@ -723,17 +721,20 @@ namespace { const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW); const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S); - Bitboard b1, b2; + Bitboard b1, b2, dcPawns1, dcPawns2; Square to; Bitboard pawns = pos.pieces(PAWN, Us); Bitboard emptySquares = pos.empty_squares(); if (pawns & TRank7BB) // There is some promotion candidate ? { - Bitboard enemyPieces = pos.pieces_of_color(opposite_color(Us)); + // When generating checks consider under-promotion moves (both captures + // and non captures) only if can give a discovery check. + Bitboard pp = GenerateChecks ? pawns & dc & EmptyBoardBB: pawns; + Bitboard enemyPieces = pos.pieces_of_color(opposite_color(Us)); // Underpromotion captures in the a1-h8 (a8-h1 for black) direction - b1 = move_pawns(pawns) & ~FileABB & enemyPieces & TRank8BB; + b1 = move_pawns(pp) & ~FileABB & enemyPieces & TRank8BB; while (b1) { to = pop_1st_bit(&b1); @@ -743,7 +744,7 @@ namespace { } // Underpromotion captures in the h1-a8 (h8-a1 for black) direction - b1 = move_pawns(pawns) & ~FileHBB & enemyPieces & TRank8BB; + b1 = move_pawns(pp) & ~FileHBB & enemyPieces & TRank8BB; while (b1) { to = pop_1st_bit(&b1); @@ -753,7 +754,7 @@ namespace { } // Underpromotion pawn pushes - b1 = move_pawns(pawns) & emptySquares & TRank8BB; + b1 = move_pawns(pp) & emptySquares & TRank8BB; while (b1) { to = pop_1st_bit(&b1); @@ -763,68 +764,25 @@ namespace { } } - // Single pawn pushes - b2 = b1 = move_pawns(pawns) & emptySquares & ~TRank8BB; - SERIALIZE_MOVES_D(b2, -TDELTA_N); - - // Double pawn pushes - b2 = move_pawns(b1 & TRank3BB) & emptySquares; - SERIALIZE_MOVES_D(b2, -TDELTA_N -TDELTA_N); - return mlist; - } - - - template - MoveStack* generate_pawn_checks(const Position& pos, Bitboard dc, Square ksq, MoveStack* mlist) - { - // Calculate our parametrized parameters at compile time - const Color Them = (Us == WHITE ? BLACK : WHITE); - const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB); - const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); - const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S); - const SquareDelta TDELTA_S = (Us == WHITE ? DELTA_S : DELTA_N); - - Square to; - Bitboard b1, b2, b3; - Bitboard pawns = pos.pieces(PAWN, Us); - - if (dc & pawns) + dcPawns1 = dcPawns2 = EmptyBoardBB; + if (GenerateChecks && (dc & pawns)) { - Bitboard empty = pos.empty_squares(); - // 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. - b1 = pawns & ~file_bb(ksq); - - // Discovered checks, single pawn pushes, no promotions - b2 = b3 = move_pawns(b1 & dc) & empty & ~TRank8BB; - SERIALIZE_MOVES_D(b3, -TDELTA_N); - - // Discovered checks, double pawn pushes - b3 = move_pawns(b2 & TRank3BB) & empty; - SERIALIZE_MOVES_D(b3, -TDELTA_N -TDELTA_N); + dcPawns1 = move_pawns(pawns & dc & ~file_bb(ksq)) & emptySquares & ~TRank8BB; + dcPawns2 = move_pawns(dcPawns1 & TRank3BB) & emptySquares; } - // Direct checks. These are possible only for pawns on neighboring files - // and in the two ranks that, after the push, are in front of the enemy king. - b1 = pawns & neighboring_files_bb(ksq) & ~dc; - - // We can get false positives if (ksq + x) is not in [0,63] range but - // is not a problem, they will be filtered out later. - b2 = b1 & (rank_bb(ksq + 2 * TDELTA_S) | rank_bb(ksq + 3 * TDELTA_S)); - if (!b2) - return mlist; - - // Direct checks, single pawn pushes - Bitboard empty = pos.empty_squares(); - b2 = move_pawns(b1) & empty; - b3 = b2 & pos.attacks_from(ksq, Them); - SERIALIZE_MOVES_D(b3, -TDELTA_N); + // Single pawn pushes + b1 = move_pawns(pawns) & emptySquares & ~TRank8BB; + b2 = GenerateChecks ? (b1 & pos.attacks_from(ksq, Them)) | dcPawns1 : b1; + SERIALIZE_MOVES_D(b2, -TDELTA_N); - // Direct checks, double pawn pushes - b3 = move_pawns(b2 & TRank3BB) & empty & pos.attacks_from(ksq, Them); - SERIALIZE_MOVES_D(b3, -TDELTA_N -TDELTA_N); + // Double pawn pushes + b1 = move_pawns(b1 & TRank3BB) & emptySquares; + b2 = GenerateChecks ? (b1 & pos.attacks_from(ksq, Them)) | dcPawns2 : b1; + SERIALIZE_MOVES_D(b2, -TDELTA_N -TDELTA_N); return mlist; } -- 2.39.2