From 8ebe5075ebd39bd0b7f6ecde41fc7fdec03df568 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 1 Nov 2009 10:40:14 +0100 Subject: [PATCH] Optimize check generation Because discovery checks are very rare it is better to handle them all in one go and strip from usual check generation function. Also rewrite direct checks generation to use piece lists instead of pop_1st_bit() On perft test we have a +6% of speed up and is verified we generate the same moves, although in a different order. Signed-off-by: Marco Costalba --- src/movegen.cpp | 103 ++++++++++++++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 39 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index f83dded7..cab7c243 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -80,12 +80,16 @@ namespace { : generate_pawn_moves(p, m)); } - // Template generate_piece_checks with specializations + // Templates for non-capture checks generation + + template + MoveStack* generate_discovered_checks(const Position& pos, Square from, MoveStack* mlist); + template - MoveStack* generate_piece_checks(const Position&, MoveStack*, Color, Bitboard, Square); + MoveStack* generate_direct_checks(const Position&, MoveStack*, Color, Bitboard, Square); template<> - inline MoveStack* generate_piece_checks(const Position& p, MoveStack* m, Color us, Bitboard dc, Square ksq) { + inline MoveStack* generate_direct_checks(const Position& p, MoveStack* m, Color us, Bitboard dc, Square ksq) { return (us == WHITE ? generate_pawn_moves(p, m, dc, ksq) : generate_pawn_moves(p, m, dc, ksq)); @@ -165,13 +169,28 @@ MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bi assert(pos.piece_on(ksq) == piece_of_color_and_type(opposite_color(us), KING)); - // Pieces moves - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + // Discovered non-capture checks + Bitboard b = dc; + while (b) + { + Square 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; + default: assert(false); break; + } + } + + // Direct non-capture checks + mlist = generate_direct_checks(pos, mlist, us, dc, ksq); + mlist = generate_direct_checks(pos, mlist, us, dc, ksq); + mlist = generate_direct_checks(pos, mlist, us, dc, ksq); + mlist = generate_direct_checks(pos, mlist, us, dc, ksq); + mlist = generate_direct_checks(pos, mlist, us, dc, ksq); // Castling moves that give check. Very rare but nice to have! if ( pos.can_castle_queenside(us) @@ -653,13 +672,13 @@ namespace { // Single pawn pushes b1 = move_pawns(pawns) & emptySquares & ~TRank8BB; b2 = (Type == CHECK ? (b1 & pos.attacks_from(ksq, Them)) | dcPawns1 : - (Type == EVASION ? b1 & blockSquares : b1)); + (Type == EVASION ? b1 & blockSquares : b1)); SERIALIZE_MOVES_D(b2, -TDELTA_N); // Double pawn pushes b1 = move_pawns(b1 & TRank3BB) & emptySquares; b2 = (Type == CHECK ? (b1 & pos.attacks_from(ksq, Them)) | dcPawns2 : - (Type == EVASION ? b1 & blockSquares : b1)); + (Type == EVASION ? b1 & blockSquares : b1)); SERIALIZE_MOVES_D(b2, -TDELTA_N -TDELTA_N); } else if (pos.ep_square() != SQ_NONE) // En passant captures @@ -680,43 +699,49 @@ namespace { } template - MoveStack* generate_piece_checks(const Position& pos, MoveStack* mlist, Color us, + MoveStack* generate_discovered_checks(const Position& pos, Square from, MoveStack* mlist) { + + assert(Piece != QUEEN); + + Bitboard b = pos.attacks_from(from) & pos.empty_squares(); + if (Piece == KING) + { + Square ksq = pos.king_square(opposite_color(pos.side_to_move())); + b &= ~QueenPseudoAttacks[ksq]; + } + SERIALIZE_MOVES(b); + return mlist; + } + + template + MoveStack* generate_direct_checks(const Position& pos, MoveStack* mlist, Color us, Bitboard dc, Square ksq) { + assert(Piece != KING); - Bitboard target = pos.pieces(Piece, us); + Square from; + Bitboard checkSqs; + const Square* ptr = pos.piece_list_begin(us, Piece); - // Discovered non-capture checks - Bitboard b = target & dc; + if ((from = *ptr++) == SQ_NONE) + return mlist; - assert(Piece != QUEEN || !b); + checkSqs = pos.attacks_from(ksq) & pos.empty_squares(); - while (b) + do { - Square from = pop_1st_bit(&b); - Bitboard bb = pos.attacks_from(from) & pos.empty_squares(); - if (Piece == KING) - bb &= ~QueenPseudoAttacks[ksq]; + if ( (Piece == QUEEN && !(QueenPseudoAttacks[from] & checkSqs)) + || (Piece == ROOK && !(RookPseudoAttacks[from] & checkSqs)) + || (Piece == BISHOP && !(BishopPseudoAttacks[from] & checkSqs))) + continue; + if (dc && bit_is_set(dc, from)) + continue; + + Bitboard bb = pos.attacks_from(from) & checkSqs; SERIALIZE_MOVES(bb); - } - // Direct non-capture checks - b = target & ~dc; - Bitboard checkSqs = pos.attacks_from(ksq) & pos.empty_squares(); - if (Piece != KING && checkSqs) - { - while (b) - { - Square from = pop_1st_bit(&b); - if ( (Piece == QUEEN && !(QueenPseudoAttacks[from] & checkSqs)) - || (Piece == ROOK && !(RookPseudoAttacks[from] & checkSqs)) - || (Piece == BISHOP && !(BishopPseudoAttacks[from] & checkSqs))) - continue; + } while ((from = *ptr++) != SQ_NONE); - Bitboard bb = pos.attacks_from(from) & checkSqs; - SERIALIZE_MOVES(bb); - } - } return mlist; }