search: fixed a bug in NULL move pruning
[owl.git] / quiesce.c
blob57f6fd0e439b97b199881383440063d30a15d19d
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 #include <assert.h>
17 #include <stdio.h>
18 #include "common.h"
19 #include "attacks.h"
20 #include "board.h"
21 #include "engine.h"
22 #include "evaluate.h"
23 #include "move.h"
24 #include "search.h"
26 int quiesce(int alpha, int beta, int depth, int ply, int flag)
28 int i, j;
29 int is_pv;
30 int score;
31 int check;
32 int moves_count;
33 uint64_t target;
34 struct moves_t moves;
36 assert(alpha >= -MATE_VALUE && alpha < +MATE_VALUE);
37 assert(beta > alpha && beta <= +MATE_VALUE);
38 assert(board_is_legal(&brd));
40 if (evaluate_draw())
41 return 0;
43 is_pv = (alpha != beta - 1);
44 /* don't store PV at non-PV nodes */
45 if (is_pv)
46 pv_length[ply] = ply;
48 check = IS_CHECKED(brd.wtm);
49 if (check) {
50 if (is_pv)
51 return search_pv(alpha, beta, 0, ply, TRUE);
52 else
53 return zwsearch(beta, 0, ply, TRUE, 1);
56 target = side_boards[1 ^ brd.wtm];
58 /* stand pat */
59 score = evaluate(alpha, beta);
61 /* already got cutoff */
62 if (score >= beta)
63 return beta;
65 /* we are too deep */
66 if (ply >= MAX_PLY - 1)
67 return score;
69 if (score > alpha)
70 alpha = score;
71 else if (e.delta_pruning && !check && !is_pv && !flag && score < (alpha - 250)) {
72 target &= ~PAWNS(1 ^ brd.wtm);
74 if (score < (alpha - 475)) {
75 target &= ~KNIGHTS(1 ^ brd.wtm);
76 target &= ~BISHOPS(1 ^ brd.wtm);
79 if (score < (alpha - 650))
80 target &= ~ROOKS(1 ^ brd.wtm);
82 if (score < (alpha - 1125))
83 target &= ~QUEENS(1 ^ brd.wtm);
85 gen_quiescent_moves(&moves, target);
87 moves_count = 0;
89 /* don't use hash move and killers in QS */
90 hash_moves[ply] = 0;
91 killers[ply].mate_killer = 0;
92 killers[ply].killer1 = 0;
93 killers[ply].killer2 = 0;
95 for (i = 0; i < moves.count; i++) {
96 assert(MOVE_IS_TACTICAL(moves.move[i]));
97 sort_moves(&moves, i, ply);
99 if (e.delta_pruning && moves_count && !flag && !is_pv && !check && MOVE_IS_TACTICAL(moves.move[i]) && \
100 !SCORE_IS_MATE(beta) && moves.see[i] < 0) {
101 #ifdef STATISTIC_COUNTERS
102 counters.delta_prunings++;
103 #endif
104 continue;
107 if (!make_move(moves.move[i], FALSE))
108 continue;
110 moves_count++;
112 score = -quiesce(-beta, -alpha, depth - 1, ply + 1, flag);
113 if (abort_search)
114 return 65535;
116 takeback();
118 if (score > alpha) {
119 if (score >= beta) {
120 #ifdef STATISTIC_COUNTERS
121 counters.failed_high_total++;
122 if (moves_count == 1)
123 counters.failed_high_first++;
124 #endif
126 return beta;
128 alpha = score;
130 if (is_pv) {
131 pv[ply][ply] = moves.move[i];
133 for (j = ply + 1; j < pv_length[ply + 1]; j++)
134 pv[ply][j] = pv[ply + 1][j];
135 pv_length[ply] = pv_length[ply + 1];
139 return alpha;