Subversion Repositories Games.Chess Giants

Rev

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