-
- // RootMoveList::scan_for_easy_move() is called at the end of the first
- // iteration, and is used to detect an "easy move", i.e. a move which appears
- // to be much bester than all the rest. If an easy move is found, the move
- // is returned, otherwise the function returns MOVE_NONE. It is very
- // important that this function is called at the right moment: The code
- // assumes that the first iteration has been completed and the moves have
- // been sorted. This is done in RootMoveList c'tor.
-
- Move RootMoveList::scan_for_easy_move() const {
-
- assert(count);
-
- if (count == 1)
- return get_move(0);
-
- // moves are sorted so just consider the best and the second one
- if (get_move_score(0) > get_move_score(1) + EasyMoveMargin)
- return get_move(0);
-
- return MOVE_NONE;
- }
-
- // RootMoveList::sort() sorts the root move list at the beginning of a new
- // iteration.
-
- inline void RootMoveList::sort() {
-
- sort_multipv(count - 1); // all items
- }
-
-
- // RootMoveList::sort_multipv() sorts the first few moves in the root move
- // list by their scores and depths. It is used to order the different PVs
- // correctly in MultiPV mode.
-
- void RootMoveList::sort_multipv(int n) {
-
- for (int i = 1; i <= n; i++)
- {
- RootMove rm = moves[i];
- int j;
- for (j = i; j > 0 && moves[j-1] < rm; j--)
- moves[j] = moves[j-1];
- moves[j] = rm;
- }
- }
-
-
- // init_node() is called at the beginning of all the search functions
- // (search(), search_pv(), qsearch(), and so on) and initializes the search
- // stack object corresponding to the current node. Once every
- // NodesBetweenPolls nodes, init_node() also calls poll(), which polls
- // for user input and checks whether it is time to stop the search.
-
- void init_node(SearchStack ss[], int ply, int threadID) {
- assert(ply >= 0 && ply < PLY_MAX);
- assert(threadID >= 0 && threadID < ActiveThreads);
-
- Threads[threadID].nodes++;
-
- if(threadID == 0) {
- NodesSincePoll++;
- if(NodesSincePoll >= NodesBetweenPolls) {
- poll();
- NodesSincePoll = 0;
- }
- }
-
- ss[ply].init(ply);
- ss[ply+2].initKillers();
-
- if(Threads[threadID].printCurrentLine)
- print_current_line(ss, ply, threadID);
- }
-
-
- // update_pv() is called whenever a search returns a value > alpha. It
- // updates the PV in the SearchStack object corresponding to the current
- // node.
-
- void update_pv(SearchStack ss[], int ply) {
- assert(ply >= 0 && ply < PLY_MAX);
-
- ss[ply].pv[ply] = ss[ply].currentMove;
- int p;
- for(p = ply + 1; ss[ply+1].pv[p] != MOVE_NONE; p++)
- ss[ply].pv[p] = ss[ply+1].pv[p];
- ss[ply].pv[p] = MOVE_NONE;
- }
-
-
- // sp_update_pv() is a variant of update_pv for use at split points. The
- // difference between the two functions is that sp_update_pv also updates
- // the PV at the parent node.
-
- void sp_update_pv(SearchStack *pss, SearchStack ss[], int ply) {
- assert(ply >= 0 && ply < PLY_MAX);
-
- ss[ply].pv[ply] = pss[ply].pv[ply] = ss[ply].currentMove;
- int p;
- for(p = ply + 1; ss[ply+1].pv[p] != MOVE_NONE; p++)
- ss[ply].pv[p] = pss[ply].pv[p] = ss[ply+1].pv[p];
- ss[ply].pv[p] = pss[ply].pv[p] = MOVE_NONE;
- }
-
-
- // connected_moves() tests whether two moves are 'connected' in the sense
- // that the first move somehow made the second move possible (for instance
- // if the moving piece is the same in both moves). The first move is
- // assumed to be the move that was made to reach the current position, while
- // the second move is assumed to be a move from the current position.
-
- bool connected_moves(const Position &pos, Move m1, Move m2) {
- Square f1, t1, f2, t2;
-
- assert(move_is_ok(m1));
- assert(move_is_ok(m2));
-
- if(m2 == MOVE_NONE)
- return false;
-
- // Case 1: The moving piece is the same in both moves.
- f2 = move_from(m2);
- t1 = move_to(m1);
- if(f2 == t1)
- return true;
-
- // Case 2: The destination square for m2 was vacated by m1.
- t2 = move_to(m2);
- f1 = move_from(m1);
- if(t2 == f1)
- return true;
-
- // Case 3: Moving through the vacated square:
- if(piece_is_slider(pos.piece_on(f2)) &&
- bit_is_set(squares_between(f2, t2), f1))
- return true;
-
- // Case 4: The destination square for m2 is attacked by the moving piece
- // in m1:
- if(pos.piece_attacks_square(pos.piece_on(t1), t1, t2))
- return true;
-
- // Case 5: Discovered check, checking piece is the piece moved in m1:
- if(piece_is_slider(pos.piece_on(t1)) &&
- bit_is_set(squares_between(t1, pos.king_square(pos.side_to_move())),
- f2) &&
- !bit_is_set(squares_between(t2, pos.king_square(pos.side_to_move())),
- t2)) {
- Bitboard occ = pos.occupied_squares();
- Color us = pos.side_to_move();
- Square ksq = pos.king_square(us);
- clear_bit(&occ, f2);
- if(pos.type_of_piece_on(t1) == BISHOP) {
- if(bit_is_set(bishop_attacks_bb(ksq, occ), t1))
- return true;
- }
- else if(pos.type_of_piece_on(t1) == ROOK) {
- if(bit_is_set(rook_attacks_bb(ksq, occ), t1))
- return true;
- }
- else {
- assert(pos.type_of_piece_on(t1) == QUEEN);
- if(bit_is_set(queen_attacks_bb(ksq, occ), t1))
- return true;
- }