Subversion Repositories Games.Chess Giants

Rev

Rev 33 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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