search: fixed a bug in NULL move pruning
[owl.git] / engine.c
blobeee73761e6a8135a4a25f2e51a1bf13417ef64e4
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 struct engine_t e; /* engine parameters */
27 int history[2][7][4096]; /* history for move ordering */
28 int hash_moves[MAX_PLY]; /* moves to try first */
29 struct killers_t killers[MAX_PLY]; /* moves to try after hash moves */
31 int pv[MAX_PLY][MAX_PLY]; /* triangular array for PV */
32 int pv_length[MAX_PLY];
34 char return_ponder[32];
36 /* initial chess position */
37 char start_position[] = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -";
38 char book_file_name[] = "book.bin";
40 /* statistic counters */
41 struct counters_t counters;
43 struct parsed_moves_t pm;
45 pthread_cond_t cond_exit = PTHREAD_COND_INITIALIZER;
48 * Return variable's value in thread-safe way
50 int
51 get_engine_value(int *val)
53 int result;
55 pthread_mutex_lock(&e.mutex);
56 result = *val;
57 pthread_mutex_unlock(&e.mutex);
59 return result;
63 * Set value in thread-safe way
65 void
66 set_engine_value(int *src, int new_value)
68 pthread_mutex_lock(&e.mutex);
69 *src = new_value;
70 pthread_mutex_unlock(&e.mutex);
73 /* time from Epoc in second/100 units - xboard time units */
74 uint32_t
75 get_time(void)
77 struct timeval t;
78 gettimeofday(&t, 0);
80 return t.tv_sec * 100 + t.tv_usec / 10000;
83 /* check if we should abort search */
84 int
85 check_time(int ply)
87 int i;
89 if (!(counters.searched_nodes & e.chk_time)) {
90 int stop_time = get_engine_value((int *)&e.stop_time);
91 if (get_time() >= stop_time) {
92 if (get_engine_value((int *)&e.pondering))
93 return FALSE;
95 if (fail_high_root && (stop_time < get_engine_value((int *)&e.max_stop_time) &&
96 !get_engine_value(&e.fixed_time))) {
97 set_engine_value((int *)&e.stop_time, stop_time + e.max_time);
98 fprintf(stderr, "Extending because fail high at ply 1\n");
99 return FALSE;
101 if (!safe_search && !get_engine_value(&e.fixed_time) &&
102 stop_time < get_engine_value((int *)&e.max_stop_time)) {
103 set_engine_value((int *)&e.stop_time, stop_time + e.max_time / 2);
104 fprintf(stderr, "Extending...\n");
105 return FALSE;
108 /* takeback all moves in search tree */
109 for (i = 0; i < ply; i++)
110 takeback();
111 abort_search = TRUE;
112 return TRUE;
116 return FALSE;
119 /* start new game */
120 void
121 new_game()
123 srand(get_time()); /* for opening book randomization */
124 setup_board(start_position);
126 clear_main_hashtable();
127 clear_pawn_hashtable();
130 /* print brief stats to console. used mostly for debugging */
131 void
132 print_stats(int timediff)
134 double search_time;
135 double move_ordering;
136 int nps;
138 search_time = timediff / 100.0;
139 move_ordering = counters.failed_high_total ? \
140 (counters.failed_high_first / (double) counters.failed_high_total) * \
141 100.0 : -1.0;
142 nps = counters.searched_nodes / search_time;
144 fprintf(stdout, "Time: %.2f, nodes: %llu, NPS: %d/sec, MO: %.2f%%\n" \
145 "NULL: %llu, delta: %llu, LMR: %llu, razor: %llu, futility: %llu\n" \
146 "pawn hash evaluations: %llu, transposition: %llu\n" \
147 "evaluations: %llu, lazy: %.2f%%, phase: %d\n",
148 search_time, counters.searched_nodes, nps, move_ordering,
149 counters.null_move_prunings, counters.delta_prunings,
150 counters.reductions, counters.razorings, counters.futility_prunings,
151 counters.pawn_hash_evaluations, counters.transposition,
152 counters.evaluations, ((double) counters.lazy_evaluations / counters.evaluations) * 100, GAME_PHASE);
155 /* if it's engine's turn to move we should search */
156 void *
157 process_turn(void *args)
159 int move;
160 int move_from_book;
161 char buf[MAX_STRING];
162 char ponder_candidate[32];
164 return_ponder[0] = 0;
166 move_from_book = TRUE;
167 move = book_move();
169 if (!move) {
170 leave_book++;
171 move_from_book = FALSE;
172 set_engine_value(&e.thinking, TRUE);
173 move = iterate(ponder_candidate);
174 set_engine_value(&e.thinking, FALSE);
175 } else
176 leave_book = 0;
177 check_move:
178 set_engine_value((int *)&e.ponderhit, FALSE);
179 if (move == -1) {
180 fprintf(stdout, "resign\n");
181 if (get_engine_value(&e.side) == WHITE)
182 fprintf(stdout, "0-1 {WHITE looses}\n");
183 else
184 fprintf(stdout, "1-0 {BLACK looses}\n");
185 set_engine_value(&e.side, NOBODY);
187 /* free resources after termination */
188 pthread_detach(pthread_self());
190 return (void *)0;
193 if (!move || evaluate_draw() || reps() >= 3) {
194 if (evaluate_draw()) {
195 if (brd.fifty_rule >= 100)
196 fprintf(stdout, "1/2-1/2 {Fifty move rule}\n");
197 else
198 fprintf(stdout, "1/2-1/2 {insufficient material}\n");
199 } else if (reps() >= 3)
200 fprintf(stdout, "1/2-1/2 {repetition}\n");
201 else if (IS_CHECKED(WHITE))
202 fprintf(stdout, "0-1 {BLACK mates}\n");
203 else if (IS_CHECKED(BLACK))
204 fprintf(stdout, "1-0 {WHITE mates}\n");
205 else
206 fprintf(stdout, "1/2-1/2 {Stalemate}\n");
207 set_engine_value(&e.side, NOBODY);
208 } else {
209 if (get_engine_value(&e.san_notation) || \
210 !get_engine_value(&e.xboard_mode)) {
211 san_move(move, buf);
212 make_move(move, FALSE);
213 fprintf(stdout, "move %s\n", buf);
215 /* create struct with all possible replies to simplify parsing
216 * later */
217 ZERO_MEM(pm);
219 int i;
220 char parse_buf[MAX_STRING];
221 struct moves_t moves_parse;
223 gen_legal_moves(&moves_parse);
225 /* generate pseudolegal moves and find target move */
226 for (i = 0; i < moves_parse.count; i++) {
227 pm.count++;
228 pm.move[i] = moves_parse.move[i];
229 strcpy(pm.sans[i], san_move(moves_parse.move[i], parse_buf));
232 if (ponder_candidate[0]) {
233 make_move(parse_move_san(ponder_candidate), FALSE);
234 if (book_move())
235 ponder_candidate[0] = 0;
236 takeback();
239 /* do we have a move to ponder? */
240 if (ponder_candidate[0]) {
241 make_move(parse_move_san(ponder_candidate), FALSE);
243 /* don't ponder if a candidate is from opening book */
244 /* ponder! */
245 strncpy(return_ponder, ponder_candidate, 7);
246 set_engine_value(&e.ponderhit, FALSE);
247 set_engine_value(&e.thinking, TRUE);
248 set_engine_value(&e.pondering, TRUE);
249 move = iterate(ponder_candidate);
250 set_engine_value(&e.thinking, FALSE);
252 if (move != -1) {
253 if (get_engine_value(&e.pondering)) {
254 pthread_mutex_lock(&e.ponder_mutex);
255 pthread_cond_wait(&cond_exit, &e.ponder_mutex);
256 pthread_mutex_unlock(&e.ponder_mutex);
258 if (get_engine_value(&e.ponderhit))
259 goto check_move;
260 } else {
261 if (get_engine_value(&e.ponderhit) ||
262 get_engine_value(&e.stop_time))
263 takeback();
264 return_ponder[0] = 0;
265 set_engine_value((int *)&e.pondering, 0);
267 } else
268 return_ponder[0] = 0;
270 } else {
271 make_move(move, FALSE);
272 fprintf(stdout, "move %s\n", coord_move(move, buf));
275 if (!get_engine_value(&e.xboard_mode) && !move_from_book)
276 fprintf(stdout, "[%s]$ ", program_name);
278 /* free resources after termination */
279 pthread_detach(pthread_self());
281 return (void *)0;
284 void
285 start_engine(void)
287 pthread_mutex_init(&e.mutex, 0);
288 pthread_mutex_init(&e.ponder_mutex, 0);
290 set_engine_value(&e.side, NOBODY);
291 set_engine_value(&e.force_mode, TRUE);
292 set_engine_value(&e.post_mode, FALSE);
293 set_engine_value(&e.xboard_mode, FALSE);
294 set_engine_value(&e.san_notation, FALSE);
295 set_engine_value(&e.ponder_allowed, TRUE);
297 /* set small limits for quick testing */
298 set_engine_value(&e.max_depth, 9);
299 set_engine_value(&e.max_time, 10000);
300 set_engine_value(&e.inc_time, 0);
302 /* check if we should abort search every 1024 nodes */
303 set_engine_value(&e.chk_time, 1023);
305 /* use 1/30 of total time for thinking */
306 set_engine_value(&e.time_div, 30);
308 set_engine_value(&e.fixed_time, FALSE);
309 set_engine_value((int *)&e.stop_time, 0);
310 set_engine_value((int *)&e.max_stop_time, 0);
312 /* if FALSE we are playing to mate */
313 set_engine_value(&e.resign, TRUE);
314 set_engine_value(&e.resign_value, -600);
316 /* if EPD tests are currently running */
317 set_engine_value(&e.thinking, FALSE);
318 set_engine_value(&e.pondering, FALSE);
319 set_engine_value(&e.ponderhit, FALSE);
321 /* search options */
322 set_engine_value(&e.delta_pruning, TRUE);
323 set_engine_value(&e.futility_pruning, TRUE);
324 set_engine_value(&e.iid, TRUE);
325 set_engine_value(&e.null_pruning, TRUE);
326 set_engine_value(&e.lmr, TRUE);
327 set_engine_value(&e.razoring, TRUE);
329 /* used to calculate 'game phase' */
330 set_engine_value(&e.phase_factor, (piece_value[KNIGHT] * 2 + \
331 piece_value[BISHOP] * 2 + piece_value[ROOK] * 2 + \
332 piece_value[QUEEN]) / 128);
334 e.tid = 0;
336 /* initialize hashtable */
337 e.pawn_hash_size = 2;
338 e.main_hash_size = 16;
339 e.pawn_hash_enabled = TRUE;
340 e.main_hash_enabled = TRUE;
342 book_open(book_file_name);
343 new_game();
346 /* free resources */
347 void perform_cleanup(void)
349 /* free memory */
350 if (get_engine_value(&e.pawn_hash_enabled))
351 free_pawn_hashtable();
353 /* destroy engine mutex */
354 pthread_mutex_destroy(&e.mutex);
355 pthread_mutex_destroy(&e.ponder_mutex);
357 /* close book file descriptor */
358 book_close();