Various tunings.
[rattatechess.git] / engine.cpp
blobceece769e6f48a01c1f022a4993284e2538e7aa2
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];
37 create_hash();
38 reset_hash();
40 mv_done_num = 0;
41 analysis_limit = TIME_LIMIT;
42 time_fixed = 2;
44 st_computer_color = BLACK;
45 status = PLAYING;
46 eng_status = PLAYING;
47 thinking = false;
48 status_string = NULL;
49 post = true;//false;
50 ponder = false;
52 io_xboard = false;
53 io_san = false;
54 io_colors = false;
56 /* register engine commands */
57 register_commands();
59 /* register engine variables */
60 register_variables();
62 /* open log file */
63 log = fopen("rattatechess.log", "w");
65 /* open the book */
66 book_mmap = NULL;
67 if(!open_book("ratta.book"))
68 if(!open_book("../ratta.book"))
70 char buf[1024];
71 snprintf(buf, 1024, "%s/ratta.book", getenv("HOME"));
72 open_book(buf);
75 /* open the play lines */
76 if(!open_lines("ratta.lines"))
77 if(!open_lines("../ratta.lines"))
79 char buf[1024];
80 snprintf(buf, 1024, "%s/ratta.lines", getenv("HOME"));
81 open_lines(buf);
84 srand(time(NULL));
85 board.set_as_default();
88 unsigned char Engine::color_to_move()
90 return board.color_to_move;
93 unsigned char Engine::computer_color()
95 return st_computer_color;
98 int Engine::get_status()
100 return status;
103 int Engine::move_number()
105 return board.num_moves;
108 void Engine::start()
110 st_computer_color = board.color_to_move;
111 status = PLAYING;
112 status_string = NULL;
113 eng_status = PLAYING;
114 //output("starting!\n");
115 if(thinking)
116 longjmp(back, 1);
119 void Engine::start(unsigned char color)
121 st_computer_color = color;
122 status = PLAYING;
123 status_string = NULL;
124 eng_status = PLAYING;
125 if(thinking)
126 longjmp(back, 1);
129 void Engine::force()
131 st_computer_color = 0;
132 eng_status = FORCING;
133 if(thinking)
134 longjmp(back, 1);
137 void Engine::analyze()
139 st_computer_color = 0;
140 HashKey h = board.hash;
141 find_best_move();
143 /* exited analyzing without any move being done?
144 (because of a near mate or a book entry found) */
145 while(eng_status==ANALYZING && h == board.hash)
146 process_input();
149 void Engine::do_ponder()
151 HashKey h = board.hash;
152 find_best_move();
154 /* exited pondering without any move being done?
155 (because of a near mate or a book entry found) */
156 while(ponder && eng_status==PLAYING &&
157 st_computer_color == board.other_color && h == board.hash)
158 process_input();
161 void Engine::move_now()
163 if(!thinking)
165 output("You cannot use this command now!\n");
166 return;
169 longjmp(back, 1);
172 /* do the move and update a couple of things */
173 void Engine::move(Move mv)
175 /* save the move in the stack of played moves (from the starting position) */
176 mv_done[mv_done_num++] = mv;
178 board.do_move(mv);
180 if(insufficient_material())
182 status=_12;
183 status_string = "Insufficient material";
184 return;
187 /* 50mvs rule */
188 if(board.fifty >= 100)
190 status=_12;
191 status_string = "Drawn by 50-move rule";
192 return;
195 /* for the latest reversible moves check if the hash value
196 (for this player) is the same */
197 int first_candidate = MAX(board.num_old_hashes-(board.fifty/2)*2, 0);
198 int repeat = 1;
199 for(int i=board.num_old_hashes-4;i>=first_candidate;i-=2)
201 if(board.hash == board.old_hashes[i])
202 repeat++;
203 if(repeat>=3)
205 status = _12;
206 status_string = "Drawn by 3-fold repetition";
207 return;
211 Move mvs[250];
212 if(board.find_moves(mvs)==0) //mate or stalemate...
214 if(board.under_check)
216 if(board.color_to_move==WHITE)
218 status = _01;
219 status_string = "Black mates";
221 else
223 status = _10;
224 status_string = "White mates";
227 else
229 status = _12;
230 status_string = "Stalemate";
232 return;
236 void Engine::retract_move()
238 if(mv_done_num>1)
239 board.undo_move(mv_done[--mv_done_num]);
240 board.undo_move(mv_done[--mv_done_num]);
243 void Engine::undo()
245 if(mv_done_num>0)
246 board.undo_move(mv_done[--mv_done_num]);
247 status = PLAYING;
250 void Engine::new_game()
252 mv_done_num = 0;
253 analysis_limit = TIME_LIMIT;
254 time_fixed = 2;
255 st_computer_color = BLACK;
256 status = PLAYING;
257 eng_status = PLAYING;
259 strcpy(opponent, "<unknown>");
260 w_rating = 0;
261 b_rating = 0;
263 board.set_as_default();
264 reset_hash();
267 void Engine::set_depth(int d)
269 analysis_limit = DEPTH_LIMIT;
270 st_depth = d;
273 void Engine::set_max_nodes(int d)
275 analysis_limit = NODES_LIMIT;
276 st_nodes = d;
279 void Engine::set_time_fixed(int t)
281 analysis_limit = TIME_LIMIT;
282 time_fixed = t;
285 void Engine::set_time_control(int mps, int basesec, int inc)
287 analysis_limit = TIME_LIMIT;
288 time_fixed = 0;
289 time_mps = mps;
290 time_base = basesec;
291 time_inc = inc;
292 time_clock_csec = time_base*100;
295 void Engine::set_my_clock(int t)
297 time_clock_csec = t;
300 void Engine::set_other_clock(int t)
302 time_oth_clock_csec = t;
305 void Engine::print_board()
307 board.print_board();
310 void Engine::read_board(char* brd, char* color, char* castle,
311 char* passing, int moves_to_draw, int num_moves)
313 board.read_board(brd, color,castle,passing,moves_to_draw,num_moves);
314 mv_done_num = 0;
315 reset_hash();
316 if(thinking)
317 longjmp(back, 1);
320 void Engine::read_board(char* str)
322 board.read_board(str);
323 mv_done_num = 0;
324 reset_hash();
325 if(thinking)
326 longjmp(back, 1);
329 void Engine::read_board(FILE* f)
331 char str[256];
332 fgets(str,256,f);
333 board.read_board(str);
336 void Engine::write_board(FILE* f)
338 char str[256];
339 board.write_board(str);
340 fputs(str,f);
343 bool Engine::check_time()
345 processed_nodes++;
346 //return false;
348 if( eng_status == PLAYING &&
349 analysis_limit == NODES_LIMIT &&
350 processed_nodes > (unsigned int)st_nodes)
352 rewind_thinking();
353 longjmp(back, 1);
356 if( (processed_nodes%4096) == 0 )
358 if( eng_status == PLAYING &&
359 analysis_limit == TIME_LIMIT &&
360 current_time()>=max_think_time )
362 rewind_thinking();
363 longjmp(back, 1);
366 if(search_gui) search_gui->process_events();
368 if(input_available())
370 rewind_thinking();
372 int n = mv_done_num;
375 process_input();
377 if(n != mv_done_num)
378 longjmp(back, 1);
380 if(eng_status == PLAYING && !ponder
381 && st_computer_color == board.other_color)
382 longjmp(back, 1);
384 while(input_available());
386 restore_thinking();
389 return false;
392 //very primitive
393 void Engine::calc_best_time()
395 if(time_fixed)
396 time_best_csec = time_fixed * 100;
397 else
399 int nummoves = (time_mps == 0) ? 30 :
400 MAX((time_mps - (board.num_moves % time_mps)), 30);
401 time_best_csec = time_clock_csec / nummoves + time_inc * 100;
402 //time_best_csec = time_clock_csec / nummoves * (50 + rand()%300) / 200 + time_inc * 100;
406 uint64_t Engine::perft(int lev)
408 Move mv_stack[200];
409 int num;
410 num = board.find_moves(mv_stack);
412 if(lev==1)
413 return num;
414 else
416 uint64_t retv=0;
417 for(int i=0;i<num;i++)
419 board.do_move(mv_stack[i]);
420 retv+=perft(lev-1);
421 board.undo_move(mv_stack[i]);
423 return retv;
427 void Engine::autotune()
429 struct Tunable { const char* name; int& param; int start; int end; int step; };
430 Tunable data[] = {
431 { "v_search_threat_threshold", v_search_threat_threshold, 150, 720, 190 },
432 { "v_search_threat_extension", v_search_threat_extension, 40, 120, 80 },
433 { "v_search_null_reduction", v_search_null_reduction, 200, 400, 100 },
435 int numparams = sizeof(data)/sizeof(Tunable);
437 for(int i=0;i<3;i++)
438 for(int p=0;p<numparams;p++)
440 int oldv = data[p].param;
441 int best = 0;
442 int best_goodness = -1;
443 int worst_goodness = 99999;
445 for(data[p].param = data[p].start; data[p].param <= data[p].end; data[p].param += data[p].step)
447 output("\n");
448 for(int k=0;k<numparams;k++)
449 output("%s = %d%s\n", data[k].name, data[k].param, k==p ? " <--" : "");
450 int goodness = run_epd_prog("self", 1, "epd/abbe.epd");
451 if(goodness > best_goodness)
453 best_goodness = goodness;
454 best = data[p].param;
456 if(goodness < worst_goodness)
457 worst_goodness = goodness;
460 if(worst_goodness == best_goodness)
461 data[p].param = oldv;
462 else
463 data[p].param = best;
466 output("\n");
467 output("FINAL REPORT:\n");
468 for(int k=0;k<numparams;k++)
469 output("%s = %d\n", data[k].name, data[k].param);
470 exit(0);