1 #include <ctype.h>
2 #include <signal.h>
3 #include "chess.h"
4 #include "data.h"
5 #if defined(UNIX)
6 #  include <unistd.h>
7 #  include <signal.h>
8 #endif
9 #include "epdglue.h"
10 #include "tbprobe.h"
11 /* last modified 08/03/16 */
12 /*
13  *******************************************************************************
14  *                                                                             *
15  *   Option() is used to handle user input necessary to control/customize the  *
16  *   program.  It performs all functions excepting chess move input which is   *
17  *   handled by main().                                                        *
18  *                                                                             *
19  *******************************************************************************
20  */
Option(TREE * RESTRICT tree)21 int Option(TREE * RESTRICT tree) {
22   int v;
23 
24 /*
25  ************************************************************
26  *                                                          *
27  *  parse the input.  If it looks like a FEN string, don't  *
28  *  parse using "/" as a separator, otherwise do.           *
29  *                                                          *
30  ************************************************************
31  */
32   if (StrCnt(buffer, '/') >= 7)
33     nargs = ReadParse(buffer, args, " \t;=");
34   else
35     nargs = ReadParse(buffer, args, " \t;=/");
36   if (!nargs)
37     return 1;
38   if (args[0][0] == '#')
39     return 1;
40 /*
41  ************************************************************
42  *                                                          *
43  *  EPD implementation interface code.  EPD commands can    *
44  *  not be handled if the program is actually searching in  *
45  *  a real game, and if Crafty is "pondering" this has to   *
46  *  be stopped.                                             *
47  *                                                          *
48  ************************************************************
49  */
50 #if defined(EPD)
51   if (initialized) {
52     if (EGCommandCheck(buffer)) {
53       if (thinking || pondering)
54         return 2;
55       else {
56         EGCommand(buffer);
57         return 1;
58       }
59     }
60   }
61 #endif
62 /*
63  ************************************************************
64  *                                                          *
65  *  "!" character is a 'shell escape' that passes the rest  *
66  *  of the command to a shell for execution.  Note that it  *
67  *  is ignored if in xboard mode because one could use your *
68  *  zippy2password to execute commands on your local        *
69  *  machine, probably something that is not wanted.         *
70  *                                                          *
71  ************************************************************
72  */
73   if (buffer[0] == '!') {
74     if (!xboard) {
75       v = system(strchr(buffer, '!') + 1);
76       if (v != 0)
77         perror("Option() system() error: ");
78     }
79   }
80 /*
81  ************************************************************
82  *                                                          *
83  *  "." ignores "." if it happens to get to this point, if  *
84  *  xboard is running.                                      *
85  *                                                          *
86  ************************************************************
87  */
88   else if (OptionMatch(".", *args)) {
89     if (xboard) {
90       printf("stat01: 0 0 0 0 0\n");
91       fflush(stdout);
92       return 1;
93     } else
94       return 0;
95   }
96 /*
97  ************************************************************
98  *                                                          *
99  *  "accepted" handles the new xboard protocol version 2    *
100  *  accepted command.                                       *
101  *                                                          *
102  ************************************************************
103  */
104   else if (OptionMatch("accepted", *args)) {
105   }
106 /*
107  ************************************************************
108  *                                                          *
109  *  "adaptive" sets the new adaptive hash algorithm         *
110  *  parameters.  It requires five parameters.  The first is *
111  *  an estimated NPS, the second is the minimum hash size,  *
112  *  and the third is the maximum hash size.  The adaptive   *
113  *  algorithm will look at the time control, and try to     *
114  *  adjust the hash sizes to an optimal value without       *
115  *  dropping below the minimum or exceeding the maximum     *
116  *  memory size given.  The min/max sizes can be given      *
117  *  using the same syntax as the hash= command, ie xxx,     *
118  *  xxxK or xxxM will all work. The fourth and fifth        *
119  *  parameters are used to limit hashp in the same way.     *
120  *                                                          *
121  ************************************************************
122  */
123   else if (OptionMatch("adaptive", *args)) {
124     if (nargs != 6) {
125       printf("usage:  adaptive NPS hmin hmax pmin pmax\n");
126       return 1;
127     }
128     if (nargs > 1) {
129       adaptive_hash = atoiKMB(args[1]);
130       adaptive_hash_min = atoiKMB(args[2]);
131       adaptive_hash_max = atoiKMB(args[3]);
132       adaptive_hashp_min = atoiKMB(args[4]);
133       adaptive_hashp_max = atoiKMB(args[5]);
134     }
135     Print(32, "adaptive estimated NPS =  %s\n", DisplayKMB(adaptive_hash, 1));
136     Print(32, "adaptive minimum hsize =  %s\n", DisplayKMB(adaptive_hash_min,
137             1));
138     Print(32, "adaptive maximum hsize =  %s\n", DisplayKMB(adaptive_hash_max,
139             1));
140     Print(32, "adaptive minimum psize =  %s\n", DisplayKMB(adaptive_hashp_min,
141             1));
142     Print(32, "adaptive maximum psize =  %s\n", DisplayKMB(adaptive_hashp_max,
143             1));
144   }
145 /*
146  ************************************************************
147  *                                                          *
148  *  "alarm" command turns audible move warning on/off.      *
149  *                                                          *
150  ************************************************************
151  */
152   else if (OptionMatch("alarm", *args)) {
153     if (!strcmp(args[1], "on"))
154       audible_alarm = 0x07;
155     else if (!strcmp(args[1], "off"))
156       audible_alarm = 0x00;
157     else
158       printf("usage:  alarm on|off\n");
159   }
160 /*
161  ************************************************************
162  *                                                          *
163  *  "analyze" puts Crafty in analyze mode, where it reads   *
164  *  moves in and between moves, computes as though it is    *
165  *  trying to find the best move to make.  When another     *
166  *  move is entered, it switches sides and continues.  It   *
167  *  will never make a move on its own, rather, it will      *
168  *  continue to analyze until an "exit" command is given.   *
169  *                                                          *
170  ************************************************************
171  */
172   else if (OptionMatch("analyze", *args)) {
173     if (thinking || pondering)
174       return 2;
175     Analyze();
176   }
177 /*
178  ************************************************************
179  *                                                          *
180  *  "annotate" command is used to read a series of moves    *
181  *  and analyze the resulting game, producing comments as   *
182  *  requested by the user.  This also handles the annotateh *
183  *  (html) and annotatet (LaTex) output forms of the        *
184  *  command.                                                *
185  *                                                          *
186  ************************************************************
187  */
188   else if (OptionMatch("annotate", *args) || OptionMatch("annotateh", *args)
189       || OptionMatch("annotatet", *args)) {
190     if (thinking || pondering)
191       return 2;
192     Annotate();
193   }
194 /*
195  ************************************************************
196  *                                                          *
197  *  "autotune" command is used to automatically tune the    *
198  *  SMP search parameters that affect search efficiency.    *
199  *                                                          *
200  ************************************************************
201  */
202   else if (OptionMatch("autotune", *args)) {
203     if (thinking || pondering)
204       return 2;
205     AutoTune(nargs, args);
206   }
207 /*
208  ************************************************************
209  *                                                          *
210  *  "batch" command disables asynchronous I/O so that a     *
211  *  stream of commands can be put into a file and they are  *
212  *  not executed instantly.                                 *
213  *                                                          *
214  ************************************************************
215  */
216   else if (OptionMatch("batch", *args)) {
217     if (!strcmp(args[1], "on"))
218       batch_mode = 1;
219     else if (!strcmp(args[1], "off"))
220       batch_mode = 0;
221     else
222       printf("usage:  batch on|off\n");
223   }
224 /*
225  ************************************************************
226  *                                                          *
227  *  "beep" command is ignored. [xboard compatibility]       *
228  *                                                          *
229  ************************************************************
230  */
231   else if (OptionMatch("beep", *args)) {
232     return xboard;
233   }
234 /*
235  ************************************************************
236  *                                                          *
237  *  "bench" runs internal performance benchmark.  An        *
238  *  optional second argument can increase or decrease the   *
239  *  time it takes.  "bench 1" increases the default depth   *
240  *  by one ply, and "bench -1" reduces the depth to speed   *
241  *  it up.                                                  *
242  *                                                          *
243  ************************************************************
244  */
245   else if (OptionMatch("bench", *args)) {
246     int mod = 0;
247 
248     if (nargs > 1)
249       mod = atoi(args[1]);
250     (void) Bench(mod, 0);
251   }
252 /*
253  ************************************************************
254  *                                                          *
255  *  "bk"  book command from xboard sends the suggested book *
256  *  moves.                                                  *
257  *                                                          *
258  ************************************************************
259  */
260   else if (OptionMatch("bk", *args)) {
261     printf("\t%s\n\n", book_hint);
262     fflush(stdout);
263     return xboard;
264   }
265 /*
266  ************************************************************
267  *                                                          *
268  *  "black" command sets black to move (Flip(wtm)).         *
269  *                                                          *
270  ************************************************************
271  */
272   else if (OptionMatch("white", *args)) {
273     if (thinking || pondering)
274       return 2;
275     game_wtm = 1;
276     ponder_move = 0;
277     last_pv.pathd = 0;
278     last_pv.pathl = 0;
279     if (!game_wtm)
280       Pass();
281     force = 0;
282   } else if (OptionMatch("black", *args)) {
283     if (thinking || pondering)
284       return 2;
285     game_wtm = 0;
286     ponder_move = 0;
287     last_pv.pathd = 0;
288     last_pv.pathl = 0;
289     if (game_wtm)
290       Pass();
291     force = 0;
292   }
293 /*
294  ************************************************************
295  *                                                          *
296  *  "bogus" command is ignored. [xboard compatibility]      *
297  *                                                          *
298  ************************************************************
299  */
300   else if (OptionMatch("bogus", *args)) {
301     return xboard;
302   }
303 /*
304  ************************************************************
305  *                                                          *
306  *  "book" command updates/creates the opening book file.   *
307  *                                                          *
308  ************************************************************
309  */
310   else if (OptionMatch("book", *args)) {
311     nargs = ReadParse(buffer, args, " \t;");
312     Bookup(tree, nargs, args);
313   } else if (!strcmp("create", *(args + 1))) {
314     nargs = ReadParse(buffer, args, " \t;");
315     Bookup(tree, nargs, args);
316   }
317 /*
318  ************************************************************
319  *                                                          *
320  *  "bookw" command updates the book selection weights.     *
321  *                                                          *
322  ************************************************************
323  */
324   else if (OptionMatch("bookw", *args)) {
325     if (nargs > 1) {
326       if (OptionMatch("frequency", args[1]))
327         book_weight_freq = atof(args[2]);
328       else if (OptionMatch("evaluation", args[1]))
329         book_weight_eval = atof(args[2]);
330       else if (OptionMatch("learning", args[1]))
331         book_weight_learn = atof(args[2]);
332     } else {
333       Print(32, "frequency (freq)..............%4.2f\n", book_weight_freq);
334       Print(32, "static evaluation (eval)......%4.2f\n", book_weight_eval);
335       Print(32, "learning (learn)..............%4.2f\n", book_weight_learn);
336     }
337   }
338 /*
339  ************************************************************
340  *                                                          *
341  *  "clock" command displays chess clock.                   *
342  *                                                          *
343  ************************************************************
344  */
345   else if (OptionMatch("clock", *args)) {
346     int side;
347 
348     for (side = white; side >= black; side--) {
349       Print(32, "time remaining (%s): %s", (side) ? "white" : "black",
350           DisplayHHMMSS(tc_time_remaining[side]));
351       if (tc_sudden_death != 1)
352         Print(32, "  (%d more moves)", tc_moves_remaining[side]);
353       Print(32, "\n");
354     }
355     Print(32, "\n");
356     if (tc_sudden_death == 1)
357       Print(32, "Sudden-death time control in effect\n");
358   }
359 /*
360  ************************************************************
361  *                                                          *
362  *  "computer" lets Crafty know it is playing a computer.   *
363  *                                                          *
364  ************************************************************
365  */
366   else if (OptionMatch("computer", *args)) {
367     Print(32, "playing a computer!\n");
368     accept_draws = 1;
369     if (resign)
370       resign = 10;
371     resign_count = 4;
372     usage_level = 0;
373     books_file = (computer_bs_file) ? computer_bs_file : normal_bs_file;
374   }
375 /*
376  ************************************************************
377  *                                                          *
378  *  "display" command displays the chess board.             *
379  *                                                          *
380  *  "display" command sets specific display options which   *
381  *  control how "chatty" the program is.  In the variable   *
382  *  display_options, the following bits are set/cleared     *
383  *  based on the option chosen.                             *
384  *                                                          *
385  *    1 -> display move/time/results/etc.                   *
386  *    2 -> display PV.                                      *
387  *    4 -> display fail high / fail low moves               *
388  *    8 -> display search statistics.                       *
389  *   16 -> display root moves as they are searched.         *
390  *   32 -> display general informational messages.          *
391  *   64 -> display ply-1 move list / flags after each       *
392  *         iteration.                                       *
393  *  128 -> display root moves and scores before search      *
394  *         begins.                                          *
395  * 2048 -> error messages (can not be disabled).            *
396  *                                                          *
397  ************************************************************
398  */
399   else if (OptionMatch("display", *args)) {
400     int i, set, old_display_options = display_options;
401     char *doptions[8] = { "moveinfo", "pv", "fail", "stats", "moves", "info",
402       "ply1", "movelist"
403     };
404     char *descriptions[8] = { "display move time/results/etc",
405       "principal variation", "fail highs/lows", "search statistics",
406       "root moves as they are searched", "general information",
407       "ply1 move list after each iteration",
408       "root move list and scores prior to search"
409     };
410 
411     if (nargs > 1) {
412       if (!strcmp(args[1], "all"))
413         old_display_options = ~display_options;
414       for (i = 0; i < 8; i++) {
415         if (strstr(args[1], doptions[i])) {
416           if (strstr(args[1], "no"))
417             set = 0;
418           else
419             set = 1;
420           display_options &= ~(1 << i);
421           display_options |= set << i;
422           break;
423         }
424       }
425       for (i = 0; i < 8; i++) {
426         if ((old_display_options & (1 << i)) != (display_options & (1 << i))) {
427           Print(32, "display ");
428           if (!(display_options & (1 << i)))
429             Print(32, "no");
430           Print(32, "%s (%s)\n", doptions[i], descriptions[i]);
431         }
432       }
433     } else
434       DisplayChessBoard(stdout, display);
435   }
436 /*
437  ************************************************************
438  *                                                          *
439  *  "debug" handles the new debug command that is often     *
440  *  modified to test some modified code function.           *
441  *                                                          *
442  ************************************************************
443  */
444   else if (OptionMatch("debug", *args)) {
445     Print(32, "ERROR:  no debug code included\n");
446   }
447 /*
448  ************************************************************
449  *                                                          *
450  *  "depth" command sets a specific search depth to         *
451  *  control the tree search depth. [xboard compatibility].  *
452  *                                                          *
453  ************************************************************
454  */
455   else if (OptionMatch("depth", *args)) {
456     if (nargs < 2) {
457       printf("usage:  depth <n>\n");
458       return 1;
459     }
460     search_depth = atoi(args[1]);
461     Print(32, "search depth set to %d.\n", search_depth);
462   }
463 /*
464  ************************************************************
465  *                                                          *
466  *  "draw" is used to offer Crafty a draw, or to control    *
467  *  whether Crafty will offer and/or accept draw offers.    *
468  *                                                          *
469  ************************************************************
470  */
471   else if (OptionMatch("draw", *args)) {
472     if (nargs == 1) {
473       draw_offer_pending = 1;
474       if (draw_offered) {
475         Print(4095, "1/2-1/2 {Draw agreed}\n");
476         strcpy(pgn_result, "1/2-1/2");
477       }
478     } else {
479       if (!strcmp(args[1], "accept")) {
480         accept_draws = 1;
481         Print(32, "accept draw offers\n");
482       } else if (!strcmp(args[1], "decline")) {
483         accept_draws = 0;
484         Print(32, "decline draw offers\n");
485       } else if (!strcmp(args[1], "dynamic")) {
486         if (nargs > 2)
487           dynamic_draw_score = atoi(args[2]);
488         Print(32, "dynamic draw scores %s\n",
489             (dynamic_draw_score) ? "enabled" : "disabled");
490       } else if (!strcmp(args[1], "offer")) {
491         offer_draws = 1;
492         Print(32, "offer draws\n");
493       } else if (!strcmp(args[1], "nooffer")) {
494         offer_draws = 0;
495         Print(32, "do not offer draws\n");
496       } else
497         Print(32, "usage: draw accept|decline|offer|nooffer\n");
498     }
499   }
500 /*
501  ************************************************************
502  *                                                          *
503  *  "easy" command disables thinking on opponent's time.    *
504  *                                                          *
505  ************************************************************
506  */
507   else if (OptionMatch("easy", *args)) {
508     if (thinking || pondering)
509       return 2;
510     ponder = 0;
511     Print(32, "pondering disabled.\n");
512   }
513 /*
514  ************************************************************
515  *                                                          *
516  *  "echo" command displays messages from command file.     *
517  *                                                          *
518  ************************************************************
519  */
520   else if (OptionMatch("echo", *args) || OptionMatch("title", *args)) {
521   }
522 /*
523  ************************************************************
524  *                                                          *
525  *  "edit" command modifies the board position.             *
526  *                                                          *
527  ************************************************************
528  */
529   else if (OptionMatch("edit", *args)) {
530     if (thinking || pondering)
531       return 2;
532     Edit();
533     move_number = 1; /* discard history */
534     if (!game_wtm) {
535       game_wtm = 1;
536       Pass();
537     }
538     ponder_move = 0;
539     last_pv.pathd = 0;
540     last_pv.pathl = 0;
541     strcpy(buffer, "savepos *");
542     Option(tree);
543   }
544 /*
545  ************************************************************
546  *                                                          *
547  *  "egtb" command enables syzygy endgame database tables.  *
548  *                                                          *
549  ************************************************************
550  */
551   else if (OptionMatch("egtb", *args)) {
552 #if defined(SYZYGY)
553     if (!strcmp(args[1], "off"))
554       EGTBlimit = 0;
555     else {
556       if (!EGTB_setup) {
557         tb_init(tb_path);
558         EGTB_setup = 1;
559       }
560       EGTBlimit = TB_LARGEST;
561     }
562     if (EGTBlimit)
563       Print(32, "SYZYGY EGTB access enabled, %d piece TBs found\n",
564           TB_LARGEST);
565     else
566       Print(32, "SYZYGY EGTB access disabled.\n");
567 #else
568     Print(32, "SYZYGY support not included (no -DSYZYGY)\n");
569 #endif
570   }
571 /*
572  ************************************************************
573  *                                                          *
574  *  "egtbd" command sets the probe depth limit.  If the     *
575  *  remaining depth is < this limit, probes are not done to *
576  *  avoid slowing the search unnecessarily.                 *
577  *                                                          *
578  ************************************************************
579  */
580 #if defined(SYZYGY)
581   else if (OptionMatch("egtbd", *args)) {
582     if (nargs > 1)
583       EGTB_depth = atoi(args[1]);
584     Print(32, "EGTB probe depth set to %d\n", EGTB_depth);
585   }
586 #endif
587 /*
588  ************************************************************
589  *                                                          *
590  *  "end" (or "quit") command terminates the program.       *
591  *                                                          *
592  ************************************************************
593  */
594   else if (OptionMatch("end", *args) || OptionMatch("quit", *args)) {
595     abort_search = 1;
596     quit = 1;
597     last_search_value =
598         (crafty_is_white) ? last_search_value : -last_search_value;
599     if (moves_out_of_book)
600       LearnBook();
601     if (thinking || pondering)
602       return 1;
603     CraftyExit(0);
604   }
605 /*
606  ************************************************************
607  *                                                          *
608  *  "evtest" command runs a test suite of problems and      *
609  *  prints evaluations only.                                *
610  *                                                          *
611  ************************************************************
612  */
613   else if (OptionMatch("evtest", *args)) {
614     if (thinking || pondering)
615       return 2;
616     if (nargs < 2) {
617       printf("usage:  evtest <filename>\n");
618       return 1;
619     }
620     EVTest(args[1]);
621     ponder_move = 0;
622     last_pv.pathd = 0;
623     last_pv.pathl = 0;
624   }
625 /*
626  ************************************************************
627  *                                                          *
628  *  "exit" command resets input device to STDIN.            *
629  *                                                          *
630  ************************************************************
631  */
632   else if (OptionMatch("exit", *args)) {
633     if (analyze_mode)
634       return 0;
635     if (input_stream != stdin)
636       fclose(input_stream);
637     input_stream = stdin;
638     ReadClear();
639     Print(32, "\n");
640   }
641 /*
642  ************************************************************
643  *                                                          *
644  *  "flag" command controls whether Crafty will call the    *
645  *  flag in xboard/winboard games (to end the game.)        *
646  *                                                          *
647  ************************************************************
648  */
649   else if (OptionMatch("flag", *args)) {
650     if (nargs < 2) {
651       printf("usage:  flag on|off\n");
652       return 1;
653     }
654     if (!strcmp(args[1], "on"))
655       call_flag = 1;
656     else if (!strcmp(args[1], "off"))
657       call_flag = 0;
658     if (call_flag)
659       Print(32, "end game on time forfeits\n");
660     else
661       Print(32, "ignore time forfeits\n");
662   }
663 /*
664  ************************************************************
665  *                                                          *
666  *  "flip" command flips the board, interchanging each      *
667  *  rank with the corresponding rank on the other half of   *
668  *  the board, and also reverses the color of all pieces.   *
669  *                                                          *
670  ************************************************************
671  */
672   else if (OptionMatch("flip", *args)) {
673     int file, rank, piece, temp;
674 
675     if (thinking || pondering)
676       return 2;
677     for (rank = 0; rank < 4; rank++) {
678       for (file = 0; file < 8; file++) {
679         piece = -PcOnSq((rank << 3) + file);
680         PcOnSq((rank << 3) + file) = -PcOnSq(((7 - rank) << 3) + file);
681         PcOnSq(((7 - rank) << 3) + file) = piece;
682       }
683     }
684     game_wtm = Flip(game_wtm);
685     temp = Castle(0, white);
686     Castle(0, white) = Castle(0, black);
687     Castle(0, black) = temp;
688     SetChessBitBoards(tree);
689 #if defined(DEBUG)
690     ValidatePosition(tree, 0, game_wtm, "Option().flip");
691 #endif
692   }
693 /*
694  ************************************************************
695  *                                                          *
696  *  "flop" command flops the board, interchanging each      *
697  *  file with the corresponding file on the other half of   *
698  *  the board.                                              *
699  *                                                          *
700  ************************************************************
701  */
702   else if (OptionMatch("flop", *args)) {
703     int file, rank, piece;
704 
705     if (thinking || pondering)
706       return 2;
707     for (rank = 0; rank < 8; rank++) {
708       for (file = 0; file < 4; file++) {
709         piece = PcOnSq((rank << 3) + file);
710         PcOnSq((rank << 3) + file) = PcOnSq((rank << 3) + 7 - file);
711         PcOnSq((rank << 3) + 7 - file) = piece;
712       }
713     }
714     SetChessBitBoards(tree);
715 #if defined(DEBUG)
716     ValidatePosition(tree, 0, game_wtm, "Option().flop");
717 #endif
718   }
719 /*
720  ************************************************************
721  *                                                          *
722  *  "force" command forces the program to make a specific   *
723  *  move instead of its last chosen move.                   *
724  *                                                          *
725  ************************************************************
726  */
727   else if (OptionMatch("force", *args)) {
728     int move, movenum, save_move_number;
729     char text[16];
730 
731     if (thinking || pondering)
732       return 3;
733     if (xboard) {
734       force = 1;
735       return 3;
736     }
737     if (nargs < 2) {
738       printf("usage:  force <move>\n");
739       return 1;
740     }
741     ponder_move = 0;
742     presult = 0;
743     last_pv.pathd = 0;
744     last_pv.pathl = 0;
745     save_move_number = move_number;
746     movenum = move_number;
747     if (game_wtm)
748       movenum--;
749     strcpy(text, args[1]);
750     sprintf(buffer, "reset %d", movenum);
751     game_wtm = Flip(game_wtm);
752     Option(tree);
753     move = InputMove(tree, 0, game_wtm, 0, 0, text);
754     if (move) {
755       if (input_stream != stdin)
756         printf("%s\n", OutputMove(tree, 0, game_wtm, move));
757       if (history_file) {
758         fseek(history_file, ((movenum - 1) * 2 + 1 - game_wtm) * 10,
759             SEEK_SET);
760         fprintf(history_file, "%9s\n", OutputMove(tree, 0, game_wtm, move));
761       }
762       MakeMoveRoot(tree, game_wtm, move);
763       last_pv.pathd = 0;
764       last_pv.pathl = 0;
765     } else if (input_stream == stdin)
766       printf("illegal move.\n");
767     game_wtm = Flip(game_wtm);
768     move_number = save_move_number;
769     strcpy(ponder_text, "none");
770   }
771 /*
772  ************************************************************
773  *                                                          *
774  *  "go" command does nothing, except force main() to start *
775  *  a search.  ("move" is an alias for go).                 *
776  *                                                          *
777  ************************************************************
778  */
779   else if (OptionMatch("go", *args) || OptionMatch("move", *args)) {
780     int t;
781     char temp[128];
782 
783     if (thinking || pondering)
784       return 2;
785     if (game_wtm) {
786       if (strncmp(pgn_white, "Crafty", 6)) {
787         strcpy(temp, pgn_white);
788         strcpy(pgn_white, pgn_black);
789         strcpy(pgn_black, temp);
790       }
791     } else {
792       if (strncmp(pgn_black, "Crafty", 6)) {
793         strcpy(temp, pgn_white);
794         strcpy(pgn_white, pgn_black);
795         strcpy(pgn_black, temp);
796       }
797     }
798     t = tc_time_remaining[white];
799     tc_time_remaining[white] = tc_time_remaining[black];
800     tc_time_remaining[black] = t;
801     t = tc_moves_remaining[white];
802     tc_moves_remaining[white] = tc_moves_remaining[black];
803     tc_moves_remaining[black] = t;
804     force = 0;
805     return -1;
806   }
807 /*
808  ************************************************************
809  *                                                          *
810  *  "history" command displays game history (moves).        *
811  *                                                          *
812  ************************************************************
813  */
814   else if (OptionMatch("history", *args)) {
815     int i;
816     char buffer[128];
817 
818     if (history_file) {
819       printf("    white       black\n");
820       for (i = 0; i < (move_number - 1) * 2 - game_wtm + 1; i++) {
821         fseek(history_file, i * 10, SEEK_SET);
822         v = fscanf(history_file, "%s", buffer);
823         if (v <= 0)
824           perror("Option() fscanf error: ");
825         if (!(i % 2))
826           printf("%3d", i / 2 + 1);
827         printf("  %-10s", buffer);
828         if (i % 2 == 1)
829           printf("\n");
830       }
831       if (Flip(game_wtm))
832         printf("  ...\n");
833     }
834   }
835 /*
836  ************************************************************
837  *                                                          *
838  *  "hard" command enables thinking on opponent's time.     *
839  *                                                          *
840  ************************************************************
841  */
842   else if (OptionMatch("hard", *args)) {
843     ponder = 1;
844     Print(32, "pondering enabled.\n");
845   }
846 /*
847  ************************************************************
848  *                                                          *
849  *  "hash" command controls the transposition table size.   *
850  *  The size can be entered in one of four ways:            *
851  *                                                          *
852  *     hash=nnn  where nnn is in bytes.                     *
853  *     hash=nnnK where nnn is in K bytes.                   *
854  *     hash=nnnM where nnn is in M bytes.                   *
855  *     hash=nnnG where nnn is in G bytes.                   *
856  *                                                          *
857  *  the only restriction is that the hash table is computed *
858  *  as a perfect power of 2.  Any value that is not a       *
859  *  perfect power of 2 is rounded down so that it is, in    *
860  *  order to avoid breaking the addressing scheme.          *
861  *                                                          *
862  ************************************************************
863  */
864   else if (OptionMatch("hash", *args)) {
865     size_t old_hash_size = hash_table_size, new_hash_size;
866 
867     if (thinking || pondering)
868       return 2;
869     if (nargs > 1) {
870       allow_memory = 0;
871       if (xboard)
872         Print(4095, "Warning--  xboard 'memory' option disabled\n");
873       new_hash_size = atoiKMB(args[1]);
874       if (new_hash_size < 64 * 1024) {
875         printf("ERROR.  Minimum hash table size is 64K bytes.\n");
876         return 1;
877       }
878       hash_table_size = ((1ull) << MSB(new_hash_size)) / 16;
879       AlignedRemalloc((void *) &hash_table, 64,
880           hash_table_size * sizeof(HASH_ENTRY));
881       if (!hash_table) {
882         printf("AlignedRemalloc() failed, not enough memory.\n");
883         exit(1);
884       }
885       hash_mask = (hash_table_size - 1) & ~3;
886     }
887     Print(32, "hash table memory = %s bytes",
888         DisplayKMB(hash_table_size * sizeof(HASH_ENTRY), 1));
889     Print(32, " (%s entries).\n", DisplayKMB(hash_table_size, 1));
890     InitializeHashTables(old_hash_size != hash_table_size);
891   }
892 /*
893  ************************************************************
894  *                                                          *
895  *  "phash" command controls the path hash table size. The  *
896  *  size can be entered in one of four ways:                *
897  *                                                          *
898  *     phash=nnn  where nnn is in bytes.                    *
899  *     phash=nnnK where nnn is in K bytes.                  *
900  *     phash=nnnM where nnn is in M bytes.                  *
901  *     phash=nnnG where nnn is in G bytes.                  *
902  *                                                          *
903  *  the only restriction is that the path hash table must   *
904  *  have a perfect power of 2 entries.  The value entered   *
905  *  will be rounded down to meet that requirement.          *
906  *                                                          *
907  ************************************************************
908  */
909   else if (OptionMatch("phash", *args)) {
910     size_t old_hash_size = hash_path_size, new_hash_size;
911 
912     if (thinking || pondering)
913       return 2;
914     if (nargs > 1) {
915       new_hash_size = atoiKMB(args[1]);
916       if (new_hash_size < 64 * 1024) {
917         printf("ERROR.  Minimum phash table size is 64K bytes.\n");
918         return 1;
919       }
920       hash_path_size = ((1ull) << MSB(new_hash_size / sizeof(HPATH_ENTRY)));
921       AlignedRemalloc((void *) &hash_path, 64,
922           sizeof(HPATH_ENTRY) * hash_path_size);
923       if (!hash_path) {
924         printf("AlignedRemalloc() failed, not enough memory.\n");
925         hash_path_size = 0;
926         hash_path = 0;
927       }
928       hash_path_mask = (hash_path_size - 1) & ~15;
929     }
930     Print(32, "hash path table memory = %s bytes",
931         DisplayKMB(hash_path_size * sizeof(HPATH_ENTRY), 1));
932     Print(32, " (%s entries).\n", DisplayKMB(hash_path_size, 1));
933     InitializeHashTables(old_hash_size != hash_path_size);
934   }
935 /*
936  ************************************************************
937  *                                                          *
938  *  "hashp" command controls the pawn hash table size.      *
939  *                                                          *
940  ************************************************************
941  */
942   else if (OptionMatch("hashp", *args)) {
943     size_t old_hash_size = pawn_hash_table_size, new_hash_size;
944 
945     if (thinking || pondering)
946       return 2;
947     if (nargs > 1) {
948       allow_memory = 0;
949       if (xboard)
950         Print(4095, "Warning--  xboard 'memory' option disabled\n");
951       new_hash_size = atoiKMB(args[1]);
952       if (new_hash_size < 16 * 1024) {
953         printf("ERROR.  Minimum pawn hash table size is 16K bytes.\n");
954         return 1;
955       }
956       pawn_hash_table_size =
957           1ull << MSB(new_hash_size / sizeof(PAWN_HASH_ENTRY));
958       AlignedRemalloc((void *) &pawn_hash_table, 64,
959           sizeof(PAWN_HASH_ENTRY) * pawn_hash_table_size);
960       if (!pawn_hash_table) {
961         printf("AlignedRemalloc() failed, not enough memory.\n");
962         exit(1);
963       }
964       pawn_hash_mask = pawn_hash_table_size - 1;
965     }
966     Print(32, "pawn hash table memory = %s bytes",
967         DisplayKMB(pawn_hash_table_size * sizeof(PAWN_HASH_ENTRY), 1));
968     Print(32, " (%s entries).\n", DisplayKMB(pawn_hash_table_size, 1));
969     InitializeHashTables(old_hash_size != pawn_hash_table_size);
970   }
971 /*
972  ************************************************************
973  *                                                          *
974  *  "help" command lists commands/options.                  *
975  *                                                          *
976  ************************************************************
977  */
978   else if (OptionMatch("help", *args)) {
979     FILE *helpfile;
980     char *readstat = (char *) -1;
981     char fname[128];
982     int lines = 0;
983 
984     sprintf(fname, "%s/crafty.hlp", book_path);
985           helpfile = fopen(fname, "r");
986     if (!helpfile) {
987       printf("ERROR.  Unable to open \"crafty.hlp\" -- help unavailable\n");
988       return 1;
989     }
990     if (nargs > 1) {
991       while (1) {
992         readstat = fgets(buffer, 128, helpfile);
993         if (!readstat) {
994           printf("Sorry, no help available for \"%s\"\n", args[1]);
995           fclose(helpfile);
996           return 1;
997         }
998         if (buffer[0] == '<') {
999           if (strstr(buffer, args[1]))
1000             break;
1001         }
1002       }
1003     }
1004     while (1) {
1005       readstat = fgets(buffer, 128, helpfile);
1006       if (!readstat)
1007         break;
1008       if (strchr(buffer, '\n'))
1009         *strchr(buffer, '\n') = 0;
1010       if (!strcmp(buffer, "<end>"))
1011         break;
1012       printf("%s\n", buffer);
1013       lines++;
1014       if (lines > 22) {
1015         lines = 0;
1016         printf("<return> for more...");
1017         fflush(stdout);
1018         Read(1, buffer);
1019       }
1020     }
1021     fclose(helpfile);
1022   }
1023 /*
1024  ************************************************************
1025  *                                                          *
1026  *  "hint" displays the expected move based on the last     *
1027  *  search done. [xboard compatibility]                     *
1028  *                                                          *
1029  ************************************************************
1030  */
1031   else if (OptionMatch("hint", *args)) {
1032     if (strlen(ponder_text)) {
1033       printf("Hint: %s\n", ponder_text);
1034       fflush(stdout);
1035     }
1036   }
1037 /*
1038  ************************************************************
1039  *                                                          *
1040  *  "input" command directs the program to read input from  *
1041  *  a file until eof is reached or an "exit" command is     *
1042  *  encountered while reading the file.                     *
1043  *                                                          *
1044  ************************************************************
1045  */
1046   else if (OptionMatch("input", *args)) {
1047     if (thinking || pondering)
1048       return 2;
1049     nargs = ReadParse(buffer, args, " \t=");
1050     if (nargs < 2) {
1051       printf("usage:  input <filename>\n");
1052       return 1;
1053     }
1054     if (!(input_stream = fopen(args[1], "r"))) {
1055       printf("file does not exist.\n");
1056       input_stream = stdin;
1057     }
1058   }
1059 /*
1060  ************************************************************
1061  *                                                          *
1062  *  "info" command gives some information about Crafty.     *
1063  *                                                          *
1064  ************************************************************
1065  */
1066   else if (OptionMatch("info", *args)) {
1067     Print(32, "Crafty version %s\n", version);
1068     Print(32, "number of threads =         %2d\n", smp_max_threads);
1069     Print(32, "hash table memory = %s bytes", DisplayKMB(hash_table_size * 64,
1070             1));
1071     Print(32, " (%s entries).\n", DisplayKMB(hash_table_size * 5, 0));
1072     Print(32, "pawn hash table memory = %5s\n",
1073         DisplayKMB(pawn_hash_table_size * sizeof(PAWN_HASH_ENTRY), 1));
1074     if (!tc_sudden_death) {
1075       Print(32, "%d moves/%d minutes %d seconds primary time control\n",
1076           tc_moves, tc_time / 6000, (tc_time / 100) % 60);
1077       Print(32, "%d moves/%d minutes %d seconds secondary time control\n",
1078           tc_secondary_moves, tc_secondary_time / 6000,
1079           (tc_secondary_time / 100) % 60);
1080       if (tc_increment)
1081         Print(32, "increment %d seconds.\n", tc_increment / 100);
1082     } else if (tc_sudden_death == 1) {
1083       Print(32, " game/%d minutes primary time control\n", tc_time / 6000);
1084       if (tc_increment)
1085         Print(32, "increment %d seconds.\n", (tc_increment / 100) % 60);
1086     } else if (tc_sudden_death == 2) {
1087       Print(32, "%d moves/%d minutes primary time control\n", tc_moves,
1088           tc_time / 6000);
1089       Print(32, "game/%d minutes secondary time control\n",
1090           tc_secondary_time / 6000);
1091       if (tc_increment)
1092         Print(32, "increment %d seconds.\n", tc_increment / 100);
1093     }
1094     Print(32, "book frequency (freq)..............%4.2f\n", book_weight_freq);
1095     Print(32, "book static evaluation (eval)......%4.2f\n", book_weight_eval);
1096     Print(32, "book learning (learn)..............%4.2f\n",
1097         book_weight_learn);
1098   }
1099 /*
1100  ************************************************************
1101  *                                                          *
1102  *  "kibitz" command sets kibitz mode for ICS.  =1 will     *
1103  *  kibitz mate announcements, =2 will kibitz scores and    *
1104  *  other info, =3 will kibitz scores and PV, =4 adds the   *
1105  *  list of book moves, =5 displays the PV after each       *
1106  *  iteration completes.                                    *
1107  *                                                          *
1108  ************************************************************
1109  */
1110   else if (OptionMatch("kibitz", *args)) {
1111     if (nargs < 2) {
1112       printf("usage:  kibitz <level>\n");
1113       return 1;
1114     }
1115     kibitz = Min(5, atoi(args[1]));
1116   }
1117 /*
1118  ************************************************************
1119  *                                                          *
1120  *  "learn" command enables/disables the learning           *
1121  *  algorithm used in Crafty.  this is controlled by a      *
1122  *  single variable that is either 0 or 1 (disabled or      *
1123  *  enabled).                                               *
1124  *                                                          *
1125  *  "learn clear" clears all learning data in the opening   *
1126  *  book, returning it to a state identical to when the     *
1127  *  book was originally created.                            *
1128  *                                                          *
1129  ************************************************************
1130  */
1131   else if (OptionMatch("learn", *args)) {
1132     if (nargs == 2) {
1133       if (OptionMatch("clear", *(args + 1))) {
1134         int index[32768], i, j, cluster;
1135         unsigned char buf32[4];
1136 
1137         fseek(book_file, 0, SEEK_SET);
1138         for (i = 0; i < 32768; i++) {
1139           v = fread(buf32, 4, 1, book_file);
1140           if (v <= 0)
1141             perror("Option() fread error: ");
1142           index[i] = BookIn32(buf32);
1143         }
1144         for (i = 0; i < 32768; i++)
1145           if (index[i] > 0) {
1146             fseek(book_file, index[i], SEEK_SET);
1147             v = fread(buf32, 4, 1, book_file);
1148             if (v <= 0)
1149               perror("Option() fread error: ");
1150             cluster = BookIn32(buf32);
1151             if (cluster)
1152               BookClusterIn(book_file, cluster, book_buffer);
1153             for (j = 0; j < cluster; j++)
1154               book_buffer[j].learn = 0.0;
1155             fseek(book_file, index[i] + sizeof(int), SEEK_SET);
1156             if (cluster)
1157               BookClusterOut(book_file, cluster, book_buffer);
1158           }
1159       } else {
1160         learning = atoi(args[1]);
1161         learn = (learning > 0) ? 1 : 0;
1162         if (learning)
1163           Print(32, "book learning enabled {-%d,+%d}\n", learning, learning);
1164         else
1165           Print(32, "book learning disabled\n");
1166       }
1167     }
1168   }
1169 /*
1170  ************************************************************
1171  *                                                          *
1172  *  "level" command sets time controls [xboard compati-     *
1173  *  bility.]                                                *
1174  *                                                          *
1175  ************************************************************
1176  */
1177   else if (OptionMatch("level", *args)) {
1178     if (nargs < 4) {
1179       printf("usage:  level <nmoves> <stime> <inc>\n");
1180       return 1;
1181     }
1182     tc_moves = atoi(args[1]);
1183     tc_time = atoi(args[2]) * 60;
1184     if (strchr(args[2], ':'))
1185       tc_time = tc_time + atoi(strchr(args[2], ':') + 1);
1186     tc_time *= 100;
1187     tc_increment = atoi(args[3]) * 100;
1188     tc_time_remaining[white] = tc_time;
1189     tc_time_remaining[black] = tc_time;
1190     if (!tc_moves) {
1191       tc_sudden_death = 1;
1192       tc_moves = 1000;
1193       tc_moves_remaining[white] = 1000;
1194       tc_moves_remaining[black] = 1000;
1195     } else
1196       tc_sudden_death = 0;
1197     if (tc_moves) {
1198       tc_secondary_moves = tc_moves;
1199       tc_secondary_time = tc_time;
1200       tc_moves_remaining[white] = tc_moves;
1201       tc_moves_remaining[black] = tc_moves;
1202     }
1203     if (!tc_sudden_death) {
1204       Print(32, "%d moves/%d seconds primary time control\n", tc_moves,
1205           tc_time / 100);
1206       Print(32, "%d moves/%d seconds secondary time control\n",
1207           tc_secondary_moves, tc_secondary_time / 100);
1208       if (tc_increment)
1209         Print(32, "increment %d seconds.\n", tc_increment / 100);
1210     } else if (tc_sudden_death == 1) {
1211       Print(32, " game/%d seconds primary time control\n", tc_time / 100);
1212       if (tc_increment)
1213         Print(32, "increment %d seconds.\n", tc_increment / 100);
1214     }
1215     if (adaptive_hash) {
1216       uint64_t positions_per_move;
1217       float percent;
1218       int optimal_hash_size;
1219 
1220       TimeSet(think);
1221       time_limit /= 100;
1222       positions_per_move = time_limit * adaptive_hash / 16;
1223       optimal_hash_size = positions_per_move * 16;
1224       printf("optimal=%d\n", optimal_hash_size);
1225       optimal_hash_size = Max(optimal_hash_size, adaptive_hash_min);
1226       optimal_hash_size = Min(optimal_hash_size, adaptive_hash_max);
1227       sprintf(buffer, "hash=%d\n", optimal_hash_size);
1228       Option(tree);
1229       percent =
1230           (float) (optimal_hash_size -
1231           adaptive_hash_min) / (float) (adaptive_hash_max -
1232           adaptive_hash_min);
1233       optimal_hash_size =
1234           adaptive_hashp_min + percent * (adaptive_hashp_max -
1235           adaptive_hashp_min);
1236       optimal_hash_size = Max(optimal_hash_size, adaptive_hashp_min);
1237       sprintf(buffer, "hashp=%d\n", optimal_hash_size);
1238       Option(tree);
1239     }
1240   }
1241 /*
1242  ************************************************************
1243  *                                                          *
1244  *  "linelength" sets the default line length to something  *
1245  *  other than 80, if desired.  Setting this to a huge      *
1246  *  number makes a PV print on one line for easier parsing  *
1247  *  by automated scripts.                                   *
1248  *                                                          *
1249  ************************************************************
1250  */
1251   else if (OptionMatch("linelength", *args)) {
1252     if (nargs > 2) {
1253       printf("usage:  linelength <n>\n");
1254       return 1;
1255     }
1256     if (nargs == 2)
1257       line_length = atoi(args[1]);
1258     printf("line length set to %d.\n", line_length);
1259   }
1260 /*
1261  ************************************************************
1262  *                                                          *
1263  *  "list" command allows the operator to add or remove     *
1264  *  names from the various lists Crafty uses to recognize   *
1265  *  and adapt to particular opponents.                      *
1266  *                                                          *
1267  *  list <listname> <player>                                *
1268  *                                                          *
1269  *  <listname> is one of AK, B, C, GM, IM, SP.              *
1270  *                                                          *
1271  *  The final parameter is a name to add  or remove.  If    *
1272  *  you prepend a + to the name, that asks that the name be *
1273  *  added to the list.  If you prepend a - to the name,     *
1274  *  that asks that the name be removed from the list.  If   *
1275  *  no name is given, the list is displayed.                *
1276  *                                                          *
1277  *  AK is the "auto-kibitz" list.  Crafty will kibitz info  *
1278  *  on a chess server when playing any opponent in this     *
1279  *  list.  This should only have computer names as humans   *
1280  *  don't approve of kibitzes while they are playing.       *
1281  *                                                          *
1282  *  B identifies "blocker" players, those that try to       *
1283  *  block the position and go for easy draws.  This makes   *
1284  *  Crafty try much harder to prevent this from happening,  *
1285  *  even at the expense of positional compensation.         *
1286  *                                                          *
1287  *  GM and IM identify titled players.  This affects how    *
1288  *  and when Crafty resigns or offers/accepts draws.  For   *
1289  *  GM players it will do so fairly early after the right   *
1290  *  circumstances have been seen, for IM it delays a bit    *
1291  *  longer as they are more prone to making a small error   *
1292  *  that avoids the loss or draw.                           *
1293  *                                                          *
1294  *  SP is the "special player" option.  This is an extended *
1295  *  version of the "list" command that allows you to        *
1296  *  specify a special "start book" for a particular         *
1297  *  opponent to make Crafty play specific openings against  *
1298  *  that opponent, as well as allowing you to specify a     *
1299  *  personality file to use against that specific opponent  *
1300  *  when he is identified by the correct "name" command.    *
1301  *                                                          *
1302  *  For the SP list, the command is extended to use         *
1303  *                                                          *
1304  *  "list SP +player book=filename  personality=filename"   *
1305  *                                                          *
1306  *  For the SP list, the files specified must exist in the  *
1307  *  current directory unless the bookpath and perspath      *
1308  *  commands direct Crafty to look elsewhere.               *
1309  *                                                          *
1310  ************************************************************
1311  */
1312   else if (OptionMatch("list", *args)) {
1313     char **targs;
1314     char listname[5][3] = { "AK", "B", "GM", "IM", "SP" };
1315     char **listaddr[] = { AK_list, B_list, GM_list,
1316       IM_list, SP_list
1317     };
1318     int i, list, lastent = -1;
1319 
1320     targs = args;
1321     for (list = 0; list < 5; list++) {
1322       if (!strcmp(listname[list], args[1]))
1323         break;
1324     }
1325     if (list > 4) {
1326       printf("usage:  list AK|B|GM|IM|P|SP +name1 -name2 etc\n");
1327       return 1;
1328     }
1329     nargs -= 2;
1330     targs += 2;
1331     if (nargs) {
1332       while (nargs) {
1333         if (targs[0][0] == '-') {
1334           for (i = 0; i < 128; i++)
1335             if (listaddr[list][i]) {
1336               if (!strcmp(listaddr[list][i], targs[0] + 1)) {
1337                 free(listaddr[list][i]);
1338                 listaddr[list][i] = NULL;
1339                 Print(32, "%s removed from %s list.\n", targs[0] + 1,
1340                     listname[list]);
1341                 break;
1342               }
1343             }
1344         } else if (targs[0][0] == '+') {
1345           for (i = 0; i < 128; i++)
1346             if (listaddr[list][i]) {
1347               if (!strcmp(listaddr[list][i], targs[0] + 1)) {
1348                 Print(32, "Warning: %s is already in %s list.\n",
1349                     targs[0] + 1, listname[list]);
1350                 break;
1351               }
1352             }
1353           for (i = 0; i < 128; i++)
1354             if (listaddr[list][i] == NULL)
1355               break;
1356           if (i >= 128)
1357             Print(32, "ERROR!  %s list is full at 128 entries\n",
1358                 listname[list]);
1359           else {
1360             listaddr[list][i] = malloc(strlen(targs[0]));
1361             strcpy(listaddr[list][i], targs[0] + 1);
1362             Print(32, "%s added to %s list.\n", targs[0] + 1, listname[list]);
1363             if (list == 5)
1364               lastent = i;
1365           }
1366         } else if (!strcmp(targs[0], "clear")) {
1367           for (i = 0; i < 128; i++) {
1368             free(listaddr[list][i]);
1369             listaddr[list][i] = NULL;
1370           }
1371         } else if (!strcmp(targs[0], "book") && lastent != -1) {
1372           char filename[256];
1373           FILE *file;
1374 
1375           strcpy(filename, book_path);
1376           strcat(filename, "/");
1377           strcat(filename, targs[1]);
1378           if (!strstr(args[2], ".bin"))
1379             strcat(filename, ".bin");
1380           file = fopen(filename, "r");
1381           if (!file) {
1382             Print(4095, "ERROR  book file %s can not be opened\n", filename);
1383             break;
1384           }
1385           fclose(file);
1386           SP_opening_filename[lastent] = malloc(strlen(filename) + 1);
1387           strcpy(SP_opening_filename[lastent], filename);
1388           nargs--;
1389           targs++;
1390         } else if (!strcmp(targs[0], "personality") && lastent != -1) {
1391           char filename[256];
1392           FILE *file;
1393 
1394           strcat(filename, targs[1]);
1395           if (!strstr(args[2], ".cpf"))
1396             strcat(filename, ".cpf");
1397           file = fopen(filename, "r");
1398           if (!file) {
1399             Print(4095, "ERROR  personality file %s can not be opened\n",
1400                 filename);
1401             break;
1402           }
1403           fclose(file);
1404           SP_personality_filename[lastent] = malloc(strlen(filename) + 1);
1405           strcpy(SP_personality_filename[lastent], filename);
1406           nargs--;
1407           targs++;
1408         } else
1409           printf("error, name must be preceeded by +/- flag.\n");
1410         nargs--;
1411         targs++;
1412       }
1413     } else {
1414       Print(32, "%s List:\n", listname[list]);
1415       for (i = 0; i < 128; i++) {
1416         if (listaddr[list][i]) {
1417           Print(32, "%s", listaddr[list][i]);
1418           if (list == 5) {
1419             if (SP_opening_filename[i])
1420               Print(32, "  book=%s", SP_opening_filename[i]);
1421             if (SP_personality_filename[i])
1422               Print(32, "  personality=%s", SP_personality_filename[i]);
1423           }
1424           Print(32, "\n");
1425         }
1426       }
1427     }
1428   }
1429 /*
1430  ************************************************************
1431  *                                                          *
1432  *  "lmp" command sets the formla parameters that produce   *
1433  *  LMP pruning bounds array.                               *
1434  *                                                          *
1435  *     lmp <maxdepth> <base> <scale>                        *
1436  *                                                          *
1437  *  <maxdepth> is the max depth at which LMP is done.       *
1438  *                                                          *
1439  *  <base> is the base pruning move count.  The function is *
1440  *  an exponential of the form x = base + f(y).  The        *
1441  *  default is currently 3.                                 *
1442  *                                                          *
1443  *  <scale> is the exponent of the exponential function.    *
1444  *  larger numbers produce more conservative (larger) move  *
1445  *  counts.  Smaller values are more aggressive.  The       *
1446  *  default is currently 1.9.                               *
1447  *                                                          *
1448  ************************************************************
1449  */
1450   else if (OptionMatch("lmp", *args)) {
1451     int i;
1452 
1453     if ((nargs > 1 && nargs < 4) || nargs > 4) {
1454       printf("usage:  lmp <maxdepth> <base> <scale>\n");
1455       return 1;
1456     }
1457     if (nargs > 1) {
1458       LMP_depth = atoi(args[1]);
1459       LMP_base = atoi(args[2]);
1460       LMP_scale = atof(args[3]);
1461       InitializeLMP();
1462     }
1463     Print(32, "LMP depth=%d  base=%d  scale=%f\n", LMP_depth, LMP_base,
1464         LMP_scale);
1465     Print(32, "depth:  ");
1466     for (i = 1; i < 16; i++)
1467       Print(32, "%4d", i);
1468     Print(32, "\n");
1469     Print(32, "movcnt: ");
1470     for (i = 1; i < 16; i++)
1471       Print(32, "%4d", LMP[i]);
1472     Print(32, "\n");
1473   }
1474 /*
1475  ************************************************************
1476  *                                                          *
1477  *  "lmr" command sets the formla parameters that produce   *
1478  *  LMR reduction matrix.  The format is:                   *
1479  *                                                          *
1480  *     lmr <min> <max> <depth bias> <moves bias> <scale>    *
1481  *                                                          *
1482  *  <min> is the minimum LMR reduction.  This probably      *
1483  *  should not be changed from 1, the default.              *
1484  *                                                          *
1485  *  <max> is the maximum LMR reduction.  If you adjust the  *
1486  *  following values, you might need to increase this as it *
1487  *  is an absolute clamp and no value can exceed this no    *
1488  *  matter what the formula produces.                       *
1489  *                                                          *
1490  *  <depth_bias> is simply a multiplier that causes depth   *
1491  *  to influence the reduction amount more or less (as the  *
1492  *  value drops below the value used for <moves bias> below *
1493  *  or as it is increased above <moves bias>.  The default  *
1494  *  is 2.0.                                                 *
1495  *                                                          *
1496  *  <moves bias> is simply a multiplier that causes the     *
1497  *  number of moves already searched to become more or less *
1498  *  important than the remaining depth as above.  The       *
1499  *  default is 1.0.                                         *
1500  *                                                          *
1501  *  <scale> is used to scale the formula back since it uses *
1502  *  a logarithmic expression.  The basic idea is to adjust  *
1503  *  the above two values to produce the desired "shape" of  *
1504  *  the reduction matrix, then adjust this to change the    *
1505  *  reduction amounts overall.  The default is 2.9.         *
1506  *                                                          *
1507  ************************************************************
1508  */
1509   else if (OptionMatch("lmr", *args)) {
1510     int i, j;
1511 
1512     if ((nargs > 1 && nargs < 6) || nargs > 7) {
1513       printf("usage:  lmr <min> <max> <depth bias> <move bias> <scale>\n");
1514       return 1;
1515     }
1516     if (nargs > 1) {
1517       LMR_min = atoi(args[1]);
1518       LMR_max = Min(atoi(args[2]), 15);
1519       LMR_db = atof(args[3]);
1520       LMR_mb = atof(args[4]);
1521       LMR_s = atof(args[5]);
1522       InitializeLMR();
1523     }
1524     if (nargs > 6) {
1525       char *axis = "|||||||||||depth left|||||||||||";
1526 
1527       Print(32,
1528           "LMR values:  %d(min) %d(max) %.2f(depth) %.2f(moves) %.2f(scale).\n",
1529           LMR_min, LMR_max, LMR_db, LMR_mb, LMR_s);
1530       Print(32, "\n                 LMR reductions[depth][moves]\n");
1531       Print(32, "  ----------------------moves searched-----------------\n");
1532       Print(32, " |      ");
1533       for (i = 0; i < 64; i += 1)
1534         Print(32, "%3d", i);
1535       Print(32, "\n");
1536       for (i = 0; i < 32; i += 1) {
1537         Print(32, " %c %3d: ", axis[i], i);
1538         for (j = 0; j < 64; j += 1)
1539           Print(32, " %2d", LMR[i][j]);
1540         Print(32, "\n");
1541       }
1542     } else {
1543       char *axis = "||depth left|||";
1544 
1545       Print(32,
1546           "LMR values:  %d(min) %d(max) %.2f(depth) %.2f(moves) %.2f(scale).\n",
1547           LMR_min, LMR_max, LMR_db, LMR_mb, LMR_s);
1548       Print(32, "\n                 LMR reductions[depth][moves]\n");
1549       Print(32, "  ----------------------moves searched------------------\n");
1550       Print(32, " |      ");
1551       for (i = 2; i < 64; i += 4)
1552         Print(32, "%3d", i);
1553       Print(32, "\n");
1554       for (i = 3; i < 32; i += 2) {
1555         Print(32, " %c %3d: ", axis[(i - 3) / 2], i);
1556         for (j = 2; j < 64; j += 4)
1557           Print(32, " %2d", LMR[i][j]);
1558         Print(32, "\n");
1559       }
1560       Print(32, "    note:  table is shown compressed, each index is in\n");
1561       Print(32, "    units of 1, all rows/columns are not shown above\n");
1562     }
1563   }
1564 /*
1565  ************************************************************
1566  *                                                          *
1567  *   "load" command directs the program to read input from  *
1568  *   a file until a "setboard" command is found  this       *
1569  *   command is then executed, setting up the position for  *
1570  *   a search.                                              *
1571  *                                                          *
1572  ************************************************************
1573  */
1574   else if (OptionMatch("load", *args)) {
1575     char title[64];
1576     char *readstat;
1577     FILE *prob_file;
1578 
1579     if (thinking || pondering)
1580       return 2;
1581     nargs = ReadParse(buffer, args, " \t=");
1582     if (nargs < 3) {
1583       printf("usage:  input <filename> title\n");
1584       return 1;
1585     }
1586     if (!(prob_file = fopen(args[1], "r"))) {
1587       printf("file does not exist.\n");
1588       return 1;
1589     }
1590     strcpy(title, args[2]);
1591     while (!feof(prob_file)) {
1592       readstat = fgets(buffer, 128, prob_file);
1593       if (readstat) {
1594         char *delim;
1595 
1596         delim = strchr(buffer, '\n');
1597         if (delim)
1598           *delim = 0;
1599         delim = strchr(buffer, '\r');
1600         if (delim)
1601           *delim = ' ';
1602       }
1603       if (readstat == NULL)
1604         break;
1605       nargs = ReadParse(buffer, args, " \t;\n");
1606       if (!strcmp(args[0], "title") && strstr(buffer, title))
1607         break;
1608     }
1609     while (!feof(prob_file)) {
1610       readstat = fgets(buffer, 128, prob_file);
1611       if (readstat) {
1612         char *delim;
1613 
1614         delim = strchr(buffer, '\n');
1615         if (delim)
1616           *delim = 0;
1617         delim = strchr(buffer, '\r');
1618         if (delim)
1619           *delim = ' ';
1620       }
1621       if (readstat == NULL)
1622         break;
1623       nargs = ReadParse(buffer, args, " \t;\n");
1624       if (!strcmp(args[0], "setboard")) {
1625         Option(tree);
1626         break;
1627       }
1628     }
1629     fclose(prob_file);
1630   }
1631 /*
1632  ************************************************************
1633  *                                                          *
1634  *   "log" command turns log on/off, and also lets you view *
1635  *   the end of the log or copy it to disk as needed.  To   *
1636  *   view the end, simply type "log <n>" where n is the #   *
1637  *   of lines you'd like to see (the last <n> lines).  You  *
1638  *   can add a filename to the end and the output will go   *
1639  *   to this file instead.                                  *
1640  *                                                          *
1641  ************************************************************
1642  */
1643   else if (OptionMatch("log", *args)) {
1644     char filename[64];
1645 
1646     if (nargs < 2) {
1647       printf("usage:  log on|off|n [filename]\n");
1648       return 1;
1649     }
1650     if (!strcmp(args[1], "on")) {
1651       int id;
1652 
1653       id = InitializeGetLogID();
1654       sprintf(log_filename, "%s/log.%03d", log_path, id);
1655       sprintf(history_filename, "%s/game.%03d", log_path, id);
1656       log_file = fopen(log_filename, "w");
1657       history_file = fopen(history_filename, "w+");
1658     } else if (!strcmp(args[1], "off")) {
1659       if (log_file)
1660         fclose(log_file);
1661       log_file = 0;
1662       sprintf(filename, "%s/log.%03d", log_path, log_id - 1);
1663       remove(filename);
1664       sprintf(filename, "%s/game.%03d", log_path, log_id - 1);
1665       remove(filename);
1666     } else if (args[1][0] >= '0' && args[1][0] <= '9')
1667       log_id = atoi(args[1]);
1668   }
1669 /*
1670  ************************************************************
1671  *                                                          *
1672  *   "memory" command is used to set the max memory to use  *
1673  *   for hash and hashp combined.  This is an xboard        *
1674  *   compatibility command, not normally used by players.   *
1675  *                                                          *
1676  ************************************************************
1677  */
1678   else if (OptionMatch("memory", *args)) {
1679     uint64_t size;
1680     size_t hmemory, pmemory;
1681     if (nargs < 2) {
1682       printf("usage:  memory <size>\n");
1683       return 1;
1684     }
1685     if (allow_memory) {
1686       size = (uint64_t) atoi(args[1]);
1687       if (size == 0) {
1688         Print(4095, "ERROR - memory size can not be zero\n");
1689         return 1;
1690       }
1691       hmemory = (1ull) << MSB(size);
1692       size &= ~hmemory;
1693       pmemory = (1ull) << MSB(size);
1694       sprintf(buffer, "hash %" PRIu64 "M\n", (uint64_t) hmemory);
1695       Option(tree);
1696       if (pmemory) {
1697         sprintf(buffer, "hashp %" PRIu64 "M\n", (uint64_t) pmemory);
1698         Option(tree);
1699       }
1700     } else
1701       Print(4095, "WARNING - memory command ignored.\n");
1702   }
1703 /*
1704  ************************************************************
1705  *                                                          *
1706  *   "mode" command sets tournament mode or normal mode.    *
1707  *   Tournament mode is used when Crafty is in a "real"     *
1708  *   tournament.  It forces draw_score to 0, and makes      *
1709  *   Crafty display the chess clock after each move.        *
1710  *                                                          *
1711  ************************************************************
1712  */
1713   else if (OptionMatch("mode", *args)) {
1714     if (nargs > 1) {
1715       if (!strcmp(args[1], "tournament")) {
1716         mode = tournament_mode;
1717         printf("use 'settc' command if a game is restarted after Crafty\n");
1718         printf("has been terminated for any reason.\n");
1719       } else if (!strcmp(args[1], "normal")) {
1720         mode = normal_mode;
1721         book_weight_learn = 1.0;
1722         book_weight_freq = 1.0;
1723         book_weight_eval = 0.5;
1724       } else if (!strcmp(args[1], "match")) {
1725         mode = normal_mode;
1726         book_weight_learn = 1.0;
1727         book_weight_freq = 0.2;
1728         book_weight_eval = 0.1;
1729       } else {
1730         printf("usage:  mode normal|tournament|match\n");
1731         mode = normal_mode;
1732         book_weight_learn = 1.0;
1733         book_weight_freq = 1.0;
1734         book_weight_eval = 0.5;
1735       }
1736     }
1737     if (mode == tournament_mode)
1738       printf("tournament mode.\n");
1739     else if (mode == normal_mode)
1740       printf("normal mode.\n");
1741   }
1742 /*
1743  ************************************************************
1744  *                                                          *
1745  *   "name" command saves opponents name and writes it into *
1746  *   logfile along with the date/time.  It also scans the   *
1747  *   list of known computers and adjusts its opening book   *
1748  *   to play less "risky" if it matches.  If the opponent   *
1749  *   is in the GM list, it tunes the resignation controls   *
1750  *   to resign earlier.  Ditto for other lists that are     *
1751  *   used to recognize specific opponents and adjust things *
1752  *   accordingly.                                           *
1753  *                                                          *
1754  ************************************************************
1755  */
1756   else if (OptionMatch("name", *args)) {
1757     char *next;
1758     int i;
1759 
1760     if (nargs < 2) {
1761       printf("usage:  name <name>\n");
1762       return 1;
1763     }
1764     if (game_wtm) {
1765       strcpy(pgn_white, args[1]);
1766       sprintf(pgn_black, "Crafty %s", version);
1767     } else {
1768       strcpy(pgn_black, args[1]);
1769       sprintf(pgn_white, "Crafty %s", version);
1770     }
1771     Print(32, "Crafty %s vs %s\n", version, args[1]);
1772     next = args[1];
1773     while (*next) {
1774       *next = tolower(*next);
1775       next++;
1776     }
1777     if (mode != tournament_mode) {
1778       for (i = 0; i < 128; i++)
1779         if (AK_list[i] && !strcmp(AK_list[i], args[1])) {
1780           kibitz = 4;
1781           break;
1782         }
1783       for (i = 0; i < 128; i++)
1784         if (GM_list[i] && !strcmp(GM_list[i], args[1])) {
1785           Print(32, "playing a GM!\n");
1786           book_selection_width = 3;
1787           resign = Min(6, resign);
1788           resign_count = 4;
1789           draw_count = 4;
1790           accept_draws = 1;
1791           kibitz = 0;
1792           break;
1793         }
1794       for (i = 0; i < 128; i++)
1795         if (IM_list[i] && !strcmp(IM_list[i], args[1])) {
1796           Print(32, "playing an IM!\n");
1797           book_selection_width = 4;
1798           resign = Min(9, resign);
1799           resign_count = 5;
1800           draw_count = 4;
1801           accept_draws = 1;
1802           kibitz = 0;
1803           break;
1804         }
1805       for (i = 0; i < 128; i++)
1806         if (SP_list[i] && !strcmp(SP_list[i], args[1])) {
1807           FILE *normal_bs_file = books_file;
1808 
1809           Print(32, "playing a special player!\n");
1810           if (SP_opening_filename[i]) {
1811             books_file = fopen(SP_opening_filename[i], "rb");
1812             if (!books_file) {
1813               Print(4095, "Error!  unable to open %s for player %s.\n",
1814                   SP_opening_filename[i], SP_list[i]);
1815               books_file = normal_bs_file;
1816             }
1817           }
1818           if (SP_personality_filename[i]) {
1819             sprintf(buffer, "personality load %s\n",
1820                 SP_personality_filename[i]);
1821             Option(tree);
1822           }
1823           break;
1824         }
1825     }
1826     printf("tellicsnoalias kibitz Hello from Crafty v%s! (%d cpus)\n",
1827         version, Max(1, smp_max_threads));
1828   }
1829 /*
1830  ************************************************************
1831  *                                                          *
1832  *  "new" command initializes for a new game.               *
1833  *                                                          *
1834  ************************************************************
1835  */
1836   else if (OptionMatch("new", *args)) {
1837     Print(4095, "NOTICE:  ""new"" command not implemented, please exit and\n");
1838     Print(4095, "restart crafty to re-initialize everything for a new game\n");
1839     return 1;
1840   }
1841 /*
1842  ************************************************************
1843  *                                                          *
1844  *  "noise" command sets a minimum limit on time searched   *
1845  *  before we start to display the normal search output.    *
1846  *  With today's hardware and deep searches, it is easy to  *
1847  *  get "swamped" with output.  Using "noise" you can say   *
1848  *  "hold the output until you have searched for <x> time   *
1849  *  (where time can be x.xx seconds or just x seconds.)     *
1850  *                                                          *
1851  ************************************************************
1852  */
1853   else if (OptionMatch("noise", *args)) {
1854     if (nargs < 2) {
1855       printf("usage:  noise <n>\n");
1856       return 1;
1857     }
1858     noise_level = atof(args[1]) * 100;
1859     Print(32, "noise level set to %.2f seconds.\n",
1860         (float) noise_level / 100.0);
1861   }
1862 /*
1863  ************************************************************
1864  *                                                          *
1865  *  "null" command sets the minimum null-move reduction and *
1866  *  a value that is used to compute the max reduction.      *
1867  *                                                          *
1868  *     null <min> <divisor>                                 *
1869  *                                                          *
1870  *  <min> is the minimum null move reduction.  The default  *
1871  *  is 3 which is pretty reliable.                          *
1872  *                                                          *
1873  *  <divisor> increases the null move by the following      *
1874  *  simple formula:                                         *
1875  *                                                          *
1876  *    null_reduction = min + depth / divisor                *
1877  *                                                          *
1878  *  The default value is currently 10, which will increase  *
1879  *  R (null-move reduction) by one at any position where    *
1880  *  depth >= 10 and < 20.  Or by two when depth > 20.  Etc. *
1881  *                                                          *
1882  ************************************************************
1883  */
1884   else if (OptionMatch("null", *args)) {
1885 
1886     if (nargs > 3) {
1887       printf("usage:  null <min> <divisor>\n");
1888       return 1;
1889     }
1890     if (nargs > 1) {
1891       null_depth = atoi(args[1]);
1892       null_divisor = atoi(args[2]);
1893     }
1894     Print(32, "null move:  R = %d + depth / %d\n", null_depth, null_divisor);
1895   }
1896 /*
1897  ************************************************************
1898  *                                                          *
1899  *  "otim" command sets the opponent's time remaining.      *
1900  *  This is used to determine if the opponent is in time    *
1901  *  trouble, and is factored into the draw score if he is.  *
1902  *                                                          *
1903  ************************************************************
1904  */
1905   else if (OptionMatch("otim", *args)) {
1906     if (nargs < 2) {
1907       printf("usage:  otime <time(unit=.01 secs))>\n");
1908       return 1;
1909     }
1910     tc_time_remaining[game_wtm] = atoi(args[1]);
1911     if (log_file && time_limit > 99)
1912       fprintf(log_file, "time remaining: %s (opponent).\n",
1913           DisplayTime(tc_time_remaining[game_wtm]));
1914     if (call_flag && xboard && tc_time_remaining[game_wtm] < 1) {
1915       if (crafty_is_white)
1916         Print(32, "1-0 {Black ran out of time}\n");
1917       else
1918         Print(32, "0-1 {White ran out of time}\n");
1919     }
1920   }
1921 /*
1922  ************************************************************
1923  *                                                          *
1924  *  "output" command sets long or short algebraic output.   *
1925  *  Long is Ng1f3, while short is simply Nf3.               *
1926  *                                                          *
1927  ************************************************************
1928  */
1929   else if (OptionMatch("output", *args)) {
1930     if (nargs < 2) {
1931       printf("usage:  output long|short\n");
1932       return 1;
1933     }
1934     if (!strcmp(args[1], "long"))
1935       output_format = 1;
1936     else if (!strcmp(args[1], "short"))
1937       output_format = 0;
1938     else
1939       printf("usage:  output long|short\n");
1940     if (output_format == 1)
1941       Print(32, "output moves in long algebraic format\n");
1942     else if (output_format == 0)
1943       Print(32, "output moves in short algebraic format\n");
1944   }
1945 /*
1946  ************************************************************
1947  *                                                          *
1948  *  "personality" command is used to adjust the eval terms  *
1949  *  and search options to modify the way Crafty plays.      *
1950  *                                                          *
1951  ************************************************************
1952  */
1953   else if (OptionMatch("personality", *args)) {
1954     int i, j, param, index, value;
1955 
1956 /*
1957  ************************************************************
1958  *                                                          *
1959  *  Handle the "personality list" command and dump every-   *
1960  *  thing the user can modify.                              *
1961  *                                                          *
1962  ************************************************************
1963  */
1964     if (nargs == 2 && !strcmp(args[1], "list")) {
1965       printf("\n");
1966       for (i = 0; i < 256; i++) {
1967         if (!personality_packet[i].description)
1968           continue;
1969         if (personality_packet[i].value) {
1970           switch (personality_packet[i].type) {
1971             case 1:
1972               printf("%3d  %s %7d\n", i, personality_packet[i].description,
1973                   *(int *) personality_packet[i].value);
1974               break;
1975             case 2:
1976               printf("%3d  %s %7d (mg) %7d (eg)\n", i,
1977                   personality_packet[i].description,
1978                   ((int *) personality_packet[i].value)[mg],
1979                   ((int *) personality_packet[i].value)[eg]);
1980               break;
1981             case 3:
1982               printf("%3d  %s %7.2f\n", i, personality_packet[i].description,
1983                   *(double *) personality_packet[i].value);
1984               break;
1985             case 4:
1986               printf("%3d  %s    ", i, personality_packet[i].description);
1987               for (j = 0; j < personality_packet[i].size; j++)
1988                 printf("%4d", ((int *) personality_packet[i].value)[j]);
1989               printf("\n");
1990               break;
1991           }
1992         } else {
1993           printf("==================================================\n");
1994           printf("=         %s  =\n", personality_packet[i].description);
1995           printf("==================================================\n");
1996         }
1997       }
1998       printf("\n");
1999       return 1;
2000     }
2001 /*
2002  ************************************************************
2003  *                                                          *
2004  *  Handle the "personality load" command and read in the   *
2005  *  specified *.cpf file.                                   *
2006  *                                                          *
2007  ************************************************************
2008  */
2009     if (!strcmp(args[1], "load")) {
2010       FILE *file;
2011       char filename[256];
2012 
2013       strcpy(filename, args[2]);
2014       if (!strstr(filename, ".cpf"))
2015         strcat(filename, ".cpf");
2016       Print(32, "Loading personality file %s\n", filename);
2017       if ((file = fopen(filename, "r+"))) {
2018         while (fgets(buffer, 4096, file)) {
2019           char *delim;
2020 
2021           delim = strchr(buffer, '\n');
2022           if (delim)
2023             *delim = 0;
2024           delim = strstr(buffer, "->");
2025           if (delim)
2026             *delim = 0;
2027           delim = strchr(buffer, '\r');
2028           if (delim)
2029             *delim = ' ';
2030           Option(tree);
2031         }
2032         fclose(file);
2033       }
2034       return 1;
2035     }
2036 /*
2037  ************************************************************
2038  *                                                          *
2039  *  Handle the "personality save" command and dump every-   *
2040  *  thing that can be modified to a file.                   *
2041  *                                                          *
2042  ************************************************************
2043  */
2044     if (nargs == 3 && !strcmp(args[1], "save")) {
2045       char filename[256];
2046       FILE *file;
2047 
2048       strcpy(filename, args[2]);
2049       if (!strstr(filename, ".cpf"))
2050         strcat(filename, ".cpf");
2051       file = fopen(filename, "w");
2052       if (!file) {
2053         printf("ERROR.  Unable to open %s for writing\n", args[2]);
2054         return 1;
2055       }
2056       printf("saving to file \"%s\"\n", filename);
2057       fprintf(file, "# Crafty v%s personality file\n", version);
2058       for (i = 0; i < 256; i++) {
2059         if (!personality_packet[i].description)
2060           continue;
2061         if (personality_packet[i].value) {
2062           if (personality_packet[i].size <= 1)
2063             fprintf(file, "personality %3d %7d\n", i,
2064                 *((int *) personality_packet[i].value));
2065           else if (personality_packet[i].size > 1) {
2066             fprintf(file, "personality %3d ", i);
2067             for (j = 0; j < personality_packet[i].size; j++)
2068               fprintf(file, "%d ", ((int *) personality_packet[i].value)[j]);
2069             fprintf(file, "\n");
2070           }
2071         }
2072       }
2073       fprintf(file, "exit\n");
2074       fclose(file);
2075       return 1;
2076     }
2077 /*
2078  ************************************************************
2079  *                                                          *
2080  *  Handle the "personality index val" command that changes *
2081  *  only those personality terms that are scalars.          *
2082  *                                                          *
2083  ************************************************************
2084  */
2085     param = atoi(args[1]);
2086     value = atoi(args[2]);
2087     if (!personality_packet[param].value) {
2088       Print(4095, "ERROR.  evaluation term %d is not defined\n", param);
2089       return 1;
2090     }
2091     if (personality_packet[param].size == 0) {
2092       if (nargs > 3) {
2093         printf("this eval term requires exactly 1 value.\n");
2094         return 1;
2095       }
2096       *(int *) personality_packet[param].value = value;
2097     }
2098 /*
2099  ************************************************************
2100  *                                                          *
2101  *  Handle the "personality index v1 v2 .. vn" command that *
2102  *  changes eval terms that are vectors.                    *
2103  *                                                          *
2104  ************************************************************
2105  */
2106     else {
2107       index = nargs - 2;
2108       if (index != personality_packet[param].size) {
2109         printf
2110             ("this eval term (%s [%d]) requires exactly %d values, found %d.\n",
2111             personality_packet[param].description, param,
2112             Abs(personality_packet[param].size), index);
2113         return 1;
2114       }
2115       for (i = 0; i < index; i++)
2116         ((int *) personality_packet[param].value)[i] = atoi(args[i + 2]);
2117     }
2118     InitializeKingSafety();
2119   }
2120 /*
2121  ************************************************************
2122  *                                                          *
2123  *  "bookpath", "logpath" and "tbpath" set the default      *
2124  *  paths to locate or save these files.                    *
2125  *                                                          *
2126  ************************************************************
2127  */
2128   else if (OptionMatch("logpath", *args) || OptionMatch("bookpath", *args)
2129       || OptionMatch("tbpath", *args)) {
2130     if (OptionMatch("logpath", *args) || OptionMatch("bookpath", *args)) {
2131       if (log_file)
2132         Print(4095, "ERROR -- this must be used on command line only\n");
2133     }
2134     nargs = ReadParse(buffer, args, " \t=");
2135     if (nargs < 2) {
2136       printf("usage:  bookpath|perspath|logpath|tbpath <path>\n");
2137       return 1;
2138     }
2139     if (!strchr(args[1], '(')) {
2140       if (strstr(args[0], "bookpath"))
2141         strcpy(book_path, args[1]);
2142       else if (strstr(args[0], "logpath"))
2143         strcpy(log_path, args[1]);
2144 #if defined(SYZYGY)
2145       else if (strstr(args[0], "tbpath"))
2146         strcpy(tb_path, args[1]);
2147 #endif
2148 
2149     } else {
2150       if (strchr(args[1], ')')) {
2151         *strchr(args[1], ')') = 0;
2152         if (strstr(args[0], "bookpath"))
2153           strcpy(book_path, args[1] + 1);
2154         else if (strstr(args[0], "logpath"))
2155           strcpy(log_path, args[1] + 1);
2156 #if defined(SYZYGY)
2157         else if (strstr(args[0], "tbpath"))
2158           strcpy(tb_path, args[1] + 1);
2159 #endif
2160       } else
2161         Print(4095, "ERROR multiple paths must be enclosed in ( and )\n");
2162     }
2163   }
2164 /*
2165  ************************************************************
2166  *                                                          *
2167  *  "perf" command turns times move generator/make_move.    *
2168  *                                                          *
2169  ************************************************************
2170  */
2171 #define PERF_CYCLES 4000000
2172   else if (OptionMatch("perf", *args)) {
2173     int i, clock_before, clock_after;
2174     unsigned *mv;
2175     float time_used;
2176 
2177     if (thinking || pondering)
2178       return 2;
2179     clock_before = clock();
2180     while (clock() == clock_before);
2181     clock_before = clock();
2182     for (i = 0; i < PERF_CYCLES; i++) {
2183       tree->last[1] = GenerateCaptures(tree, 0, game_wtm, tree->last[0]);
2184       tree->last[1] = GenerateNoncaptures(tree, 0, game_wtm, tree->last[1]);
2185     }
2186     clock_after = clock();
2187     time_used =
2188         ((float) clock_after - (float) clock_before) / (float) CLOCKS_PER_SEC;
2189     printf("generated %d moves, time=%.2f seconds\n",
2190         (int) (tree->last[1] - tree->last[0]) * PERF_CYCLES, time_used);
2191     printf("generated %d moves per second\n",
2192         (int) (((float) (PERF_CYCLES * (tree->last[1] -
2193                         tree->last[0]))) / time_used));
2194     clock_before = clock();
2195     while (clock() == clock_before);
2196     clock_before = clock();
2197     for (i = 0; i < PERF_CYCLES; i++) {
2198       tree->last[1] = GenerateCaptures(tree, 0, game_wtm, tree->last[0]);
2199       tree->last[1] = GenerateNoncaptures(tree, 0, game_wtm, tree->last[1]);
2200       for (mv = tree->last[0]; mv < tree->last[1]; mv++) {
2201         MakeMove(tree, 0, game_wtm, *mv);
2202         UnmakeMove(tree, 0, game_wtm, *mv);
2203       }
2204     }
2205     clock_after = clock();
2206     time_used =
2207         ((float) clock_after - (float) clock_before) / (float) CLOCKS_PER_SEC;
2208     printf("generated/made/unmade %d moves, time=%.2f seconds\n",
2209         (int) (tree->last[1] - tree->last[0]) * PERF_CYCLES, time_used);
2210     printf("generated/made/unmade %d moves per second\n",
2211         (int) (((float) (PERF_CYCLES * (tree->last[1] -
2212                         tree->last[0]))) / time_used));
2213   }
2214 /*
2215  ************************************************************
2216  *                                                          *
2217  *  "perft" command turns tests move generator/make_move.   *
2218  *                                                          *
2219  ************************************************************
2220  */
2221   else if (OptionMatch("perft", *args)) {
2222     float time_used;
2223     int i, clock_before, clock_after;
2224 
2225     if (thinking || pondering)
2226       return 2;
2227     clock_before = clock();
2228     while (clock() == clock_before);
2229     clock_before = clock();
2230     if (nargs < 2) {
2231       printf("usage:  perft <depth>\n");
2232       return 1;
2233     }
2234     tree->status[1] = tree->status[0];
2235     tree->last[0] = tree->move_list;
2236     i = atoi(args[1]);
2237     if (i <= 0) {
2238       Print(32, "usage:  perft <maxply>\n");
2239       return 1;
2240     }
2241     total_moves = 0;
2242     OptionPerft(tree, 1, i, game_wtm);
2243     clock_after = clock();
2244     time_used =
2245         ((float) clock_after - (float) clock_before) / (float) CLOCKS_PER_SEC;
2246     printf("total moves=%" PRIu64 "  time=%.2f\n", total_moves, time_used);
2247   }
2248 /*
2249  ************************************************************
2250  *                                                          *
2251  *  "pgn" command sets the various PGN header files.        *
2252  *                                                          *
2253  ************************************************************
2254  */
2255   else if (OptionMatch("pgn", *args)) {
2256     int i;
2257 
2258     if (nargs < 3) {
2259       printf("usage:  pgn <tag> <value>\n");
2260       return 1;
2261     }
2262     if (!strcmp(args[1], "Event")) {
2263       pgn_event[0] = 0;
2264       for (i = 2; i < nargs; i++) {
2265         strcpy(pgn_event + strlen(pgn_event), args[i]);
2266         strcpy(pgn_event + strlen(pgn_event), " ");
2267       }
2268     } else if (!strcmp(args[1], "Site")) {
2269       pgn_site[0] = 0;
2270       for (i = 2; i < nargs; i++) {
2271         strcpy(pgn_site + strlen(pgn_site), args[i]);
2272         strcpy(pgn_site + strlen(pgn_site), " ");
2273       }
2274     } else if (!strcmp(args[1], "Round")) {
2275       pgn_round[0] = 0;
2276       strcpy(pgn_round, args[2]);
2277     } else if (!strcmp(args[1], "White")) {
2278       pgn_white[0] = 0;
2279       for (i = 2; i < nargs; i++) {
2280         strcpy(pgn_white + strlen(pgn_white), args[i]);
2281         strcpy(pgn_white + strlen(pgn_white), " ");
2282       }
2283     } else if (!strcmp(args[1], "WhiteElo")) {
2284       pgn_white_elo[0] = 0;
2285       strcpy(pgn_white_elo, args[2]);
2286     } else if (!strcmp(args[1], "Black")) {
2287       pgn_black[0] = 0;
2288       for (i = 2; i < nargs; i++) {
2289         strcpy(pgn_black + strlen(pgn_black), args[i]);
2290         strcpy(pgn_black + strlen(pgn_black), " ");
2291       }
2292     } else if (!strcmp(args[1], "BlackElo")) {
2293       pgn_black_elo[0] = 0;
2294       strcpy(pgn_black_elo, args[2]);
2295     }
2296   }
2297 /*
2298  ************************************************************
2299  *                                                          *
2300  *  "ping" command simply echos the argument back to xboard *
2301  *  to let it know all previous commands have been executed *
2302  *  and we are ready for whatever is next.                  *
2303  *                                                          *
2304  ************************************************************
2305  */
2306   else if (OptionMatch("ping", *args)) {
2307     if (pondering)
2308       Print(-1, "pong %s\n", args[1]);
2309     else
2310       pong = atoi(args[1]);
2311   }
2312 /*
2313  ************************************************************
2314  *                                                          *
2315  *  "playother" command says "position is set up, we are    *
2316  *  waiting on the opponent to move, ponder if you want to  *
2317  *  do so.                                                  *
2318  *                                                          *
2319  ************************************************************
2320  */
2321   else if (OptionMatch("playother", *args)) {
2322     force = 0;
2323   }
2324 /*
2325  ************************************************************
2326  *                                                          *
2327  *  "ponder" command toggles pondering off/on or sets a     *
2328  *  move to ponder.                                         *
2329  *                                                          *
2330  ************************************************************
2331  */
2332   else if (OptionMatch("ponder", *args)) {
2333     if (thinking || pondering)
2334       return 2;
2335     if (nargs < 2) {
2336       printf("usage:  ponder off|on|<move>\n");
2337       return 1;
2338     }
2339     if (!strcmp(args[1], "on")) {
2340       ponder = 1;
2341       Print(32, "pondering enabled.\n");
2342     } else if (!strcmp(args[1], "off")) {
2343       ponder = 0;
2344       Print(32, "pondering disabled.\n");
2345     } else {
2346       ponder_move = InputMove(tree, 0, game_wtm, 0, 0, args[1]);
2347       last_pv.pathd = 0;
2348       last_pv.pathl = 0;
2349     }
2350   }
2351 /*
2352  ************************************************************
2353  *                                                          *
2354  *  "post/nopost" command sets/resets "show thinking" mode  *
2355  *  for xboard compatibility.                               *
2356  *                                                          *
2357  ************************************************************
2358  */
2359   else if (OptionMatch("post", *args)) {
2360     post = 1;
2361   } else if (OptionMatch("nopost", *args)) {
2362     post = 0;
2363   }
2364 /*
2365  ************************************************************
2366  *                                                          *
2367  *  "protover" command is sent by xboard to identify the    *
2368  *  xboard protocol version and discover what the engine    *
2369  *  can handle.                                             *
2370  *                                                          *
2371  ************************************************************
2372  */
2373   else if (OptionMatch("protover", *args)) {
2374     int pversion = atoi(args[1]);
2375 
2376     if (pversion >= 1 && pversion <= 3) {
2377       if (pversion >= 2) {
2378         Print(-1, "feature ping=1 setboard=1 san=1 time=1 draw=1\n");
2379         Print(-1, "feature sigint=0 sigterm=0 reuse=0 analyze=1\n");
2380         Print(-1, "feature myname=\"Crafty-%s\" name=1\n", version);
2381         Print(-1, "feature playother=1 colors=0 memory=%d\n", allow_memory);
2382 #if (CPUS > 1)
2383         Print(-1, "feature smp=%d\n", allow_cores);
2384 #endif
2385         Print(-1, "feature variants=\"normal,nocastle\"\n");
2386         Print(-1, "feature done=1\n");
2387         xboard_done = 1;
2388       }
2389     } else
2390       Print(4095, "ERROR, bogus xboard protocol version received.\n");
2391   }
2392 /*
2393  ************************************************************
2394  *                                                          *
2395  *  "random" command is ignored. [xboard compatibility]     *
2396  *                                                          *
2397  ************************************************************
2398  */
2399   else if (OptionMatch("random", *args)) {
2400     return xboard;
2401   }
2402 /*
2403  ************************************************************
2404  *                                                          *
2405  *  "rating" is used by xboard to set Crafty's rating and   *
2406  *  the opponent's rating, which is used by the learning    *
2407  *  functions.                                              *
2408  *                                                          *
2409  ************************************************************
2410  */
2411   else if (OptionMatch("rating", *args)) {
2412     int rd;
2413 
2414     if (nargs < 3) {
2415       printf("usage:  rating <Crafty> <opponent>\n");
2416       return 1;
2417     }
2418     crafty_rating = atoi(args[1]);
2419     opponent_rating = atoi(args[2]);
2420     if (crafty_rating == 0 && opponent_rating == 0) {
2421       crafty_rating = 2500;
2422       opponent_rating = 2300;
2423     }
2424     if (dynamic_draw_score) {
2425       rd = opponent_rating - crafty_rating;
2426       rd = Max(Min(rd, 300), -300);
2427       abs_draw_score = rd / 8;
2428       if (log_file) {
2429         fprintf(log_file, "Crafty's rating: %d.\n", crafty_rating);
2430         fprintf(log_file, "opponent's rating: %d.\n", opponent_rating);
2431         fprintf(log_file, "draw score: %d.\n", abs_draw_score);
2432       }
2433     }
2434   }
2435 /*
2436  ************************************************************
2437  *                                                          *
2438  *  "remove" command backs up the game one whole move,      *
2439  *  leaving the opponent still on move.  It's intended for  *
2440  *  xboard compatibility, but works in any mode.            *
2441  *                                                          *
2442  ************************************************************
2443  */
2444   else if (OptionMatch("remove", *args)) {
2445     if (thinking || pondering)
2446       return 2;
2447     move_number--;
2448     sprintf(buffer, "reset %d", move_number);
2449     Option(tree);
2450   }
2451 /*
2452  ************************************************************
2453  *                                                          *
2454  *  "read" reads game moves in and makes them.  This can    *
2455  *  be used in two ways:  (1) type "read" and then start    *
2456  *  entering moves;  type "exit" when done;  (2) type       *
2457  *  "read <filename>" to read moves in from <filename>.     *
2458  *  Note that read will attempt to skip over "non-move"     *
2459  *  text and try to extract moves if it can.                *
2460  *                                                          *
2461  *  Note that "reada" appends to the existing position,     *
2462  *  while "read" resets the board to the start position     *
2463  *  before reading moves.                                   *
2464  *                                                          *
2465  ************************************************************
2466  */
2467   else if (OptionMatch("read", *args) || OptionMatch("reada", *args)) {
2468     FILE *read_input = 0;
2469     int append, move, readstat;
2470 
2471     if (thinking || pondering)
2472       return 2;
2473     nargs = ReadParse(buffer, args, " \t=");
2474     if (!strcmp("reada", *args))
2475       append = 1;
2476     else
2477       append = 0;
2478     ponder_move = 0;
2479     last_pv.pathd = 0;
2480     last_pv.pathl = 0;
2481     if (nargs > 1) {
2482       if (!(read_input = fopen(args[1], "r"))) {
2483         printf("file %s does not exist.\n", args[1]);
2484         return 1;
2485       }
2486     } else {
2487       printf("type \"exit\" to terminate.\n");
2488       read_input = stdin;
2489     }
2490     if (!append) {
2491       InitializeChessBoard(tree);
2492       game_wtm = 1;
2493       move_number = 1;
2494       tc_moves_remaining[white] = tc_moves;
2495       tc_moves_remaining[black] = tc_moves;
2496     }
2497 /*
2498  step 1:  read in the PGN tags.
2499  */
2500     readstat = ReadPGN(0, 0);
2501     do {
2502       if (read_input == stdin) {
2503         if (game_wtm)
2504           printf("read.White(%d): ", move_number);
2505         else
2506           printf("read.Black(%d): ", move_number);
2507         fflush(stdout);
2508       }
2509       readstat = ReadPGN(read_input, 0);
2510     } while (readstat == 1);
2511     if (readstat < 0)
2512       return 1;
2513 /*
2514  step 2:  read in the moves.
2515  */
2516     do {
2517       move = 0;
2518       move = ReadNextMove(tree, buffer, 0, game_wtm);
2519       if (move) {
2520         if (read_input != stdin) {
2521           printf("%s ", OutputMove(tree, 0, game_wtm, move));
2522           if (!(move_number % 8) && Flip(game_wtm))
2523             printf("\n");
2524         }
2525         fseek(history_file, ((move_number - 1) * 2 + 1 - game_wtm) * 10,
2526             SEEK_SET);
2527         fprintf(history_file, "%9s\n", OutputMove(tree, 0, game_wtm, move));
2528         MakeMoveRoot(tree, game_wtm, move);
2529         TimeAdjust(game_wtm, 0);
2530 #if defined(DEBUG)
2531         ValidatePosition(tree, 1, move, "Option()");
2532 #endif
2533       } else if (!read_input)
2534         printf("illegal move.\n");
2535       if (move) {
2536         game_wtm = Flip(game_wtm);
2537         if (game_wtm)
2538           move_number++;
2539       }
2540       if (read_input == stdin) {
2541         if (game_wtm)
2542           printf("read.White(%d): ", move_number);
2543         else
2544           printf("read.Black(%d): ", move_number);
2545         fflush(stdout);
2546       }
2547       readstat = ReadPGN(read_input, 0);
2548       if (readstat < 0)
2549         break;
2550       if (!strcmp(buffer, "exit"))
2551         break;
2552     } while (1);
2553     moves_out_of_book = 0;
2554     printf("NOTICE: %d moves to next time control\n",
2555         tc_moves_remaining[root_wtm]);
2556     root_wtm = !game_wtm;
2557     if (read_input != stdin) {
2558       printf("\n");
2559       fclose(read_input);
2560     }
2561   }
2562 /*
2563  ************************************************************
2564  *                                                          *
2565  *  "rejected" handles the new xboard protocol version 2    *
2566  *  rejected command.                                       *
2567  *                                                          *
2568  ************************************************************
2569  */
2570   else if (OptionMatch("rejected", *args)) {
2571     Print(4095, "ERROR.  feature %s rejected by xboard\n", args[1]);
2572   }
2573 /*
2574  ************************************************************
2575  *                                                          *
2576  *  "reset" restores (backs up) a game to a prior position  *
2577  *  with the same side on move.  Reset 17 would reset the   *
2578  *  position to what it was at move 17 with the current     *
2579  *  still on move (you can use white/black commands to      *
2580  *  change the side to move first, if needed.)              *
2581  *                                                          *
2582  ************************************************************
2583  */
2584   else if (OptionMatch("reset", *args)) {
2585     int i, move, nmoves;
2586 
2587     if (!history_file)
2588       return 1;
2589     if (thinking || pondering)
2590       return 2;
2591     if (nargs < 2) {
2592       printf("usage:  reset <movenumber>\n");
2593       return 1;
2594     }
2595     ponder_move = 0;
2596     last_mate_score = 0;
2597     last_pv.pathd = 0;
2598     last_pv.pathl = 0;
2599     if (thinking || pondering)
2600       return 2;
2601     over = 0;
2602     move_number = atoi(args[1]);
2603     if (!move_number) {
2604       move_number = 1;
2605       return 1;
2606     }
2607     nmoves = (move_number - 1) * 2 + 1 - game_wtm;
2608     root_wtm = Flip(game_wtm);
2609     InitializeChessBoard(tree);
2610     game_wtm = 1;
2611     move_number = 1;
2612     tc_moves_remaining[white] = tc_moves;
2613     tc_moves_remaining[black] = tc_moves;
2614     for (i = 0; i < nmoves; i++) {
2615       fseek(history_file, i * 10, SEEK_SET);
2616       v = fscanf(history_file, "%s", buffer);
2617       if (v <= 0)
2618         perror("Option() fscanf error: ");
2619 /*
2620  If the move is "pass", that means that the side on move passed.
2621  This includes the case where the game started from a black-to-move
2622  position; then white's first move is recorded as a pass.
2623  */
2624       if (strcmp(buffer, "pass") == 0) {
2625         game_wtm = Flip(game_wtm);
2626         if (game_wtm)
2627           move_number++;
2628         continue;
2629       }
2630       move = InputMove(tree, 0, game_wtm, 0, 0, buffer);
2631       if (move)
2632         MakeMoveRoot(tree, game_wtm, move);
2633       else {
2634         printf("ERROR!  move %s is illegal\n", buffer);
2635         break;
2636       }
2637       TimeAdjust(game_wtm, 0);
2638       game_wtm = Flip(game_wtm);
2639       if (game_wtm)
2640         move_number++;
2641     }
2642     moves_out_of_book = 0;
2643     printf("NOTICE: %d moves to next time control\n",
2644         tc_moves_remaining[root_wtm]);
2645   }
2646 /*
2647  ************************************************************
2648  *                                                          *
2649  *  "resign" command sets the resignation threshold to the  *
2650  *  number of pawns the program must be behind before       *
2651  *  resigning (0 -> disable resignations).  Resign with no  *
2652  *  arguments will mark the pgn result as lost by the       *
2653  *  opponent.                                               *
2654  *                                                          *
2655  ************************************************************
2656  */
2657   else if (OptionMatch("resign", *args)) {
2658     if (nargs < 2) {
2659       if (crafty_is_white) {
2660         Print(4095, "result 1-0\n");
2661         strcpy(pgn_result, "1-0");
2662       } else {
2663         Print(4095, "result 0-1\n");
2664         strcpy(pgn_result, "0-1");
2665       }
2666       learn_value = 300;
2667       LearnBook();
2668       return 1;
2669     }
2670     resign = atoi(args[1]);
2671     if (nargs == 3)
2672       resign_count = atoi(args[2]);
2673     if (resign)
2674       Print(32, "resign after %d consecutive moves with score < %d.\n",
2675           resign_count, -resign);
2676     else
2677       Print(32, "disabled resignations.\n");
2678   }
2679 /*
2680  ************************************************************
2681  *                                                          *
2682  *  "result" command comes from xboard/winboard and gives   *
2683  *  the result of the current game.  If learning routines   *
2684  *  have not yet been activated, this will do it.           *
2685  *                                                          *
2686  ************************************************************
2687  */
2688   else if (OptionMatch("result", *args)) {
2689     if (nargs > 1) {
2690       if (!strcmp(args[1], "1-0")) {
2691         strcpy(pgn_result, "1-0");
2692         if (crafty_is_white)
2693           learn_value = 300;
2694         else
2695           learn_value = -300;
2696       } else if (!strcmp(args[1], "0-1")) {
2697         strcpy(pgn_result, "0-1");
2698         if (crafty_is_white)
2699           learn_value = -300;
2700         else
2701           learn_value = 300;
2702       } else if (!strcmp(args[1], "1/2-1/2")) {
2703         strcpy(pgn_result, "1/2-1/2");
2704         learn_value = 1;
2705       }
2706       LearnBook();
2707       return 1;
2708     }
2709   }
2710 /*
2711  ************************************************************
2712  *                                                          *
2713  *  "safety" command sets a specific time safety margin     *
2714  *  target for normal timed games.  This can generally be   *
2715  *  left at the default value unless Crafty is being        *
2716  *  manually operated.                                      *
2717  *                                                          *
2718  ************************************************************
2719  */
2720   else if (OptionMatch("safety", *args)) {
2721     if (nargs == 2)
2722       tc_safety_margin = atoi(args[1]) * 100;
2723     Print(32, "safety margin set to %s.\n", DisplayTime(tc_safety_margin));
2724   }
2725 /*
2726  ************************************************************
2727  *                                                          *
2728  *  "savegame" command saves the game in a file in PGN      *
2729  *  format.  Command has an optional filename.              *
2730  *                                                          *
2731  ************************************************************
2732  */
2733   else if (OptionMatch("savegame", *args)) {
2734     struct tm *timestruct;
2735     FILE *output_file;
2736     time_t secs;
2737     int i, more, swtm;
2738     char input[128], text[128], *next;
2739 
2740     output_file = stdout;
2741     secs = time(0);
2742     timestruct = localtime((time_t *) & secs);
2743     if (nargs > 1) {
2744       if (!(output_file = fopen(args[1], "w"))) {
2745         printf("unable to open %s for write.\n", args[1]);
2746         return 1;
2747       }
2748     }
2749     fprintf(output_file, "[Event \"%s\"]\n", pgn_event);
2750     fprintf(output_file, "[Site \"%s\"]\n", pgn_site);
2751     fprintf(output_file, "[Date \"%4d.%02d.%02d\"]\n",
2752         timestruct->tm_year + 1900, timestruct->tm_mon + 1,
2753         timestruct->tm_mday);
2754     fprintf(output_file, "[Round \"%s\"]\n", pgn_round);
2755     fprintf(output_file, "[White \"%s\"]\n", pgn_white);
2756     fprintf(output_file, "[WhiteElo \"%s\"]\n", pgn_white_elo);
2757     fprintf(output_file, "[Black \"%s\"]\n", pgn_black);
2758     fprintf(output_file, "[BlackElo \"%s\"]\n", pgn_black_elo);
2759     fprintf(output_file, "[Result \"%s\"]\n", pgn_result);
2760 /* Handle setup positions and initial pass by white */
2761     swtm = 1;
2762     if (move_number > 1 || !game_wtm) {
2763       fseek(history_file, 0, SEEK_SET);
2764       if (fscanf(history_file, "%s", input) == 1 &&
2765           strcmp(input, "pass") == 0)
2766         swtm = 0;
2767     }
2768     if (initial_position[0])
2769       fprintf(output_file, "[FEN \"%s\"]\n[SetUp \"1\"]\n", initial_position);
2770     else if (!swtm) {
2771       fprintf(output_file,
2772           "[FEN \"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq - 0 1\"\n"
2773           "[SetUp \"1\"]\n");
2774     }
2775     fprintf(output_file, "\n");
2776     next = text;
2777     if (!swtm) {
2778       strcpy(next, "1... ");
2779       next = text + strlen(text);
2780     }
2781 /* Output the moves */
2782     more = 0;
2783     for (i = (swtm ? 0 : 1); i < (move_number - 1) * 2 - game_wtm + 1; i++) {
2784       fseek(history_file, i * 10, SEEK_SET);
2785       v = fscanf(history_file, "%s", input);
2786       if (v <= 0)
2787         perror("Option() fscanf error: ");
2788       if (!(i % 2)) {
2789         sprintf(next, "%d. ", i / 2 + 1);
2790         next = text + strlen(text);
2791       }
2792       sprintf(next, "%s ", input);
2793       next = text + strlen(text);
2794       more = 1;
2795       if (next - text >= 60) {
2796         fprintf(output_file, "%s\n", text);
2797         more = 0;
2798         next = text;
2799       }
2800     }
2801     if (more)
2802       fprintf(output_file, "%s", text);
2803     fprintf(output_file, "%s\n", pgn_result);
2804     if (output_file != stdout)
2805       fclose(output_file);
2806     printf("PGN save complete.\n");
2807   }
2808 /*
2809  ************************************************************
2810  *                                                          *
2811  *  "savepos" command saves the current position in a FEN   *
2812  *  (Forsythe-Edwards Notation) string that can be later    *
2813  *  used to recreate this exact position.                   *
2814  *                                                          *
2815  ************************************************************
2816  */
2817   else if (OptionMatch("savepos", *args)) {
2818     FILE *output_file;
2819     int rank, file, nempty;
2820 
2821     output_file = stdout;
2822     if (nargs > 1) {
2823       if (!strcmp(args[1], "*")) {
2824         output_file = 0;
2825         strcpy(initial_position, "");
2826       } else if (!(output_file = fopen(args[1], "w"))) {
2827         printf("unable to open %s for write.\n", args[1]);
2828         return 1;
2829       }
2830     }
2831     if (output_file)
2832       fprintf(output_file, "setboard ");
2833     for (rank = RANK8; rank >= RANK1; rank--) {
2834       nempty = 0;
2835       for (file = FILEA; file <= FILEH; file++) {
2836         if (PcOnSq((rank << 3) + file)) {
2837           if (nempty) {
2838             if (output_file)
2839               fprintf(output_file, "%c", empty_sqs[nempty]);
2840             else
2841               sprintf(initial_position + strlen(initial_position), "%c",
2842                   empty_sqs[nempty]);
2843             nempty = 0;
2844           }
2845           if (output_file)
2846             fprintf(output_file, "%c",
2847                 translate[PcOnSq((rank << 3) + file) + 6]);
2848           else
2849             sprintf(initial_position + strlen(initial_position), "%c",
2850                 translate[PcOnSq((rank << 3) + file) + 6]);
2851         } else
2852           nempty++;
2853       }
2854       if (empty_sqs[nempty]) {
2855         if (output_file)
2856           fprintf(output_file, "%c", empty_sqs[nempty]);
2857         else
2858           sprintf(initial_position + strlen(initial_position), "%c",
2859               empty_sqs[nempty]);
2860       }
2861       if (rank != RANK1) {
2862         if (output_file)
2863           fprintf(output_file, "/");
2864         else
2865           sprintf(initial_position + strlen(initial_position), "/");
2866       }
2867     }
2868     if (output_file)
2869       fprintf(output_file, " %c ", (game_wtm) ? 'w' : 'b');
2870     else
2871       sprintf(initial_position + strlen(initial_position), " %c ",
2872           (game_wtm) ? 'w' : 'b');
2873     if (Castle(0, white) & 1) {
2874       if (output_file)
2875         fprintf(output_file, "K");
2876       else
2877         sprintf(initial_position + strlen(initial_position), "K");
2878     }
2879     if (Castle(0, white) & 2) {
2880       if (output_file)
2881         fprintf(output_file, "Q");
2882       else
2883         sprintf(initial_position + strlen(initial_position), "Q");
2884     }
2885     if (Castle(0, black) & 1) {
2886       if (output_file)
2887         fprintf(output_file, "k");
2888       else
2889         sprintf(initial_position + strlen(initial_position), "k");
2890     }
2891     if (Castle(0, black) & 2) {
2892       if (output_file)
2893         fprintf(output_file, "q");
2894       else
2895         sprintf(initial_position + strlen(initial_position), "q");
2896     }
2897     if (!Castle(0, white) && !Castle(0, black)) {
2898       if (output_file)
2899         fprintf(output_file, " -");
2900       else
2901         sprintf(initial_position + strlen(initial_position), " -");
2902     }
2903     if (EnPassant(0)) {
2904       if (output_file)
2905         fprintf(output_file, " %c%c", File(EnPassant(0)) + 'a',
2906             Rank(EnPassant(0)) + '1');
2907       else
2908         sprintf(initial_position + strlen(initial_position), " %c%c",
2909             File(EnPassant(0)) + 'a', Rank(EnPassant(0)) + '1');
2910     } else {
2911       if (output_file)
2912         fprintf(output_file, " -");
2913       else
2914         sprintf(initial_position + strlen(initial_position), " -");
2915     }
2916     if (output_file)
2917       fprintf(output_file, "\n");
2918     if (output_file && output_file != stdout) {
2919       fprintf(output_file, "exit\n");
2920       fclose(output_file);
2921     }
2922     if (output_file)
2923       printf("FEN save complete.\n");
2924   }
2925 /*
2926  ************************************************************
2927  *                                                          *
2928  *  "scale" command is used for tuning.  We modify this to  *
2929  *  scale some scoring value(s) by a percentage that can    *
2930  *  be either positive or negative.                         *
2931  *                                                          *
2932  ************************************************************
2933  */
2934   else if (!strcmp("scale", *args)) {
2935     scale = atoi(args[1]);
2936   }
2937 /*
2938  ************************************************************
2939  *                                                          *
2940  *  "score" command displays static evaluation of the       *
2941  *  current board position.                                 *
2942  *                                                          *
2943  ************************************************************
2944  */
2945   else if (OptionMatch("score", *args)) {
2946     int phase, s, tw, tb, mgb, mgw, egb, egw, trop[2];
2947 
2948     if (thinking || pondering)
2949       return 2;
2950     memset((void *) &(tree->pawn_score), 0, sizeof(tree->pawn_score));
2951     Print(32, "note: scores are for the white side\n");
2952     Print(32, "                       ");
2953     Print(32, " +-----------white----------+");
2954     Print(32, "-----------black----------+\n");
2955     tree->score_mg = 0;
2956     tree->score_eg = 0;
2957     mgb = tree->score_mg;
2958     EvaluateMaterial(tree, game_wtm);
2959     mgb = tree->score_mg - mgb;
2960     Print(32, "material.......%s", DisplayEvaluation(mgb, 1));
2961     Print(32, "  |    comp     mg      eg   |");
2962     Print(32, "    comp     mg      eg   |\n");
2963     root_wtm = Flip(game_wtm);
2964     tree->status[1] = tree->status[0];
2965     s = Evaluate(tree, 1, game_wtm, -99999, 99999);
2966     trop[black] = tree->tropism[black];
2967     trop[white] = tree->tropism[white];
2968     if (!game_wtm)
2969       s = -s;
2970     tree->score_mg = 0;
2971     tree->score_eg = 0;
2972     phase =
2973         Min(62, TotalPieces(white, occupied) + TotalPieces(black, occupied));
2974     tree->pawn_score.score_mg = 0;
2975     tree->pawn_score.score_eg = 0;
2976     mgb = tree->pawn_score.score_mg;
2977     egb = tree->pawn_score.score_eg;
2978     EvaluatePawns(tree, black);
2979     mgb = tree->pawn_score.score_mg - mgb;
2980     egb = tree->pawn_score.score_eg - egb;
2981     mgw = tree->pawn_score.score_mg;
2982     egw = tree->pawn_score.score_eg;
2983     EvaluatePawns(tree, white);
2984     mgw = tree->pawn_score.score_mg - mgw;
2985     egw = tree->pawn_score.score_eg - egw;
2986     tb = (mgb * phase + egb * (62 - phase)) / 62;
2987     tw = (mgw * phase + egw * (62 - phase)) / 62;
2988     Print(32, "pawns..........%s  |", DisplayEvaluation(tb + tw, 1));
2989     Print(32, " %s", DisplayEvaluation(tw, 1));
2990     Print(32, " %s", DisplayEvaluation(mgw, 1));
2991     Print(32, " %s  |", DisplayEvaluation(egw, 1));
2992     Print(32, " %s", DisplayEvaluation(tb, 1));
2993     Print(32, " %s", DisplayEvaluation(mgb, 1));
2994     Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
2995     mgb = tree->score_mg;
2996     egb = tree->score_eg;
2997     EvaluatePassedPawns(tree, black, game_wtm);
2998     mgb = tree->score_mg - mgb;
2999     egb = tree->score_eg - egb;
3000     mgw = tree->score_mg;
3001     egw = tree->score_eg;
3002     EvaluatePassedPawns(tree, white, game_wtm);
3003     mgw = tree->score_mg - mgw;
3004     egw = tree->score_eg - egw;
3005     tb = (mgb * phase + egb * (62 - phase)) / 62;
3006     tw = (mgw * phase + egw * (62 - phase)) / 62;
3007     Print(32, "passed pawns...%s  |", DisplayEvaluation(tb + tw, 1));
3008     Print(32, " %s", DisplayEvaluation(tw, 1));
3009     Print(32, " %s", DisplayEvaluation(mgw, 1));
3010     Print(32, " %s  |", DisplayEvaluation(egw, 1));
3011     Print(32, " %s", DisplayEvaluation(tb, 1));
3012     Print(32, " %s", DisplayEvaluation(mgb, 1));
3013     Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
3014     mgb = tree->score_mg;
3015     egb = tree->score_eg;
3016     EvaluateKnights(tree, black);
3017     mgb = tree->score_mg - mgb;
3018     egb = tree->score_eg - egb;
3019     mgw = tree->score_mg;
3020     egw = tree->score_eg;
3021     EvaluateKnights(tree, white);
3022     mgw = tree->score_mg - mgw;
3023     egw = tree->score_eg - egw;
3024     tb = (mgb * phase + egb * (62 - phase)) / 62;
3025     tw = (mgw * phase + egw * (62 - phase)) / 62;
3026     Print(32, "knights........%s  |", DisplayEvaluation(tb + tw, 1));
3027     Print(32, " %s", DisplayEvaluation(tw, 1));
3028     Print(32, " %s", DisplayEvaluation(mgw, 1));
3029     Print(32, " %s  |", DisplayEvaluation(egw, 1));
3030     Print(32, " %s", DisplayEvaluation(tb, 1));
3031     Print(32, " %s", DisplayEvaluation(mgb, 1));
3032     Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
3033     mgb = tree->score_mg;
3034     egb = tree->score_eg;
3035     EvaluateBishops(tree, black);
3036     mgb = tree->score_mg - mgb;
3037     egb = tree->score_eg - egb;
3038     mgw = tree->score_mg;
3039     egw = tree->score_eg;
3040     EvaluateBishops(tree, white);
3041     mgw = tree->score_mg - mgw;
3042     egw = tree->score_eg - egw;
3043     tb = (mgb * phase + egb * (62 - phase)) / 62;
3044     tw = (mgw * phase + egw * (62 - phase)) / 62;
3045     Print(32, "bishops........%s  |", DisplayEvaluation(tb + tw, 1));
3046     Print(32, " %s", DisplayEvaluation(tw, 1));
3047     Print(32, " %s", DisplayEvaluation(mgw, 1));
3048     Print(32, " %s  |", DisplayEvaluation(egw, 1));
3049     Print(32, " %s", DisplayEvaluation(tb, 1));
3050     Print(32, " %s", DisplayEvaluation(mgb, 1));
3051     Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
3052     mgb = tree->score_mg;
3053     egb = tree->score_eg;
3054     EvaluateRooks(tree, black);
3055     mgb = tree->score_mg - mgb;
3056     egb = tree->score_eg - egb;
3057     mgw = tree->score_mg;
3058     egw = tree->score_eg;
3059     EvaluateRooks(tree, white);
3060     mgw = tree->score_mg - mgw;
3061     egw = tree->score_eg - egw;
3062     tb = (mgb * phase + egb * (62 - phase)) / 62;
3063     tw = (mgw * phase + egw * (62 - phase)) / 62;
3064     Print(32, "rooks..........%s  |", DisplayEvaluation(tb + tw, 1));
3065     Print(32, " %s", DisplayEvaluation(tw, 1));
3066     Print(32, " %s", DisplayEvaluation(mgw, 1));
3067     Print(32, " %s  |", DisplayEvaluation(egw, 1));
3068     Print(32, " %s", DisplayEvaluation(tb, 1));
3069     Print(32, " %s", DisplayEvaluation(mgb, 1));
3070     Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
3071     mgb = tree->score_mg;
3072     egb = tree->score_eg;
3073     EvaluateQueens(tree, black);
3074     mgb = tree->score_mg - mgb;
3075     egb = tree->score_eg - egb;
3076     mgw = tree->score_mg;
3077     egw = tree->score_eg;
3078     EvaluateQueens(tree, white);
3079     mgw = tree->score_mg - mgw;
3080     egw = tree->score_eg - egw;
3081     tb = (mgb * phase + egb * (62 - phase)) / 62;
3082     tw = (mgw * phase + egw * (62 - phase)) / 62;
3083     Print(32, "queens.........%s  |", DisplayEvaluation(tb + tw, 1));
3084     Print(32, " %s", DisplayEvaluation(tw, 1));
3085     Print(32, " %s", DisplayEvaluation(mgw, 1));
3086     Print(32, " %s  |", DisplayEvaluation(egw, 1));
3087     Print(32, " %s", DisplayEvaluation(tb, 1));
3088     Print(32, " %s", DisplayEvaluation(mgb, 1));
3089     Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
3090     tree->tropism[black] = trop[black];
3091     tree->tropism[white] = trop[white];
3092     mgb = tree->score_mg;
3093     egb = tree->score_eg;
3094     EvaluateKing(tree, 1, black);
3095     mgb = tree->score_mg - mgb;
3096     egb = tree->score_eg - egb;
3097     mgw = tree->score_mg;
3098     egw = tree->score_eg;
3099     EvaluateKing(tree, 1, white);
3100     mgw = tree->score_mg - mgw;
3101     egw = tree->score_eg - egw;
3102     tb = (mgb * phase + egb * (62 - phase)) / 62;
3103     tw = (mgw * phase + egw * (62 - phase)) / 62;
3104     Print(32, "kings..........%s  |", DisplayEvaluation(tb + tw, 1));
3105     Print(32, " %s", DisplayEvaluation(tw, 1));
3106     Print(32, " %s", DisplayEvaluation(mgw, 1));
3107     Print(32, " %s  |", DisplayEvaluation(egw, 1));
3108     Print(32, " %s", DisplayEvaluation(tb, 1));
3109     Print(32, " %s", DisplayEvaluation(mgb, 1));
3110     Print(32, " %s  |\n", DisplayEvaluation(egb, 1));
3111     egb = tree->score_eg;
3112     if ((TotalPieces(white, occupied) == 0 && tree->pawn_score.passed[black])
3113         || (TotalPieces(black, occupied) == 0 &&
3114             tree->pawn_score.passed[white]))
3115       EvaluatePassedPawnRaces(tree, game_wtm);
3116     egb = tree->score_eg - egb;
3117     Print(32, "pawn races.....%s", DisplayEvaluation(egb, 1));
3118     Print(32, "  +--------------------------+--------------------------+\n");
3119     Print(32, "total..........%s\n", DisplayEvaluation(s, 1));
3120   }
3121 /*
3122  ************************************************************
3123  *                                                          *
3124  *  "screen" command runs runs through a test suite of      *
3125  *  positions and culls any where a search returns a value  *
3126  *  outside the margin given to the screen command.         *
3127  *                                                          *
3128  ************************************************************
3129  */
3130   else if (OptionMatch("screen", *args)) {
3131     int margin = 9999999, save_noise, save_display;
3132 
3133     nargs = ReadParse(buffer, args, " \t;=");
3134     if (thinking || pondering)
3135       return 2;
3136     if (nargs < 3) {
3137       printf("usage:  screen <filename> score-margin\n");
3138       return 1;
3139     }
3140     save_noise = noise_level;
3141     save_display = display_options;
3142     early_exit = 99;
3143     margin = atoi(args[2]);
3144     noise_level = 99999999;
3145     display_options = 2048;
3146     Test(args[1], 0, 1, margin);
3147     noise_level = save_noise;
3148     display_options = save_display;
3149     ponder_move = 0;
3150     last_pv.pathd = 0;
3151     last_pv.pathl = 0;
3152   }
3153 /*
3154  ************************************************************
3155  *                                                          *
3156  *  "sd" command sets a specific search depth to control    *
3157  *  the tree search depth.                                  *
3158  *                                                          *
3159  ************************************************************
3160  */
3161   else if (OptionMatch("sd", *args)) {
3162     if (nargs < 2) {
3163       printf("usage:  sd <depth>\n");
3164       return 1;
3165     }
3166     search_depth = atoi(args[1]);
3167     Print(32, "search depth set to %d.\n", search_depth);
3168   }
3169 /*
3170  ************************************************************
3171  *                                                          *
3172  *  "search" command sets a specific move for the search    *
3173  *  to analyze, ignoring all others completely.             *
3174  *                                                          *
3175  ************************************************************
3176  */
3177   else if (OptionMatch("search", *args)) {
3178     if (thinking || pondering)
3179       return 2;
3180     if (nargs < 2) {
3181       printf("usage:  search <move>\n");
3182       return 1;
3183     }
3184     search_move = InputMove(tree, 0, game_wtm, 0, 0, args[1]);
3185     if (!search_move)
3186       search_move = InputMove(tree, 0, Flip(game_wtm), 0, 0, args[1]);
3187     if (!search_move)
3188       printf("illegal move.\n");
3189   }
3190 /*
3191  ************************************************************
3192  *                                                          *
3193  *  "setboard" command sets the board to a specific         *
3194  *  position for analysis by the program.                   *
3195  *                                                          *
3196  ************************************************************
3197  */
3198   else if (OptionMatch("setboard", *args)) {
3199     if (thinking || pondering)
3200       return 2;
3201     nargs = ReadParse(buffer, args, " \t;=");
3202     if (nargs < 3) {
3203       printf("usage:  setboard <fen>\n");
3204       return 1;
3205     }
3206     SetBoard(tree, nargs - 1, args + 1, 0);
3207     move_number = 1;
3208     if (!game_wtm) {
3209       game_wtm = 1;
3210       Pass();
3211     }
3212     ponder_move = 0;
3213     last_pv.pathd = 0;
3214     last_pv.pathl = 0;
3215     over = 0;
3216     strcpy(buffer, "savepos *");
3217     Option(tree);
3218   } else if (StrCnt(*args, '/') > 3) {
3219     if (thinking || pondering)
3220       return 2;
3221     nargs = ReadParse(buffer, args, " \t;=");
3222     SetBoard(tree, nargs, args, 0);
3223     move_number = 1;
3224     if (!game_wtm) {
3225       game_wtm = 1;
3226       Pass();
3227     }
3228     ponder_move = 0;
3229     last_pv.pathd = 0;
3230     last_pv.pathl = 0;
3231     over = 0;
3232     strcpy(buffer, "savepos *");
3233     Option(tree);
3234   }
3235 /*
3236  ************************************************************
3237  *                                                          *
3238  *  "settc" command is used to reset the time controls      *
3239  *  after a complete restart.                               *
3240  *                                                          *
3241  ************************************************************
3242  */
3243   else if (OptionMatch("settc", *args)) {
3244     if (thinking || pondering)
3245       return 2;
3246     if (nargs < 4) {
3247       printf("usage:  settc <wmoves> <wtime> <bmoves> <btime>\n");
3248       return 1;
3249     }
3250     tc_moves_remaining[white] = atoi(args[1]);
3251     tc_time_remaining[white] = ParseTime(args[2]) * 6000;
3252     tc_moves_remaining[black] = atoi(args[3]);
3253     tc_time_remaining[black] = ParseTime(args[4]) * 6000;
3254     Print(32, "time remaining: %s (white).\n",
3255         DisplayTime(tc_time_remaining[white]));
3256     Print(32, "time remaining: %s (black).\n",
3257         DisplayTime(tc_time_remaining[black]));
3258     if (tc_sudden_death != 1) {
3259       Print(32, "%d moves to next time control (white)\n",
3260           tc_moves_remaining[white]);
3261       Print(32, "%d moves to next time control (black)\n",
3262           tc_moves_remaining[black]);
3263     } else
3264       Print(32, "Sudden-death time control in effect\n");
3265     TimeSet(999);
3266   }
3267 /*
3268  ************************************************************
3269  *                                                          *
3270  *  "show" command enables/disables whether or not we want  *
3271  *  show book information as the game is played.            *
3272  *                                                          *
3273  ************************************************************
3274  */
3275   else if (OptionMatch("show", *args)) {
3276     if (nargs < 2) {
3277       printf("usage:  show book\n");
3278       return 1;
3279     }
3280     if (OptionMatch("book", args[1])) {
3281       show_book = !show_book;
3282       if (show_book)
3283         Print(32, "show book statistics\n");
3284       else
3285         Print(32, "don't show book statistics\n");
3286     }
3287   }
3288 /*
3289  ************************************************************
3290  *                                                          *
3291  *  "skill" command sets a value from 1-100 that affects    *
3292  *  Crafty's playing skill level.  100 => max skill, 1 =>   *
3293  *  minimal skill.  This is used to slow the search speed   *
3294  *  (and depth) significantly.                              *
3295  *                                                          *
3296  ************************************************************
3297  */
3298 #if defined(SKILL)
3299   else if (OptionMatch("skill", *args)) {
3300     if (nargs < 2) {
3301       printf("usage:  skill <1-100>\n");
3302       return 1;
3303     }
3304     if (skill != 100)
3305       printf("ERROR:  skill can only be changed one time in a game\n");
3306     else {
3307       skill = atoi(args[1]);
3308       if (skill < 1 || skill > 100) {
3309         printf("ERROR: skill range is 1-100 only\n");
3310         skill = 100;
3311       }
3312       Print(32, "skill level set to %d%%\n", skill);
3313     }
3314   }
3315 #endif
3316 /*
3317  ************************************************************
3318  *                                                          *
3319  *   "smp" command is used to tune the various SMP search   *
3320  *   parameters.                                            *
3321  *                                                          *
3322  *   "smpaffinity" command is used to enable (>= 0) and to  *
3323  *   disable smp processor affinity (off).  If you try to   *
3324  *   run two instances of Crafty on the same machine, ONE   *
3325  *   them (if not both) need to have processor affinity     *
3326  *   disabled or else you can use the smpaffinity=<n> to    *
3327  *   prevent processor conflicts.  If you use a 32 core     *
3328  *   machine, and you want to run two instances of Crafty,  *
3329  *   use smpaffinity=0 on one, and smpaffinity=16 on the    *
3330  *   other.  The first will bind to processors 0-15, and    *
3331  *   the second will bind to processors 16-31.              *
3332  *                                                          *
3333  *   "smpgroup" command is used to control how many threads *
3334  *   may work together at any point in the tree.  The       *
3335  *   usual default is 6, but this might be reduced on a     *
3336  *   machine with a large number of processors.  It should  *
3337  *   be tested, of course.                                  *
3338  *                                                          *
3339  *   "smpmin" sets the minimum depth the search can split   *
3340  *   at to keep it from splitting too near the leaves.      *
3341  *                                                          *
3342  *   "smpmt" command is used to set the maximum number of   *
3343  *   parallel threads to use, assuming that Crafty was      *
3344  *   compiled with -DSMP.  This value can not be set        *
3345  *   larger than the compiled-in -DCPUS=n value.            *
3346  *                                                          *
3347  *   "smpnice" command turns on "nice" mode where idle      *
3348  *   processors are terminated between searches to avoid    *
3349  *   burning CPU time in the idle loop.                     *
3350  *                                                          *
3351  *   "smpnuma" command enables NUMA mode which distributes  *
3352  *   hash tables across all NUMA nodes evenly.  If your     *
3353  *   machine is not NUMA, or only has one socket (node) you *
3354  *   should set this to zero as it will be slightly more    *
3355  *   efficient when you change hash sizes.                  *
3356  *                                                          *
3357  *   "smproot" command is used to enable (1) or disable (0) *
3358  *   splitting the tree at the root (ply=1).  Splitting at  *
3359  *   the root is more efficient, but might slow finding the *
3360  *   move in some test positions.                           *
3361  *                                                          *
3362  *   "smpgsd" sets the minimum depth remaining at which a   *
3363  *   gratuitous split can be done.                          *
3364  *                                                          *
3365  *   "smpgsl" sets the maximum number of gratuitous splits  *
3366  *   per thread.  This only counts splits that have not yet *
3367  *   been joined.                                           *
3368  *                                                          *
3369  ************************************************************
3370  */
3371   else if (OptionMatch("smpaffinity", *args)) {
3372     if (nargs < 2) {
3373       printf("usage:  smpaffinity <0/1>\n");
3374       return 1;
3375     }
3376     if (!strcmp(args[1], "off"))
3377       smp_affinity = -1;
3378     else
3379       smp_affinity = atoi(args[1]);
3380     if (smp_affinity >= 0)
3381       Print(32, "smp processor affinity enabled.\n");
3382     else
3383       Print(32, "smp processor affinity disabled.\n");
3384   } else if (OptionMatch("smpmin", *args)) {
3385     if (nargs < 2) {
3386       printf("usage:  smpmin <depth>\n");
3387       return 1;
3388     }
3389     smp_min_split_depth = atoi(args[1]);
3390     Print(32, "minimum thread depth set to %d.\n", smp_min_split_depth);
3391   } else if (OptionMatch("smpgroup", *args)) {
3392     if (nargs < 2) {
3393       printf("usage:  smpgroup <threads>\n");
3394       return 1;
3395     }
3396     smp_split_group = atoi(args[1]);
3397     Print(32, "maximum thread group size set to %d.\n", smp_split_group);
3398   } else if (OptionMatch("smpmt", *args) || OptionMatch("mt", *args)
3399       || OptionMatch("cores", *args)) {
3400     int proc;
3401 
3402     if (nargs < 2) {
3403       printf("usage:  smpmt=<threads>\n");
3404       return 1;
3405     }
3406     if (thinking || pondering)
3407       return 3;
3408     allow_cores = 0;
3409     if (xboard)
3410       Print(4095, "Warning--  xboard 'cores' option disabled\n");
3411     smp_max_threads = atoi(args[1]);
3412     if (smp_max_threads > hardware_processors) {
3413       Print(4095, "ERROR - machine has %d processors.\n",
3414           hardware_processors);
3415       Print(4095, "ERROR - max threads can not exceed this limit.\n");
3416       smp_max_threads = hardware_processors;
3417     }
3418     if (smp_max_threads > CPUS) {
3419       Print(4095, "ERROR - Crafty was compiled with CPUS=%d.", CPUS);
3420       Print(4095, "  mt can not exceed this value.\n");
3421       smp_max_threads = CPUS;
3422     }
3423     if (smp_max_threads == 1) {
3424       Print(4095, "ERROR - max threads can be set to zero (0) to");
3425       Print(4095, " disable parallel search, otherwise it must be > 1.\n");
3426       smp_max_threads = 0;
3427     }
3428     if (smp_max_threads)
3429       Print(32, "max threads set to %d.\n", smp_max_threads);
3430     else
3431       Print(32, "parallel threads disabled.\n");
3432     for (proc = 1; proc < CPUS; proc++)
3433       if (proc >= smp_max_threads)
3434         thread[proc].terminate = 1;
3435   } else if (OptionMatch("smpnice", *args)) {
3436     if (nargs < 2) {
3437       printf("usage:  smpnice 0|1\n");
3438       return 1;
3439     }
3440     smp_nice = atoi(args[1]);
3441     if (smp_nice)
3442       Print(32, "SMP terminate extra threads when idle.\n");
3443     else
3444       Print(32, "SMP keep extra threads spinning when idle.\n");
3445   } else if (OptionMatch("smpnuma", *args)) {
3446     if (nargs < 2) {
3447       printf("usage:  smpnuma 0|1\n");
3448       return 1;
3449     }
3450     smp_numa = atoi(args[1]);
3451     if (smp_numa)
3452       Print(32, "SMP NUMA mode enabled.\n");
3453     else
3454       Print(32, "SMP NUMA mode disabled.\n");
3455   } else if (OptionMatch("smproot", *args)) {
3456     if (nargs < 2) {
3457       printf("usage:  smproot 0|1\n");
3458       return 1;
3459     }
3460     smp_split_at_root = atoi(args[1]);
3461     if (smp_split_at_root)
3462       Print(32, "SMP search split at ply >= 1.\n");
3463     else
3464       Print(32, "SMP search split at ply > 1.\n");
3465   } else if (OptionMatch("smpgsl", *args)) {
3466     if (nargs < 2) {
3467       printf("usage:  smpgsl <n>\n");
3468       return 1;
3469     }
3470     smp_gratuitous_limit = atoi(args[1]);
3471     Print(32, "maximum gratuitous splits allowed %d.\n",
3472         smp_gratuitous_limit);
3473   } else if (OptionMatch("smpgsd", *args)) {
3474     if (nargs < 2) {
3475       printf("usage:  smpgsd <nodes>\n");
3476       return 1;
3477     }
3478     smp_gratuitous_depth = atoi(args[1]);
3479     Print(32, "gratuitous split min depth %d.\n", smp_gratuitous_depth);
3480   }
3481 /*
3482  ************************************************************
3483  *                                                          *
3484  *  "sn" command sets a specific number of nodes to search  *
3485  *  before stopping.  Note:  this requires -DNODES as an    *
3486  *  option when building Crafty.                            *
3487  *                                                          *
3488  ************************************************************
3489  */
3490   else if (OptionMatch("sn", *args)) {
3491     if (nargs < 2) {
3492       printf("usage:  sn <nodes>\n");
3493       return 1;
3494     }
3495     search_nodes = atoi(args[1]);
3496     Print(32, "search nodes set to %" PRIu64 ".\n", search_nodes);
3497     ponder = 0;
3498   }
3499 /*
3500  ************************************************************
3501  *                                                          *
3502  *  "speech" command turns speech on/off.                   *
3503  *                                                          *
3504  ************************************************************
3505  */
3506   else if (OptionMatch("speech", *args)) {
3507     if (nargs < 2) {
3508       printf("usage:  speech on|off\n");
3509       return 1;
3510     }
3511     if (!strcmp(args[1], "on"))
3512       speech = 1;
3513     else if (!strcmp(args[1], "off"))
3514       speech = 0;
3515     if (speech)
3516       Print(4095, "Audio output enabled\n");
3517     else
3518       Print(4095, "Audio output disabled\n");
3519   }
3520 /*
3521  ************************************************************
3522  *                                                          *
3523  *  "st" command sets a specific search time to control the *
3524  *  tree search time.                                       *
3525  *                                                          *
3526  ************************************************************
3527  */
3528   else if (OptionMatch("st", *args)) {
3529     if (nargs < 2) {
3530       printf("usage:  st <time>\n");
3531       return 1;
3532     }
3533     search_time_limit = atof(args[1]) * 100;
3534     Print(32, "search time set to %.2f.\n",
3535         (float) search_time_limit / 100.0);
3536   }
3537 /*
3538  ************************************************************
3539  *                                                          *
3540  *  "swindle" command turns swindle mode off/on.            *
3541  *                                                          *
3542  ************************************************************
3543  */
3544   else if (OptionMatch("swindle", *args)) {
3545     if (!strcmp(args[1], "on"))
3546       swindle_mode = 1;
3547     else if (!strcmp(args[1], "off"))
3548       swindle_mode = 0;
3549     else
3550       printf("usage:  swindle on|off\n");
3551   }
3552 /*
3553  ************************************************************
3554  *                                                          *
3555  *  "tags" command lists the current PGN header tags.       *
3556  *                                                          *
3557  ************************************************************
3558  */
3559   else if (OptionMatch("tags", *args)) {
3560     struct tm *timestruct;
3561     uint64_t secs;
3562 
3563     secs = time(0);
3564     timestruct = localtime((time_t *) & secs);
3565     printf("[Event \"%s\"]\n", pgn_event);
3566     printf("[Site \"%s\"]\n", pgn_site);
3567     printf("[Date \"%4d.%02d.%02d\"]\n", timestruct->tm_year + 1900,
3568         timestruct->tm_mon + 1, timestruct->tm_mday);
3569     printf("[Round \"%s\"]\n", pgn_round);
3570     printf("[White \"%s\"]\n", pgn_white);
3571     printf("[WhiteElo \"%s\"]\n", pgn_white_elo);
3572     printf("[Black \"%s\"]\n", pgn_black);
3573     printf("[BlackElo \"%s\"]\n", pgn_black_elo);
3574     printf("[Result \"%s\"]\n", pgn_result);
3575   }
3576 /*
3577  ************************************************************
3578  *                                                          *
3579  *  "test" command runs a test suite of problems and        *
3580  *  displays results.                                       *
3581  *                                                          *
3582  ************************************************************
3583  */
3584   else if (OptionMatch("test", *args)) {
3585     FILE *unsolved = NULL;
3586     int save_noise, save_display;
3587 
3588     if (thinking || pondering)
3589       return 2;
3590     nargs = ReadParse(buffer, args, " \t;=");
3591     if (nargs < 2) {
3592       printf("usage:  test <filename> [exitcnt]\n");
3593       return 1;
3594     }
3595     save_noise = noise_level;
3596     save_display = display_options;
3597     if (nargs > 2)
3598       early_exit = atoi(args[2]);
3599     if (nargs > 3)
3600       unsolved = fopen(args[3], "w+");
3601     Test(args[1], unsolved, 0, 0);
3602     noise_level = save_noise;
3603     display_options = save_display;
3604     ponder_move = 0;
3605     last_pv.pathd = 0;
3606     last_pv.pathl = 0;
3607     if (unsolved)
3608       fclose(unsolved);
3609   }
3610 /*
3611  ************************************************************
3612  *                                                          *
3613  *  "time" is used to set the basic search timing controls. *
3614  *  The general form of the command is as follows:          *
3615  *                                                          *
3616  *    time nmoves/ntime/[nmoves/ntime]/[increment]          *
3617  *                                                          *
3618  *  nmoves/ntime represents a traditional first time        *
3619  *  control when nmoves is an integer representing the      *
3620  *  number of moves and ntime is the total time allowed for *
3621  *  these moves.  The [optional] nmoves/ntime is a          *
3622  *  traditional secondary time control.  Increment is a     *
3623  *  feature related to ics play and emulates the fischer    *
3624  *  clock where "increment" is added to the time left after *
3625  *  each move is made.                                      *
3626  *                                                          *
3627  *  As an alternative, nmoves can be "sd" which represents  *
3628  *  a "sudden death" time control of the remainder of the   *
3629  *  game played in ntime.  The optional secondary time      *
3630  *  control can be a sudden-death time control, as in the   *
3631  *  following example:                                      *
3632  *                                                          *
3633  *    time 60/30/sd/30                                      *
3634  *                                                          *
3635  *  This sets 60 moves in 30 minutes, then game in 30       *
3636  *  additional minutes.  An increment can be added if       *
3637  *  desired.                                                *
3638  *                                                          *
3639  ************************************************************
3640  */
3641   else if (OptionMatch("time", *args)) {
3642     if (xboard) {
3643       tc_time_remaining[Flip(game_wtm)] = atoi(args[1]);
3644       if (log_file && time_limit > 99)
3645         fprintf(log_file, "time remaining: %s (Crafty).\n",
3646             DisplayTime(tc_time_remaining[Flip(game_wtm)]));
3647     } else {
3648       if (thinking || pondering)
3649         return 2;
3650       tc_moves = 60;
3651       tc_time = 180000;
3652       tc_moves_remaining[white] = 60;
3653       tc_moves_remaining[black] = 60;
3654       tc_time_remaining[white] = 180000;
3655       tc_time_remaining[black] = 180000;
3656       tc_secondary_moves = 60;
3657       tc_secondary_time = 180000;
3658       tc_increment = 0;
3659       tc_sudden_death = 0;
3660 /*
3661  first let's pick off the basic time control (moves/minutes)
3662  */
3663       if (nargs > 1)
3664         if (!strcmp(args[1], "sd")) {
3665           tc_sudden_death = 1;
3666           tc_moves = 1000;
3667         }
3668       if (nargs > 2) {
3669         tc_moves = atoi(args[1]);
3670         tc_time = atoi(args[2]) * 100;
3671       }
3672 /*
3673  now let's pick off the secondary time control (moves/minutes)
3674  */
3675       tc_secondary_time = tc_time;
3676       tc_secondary_moves = tc_moves;
3677       if (nargs > 4) {
3678         if (!strcmp(args[3], "sd")) {
3679           tc_sudden_death = 2;
3680           tc_secondary_moves = 1000;
3681         } else
3682           tc_secondary_moves = atoi(args[3]);
3683         tc_secondary_time = atoi(args[4]) * 100;
3684       }
3685       if (nargs > 5)
3686         tc_increment = atoi(args[5]) * 100;
3687       tc_time_remaining[white] = tc_time;
3688       tc_time_remaining[black] = tc_time;
3689       tc_moves_remaining[white] = tc_moves;
3690       tc_moves_remaining[black] = tc_moves;
3691       if (!tc_sudden_death) {
3692         Print(32, "%d moves/%d minutes primary time control\n", tc_moves,
3693             tc_time / 100);
3694         Print(32, "%d moves/%d minutes secondary time control\n",
3695             tc_secondary_moves, tc_secondary_time / 100);
3696         if (tc_increment)
3697           Print(32, "increment %d seconds.\n", tc_increment / 100);
3698       } else if (tc_sudden_death == 1) {
3699         Print(32, " game/%d minutes primary time control\n", tc_time / 100);
3700         if (tc_increment)
3701           Print(32, "increment %d seconds.\n", tc_increment / 100);
3702       } else if (tc_sudden_death == 2) {
3703         Print(32, "%d moves/%d minutes primary time control\n", tc_moves,
3704             tc_time / 100);
3705         Print(32, "game/%d minutes secondary time control\n",
3706             tc_secondary_time / 100);
3707         if (tc_increment)
3708           Print(32, "increment %d seconds.\n", tc_increment / 100);
3709       }
3710       tc_time *= 60;
3711       tc_time_remaining[white] *= 60;
3712       tc_time_remaining[black] *= 60;
3713       tc_secondary_time *= 60;
3714       tc_safety_margin = tc_time / 6;
3715     }
3716   }
3717 /*
3718  ************************************************************
3719  *                                                          *
3720  *  "timebook" command is used to adjust Crafty's time      *
3721  *  usage after it leaves the opening book.  The first      *
3722  *  value specifies the multiplier for the time added to    *
3723  *  the first move out of book expressed as a percentage    *
3724  *  (100 is 100% for example).  The second value specifies  *
3725  *  the "span" (number of moves) that this multiplier       *
3726  *  decays over.  For example, "timebook 100 10" says to    *
3727  *  add 100% of the normal search time for the first move   *
3728  *  out of book, then 90% for the next, until after 10      *
3729  *  non-book moves have been played, the percentage has     *
3730  *  dropped back to 0 where it will stay for the rest of    *
3731  *  the game.                                               *
3732  *                                                          *
3733  ************************************************************
3734  */
3735   else if (OptionMatch("timebook", *args)) {
3736     if (nargs < 3) {
3737       printf("usage:  timebook <percentage> <move span>\n");
3738       return 1;
3739     }
3740     first_nonbook_factor = atoi(args[1]);
3741     first_nonbook_span = atoi(args[2]);
3742     if (first_nonbook_factor < 0 || first_nonbook_factor > 500) {
3743       Print(4095, "ERROR, factor must be >= 0 and <= 500\n");
3744       first_nonbook_factor = 0;
3745     }
3746     if (first_nonbook_span < 0 || first_nonbook_span > 30) {
3747       Print(4095, "ERROR, span must be >= 0 and <= 30\n");
3748       first_nonbook_span = 0;
3749     }
3750   }
3751 /*
3752  ************************************************************
3753  *                                                          *
3754  *  "trace" command sets the search trace level which will  *
3755  *  dump the tree as it is searched.                        *
3756  *                                                          *
3757  ************************************************************
3758  */
3759   else if (OptionMatch("trace", *args)) {
3760 #if !defined(TRACE)
3761     printf
3762         ("Sorry, but I can't display traces unless compiled with -DTRACE\n");
3763 #endif
3764     if (nargs < 2) {
3765       printf("usage:  trace <depth>\n");
3766       return 1;
3767     }
3768     trace_level = atoi(args[1]);
3769     printf("trace=%d\n", trace_level);
3770   }
3771 /*
3772  ************************************************************
3773  *                                                          *
3774  *  "undo" command backs up 1/2 move, which leaves the      *
3775  *  opposite side on move. [xboard compatibility]           *
3776  *                                                          *
3777  ************************************************************
3778  */
3779   else if (OptionMatch("undo", *args)) {
3780     if (thinking || pondering)
3781       return 2;
3782     if (!game_wtm || move_number != 1) {
3783       game_wtm = Flip(game_wtm);
3784       if (Flip(game_wtm))
3785         move_number--;
3786       sprintf(buffer, "reset %d", move_number);
3787       Option(tree);
3788     }
3789   }
3790 /*
3791  ************************************************************
3792  *                                                          *
3793  *  "usage" command controls the time usage multiplier      *
3794  *  factors used in the game  - percentage increase or      *
3795  *  decrease in time used up front.  Enter a number between *
3796  *  1 to 100 for the % decrease (negative value) or to      *
3797  *  increase (positive value) although other time           *
3798  *  limitation controls may kick in.  This more commonly    *
3799  *  used in the .craftyrc/crafty.rc file.                   *
3800  *                                                          *
3801  ************************************************************
3802  */
3803   else if (OptionMatch("usage", *args)) {
3804     if (nargs < 2) {
3805       printf("usage:  usage <percentage>\n");
3806       return 1;
3807     }
3808     usage_level = atoi(args[1]);
3809     if (usage_level > 50)
3810       usage_level = 50;
3811     else if (usage_level < -50)
3812       usage_level = -50;
3813     Print(32, "time usage up front set to %d percent increase/(-)decrease.\n",
3814         usage_level);
3815   }
3816 /*
3817  ************************************************************
3818  *                                                          *
3819  *  "variant" command sets the wild variant being played    *
3820  *  on a chess server.  [xboard compatibility].             *
3821  *                                                          *
3822  ************************************************************
3823  */
3824   else if (OptionMatch("variant", *args)) {
3825     if (thinking || pondering)
3826       return 2;
3827     printf("command=[%s]\n", buffer);
3828     return -1;
3829   }
3830 /*
3831  ************************************************************
3832  *                                                          *
3833  *  "whisper" command sets whisper mode for ICS.  =1 will   *
3834  *  whisper mate announcements, =2 will whisper scores and  *
3835  *  other info, =3 will whisper scores and PV, =4 adds the  *
3836  *  list of book moves, =5 displays the PV after each       *
3837  *  iteration completes, and =6 displays the PV each time   *
3838  *  it changes in an iteration.                             *
3839  *                                                          *
3840  ************************************************************
3841  */
3842   else if (OptionMatch("whisper", *args)) {
3843     if (nargs < 2) {
3844       printf("usage:  whisper <level>\n");
3845       return 1;
3846     }
3847     kibitz = 16 + Min(0, atoi(args[1]));
3848   }
3849 /*
3850  ************************************************************
3851  *                                                          *
3852  *  "white" command sets white to move (wtm).               *
3853  *                                                          *
3854  ************************************************************
3855  */
3856   else if (OptionMatch("white", *args)) {
3857     if (thinking || pondering)
3858       return 2;
3859     ponder_move = 0;
3860     last_pv.pathd = 0;
3861     last_pv.pathl = 0;
3862     if (!game_wtm)
3863       Pass();
3864     force = 0;
3865   }
3866 /*
3867  ************************************************************
3868  *                                                          *
3869  *  "wild" command sets up an ICS wild position (only 7 at  *
3870  *  present, but any can be added easily, except for those  *
3871  *  that Crafty simply can't play (two kings, invisible     *
3872  *  pieces, etc.)                                           *
3873  *                                                          *
3874  ************************************************************
3875  */
3876   else if (OptionMatch("wild", *args)) {
3877     int i;
3878 
3879     if (nargs < 2) {
3880       printf("usage:  wild <value>\n");
3881       return 1;
3882     }
3883     i = atoi(args[1]);
3884     switch (i) {
3885       case 7:
3886         strcpy(buffer, "setboard 4k/5ppp/////PPP/3K/ w");
3887         Option(tree);
3888         break;
3889       default:
3890         printf("sorry, only wild7 implemented at present\n");
3891         break;
3892     }
3893   }
3894 /*
3895  ************************************************************
3896  *                                                          *
3897  *  "xboard" command is normally invoked from main() via    *
3898  *  the xboard command-line option.  It sets proper         *
3899  *  defaults for Xboard interface requirements.             *
3900  *                                                          *
3901  ************************************************************
3902  */
3903   else if (OptionMatch("xboard", *args) || OptionMatch("winboard", *args)) {
3904     if (!xboard) {
3905       signal(SIGINT, SIG_IGN);
3906       xboard = 1;
3907       display_options = 2048;
3908       Print(-1, "\n");
3909       Print(-1, "tellicsnoalias set 1 Crafty v%s (%d cpus)\n", version, Max(1,
3910               smp_max_threads));
3911       Print(-1, "tellicsnoalias kibitz Hello from Crafty v%s! (%d cpus)\n",
3912           version, Max(1, smp_max_threads));
3913     }
3914   }
3915 /*
3916  ************************************************************
3917  *                                                          *
3918  *  "?" command does nothing, but since this is the "move   *
3919  *  now" keystroke, if Crafty is not searching, this will   *
3920  *  simply "wave it off" rather than produce an error.      *
3921  *                                                          *
3922  ************************************************************
3923  */
3924   else if (OptionMatch("?", *args)) {
3925   }
3926 /*
3927  ************************************************************
3928  *                                                          *
3929  *  unknown command, it must be a move.                     *
3930  *                                                          *
3931  ************************************************************
3932  */
3933   else
3934     return 0;
3935 /*
3936  ************************************************************
3937  *                                                          *
3938  *  command executed, return for another.                   *
3939  *                                                          *
3940  ************************************************************
3941  */
3942   return 1;
3943 }
3944 
3945 /*
3946  *******************************************************************************
3947  *                                                                             *
3948  *   OptionMatch() is used to recognize user commands.  It requires that the   *
3949  *   command (text input which is the *2nd parameter* conform to the following *
3950  *   simple rules:                                                             *
3951  *                                                                             *
3952  *     1.  The input must match the command, starting at the left-most         *
3953  *         character.                                                          *
3954  *     2.  If the command starts with a sequence of characters that could      *
3955  *         be interpreted as a chess move as well (re for reset and/or rook    *
3956  *         to the e-file) then the input must match enough of the command      *
3957  *         to get past the ambiguity (res would be minimum we will accept      *
3958  *         for the reset command.)                                             *
3959  *                                                                             *
3960  *******************************************************************************
3961  */
OptionMatch(char * command,char * input)3962 int OptionMatch(char *command, char *input) {
3963 /*
3964  ************************************************************
3965  *                                                          *
3966  *  check for the obvious exact match first.                *
3967  *                                                          *
3968  ************************************************************
3969  */
3970   if (!strcmp(command, input))
3971     return 1;
3972 /*
3973  ************************************************************
3974  *                                                          *
3975  *  now use strstr() to see if "input" is in "command." the *
3976  *  first requirement is that input matches command         *
3977  *  starting at the very left-most character.               *
3978  *                                                          *
3979  ************************************************************
3980  */
3981   if (strstr(command, input) == command)
3982     return 1;
3983   return 0;
3984 }
3985 
OptionPerft(TREE * RESTRICT tree,int ply,int depth,int wtm)3986 void OptionPerft(TREE * RESTRICT tree, int ply, int depth, int wtm) {
3987   unsigned *mv;
3988 #if defined(TRACE)
3989   static char line[256];
3990   static char move[16], *p[64];
3991 #endif
3992 
3993   tree->last[ply] = GenerateCaptures(tree, ply, wtm, tree->last[ply - 1]);
3994   for (mv = tree->last[ply - 1]; mv < tree->last[ply]; mv++)
3995     if (Captured(*mv) == king)
3996       return;
3997   tree->last[ply] = GenerateNoncaptures(tree, ply, wtm, tree->last[ply]);
3998 #if defined(TRACE)
3999   p[1] = line;
4000 #endif
4001   for (mv = tree->last[ply - 1]; mv < tree->last[ply]; mv++) {
4002 #if defined(TRACE)
4003     strcpy(move, OutputMove(tree, ply, wtm, *mv));
4004 #endif
4005     MakeMove(tree, ply, wtm, *mv);
4006 #if defined(TRACE)
4007     if (ply <= trace_level) {
4008       strcpy(p[ply], move);
4009       strcpy(line + strlen(line), " ");
4010       p[ply + 1] = line + strlen(line);
4011       if (ply == trace_level)
4012         printf("%s\n", line);
4013     }
4014 #endif
4015     if (depth - 1)
4016       OptionPerft(tree, ply + 1, depth - 1, Flip(wtm));
4017     else if (!Check(wtm))
4018       total_moves++;
4019     UnmakeMove(tree, ply, wtm, *mv);
4020   }
4021 }
4022