Fixed sideeffects of enabling the gui to visualize the search tree.
[rattatechess.git] / commands.cpp
blob2b778a8e8d1a8e284f63660a638dcc867c58698b
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 "search_gui.h"
22 #include <stdarg.h>
23 #include <signal.h>
24 #include <string.h>
26 void Engine::Cmd::run(int argc, char *argv[])
28 (Engine::eng()->*m_func)(argc, argv);
31 Engine::Variable::Variable(int (Engine::*ivar), int def_val, const char *d)
32 : m_type(Integer)
33 , m_desc(d)
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_int_var(ivar)
45 , m_range_min(min)
46 , m_range_max(max)
48 Engine::eng()->*m_int_var = def_val;
51 Engine::Variable::Variable(char* (Engine::*svar), const char* def_val, const char *d)
52 : m_type(String)
53 , m_desc(d)
54 , m_string_var(svar)
56 Engine::eng()->*m_string_var = strdup(def_val);
59 Engine::Variable::Variable(VarSetFunc set, VarGetFunc get, const char *d)
60 : m_type(String)
61 , m_desc(d)
62 , m_custom_data(NULL)
63 , m_custom_set(set)
64 , m_custom_get(get)
68 Engine::Variable::Variable(VarSetFunc set, VarGetFunc get, void* data, const char *d)
69 : m_type(String)
70 , m_desc(d)
71 , m_custom_data(data)
72 , m_custom_set(set)
73 , m_custom_get(get)
77 void Engine::Variable::from_string(const char* s)
79 switch(m_type)
81 case Integer:
83 int v = atoi(s);
84 if(v < m_range_min || v > m_range_max)
85 printf("Error! value %d out of range (%d-%d)\n", v, m_range_min, m_range_max);
86 else
87 Engine::eng()->*m_int_var = v;
88 break;
91 case String:
92 if(Engine::eng()->*m_string_var)
93 free(Engine::eng()->*m_string_var);
94 Engine::eng()->*m_string_var = strdup(s);
95 break;
97 case Custom:
98 (Engine::eng()->*m_custom_set)(m_custom_data, s);
99 break;
101 default:
102 break;
106 const char* Engine::Variable::to_string(char* buf64)
108 switch(m_type)
110 case Integer:
111 snprintf(buf64, 64, "%d", Engine::eng()->*m_int_var);
112 break;
114 case String:
115 strncpy(buf64, Engine::eng()->*m_string_var, 64);
116 break;
118 case Custom:
119 (Engine::eng()->*m_custom_get)(m_custom_data, buf64);
120 break;
122 default:
123 buf64[0] = '\0';
124 break;
127 return buf64;
130 static void print_description(int indent, const char* desc)
132 int num;
133 char** tokenized = tokenize(desc ? desc : "<No description>", "\n", &num, false);
135 for(int i=0;i<num;i++)
137 for(int q=0;q<indent;q++)
138 putchar(' ');
139 puts(tokenized[i]);
141 putchar('\n');
142 free(tokenized);
145 void Engine::cmd_quit(int argc, char *argv[])
147 exit(0);
150 void Engine::cmd_ping(int argc, char *argv[])
152 printf("pong %s\n",argv[0]);
155 void Engine::cmd_bench(int argc, char *argv[])
159 void Engine::cmd_perft(int argc, char *argv[])
161 int t = current_time();
162 uint64_t p = perft( atoi(argv[0]) );
163 printf("%lld (time %.02f)\n", (long long)p, (current_time()-t)*0.01 );
166 void Engine::cmd_perftall(int argc, char *argv[])
168 int lev = atoi(argv[0]);
169 Move mv_stack[200];
170 int num;
171 num = board.find_moves(mv_stack);
173 printf("---------\n");
174 for(int i=0;i<num;i++)
176 int p;
177 board.do_move(mv_stack[i], save_buf[save_buf_num++]);
178 p = perft(lev);
179 board.undo_move(mv_stack[i], save_buf[--save_buf_num]);
180 printf("%s: %d\n", board.move_to_alg(MoveStr().data(), mv_stack[i]), p);
182 printf("---------\n");
185 void Engine::cmd_sd(int argc, char *argv[])
187 set_depth( atoi(argv[0]) );
190 void Engine::cmd_st(int argc, char *argv[])
192 set_time_fixed( atoi(argv[0]) );
195 void Engine::cmd_sn(int argc, char *argv[])
197 set_max_nodes( atoi(argv[0]) );
200 void Engine::cmd_otim(int argc, char *argv[])
202 set_other_clock( atoi(argv[0]) );
205 void Engine::cmd_time(int argc, char *argv[])
207 set_my_clock( atoi(argv[0]) );
210 void Engine::cmd_level(int argc, char *argv[])
212 int basem,bases=0;
213 sscanf(argv[1],"%d:%d",&basem,&bases);
215 set_time_control( atoi(argv[0]) ,basem*60+bases, atoi(argv[2]) );
218 void Engine::cmd_help(int argc, char *argv[])
220 for(CmdSet::iterator it = commands.begin(); it != commands.end(); ++it)
222 if(!it->second.max())
223 printf(" %s\n", it->first.c_str() );
224 else if(it->second.min() == it->second.max())
225 printf(" %s (%d %s)\n", it->first.c_str(), it->second.min(), it->second.min()==1?"arg":"args" );
226 else
227 printf(" %s (%d-%d args)\n", it->first.c_str(), it->second.min(), it->second.max() );
229 print_description(4, it->second.desc());
233 void Engine::cmd_force(int argc, char *argv[])
235 force();
238 void Engine::cmd_undo(int argc, char *argv[])
240 undo();
241 if(!io_xboard)
242 print_board();
245 void Engine::cmd_remove(int argc, char *argv[])
247 retract_move();
248 if(!io_xboard)
249 print_board();
252 void Engine::cmd_new(int argc, char *argv[])
254 new_game();
255 if(!io_xboard)
256 print_board();
259 void Engine::cmd_white(int argc, char *argv[])
261 board.color_to_move = WHITE;
262 board.other_color = BLACK;
263 start(BLACK);
266 void Engine::cmd_black(int argc, char *argv[])
268 board.color_to_move = BLACK;
269 board.other_color = WHITE;
270 start(WHITE);
273 void Engine::cmd_go(int argc, char *argv[])
275 start();
278 void Engine::cmd_setboard(int argc, char *argv[])
280 read_board(argv[0], argv[1], argv[2], argv[3], atoi(argv[4]), atoi(argv[5]) );
281 if(!io_xboard)
282 print_board();
285 void Engine::cmd_edit(int argc, char *argv[])
287 //output("Unimplemented!\n");
288 char str[256];
289 while(1)
291 if(!fgets(str, 256, stdin))
292 exit(0);
294 if(str[0]=='.')
295 break;
299 void Engine::cmd_load(int argc, char *argv[])
301 FILE* f = fopen(argv[0],"r");
302 if(f)
304 read_board(f);
305 fclose(f);
306 if(!io_xboard)
307 print_board();
309 else
310 output("Error, could not open \"%s\" for reading.\n", argv[0]);
313 void Engine::cmd_load_pgn(int argc, char *argv[])
315 FILE* f = fopen(argv[0],"r");
316 if(!f)
317 output("Error, could not open \"%s\" for reading.\n", argv[0]);
319 st_computer_color = 0;
320 load_pgn(f);
321 fclose(f);
322 if(!io_xboard)
323 print_board();
326 void Engine::cmd_epdtest(int argc, char *argv[])
328 run_epd_prog(argv[0], atoi(argv[1]), argv[2], argc==4 && !strncmp(argv[3], "quiet", strlen(argv[3])));
331 void Engine::cmd_challenge(int argc, char *argv[])
333 challenge(argv[0], atoi(argv[1]), argv[2]);
336 void Engine::cmd_create_book(int argc, char *argv[])
338 create_book(argc, argv);
341 void Engine::cmd_open_book(int argc, char *argv[])
343 open_book(argv[0]);
346 void Engine::cmd_close_book(int argc, char *argv[])
348 close_book();
351 void Engine::cmd_open_lines(int argc, char *argv[])
353 open_lines(argv[0]);
356 void Engine::cmd_close_lines(int argc, char *argv[])
358 close_lines();
361 void Engine::cmd_open_eco(int argc, char *argv[])
363 open_openings(argv[0]);
366 void Engine::cmd_close_eco(int argc, char *argv[])
368 close_openings();
371 void Engine::cmd_save(int argc, char *argv[])
373 FILE* f = fopen(argv[0],"w");
374 if(f)
376 write_board(f);
377 fclose(f);
379 else
380 output("Error, could not open \"%s\" for writing.\n", argv[0]);
384 void Engine::cmd_test(int argc, char *argv[])
386 printf("test");
387 for(int i=0;i< argc;i++)
388 printf(" \"%s\"", argv[i]);
389 printf("\n");
392 void Engine::cmd_protover(int argc, char *argv[])
394 static const char* features[] = {
395 "san=1",
396 "ping=1",
397 "setboard=1",
398 "sigint=0",
399 "sigterm=0",
400 "analyze=1",
401 "draw=0",
402 "colors=0",
403 "variants=\"normal\"",
404 "myname=\"RattateChess 1.1 Artin\"",
405 "done=1"
407 for(unsigned int i=0; i<sizeof(features)/sizeof(const char*); i++)
408 output("feature %s\n", features[i]);
411 void Engine::cmd_accepted(int argc, char *argv[])
413 if(0 == strcmp("san",argv[0]))
414 io_san = true;
417 void Engine::cmd_rejected(int argc, char *argv[])
422 void Engine::cmd_xboard(int argc, char *argv[])
424 io_xboard = true;
425 signal(SIGINT, SIG_IGN);
428 void Engine::cmd_analyze(int argc, char *argv[])
430 eng_status = ANALYZING;
431 if(thinking)
432 longjmp(back, 1);
435 void Engine::cmd_exit(int argc, char *argv[])
437 eng_status = FORCING;
438 if(thinking)
439 longjmp(back, 1);
442 void Engine::cmd_easy(int argc, char *argv[])
444 ponder = false;
447 void Engine::cmd_hard(int argc, char *argv[])
449 ponder = true;
452 void Engine::cmd_post(int argc, char *argv[])
454 post = true;
457 void Engine::cmd_nopost(int argc, char *argv[])
459 post = false;
462 void Engine::cmd_result(int argc, char *argv[])
464 if(!strcmp(argv[0], "1-0"))
465 status = _10;
466 else if(!strcmp(argv[0], "0-1"))
467 status = _01;
468 else if(!strcmp(argv[0], "1/2-1/2"))
469 status = _12;
470 else
471 output("Unknown result command!\n");
473 if(st_computer_color)
475 FILE *f = fopen("ratta.games", "a");
476 if(f)
478 char all_res[2048];
479 all_res[0] = '\0';
480 for(int i=0;i<argc;i++)
482 strcat(all_res, argv[i]);
483 if(i!=argc-1)
484 strcat(all_res, " " );
486 save_pgn(f, argv[0], all_res);
487 fclose(f);
492 void Engine::cmd_DOT(int argc, char *argv[])
494 print_stat();
497 void Engine::cmd_QUESTION(int argc, char *argv[])
499 move_now();
502 void Engine::cmd_name(int argc, char *argv[])
504 strncpy(opponent, argv[0], 256);
505 opponent[255] = '\0';
508 void Engine::cmd_rating(int argc, char *argv[])
510 w_rating = atoi(argv[0]);
511 b_rating = atoi(argv[1]);
514 void Engine::cmd__gon(int argc, char *argv[])
516 if(search_gui)
517 output("Gui already on!\n");
518 else
519 search_gui = new SearchGui(argc, argv);
522 void Engine::cmd__goff(int argc, char *argv[])
524 if(!search_gui)
525 output("Gui already off!\n");
526 else
528 delete search_gui;
529 search_gui = NULL;
533 void Engine::cmd__check(int argc, char *argv[])
535 Move m = board.move_from_string(argv[0]);
536 if(!m.valid())
538 output("Not a legal move\n");
539 return;
542 board.find_other_pins();
543 if(board.move_is_check(m))
544 output("Yes it is a check\n");
545 else
546 output("Not a check\n");
549 void Engine::cmd__attacks(int argc, char *argv[])
551 uint8_t col = argv[1][0] == 'w' ? WHITE : BLACK;
552 uint8_t pos = POS_XY(argv[0][0]-'a', argv[0][1]-'1' );
553 Board::AttackList al[12];
554 int alnum = board.list_attackers(pos, col, col == board.color_to_move ?
555 board.pins : board.oth_pins, al);
556 for(int i=0;i<alnum;i++)
558 static char nam[] = { 0, 'r', 'b', 'q', 'n', 'p', 'k' };
559 for(int j=0;j<al[i].count;j++)
560 printf("%c ", nam[al[i].piece[j]]);
561 printf("\n");
565 void Engine::cmd__shat(int argc, char *argv[])
567 #if TRACK_ATTACKS
568 board.print_attacks();
569 #else
570 output("Unsupported.\n");
571 #endif
574 void Engine::cmd__see(int argc, char *argv[])
576 Move m = board.move_from_string(argv[0]);
577 if(!m.valid())
579 output("Not a legal move\n");
580 return;
583 output("SEE val: %d\n", board.move_see_val(m));
586 void Engine::cmd__find_moves(int argc, char *argv[])
588 Move mv[200];
589 int n = board.find_moves(mv);
591 for(int i=0;i<n;i++)
592 output(" - %s\n", board.move_to_alg(MoveStr().data(), mv[i]) );
595 void Engine::cmd__gen_hash(int argc, char *argv[])
597 Board::init_hash_keys( argv[0] );
600 void Engine::cmd_set(int argc, char *argv[])
602 std::map<std::string, Variable>::iterator it = variables.find(argv[0]);
603 if(it == variables.end())
604 printf(" -> unknown variable '%s'!\n", argv[0]);
605 else
607 it->second.from_string(argv[1]);
608 printf(" %s -> %s\n", it->second.to_string(TmpStr().data()), it->first.c_str() );
612 void Engine::cmd_var(int argc, char *argv[])
614 if(argc == 0)
615 for(VariableSet::iterator it = variables.begin(); it != variables.end(); ++it)
616 printf(" %s = %s\n", it->first.c_str(), it->second.to_string(TmpStr().data()) );
617 else
618 for(int i=0;i<argc;i++)
620 std::map<std::string, Variable>::iterator it = variables.find(argv[i]);
621 if(it == variables.end())
622 printf(" -> unknown variable '%s'!\n", argv[i]);
623 else
624 printf(" %s = %s\n", it->first.c_str(), it->second.to_string(TmpStr().data()) );
628 void Engine::cmd_varhelp(int argc, char *argv[])
630 for(VariableSet::iterator it = variables.begin(); it != variables.end(); ++it)
632 printf(" %s = %s\n", it->first.c_str(), it->second.to_string(TmpStr().data()) );
633 print_description(4, it->second.desc());
637 void Engine::register_commands()
639 commands["_see"] = Cmd( &Engine::cmd__see, 1,
640 "_see [move]\n"
641 "Calculates the SEE value of a move\n");
642 commands["_shat"] = Cmd( &Engine::cmd__shat,
643 "Shows all attacks\n" );
644 commands["_attacks"] = Cmd( &Engine::cmd__attacks, 2,
645 "_attacks [w|b] [square|a1|a2|...]\n"
646 "Shows all attackers of a square from a color\n" );
647 commands["_check"] = Cmd( &Engine::cmd__check, 1 );
648 commands["_find_moves"] = Cmd( &Engine::cmd__find_moves );
649 commands["_gen_hash"] = Cmd( &Engine::cmd__gen_hash );
650 commands["_gon"] = Cmd( &Engine::cmd__gon );
651 commands["_goff"] = Cmd( &Engine::cmd__goff );
652 //commands["exit"] = Cmd( &Engine::cmd_quit );
653 commands["quit"] = Cmd( &Engine::cmd_quit );
654 commands["ping"] = Cmd( &Engine::cmd_ping, 1 );
655 commands["bench"] = Cmd( &Engine::cmd_bench );
656 commands["perft"] = Cmd( &Engine::cmd_perft, 1 );
657 commands["perftall"] = Cmd( &Engine::cmd_perftall, 1 );
658 commands["sd"] = Cmd( &Engine::cmd_sd, 1 );
659 commands["st"] = Cmd( &Engine::cmd_st, 1 );
660 commands["sn"] = Cmd( &Engine::cmd_sn, 1 );
661 commands["otim"] = Cmd( &Engine::cmd_otim, 1 );
662 commands["time"] = Cmd( &Engine::cmd_time, 1 );
663 commands["level"] = Cmd( &Engine::cmd_level, 3 );
664 commands["help"] = Cmd( &Engine::cmd_help,
665 "Printf this help\n" );
666 commands["force"] = Cmd( &Engine::cmd_force,
667 "Puts the engine in 'force' mode (ie edit game)\n" );
668 commands["undo"] = Cmd( &Engine::cmd_undo );
669 commands["remove"] = Cmd( &Engine::cmd_remove );
670 commands["new"] = Cmd( &Engine::cmd_new );
671 commands["white"] = Cmd( &Engine::cmd_white );
672 commands["black"] = Cmd( &Engine::cmd_black );
673 commands["go"] = Cmd( &Engine::cmd_go );
674 commands["setboard"] = Cmd( &Engine::cmd_setboard, 6,
675 "Sets a FEN string as the current position\n" );
676 commands["edit"] = Cmd( &Engine::cmd_edit,
677 "Puts the engine in (old style) position editing mode\n" );
678 commands["load"] = Cmd( &Engine::cmd_load, 1 );
679 commands["load_pgn"] = Cmd( &Engine::cmd_load_pgn, 1 );
680 commands["epdtest"] = Cmd( &Engine::cmd_epdtest, 3, 4,
681 "Runs an epd test with a chess program and a given time out for each\n"
682 "problem. It requires 3 arguments: the first must be an xboard program\n"
683 "path or 'self', the second the time to think in millseconds, and the\n"
684 "third is the file containing the test positions\n");
685 commands["challenge"] = Cmd( &Engine::cmd_challenge, 3 );
686 commands["create_book"] = Cmd( &Engine::cmd_create_book, 1, 2,
687 "Creates a book file using as argument the path of a PGN file with\n"
688 "a database of games, and possibly the path of a file with ECO codes.\n"
689 "See also the 'vars' command and the variables named book_creation_*,\n"
690 "that you can use to change many options\n" );
691 commands["open_book"] = Cmd( &Engine::cmd_open_book, 1,
692 "Loads a book file\n" );
693 commands["close_book"] = Cmd( &Engine::cmd_close_book,
694 "Closes the book (and make the engine use no book)\n" );
695 commands["open_lines"] = Cmd( &Engine::cmd_open_lines, 1,
696 "Loads a lines file (where you can select the openings to play)\n" );
697 commands["close_lines"] = Cmd( &Engine::cmd_close_lines,
698 "Closes the lines file (and make the engine use no lines)\n" );
699 commands["open_eco"] = Cmd( &Engine::cmd_open_eco, 1,
700 "Loads a eco file\n" );
701 commands["close_eco"] = Cmd( &Engine::cmd_close_eco,
702 "Closes the eco (and make the engine use no eco)\n" );
703 commands["save"] = Cmd( &Engine::cmd_save, 1 );
704 commands["test"] = Cmd( &Engine::cmd_test );
705 commands["protover"] = Cmd( &Engine::cmd_protover, 1 );
706 commands["accepted"] = Cmd( &Engine::cmd_accepted, 1 );
707 commands["rejected"] = Cmd( &Engine::cmd_rejected, 1 );
708 commands["xboard"] = Cmd( &Engine::cmd_xboard );
709 commands["winboard"] = Cmd( &Engine::cmd_xboard );
710 commands["analyze"] = Cmd( &Engine::cmd_analyze );
711 commands["exit"] = Cmd( &Engine::cmd_exit );
712 commands["easy"] = Cmd( &Engine::cmd_easy );
713 commands["hard"] = Cmd( &Engine::cmd_hard );
714 commands["post"] = Cmd( &Engine::cmd_post,
715 "Enables printing the thinking\n" );
716 commands["nopost"] = Cmd( &Engine::cmd_nopost,
717 "Disables printing the thinking\n");
718 commands["name"] = Cmd( &Engine::cmd_name, 1 );
719 commands["rating"] = Cmd( &Engine::cmd_rating, 2 );
720 commands["result"] = Cmd( &Engine::cmd_result, 1, 999 );
721 commands["var"] = Cmd( &Engine::cmd_var, 0, 999,
722 "Prints variable[s] values\n" );
723 commands["set"] = Cmd( &Engine::cmd_set, 2,
724 "Set variable value\n" );
725 commands["varhelp"] = Cmd( &Engine::cmd_varhelp,
726 "Prints variable values and with help information\n" );
727 commands["."] = Cmd( &Engine::cmd_DOT,
728 "Print statistics (during analysis)\n" );
729 commands["?"] = Cmd( &Engine::cmd_QUESTION,
730 "Move immediatly\n" );
733 void Engine::register_variables()
735 variables["book_creation_max_depth"] = Variable( &Engine::v_book_creation_max_depth, 28, 1, 50,
736 "Maximum depth (in ply) for selecting positions to include in the book\n");
737 variables["book_creation_max_alternatives"] = Variable( &Engine::v_book_creation_max_alternatives, 7, 1, INT_MAX,
738 "Maximum number of possible moves to store in the book for each position\n");
739 variables["book_creation_min_games"] = Variable( &Engine::v_book_creation_min_games, 6, 1, INT_MAX,
740 "Minimum number of games in which a position must appear to be included\n" );
741 variables["book_creation_min_probability"] = Variable( &Engine::v_book_creation_min_probability, 10, 0, 1000,
742 "Minimum probability that an possible move must have to be put in the book\n");
743 variables["book_creation_weigh_win"] = Variable( &Engine::v_book_creation_weigh_win, 3, 0, INT_MAX,
744 "Weight for a move played in a won game (to make more likely winning moves)\n");
745 variables["book_creation_weigh_draw"] = Variable( &Engine::v_book_creation_weigh_draw, 2, 0, INT_MAX,
746 "Weight for a move played in a drawn game (to make more likely winning moves)\n");
747 variables["book_creation_weigh_lose"] = Variable( &Engine::v_book_creation_weigh_lose, 1, 0, INT_MAX,
748 "Weight for a move played in a lost game (to make more likely winning moves)\n");
750 variables["search_null_reduction"] = Variable( &Engine::v_search_null_reduction, 300, 200, 400,
751 "Reduction for null move (in ply*100)\n");
752 variables["search_threat_extension"] = Variable( &Engine::v_search_threat_extension, 100, 40, 120,
753 "Reduction for null move (in ply*100)\n");
754 variables["search_threat_threshold"] = Variable( &Engine::v_search_threat_threshold, 340, 150, 720,
755 "Reduction for null move (in ply*100)\n");
757 variables["eval_draw"] = Variable( &Engine::v_eval_draw, -20, 0, -100,
758 "Value of a position drawn by repetition, 50 moves rule or insufficient material\n");