search: fixed a bug in NULL move pruning
[owl.git] / iterate.c
blob90f4078fce39df1954be8ec10075c8b30612cc88
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 "common.h"
17 #include "attacks.h"
18 #include "board.h"
19 #include "engine.h"
20 #include "evaluate.h"
21 #include "move.h"
22 #include "search.h"
23 #include "trans.h"
25 #define MAX_PV_STRING_SIZE 2048
27 int follow_pv; /* if we are following PV searched by previous
28 iteration */
29 int abort_search; /* TRUE if search should be stopped by some reason */
30 int fail_high_root; /* fail high at first ply */
31 int leave_book;
32 int safe_search;
34 /* iterative deeping */
35 int
36 iterate(char *ponder_candidate)
38 int engine_xboard;
39 int best_move;
40 int best_ponder;
41 int best_score;
42 int best_depth;
43 int i_depth;
44 int score;
45 int start_time;
46 struct moves_t moves;
47 char pv_string[MAX_PV_STRING_SIZE];
49 start_time = get_time();
51 int max_time = get_engine_value(&e.max_time);
52 int inc_time = (get_engine_value(&e.inc_time) * 90) / 100;
53 int time_bonus = leave_book == 1 && !get_engine_value(&e.fixed_time)? max_time : 0;
55 set_engine_value((int *)&e.stop_time, start_time + \
56 max_time + time_bonus + inc_time); /* when stop search */
57 set_engine_value((int *)&e.max_stop_time, start_time + \
58 e.max_time * 4 + time_bonus + inc_time); /* when stop longest search */
60 if (get_engine_value(&e.pondering))
61 set_engine_value((int *)&e.max_depth, 64);
63 /* initialize some data */
64 ZERO_MEM(pv);
65 ZERO_MEM(pv_length);
66 ZERO_MEM(history);
67 ZERO_MEM(killers);
68 ZERO_MEM(hash_moves);
69 ZERO_MEM(counters);
71 if (ponder_candidate != NULL)
72 ponder_candidate[0] = 0;
74 best_move = 0;
75 best_score = -MATE_VALUE;
76 best_ponder = 0;
77 best_depth = 0;
78 abort_search = FALSE;
79 fail_high_root = FALSE;
81 #ifdef CONSOLE_DEBUG
82 char fen_position[256];
83 fprintf(stdout, "setboard %s\n", current_fen_position(fen_position));
84 #endif
85 hashtable_age++;
87 if (evaluate_draw() && !get_engine_value(&e.pondering))
88 return 0;
89 else if (reps() >= 3 && !get_engine_value(&e.pondering))
90 return 0;
92 engine_xboard = get_engine_value(&e.xboard_mode);
93 /* if we have the only one move, don't think about it */
94 if (gen_legal_moves(&moves) == 1 && !get_engine_value(&e.pondering))
95 return moves.move[0];
97 if (!engine_xboard)
98 printf("ply nodes score pv\n");
100 safe_search = FALSE;
102 for (i_depth = 1; i_depth <= get_engine_value(&e.max_depth); i_depth++) {
103 follow_pv = TRUE;
104 score = search_root(-MATE_VALUE, +MATE_VALUE, i_depth, \
105 IS_CHECKED(brd.wtm));
107 if (abort_search)
108 break;
110 /* save best move from last successful iteration */
111 best_move = pv[0][0];
112 best_ponder = pv_length[0] > 1? pv[0][1] : 0;
113 best_score = score;
114 best_depth = i_depth;
116 /* get string PV representation (for 'Show Thinking' option or console
117 output) */
118 if (get_engine_value(&e.san_notation) || !engine_xboard)
119 get_pv_string_san(pv_string);
120 else
121 get_pv_string_coord(pv_string);
123 assert(score >= -MATE_VALUE && score <= MATE_VALUE);
125 if (!engine_xboard && pv[0][0])
126 fprintf(stdout, "%3d %10llu %5s%.2f %5u %s", i_depth, \
127 counters.searched_nodes, score >= 0? "+" : "-", \
128 abs(score) / (float)100, get_time() - start_time, pv_string);
129 else if (engine_xboard && get_engine_value(&e.post_mode) && \
130 ((i_depth > 5) || SCORE_IS_MATE(score))) {
131 fprintf(stdout, "%3d %7d %5u %10llu %s",
132 i_depth, score, get_time() - start_time,
133 counters.searched_nodes, pv_string);
136 if (SCORE_IS_MATE(score) && i_depth > 1)
137 /* don't search further if we have confirmed mate */
138 break;
139 /* if it's not fixed time search and we used more than 50% of the
140 required time */
141 if (!get_engine_value(&e.fixed_time) && ((get_time() - start_time) / \
142 (double)(get_engine_value((int *)&e.stop_time) - start_time) > 0.5) &&
143 !get_engine_value(&e.pondering))
144 break;
145 /* if it's not fixed time search and we used more than 30% of the
146 required time */
147 if (!get_engine_value(&e.fixed_time) && ((get_time() - start_time) / \
148 (double)(get_engine_value((int *)&e.stop_time) - start_time) > 0.33))
149 safe_search = TRUE;
152 if (get_engine_value(&e.play_computer) && get_engine_value(&e.post_mode))
153 fprintf(stdout, "tellics kibitz %.2f [%d], %dkNPS, PV = %s", (double)
154 best_score/100, best_depth, (int)((counters.searched_nodes/ 1000) / ((get_time() -
155 start_time) / (double)100)), pv_string);
157 /* should we resign? */
158 if (get_engine_value(&e.resign) && (best_score <= \
159 get_engine_value(&e.resign_value))) {
160 if (++e.hopeless_moves >= 3 && !get_engine_value(&e.pondering) &&
161 !get_engine_value(&e.ponderhit))
162 return -1;
163 } else
164 e.hopeless_moves = 0;
166 #ifdef CONSOLE_DEBUG
167 print_stats(get_time() - start_time);
168 #endif
169 if (get_engine_value(&e.pondering) ||
170 !get_engine_value(&e.stop_time) ||
171 !get_engine_value(&e.ponder_allowed))
172 best_ponder = 0;
174 if (ponder_candidate && best_ponder &&
175 (!engine_xboard ||
176 (engine_xboard && get_engine_value(&e.post_mode))) &&
177 !SCORE_IS_MATE(best_score)) {
178 /* print a move that we could ponder */
179 make_move(best_move, 0);
180 printf("Ponder candidate: %s\n", san_move(best_ponder,
181 ponder_candidate));
182 takeback();
184 if ((SCORE_IS_MATE(best_score) || (i_depth == get_engine_value(&e.max_depth)))&&
185 get_engine_value(&e.pondering) && !get_engine_value(&e.ponderhit)) {
186 ponder_candidate[0] = 0;
187 return -1;
190 return best_move;