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.
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
51 get_engine_value(int *val
)
55 pthread_mutex_lock(&e
.mutex
);
57 pthread_mutex_unlock(&e
.mutex
);
63 * Set value in thread-safe way
66 set_engine_value(int *src
, int new_value
)
68 pthread_mutex_lock(&e
.mutex
);
70 pthread_mutex_unlock(&e
.mutex
);
73 /* time from Epoc in second/100 units - xboard time units */
80 return t
.tv_sec
* 100 + t
.tv_usec
/ 10000;
83 /* check if we should abort search */
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
))
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");
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");
108 /* takeback all moves in search tree */
109 for (i
= 0; i
< ply
; i
++)
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 */
132 print_stats(int timediff
)
135 double move_ordering
;
138 search_time
= timediff
/ 100.0;
139 move_ordering
= counters
.failed_high_total
? \
140 (counters
.failed_high_first
/ (double) counters
.failed_high_total
) * \
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 */
157 process_turn(void *args
)
161 char buf
[MAX_STRING
];
162 char ponder_candidate
[32];
164 return_ponder
[0] = 0;
166 move_from_book
= TRUE
;
171 move_from_book
= FALSE
;
172 set_engine_value(&e
.thinking
, TRUE
);
173 move
= iterate(ponder_candidate
);
174 set_engine_value(&e
.thinking
, FALSE
);
178 set_engine_value((int *)&e
.ponderhit
, FALSE
);
180 fprintf(stdout
, "resign\n");
181 if (get_engine_value(&e
.side
) == WHITE
)
182 fprintf(stdout
, "0-1 {WHITE looses}\n");
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());
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");
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");
206 fprintf(stdout
, "1/2-1/2 {Stalemate}\n");
207 set_engine_value(&e
.side
, NOBODY
);
209 if (get_engine_value(&e
.san_notation
) || \
210 !get_engine_value(&e
.xboard_mode
)) {
212 make_move(move
, FALSE
);
213 fprintf(stdout
, "move %s\n", buf
);
215 /* create struct with all possible replies to simplify parsing
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
++) {
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
);
235 ponder_candidate
[0] = 0;
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 */
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
);
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
))
261 if (get_engine_value(&e
.ponderhit
) ||
262 get_engine_value(&e
.stop_time
))
264 return_ponder
[0] = 0;
265 set_engine_value((int *)&e
.pondering
, 0);
268 return_ponder
[0] = 0;
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());
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
);
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);
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
);
347 void perform_cleanup(void)
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 */