From 20d7197a9be9c03f153c7ceac73857da8416bba4 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 15 Nov 2008 13:00:56 +0100 Subject: [PATCH] MovePicker: use EvalInfo to skip generating captures When we know already no captures are possible in a given position. Signed-off-by: Marco Costalba --- src/movepick.cpp | 41 +++++++++++++++++++++++++++++++---------- src/movepick.h | 4 +++- src/position.cpp | 3 ++- src/position.h | 4 ++-- src/search.cpp | 2 +- 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 34c69895..dc295e17 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -26,6 +26,7 @@ #include #include "history.h" +#include "evaluate.h" #include "movegen.h" #include "movepick.h" #include "search.h" @@ -44,7 +45,9 @@ namespace { int MainSearchPhaseIndex; int EvasionsPhaseIndex; int QsearchWithChecksPhaseIndex; + int QsearchNoCapturesPhaseIndex; int QsearchWithoutChecksPhaseIndex; + int NoMovesPhaseIndex; } @@ -62,9 +65,9 @@ namespace { /// search captures, promotions and some checks) and about how important good /// move ordering is at the current node. -MovePicker::MovePicker(const Position& p, bool pvnode, Move ttm, Move mk, - Move k1, Move k2, Depth d) : pos(p) { - pvNode = pvnode; +MovePicker::MovePicker(const Position& p, bool pv, Move ttm, + Move mk, Move k1, Move k2, Depth d, EvalInfo* ei) : pos(p) { + pvNode = pv; ttMove = ttm; mateKiller = (mk == ttm)? MOVE_NONE : mk; killer1 = k1; @@ -73,17 +76,25 @@ MovePicker::MovePicker(const Position& p, bool pvnode, Move ttm, Move mk, movesPicked = 0; numOfMoves = 0; numOfBadCaptures = 0; - dc = p.discovered_check_candidates(p.side_to_move()); + + // With EvalInfo we are able to know how many captures are possible before + // generating them. So avoid generating them in case we know are zero. + Color us = pos.side_to_move(); + Color them = opposite_color(us); + bool noAttacks = ei && (ei->attackedBy[us][0] & pos.pieces_of_color(them)) == 0; + bool noCaptures = noAttacks && (pos.ep_square() == SQ_NONE) && !pos.has_pawn_on_7th(us); if (p.is_check()) - phaseIndex = EvasionsPhaseIndex; + phaseIndex = EvasionsPhaseIndex; else if (depth > Depth(0)) - phaseIndex = MainSearchPhaseIndex; + phaseIndex = MainSearchPhaseIndex; else if (depth == Depth(0)) - phaseIndex = QsearchWithChecksPhaseIndex; + phaseIndex = (noCaptures ? QsearchNoCapturesPhaseIndex : QsearchWithChecksPhaseIndex); else - phaseIndex = QsearchWithoutChecksPhaseIndex; + phaseIndex = (noCaptures ? NoMovesPhaseIndex : QsearchWithoutChecksPhaseIndex); + + dc = p.discovered_check_candidates(us); pinned = p.pinned_pieces(p.side_to_move()); finished = false; @@ -493,8 +504,9 @@ MovePicker::MovegenPhase MovePicker::current_move_type() const { /// MovePicker::init_phase_table() initializes the PhaseTable[], /// MainSearchPhaseIndex, EvasionPhaseIndex, QsearchWithChecksPhaseIndex -/// and QsearchWithoutChecksPhaseIndex variables. It is only called once -/// during program startup, and never again while the program is running. +/// QsearchNoCapturesPhaseIndex, QsearchWithoutChecksPhaseIndex and +/// NoMovesPhaseIndex variables. It is only called once during program +/// startup, and never again while the program is running. void MovePicker::init_phase_table() { @@ -523,8 +535,17 @@ void MovePicker::init_phase_table() { PhaseTable[i++] = PH_QCHECKS; PhaseTable[i++] = PH_STOP; + // Quiescence search with checks only and no captures + QsearchNoCapturesPhaseIndex = i - 1; + PhaseTable[i++] = PH_QCHECKS; + PhaseTable[i++] = PH_STOP; + // Quiescence search without checks QsearchWithoutChecksPhaseIndex = i - 1; PhaseTable[i++] = PH_QCAPTURES; PhaseTable[i++] = PH_STOP; + + // Do not generate any move + NoMovesPhaseIndex = i - 1; + PhaseTable[i++] = PH_STOP; } diff --git a/src/movepick.h b/src/movepick.h index c7b1ddaf..e8a32c93 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -34,6 +34,8 @@ //// Types //// +struct EvalInfo; + /// MovePicker is a class which is used to pick one legal move at a time from /// the current position. It is initialized with a Position object and a few /// moves we have reason to believe are good. The most important method is @@ -60,7 +62,7 @@ public: PH_STOP }; - MovePicker(const Position& p, bool pvnode, Move ttm, Move mk, Move k1, Move k2, Depth d); + MovePicker(const Position& p, bool pvnode, Move ttm, Move mk, Move k1, Move k2, Depth d, EvalInfo* ei = NULL); Move get_next_move(); Move get_next_move(Lock &lock); int number_of_moves() const; diff --git a/src/position.cpp b/src/position.cpp index df6b4270..0c7d62ce 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -274,7 +274,8 @@ void Position::print(Move m) const { if (m != MOVE_NONE) { Position p(*this); - std::cout << "Move is: " << move_to_san(p, m) << std::endl; + std::string col = (color_of_piece_on(move_from(m)) == BLACK ? ".." : ""); + std::cout << "Move is: " << col << move_to_san(p, m) << std::endl; } for (Rank rank = RANK_8; rank >= RANK_1; rank--) { diff --git a/src/position.h b/src/position.h index 6076a539..743acf33 100644 --- a/src/position.h +++ b/src/position.h @@ -174,13 +174,13 @@ public: // Number of pieces of each color and type int piece_count(Color c, PieceType pt) const; - // The en passant square: + // The en passant square Square ep_square() const; // Current king position for each color Square king_square(Color c) const; - // Castling rights. + // Castling rights bool can_castle_kingside(Color c) const; bool can_castle_queenside(Color c) const; bool can_castle(Color c) const; diff --git a/src/search.cpp b/src/search.cpp index e28b866e..e2d4093a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1389,7 +1389,7 @@ namespace { // to search the moves. Because the depth is <= 0 here, only captures, // queen promotions and checks (only if depth == 0) will be generated. MovePicker mp = MovePicker(pos, false, MOVE_NONE, MOVE_NONE, MOVE_NONE, - MOVE_NONE, depth); + MOVE_NONE, depth, &ei); Move move; int moveCount = 0; Bitboard dcCandidates = mp.discovered_check_candidates(); -- 2.39.2