Tuned null move and history prun... ops, late move reduction :)
[rattatechess.git] / engine.cpp
blob7bed80f7770a9e78dced9a9decd4bf2f86e1c769
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 <string.h>
23 Engine* Engine::instance = NULL;
25 Engine* Engine::eng()
27 return instance;
30 Engine::Engine()
32 instance = this;
34 mv_done = new Move[400];
36 create_hash();
37 reset_hash();
39 mv_done_num = 0;
40 analysis_limit = TIME_LIMIT;
41 time_fixed = 2;
43 st_computer_color = BLACK;
44 status = PLAYING;
45 eng_status = PLAYING;
46 thinking = false;
47 status_string = NULL;
48 post = true;//false;
49 ponder = false;
51 io_xboard = false;
52 io_san = false;
53 io_colors = false;
55 /* register engine commands */
56 register_commands();
58 /* register engine variables */
59 register_variables();
61 /* open log file */
62 log = fopen("rattatechess.log", "w");
64 /* open the book */
65 book_mmap = NULL;
66 if(!open_book("ratta.book"))
67 if(!open_book("../ratta.book"))
69 char buf[1024];
70 snprintf(buf, 1024, "%s/ratta.book", getenv("HOME"));
71 open_book(buf);
74 /* open the play lines */
75 if(!open_lines("ratta.lines"))
76 if(!open_lines("../ratta.lines"))
78 char buf[1024];
79 snprintf(buf, 1024, "%s/ratta.lines", getenv("HOME"));
80 open_lines(buf);
83 srand(time(NULL));
84 board.set_as_default();
87 unsigned char Engine::color_to_move()
89 return board.color_to_move;
92 unsigned char Engine::computer_color()
94 return st_computer_color;
97 int Engine::get_status()
99 return status;
102 int Engine::move_number()
104 return board.num_moves;
107 void Engine::start()
109 st_computer_color = board.color_to_move;
110 status = PLAYING;
111 status_string = NULL;
112 eng_status = PLAYING;
113 //output("starting!\n");
114 if(thinking)
115 longjmp(back, 1);
118 void Engine::start(unsigned char color)
120 st_computer_color = color;
121 status = PLAYING;
122 status_string = NULL;
123 eng_status = PLAYING;
124 if(thinking)
125 longjmp(back, 1);
128 void Engine::force()
130 st_computer_color = 0;
131 eng_status = FORCING;
132 if(thinking)
133 longjmp(back, 1);
136 void Engine::analyze()
138 st_computer_color = 0;
139 HashKey h = board.hash;
140 find_best_move();
142 /* exited analyzing without any move being done?
143 (because of a near mate or a book entry found) */
144 while(eng_status==ANALYZING && h == board.hash)
145 process_input();
148 void Engine::do_ponder()
150 HashKey h = board.hash;
151 find_best_move();
153 /* exited pondering without any move being done?
154 (because of a near mate or a book entry found) */
155 while(ponder && eng_status==PLAYING &&
156 st_computer_color == board.other_color && h == board.hash)
157 process_input();
160 void Engine::move_now()
162 if(!thinking)
164 output("You cannot use this command now!\n");
165 return;
168 longjmp(back, 1);
171 /* do the move and update a couple of things */
172 void Engine::move(Move mv)
174 /* save the move in the stack of played moves (from the starting position) */
175 mv_done[mv_done_num++] = mv;
177 board.do_move(mv);
179 if(insufficient_material())
181 status=_12;
182 status_string = "Insufficient material";
183 return;
186 /* 50mvs rule */
187 if(board.fifty >= 100)
189 status=_12;
190 status_string = "Drawn by 50-move rule";
191 return;
194 /* for the latest reversible moves check if the hash value
195 (for this player) is the same */
196 int first_candidate = MAX(board.num_old_hashes-(board.fifty/2)*2, 0);
197 int repeat = 1;
198 for(int i=board.num_old_hashes-4;i>=first_candidate;i-=2)
200 if(board.hash == board.old_hashes[i])
201 repeat++;
202 if(repeat>=3)
204 status = _12;
205 status_string = "Drawn by 3-fold repetition";
206 return;
210 Move mvs[250];
211 if(board.find_moves(mvs)==0) //mate or stalemate...
213 if(board.under_check)
215 if(board.color_to_move==WHITE)
217 status = _01;
218 status_string = "Black mates";
220 else
222 status = _10;
223 status_string = "White mates";
226 else
228 status = _12;
229 status_string = "Stalemate";
231 return;
235 void Engine::retract_move()
237 if(mv_done_num>1)
238 board.undo_move(mv_done[--mv_done_num]);
239 board.undo_move(mv_done[--mv_done_num]);
242 void Engine::undo()
244 if(mv_done_num>0)
245 board.undo_move(mv_done[--mv_done_num]);
246 status = PLAYING;
249 void Engine::new_game()
251 mv_done_num = 0;
252 analysis_limit = TIME_LIMIT;
253 time_fixed = 2;
254 st_computer_color = BLACK;
255 status = PLAYING;
256 eng_status = PLAYING;
258 strcpy(opponent, "<unknown>");
259 w_rating = 0;
260 b_rating = 0;
262 board.set_as_default();
263 reset_hash();
266 void Engine::set_depth(int d)
268 analysis_limit = DEPTH_LIMIT;
269 st_depth = d;
272 void Engine::set_max_nodes(int d)
274 analysis_limit = NODES_LIMIT;
275 st_nodes = d;
278 void Engine::set_time_fixed(int t)
280 analysis_limit = TIME_LIMIT;
281 time_fixed = t;
284 void Engine::set_time_control(int mps, int basesec, int inc)
286 analysis_limit = TIME_LIMIT;
287 time_fixed = 0;
288 time_mps = mps;
289 time_base = basesec;
290 time_inc = inc;
291 time_clock_csec = time_base*100;
294 void Engine::set_my_clock(int t)
296 time_clock_csec = t;
299 void Engine::set_other_clock(int t)
301 time_oth_clock_csec = t;
304 void Engine::print_board()
306 board.print_board();
309 void Engine::read_board(char* brd, char* color, char* castle,
310 char* passing, int moves_to_draw, int num_moves)
312 board.read_board(brd, color,castle,passing,moves_to_draw,num_moves);
313 mv_done_num = 0;
314 reset_hash();
315 if(thinking)
316 longjmp(back, 1);
319 void Engine::read_board(char* str)
321 board.read_board(str);
322 mv_done_num = 0;
323 reset_hash();
324 if(thinking)
325 longjmp(back, 1);
328 void Engine::read_board(FILE* f)
330 char str[256];
331 fgets(str,256,f);
332 board.read_board(str);
335 void Engine::write_board(FILE* f)
337 char str[256];
338 board.write_board(str);
339 fputs(str,f);
342 bool Engine::check_time()
344 processed_nodes++;
345 //return false;
347 if( eng_status == PLAYING &&
348 analysis_limit == NODES_LIMIT &&
349 processed_nodes > (unsigned int)st_nodes)
351 rewind_thinking();
352 longjmp(back, 1);
355 if( (processed_nodes%4096) == 0 )
357 if( eng_status == PLAYING &&
358 analysis_limit == TIME_LIMIT &&
359 current_time()>=max_think_time )
361 rewind_thinking();
362 longjmp(back, 1);
365 if(input_available())
367 rewind_thinking();
369 int n = mv_done_num;
372 process_input();
374 if(n != mv_done_num)
375 longjmp(back, 1);
377 if(eng_status == PLAYING && !ponder
378 && st_computer_color == board.other_color)
379 longjmp(back, 1);
381 while(input_available());
383 restore_thinking();
386 return false;
389 //very primitive
390 void Engine::calc_best_time()
392 if(time_fixed)
393 time_best_csec = time_fixed * 100;
394 else
396 int nummoves = (time_mps == 0) ? 30 :
397 MAX((time_mps - (board.num_moves % time_mps)), 30);
398 time_best_csec = time_clock_csec / nummoves + time_inc * 100;
402 uint64_t Engine::perft(int lev)
404 Move mv_stack[200];
405 int num;
406 num = board.find_moves(mv_stack);
408 if(lev==1)
409 return num;
410 else
412 uint64_t retv=0;
413 for(int i=0;i<num;i++)
415 board.do_move(mv_stack[i]);
416 retv+=perft(lev-1);
417 board.undo_move(mv_stack[i]);
419 return retv;
423 void Engine::autotune()
425 struct Tunable { const char* name; int& param; int start; int end; int step; };
426 Tunable data[] = {
427 { "v_search_threat_threshold", v_search_threat_threshold, 150, 720, 190 },
428 { "v_search_threat_extension", v_search_threat_extension, 40, 120, 80 },
429 { "v_search_null_reduction", v_search_null_reduction, 200, 400, 100 },
431 int numparams = sizeof(data)/sizeof(Tunable);
433 for(int i=0;i<3;i++)
434 for(int p=0;p<numparams;p++)
436 int oldv = data[p].param;
437 int best = 0;
438 int best_goodness = -1;
439 int worst_goodness = 99999;
441 for(data[p].param = data[p].start; data[p].param <= data[p].end; data[p].param += data[p].step)
443 output("\n");
444 for(int k=0;k<numparams;k++)
445 output("%s = %d%s\n", data[k].name, data[k].param, k==p ? " <--" : "");
446 int goodness = run_epd_prog("self", 1, "epd/abbe.epd");
447 if(goodness > best_goodness)
449 best_goodness = goodness;
450 best = data[p].param;
452 if(goodness < worst_goodness)
453 worst_goodness = goodness;
456 if(worst_goodness == best_goodness)
457 data[p].param = oldv;
458 else
459 data[p].param = best;
462 output("\n");
463 output("FINAL REPORT:\n");
464 for(int k=0;k<numparams;k++)
465 output("%s = %d\n", data[k].name, data[k].param);
466 exit(0);