More search tunings and features (NULL SOLIDITY)
[rattatechess.git] / engine.cpp
blob19a7e5420fc5cbb4f5448cc0961fe2f6b1b5050f
1 /***************************************************************************
2 engine.cpp - description
3 -------------------
4 begin : mer ott 23 2002
5 copyright : (C) 2002-2005 by Maurizio Monge
6 email : monge@linuz.sns.it
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include "engine.h"
19 #include "utils.h"
20 #include "commands.h"
21 #include "search_gui.h"
22 #include <string.h>
24 Engine* Engine::instance = NULL;
26 Engine* Engine::eng()
28 return instance;
31 Engine::Engine()
33 instance = this;
35 mv_done = new Move[400];
36 mv_done_num = 0;
38 save_buf = new SaveBuf[4096];
39 save_buf_num = 0;
41 create_hash();
42 reset_hash();
44 analysis_limit = TIME_LIMIT;
45 time_fixed = 2;
47 st_computer_color = BLACK;
48 status = PLAYING;
49 eng_status = PLAYING;
50 thinking = false;
51 status_string = NULL;
52 post = true;
53 ponder = false;
55 io_xboard = false;
56 io_san = false;
57 io_colors = false;
59 /* register engine commands */
60 register_commands();
62 /* register engine variables */
63 register_variables();
65 /* open log file */
66 log = fopen("rattatechess.log", "w");
68 /* open the book */
69 book_mmap = NULL;
70 if(!open_book("ratta.book"))
71 if(!open_book("../ratta.book"))
73 char buf[1024];
74 snprintf(buf, 1024, "%s/ratta.book", getenv("HOME"));
75 open_book(buf);
78 /* open the play lines */
79 if(!open_lines("ratta.lines"))
80 if(!open_lines("../ratta.lines"))
82 char buf[1024];
83 snprintf(buf, 1024, "%s/ratta.lines", getenv("HOME"));
84 open_lines(buf);
87 srand(time(NULL));
88 board.set_as_default();
91 unsigned char Engine::color_to_move()
93 return board.color_to_move;
96 unsigned char Engine::computer_color()
98 return st_computer_color;
101 int Engine::get_status()
103 return status;
106 int Engine::move_number()
108 return board.num_moves;
111 void Engine::start()
113 st_computer_color = board.color_to_move;
114 status = PLAYING;
115 status_string = NULL;
116 eng_status = PLAYING;
117 //output("starting!\n");
118 if(thinking)
119 longjmp(back, 1);
122 void Engine::start(unsigned char color)
124 st_computer_color = color;
125 status = PLAYING;
126 status_string = NULL;
127 eng_status = PLAYING;
128 if(thinking)
129 longjmp(back, 1);
132 void Engine::force()
134 st_computer_color = 0;
135 eng_status = FORCING;
136 if(thinking)
137 longjmp(back, 1);
140 void Engine::analyze()
142 st_computer_color = 0;
143 HashKey h = board.hash;
144 find_best_move();
146 /* exited analyzing without any move being done?
147 (because of a near mate or a book entry found) */
148 while(eng_status==ANALYZING && h == board.hash)
149 process_input();
152 void Engine::do_ponder()
154 HashKey h = board.hash;
155 find_best_move();
157 /* exited pondering without any move being done?
158 (because of a near mate or a book entry found) */
159 while(ponder && eng_status==PLAYING &&
160 st_computer_color == board.other_color && h == board.hash)
161 process_input();
164 void Engine::move_now()
166 if(!thinking)
168 output("You cannot use this command now!\n");
169 return;
172 longjmp(back, 1);
175 /* do the move and update a couple of things */
176 void Engine::move(Move mv)
178 /* save the move in the stack of played moves (from the starting position) */
179 mv_done[mv_done_num++] = mv;
181 board.do_move(mv, save_buf[save_buf_num++]);
183 if(board.insufficient_material())
185 status=_12;
186 status_string = "Insufficient material";
187 return;
190 /* 50mvs rule */
191 if(board.fifty >= 100)
193 status=_12;
194 status_string = "Drawn by 50-move rule";
195 return;
198 /* draw by 3fold repetition */
199 if(check_repetition(3))
201 status = _12;
202 status_string = "Drawn by 3-fold repetition";
203 return;
206 Move mvs[250];
207 if(board.find_moves(mvs)==0) //mate or stalemate...
209 if(board.under_check)
211 if(board.color_to_move==WHITE)
213 status = _01;
214 status_string = "Black mates";
216 else
218 status = _10;
219 status_string = "White mates";
222 else
224 status = _12;
225 status_string = "Stalemate";
227 return;
231 void Engine::retract_move()
233 if(mv_done_num>1)
235 board.undo_move(mv_done[--mv_done_num], save_buf[--save_buf_num]);
236 board.undo_move(mv_done[--mv_done_num], save_buf[--save_buf_num]);
240 void Engine::undo()
242 if(mv_done_num>0)
243 board.undo_move(mv_done[--mv_done_num], save_buf[--save_buf_num]);
244 status = PLAYING;
247 void Engine::new_game()
249 mv_done_num = 0;
250 analysis_limit = TIME_LIMIT;
251 time_fixed = 2;
252 st_computer_color = BLACK;
253 status = PLAYING;
254 eng_status = PLAYING;
256 strcpy(opponent, "<unknown>");
257 w_rating = 0;
258 b_rating = 0;
260 board.set_as_default();
261 reset_hash();
264 void Engine::set_depth(int d)
266 analysis_limit = DEPTH_LIMIT;
267 st_depth = d;
270 void Engine::set_max_nodes(int d)
272 analysis_limit = NODES_LIMIT;
273 st_nodes = d;
276 void Engine::set_time_fixed(int t)
278 analysis_limit = TIME_LIMIT;
279 time_fixed = t;
282 void Engine::set_time_control(int mps, int basesec, int inc)
284 analysis_limit = TIME_LIMIT;
285 time_fixed = 0;
286 time_mps = mps;
287 time_base = basesec;
288 time_inc = inc;
289 time_clock_csec = time_base*100;
292 void Engine::set_my_clock(int t)
294 time_clock_csec = t;
297 void Engine::set_other_clock(int t)
299 time_oth_clock_csec = t;
302 void Engine::print_board()
304 board.print_board();
307 void Engine::read_board(char* brd, char* color, char* castle,
308 char* passing, int moves_to_draw, int num_moves)
310 board.read_board(brd, color,castle,passing,moves_to_draw,num_moves);
311 mv_done_num = 0;
312 reset_hash();
313 if(thinking)
314 longjmp(back, 1);
317 void Engine::read_board(char* str)
319 board.read_board(str);
320 mv_done_num = 0;
321 reset_hash();
322 if(thinking)
323 longjmp(back, 1);
326 void Engine::read_board(FILE* f)
328 char str[256];
329 fgets(str,256,f);
330 board.read_board(str);
333 void Engine::write_board(FILE* f)
335 char str[256];
336 board.write_board(str);
337 fputs(str,f);
340 bool Engine::check_time()
342 processed_nodes++;
344 if( eng_status == PLAYING &&
345 analysis_limit == NODES_LIMIT &&
346 processed_nodes > (unsigned int)st_nodes)
347 longjmp(back, 1);
349 if( (processed_nodes%4096) == 0 )
351 if( eng_status == PLAYING &&
352 analysis_limit == TIME_LIMIT &&
353 current_time()>=max_think_time )
354 longjmp(back, 1);
356 if(search_gui) search_gui->process_events();
358 if(input_available())
360 int n = mv_done_num;
363 process_input();
365 if(n != mv_done_num)
366 longjmp(back, 1);
368 if(eng_status == PLAYING && !ponder
369 && st_computer_color == board.other_color)
370 longjmp(back, 1);
372 while(input_available());
375 return false;
378 //very primitive
379 void Engine::calc_best_time()
381 if(time_fixed)
382 time_best_csec = time_fixed * 100;
383 else
385 int nummoves = (time_mps == 0) ? 30 :
386 MAX((time_mps - (board.num_moves % time_mps)), 30);
387 time_best_csec = time_clock_csec / nummoves + time_inc * 100;
388 //time_best_csec = time_clock_csec / nummoves * (50 + rand()%300) / 200 + time_inc * 100;
392 uint64_t Engine::perft(int lev)
394 Move mv_stack[200];
395 int num;
396 num = board.find_moves(mv_stack);
398 if(lev==1)
399 return num;
400 else
402 uint64_t retv=0;
403 for(int i=0;i<num;i++)
405 board.do_move(mv_stack[i], save_buf[save_buf_num++]);
406 retv+=perft(lev-1);
407 board.undo_move(mv_stack[i], save_buf[--save_buf_num]);
409 return retv;
413 void Engine::autotune()
415 struct Tunable { const char* name; int& param; int start; int end; int step; };
416 Tunable data[] = {
417 { "v_search_threat_threshold", v_search_threat_threshold, 150, 720, 190 },
418 { "v_search_threat_extension", v_search_threat_extension, 40, 120, 80 },
419 { "v_search_null_reduction", v_search_null_reduction, 200, 400, 100 },
421 int numparams = sizeof(data)/sizeof(Tunable);
423 for(int i=0;i<3;i++)
424 for(int p=0;p<numparams;p++)
426 int oldv = data[p].param;
427 int best = 0;
428 int best_goodness = -1;
429 int worst_goodness = 99999;
431 for(data[p].param = data[p].start; data[p].param <= data[p].end; data[p].param += data[p].step)
433 output("\n");
434 for(int k=0;k<numparams;k++)
435 output("%s = %d%s\n", data[k].name, data[k].param, k==p ? " <--" : "");
436 int goodness = run_epd_prog("self", 1, "epd/abbe.epd");
437 if(goodness > best_goodness)
439 best_goodness = goodness;
440 best = data[p].param;
442 if(goodness < worst_goodness)
443 worst_goodness = goodness;
446 if(worst_goodness == best_goodness)
447 data[p].param = oldv;
448 else
449 data[p].param = best;
452 output("\n");
453 output("FINAL REPORT:\n");
454 for(int k=0;k<numparams;k++)
455 output("%s = %d\n", data[k].name, data[k].param);
456 exit(0);