Small fixes.
[rattatechess.git] / commands.cpp
blobcc890dd4602ba69880de7afd291db9ca74ed3d6d
1 /***************************************************************************
2 commandparse.cpp - description
3 -------------------
4 begin : sab nov 2 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 "commands.h"
20 #include "utils.h"
21 #include <stdarg.h>
22 #include <signal.h>
23 #include <string.h>
25 void Engine::Cmd::run(int argc, char *argv[])
27 (Engine::eng()->*m_func)(argc, argv);
30 Engine::Variable::Variable(int (Engine::*ivar), int def_val, const char *d)
31 : m_type(Integer)
32 , m_desc(d)
33 , m_buf(NULL)
34 , m_int_var(ivar)
35 , m_range_min(INT_MIN)
36 , m_range_max(INT_MAX)
38 Engine::eng()->*m_int_var = def_val;
41 Engine::Variable::Variable(int (Engine::*ivar), int def_val, int min, int max, const char *d)
42 : m_type(Integer)
43 , m_desc(d)
44 , m_buf(NULL)
45 , m_int_var(ivar)
46 , m_range_min(min)
47 , m_range_max(max)
49 Engine::eng()->*m_int_var = def_val;
52 Engine::Variable::Variable(char* (Engine::*svar), const char* def_val, const char *d)
53 : m_type(String)
54 , m_desc(d)
55 , m_buf(NULL)
56 , m_string_var(svar)
58 Engine::eng()->*m_string_var = strdup(def_val);
61 Engine::Variable::Variable(VarSetFunc set, VarGetFunc get, const char *d)
62 : m_type(String)
63 , m_desc(d)
64 , m_custom_data(NULL)
65 , m_custom_set(set)
66 , m_custom_get(get)
70 Engine::Variable::Variable(VarSetFunc set, VarGetFunc get, void* data, const char *d)
71 : m_type(String)
72 , m_desc(d)
73 , m_custom_data(data)
74 , m_custom_set(set)
75 , m_custom_get(get)
79 void Engine::Variable::from_string(const char* s)
81 if(m_buf)
83 free(m_buf);
84 m_buf = NULL;
87 switch(m_type)
89 case Integer:
91 int v = atoi(s);
92 if(v < m_range_min || v > m_range_max)
93 printf("Error! value %d out of range (%d-%d)\n", v, m_range_min, m_range_max);
94 else
95 Engine::eng()->*m_int_var = v;
96 break;
99 case String:
100 if(Engine::eng()->*m_string_var)
101 free(Engine::eng()->*m_string_var);
102 Engine::eng()->*m_string_var = strdup(s);
103 break;
105 case Custom:
106 (Engine::eng()->*m_custom_set)(m_custom_data, s);
107 break;
109 default:
110 break;
114 char* str_printf(const char* fmt, ...) {
115 va_list ap;
117 va_start(ap, fmt);
118 int l = vsnprintf(NULL, 0, fmt, ap)+1;
119 va_end(ap);
121 char *str = (char*)malloc(l);
123 va_start(ap, fmt);
124 vsnprintf(str, l, fmt, ap);
125 va_end(ap);
127 return str;
130 const char* Engine::Variable::to_string()
132 if(m_buf)
133 free(m_buf);
135 switch(m_type)
137 case Integer:
138 m_buf = str_printf("%d", Engine::eng()->*m_int_var);
139 break;
141 case String:
142 m_buf = strdup(Engine::eng()->*m_string_var);
143 break;
145 case Custom:
146 m_buf = (Engine::eng()->*m_custom_get)(m_custom_data);
147 break;
149 default:
150 m_buf = NULL;
151 break;
154 return m_buf;
157 static void print_description(int indent, const char* desc)
159 if(!desc)
161 for(int i=0;i<indent;i++)
162 fwrite(" ", 1, 1, stdout);
163 printf("<No description>\n\n");
164 return;
167 while(1)
169 int l = strcspn(desc, "\n");
170 l += strspn(desc+l, "\n");
171 if(!l)
172 break;
173 for(int i=0;i<indent;i++)
174 fwrite(" ", 1, 1, stdout);
175 fwrite(desc, 1, l, stdout);
176 desc += l;
178 fwrite("\n", 1, 1, stdout);
181 void Engine::cmd_quit(int argc, char *argv[])
183 exit(0);
186 void Engine::cmd_ping(int argc, char *argv[])
188 printf("pong %s\n",argv[0]);
191 void Engine::cmd_bench(int argc, char *argv[])
195 void Engine::cmd_perft(int argc, char *argv[])
197 int t = current_time();
198 uint64_t p = perft( atoi(argv[0]) );
199 printf("%lld (time %.02f)\n", (long long)p, (current_time()-t)*0.01 );
202 void Engine::cmd_perftall(int argc, char *argv[])
204 int lev = atoi(argv[0]);
205 Move mv_stack[200];
206 int num;
207 num = board.find_moves(mv_stack);
209 printf("---------\n");
210 for(int i=0;i<num;i++)
212 int p;
213 char buf[32];
214 board.do_move(mv_stack[i]);
215 p = perft(lev);
216 board.undo_move(mv_stack[i]);
217 printf("%s: %d\n", move_to_alg(buf, &mv_stack[i]), p);
219 printf("---------\n");
222 void Engine::cmd_sd(int argc, char *argv[])
224 set_depth( atoi(argv[0]) );
227 void Engine::cmd_st(int argc, char *argv[])
229 set_time_fixed( atoi(argv[0]) );
232 void Engine::cmd_sn(int argc, char *argv[])
234 set_max_nodes( atoi(argv[0]) );
237 void Engine::cmd_otim(int argc, char *argv[])
239 set_other_clock( atoi(argv[0]) );
242 void Engine::cmd_time(int argc, char *argv[])
244 set_my_clock( atoi(argv[0]) );
247 void Engine::cmd_level(int argc, char *argv[])
249 int basem,bases=0;
250 sscanf(argv[1],"%d:%d",&basem,&bases);
252 set_time_control( atoi(argv[0]) ,basem*60+bases, atoi(argv[2]) );
255 void Engine::cmd_help(int argc, char *argv[])
257 for(CmdSet::iterator it = commands.begin(); it != commands.end(); ++it)
259 if(!it->second.max())
260 printf(" %s\n", it->first.c_str() );
261 else if(it->second.min() == it->second.max())
262 printf(" %s (%d %s)\n", it->first.c_str(), it->second.min(), it->second.min()==1?"arg":"args" );
263 else
264 printf(" %s (%d-%d args)\n", it->first.c_str(), it->second.min(), it->second.max() );
266 print_description(4, it->second.desc());
270 void Engine::cmd_force(int argc, char *argv[])
272 force();
275 void Engine::cmd_undo(int argc, char *argv[])
277 undo();
278 if(!io_xboard)
279 print_board();
282 void Engine::cmd_remove(int argc, char *argv[])
284 retract_move();
285 if(!io_xboard)
286 print_board();
289 void Engine::cmd_new(int argc, char *argv[])
291 new_game();
292 if(!io_xboard)
293 print_board();
296 void Engine::cmd_white(int argc, char *argv[])
298 board.color_to_move = WHITE;
299 board.other_color = BLACK;
300 start(BLACK);
303 void Engine::cmd_black(int argc, char *argv[])
305 board.color_to_move = BLACK;
306 board.other_color = WHITE;
307 start(WHITE);
310 void Engine::cmd_go(int argc, char *argv[])
312 start();
315 void Engine::cmd_setboard(int argc, char *argv[])
317 read_board(argv[0], argv[1], argv[2], argv[3], atoi(argv[4]), atoi(argv[5]) );
318 if(!io_xboard)
319 print_board();
322 void Engine::cmd_edit(int argc, char *argv[])
324 //output("Unimplemented!\n");
325 char str[256];
326 while(1)
328 if(!fgets(str, 256, stdin))
329 exit(0);
331 if(str[0]=='.')
332 break;
336 void Engine::cmd_load(int argc, char *argv[])
338 FILE* f = fopen(argv[0],"r");
339 if(f)
341 read_board(f);
342 fclose(f);
343 if(!io_xboard)
344 print_board();
346 else
347 output("Error, could not open \"%s\" for reading.\n", argv[0]);
350 void Engine::cmd_load_pgn(int argc, char *argv[])
352 FILE* f = fopen(argv[0],"r");
353 if(!f)
354 output("Error, could not open \"%s\" for reading.\n", argv[0]);
356 st_computer_color = 0;
357 load_pgn(f);
358 fclose(f);
359 if(!io_xboard)
360 print_board();
363 void Engine::cmd_epdtest(int argc, char *argv[])
365 run_epd_prog(argv[0], atoi(argv[1]), argv[2]);
368 void Engine::cmd_challenge(int argc, char *argv[])
370 challenge(argv[0], atoi(argv[1]), argv[2]);
373 void Engine::cmd_create_book(int argc, char *argv[])
375 create_book(argc, argv);
378 void Engine::cmd_open_book(int argc, char *argv[])
380 open_book(argv[0]);
383 void Engine::cmd_close_book(int argc, char *argv[])
385 close_book();
388 void Engine::cmd_save(int argc, char *argv[])
390 FILE* f = fopen(argv[0],"w");
391 if(f)
393 write_board(f);
394 fclose(f);
396 else
397 output("Error, could not open \"%s\" for writing.\n", argv[0]);
401 void Engine::cmd_test(int argc, char *argv[])
403 printf("test");
404 for(int i=0;i< argc;i++)
405 printf(" \"%s\"", argv[i]);
406 printf("\n");
409 void Engine::cmd_protover(int argc, char *argv[])
411 static const char* features[] = {
412 "san=1",
413 "ping=1",
414 "setboard=1",
415 "sigint=0",
416 "sigterm=0",
417 "analyze=1",
418 "draw=0",
419 "colors=0",
420 "variants=\"normal\"",
421 "myname=\"RattateChess 1.0-rc1 Bologna 2007\"",
422 "done=1"
424 for(unsigned int i=0; i<sizeof(features)/sizeof(const char*); i++)
425 output("feature %s\n", features[i]);
428 void Engine::cmd_accepted(int argc, char *argv[])
430 if(0 == strcmp("san",argv[0]))
431 io_san = true;
434 void Engine::cmd_rejected(int argc, char *argv[])
439 void Engine::cmd_xboard(int argc, char *argv[])
441 io_xboard = true;
442 signal(SIGINT, SIG_IGN);
445 void Engine::cmd_analyze(int argc, char *argv[])
447 eng_status = ANALYZING;
448 if(thinking)
449 longjmp(back, 1);
452 void Engine::cmd_exit(int argc, char *argv[])
454 eng_status = FORCING;
455 if(thinking)
456 longjmp(back, 1);
459 void Engine::cmd_easy(int argc, char *argv[])
461 ponder = false;
464 void Engine::cmd_hard(int argc, char *argv[])
466 ponder = true;
469 void Engine::cmd_post(int argc, char *argv[])
471 post = true;
474 void Engine::cmd_nopost(int argc, char *argv[])
476 post = false;
479 void Engine::cmd_result(int argc, char *argv[])
481 if(!strcmp(argv[0], "1-0"))
482 status = _10;
483 else if(!strcmp(argv[0], "0-1"))
484 status = _01;
485 else if(!strcmp(argv[0], "1/2-1/2"))
486 status = _12;
487 else
488 output("Unknown result command!\n");
490 if(st_computer_color)
492 FILE *f = fopen("ratta.games", "a");
493 if(f)
495 char all_res[2048];
496 all_res[0] = '\0';
497 for(int i=0;i<argc;i++)
499 strcat(all_res, argv[i]);
500 if(i!=argc-1)
501 strcat(all_res, " " );
503 save_pgn(f, argv[0], all_res);
504 fclose(f);
509 void Engine::cmd_DOT(int argc, char *argv[])
511 print_stat();
514 void Engine::cmd_QUESTION(int argc, char *argv[])
516 move_now();
519 void Engine::cmd_name(int argc, char *argv[])
521 strncpy(opponent, argv[0], 256);
522 opponent[255] = '\0';
525 void Engine::cmd_rating(int argc, char *argv[])
527 w_rating = atoi(argv[0]);
528 b_rating = atoi(argv[1]);
531 void Engine::cmd__check(int argc, char *argv[])
533 Move m;
534 if(parse_move(&m, argv[0])!=1)
536 output("Not a legal move\n");
537 return;
540 board.find_other_pins();
541 if(board.move_is_check(m))
542 output("Yes it is a check\n");
543 else
544 output("Not a check\n");
547 void Engine::cmd__attacks(int argc, char *argv[])
549 uint8_t col = argv[1][0] == 'w' ? WHITE : BLACK;
550 uint8_t pos = POS_XY(argv[0][0]-'a', argv[0][1]-'1' );
551 Board::AttackList al[12];
552 int alnum = board.list_attackers(pos, col, col == board.color_to_move ?
553 board.pins : board.oth_pins, al);
554 for(int i=0;i<alnum;i++)
556 static char nam[] = { 0, 'r', 'b', 'q', 'n', 'p', 'k' };
557 for(int j=0;j<al[i].count;j++)
558 printf("%c ", nam[al[i].piece[j]]);
559 printf("\n");
563 void Engine::cmd__shat(int argc, char *argv[])
565 #if TRACK_ATTACKS
566 board.print_attacks();
567 #else
568 output("Unsupported.\n");
569 #endif
572 void Engine::cmd__see(int argc, char *argv[])
574 Move m;
575 if(parse_move(&m, argv[0])!=1)
577 output("Not a legal move\n");
578 return;
581 output("SEE val: %d\n", board.move_see_val(m));
584 void Engine::cmd__find_moves(int argc, char *argv[])
586 char str[64];
587 Move mv[200];
588 int n = board.find_moves(mv);
590 for(int i=0;i<n;i++)
591 output(" - %s\n", move_to_alg(str, mv+i) );
594 void Engine::cmd__gen_hash(int argc, char *argv[])
596 Board::init_hash_keys( argv[0] );
599 void Engine::cmd_var(int argc, char *argv[])
601 for(VariableSet::iterator it = variables.begin(); it != variables.end(); ++it)
603 printf(" %s = %s\n", it->first.c_str(), it->second.to_string() );
607 void Engine::cmd_varhelp(int argc, char *argv[])
609 for(VariableSet::iterator it = variables.begin(); it != variables.end(); ++it)
611 printf(" %s = %s\n", it->first.c_str(), it->second.to_string() );
612 print_description(4, it->second.desc());
616 void Engine::register_commands()
618 commands["_see"] = Cmd( &Engine::cmd__see, 1,
619 "_see [move]\n"
620 "Calculates the SEE value of a move\n");
621 commands["_shat"] = Cmd( &Engine::cmd__shat,
622 "Shows all attacks\n" );
623 commands["_attacks"] = Cmd( &Engine::cmd__attacks, 2,
624 "_attacks [w|b] [square|a1|a2|...]\n"
625 "Shows all attackers of a square from a color\n" );
626 commands["_check"] = Cmd( &Engine::cmd__check, 1 );
627 commands["_find_moves"] = Cmd( &Engine::cmd__find_moves );
628 commands["_gen_hash"] = Cmd( &Engine::cmd__gen_hash );
629 //commands["exit"] = Cmd( &Engine::cmd_quit );
630 commands["quit"] = Cmd( &Engine::cmd_quit );
631 commands["ping"] = Cmd( &Engine::cmd_ping, 1 );
632 commands["bench"] = Cmd( &Engine::cmd_bench );
633 commands["perft"] = Cmd( &Engine::cmd_perft, 1 );
634 commands["perftall"] = Cmd( &Engine::cmd_perftall, 1 );
635 commands["sd"] = Cmd( &Engine::cmd_sd, 1 );
636 commands["st"] = Cmd( &Engine::cmd_st, 1 );
637 commands["sn"] = Cmd( &Engine::cmd_sn, 1 );
638 commands["otim"] = Cmd( &Engine::cmd_otim, 1 );
639 commands["time"] = Cmd( &Engine::cmd_time, 1 );
640 commands["level"] = Cmd( &Engine::cmd_level, 3 );
641 commands["help"] = Cmd( &Engine::cmd_help,
642 "Printf this help\n" );
643 commands["force"] = Cmd( &Engine::cmd_force,
644 "Puts the engine in 'force' mode (ie edit game)\n" );
645 commands["undo"] = Cmd( &Engine::cmd_undo );
646 commands["remove"] = Cmd( &Engine::cmd_remove );
647 commands["new"] = Cmd( &Engine::cmd_new );
648 commands["white"] = Cmd( &Engine::cmd_white );
649 commands["black"] = Cmd( &Engine::cmd_black );
650 commands["go"] = Cmd( &Engine::cmd_go );
651 commands["setboard"] = Cmd( &Engine::cmd_setboard, 6,
652 "Sets a FEN string as the current position\n" );
653 commands["edit"] = Cmd( &Engine::cmd_edit,
654 "Puts the engine in (old style) position editing mode\n" );
655 commands["load"] = Cmd( &Engine::cmd_load, 1 );
656 commands["load_pgn"] = Cmd( &Engine::cmd_load_pgn, 1 );
657 commands["epdtest"] = Cmd( &Engine::cmd_epdtest, 3,
658 "Runs an epd test with a chess program and a given time out for each\n"
659 "problem. It requires 3 arguments: the first must be an xboard program\n"
660 "path or 'self', the second the time to think in millseconds, and the\n"
661 "third is the file containing the test positions\n");
662 commands["challenge"] = Cmd( &Engine::cmd_challenge, 3 );
663 commands["create_book"] = Cmd( &Engine::cmd_create_book, 1,
664 "Creates a book file using as argument the path of a PGN file with\n"
665 "a database of games. See also the 'vars' command and the variables\n"
666 "named book_creation_*, that you can use to change many parameters\n" );
667 commands["open_book"] = Cmd( &Engine::cmd_open_book, 1,
668 "Loads a book file\n" );
669 commands["close_book"] = Cmd( &Engine::cmd_close_book,
670 "Closes the book (and make the engine use no book)\n" );
671 commands["save"] = Cmd( &Engine::cmd_save, 1 );
672 commands["test"] = Cmd( &Engine::cmd_test );
673 commands["protover"] = Cmd( &Engine::cmd_protover, 1 );
674 commands["accepted"] = Cmd( &Engine::cmd_accepted, 1 );
675 commands["rejected"] = Cmd( &Engine::cmd_rejected, 1 );
676 commands["xboard"] = Cmd( &Engine::cmd_xboard );
677 commands["winboard"] = Cmd( &Engine::cmd_xboard );
678 commands["analyze"] = Cmd( &Engine::cmd_analyze );
679 commands["exit"] = Cmd( &Engine::cmd_exit );
680 commands["easy"] = Cmd( &Engine::cmd_easy );
681 commands["hard"] = Cmd( &Engine::cmd_hard );
682 commands["post"] = Cmd( &Engine::cmd_post,
683 "Enables printing the thinking\n" );
684 commands["nopost"] = Cmd( &Engine::cmd_nopost,
685 "Disables printing the thinking\n");
686 commands["name"] = Cmd( &Engine::cmd_name, 1 );
687 commands["rating"] = Cmd( &Engine::cmd_rating, 2 );
688 commands["result"] = Cmd( &Engine::cmd_result, 1, 999 );
689 commands["var"] = Cmd( &Engine::cmd_var,
690 "Prints variable values\n" );
691 commands["varhelp"] = Cmd( &Engine::cmd_varhelp,
692 "Prints variable values and with help information\n" );
693 commands["."] = Cmd( &Engine::cmd_DOT,
694 "Print statistics (during analysis)\n" );
695 commands["?"] = Cmd( &Engine::cmd_QUESTION,
696 "Move immediatly\n" );
699 void Engine::register_variables()
701 variables["book_creation_max_depth"] = Variable( &Engine::v_book_creation_max_depth, 28, 1, 50,
702 "Maximum depth (in ply) for selecting positions to include in the book\n");
703 variables["book_creation_max_alternatives"] = Variable( &Engine::v_book_creation_max_alternatives, 7, 1, INT_MAX,
704 "Maximum number of possible moves to store in the book for each position\n");
705 variables["book_creation_min_games"] = Variable( &Engine::v_book_creation_min_games, 6, 1, INT_MAX,
706 "Minimum number of games in which a position must appear to be included\n" );
707 variables["book_creation_min_probability"] = Variable( &Engine::v_book_creation_min_probability, 10, 0, 1000,
708 "Minimum probability that an possible move must have to be put in the book\n");
709 variables["book_creation_weigh_win"] = Variable( &Engine::v_book_creation_weigh_win, 3, 0, INT_MAX,
710 "Weight for a move played in a won game (to make more likely winning moves)\n");
711 variables["book_creation_weigh_draw"] = Variable( &Engine::v_book_creation_weigh_draw, 2, 0, INT_MAX,
712 "Weight for a move played in a drawn game (to make more likely winning moves)\n");
713 variables["book_creation_weigh_lose"] = Variable( &Engine::v_book_creation_weigh_lose, 1, 0, INT_MAX,
714 "Weight for a move played in a lost game (to make more likely winning moves)\n");
716 variables["search_null_reduction"] = Variable( &Engine::v_search_null_reduction, 300, 200, 400,
717 "Reduction for null move (in ply*100)\n");
718 variables["search_threat_extension"] = Variable( &Engine::v_search_threat_extension, 100, 40, 120,
719 "Reduction for null move (in ply*100)\n");
720 variables["search_threat_threshold"] = Variable( &Engine::v_search_threat_threshold, 340, 150, 720,
721 "Reduction for null move (in ply*100)\n");
723 variables["eval_draw"] = Variable( &Engine::v_eval_draw, -20, 0, -100,
724 "Value of a position drawn by repetition, 50 moves rule or insufficient material\n");