From d08a8d76f7d5b992d65614714cc76e3f13e00dfc Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Tue, 16 Nov 2010 09:42:12 +0100 Subject: [PATCH] Rearrange pawn moves generation This patch greatly cleanups generation of pawn moves but we change the order in which moves are generated so there is a change in functionality, but not in perft. The only real functionality change is that now when type == CHECK we generate knight underpromotion captures only if give check and not always as before. Perft is 2% faster and fully verified. Signed-off-by: Marco Costalba --- src/movegen.cpp | 110 +++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 61 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 131bbb53..8cb5d4d6 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -455,35 +455,27 @@ namespace { template inline MoveStack* generate_pawn_captures(MoveStack* mlist, Bitboard pawns, Bitboard target) { - // Calculate our parametrized parameters at compile time - const Bitboard TRank8BB = (Delta == DELTA_NE || Delta == DELTA_NW ? Rank8BB : Rank1BB); 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) - if (Type == CAPTURE || Type == EVASION) - { - b = move_pawns(pawns) & target & ~TFileABB & ~TRank8BB; - SERIALIZE_MOVES_D(b, -Delta); - } + b = move_pawns(pawns) & target & ~TFileABB; + SERIALIZE_MOVES_D(b, -Delta); return mlist; } template - inline MoveStack* generate_promotions(const Position& pos, MoveStack* mlist, Bitboard pawns, Bitboard target) { + 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 = (Delta == DELTA_NE || Delta == DELTA_SE ? FileABB : FileHBB); - const bool IsPush = (Delta == DELTA_N || Delta == DELTA_S); Bitboard b; Square to; - // Promotions and under-promotions - b = move_pawns(pawns) & target & TRank8BB; + // Promotions and under-promotions, both captures and non-captures + b = move_pawns(pawnsOn7) & target; if (Delta != DELTA_N && Delta != DELTA_S) b &= ~TFileABB; @@ -502,16 +494,12 @@ namespace { (*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT); } - // This is the only possible under promotion that can give a check - // not already included in the queen-promotion. It is not sure that - // the promoted knight will give check, but it doesn't worth to verify. - if (Type == CHECK && !IsPush) - (*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT); - // This is the only possible under promotion that can give a check // not already included in the queen-promotion. - if (Type == CHECK && IsPush && bit_is_set(pos.attacks_from(to), pos.king_square(opposite_color(Us)))) + 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; } @@ -519,72 +507,72 @@ namespace { template MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, Bitboard target, 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); + // 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); Square to; - Bitboard b1, b2, enemyPieces, emptySquares; + 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)); - // Standard captures and capturing promotions and underpromotions - if (Type == CAPTURE || Type == EVASION || (pawns & TRank7BB)) + // Pre-calculate pawn pushes before changing emptySquares definition + if (Type != CAPTURE) { - enemyPieces = (Type == CAPTURE ? target : pos.pieces_of_color(opposite_color(Us))); - - if (Type == EVASION) - enemyPieces &= target; // Capture only the checker piece + emptySquares = (Type == NON_CAPTURE ? target : pos.empty_squares()); + pawnPushes = move_pawns(pawns & ~TRank7BB) & emptySquares; + } - mlist = generate_promotions(pos, mlist, pawns, enemyPieces); - mlist = generate_pawn_captures(mlist, pawns, enemyPieces); - mlist = generate_promotions(pos, mlist, pawns, enemyPieces); - mlist = generate_pawn_captures(mlist, pawns, enemyPieces); + if (Type == EVASION) + { + emptySquares &= target; // Only blocking squares + enemyPieces &= target; // Capture only the checker piece } - // Non-capturing promotions and underpromotions - if (pawns & TRank7BB) + // Promotions and underpromotions + if (pawnsOn7) { - b1 = pos.empty_squares(); + if (Type == CAPTURE) + emptySquares = pos.empty_squares(); - if (Type == EVASION) - b1 &= target; // Only blocking promotion pushes + pawns &= ~TRank7BB; + mlist = generate_promotions(pos, mlist, pawnsOn7, enemyPieces); + mlist = generate_promotions(pos, mlist, pawnsOn7, enemyPieces); + mlist = generate_promotions(pos, mlist, pawnsOn7, emptySquares); + } - mlist = generate_promotions(pos, mlist, pawns, b1); + // Standard captures + if (Type == CAPTURE || Type == EVASION) + { + mlist = generate_pawn_captures(mlist, pawns, enemyPieces); + mlist = generate_pawn_captures(mlist, pawns, enemyPieces); } - // Standard pawn pushes and double pushes + // Single and double pawn pushes if (Type != CAPTURE) { - emptySquares = (Type == NON_CAPTURE ? target : pos.empty_squares()); - - // Single and double pawn pushes - b1 = move_pawns(pawns) & emptySquares & ~TRank8BB; - b2 = move_pawns(b1 & TRank3BB) & emptySquares; + b1 = pawnPushes & emptySquares; + b2 = move_pawns(pawnPushes & TRank3BB) & emptySquares; - // Filter out unwanted pushes according to the move type - if (Type == EVASION) - { - b1 &= target; - b2 &= target; - } - else if (Type == CHECK) + if (Type == CHECK) { - // Pawn moves which give direct cheks + // Condider only pawn moves which give direct checks b1 &= pos.attacks_from(ksq, Them); b2 &= pos.attacks_from(ksq, Them); - // 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. + // 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 { - Bitboard dc1 = move_pawns(pawns & target & ~file_bb(ksq)) & emptySquares & ~TRank8BB; - Bitboard dc2 = move_pawns(dc1 & TRank3BB) & emptySquares; + dc1 = move_pawns(pawns & target & ~file_bb(ksq)) & emptySquares; + dc2 = move_pawns(dc1 & TRank3BB) & emptySquares; b1 |= dc1; b2 |= dc2; -- 2.39.2