search: move reductions
[owl.git] / engine.c
blob0fa8f8653bf9f093d6c427f4bd3734a4c0da9861
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 /* initial chess position */
35 char start_position[] = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -";
36 char book_file_name[] = "book.bin";
38 /* statistic counters */
39 struct counters_t counters;
42 * Return variable's value in thread-safe way
44 int
45 get_engine_value(int *val)
47 int result;
49 pthread_mutex_lock(&e.mutex);
50 result = *val;
51 pthread_mutex_unlock(&e.mutex);
53 return result;
57 * Set value in thread-safe way
59 void
60 set_engine_value(int *src, int new_value)
62 pthread_mutex_lock(&e.mutex);
63 *src = new_value;
64 pthread_mutex_unlock(&e.mutex);
67 /* time from Epoc in second/100 units - xboard time units */
68 uint32_t
69 get_time(void)
71 struct timeval t;
72 gettimeofday(&t, 0);
74 return t.tv_sec * 100 + t.tv_usec / 10000;
77 /* check if we should abort search */
78 int
79 check_time(int ply)
81 int i;
83 if (!(counters.searched_nodes & e.chk_time)) {
84 int stop_time = get_engine_value((int *)&e.stop_time);
85 if (get_time() >= stop_time) {
86 if (fail_high_root && (stop_time < get_engine_value((int *)&e.max_stop_time) &&
87 !get_engine_value(&e.fixed_time))) {
88 set_engine_value((int *)&e.stop_time, stop_time + e.max_time);
89 fprintf(stderr, "Extending because fail high at ply 1\n");
90 return FALSE;
92 if (!safe_search && !get_engine_value(&e.fixed_time) &&
93 stop_time < get_engine_value((int *)&e.max_stop_time)) {
94 set_engine_value((int *)&e.stop_time, stop_time + e.max_time / 2);
95 fprintf(stderr, "Extending...\n");
96 return FALSE;
99 /* takeback all moves in search tree */
100 for (i = 0; i < ply; i++)
101 takeback();
102 abort_search = TRUE;
103 return TRUE;
107 return FALSE;
110 /* start new game */
111 void
112 new_game()
114 srand(get_time()); /* for opening book randomization */
115 setup_board(start_position);
117 clear_main_hashtable();
118 clear_pawn_hashtable();
121 /* print brief stats to console. used mostly for debugging */
122 void
123 print_stats(int timediff)
125 double search_time;
126 double move_ordering;
127 int nps;
129 search_time = timediff / 100.0;
130 move_ordering = counters.failed_high_total ? \
131 (counters.failed_high_first / (double) counters.failed_high_total) * \
132 100.0 : -1.0;
133 nps = counters.searched_nodes / search_time;
135 fprintf(stdout, "Time: %.2f, nodes: %llu, NPS: %d/sec, MO: %.2f%%\n" \
136 "NULL: %llu, delta: %llu, LMR: %llu, razor: %llu, futility: %llu\n" \
137 "pawn hash evaluations: %llu, transposition: %llu\n" \
138 "evaluations: %llu, lazy: %.2f%%, phase: %d\n",
139 search_time, counters.searched_nodes, nps, move_ordering,
140 counters.null_move_prunings, counters.delta_prunings,
141 counters.reductions, counters.razorings, counters.futility_prunings,
142 counters.pawn_hash_evaluations, counters.transposition,
143 counters.evaluations, ((double) counters.lazy_evaluations / counters.evaluations) * 100, GAME_PHASE);
146 /* if it's engine's turn to move we should search */
147 void *
148 process_turn(void *args)
150 int move;
151 int move_from_book;
152 char buf[MAX_STRING];
154 move_from_book = TRUE;
155 move = book_move();
157 if (!move) {
158 leave_book++;
159 move_from_book = FALSE;
160 set_engine_value(&e.thinking, TRUE);
161 move = iterate();
162 set_engine_value(&e.thinking, FALSE);
163 } else
164 leave_book = 0;
166 if (move == -1) {
167 fprintf(stdout, "resign\n");
168 if (get_engine_value(&e.side) == WHITE)
169 fprintf(stdout, "0-1 {WHITE looses}\n");
170 else
171 fprintf(stdout, "1-0 {BLACK looses}\n");
172 set_engine_value(&e.side, NOBODY);
174 /* free resources after termination */
175 pthread_detach(pthread_self());
177 return (void *)0;
180 if (!move || evaluate_draw() || reps() >= 3) {
181 if (evaluate_draw()) {
182 if (brd.fifty_rule >= 100)
183 fprintf(stdout, "1/2-1/2 {Fifty move rule}\n");
184 else
185 fprintf(stdout, "1/2-1/2 {insufficient material}\n");
186 } else if (reps() >= 3)
187 fprintf(stdout, "1/2-1/2 {repetition}\n");
188 else if (IS_CHECKED(WHITE))
189 fprintf(stdout, "0-1 {BLACK mates}\n");
190 else if (IS_CHECKED(BLACK))
191 fprintf(stdout, "1-0 {WHITE mates}\n");
192 else
193 fprintf(stdout, "1/2-1/2 {Stalemate}\n");
194 set_engine_value(&e.side, NOBODY);
195 } else {
196 if (get_engine_value(&e.san_notation) || \
197 !get_engine_value(&e.xboard_mode)) {
198 san_move(move, buf);
199 make_move(move, FALSE);
200 fprintf(stdout, "move %s\n", buf);
201 } else {
202 make_move(move, FALSE);
203 fprintf(stdout, "move %s\n", coord_move(move, buf));
206 if (!get_engine_value(&e.xboard_mode) && !move_from_book)
207 fprintf(stdout, "[%s]$ ", program_name);
209 /* free resources after termination */
210 pthread_detach(pthread_self());
212 return (void *)0;
215 void
216 start_engine(void)
218 pthread_mutex_init(&e.mutex, 0);
220 set_engine_value(&e.side, NOBODY);
221 set_engine_value(&e.force_mode, TRUE);
222 set_engine_value(&e.post_mode, FALSE);
223 set_engine_value(&e.xboard_mode, FALSE);
224 set_engine_value(&e.san_notation, FALSE);
226 /* set small limits for quick testing */
227 set_engine_value(&e.max_depth, 9);
228 set_engine_value(&e.max_time, 10000);
229 set_engine_value(&e.inc_time, 0);
231 /* check if we should abort search every 1024 nodes */
232 set_engine_value(&e.chk_time, 1023);
234 /* use 1/30 of total time for thinking */
235 set_engine_value(&e.time_div, 30);
237 set_engine_value(&e.fixed_time, FALSE);
238 set_engine_value((int *)&e.stop_time, 0);
239 set_engine_value((int *)&e.max_stop_time, 0);
241 /* if FALSE we are playing to mate */
242 set_engine_value(&e.resign, TRUE);
243 set_engine_value(&e.resign_value, -600);
245 /* if EPD tests are currently running */
246 set_engine_value(&e.thinking, FALSE);
248 /* search options */
249 set_engine_value(&e.delta_pruning, TRUE);
250 set_engine_value(&e.futility_pruning, TRUE);
251 set_engine_value(&e.iid, TRUE);
252 set_engine_value(&e.null_pruning, TRUE);
253 set_engine_value(&e.lmr, TRUE);
254 set_engine_value(&e.razoring, TRUE);
256 /* used to calculate 'game phase' */
257 set_engine_value(&e.phase_factor, (piece_value[KNIGHT] * 2 + \
258 piece_value[BISHOP] * 2 + piece_value[ROOK] * 2 + \
259 piece_value[QUEEN]) / 128);
261 e.tid = 0;
263 /* initialize hashtable */
264 e.pawn_hash_size = 2;
265 e.main_hash_size = 16;
266 e.pawn_hash_enabled = TRUE;
267 e.main_hash_enabled = TRUE;
269 book_open(book_file_name);
270 new_game();
273 /* free resources */
274 void perform_cleanup(void)
276 /* free memory */
277 if (get_engine_value(&e.pawn_hash_enabled))
278 free_pawn_hashtable();
280 /* destroy engine mutex */
281 pthread_mutex_destroy(&e.mutex);
283 /* close book file descriptor */
284 book_close();